lody 0.101.1 → 0.102.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import crypto__default, { createHash as createHash$1, randomUUID as randomUUID$1
13
13
  import os__default, { homedir, userInfo, cpus } from "node:os";
14
14
  import * as path from "node:path";
15
15
  import path__default, { posix as posix$1, basename, win32, join as join$2, resolve, relative as relative$1, dirname as dirname$1, isAbsolute as isAbsolute$2, sep as sep$1, delimiter, normalize } from "node:path";
16
- import { _ as _coercedNumber, Z as ZodNumber, o as object, s as string$1, l as literal$1, b as boolean, a as _enum, n as number$4, d as discriminatedUnion, c as array$2, r as record$3, u as unknown, e as union$7, f as custom$1, g as ZodObject, h as ZodLiteral, j as json$1, p as preprocess, i as ZodError, k as safeParse, m as ZodOptional, q as ZodNullable, t as ZodPipe, v as ZodUnion, w as ZodArray, x as ZodNever, y as ZodDiscriminatedUnion, z as _instanceof, A as uuid, N as NEVER, B as _null, C as lazy, D as looseObject, E as intersection, F as optional$1, G as datetime, H as url, I as any, J as toJSONSchema, K as date, L as email, M as never$1, O as xor } from "./chunks/schemas-9JpFbIUJ.js";
16
+ import { _ as _coercedNumber, Z as ZodNumber, o as object, s as string$1, l as literal$1, b as boolean, a as _enum, n as number$4, d as discriminatedUnion, c as array$2, r as record$3, u as unknown, e as union$7, f as custom$1, g as ZodObject, h as ZodLiteral, j as json$1, p as preprocess, i as ZodError, k as safeParse, m as ZodOptional, q as ZodNullable, t as ZodPipe, v as ZodUnion, w as ZodArray, x as ZodNever, y as ZodDiscriminatedUnion, z as _instanceof, A as uuid, N as NEVER, B as _null, C as looseObject, D as lazy, E as intersection, F as optional$1, G as datetime, H as url, I as any, J as toJSONSchema, K as date, L as email, M as xor, O as never$1 } from "./chunks/schemas-WuyisFi9.js";
17
17
  import require$$0$4, { EventEmitter as EventEmitter$1, once as once$1 } from "node:events";
18
18
  import require$$1$2, { execFile, spawn as spawn$1, execFileSync } from "node:child_process";
19
19
  import process$2 from "node:process";
@@ -37,7 +37,7 @@ import fs__default$2, { readFile, readdir, rm, mkdir as mkdir$1, mkdtemp, chmod,
37
37
  import zlib__default, { gzip, gunzip as gunzip$1, gunzipSync, brotliDecompressSync } from "node:zlib";
38
38
  import require$$1$8, { exec, execFile as execFile$1, spawn as spawn$2 } from "child_process";
39
39
  import { c as createPlanModeConfigOption, L as LODY_PLAN_MODE_CONFIG_ID } from "./chunks/plan-mode-D0D5cnMs.js";
40
- import { D as DEEPSEEK_HARNESS_PERMISSION_MODES, a as DEEPSEEK_HARNESS_AGENT_PRESETS, A as ACP_EXTENSION_DSH_CAPABILITY_SOURCE_VERSION, c as createDeepSeekHarnessProfileFiles, b as DEEPSEEK_HARNESS_PROFILE_NAME, d as DEEPSEEK_HARNESS_PROFILE_FILENAMES, e as ACP_EXTENSION_DSH_QUERY_PATH_ENV, f as ACP_EXTENSION_DSH_SESSION_ROOT_ENV, g as createDeepSeekHarnessNpxSpecifiers, h as DEEPSEEK_HARNESS_DEFAULT_SESSION_COMPRESSION, i as DEEPSEEK_HARNESS_VERSION, j as DEEPSEEK_HARNESS_BASE_URL_ENV, R as RequestError$1, C as ClientSideConnection, P as PROTOCOL_VERSION, n as ndJsonStream, k as client$2, m as methods$1 } from "./chunks/acp-w0Ug9k0u.js";
40
+ import { D as DEEPSEEK_HARNESS_PERMISSION_MODES, a as DEEPSEEK_HARNESS_AGENT_PRESETS, A as ACP_EXTENSION_DSH_CAPABILITY_SOURCE_VERSION, c as createDeepSeekHarnessProfileFiles, b as DEEPSEEK_HARNESS_PROFILE_NAME, d as DEEPSEEK_HARNESS_PROFILE_FILENAMES, e as ACP_EXTENSION_DSH_QUERY_PATH_ENV, f as ACP_EXTENSION_DSH_SESSION_ROOT_ENV, g as createDeepSeekHarnessNpxSpecifiers, h as DEEPSEEK_HARNESS_DEFAULT_SESSION_COMPRESSION, i as DEEPSEEK_HARNESS_VERSION, j as DEEPSEEK_HARNESS_BASE_URL_ENV, R as RequestError$1, C as ClientSideConnection, P as PROTOCOL_VERSION, n as ndJsonStream, k as client$2, m as methods$1 } from "./chunks/acp-Bsd2Lmd6.js";
41
41
  import { i as isLodySubagentProgress, a as isLodySubagentSnapshot, b as isLodySubagentEvent, c as isLodySubagentOutput, L as LODY_EXTENSION_METHODS, M as MAX_USAGE_SCOPE_ID_LENGTH, n as normalizeLodyExtensionMethod, d as LODY_SUBAGENT_EVENT_METHOD } from "./chunks/subagent-events-BJ9JwZva.js";
42
42
  import { i as imports, _ as __wbg_set_wasm$1, r as rawWasm, L as LoroDoc, E as EphemeralStoreWasm, U as UndoManager, a as isValidContainerId, c as callPendingEvents$3, b as LoroTree, d as LoroText, e as LoroMovableList, f as LoroList, g as LoroMap, V as VersionVector, h as __vite__initWasm, j as decodeImportBlobMeta } from "./chunks/loro_wasm_bg-DIxpLA2J.js";
43
43
  import { performance as performance$1 } from "perf_hooks";
@@ -62,17 +62,18 @@ import require$$1$4, { Worker as Worker$1 } from "node:worker_threads";
62
62
  import require$$1$5, { fileURLToPath, pathToFileURL } from "node:url";
63
63
  import require$$1$6 from "node:console";
64
64
  import require$$1$7 from "node:dns";
65
- import { C as CodeCollabV2FileIndexRequestSchema, a as CodeCollabV2OpenTextRequestSchema, b as CodeCollabV2RefreshTextRequestSchema, c as CodeCollabV2SaveTextRequestSchema, d as CodeCollabV2OpenCurrentDiffRequestSchema, e as CodeCollabV2OpenAllChangesDiffRequestSchema, f as CodeCollabV2OpenTurnDiffRequestSchema, g as CodeCollabV2InitDirectoryRequestSchema, h as CodeCollabV2FileIndexSnapshotSchema, i as CodeCollabV2OpenTextOkSchema, j as CodeCollabV2RefreshTextResponseSchema, k as CodeCollabV2SaveTextResponseSchema, l as CodeCollabV2OpenCurrentDiffResponseSchema, m as CodeCollabV2OpenAllChangesDiffResponseSchema, n as CodeCollabV2OpenTurnDiffResponseSchema, o as CodeCollabV2InitDirectoryOkSchema, p as CodeCollabV2LspUnsupportedSchema, q as CodeCollabV2ErrorSchema, r as CodeCollabV2RpcContentEnvelopeSchema, s as deriveCodeCollabV2ContentKeyId, t as CodeCollabV2ErrorCodeSchema, u as CodeCollabV2RpcResponseSchema, v as deriveCodeCollabV2ContentKeyBytes, w as readCodeCollabFileIndexSignalFromFlock, x as writeCodeCollabFileIndexSignalToFlock, y as writeCodeCollabFileIndexToFlock, z as buildCodeCollabFileIndexState, A as CODE_COLLAB_V2_TEXT_LIMITS, B as CODE_COLLAB_V2_ALL_CHANGES_DIFF_LIMITS, D as computeAllChanges, E as codeCollabFileIndexStatesEqual, F as scanGitDirectoryEntries, G as closeDirectoryQuietly } from "./chunks/directory-handle-CjQk33eZ.js";
65
+ import { C as CodeCollabV2FileIndexRequestSchema, a as CodeCollabV2OpenTextRequestSchema, b as CodeCollabV2RefreshTextRequestSchema, c as CodeCollabV2SaveTextRequestSchema, d as CodeCollabV2OpenCurrentDiffRequestSchema, e as CodeCollabV2OpenAllChangesDiffRequestSchema, f as CodeCollabV2OpenTurnDiffRequestSchema, g as CodeCollabV2InitDirectoryRequestSchema, h as CodeCollabV2FileIndexSnapshotSchema, i as CodeCollabV2OpenTextOkSchema, j as CodeCollabV2RefreshTextResponseSchema, k as CodeCollabV2SaveTextResponseSchema, l as CodeCollabV2OpenCurrentDiffResponseSchema, m as CodeCollabV2OpenAllChangesDiffResponseSchema, n as CodeCollabV2OpenTurnDiffResponseSchema, o as CodeCollabV2InitDirectoryOkSchema, p as CodeCollabV2LspUnsupportedSchema, q as CodeCollabV2ErrorSchema, r as CodeCollabV2RpcContentEnvelopeSchema, s as deriveCodeCollabV2ContentKeyId, t as CodeCollabV2ErrorCodeSchema, u as CodeCollabV2RpcResponseSchema, v as deriveCodeCollabV2ContentKeyBytes, w as readCodeCollabFileIndexSignalFromFlock, x as writeCodeCollabFileIndexSignalToFlock, y as writeCodeCollabFileIndexToFlock, z as buildCodeCollabFileIndexState, A as CODE_COLLAB_V2_TEXT_LIMITS, B as CODE_COLLAB_V2_ALL_CHANGES_DIFF_LIMITS, D as computeAllChanges, E as codeCollabFileIndexStatesEqual, F as scanGitDirectoryEntries, G as closeDirectoryQuietly } from "./chunks/directory-handle-CtdCjbNh.js";
66
66
  import { finished, pipeline } from "node:stream/promises";
67
67
  import { StringDecoder } from "node:string_decoder";
68
68
  import { p as packageJson } from "./chunks/package-BoOO46ct.js";
69
+ import { L as LODY_TOOL_NAMES } from "./chunks/session-DyqwlJbY.js";
69
70
  import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
70
71
  import { createRequire } from "module";
71
72
  import { c as computeLineCounts, a as countTextLines } from "./chunks/diff-line-counts-DDGc5P-T.js";
72
73
  import { r as runDiffWorkerTask } from "./chunks/diff-worker-task-MZsLArT5.js";
73
74
  import { C as CODE_COLLAB_IGNORED_DIRECTORY_NAMES, p as parseWorkspaceWatchChildMessage } from "./chunks/workspace-watch-protocol-POg9Lpeq.js";
74
75
  import { Resolver } from "node:dns/promises";
75
- import { C as CloudflaredError } from "./chunks/cloudflared-native-BPe7OSUZ.js";
76
+ import { C as CloudflaredError } from "./chunks/cloudflared-native-DbUToPHH.js";
76
77
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
77
78
  import { createRequire as createRequire$1 } from "node:module";
78
79
  import v8 from "node:v8";
@@ -4316,7 +4317,7 @@ function resolvePlatformKind(raw2) {
4316
4317
  }
4317
4318
  const name$3 = "lody";
4318
4319
  const name$2 = "@lody/cli-cloud";
4319
- const version$d = "0.101.1";
4320
+ const version$d = "0.102.0";
4320
4321
  const type = "module";
4321
4322
  const scripts = { "dev": "node dev.mjs", "dev:staging": "LODY_ENV=staging NODE_ENV=production node dev.mjs", "build": "node build.mjs", "prepare:publish": "node prepare-publish.js", "test": "node --test pnpm-runner.test.mjs vite-config.test.mjs" };
4322
4323
  const devDependencies = { "dotenv": "^16.6.1", "vite": "^7.0.0", "vite-plugin-wasm": "catalog:" };
@@ -4611,9 +4612,6 @@ const mergeSubagentTaskPayload = (prev, incoming) => {
4611
4612
  }
4612
4613
  return merged;
4613
4614
  };
4614
- const LODY_TOOL_NAMES = {
4615
- imageGeneration: "ImageGeneration"
4616
- };
4617
4615
  const MANAGED_BUILTIN_RUNTIMES = [
4618
4616
  { runtimeName: "kimi-code", agentType: "kimi", displayName: "Kimi Code" },
4619
4617
  { runtimeName: "grok-build", agentType: "grok", displayName: "Grok" },
@@ -27051,7 +27049,23 @@ const SessionActiveInvocationContextResultSchema = discriminatedUnion("active",
27051
27049
  inputConfig: record$3(string$1(), unknown())
27052
27050
  }).strict()
27053
27051
  ]);
27052
+ const SessionToolResultSchema = object({
27053
+ type: literal$1("session/tool-result"),
27054
+ content: array$2(object({ type: literal$1("text"), text: string$1() }).strict()),
27055
+ isError: boolean().optional()
27056
+ }).strict();
27054
27057
  const LocalMachineRpcRequestSchema = discriminatedUnion("method", [
27058
+ BaseLocalMachineRpcRequestSchema.extend({
27059
+ method: literal$1("session/call-tool"),
27060
+ params: object({
27061
+ sessionId: SessionIdSchema$1,
27062
+ name: string$1().min(1).max(100),
27063
+ arguments: record$3(string$1(), json$1()).refine(
27064
+ (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <= 256 * 1024,
27065
+ "Session tool arguments exceed 256 KiB"
27066
+ )
27067
+ }).strict()
27068
+ }).strict(),
27055
27069
  BaseLocalMachineRpcRequestSchema.extend({
27056
27070
  method: literal$1("session/get-active-invocation-context"),
27057
27071
  params: object({
@@ -27219,6 +27233,7 @@ const LocalMachineRpcRequestSchema = discriminatedUnion("method", [
27219
27233
  }).strict()
27220
27234
  ]);
27221
27235
  const LocalMachineRpcResultSchema = union$7([
27236
+ SessionToolResultSchema,
27222
27237
  SessionActiveInvocationContextResultSchema,
27223
27238
  CodeCollabV2FileIndexSnapshotSchema,
27224
27239
  CodeCollabV2OpenTextOkSchema,
@@ -127633,10 +127648,15 @@ const ProfileRecordSchema = object({
127633
127648
  configId: string$1().min(1),
127634
127649
  profile: CodexAuthProfileSchema,
127635
127650
  state: _enum(["pending", "ready", "removed"]),
127651
+ authStore: _enum(["codex-default", "keyring"]).optional(),
127636
127652
  activeGeneration: uuid().optional(),
127637
127653
  generations: array$2(uuid()),
127638
127654
  credentialsRemoved: boolean().optional()
127639
127655
  }).strict();
127656
+ function resolveAuthStore(record2) {
127657
+ if (record2.authStore) return record2.authStore;
127658
+ return record2.profile.mode === "chatgpt" && record2.state !== "pending" ? "keyring" : "codex-default";
127659
+ }
127640
127660
  const identity$1 = (owner) => createHash("sha256").update(JSON.stringify([owner.workspaceId, owner.machineId, owner.configId])).digest("hex");
127641
127661
  class CodexProfileStore {
127642
127662
  constructor(root = path__default.join(getLodyDataDir(), "codex-profiles"), vault = new SystemCodexCredentialVault(), logout = logoutNativeProfile) {
@@ -127724,7 +127744,14 @@ class CodexProfileStore {
127724
127744
  if (!record2) {
127725
127745
  if (!allowPending)
127726
127746
  throw new Error("This Codex account has not been authenticated on this machine");
127727
- record2 = { version: 1, ...owner, profile, state: "pending", generations: [] };
127747
+ record2 = {
127748
+ version: 1,
127749
+ ...owner,
127750
+ profile,
127751
+ state: "pending",
127752
+ authStore: "codex-default",
127753
+ generations: []
127754
+ };
127728
127755
  await this.write(directory, record2);
127729
127756
  }
127730
127757
  this.assertBinding(record2, owner, profile);
@@ -127736,7 +127763,7 @@ class CodexProfileStore {
127736
127763
  });
127737
127764
  if ((await lstat(home)).isSymbolicLink() || await realpath(home) !== home)
127738
127765
  throw new Error("Invalid Codex account home");
127739
- return { ...owner, profile, home };
127766
+ return { ...owner, profile, home, authStore: resolveAuthStore(record2) };
127740
127767
  });
127741
127768
  }
127742
127769
  credentialId(owner, profileId, generation) {
@@ -127797,7 +127824,7 @@ class CodexProfileStore {
127797
127824
  const record2 = await this.read(directory);
127798
127825
  if (!record2) throw new Error("Codex account is unavailable");
127799
127826
  this.assertBinding(record2, resolved, resolved.profile);
127800
- await this.write(directory, { ...record2, state: "ready" });
127827
+ await this.write(directory, { ...record2, state: "ready", authStore: resolved.authStore });
127801
127828
  });
127802
127829
  }
127803
127830
  async remove(resolved) {
@@ -127807,7 +127834,7 @@ class CodexProfileStore {
127807
127834
  if (!record2) return true;
127808
127835
  if (identity$1(record2) !== identity$1(resolved)) throw new Error("Codex account owner mismatch");
127809
127836
  if (record2.credentialsRemoved) return true;
127810
- await this.write(directory, { ...record2, state: "removed" });
127837
+ await this.write(directory, { ...record2, state: "removed", authStore: resolved.authStore });
127811
127838
  if (record2.profile.mode === "chatgpt") {
127812
127839
  if (!await reconcileCodexProfileProcesses(resolved)) return false;
127813
127840
  const lease = await registerCodexProfileProcess(resolved, {
@@ -127826,6 +127853,7 @@ class CodexProfileStore {
127826
127853
  await this.write(directory, {
127827
127854
  ...record2,
127828
127855
  state: "removed",
127856
+ authStore: resolved.authStore,
127829
127857
  generations: [],
127830
127858
  activeGeneration: void 0,
127831
127859
  credentialsRemoved: true
@@ -127864,7 +127892,11 @@ class CodexProfileStore {
127864
127892
  const directory = await this.directory(entry.name);
127865
127893
  const record2 = await this.read(directory);
127866
127894
  if (record2?.workspaceId === workspaceId)
127867
- profiles.push({ ...record2, home: path__default.join(directory, "home") });
127895
+ profiles.push({
127896
+ ...record2,
127897
+ home: path__default.join(directory, "home"),
127898
+ authStore: resolveAuthStore(record2)
127899
+ });
127868
127900
  }
127869
127901
  return profiles;
127870
127902
  }
@@ -127884,7 +127916,10 @@ async function logoutNativeProfile(profile, lease) {
127884
127916
  await new Promise((resolve2, reject2) => {
127885
127917
  const child = execFile(
127886
127918
  launch.command,
127887
- ["-c", 'cli_auth_credentials_store="keyring"', "logout"],
127919
+ [
127920
+ ...profile.authStore === "keyring" ? ["-c", 'cli_auth_credentials_store="keyring"'] : [],
127921
+ "logout"
127922
+ ],
127888
127923
  { env: env2, timeout: 2e4, windowsHide: true },
127889
127924
  (error2) => {
127890
127925
  if (error2) reject2(new Error("Codex account cleanup could not complete"));
@@ -142036,7 +142071,7 @@ async function startCodexCredentialBroker(options) {
142036
142071
  }
142037
142072
  function codexProfileConfig(profile, baseUrl) {
142038
142073
  const base = {
142039
- cli_auth_credentials_store: "keyring",
142074
+ ...profile.authStore === "keyring" ? { cli_auth_credentials_store: "keyring" } : {},
142040
142075
  check_for_update_on_startup: false,
142041
142076
  shell_environment_policy: {
142042
142077
  inherit: "all",
@@ -142849,7 +142884,7 @@ function getBuiltinDisplayName(agentType) {
142849
142884
  function formatAuthenticationExitError(agentType, displayName, exitCode) {
142850
142885
  const base = `${displayName} authentication exited with code ${exitCode ?? "unknown"}`;
142851
142886
  if (agentType !== "codex") return base;
142852
- return `${base}. Make sure device-code login is enabled in your ChatGPT security settings or workspace permissions, then try again.`;
142887
+ return `${base}. Check the Codex login log on the execution machine for the cause, then try again.`;
142853
142888
  }
142854
142889
  async function buildAuthenticationProcessEnv(options) {
142855
142890
  const loginShellEnv = await options.resolveLoginShellEnv();
@@ -142973,8 +143008,6 @@ class AcpAuthenticationManager {
142973
143008
  this.resolveLoginShellEnv = options.resolveLoginShellEnv ?? getLoginShellEnv;
142974
143009
  this.resolveAuthenticationProcessLaunch = options.resolveAuthenticationProcessLaunch ?? resolveBuiltinAuthenticationProcessLaunch;
142975
143010
  }
142976
- // Each builtin provider has one shared credential store, so concurrent login
142977
- // attempts are intentionally keyed by agent type.
142978
143011
  runningByAgentType = /* @__PURE__ */ new Map();
142979
143012
  authenticationTimeoutMs;
142980
143013
  terminationGraceMs;
@@ -143094,13 +143127,7 @@ class AcpAuthenticationManager {
143094
143127
  options.onProgress?.({ status: "starting" });
143095
143128
  const child = this.spawnProcess(
143096
143129
  launch.command,
143097
- options.codexProfile ? [
143098
- "-c",
143099
- 'cli_auth_credentials_store="keyring"',
143100
- "-c",
143101
- 'forced_login_method="chatgpt"',
143102
- ...launch.args
143103
- ] : launch.args,
143130
+ options.codexProfile ? ["-c", 'forced_login_method="chatgpt"', ...launch.args] : launch.args,
143104
143131
  {
143105
143132
  cwd: os__default$1.homedir(),
143106
143133
  env: env2,
@@ -158335,12 +158362,13 @@ class LodyOperationCoordinator {
158335
158362
  }
158336
158363
  claimedMaterialization = true;
158337
158364
  try {
158338
- await this.options.workspaceDocument.syncRemoteDocOrThrow(
158339
- getSessionRoomId(target.sessionId),
158340
- {
158341
- reason: `orchestration.materialize:${operation.operationId}:${index}`
158342
- }
158343
- );
158365
+ const docId = getSessionRoomId(target.sessionId);
158366
+ const reason = `orchestration.materialize:${operation.operationId}:${index}`;
158367
+ if (this.options.confirmTargetReadable) {
158368
+ await this.options.confirmTargetReadable(docId, reason);
158369
+ } else {
158370
+ await this.options.workspaceDocument.syncRemoteDocOrThrow(docId, { reason });
158371
+ }
158344
158372
  } catch (error2) {
158345
158373
  if (signal.aborted) return item;
158346
158374
  if (!isAtDeadline()) {
@@ -159099,6 +159127,40 @@ class LodyOperationCoordinator {
159099
159127
  });
159100
159128
  }
159101
159129
  }
159130
+ const environments = new AsyncLocalStorage();
159131
+ const getSessionCommandEnvironment = () => environments.getStore();
159132
+ const runWithSessionCommandEnvironment = (environment2, run2) => environments.run(environment2, run2);
159133
+ function createLocalSessionCommandEnvironment(args2) {
159134
+ const { manager, workspaceId, machineId, userId } = args2;
159135
+ return {
159136
+ auth: {
159137
+ token: "",
159138
+ userId,
159139
+ userName: userId,
159140
+ userEmail: "",
159141
+ machineId,
159142
+ machineName: args2.machineName
159143
+ },
159144
+ workspace: { id: workspaceId, name: "Lody", slug: "local", role: "owner" },
159145
+ manager,
159146
+ host: args2.host,
159147
+ async checkMachineAccess(target) {
159148
+ if (target.workspaceId !== workspaceId || target.requesterUserId !== userId)
159149
+ return { allowed: false, reason: "requester_not_member" };
159150
+ if (target.machineId !== machineId)
159151
+ return { allowed: false, reason: "machine_not_registered" };
159152
+ const row = await manager.repo.getDocMeta(getMachineRoomId(machineId));
159153
+ if (!row?.meta || isLoroRepoDocDeleted(row) || row.meta.ownerUserId !== userId)
159154
+ return { allowed: false, reason: "not_visible" };
159155
+ if (target.localProjectId) {
159156
+ const projects = await readMachineLocalProjects(manager.repo, workspaceId, machineId);
159157
+ const project = Object.values(projects).find((entry) => entry.id === target.localProjectId);
159158
+ if (!project) return { allowed: false, reason: "project_not_shared" };
159159
+ }
159160
+ return { allowed: true };
159161
+ }
159162
+ };
159163
+ }
159102
159164
  function hasSessionDispatchEvidence(meta, history, userTurnId) {
159103
159165
  const user = history.find((entry) => entry.id === userTurnId && entry.role === "user");
159104
159166
  return !!user && (meta.latestUserMsgId === userTurnId || meta.processingUserMsgId === userTurnId || meta.lastHandledUserMsgId === userTurnId || user.status === "handled" || user.status === "failed" || user.status === "canceled" || history.some(
@@ -167332,6 +167394,25 @@ async function canUseMachineForCliToken(input2) {
167332
167394
  throw error2;
167333
167395
  }
167334
167396
  }
167397
+ const MISSING_PUBLIC_FUNCTION_ERROR = /Could not find (public )?function/;
167398
+ async function canDelegateMachineUseForCliToken(input2) {
167399
+ const client2 = createAuthConvexClient();
167400
+ try {
167401
+ const raw2 = await client2.query(api.machines.canDelegateMachineUseFromCliToken, {
167402
+ cliToken: input2.token,
167403
+ workspaceId: input2.workspaceId,
167404
+ machineId: input2.machineId,
167405
+ requesterUserId: input2.requesterUserId,
167406
+ ...input2.localProjectId !== void 0 ? { localProjectId: input2.localProjectId } : {}
167407
+ });
167408
+ return MachineAccessCheckResultSchema.parse(raw2);
167409
+ } catch (error2) {
167410
+ if (error2 instanceof Error && MISSING_PUBLIC_FUNCTION_ERROR.test(error2.message)) {
167411
+ return null;
167412
+ }
167413
+ throw error2;
167414
+ }
167415
+ }
167335
167416
  async function canRequestMachineForCliToken(input2) {
167336
167417
  const client2 = createAuthConvexClient();
167337
167418
  const raw2 = await client2.query(api.machines.canRequestMachineFromCliToken, {
@@ -168755,6 +168836,8 @@ function selectWorkspaceSummary(workspaces, selector) {
168755
168836
  );
168756
168837
  }
168757
168838
  function getAuthContextOrThrow$1(loggerName) {
168839
+ const environment2 = getSessionCommandEnvironment();
168840
+ if (environment2) return environment2.auth;
168758
168841
  const authClient = new AuthClient(getLogger(loggerName));
168759
168842
  const authInfo = authClient.getAuthInfo();
168760
168843
  if (!authInfo) {
@@ -168770,11 +168853,22 @@ function getAuthContextOrThrow$1(loggerName) {
168770
168853
  };
168771
168854
  }
168772
168855
  async function resolveWorkspaceOrThrow$1(auth, selector) {
168856
+ const environment2 = getSessionCommandEnvironment();
168857
+ if (environment2) {
168858
+ if (auth !== environment2.auth) throw new Error("Session command identity mismatch");
168859
+ return selectWorkspaceSummary([environment2.workspace], selector);
168860
+ }
168773
168861
  const workspaces = await listWorkspacesForToken(auth.token);
168774
168862
  const effectiveSelector = normalizeCliValue(selector) ?? normalizeCliValue(process.env.LODY_WORKSPACE_ID);
168775
168863
  return selectWorkspaceSummary(workspaces, effectiveSelector);
168776
168864
  }
168777
168865
  async function withWorkspaceManager$1(auth, workspace, loggerName, fn) {
168866
+ const environment2 = getSessionCommandEnvironment();
168867
+ if (environment2) {
168868
+ if (auth !== environment2.auth || workspace.id !== environment2.workspace.id)
168869
+ throw new Error("Session command workspace mismatch");
168870
+ return fn(environment2.manager);
168871
+ }
168778
168872
  if (!LODY_AUTH_URL) {
168779
168873
  throw new Error("Cloud workspace commands require LODY_AUTH_URL");
168780
168874
  }
@@ -171026,8 +171120,6 @@ class ResourceDiscovery {
171026
171120
  const modeId = role.runConfig.modeId ?? role.runConfig.configOptionValues?._permission;
171027
171121
  if (state2.state === "available" && capability && modeId && !(permission ? permission.options.some((option2) => option2.value === modeId) : capability.modes.some((mode2) => mode2.id === modeId)))
171028
171122
  state2 = { state: "unavailable", reason: "mode_unavailable" };
171029
- if (state2.state === "available" && source2.roleMachineScope && role.machineId !== source2.roleMachineScope)
171030
- state2 = { state: "unavailable", reason: "outside_work_context" };
171031
171123
  return {
171032
171124
  id: role.id,
171033
171125
  name: role.name,
@@ -171075,14 +171167,6 @@ class ResourceDiscovery {
171075
171167
  async function createResourceDiscovery(args2) {
171076
171168
  const { manager, auth, workspaceId } = args2;
171077
171169
  if (!args2.offline) await syncWorkspaceMetaForRead(manager, "resource.discovery");
171078
- let roleMachineScope;
171079
- if (args2.requesterSessionId) {
171080
- const record2 = await manager.repo.getDocMeta(getSessionRoomId(args2.requesterSessionId));
171081
- if (!record2?.meta || isLoroRepoDocDeleted(record2))
171082
- throw new Error("Requester Session not found.");
171083
- const session2 = record2.meta;
171084
- if (session2.project?.kind !== "github") roleMachineScope = session2.machineId;
171085
- }
171086
171170
  const synced = /* @__PURE__ */ new Set();
171087
171171
  async function sync2(id2) {
171088
171172
  if (!args2.offline && !synced.has(id2)) {
@@ -171094,9 +171178,8 @@ async function createResourceDiscovery(args2) {
171094
171178
  workspaceId,
171095
171179
  userId: args2.delegatedRequester?.userId ?? auth.userId,
171096
171180
  selectedMcpServerIds: args2.selectedMcpServerIds,
171097
- roleMachineScope,
171098
171181
  machines: async () => (await listAliveDocMetas(manager, isMachineDocRoomId)).map((row) => row.meta),
171099
- onlineMachineIds: async () => args2.offline ? null : manager.getOnlineMachineIds(),
171182
+ onlineMachineIds: async () => getSessionCommandEnvironment() ? /* @__PURE__ */ new Set([auth.machineId]) : args2.offline ? null : manager.getOnlineMachineIds(),
171100
171183
  canAccess: async (machineId, localProjectId) => (await readSessionMachineAccess({
171101
171184
  auth,
171102
171185
  workspaceId,
@@ -173136,6 +173219,12 @@ async function withMachineRpcClient(args2, fn) {
173136
173219
  }
173137
173220
  }
173138
173221
  async function ensureTargetMachineOnline(args2) {
173222
+ const environment2 = getSessionCommandEnvironment();
173223
+ if (environment2) {
173224
+ if (args2.workspaceId !== environment2.workspace.id || args2.machineId !== environment2.auth.machineId)
173225
+ throw new Error("Target machine is unavailable in this workspace");
173226
+ return;
173227
+ }
173139
173228
  if (args2.machineId === args2.auth.machineId) {
173140
173229
  await ensureLocalRuntimeAvailable(args2.machineId, args2.workspaceId);
173141
173230
  return;
@@ -173176,16 +173265,48 @@ async function readSessionMachineAccess(args2) {
173176
173265
  ...args2.localProjectId ? { localProjectId: args2.localProjectId } : {}
173177
173266
  });
173178
173267
  }
173268
+ const defaultMachineAccessReaders = {
173269
+ delegated: canDelegateMachineUseForCliToken,
173270
+ asTokenUser: canRequestMachineForCliToken,
173271
+ asServedRequester: canUseMachineForCliToken
173272
+ };
173273
+ async function readDelegatedMachineAccess(input2, readers = defaultMachineAccessReaders) {
173274
+ const target = {
173275
+ token: input2.token,
173276
+ workspaceId: input2.workspaceId,
173277
+ machineId: input2.machineId,
173278
+ ...input2.localProjectId ? { localProjectId: input2.localProjectId } : {}
173279
+ };
173280
+ const verdict = await readers.delegated({ ...target, requesterUserId: input2.requesterUserId });
173281
+ if (verdict) {
173282
+ return verdict;
173283
+ }
173284
+ const owner = await readers.asTokenUser({ ...target, requesterUserId: input2.tokenUserId });
173285
+ if (!owner.allowed || input2.requesterUserId === input2.tokenUserId) {
173286
+ return owner;
173287
+ }
173288
+ return await readers.asServedRequester({ ...target, requesterUserId: input2.requesterUserId });
173289
+ }
173179
173290
  async function readResolvedSessionMachineAccess(args2) {
173180
- const readAccess = args2.requester.isDelegated ? canUseMachineForCliToken : canRequestMachineForCliToken;
173181
- return await readMachineAccessWithBoundedRetry({
173182
- verify: async () => await readAccess({
173183
- token: args2.auth.token,
173291
+ const environment2 = getSessionCommandEnvironment();
173292
+ if (environment2) {
173293
+ if (args2.auth !== environment2.auth) throw new Error("Session command identity mismatch");
173294
+ return environment2.checkMachineAccess({
173184
173295
  workspaceId: args2.workspaceId,
173185
173296
  machineId: args2.machineId,
173186
173297
  requesterUserId: args2.requester.userId,
173187
- ...args2.localProjectId ? { localProjectId: args2.localProjectId } : {}
173188
- }),
173298
+ localProjectId: args2.localProjectId
173299
+ });
173300
+ }
173301
+ const target = {
173302
+ token: args2.auth.token,
173303
+ workspaceId: args2.workspaceId,
173304
+ machineId: args2.machineId,
173305
+ requesterUserId: args2.requester.userId,
173306
+ ...args2.localProjectId ? { localProjectId: args2.localProjectId } : {}
173307
+ };
173308
+ return await readMachineAccessWithBoundedRetry({
173309
+ verify: async () => args2.requester.isDelegated ? await readDelegatedMachineAccess({ ...target, tokenUserId: args2.auth.userId }) : await canRequestMachineForCliToken(target),
173189
173310
  onRetry: ({ attempt, maxAttempts, delayMs, error: error2 }) => {
173190
173311
  getLogger("session").warn(
173191
173312
  `Machine access verification unavailable; retrying (attempt=${attempt}/${maxAttempts} delayMs=${delayMs}): ${error2}`
@@ -173200,6 +173321,11 @@ async function assertMachineAccess(args2) {
173200
173321
  }
173201
173322
  }
173202
173323
  async function dispatchTurnFastPath(args2) {
173324
+ const environment2 = getSessionCommandEnvironment();
173325
+ if (environment2) {
173326
+ await environment2.host.dispatchSession(args2.sessionId);
173327
+ return;
173328
+ }
173203
173329
  if (!args2.inputConfig) {
173204
173330
  return;
173205
173331
  }
@@ -173430,6 +173556,8 @@ async function resolveAgentConfigForCreate(args2) {
173430
173556
  );
173431
173557
  }
173432
173558
  async function assertGitHubRepoAccess(args2) {
173559
+ if (getSessionCommandEnvironment())
173560
+ throw new Error("Hosted repository contexts are unavailable; use a registered local project.");
173433
173561
  const repos = await listWorkspaceGitHubRepositoriesForCliToken({
173434
173562
  token: args2.auth.token,
173435
173563
  workspaceId: args2.workspaceId,
@@ -174175,6 +174303,22 @@ async function readSessionLiveStatus(args2) {
174175
174303
  }
174176
174304
  }
174177
174305
  async function readSessionLiveStatusesMany(args2) {
174306
+ const environment2 = getSessionCommandEnvironment();
174307
+ if (environment2) {
174308
+ const output2 = /* @__PURE__ */ new Map();
174309
+ for (const session2 of args2.sessions) {
174310
+ output2.set(
174311
+ session2.id,
174312
+ session2.machineId === environment2.auth.machineId ? await environment2.host.readLiveStatus(session2.id) : {
174313
+ sessionId: session2.id,
174314
+ machineOnline: false,
174315
+ fresh: false,
174316
+ reason: "Machine unavailable in local workspace"
174317
+ }
174318
+ );
174319
+ }
174320
+ return output2;
174321
+ }
174178
174322
  const groups = /* @__PURE__ */ new Map();
174179
174323
  for (const session2 of args2.sessions) {
174180
174324
  const group = groups.get(session2.machineId) ?? [];
@@ -175019,6 +175163,7 @@ const session = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
175019
175163
  normalizeLocalProjectPathSelector,
175020
175164
  prepareSessionInput,
175021
175165
  readAgentAcpCapability,
175166
+ readDelegatedMachineAccess,
175022
175167
  readLocalProjectGitStateOnMachine,
175023
175168
  readSessionLiveStatusesMany,
175024
175169
  readSessionMachineAccess,
@@ -185761,7 +185906,14 @@ class MessageHandler {
185761
185906
  dispatchWatcher: this.sessionDispatchWatcher,
185762
185907
  userResolver: this.sessionUserResolver,
185763
185908
  logger: this.logger,
185764
- materializeTarget: async (operation, item, index) => await this.materializeOperationTarget(operation, item, index)
185909
+ ...this.cloudPort.kind === "local" ? {
185910
+ confirmTargetReadable: async () => {
185911
+ await this.workspaceDocument.repo.flush();
185912
+ }
185913
+ } : {},
185914
+ materializeTarget: async (operation, item, index) => await this.withSessionCommandEnvironment(
185915
+ () => this.materializeOperationTarget(operation, item, index)
185916
+ )
185765
185917
  });
185766
185918
  this.setupSessionEventHandlers();
185767
185919
  this.setupSessionLifecycleWatchers();
@@ -187348,7 +187500,7 @@ class MessageHandler {
187348
187500
  if (!prompt2) {
187349
187501
  throw new Error(`Operation ${operation.operationId} item ${index} has no prompt.`);
187350
187502
  }
187351
- const auth = {
187503
+ const auth = getSessionCommandEnvironment()?.auth ?? {
187352
187504
  token: this.token,
187353
187505
  userId: this.userId,
187354
187506
  userName: this.userId,
@@ -189681,6 +189833,61 @@ class MessageHandler {
189681
189833
  const ownerUserId = args2.ownerMeta?.userId?.trim();
189682
189834
  return requester === ownerUserId || requester === this.userId;
189683
189835
  }
189836
+ withSessionCommandEnvironment(run2) {
189837
+ if (this.cloudPort.kind !== "local") return run2();
189838
+ return runWithSessionCommandEnvironment(
189839
+ createLocalSessionCommandEnvironment({
189840
+ manager: this.workspaceDocument,
189841
+ workspaceId: this.workspaceId,
189842
+ machineId: this.machineId,
189843
+ machineName: this.machineName,
189844
+ userId: this.userId,
189845
+ host: {
189846
+ readInvocation: (sessionId) => {
189847
+ const invocation = this.executionService.getActiveInvocationContext(sessionId);
189848
+ return invocation ? {
189849
+ type: "session/active-invocation-context",
189850
+ sessionId,
189851
+ active: true,
189852
+ ...invocation
189853
+ } : { type: "session/active-invocation-context", sessionId, active: false };
189854
+ },
189855
+ readLiveStatus: async (sessionId) => {
189856
+ const live = resolveSessionLiveStatus({
189857
+ presence: this.sessionActivePresence.getStatus(sessionId),
189858
+ execution: this.executionService.getExecutionSnapshot(sessionId),
189859
+ hasPendingDispatch: this.sessionDispatchWatcher.hasPendingDispatch(sessionId)
189860
+ });
189861
+ return {
189862
+ sessionId,
189863
+ machineOnline: true,
189864
+ fresh: true,
189865
+ state: live.state,
189866
+ observedAt: getServerNow()
189867
+ };
189868
+ },
189869
+ cancelSession: async (sessionId, turnId) => {
189870
+ const targetTurnId = turnId ?? this.executionService.getExecutionSnapshot(sessionId).activeTurnId;
189871
+ if (!targetTurnId) return { success: false, error: "Session has no active turn" };
189872
+ return this.executionService.cancelSession(
189873
+ {
189874
+ type: "session/cancel",
189875
+ machineId: this.machineId,
189876
+ workspaceId: this.workspaceId,
189877
+ sessionId,
189878
+ turnId: targetTurnId
189879
+ },
189880
+ { pendingInput: "promote", prePromptSession: "discard" }
189881
+ );
189882
+ },
189883
+ dispatchSession: async (sessionId) => {
189884
+ void this.sessionDispatchWatcher.enqueueSessionCheck(sessionId);
189885
+ }
189886
+ }
189887
+ }),
189888
+ run2
189889
+ );
189890
+ }
189684
189891
  async handleLocalMachineRpc(request2) {
189685
189892
  try {
189686
189893
  const result = await this.dispatchLocalMachineRpc(request2);
@@ -189707,6 +189914,27 @@ class MessageHandler {
189707
189914
  }
189708
189915
  };
189709
189916
  switch (request2.method) {
189917
+ case "session/call-tool": {
189918
+ if (this.cloudPort.kind !== "local")
189919
+ throw new Error("Daemon Session tools require a local workspace");
189920
+ const { sessionId, name: name2, arguments: args2 } = request2.params;
189921
+ if (request2.workspaceId !== this.workspaceId || request2.machineId !== this.machineId || request2.ownerSessionId !== sessionId)
189922
+ throw new Error("Session tool scope mismatch");
189923
+ const { executeDaemonSessionTool } = await import("./chunks/daemon-session-tools-BeXk1A1E.js");
189924
+ return this.withSessionCommandEnvironment(
189925
+ () => executeDaemonSessionTool(
189926
+ {
189927
+ machineId: this.machineId,
189928
+ workspaceId: this.workspaceId,
189929
+ sessionId,
189930
+ localControlSocketPath: void 0,
189931
+ workdir: process.cwd()
189932
+ },
189933
+ name2,
189934
+ args2
189935
+ )
189936
+ );
189937
+ }
189710
189938
  case "code-collab/get-file-index":
189711
189939
  await assertOwner(request2.params.sessionId);
189712
189940
  return await this.codeCollabV2Service.getFileIndex(request2.params);
@@ -194750,6 +194978,11 @@ class GitCredentialBroker {
194750
194978
  this.startHealthCheck();
194751
194979
  return this.env;
194752
194980
  }
194981
+ /** Rotate only sessions that opted into managed credentials during preparation. */
194982
+ refreshSessionContext(context2) {
194983
+ if (!this.sessionContextTokens.has(context2.sessionId)) return void 0;
194984
+ return this.activateSessionContext(context2);
194985
+ }
194753
194986
  activateSessionContext(context2) {
194754
194987
  const existingToken = this.sessionContextTokens.get(context2.sessionId);
194755
194988
  if (existingToken) {
@@ -198262,6 +198495,7 @@ class SessionManager extends EventEmitter {
198262
198495
  });
198263
198496
  }
198264
198497
  async prepareGitHubRepoSessionConfig(config2) {
198498
+ if (config2.project?.kind === "local") return;
198265
198499
  const githubRepo = config2.githubRepo ?? tryDeriveGitHubRepoFromUrl(config2.githubRepoUrl);
198266
198500
  if (githubRepo) {
198267
198501
  config2.githubRepo = githubRepo;
@@ -198340,7 +198574,7 @@ class SessionManager extends EventEmitter {
198340
198574
  };
198341
198575
  }
198342
198576
  async refreshGhTokenForSession(session2, _githubRepo, requesterUserId) {
198343
- const contextToken = this.gitCredentialBroker?.activateSessionContext({
198577
+ const contextToken = this.gitCredentialBroker?.refreshSessionContext({
198344
198578
  sessionId: session2.sessionId,
198345
198579
  requesterUserId,
198346
198580
  machineId: this.machineId
@@ -233902,7 +234136,7 @@ async function runRender(file2, options) {
233902
234136
  data = createReviewBundleSnapshot(bundle);
233903
234137
  }
233904
234138
  const { injectReviewSnapshot } = await import("./chunks/index-BeRTvYK1.js");
233905
- const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-CEUQAboP.js");
234139
+ const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-B6wZ9fN1.js");
233906
234140
  const template = await resolveReviewViewerTemplate();
233907
234141
  const html = injectReviewSnapshot(template, data);
233908
234142
  const outputPath = options.output ? path__default.resolve(options.output) : defaultHtmlOutputPath(inputPath);
@@ -252338,7 +252572,7 @@ async function configureWorkspaceMcpServer(manager, workspaceId, userId, rawInpu
252338
252572
  };
252339
252573
  });
252340
252574
  }
252341
- function registerDiscoveryTools(server, withDiscovery) {
252575
+ function registerDiscoveryTools(registerTool, withDiscovery) {
252342
252576
  const descriptions = {
252343
252577
  machine: "List readable machines, including offline machines, with online/offline/unknown presence and protocol capabilities.",
252344
252578
  project: "List readable local projects across machines and enabled GitHub repositories. kind and machineId restrict the catalog. Local project identity includes machineId.",
@@ -252364,7 +252598,7 @@ function registerDiscoveryTools(server, withDiscovery) {
252364
252598
  }
252365
252599
  };
252366
252600
  for (const resource of Object.keys(ResourceListSchemas)) {
252367
- server.registerTool(
252601
+ registerTool(
252368
252602
  `lody_${resource}_list`,
252369
252603
  {
252370
252604
  description: `${descriptions[resource]} Returns a bounded page (default 20, maximum 100); follow nextCursor with the same filters to enumerate all entries.`,
@@ -252375,7 +252609,7 @@ function registerDiscoveryTools(server, withDiscovery) {
252375
252609
  );
252376
252610
  }
252377
252611
  for (const resource of ["agent_config", "agent_role"]) {
252378
- server.registerTool(
252612
+ registerTool(
252379
252613
  `lody_${resource}_get`,
252380
252614
  {
252381
252615
  description: `Read one ${resource} by stable id from its list tool.`,
@@ -252386,6 +252620,20 @@ function registerDiscoveryTools(server, withDiscovery) {
252386
252620
  );
252387
252621
  }
252388
252622
  }
252623
+ function createSessionToolRegistrar(server, route2, handlers) {
252624
+ return (name2, config2, callback) => {
252625
+ handlers?.set(name2, async (args2) => callback(await config2.inputSchema.parseAsync(args2)));
252626
+ const inputSchema = config2.inputSchema;
252627
+ return server.registerTool(
252628
+ name2,
252629
+ { ...config2, inputSchema },
252630
+ async (args2) => (
252631
+ // The SDK has already parsed MCP input; only direct daemon calls need parsing here.
252632
+ route2(name2, args2, () => callback(args2))
252633
+ )
252634
+ );
252635
+ };
252636
+ }
252389
252637
  const PREVIEW_TOOL_NAME = "lody_report_preview_candidate";
252390
252638
  const IMAGE_UPLOAD_TOOL_NAME = "lody_upload_images";
252391
252639
  const FILE_UPLOAD_TOOL_NAME = "lody_upload_files";
@@ -252850,6 +253098,8 @@ const postSessionControl = async (request2, localControlSocketPath, timeoutMs =
252850
253098
  return responses.map((response2) => LocalSessionControlResponseSchema.parse(response2));
252851
253099
  };
252852
253100
  const readActiveInvocationContext = async (ctx) => {
253101
+ const environment2 = getSessionCommandEnvironment();
253102
+ if (environment2) return environment2.host.readInvocation(ctx.sessionId);
252853
253103
  const response2 = await runPromise(
252854
253104
  makeLocalControlClientAuto({ socketPath: ctx.localControlSocketPath }).machineRpc(
252855
253105
  {
@@ -253035,13 +253285,6 @@ const resolveMcpSessionCreate = (input2, invoking, requester, role) => {
253035
253285
  );
253036
253286
  }
253037
253287
  const project = requester.project;
253038
- if (project?.kind !== "github" && role.machineId !== requester.machineId) {
253039
- throw new LodyOperationStoreError(
253040
- "AGENT_ROLE_MACHINE_MISMATCH",
253041
- project?.kind === "local" ? `Agent Role ${role.name} must run on the Local Project's Machine.` : `Agent Role ${role.name} must run on the current Machine in a chat Session.`,
253042
- false
253043
- );
253044
- }
253045
253288
  let useCurrentSessionAsParent = input2.useCurrentSessionAsParent;
253046
253289
  let workContext = input2.workContext;
253047
253290
  if (project?.kind === "github" && useCurrentSessionAsParent !== true && workContext === void 0) {
@@ -253050,7 +253293,7 @@ const resolveMcpSessionCreate = (input2, invoking, requester, role) => {
253050
253293
  repo: project.repoFullName,
253051
253294
  ...project.branch ? { branch: project.branch } : {}
253052
253295
  };
253053
- } else if (project?.kind === "local" && useCurrentSessionAsParent === void 0 && workContext === void 0) {
253296
+ } else if (project?.kind === "local" && role.machineId === requester.machineId && useCurrentSessionAsParent === void 0 && workContext === void 0) {
253054
253297
  useCurrentSessionAsParent = true;
253055
253298
  }
253056
253299
  const resolvedInput = {
@@ -253851,7 +254094,7 @@ const buildSessionCreateOptions = async (input2) => {
253851
254094
  )
253852
254095
  );
253853
254096
  const repoQuery = normalizeCliValue(input2.repoQuery)?.toLowerCase();
253854
- const repos = repoQuery ? (await listWorkspaceGitHubRepositoriesForCliToken({
254097
+ const repos = repoQuery && !getSessionCommandEnvironment() ? (await listWorkspaceGitHubRepositoriesForCliToken({
253855
254098
  token: auth.token,
253856
254099
  workspaceId,
253857
254100
  requesterUserId,
@@ -254731,6 +254974,9 @@ const ReviewSubmitToolInputSchema = object({
254731
254974
  summary: string$1().trim().max(2e3).optional()
254732
254975
  }).strict();
254733
254976
  function buildLodyMcpServer() {
254977
+ return buildSessionToolServer();
254978
+ }
254979
+ function buildSessionToolServer(handlers) {
254734
254980
  initCliAnalytics();
254735
254981
  const server = new McpServer(
254736
254982
  {
@@ -254755,10 +255001,41 @@ function buildLodyMcpServer() {
254755
255001
  });
254756
255002
  }
254757
255003
  });
254758
- registerDiscoveryTools(server, async (read) => {
254759
- if (getCliPlatformKind() === "local") {
254760
- throw new Error("Workspace catalog discovery is unavailable on the local platform.");
254761
- }
255004
+ const registerSessionTool = createSessionToolRegistrar(
255005
+ server,
255006
+ async (name2, args2, execute) => {
255007
+ if (getCliPlatformKind() !== "local" || getSessionCommandEnvironment()) return execute();
255008
+ try {
255009
+ const ctx = getSessionContext();
255010
+ const outcome = await runPromise(
255011
+ makeLocalControlClientAuto({ socketPath: ctx.localControlSocketPath }).machineRpc(
255012
+ {
255013
+ method: "session/call-tool",
255014
+ machineId: ctx.machineId,
255015
+ workspaceId: ctx.workspaceId,
255016
+ ownerSessionId: ctx.sessionId,
255017
+ params: {
255018
+ sessionId: ctx.sessionId,
255019
+ name: name2,
255020
+ arguments: record$3(string$1(), json$1()).parse(args2)
255021
+ }
255022
+ },
255023
+ { timeoutMs: SESSION_CONTROL_TIMEOUT_MS }
255024
+ ).pipe(either)
255025
+ );
255026
+ if (outcome._tag === "Left") throw classifyLocalDaemonIpcError(outcome.left);
255027
+ const response2 = outcome.right;
255028
+ if (!response2.ok) throw new Error(response2.error);
255029
+ if (!("type" in response2.result) || response2.result.type !== "session/tool-result")
255030
+ throw new Error("Unexpected Session tool response");
255031
+ return { content: response2.result.content, isError: response2.result.isError };
255032
+ } catch (error2) {
255033
+ return mcpErrorResult(error2);
255034
+ }
255035
+ },
255036
+ handlers
255037
+ );
255038
+ registerDiscoveryTools(registerSessionTool, async (read) => {
254762
255039
  const ctx = getSessionContext();
254763
255040
  const source2 = await resolveInvokingTurnSource();
254764
255041
  const auth = getAuthContextOrThrow$1("mcp");
@@ -254772,7 +255049,6 @@ function buildLodyMcpServer() {
254772
255049
  manager,
254773
255050
  auth,
254774
255051
  workspaceId: workspace.id,
254775
- requesterSessionId: ctx.sessionId,
254776
255052
  delegatedRequester: { userId: source2.userId },
254777
255053
  selectedMcpServerIds: source2.inputConfig.mcpServerIds
254778
255054
  })
@@ -255014,7 +255290,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255014
255290
  }
255015
255291
  }
255016
255292
  );
255017
- server.registerTool(
255293
+ registerSessionTool(
255018
255294
  SESSION_CREATE_OPTIONS_TOOL_NAME,
255019
255295
  {
255020
255296
  title: "List session create options",
@@ -255029,11 +255305,11 @@ ${lines2.join("\n")}` : ""}${suffix}`
255029
255305
  }
255030
255306
  }
255031
255307
  );
255032
- server.registerTool(
255308
+ registerSessionTool(
255033
255309
  SESSION_CREATE_TOOL_NAME,
255034
255310
  {
255035
255311
  title: "Create a Lody session",
255036
- description: "Start durable asynchronous work that creates a Lody session. Supply operationId; the result arrives automatically as a continuation, so do not poll operation_get. To use an Agent Role, pass agentRoleId; the current workspace catalog row supplies the exact Machine, Agent config, model, reasoning, and permission mode. If manual machine or run-config fields are also present, the Role takes precedence and those fields are ignored. To recover an already accepted create without resending its prompt, send only operationId with resume=true. useCurrentSessionAsParent=true and workContext are mutually exclusive schema branches. Machine/config ids and runConfig values for non-Role creates come from lody_session_create_options. The wait field is temporary legacy compatibility only.",
255312
+ description: "Start durable asynchronous work that creates a Lody session. Supply operationId; the result arrives automatically as a continuation, so do not poll operation_get. To use an Agent Role, pass agentRoleId; the current workspace catalog row supplies the exact Machine, Agent config, model, reasoning, and permission mode. If manual machine or run-config fields are also present, the Role takes precedence and those fields are ignored. A Role may run on any Machine the owner of this Machine can use; to work in a project there, pass workContext for a local project on that Machine (find it with lody_session_create_options machineId + localProjectQuery). Without workContext a Role on another Machine starts as a plain chat there. To recover an already accepted create without resending its prompt, send only operationId with resume=true. useCurrentSessionAsParent=true and workContext are mutually exclusive schema branches. Machine/config ids and runConfig values for non-Role creates come from lody_session_create_options. The wait field is temporary legacy compatibility only.",
255037
255313
  inputSchema: SessionCreateToolInputSchema
255038
255314
  },
255039
255315
  async (input2) => {
@@ -255117,7 +255393,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255117
255393
  }
255118
255394
  }
255119
255395
  );
255120
- server.registerTool(
255396
+ registerSessionTool(
255121
255397
  SESSION_CHAT_TOOL_NAME,
255122
255398
  {
255123
255399
  title: "Send a prompt to a Lody session",
@@ -255180,7 +255456,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255180
255456
  }
255181
255457
  }
255182
255458
  );
255183
- server.registerTool(
255459
+ registerSessionTool(
255184
255460
  SESSION_CREATE_MANY_TOOL_NAME,
255185
255461
  {
255186
255462
  title: "Create multiple Lody sessions",
@@ -255196,7 +255472,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255196
255472
  }
255197
255473
  }
255198
255474
  );
255199
- server.registerTool(
255475
+ registerSessionTool(
255200
255476
  SESSION_CHAT_MANY_TOOL_NAME,
255201
255477
  {
255202
255478
  title: "Chat multiple Lody sessions",
@@ -255211,7 +255487,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255211
255487
  }
255212
255488
  }
255213
255489
  );
255214
- server.registerTool(
255490
+ registerSessionTool(
255215
255491
  SESSION_CANCEL_TOOL_NAME,
255216
255492
  {
255217
255493
  title: "Cancel a Lody session turn",
@@ -255223,6 +255499,14 @@ ${lines2.join("\n")}` : ""}${suffix}`
255223
255499
  const ctx = getSessionContext();
255224
255500
  const auth = getAuthContextOrThrow$1("mcp");
255225
255501
  await resolveWorkspaceOrThrow$1(auth, getMcpWorkspaceId(ctx));
255502
+ const environment2 = getSessionCommandEnvironment();
255503
+ if (environment2) {
255504
+ const sessionId = resolveMcpSessionId(args2.sessionId, ctx);
255505
+ const session2 = await readCurrentSessionMeta(environment2.manager, sessionId);
255506
+ if (!session2 || session2.machineId !== auth.machineId)
255507
+ throw new Error("Session not found on this machine");
255508
+ return jsonTextResult(await environment2.host.cancelSession(sessionId));
255509
+ }
255226
255510
  return jsonTextResult(
255227
255511
  await runLodyCliJson([
255228
255512
  "session",
@@ -255238,7 +255522,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255238
255522
  }
255239
255523
  }
255240
255524
  );
255241
- server.registerTool(
255525
+ registerSessionTool(
255242
255526
  "lody_operation_list",
255243
255527
  {
255244
255528
  description: "List durable Operation summaries owned by the current Session and invoking user. Optional state filter and keyset pagination. Completion is automatic; do not poll.",
@@ -255266,7 +255550,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255266
255550
  }
255267
255551
  }
255268
255552
  );
255269
- server.registerTool(
255553
+ registerSessionTool(
255270
255554
  OPERATION_GET_TOOL_NAME,
255271
255555
  {
255272
255556
  title: "Get a Lody Operation snapshot",
@@ -255284,7 +255568,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255284
255568
  }
255285
255569
  }
255286
255570
  );
255287
- server.registerTool(
255571
+ registerSessionTool(
255288
255572
  OPERATION_CANCEL_TOOL_NAME,
255289
255573
  {
255290
255574
  title: "Cancel a Lody Operation",
@@ -255302,12 +255586,13 @@ ${lines2.join("\n")}` : ""}${suffix}`
255302
255586
  (store) => store.cancel(requesterSessionId, args2.operationId)
255303
255587
  );
255304
255588
  if (cancellation.didCancel && before.state === "active") {
255589
+ const environment2 = getSessionCommandEnvironment();
255305
255590
  const startedTargets = before.items.filter(
255306
255591
  (item) => item.status === "active" && item.inputDurable
255307
255592
  );
255308
255593
  await Promise.allSettled(
255309
255594
  startedTargets.map(
255310
- (item) => item.status === "active" ? runLodyCliJson(buildOperationTargetCancelArgs(getMcpWorkspaceId(ctx), item)) : Promise.resolve()
255595
+ (item) => item.status === "active" ? environment2 ? environment2.host.cancelSession(item.target.sessionId, item.target.userTurnId) : runLodyCliJson(buildOperationTargetCancelArgs(getMcpWorkspaceId(ctx), item)) : Promise.resolve()
255311
255596
  )
255312
255597
  );
255313
255598
  }
@@ -255319,7 +255604,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255319
255604
  }
255320
255605
  }
255321
255606
  );
255322
- server.registerTool(
255607
+ registerSessionTool(
255323
255608
  SESSION_RENAME_TOOL_NAME,
255324
255609
  {
255325
255610
  title: "Rename a Lody session",
@@ -255340,7 +255625,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255340
255625
  }
255341
255626
  }
255342
255627
  );
255343
- server.registerTool(
255628
+ registerSessionTool(
255344
255629
  SESSION_RENAME_MANY_TOOL_NAME,
255345
255630
  {
255346
255631
  title: "Rename multiple Lody sessions",
@@ -255386,7 +255671,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255386
255671
  }
255387
255672
  }
255388
255673
  );
255389
- server.registerTool(
255674
+ registerSessionTool(
255390
255675
  SESSION_LIST_TOOL_NAME,
255391
255676
  {
255392
255677
  title: "List Lody sessions",
@@ -255401,7 +255686,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255401
255686
  }
255402
255687
  }
255403
255688
  );
255404
- server.registerTool(
255689
+ registerSessionTool(
255405
255690
  SESSION_STATUS_MANY_TOOL_NAME,
255406
255691
  {
255407
255692
  title: "Get Lody session statuses",
@@ -255416,7 +255701,7 @@ ${lines2.join("\n")}` : ""}${suffix}`
255416
255701
  }
255417
255702
  }
255418
255703
  );
255419
- server.registerTool(
255704
+ registerSessionTool(
255420
255705
  SESSION_HISTORY_TOOL_NAME,
255421
255706
  {
255422
255707
  title: "Read Lody session history",
@@ -257141,7 +257426,13 @@ void (async () => {
257141
257426
  }
257142
257427
  })();
257143
257428
  export {
257429
+ SessionToolResultSchema as S,
257430
+ getSessionCommandEnvironment as a,
257431
+ getSessionRoomId as b,
257432
+ buildSessionToolServer as c,
257144
257433
  program as default,
257145
- getLodyDataDir as g
257434
+ getLodyDataDir as g,
257435
+ isLoroRepoDocDeleted as i,
257436
+ runWithMcpSessionContext as r
257146
257437
  };
257147
257438
  //# sourceMappingURL=index.js.map