@aiden-ade/sandbox-agent 0.1.53 → 0.1.55

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.
Files changed (2) hide show
  1. package/dist/index.cjs +1457 -690
  2. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -7761,7 +7761,7 @@ var require_compile = __commonJS({
7761
7761
  const schOrFunc = root.refs[ref];
7762
7762
  if (schOrFunc)
7763
7763
  return schOrFunc;
7764
- let _sch = resolve7.call(this, root, ref);
7764
+ let _sch = resolve9.call(this, root, ref);
7765
7765
  if (_sch === void 0) {
7766
7766
  const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
7767
7767
  const { schemaId } = this.opts;
@@ -7788,7 +7788,7 @@ var require_compile = __commonJS({
7788
7788
  function sameSchemaEnv(s1, s2) {
7789
7789
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
7790
7790
  }
7791
- function resolve7(root, ref) {
7791
+ function resolve9(root, ref) {
7792
7792
  let sch;
7793
7793
  while (typeof (sch = this.refs[ref]) == "string")
7794
7794
  ref = sch;
@@ -8419,55 +8419,55 @@ var require_fast_uri = __commonJS({
8419
8419
  }
8420
8420
  return uri;
8421
8421
  }
8422
- function resolve7(baseURI, relativeURI, options) {
8422
+ function resolve9(baseURI, relativeURI, options) {
8423
8423
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
8424
8424
  const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
8425
8425
  schemelessOptions.skipEscape = true;
8426
8426
  return serialize(resolved, schemelessOptions);
8427
8427
  }
8428
- function resolveComponent(base, relative3, options, skipNormalization) {
8428
+ function resolveComponent(base, relative4, options, skipNormalization) {
8429
8429
  const target = {};
8430
8430
  if (!skipNormalization) {
8431
8431
  base = parse6(serialize(base, options), options);
8432
- relative3 = parse6(serialize(relative3, options), options);
8432
+ relative4 = parse6(serialize(relative4, options), options);
8433
8433
  }
8434
8434
  options = options || {};
8435
- if (!options.tolerant && relative3.scheme) {
8436
- target.scheme = relative3.scheme;
8437
- target.userinfo = relative3.userinfo;
8438
- target.host = relative3.host;
8439
- target.port = relative3.port;
8440
- target.path = removeDotSegments(relative3.path || "");
8441
- target.query = relative3.query;
8435
+ if (!options.tolerant && relative4.scheme) {
8436
+ target.scheme = relative4.scheme;
8437
+ target.userinfo = relative4.userinfo;
8438
+ target.host = relative4.host;
8439
+ target.port = relative4.port;
8440
+ target.path = removeDotSegments(relative4.path || "");
8441
+ target.query = relative4.query;
8442
8442
  } else {
8443
- if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
8444
- target.userinfo = relative3.userinfo;
8445
- target.host = relative3.host;
8446
- target.port = relative3.port;
8447
- target.path = removeDotSegments(relative3.path || "");
8448
- target.query = relative3.query;
8443
+ if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
8444
+ target.userinfo = relative4.userinfo;
8445
+ target.host = relative4.host;
8446
+ target.port = relative4.port;
8447
+ target.path = removeDotSegments(relative4.path || "");
8448
+ target.query = relative4.query;
8449
8449
  } else {
8450
- if (!relative3.path) {
8450
+ if (!relative4.path) {
8451
8451
  target.path = base.path;
8452
- if (relative3.query !== void 0) {
8453
- target.query = relative3.query;
8452
+ if (relative4.query !== void 0) {
8453
+ target.query = relative4.query;
8454
8454
  } else {
8455
8455
  target.query = base.query;
8456
8456
  }
8457
8457
  } else {
8458
- if (relative3.path[0] === "/") {
8459
- target.path = removeDotSegments(relative3.path);
8458
+ if (relative4.path[0] === "/") {
8459
+ target.path = removeDotSegments(relative4.path);
8460
8460
  } else {
8461
8461
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
8462
- target.path = "/" + relative3.path;
8462
+ target.path = "/" + relative4.path;
8463
8463
  } else if (!base.path) {
8464
- target.path = relative3.path;
8464
+ target.path = relative4.path;
8465
8465
  } else {
8466
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
8466
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
8467
8467
  }
8468
8468
  target.path = removeDotSegments(target.path);
8469
8469
  }
8470
- target.query = relative3.query;
8470
+ target.query = relative4.query;
8471
8471
  }
8472
8472
  target.userinfo = base.userinfo;
8473
8473
  target.host = base.host;
@@ -8475,7 +8475,7 @@ var require_fast_uri = __commonJS({
8475
8475
  }
8476
8476
  target.scheme = base.scheme;
8477
8477
  }
8478
- target.fragment = relative3.fragment;
8478
+ target.fragment = relative4.fragment;
8479
8479
  return target;
8480
8480
  }
8481
8481
  function equal(uriA, uriB, options) {
@@ -8677,7 +8677,7 @@ var require_fast_uri = __commonJS({
8677
8677
  var fastUri = {
8678
8678
  SCHEMES,
8679
8679
  normalize,
8680
- resolve: resolve7,
8680
+ resolve: resolve9,
8681
8681
  resolveComponent,
8682
8682
  equal,
8683
8683
  serialize,
@@ -11703,9 +11703,7 @@ var PROVIDER_ALIASES = {
11703
11703
  agy: "antigravity_cli",
11704
11704
  antigravity: "antigravity_cli",
11705
11705
  antigravity_cli: "antigravity_cli",
11706
- codex: "codex_app_server",
11707
- gemini: "antigravity_cli",
11708
- gemini_cli: "antigravity_cli"
11706
+ codex: "codex_app_server"
11709
11707
  };
11710
11708
  var BACKEND_CLI_COMMANDS = {
11711
11709
  claude_cli: "claude",
@@ -11716,11 +11714,10 @@ var BACKEND_CLI_COMMANDS = {
11716
11714
  agy: "agy",
11717
11715
  antigravity: "agy",
11718
11716
  antigravity_cli: "agy",
11719
- gemini_cli: "agy",
11720
- gemini: "agy",
11721
11717
  kimi_cli: "kimi-cli",
11722
11718
  grok_cli: "grok",
11723
11719
  opencode_cli: "opencode",
11720
+ opencode_serve: "opencode",
11724
11721
  droid_cli: "droid",
11725
11722
  supatest_cli: "supatest"
11726
11723
  };
@@ -11812,7 +11809,7 @@ function resolveViaWhere(command, env) {
11812
11809
  return null;
11813
11810
  }
11814
11811
  function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3, spawnOptions) {
11815
- return new Promise((resolve7) => {
11812
+ return new Promise((resolve9) => {
11816
11813
  const isWin = (0, import_node_os.platform)() === "win32";
11817
11814
  let command = executable;
11818
11815
  let commandArgs = args;
@@ -11832,7 +11829,7 @@ function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3
11832
11829
  stdio: closeStdin ? ["pipe", "pipe", "pipe"] : void 0
11833
11830
  });
11834
11831
  } catch (error2) {
11835
- resolve7({ status: null, stdout: "", stderr: "", error: error2 });
11832
+ resolve9({ status: null, stdout: "", stderr: "", error: error2 });
11836
11833
  return;
11837
11834
  }
11838
11835
  if (closeStdin) {
@@ -11846,10 +11843,10 @@ function runCliProbeAsync(executable, env, args = ["--version"], timeoutMs = 3e3
11846
11843
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
11847
11844
  stderr += chunk;
11848
11845
  });
11849
- child.once("error", (error2) => resolve7({ status: null, stdout, stderr, error: error2 }));
11846
+ child.once("error", (error2) => resolve9({ status: null, stdout, stderr, error: error2 }));
11850
11847
  child.once(
11851
11848
  "close",
11852
- (status, signal) => resolve7({ status, stdout, stderr, signal: signal ?? null })
11849
+ (status, signal) => resolve9({ status, stdout, stderr, signal: signal ?? null })
11853
11850
  );
11854
11851
  });
11855
11852
  }
@@ -12161,7 +12158,7 @@ You MUST NOT call these tools:
12161
12158
 
12162
12159
  You MUST NOT call \`start_task_session\` before you have written a plan or requirements document. Delegate only after scope is defined.
12163
12160
 
12164
- Read-only inspection is fine when you need to understand what exists.
12161
+ Read-only inspection is fine when you need to understand what exists \u2014 but check the platform first. See "Platform tools come before local tools" below.
12165
12162
 
12166
12163
  ## Platform document policy
12167
12164
 
@@ -12169,13 +12166,37 @@ Platform Documents are the default destination and source of truth for PM work.
12169
12166
 
12170
12167
  Do NOT call \`create_plan\`, \`create_document_artifact\`, or another artifact-creation tool unless the user explicitly asks for an **artifact**. If \`create_document\` is unavailable or fails, report that blocker; do not silently substitute an artifact.
12171
12168
 
12172
- ## How to access docs
12169
+ ## Platform tools come before local tools
12173
12170
 
12174
- When asked to access, check, consult, or answer from docs, use this order:
12175
- 1. **Platform Documents first** \u2014 use \`list_documents\` or \`search\` to locate the relevant platform document, then \`get_document\` to read it. If a document ID is already known, call \`get_document\` directly.
12176
- 2. **Local repository docs only as fallback** \u2014 read \`README.md\`, \`AGENTS.md\`, \`notes/\`, or \`docs/\` only when no relevant platform document exists or the platform document tools are unavailable.
12171
+ You work on the Alan platform. The platform is where product truth lives: tasks, subtasks, decisions, events, sessions, artifacts, memory, and Documents. Local files and shell commands are a **last resort**, not a starting point.
12177
12172
 
12178
- Do not inspect local repository docs first when the user asks to access docs. Cite which document answered the question and say when local fallback was necessary. If neither source covers it, say so instead of guessing.
12173
+ **Before every lookup, ask: does the platform know this?** If a platform MCP tool could plausibly answer the question, you MUST call it before any \`Read\`, \`Glob\`, \`Grep\`, or \`Bash\`. Reaching for a local tool first is a mistake even when it would be faster or you already know the file path.
12174
+
12175
+ | What you want | Use this | Not this |
12176
+ |---|---|---|
12177
+ | Requirements, PRDs, specs, notes, any written knowledge | \`list_documents\`, \`search\`, \`get_document\` | reading \`docs/\`, \`notes/\`, \`README.md\` |
12178
+ | Scope, status, priority, or history of work | \`get_task\`, \`list_subtasks\`, \`list_tasks\` | \`git log\`, commit messages |
12179
+ | What was decided and why | \`list_task_decisions\`, \`list_task_events\` | code comments, in-repo ADRs |
12180
+ | What an agent did or is doing | \`list_sessions\`, \`get_session_context\` | \`git log\`, diffing the worktree |
12181
+ | Prior agent context | \`list_agent_memory\`, \`get_task_memory\` | scratch files |
12182
+ | Outputs of completed work | \`list_artifacts\`, \`get_artifact\` | build output, generated files |
12183
+ | Where code lives or how it works | \`search_code_context\` first, then \`Read\` the cited files | \`Grep\`/\`Glob\` sweeps |
12184
+
12185
+ **If you do fall back to a local tool, say so out loud** \u2014 name the platform tool you tried and what it returned (nothing, unavailable, insufficient). A silent local read is a violation of this rule. If no platform tool was tried, you have not earned the local read.
12186
+
12187
+ Code is the exception that proves the rule: understanding how something works legitimately ends in reading source. Even then, start with \`search_code_context\` and read only the files it cites.
12188
+
12189
+ **Default for written knowledge: platform Documents.** Any request to find, check, consult, review, summarize, or answer from written knowledge resolves against platform Documents \u2014 use \`list_documents\` or \`search\` to locate it, then \`get_document\` to read it. If a document ID is already known, call \`get_document\` directly.
12190
+
12191
+ This applies no matter which word the user uses. Treat all of these as the same request: docs, documentation, documents, notes, PRD, spec, requirements, design doc, plan, proposal, RFC, wiki, runbook, onboarding, guidelines, "what did we decide", "what did we write down", "what do we have on X". The noun never changes where you look.
12192
+
12193
+ **Local repository files are off-limits for knowledge lookup** unless the user unambiguously points you at the repository. Do not read \`README.md\`, \`AGENTS.md\`, \`notes/\`, \`docs/\`, or any other in-repo file as a fallback, as corroboration, because no platform document matched, or because the user's wording happens to match a directory name.
12194
+
12195
+ A bare noun is never a pointer to the repository. "Check the notes" means platform Documents, not \`notes/\`. "Check the docs" means platform Documents, not \`docs/\`. Only these count as pointing at the repository:
12196
+ - an explicit location \u2014 "in the repo", "in the codebase", "local files", "on disk", "in the worktree"
12197
+ - a concrete path or filename \u2014 \`notes/foo.md\`, \`AGENTS.md\`, "the readme"
12198
+
12199
+ When platform Documents do not cover the question, stop and say so, then offer to check the repository. Do not read local files first, and do not guess. Cite which document answered the question.
12179
12200
 
12180
12201
  ## Your primary tools
12181
12202
 
@@ -12631,7 +12652,10 @@ function toAntigravityMcpServers(src) {
12631
12652
  const s = raw;
12632
12653
  if (typeof s.type === "string" && s.type === "http" || typeof s.url === "string") {
12633
12654
  out[name] = {
12634
- httpUrl: s.url,
12655
+ // Antigravity's current mcp_config.json schema uses `serverUrl`. Its
12656
+ // legacy settings.json integration used `httpUrl`, which the current CLI
12657
+ // intentionally does not read for MCP registration.
12658
+ serverUrl: s.url,
12635
12659
  ...s.headers && typeof s.headers === "object" && s.headers !== null && Object.keys(s.headers).length > 0 ? { headers: s.headers } : {}
12636
12660
  };
12637
12661
  } else if (typeof s.command === "string") {
@@ -12720,11 +12744,7 @@ function renderAlanMcpConfigFiles(mcpServers, home) {
12720
12744
  content: JSON.stringify({ mcpServers: toFactoryMcpServers(mcpServers) })
12721
12745
  },
12722
12746
  {
12723
- path: `${home}/.gemini/settings.json`,
12724
- content: JSON.stringify({ mcpServers: toAntigravityMcpServers(mcpServers) })
12725
- },
12726
- {
12727
- path: `${home}/.gemini/antigravity-cli/settings.json`,
12747
+ path: `${home}/.gemini/config/mcp_config.json`,
12728
12748
  content: JSON.stringify({ mcpServers: toAntigravityMcpServers(mcpServers) })
12729
12749
  },
12730
12750
  {
@@ -12747,8 +12767,9 @@ function alanMcpConfigFilesForBackend(backendKind, mcpServers, home) {
12747
12767
  case "droid_cli":
12748
12768
  return byPathSuffix("/.factory/mcp.json");
12749
12769
  case "antigravity_cli":
12750
- return byPathSuffix("/.gemini/settings.json", "/.gemini/antigravity-cli/settings.json");
12770
+ return byPathSuffix("/.gemini/config/mcp_config.json");
12751
12771
  case "opencode_cli":
12772
+ case "opencode_serve":
12752
12773
  return byPathSuffix("/.config/opencode/opencode.json");
12753
12774
  default:
12754
12775
  return all;
@@ -16926,6 +16947,7 @@ var APPLICATION_PROBLEM_CODES = [
16926
16947
  "app.dispatch.runtime_offline",
16927
16948
  "app.dispatch.delivery_failed",
16928
16949
  "app.workspace.missing",
16950
+ "app.workspace.branch_changed",
16929
16951
  "app.transport.disconnected",
16930
16952
  "app.persistence.failed",
16931
16953
  "app.service.unavailable",
@@ -16960,6 +16982,7 @@ var APPLICATION_PROBLEM_TITLES = {
16960
16982
  "app.dispatch.runtime_offline": "Runtime unavailable",
16961
16983
  "app.dispatch.delivery_failed": "Agent delivery failed",
16962
16984
  "app.workspace.missing": "Workspace unavailable",
16985
+ "app.workspace.branch_changed": "Workspace branch changed",
16963
16986
  "app.transport.disconnected": "Connection lost",
16964
16987
  "app.persistence.failed": "Persistence failed",
16965
16988
  "app.service.unavailable": "Service unavailable",
@@ -16985,6 +17008,14 @@ var APPLICATION_PROBLEM_RECOVERY = {
16985
17008
  },
16986
17009
  "app.dispatch.delivery_failed": { mode: "manual", action: "start_new_attempt", safe: false },
16987
17010
  "app.workspace.missing": { mode: "after_user_action", action: "select_workspace", safe: true },
17011
+ // Distinct from `app.workspace.missing`: the folder is exactly where it was, so
17012
+ // telling the user to relocate it sends them looking for a problem that does not
17013
+ // exist. What they need to do is restore the branch the run was pinned to.
17014
+ "app.workspace.branch_changed": {
17015
+ mode: "after_user_action",
17016
+ action: "restore_branch",
17017
+ safe: true
17018
+ },
16988
17019
  "app.transport.disconnected": { mode: "automatic", action: "reconnect", safe: true },
16989
17020
  "app.persistence.failed": { mode: "automatic", action: "reconcile", safe: true },
16990
17021
  "app.service.unavailable": { mode: "after_user_action", action: "retry", safe: true },
@@ -17310,6 +17341,55 @@ function getAlanAgentPrompt(agentId) {
17310
17341
  return getAgentSystemPrompt(agentId);
17311
17342
  }
17312
17343
 
17344
+ // ../shared/dist/constants/agent.js
17345
+ var INTERACTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
17346
+ "askuserquestion",
17347
+ "askquestion",
17348
+ "exitplanmode",
17349
+ "enterplanmode"
17350
+ ]);
17351
+ var HARNESS_ASK_TOOL_NAMES = /* @__PURE__ */ new Set(["askuserquestion", "askquestion"]);
17352
+ function normalizeToolName2(name) {
17353
+ const lower = name.toLowerCase();
17354
+ const mcp = lower.match(/^mcp__[a-z0-9-]+__(.+)$/);
17355
+ const bare = mcp ? mcp[1] : lower;
17356
+ return bare.replace(/[_\s-]/g, "");
17357
+ }
17358
+ function toolNameFromInput(input) {
17359
+ if (!input || typeof input !== "object")
17360
+ return null;
17361
+ const rec = input;
17362
+ if (typeof rec.toolName === "string" && rec.toolName.trim())
17363
+ return rec.toolName;
17364
+ if (typeof rec.name === "string" && rec.name.trim())
17365
+ return rec.name;
17366
+ return null;
17367
+ }
17368
+ function inputLooksLikeAskUserQuestion(input) {
17369
+ if (!input || typeof input !== "object")
17370
+ return false;
17371
+ const rec = input;
17372
+ const args = typeof rec.args === "object" && rec.args !== null ? rec.args : rec;
17373
+ return Array.isArray(args.questions) && args.questions.length > 0;
17374
+ }
17375
+ function isAskUserQuestionTool(name, input) {
17376
+ if (HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(name)))
17377
+ return true;
17378
+ const nested = toolNameFromInput(input);
17379
+ if (nested && nested !== name && HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(nested))) {
17380
+ return true;
17381
+ }
17382
+ return inputLooksLikeAskUserQuestion(input);
17383
+ }
17384
+ function isInteractiveToolName(name, input) {
17385
+ const normalized = normalizeToolName2(name);
17386
+ if (INTERACTIVE_TOOL_NAMES.has(normalized))
17387
+ return true;
17388
+ return isAskUserQuestionTool(name, input);
17389
+ }
17390
+ var ALAN_AGENT_WORKOS_USER_ID_PREFIX = "alan-agent:";
17391
+ var ALAN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${ALAN_AGENT_WORKOS_USER_ID_PREFIX}%`;
17392
+
17313
17393
  // ../shared/dist/effort.js
17314
17394
  var EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
17315
17395
  var CLAUDE_EFFORT_LEVELS = [
@@ -17736,6 +17816,9 @@ var PROVIDER_MODELS = {
17736
17816
  cursor_agent_cli: CURSOR_AGENT_MODELS,
17737
17817
  antigravity_cli: ANTIGRAVITY_CLI_SEED_MODELS,
17738
17818
  opencode_cli: OPENCODE_ZEN_MODELS,
17819
+ // Server transport dispatches the same "opencode" binary/models as opencode_cli —
17820
+ // share the catalog reference rather than duplicating it.
17821
+ opencode_serve: OPENCODE_ZEN_MODELS,
17739
17822
  droid_cli: [
17740
17823
  { id: "claude-opus-4-8", name: "Claude Opus 4.8" },
17741
17824
  { id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5" },
@@ -17946,17 +18029,17 @@ var CODEX_APP_SERVER_PICKER_FALLBACK_MODELS = [
17946
18029
  var ANTIGRAVITY_CLI_PICKER_FALLBACK_MODELS = [
17947
18030
  { id: "", name: "CLI default", capabilities: caps([]) },
17948
18031
  {
17949
- id: "Antigravity 3.5 Flash",
18032
+ id: "gemini-3.5-flash",
17950
18033
  name: "Antigravity 3.5 Flash",
17951
18034
  capabilities: caps(ANTIGRAVITY_EFFORT)
17952
18035
  },
17953
18036
  {
17954
- id: "Antigravity 3.1 Pro",
18037
+ id: "gemini-3.1-pro",
17955
18038
  name: "Antigravity 3.1 Pro",
17956
18039
  capabilities: caps(ANTIGRAVITY_EFFORT)
17957
18040
  },
17958
18041
  {
17959
- id: "Antigravity 3 Flash",
18042
+ id: "gemini-3-flash",
17960
18043
  name: "Antigravity 3 Flash",
17961
18044
  capabilities: caps(ANTIGRAVITY_EFFORT)
17962
18045
  },
@@ -18027,14 +18110,16 @@ var DISCOVERY_SEED_PROVIDERS = /* @__PURE__ */ new Set([
18027
18110
  "antigravity_cli",
18028
18111
  "cursor_agent_cli",
18029
18112
  "opencode_cli",
18113
+ "opencode_serve",
18030
18114
  "kimi_cli",
18031
18115
  "grok_cli",
18032
18116
  "copilot_cli",
18033
18117
  "droid_cli"
18034
18118
  ]);
18035
18119
  function baseCatalogForProvider(providerKind) {
18036
- const fallback = getProviderPickerFallbackModels(providerKind);
18037
- const staticCatalog = PROVIDER_MODELS[providerKind] ?? [];
18120
+ const catalogProvider = providerKind === "opencode_serve" ? "opencode_cli" : providerKind;
18121
+ const fallback = getProviderPickerFallbackModels(catalogProvider);
18122
+ const staticCatalog = PROVIDER_MODELS[catalogProvider] ?? [];
18038
18123
  if (staticCatalog.length === 0) {
18039
18124
  return fallback;
18040
18125
  }
@@ -18063,68 +18148,25 @@ var import_os2 = require("os");
18063
18148
  var import_path2 = require("path");
18064
18149
  var import_child_process = require("child_process");
18065
18150
  var import_fs3 = require("fs");
18066
- var import_os3 = require("os");
18067
18151
  var import_path3 = require("path");
18152
+ var import_fs4 = require("fs");
18153
+ var import_os3 = require("os");
18154
+ var import_path4 = require("path");
18068
18155
  var import_readline = require("readline");
18069
18156
  var import_crypto2 = require("crypto");
18070
18157
  var import_child_process2 = require("child_process");
18071
18158
  var import_child_process3 = require("child_process");
18072
- var import_crypto3 = require("crypto");
18073
- var import_fs4 = require("fs");
18159
+ var import_fs5 = require("fs");
18074
18160
  var import_os4 = require("os");
18075
- var import_path4 = require("path");
18161
+ var import_path5 = require("path");
18162
+ var import_url = require("url");
18163
+ var import_crypto3 = require("crypto");
18164
+ var import_fs6 = require("fs");
18165
+ var import_os5 = require("os");
18166
+ var import_path6 = require("path");
18076
18167
  var import_child_process4 = require("child_process");
18077
18168
  var import_util4 = require("util");
18078
18169
 
18079
- // ../shared/dist/constants/agent.js
18080
- var INTERACTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
18081
- "askuserquestion",
18082
- "askquestion",
18083
- "exitplanmode",
18084
- "enterplanmode"
18085
- ]);
18086
- var HARNESS_ASK_TOOL_NAMES = /* @__PURE__ */ new Set(["askuserquestion", "askquestion"]);
18087
- function normalizeToolName2(name) {
18088
- const lower = name.toLowerCase();
18089
- const mcp = lower.match(/^mcp__[a-z0-9-]+__(.+)$/);
18090
- const bare = mcp ? mcp[1] : lower;
18091
- return bare.replace(/[_\s-]/g, "");
18092
- }
18093
- function toolNameFromInput(input) {
18094
- if (!input || typeof input !== "object")
18095
- return null;
18096
- const rec = input;
18097
- if (typeof rec.toolName === "string" && rec.toolName.trim())
18098
- return rec.toolName;
18099
- if (typeof rec.name === "string" && rec.name.trim())
18100
- return rec.name;
18101
- return null;
18102
- }
18103
- function inputLooksLikeAskUserQuestion(input) {
18104
- if (!input || typeof input !== "object")
18105
- return false;
18106
- const rec = input;
18107
- const args = typeof rec.args === "object" && rec.args !== null ? rec.args : rec;
18108
- return Array.isArray(args.questions) && args.questions.length > 0;
18109
- }
18110
- function isAskUserQuestionTool(name, input) {
18111
- if (HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(name)))
18112
- return true;
18113
- const nested = toolNameFromInput(input);
18114
- if (nested && nested !== name && HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(nested))) {
18115
- return true;
18116
- }
18117
- return inputLooksLikeAskUserQuestion(input);
18118
- }
18119
- function isInteractiveToolName(name, input) {
18120
- const normalized = normalizeToolName2(name);
18121
- if (INTERACTIVE_TOOL_NAMES.has(normalized))
18122
- return true;
18123
- return isAskUserQuestionTool(name, input);
18124
- }
18125
- var ALAN_AGENT_WORKOS_USER_ID_PREFIX = "alan-agent:";
18126
- var ALAN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${ALAN_AGENT_WORKOS_USER_ID_PREFIX}%`;
18127
-
18128
18170
  // ../shared/dist/constants/colors.js
18129
18171
  var CATEGORICAL_COLORS = {
18130
18172
  slate: "#7280a0",
@@ -18368,23 +18410,23 @@ var PRIORITY_OPTIONS = [
18368
18410
  ];
18369
18411
 
18370
18412
  // ../agent-core/dist/index.js
18371
- var import_fs5 = require("fs");
18372
- var import_os5 = require("os");
18373
- var import_path5 = require("path");
18374
- var import_fs6 = require("fs");
18375
- var import_os6 = require("os");
18376
- var import_path6 = require("path");
18377
18413
  var import_fs7 = require("fs");
18378
- var import_os7 = require("os");
18414
+ var import_os6 = require("os");
18379
18415
  var import_path7 = require("path");
18380
- var import_readline2 = require("readline");
18381
- var import_url = require("url");
18382
18416
  var import_fs8 = require("fs");
18383
- var import_os8 = require("os");
18417
+ var import_os7 = require("os");
18384
18418
  var import_path8 = require("path");
18385
- var import_crypto4 = require("crypto");
18386
18419
  var import_fs9 = require("fs");
18420
+ var import_os8 = require("os");
18387
18421
  var import_path9 = require("path");
18422
+ var import_readline2 = require("readline");
18423
+ var import_url2 = require("url");
18424
+ var import_fs10 = require("fs");
18425
+ var import_os9 = require("os");
18426
+ var import_path10 = require("path");
18427
+ var import_crypto4 = require("crypto");
18428
+ var import_fs11 = require("fs");
18429
+ var import_path11 = require("path");
18388
18430
  var MANAGED_ALAN_MCP_SERVER_NAMES = [
18389
18431
  "alan",
18390
18432
  "alan-prod",
@@ -18438,7 +18480,7 @@ async function acquireConfigLock(path) {
18438
18480
  if (Date.now() - startedAt >= 2e3) {
18439
18481
  throw new Error(`Alan could not safely update ${path}`);
18440
18482
  }
18441
- await new Promise((resolve22) => setTimeout(resolve22, 20));
18483
+ await new Promise((resolve42) => setTimeout(resolve42, 20));
18442
18484
  }
18443
18485
  }
18444
18486
  }
@@ -18674,23 +18716,10 @@ function buildJsonTargets(home) {
18674
18716
  server.headers = headers;
18675
18717
  }
18676
18718
  },
18677
- {
18678
- cli: "Antigravity",
18679
- configPath: (0, import_path2.join)(home, ".gemini", "settings.json"),
18680
- guardDir: (0, import_path2.join)(home, ".gemini"),
18681
- readServers: (config2) => config2.mcpServers ?? {},
18682
- writeServers: (config2, servers) => {
18683
- config2.mcpServers = servers;
18684
- },
18685
- readHeaders: (server) => server.headers,
18686
- writeHeaders: (server, headers) => {
18687
- server.headers = headers;
18688
- }
18689
- },
18690
18719
  {
18691
18720
  cli: "Antigravity CLI",
18692
- configPath: (0, import_path2.join)(home, ".gemini", "antigravity-cli", "settings.json"),
18693
- guardDir: (0, import_path2.join)(home, ".gemini"),
18721
+ configPath: (0, import_path2.join)(home, ".gemini", "config", "mcp_config.json"),
18722
+ guardDir: (0, import_path2.join)(home, ".gemini", "config"),
18694
18723
  readServers: (config2) => config2.mcpServers ?? {},
18695
18724
  writeServers: (config2, servers) => {
18696
18725
  config2.mcpServers = servers;
@@ -18736,8 +18765,8 @@ var mcpConfigWriteGateTail = Promise.resolve();
18736
18765
  function acquireMcpConfigWriteGate() {
18737
18766
  const previous = mcpConfigWriteGateTail;
18738
18767
  let releaseCurrent;
18739
- const current = new Promise((resolve22) => {
18740
- releaseCurrent = resolve22;
18768
+ const current = new Promise((resolve42) => {
18769
+ releaseCurrent = resolve42;
18741
18770
  });
18742
18771
  mcpConfigWriteGateTail = previous.then(() => current);
18743
18772
  return previous.then(() => {
@@ -18749,6 +18778,64 @@ function acquireMcpConfigWriteGate() {
18749
18778
  };
18750
18779
  });
18751
18780
  }
18781
+ var AGENT_INSTRUCTIONS_FILE = "AGENTS.md";
18782
+ var MAX_INSTRUCTION_CHARS = 48e3;
18783
+ function isWorkspaceRoot(dir) {
18784
+ return (0, import_fs3.existsSync)((0, import_path3.join)(dir, ".git"));
18785
+ }
18786
+ function findWorkspaceRoot(cwd) {
18787
+ let current = (0, import_path3.resolve)(cwd);
18788
+ while (true) {
18789
+ if (isWorkspaceRoot(current)) return current;
18790
+ const parent = (0, import_path3.dirname)(current);
18791
+ if (parent === current) return (0, import_path3.resolve)(cwd);
18792
+ current = parent;
18793
+ }
18794
+ }
18795
+ function instructionPaths(cwd) {
18796
+ const root = findWorkspaceRoot(cwd);
18797
+ const paths = [];
18798
+ let current = (0, import_path3.resolve)(cwd);
18799
+ while (true) {
18800
+ const path = (0, import_path3.join)(current, AGENT_INSTRUCTIONS_FILE);
18801
+ try {
18802
+ if ((0, import_fs3.existsSync)(path) && (0, import_fs3.statSync)(path).isFile()) paths.unshift(path);
18803
+ } catch {
18804
+ }
18805
+ if (current === root) return paths;
18806
+ const parent = (0, import_path3.dirname)(current);
18807
+ if (parent === current) return paths;
18808
+ current = parent;
18809
+ }
18810
+ }
18811
+ function buildAntigravityWorkspaceInstructions(cwd) {
18812
+ let remaining = MAX_INSTRUCTION_CHARS;
18813
+ const sections = [];
18814
+ for (const path of instructionPaths(cwd)) {
18815
+ if (remaining <= 0) break;
18816
+ let content;
18817
+ try {
18818
+ content = (0, import_fs3.readFileSync)(path, "utf8").trim();
18819
+ } catch {
18820
+ continue;
18821
+ }
18822
+ if (!content) continue;
18823
+ const included = content.slice(0, remaining);
18824
+ sections.push(
18825
+ [
18826
+ `<workspace_agent_instructions source="${path}">`,
18827
+ included,
18828
+ "</workspace_agent_instructions>"
18829
+ ].join("\n")
18830
+ );
18831
+ remaining -= included.length;
18832
+ }
18833
+ if (sections.length === 0) return void 0;
18834
+ return [
18835
+ "Treat the following repository agent instructions as active for this session.",
18836
+ ...sections
18837
+ ].join("\n\n");
18838
+ }
18752
18839
  function buildPromptWithSystem(config2, promptText) {
18753
18840
  const parts2 = [
18754
18841
  config2.systemPrompt?.trim(),
@@ -18780,16 +18867,16 @@ function imageFileExtension(mimeType) {
18780
18867
  }
18781
18868
  function createImageTempDirectory(cwd) {
18782
18869
  const candidates = [
18783
- cwd ? (0, import_path3.join)(cwd, ".alan-images-") : null,
18784
- (0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-")
18870
+ cwd ? (0, import_path4.join)(cwd, ".alan-images-") : null,
18871
+ (0, import_path4.join)((0, import_os3.tmpdir)(), "alan-images-")
18785
18872
  ].filter((value2) => Boolean(value2));
18786
18873
  for (const candidate of candidates) {
18787
18874
  try {
18788
- return (0, import_fs3.mkdtempSync)(candidate);
18875
+ return (0, import_fs4.mkdtempSync)(candidate);
18789
18876
  } catch {
18790
18877
  }
18791
18878
  }
18792
- return (0, import_fs3.mkdtempSync)((0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-"));
18879
+ return (0, import_fs4.mkdtempSync)((0, import_path4.join)((0, import_os3.tmpdir)(), "alan-images-"));
18793
18880
  }
18794
18881
  function safeFilename(filename) {
18795
18882
  const safe = filename.replace(/[^a-zA-Z0-9._-]/g, "_").replace(/^_+/, "");
@@ -18803,8 +18890,8 @@ function writeImagesToTempFiles(images, cwd) {
18803
18890
  const files = [];
18804
18891
  for (const img of images) {
18805
18892
  const ext = imageFileExtension(img.mimeType);
18806
- const filePath = (0, import_path3.join)(directory, `alan-img-${img.id}.${ext}`);
18807
- (0, import_fs3.writeFileSync)(filePath, Buffer.from(img.data, "base64"));
18893
+ const filePath = (0, import_path4.join)(directory, `alan-img-${img.id}.${ext}`);
18894
+ (0, import_fs4.writeFileSync)(filePath, Buffer.from(img.data, "base64"));
18808
18895
  paths.push(filePath);
18809
18896
  files.push({
18810
18897
  filename: img.filename,
@@ -18819,7 +18906,7 @@ function writeImagesToTempFiles(images, cwd) {
18819
18906
  files,
18820
18907
  cleanup: () => {
18821
18908
  try {
18822
- (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
18909
+ (0, import_fs4.rmSync)(directory, { recursive: true, force: true });
18823
18910
  } catch {
18824
18911
  }
18825
18912
  }
@@ -18845,8 +18932,8 @@ function writeFilesToTempFiles(files, cwd) {
18845
18932
  }
18846
18933
  for (const file2 of dataFiles) {
18847
18934
  if (!directory || file2.data === void 0) continue;
18848
- const filePath = (0, import_path3.join)(directory, `${file2.id}-${safeFilename(file2.filename)}`);
18849
- (0, import_fs3.writeFileSync)(filePath, Buffer.from(file2.data, "base64"));
18935
+ const filePath = (0, import_path4.join)(directory, `${file2.id}-${safeFilename(file2.filename)}`);
18936
+ (0, import_fs4.writeFileSync)(filePath, Buffer.from(file2.data, "base64"));
18850
18937
  paths.push(filePath);
18851
18938
  tempFiles.push({
18852
18939
  filename: file2.filename,
@@ -18861,7 +18948,7 @@ function writeFilesToTempFiles(files, cwd) {
18861
18948
  cleanup: () => {
18862
18949
  if (!directory) return;
18863
18950
  try {
18864
- (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
18951
+ (0, import_fs4.rmSync)(directory, { recursive: true, force: true });
18865
18952
  } catch {
18866
18953
  }
18867
18954
  }
@@ -19322,15 +19409,15 @@ var SPAWN_RETRY_DELAYS_BY_CODE = {
19322
19409
  ETXTBSY: [250, 750, 1500, 3e3, 5e3],
19323
19410
  ENOENT: [250, 750]
19324
19411
  };
19325
- var delay = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
19412
+ var delay = (ms) => new Promise((resolve42) => setTimeout(resolve42, ms));
19326
19413
  var SPAWN_OUTCOME_TIMEOUT_MS = 2e3;
19327
19414
  function waitForSpawnOutcome(child, timeoutMs = SPAWN_OUTCOME_TIMEOUT_MS) {
19328
- return new Promise((resolve22) => {
19329
- const timer = setTimeout(() => resolve22(null), timeoutMs);
19415
+ return new Promise((resolve42) => {
19416
+ const timer = setTimeout(() => resolve42(null), timeoutMs);
19330
19417
  timer.unref?.();
19331
19418
  const settle = (value2) => {
19332
19419
  clearTimeout(timer);
19333
- resolve22(value2);
19420
+ resolve42(value2);
19334
19421
  };
19335
19422
  child.once("spawn", () => settle(null));
19336
19423
  child.once("error", (error2) => settle(error2));
@@ -19457,36 +19544,36 @@ function createGenericCliBackend(options) {
19457
19544
  let idleTimedOut = false;
19458
19545
  let idleTimeoutReason = null;
19459
19546
  try {
19460
- const exitPromise = new Promise((resolve22, reject) => {
19547
+ const exitPromise = new Promise((resolve42, reject) => {
19461
19548
  child.on("error", (error2) => {
19462
19549
  reject(formatCliSpawnError(options.command, error2));
19463
19550
  });
19464
- child.on("close", (exitCode2, signal) => resolve22({ exitCode: exitCode2, signal }));
19551
+ child.on("close", (exitCode2, signal) => resolve42({ exitCode: exitCode2, signal }));
19465
19552
  const onAbort = () => {
19466
19553
  killProcessTree(child.pid, { signal: "SIGTERM", child });
19467
19554
  };
19468
19555
  context.abortController.signal.addEventListener("abort", onAbort, { once: true });
19469
19556
  });
19470
19557
  if (options.keepStdinOpen) {
19471
- const resultPromise = new Promise((resolve22) => {
19472
- state.onResultReceived = () => resolve22("result_received");
19473
- if (state.resultReceived) resolve22("result_received");
19558
+ const resultPromise = new Promise((resolve42) => {
19559
+ state.onResultReceived = () => resolve42("result_received");
19560
+ if (state.resultReceived) resolve42("result_received");
19474
19561
  });
19475
19562
  const IDLE_MS = options.resultIdleTimeoutMs ?? 10 * 60 * 1e3;
19476
19563
  let idleTimer = null;
19477
- const idlePromise = new Promise((resolve22) => {
19564
+ const idlePromise = new Promise((resolve42) => {
19478
19565
  const armIdleTimer = () => {
19479
19566
  if (idleTimer) clearTimeout(idleTimer);
19480
19567
  idleTimer = setTimeout(() => {
19481
19568
  if (presenter.pendingAskUserToolIds?.size) {
19482
19569
  idleTimeoutReason = "pending_user_answer";
19483
- resolve22("idle_timeout");
19570
+ resolve42("idle_timeout");
19484
19571
  } else if (state.awaitingPostBackgroundSynthesis || state.resultDeferredOnBackgroundWork && state.activeBackgroundTaskIds?.size) {
19485
19572
  idleTimeoutReason = state.awaitingPostBackgroundSynthesis ? "post_subagent_synthesis" : "background_task";
19486
- resolve22("idle_timeout");
19573
+ resolve42("idle_timeout");
19487
19574
  } else if (options.postStartupSilenceTimeoutMs && sawStdoutLine && typeof state.lastRawOutputAtMs === "number" && Date.now() - state.lastRawOutputAtMs >= options.postStartupSilenceTimeoutMs) {
19488
19575
  idleTimeoutReason = "post_startup_silence";
19489
- resolve22("idle_timeout");
19576
+ resolve42("idle_timeout");
19490
19577
  } else {
19491
19578
  armIdleTimer();
19492
19579
  }
@@ -19507,14 +19594,14 @@ function createGenericCliBackend(options) {
19507
19594
  processExit = await Promise.race([
19508
19595
  exitPromise,
19509
19596
  new Promise(
19510
- (resolve22) => setTimeout(() => resolve22({ exitCode: null, signal: "SIGKILL" }), 5e3)
19597
+ (resolve42) => setTimeout(() => resolve42({ exitCode: null, signal: "SIGKILL" }), 5e3)
19511
19598
  )
19512
19599
  ]);
19513
19600
  } else if (raceResult === "result_received") {
19514
19601
  const GRACE_MS = 5e3;
19515
19602
  const gracedExit = await Promise.race([
19516
19603
  exitPromise,
19517
- new Promise((resolve22) => setTimeout(() => resolve22(null), GRACE_MS))
19604
+ new Promise((resolve42) => setTimeout(() => resolve42(null), GRACE_MS))
19518
19605
  ]);
19519
19606
  if (gracedExit) processExit = gracedExit;
19520
19607
  if (child.exitCode === null && !child.killed) {
@@ -19832,6 +19919,234 @@ function createGenericCliBackend(options) {
19832
19919
  }
19833
19920
  };
19834
19921
  }
19922
+ function stringField(record2, key) {
19923
+ const value2 = record2[key];
19924
+ return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
19925
+ }
19926
+ function backgroundTaskKeys(record2) {
19927
+ return [
19928
+ stringField(record2, "task_id"),
19929
+ stringField(record2, "taskId"),
19930
+ stringField(record2, "tool_use_id"),
19931
+ stringField(record2, "toolUseId"),
19932
+ stringField(record2, "id")
19933
+ ].filter((key) => Boolean(key));
19934
+ }
19935
+ function backgroundTaskId(record2) {
19936
+ return stringField(record2, "task_id") ?? stringField(record2, "taskId");
19937
+ }
19938
+ function backgroundToolUseId(record2) {
19939
+ return stringField(record2, "tool_use_id") ?? stringField(record2, "toolUseId");
19940
+ }
19941
+ function registerBackgroundTaskIds(state, keys) {
19942
+ for (const key of keys) {
19943
+ if (!key) continue;
19944
+ if (!state.activeBackgroundTaskIds) state.activeBackgroundTaskIds = /* @__PURE__ */ new Set();
19945
+ state.activeBackgroundTaskIds.add(key);
19946
+ }
19947
+ }
19948
+ function registerBackgroundLauncher(state, toolUseId) {
19949
+ registerBackgroundTaskIds(state, [toolUseId]);
19950
+ if (!state.pendingLauncherToolIds) state.pendingLauncherToolIds = [];
19951
+ if (!state.pendingLauncherToolIds.includes(toolUseId)) {
19952
+ state.pendingLauncherToolIds.push(toolUseId);
19953
+ }
19954
+ }
19955
+ function drainNextUnlinkedBackgroundLauncher(state) {
19956
+ const launcherId = state.pendingLauncherToolIds?.shift();
19957
+ if (state.pendingLauncherToolIds?.length === 0) state.pendingLauncherToolIds = void 0;
19958
+ if (launcherId) clearBackgroundTaskIds(state, [launcherId]);
19959
+ return launcherId;
19960
+ }
19961
+ function registerBackgroundTaskRecord(state, record2, launcherToolUseId) {
19962
+ const taskId = backgroundTaskId(record2);
19963
+ let toolUseId = backgroundToolUseId(record2) ?? launcherToolUseId ?? void 0;
19964
+ if (!toolUseId && taskId) {
19965
+ const nextLauncher = state.pendingLauncherToolIds?.[0];
19966
+ if (nextLauncher) {
19967
+ toolUseId = nextLauncher;
19968
+ } else if (state.activeBackgroundTaskIds?.size === 1) {
19969
+ const [candidate] = state.activeBackgroundTaskIds;
19970
+ if (candidate && candidate !== taskId) toolUseId = candidate;
19971
+ }
19972
+ }
19973
+ registerBackgroundTaskIds(state, backgroundTaskKeys(record2));
19974
+ if (!taskId || !toolUseId) return;
19975
+ if (state.pendingLauncherToolIds) {
19976
+ const idx = state.pendingLauncherToolIds.indexOf(toolUseId);
19977
+ if (idx >= 0) state.pendingLauncherToolIds.splice(idx, 1);
19978
+ if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
19979
+ }
19980
+ if (!state.backgroundToolIdByTaskId) state.backgroundToolIdByTaskId = /* @__PURE__ */ new Map();
19981
+ if (!state.backgroundTaskIdsByToolId) state.backgroundTaskIdsByToolId = /* @__PURE__ */ new Map();
19982
+ state.backgroundToolIdByTaskId.set(taskId, toolUseId);
19983
+ const taskIds = state.backgroundTaskIdsByToolId.get(toolUseId) ?? /* @__PURE__ */ new Set();
19984
+ taskIds.add(taskId);
19985
+ state.backgroundTaskIdsByToolId.set(toolUseId, taskIds);
19986
+ }
19987
+ function clearBackgroundTaskIds(state, keys) {
19988
+ const activeIds = state.activeBackgroundTaskIds;
19989
+ if (!activeIds) return;
19990
+ for (const key of keys) {
19991
+ if (!key) continue;
19992
+ activeIds.delete(key);
19993
+ const toolUseId = state.backgroundToolIdByTaskId?.get(key);
19994
+ if (toolUseId) {
19995
+ activeIds.delete(toolUseId);
19996
+ state.backgroundToolIdByTaskId?.delete(key);
19997
+ const taskIds2 = state.backgroundTaskIdsByToolId?.get(toolUseId);
19998
+ taskIds2?.delete(key);
19999
+ if (taskIds2?.size === 0) state.backgroundTaskIdsByToolId?.delete(toolUseId);
20000
+ }
20001
+ const taskIds = state.backgroundTaskIdsByToolId?.get(key);
20002
+ if (taskIds) {
20003
+ for (const taskId of taskIds) {
20004
+ activeIds.delete(taskId);
20005
+ state.backgroundToolIdByTaskId?.delete(taskId);
20006
+ }
20007
+ state.backgroundTaskIdsByToolId?.delete(key);
20008
+ }
20009
+ }
20010
+ if (state.pendingLauncherToolIds) {
20011
+ state.pendingLauncherToolIds = state.pendingLauncherToolIds.filter((id) => activeIds.has(id));
20012
+ if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
20013
+ }
20014
+ if (activeIds.size === 0) state.activeBackgroundTaskIds = void 0;
20015
+ }
20016
+ function resolveBackgroundTaskToolUseId(state, record2) {
20017
+ const explicitToolUseId = backgroundToolUseId(record2);
20018
+ if (explicitToolUseId) return explicitToolUseId;
20019
+ const taskId = backgroundTaskId(record2);
20020
+ return taskId ? state.backgroundToolIdByTaskId?.get(taskId) : void 0;
20021
+ }
20022
+ var TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20023
+ "complete",
20024
+ "completed",
20025
+ "done",
20026
+ "success",
20027
+ "succeeded",
20028
+ "failed",
20029
+ "failure",
20030
+ "error",
20031
+ "cancelled",
20032
+ "canceled",
20033
+ "aborted",
20034
+ "interrupted",
20035
+ "stopped"
20036
+ ]);
20037
+ var NON_TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20038
+ "running",
20039
+ "in_progress",
20040
+ "inprogress",
20041
+ "started",
20042
+ "pending",
20043
+ "active",
20044
+ "working",
20045
+ "queued"
20046
+ ]);
20047
+ var ASYNC_LAUNCH_ACK_RE = /^(async agent launched successfully|background (?:task|agent|subagent) (?:launched|started|running)|task (?:launched|started) successfully)/i;
20048
+ function isTerminalBackgroundStatus(record2) {
20049
+ const status = stringField(record2, "status")?.toLowerCase();
20050
+ if (status && TERMINAL_BACKGROUND_STATUSES.has(status)) return true;
20051
+ if (status && NON_TERMINAL_BACKGROUND_STATUSES.has(status)) return false;
20052
+ return typeof record2.duration_ms === "number" || typeof record2.durationMs === "number" || typeof record2.total_tokens === "number" || typeof record2.totalTokens === "number" || typeof record2.tool_uses === "number" || typeof record2.toolUses === "number";
20053
+ }
20054
+ function isFailedBackgroundStatus(record2) {
20055
+ const status = stringField(record2, "status")?.toLowerCase();
20056
+ return status === "failed" || status === "failure" || status === "error" || status === "cancelled" || status === "canceled" || status === "aborted" || status === "interrupted";
20057
+ }
20058
+ function extractBackgroundTaskIdFromPayload(value2) {
20059
+ if (typeof value2 === "string") {
20060
+ const trimmed = value2.trim();
20061
+ if (!trimmed) return void 0;
20062
+ try {
20063
+ return extractBackgroundTaskIdFromPayload(JSON.parse(trimmed));
20064
+ } catch {
20065
+ const match = trimmed.match(/\btask[_-]?id["']?\s*[:=]\s*["']?([A-Za-z0-9_.-]+)/i) ?? trimmed.match(/\btasks\/([A-Za-z0-9_.-]+)/i);
20066
+ if (match?.[1]) return match[1];
20067
+ if (/^[A-Za-z0-9_-]{6,128}$/.test(trimmed) && /(?:task|bg|async|job|agent)/i.test(trimmed)) {
20068
+ return trimmed;
20069
+ }
20070
+ return void 0;
20071
+ }
20072
+ }
20073
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return void 0;
20074
+ const record2 = value2;
20075
+ return stringField(record2, "task_id") ?? stringField(record2, "taskId") ?? stringField(record2, "agentId") ?? stringField(record2, "agent_id") ?? extractBackgroundTaskIdFromPayload(record2.value) ?? extractBackgroundTaskIdFromPayload(record2.result) ?? extractBackgroundTaskIdFromPayload(record2.data) ?? extractBackgroundTaskIdFromPayload(record2.content);
20076
+ }
20077
+ function looksLikeBackgroundLaunchAck(options) {
20078
+ const taskId = extractBackgroundTaskIdFromPayload(options.value) ?? extractBackgroundTaskIdFromPayload(options.content);
20079
+ const content = options.content.trim();
20080
+ const explicitAckText = ASYNC_LAUNCH_ACK_RE.test(content);
20081
+ if (!options.trackedUnlinkedLauncher) return { isAck: false, taskId };
20082
+ if (options.explicitBackground && taskId) return { isAck: true, taskId };
20083
+ if (explicitAckText) return { isAck: true, taskId };
20084
+ if (taskId && content.length > 0 && content.length < 400) {
20085
+ const record2 = options.value && typeof options.value === "object" && !Array.isArray(options.value) ? options.value : null;
20086
+ const looksStructured = record2 !== null || content.startsWith("{") || /^task[_-]?id\b/i.test(content) || content === taskId;
20087
+ if (looksStructured) return { isAck: true, taskId };
20088
+ }
20089
+ return { isAck: false, taskId };
20090
+ }
20091
+ function settleBackgroundTerminalNotification(kind, context, state, record2, options) {
20092
+ const toolUseId = resolveBackgroundTaskToolUseId(state, record2);
20093
+ const keys = backgroundTaskKeys(record2);
20094
+ const wasActive = !!toolUseId && state.activeBackgroundTaskIds?.has(toolUseId) === true || keys.some((key) => state.activeBackgroundTaskIds?.has(key) === true);
20095
+ if (toolUseId && wasActive) {
20096
+ options.emitToolResult(toolUseId, options.resultText, options.isError);
20097
+ clearBackgroundTaskIds(state, keys);
20098
+ maybeFinalizeDeferredResult(kind, context, state);
20099
+ return toolUseId;
20100
+ }
20101
+ clearBackgroundTaskIds(state, keys);
20102
+ const drainedLauncher = drainNextUnlinkedBackgroundLauncher(state);
20103
+ if (drainedLauncher) {
20104
+ options.emitToolResult(drainedLauncher, options.resultText, options.isError);
20105
+ }
20106
+ maybeFinalizeDeferredResult(kind, context, state);
20107
+ return drainedLauncher;
20108
+ }
20109
+ function finalizeStructuredResult(kind, state) {
20110
+ state.resultReceived = true;
20111
+ state.onResultReceived?.();
20112
+ if (state.stdin && !state.stdin.destroyed) {
20113
+ state.stdin.end();
20114
+ console.info(`[${kind}] Closed stdin after result event to signal CLI exit`);
20115
+ }
20116
+ }
20117
+ function deferOrFinalizeStructuredResult(kind, context, state) {
20118
+ const pendingAsks = context.presenter.pendingAskUserToolIds?.size ?? 0;
20119
+ if (pendingAsks > 0) {
20120
+ console.info(
20121
+ `[${kind}] Keeping stdin open \u2014 ${pendingAsks} interactive question(s) awaiting user response`
20122
+ );
20123
+ state.resultDeferredOnPendingAnswer = true;
20124
+ return "deferred_pending_answer";
20125
+ }
20126
+ const activeBackgroundTasks = state.activeBackgroundTaskIds?.size ?? 0;
20127
+ if (activeBackgroundTasks > 0) {
20128
+ console.info(
20129
+ `[${kind}] Keeping stdin open \u2014 ${activeBackgroundTasks} background task(s) still active`
20130
+ );
20131
+ state.resultDeferredOnBackgroundWork = true;
20132
+ return "deferred_background_work";
20133
+ }
20134
+ finalizeStructuredResult(kind, state);
20135
+ return "finalized";
20136
+ }
20137
+ function maybeFinalizeDeferredResult(kind, context, state) {
20138
+ if (!state.resultDeferredOnBackgroundWork && !state.resultDeferredOnPendingAnswer) return;
20139
+ if (context.presenter.pendingAskUserToolIds?.size || state.activeBackgroundTaskIds?.size) return;
20140
+ if (state.resultDeferredOnBackgroundWork) {
20141
+ state.awaitingPostBackgroundSynthesis = true;
20142
+ console.info(
20143
+ `[${kind}] Background work drained \u2014 awaiting post-subagent synthesis before stdin close`
20144
+ );
20145
+ return;
20146
+ }
20147
+ state.resultDeferredOnPendingAnswer = false;
20148
+ finalizeStructuredResult(kind, state);
20149
+ }
19835
20150
  var MAX_INLINE_GENERATED_IMAGE_BYTES = 20 * 1024 * 1024;
19836
20151
  function inferImageMimeType(buffer) {
19837
20152
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
@@ -19947,6 +20262,20 @@ function buildToolResultText(parsed) {
19947
20262
  const status = typeof parsed.status === "string" ? parsed.status.trim() : "";
19948
20263
  return status || "Tool completed";
19949
20264
  }
20265
+ function buildSubagentResultText(parsed) {
20266
+ const output = buildToolResultText(parsed);
20267
+ const status = typeof parsed.status === "string" ? parsed.status.trim() : "";
20268
+ const details = [
20269
+ typeof parsed.duration_ms === "number" ? `Duration: ${parsed.duration_ms}ms.` : "",
20270
+ typeof parsed.durationMs === "number" ? `Duration: ${parsed.durationMs}ms.` : "",
20271
+ typeof parsed.tool_uses === "number" ? `Tool uses: ${parsed.tool_uses}.` : "",
20272
+ typeof parsed.toolUses === "number" ? `Tool uses: ${parsed.toolUses}.` : "",
20273
+ typeof parsed.total_tokens === "number" ? `Tokens: ${parsed.total_tokens}.` : "",
20274
+ typeof parsed.totalTokens === "number" ? `Tokens: ${parsed.totalTokens}.` : ""
20275
+ ].filter(Boolean);
20276
+ if (output !== "Tool completed") return output;
20277
+ return [`Subagent ${status || "completed"}.`, ...details].join(" ");
20278
+ }
19950
20279
  function extractText(parsed) {
19951
20280
  for (const key of ["text", "delta", "content", "message", "result"]) {
19952
20281
  const value2 = parsed[key];
@@ -19993,6 +20322,286 @@ function extractSubagentInput(parsed) {
19993
20322
  workspace: parsed.workspace
19994
20323
  };
19995
20324
  }
20325
+ function antigravityTranscriptRoot(context) {
20326
+ const home = context.env.HOME || process.env.HOME || (0, import_os4.homedir)();
20327
+ return (0, import_path5.resolve)(home, ".gemini", "antigravity-cli", "brain");
20328
+ }
20329
+ function resolveAntigravityTranscriptPath(parsed, context) {
20330
+ const logUri = stringField2(parsed, "log_uri");
20331
+ const conversationId = stringField2(parsed, "task_id") ?? stringField2(parsed, "conversation_id");
20332
+ if (!logUri || !conversationId) return void 0;
20333
+ try {
20334
+ const url3 = new URL(logUri);
20335
+ if (url3.protocol !== "file:") return void 0;
20336
+ const root = antigravityTranscriptRoot(context);
20337
+ const transcriptPath = (0, import_path5.resolve)((0, import_url.fileURLToPath)(url3));
20338
+ const pathFromRoot = (0, import_path5.relative)(root, transcriptPath);
20339
+ const segments = pathFromRoot.split(import_path5.sep);
20340
+ if (!pathFromRoot || pathFromRoot === ".." || pathFromRoot.startsWith(`..${import_path5.sep}`) || (0, import_path5.isAbsolute)(pathFromRoot) || segments[0] !== conversationId || segments.at(-1) !== "transcript.jsonl" || segments.at(-2) !== "logs" || segments.at(-3) !== ".system_generated") {
20341
+ return void 0;
20342
+ }
20343
+ return transcriptPath;
20344
+ } catch {
20345
+ return void 0;
20346
+ }
20347
+ }
20348
+ function antigravityTranscriptToolId(parentToolUseId, lineIndex, toolIndex) {
20349
+ return `${parentToolUseId}-transcript-${lineIndex}-${toolIndex}`;
20350
+ }
20351
+ var ANTIGRAVITY_TOOL_RESULT_TYPES = /* @__PURE__ */ new Set([
20352
+ "LIST_DIRECTORY",
20353
+ "VIEW_FILE",
20354
+ "MCP_TOOL",
20355
+ "INVOKE_SUBAGENT",
20356
+ "RUN_COMMAND",
20357
+ "GENERIC",
20358
+ "GREP_SEARCH",
20359
+ "CODE_ACTION",
20360
+ "SEND_MESSAGE"
20361
+ ]);
20362
+ function isAntigravityToolResultEntry(entry) {
20363
+ const type = stringField2(entry, "type")?.toUpperCase();
20364
+ if (type && ANTIGRAVITY_TOOL_RESULT_TYPES.has(type)) return true;
20365
+ const content = stringField2(entry, "content");
20366
+ return Boolean(content?.startsWith("Created At:"));
20367
+ }
20368
+ function stripAntigravityToolResultEnvelope(content) {
20369
+ const stripped = content.replace(/^(?:Created At:[^\n]*\n|Completed At:[^\n]*\n)+/u, "");
20370
+ return stripped.trim().length > 0 ? stripped : content;
20371
+ }
20372
+ function readAntigravityTranscriptLines(transcriptPath) {
20373
+ try {
20374
+ const lines = (0, import_fs5.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
20375
+ if (lines.at(-1) === "") lines.pop();
20376
+ return lines;
20377
+ } catch {
20378
+ return void 0;
20379
+ }
20380
+ }
20381
+ function syncAntigravitySubagentTranscript(transcriptPath, parentToolUseId, presenter, startLine = 0, pendingToolIds = []) {
20382
+ const lines = readAntigravityTranscriptLines(transcriptPath);
20383
+ if (!lines) {
20384
+ return { processedLineCount: startLine, emittedEventCount: 0, pendingToolIds };
20385
+ }
20386
+ let processedLineCount = startLine > lines.length ? 0 : startLine;
20387
+ let emittedEventCount = 0;
20388
+ for (let lineIndex = processedLineCount; lineIndex < lines.length; lineIndex += 1) {
20389
+ const line = lines[lineIndex];
20390
+ if (!line) {
20391
+ processedLineCount = lineIndex + 1;
20392
+ continue;
20393
+ }
20394
+ let entry;
20395
+ try {
20396
+ entry = JSON.parse(line);
20397
+ } catch {
20398
+ break;
20399
+ }
20400
+ processedLineCount = lineIndex + 1;
20401
+ if (stringField2(entry, "source") !== "MODEL") continue;
20402
+ const thinking = stringField2(entry, "thinking") ?? stringField2(entry, "thinking_delta");
20403
+ if (thinking) {
20404
+ emittedEventCount += 1;
20405
+ void presenter.onThinking(thinking, parentToolUseId);
20406
+ }
20407
+ const toolCalls = Array.isArray(entry.tool_calls) ? entry.tool_calls : [];
20408
+ toolCalls.forEach((rawToolCall, toolIndex) => {
20409
+ const toolCall = asRecord(rawToolCall);
20410
+ const toolName = toolCall && stringField2(toolCall, "name");
20411
+ if (!toolName) return;
20412
+ const toolId = antigravityTranscriptToolId(parentToolUseId, lineIndex, toolIndex);
20413
+ pendingToolIds.push(toolId);
20414
+ emittedEventCount += 1;
20415
+ void presenter.onToolUse(
20416
+ toolName,
20417
+ toolCall?.args ?? toolCall?.parameters ?? {},
20418
+ toolId,
20419
+ parentToolUseId
20420
+ );
20421
+ });
20422
+ const content = stringField2(entry, "content");
20423
+ if (content && isAntigravityToolResultEntry(entry)) {
20424
+ const toolId = pendingToolIds.shift();
20425
+ if (toolId) {
20426
+ emittedEventCount += 1;
20427
+ void presenter.onToolResult?.(
20428
+ toolId,
20429
+ stripAntigravityToolResultEnvelope(content),
20430
+ void 0,
20431
+ parentToolUseId
20432
+ );
20433
+ }
20434
+ continue;
20435
+ }
20436
+ if (!content) continue;
20437
+ const entryType = stringField2(entry, "type")?.toUpperCase();
20438
+ if (entryType === "SYSTEM_MESSAGE") continue;
20439
+ emittedEventCount += 1;
20440
+ void presenter.onAssistantText(content, parentToolUseId);
20441
+ }
20442
+ return { processedLineCount, emittedEventCount, pendingToolIds };
20443
+ }
20444
+ function resolveAntigravityParentTranscriptPath(conversationId, context) {
20445
+ return (0, import_path5.resolve)(
20446
+ antigravityTranscriptRoot(context),
20447
+ conversationId,
20448
+ ".system_generated",
20449
+ "logs",
20450
+ "transcript.jsonl"
20451
+ );
20452
+ }
20453
+ function syncAntigravityParentThinkingFromTranscript(context, state) {
20454
+ const parent = state.antigravityParentTranscript;
20455
+ if (!parent?.transcriptPath) return 0;
20456
+ const lines = readAntigravityTranscriptLines(parent.transcriptPath);
20457
+ if (!lines) return 0;
20458
+ let processedLineCount = parent.replayedLineCount > lines.length ? 0 : parent.replayedLineCount;
20459
+ let emittedEventCount = 0;
20460
+ for (let lineIndex = processedLineCount; lineIndex < lines.length; lineIndex += 1) {
20461
+ const line = lines[lineIndex];
20462
+ if (!line) {
20463
+ processedLineCount = lineIndex + 1;
20464
+ continue;
20465
+ }
20466
+ let entry;
20467
+ try {
20468
+ entry = JSON.parse(line);
20469
+ } catch {
20470
+ break;
20471
+ }
20472
+ processedLineCount = lineIndex + 1;
20473
+ if (stringField2(entry, "source") !== "MODEL") continue;
20474
+ const thinking = stringField2(entry, "thinking") ?? stringField2(entry, "thinking_delta");
20475
+ if (!thinking) continue;
20476
+ emittedEventCount += 1;
20477
+ void context.presenter.onThinking(thinking);
20478
+ }
20479
+ parent.replayedLineCount = processedLineCount;
20480
+ return emittedEventCount;
20481
+ }
20482
+ function syncAntigravitySubagentEventsFromTranscripts(context, state) {
20483
+ let emittedEventCount = syncAntigravityParentThinkingFromTranscript(context, state);
20484
+ for (const [launcherId, task] of state.antigravitySubagentTranscripts ?? []) {
20485
+ if (!task.transcriptPath) continue;
20486
+ const replay = syncAntigravitySubagentTranscript(
20487
+ task.transcriptPath,
20488
+ launcherId,
20489
+ context.presenter,
20490
+ task.replayedLineCount,
20491
+ task.pendingToolIds ?? []
20492
+ );
20493
+ task.replayedLineCount = replay.processedLineCount;
20494
+ task.pendingToolIds = replay.pendingToolIds;
20495
+ task.emittedEventCount += replay.emittedEventCount;
20496
+ emittedEventCount += replay.emittedEventCount;
20497
+ }
20498
+ if (emittedEventCount > 0) state.onNewOutput?.();
20499
+ return emittedEventCount;
20500
+ }
20501
+ function ensureAntigravitySubagentTranscriptPolling(context, state) {
20502
+ if (state.providerTranscriptPollTimer) {
20503
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20504
+ return;
20505
+ }
20506
+ const poll = () => {
20507
+ try {
20508
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20509
+ state.providerTranscriptPollErrorLogged = false;
20510
+ } catch (error2) {
20511
+ if (!state.providerTranscriptPollErrorLogged) {
20512
+ console.warn("[antigravity_cli] Failed to poll child transcript:", error2);
20513
+ state.providerTranscriptPollErrorLogged = true;
20514
+ }
20515
+ }
20516
+ };
20517
+ poll();
20518
+ const timer = setInterval(poll, 750);
20519
+ timer.unref?.();
20520
+ state.providerTranscriptPollTimer = timer;
20521
+ }
20522
+ function clearAntigravityTranscriptPollingIfIdle(state) {
20523
+ const hasChildren = (state.antigravitySubagentTranscripts?.size ?? 0) > 0;
20524
+ const hasParent = Boolean(state.antigravityParentTranscript);
20525
+ if (hasChildren || hasParent) return;
20526
+ if (state.providerTranscriptPollTimer) clearInterval(state.providerTranscriptPollTimer);
20527
+ state.providerTranscriptPollTimer = void 0;
20528
+ }
20529
+ function registerAntigravityParentTranscript(conversationId, context, state) {
20530
+ if (!conversationId) return;
20531
+ const existing = state.antigravityParentTranscript;
20532
+ if (existing?.conversationId === conversationId) {
20533
+ ensureAntigravitySubagentTranscriptPolling(context, state);
20534
+ return;
20535
+ }
20536
+ state.antigravityParentTranscript = {
20537
+ conversationId,
20538
+ transcriptPath: resolveAntigravityParentTranscriptPath(conversationId, context),
20539
+ // Skip historical rows from prior turns on resume; only stream new thinking.
20540
+ replayedLineCount: readAntigravityTranscriptLines(
20541
+ resolveAntigravityParentTranscriptPath(conversationId, context)
20542
+ )?.length ?? 0
20543
+ };
20544
+ ensureAntigravitySubagentTranscriptPolling(context, state);
20545
+ }
20546
+ function registerAntigravitySubagentTranscript(parsed, toolId, context, state) {
20547
+ if (!state.antigravitySubagentTranscripts) state.antigravitySubagentTranscripts = /* @__PURE__ */ new Map();
20548
+ const task = state.antigravitySubagentTranscripts.get(toolId) ?? {
20549
+ replayedLineCount: 0,
20550
+ emittedEventCount: 0,
20551
+ pendingToolIds: []
20552
+ };
20553
+ const incomingConversationId = stringField2(parsed, "task_id");
20554
+ if (task.conversationId && incomingConversationId && incomingConversationId !== task.conversationId) {
20555
+ if (!state.antigravityCorrelationWarnLogged) {
20556
+ console.warn(
20557
+ `[antigravity_cli] Subagent launcher ${toolId} saw a conversation id change (${task.conversationId} -> ${incomingConversationId}); keeping the original transcript association.`
20558
+ );
20559
+ state.antigravityCorrelationWarnLogged = true;
20560
+ }
20561
+ return;
20562
+ }
20563
+ task.conversationId = incomingConversationId ?? task.conversationId;
20564
+ const resolvedPath = resolveAntigravityTranscriptPath(parsed, context);
20565
+ if (!resolvedPath && !task.transcriptPath && stringField2(parsed, "log_uri")) {
20566
+ if (!state.antigravityTranscriptPathWarnLogged) {
20567
+ console.warn(
20568
+ `[antigravity_cli] Subagent log_uri for ${toolId} did not match the expected Antigravity transcript path layout; its live stream will not be tailed.`
20569
+ );
20570
+ state.antigravityTranscriptPathWarnLogged = true;
20571
+ }
20572
+ }
20573
+ task.transcriptPath = resolvedPath ?? task.transcriptPath;
20574
+ state.antigravitySubagentTranscripts.set(toolId, task);
20575
+ if (task.transcriptPath) ensureAntigravitySubagentTranscriptPolling(context, state);
20576
+ }
20577
+ function settleAntigravitySubagentTranscripts(context, state, isError = false) {
20578
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20579
+ for (const [toolId, task] of state.antigravitySubagentTranscripts ?? []) {
20580
+ settleBackgroundTerminalNotification(
20581
+ "antigravity_cli",
20582
+ context,
20583
+ state,
20584
+ {
20585
+ tool_use_id: toolId,
20586
+ ...task.conversationId ? { task_id: task.conversationId } : {},
20587
+ status: isError ? "error" : "completed"
20588
+ },
20589
+ {
20590
+ resultText: isError ? "Subagent ended because the parent run failed" : "Subagent completed",
20591
+ isError: isError || void 0,
20592
+ emitToolResult: (id, text, error2) => {
20593
+ void context.presenter.onToolResult?.(id, text, error2);
20594
+ }
20595
+ }
20596
+ );
20597
+ state.antigravitySubagentTranscripts?.delete(toolId);
20598
+ }
20599
+ if (state.antigravitySubagentTranscripts?.size === 0) {
20600
+ state.antigravitySubagentTranscripts = void 0;
20601
+ }
20602
+ state.antigravityParentTranscript = void 0;
20603
+ clearAntigravityTranscriptPollingIfIdle(state);
20604
+ }
19996
20605
  function extractToolId(parsed, state) {
19997
20606
  for (const key of ["tool_id", "toolId", "id", "call_id"]) {
19998
20607
  const value2 = parsed[key];
@@ -20001,21 +20610,140 @@ function extractToolId(parsed, state) {
20001
20610
  state.iterations += 1;
20002
20611
  return `antigravity-tool-${state.iterations}`;
20003
20612
  }
20004
- function parseAntigravityStructuredLine(line, context, state) {
20005
- const presenter = context.presenter;
20006
- let parsed = null;
20007
- try {
20008
- parsed = JSON.parse(line);
20009
- } catch {
20010
- void presenter.onLog(`[antigravity] ${line}`);
20011
- return;
20613
+ function asRecord(value2) {
20614
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
20615
+ }
20616
+ function stringField2(value2, key) {
20617
+ const field = value2[key];
20618
+ return typeof field === "string" && field.trim() ? field : void 0;
20619
+ }
20620
+ function liveStepId(step, subagentIndex) {
20621
+ const conversationId = stringField2(step, "conversation_id") ?? "unknown";
20622
+ const stepIndex = typeof step.step_index === "number" ? step.step_index : "unknown";
20623
+ const base = `antigravity-${conversationId}-step-${stepIndex}`;
20624
+ return typeof subagentIndex === "number" ? `${base}-subagent-${subagentIndex}` : base;
20625
+ }
20626
+ function isActiveStep(step) {
20627
+ return stringField2(step, "state")?.toLowerCase() === "active";
20628
+ }
20629
+ function normalizeLiveAntigravityEvent(parsed) {
20630
+ const event = stringField2(parsed, "event");
20631
+ if (!event) return void 0;
20632
+ const conversationId = stringField2(parsed, "conversation_id");
20633
+ if (event === "init") {
20634
+ return [
20635
+ {
20636
+ ...asRecord(parsed.init) ?? {},
20637
+ type: "init",
20638
+ ...conversationId ? { conversation_id: conversationId } : {}
20639
+ }
20640
+ ];
20641
+ }
20642
+ if (event === "result") {
20643
+ const result = asRecord(parsed.result) ?? {};
20644
+ return [
20645
+ {
20646
+ ...result,
20647
+ type: "complete",
20648
+ ...conversationId && !stringField2(result, "conversation_id") ? { conversation_id: conversationId } : {},
20649
+ ...typeof result.response === "string" && typeof result.result !== "string" ? { result: result.response } : {}
20650
+ }
20651
+ ];
20652
+ }
20653
+ if (event !== "step_update") return [{ type: `antigravity_event:${event}` }];
20654
+ const step = asRecord(parsed.step_update);
20655
+ if (!step) return [{ type: "antigravity_step_update" }];
20656
+ const normalizedStep = {
20657
+ ...step,
20658
+ ...conversationId && !stringField2(step, "conversation_id") ? { conversation_id: conversationId } : {}
20659
+ };
20660
+ const stepType = stringField2(normalizedStep, "step_type")?.toLowerCase();
20661
+ const thinkingText = stringField2(normalizedStep, "thinking_delta") ?? stringField2(normalizedStep, "thinking");
20662
+ const thinkingEvents = thinkingText ? [{ type: "thinking", text: thinkingText, content: thinkingText }] : [];
20663
+ if (stepType === "agent_response") {
20664
+ return [
20665
+ ...thinkingEvents,
20666
+ {
20667
+ ...normalizedStep,
20668
+ type: "assistant_message",
20669
+ ...typeof normalizedStep.text_delta === "string" ? { content: normalizedStep.text_delta } : {}
20670
+ }
20671
+ ];
20012
20672
  }
20673
+ if (stepType === "tool") {
20674
+ const toolInfo = asRecord(normalizedStep.tool_info) ?? {};
20675
+ const toolName = stringField2(normalizedStep, "tool_name") ?? stringField2(toolInfo, "name") ?? "Antigravity Tool";
20676
+ const toolId = liveStepId(normalizedStep);
20677
+ if (isActiveStep(normalizedStep)) {
20678
+ return [
20679
+ ...thinkingEvents,
20680
+ {
20681
+ ...normalizedStep,
20682
+ ...toolInfo,
20683
+ type: "tool_call",
20684
+ tool_id: toolId,
20685
+ tool_name: toolName,
20686
+ parameters: toolInfo.parameters ?? normalizedStep.parameters ?? {}
20687
+ }
20688
+ ];
20689
+ }
20690
+ const toolOutput = stringField2(toolInfo, "output") ?? stringField2(normalizedStep, "output") ?? `${toolName} completed`;
20691
+ return [
20692
+ ...thinkingEvents,
20693
+ {
20694
+ ...normalizedStep,
20695
+ type: "tool_result",
20696
+ tool_id: toolId,
20697
+ output: toolOutput
20698
+ }
20699
+ ];
20700
+ }
20701
+ if (stepType === "subagent") {
20702
+ const subagents = asRecord(normalizedStep.subagent_info)?.subagents;
20703
+ const children = Array.isArray(subagents) ? subagents.map(asRecord).filter((subagent) => Boolean(subagent)) : [];
20704
+ const entries = children.length > 0 ? children : [void 0];
20705
+ return [
20706
+ ...thinkingEvents,
20707
+ ...entries.map((subagent, index) => {
20708
+ const toolId = liveStepId(normalizedStep, index);
20709
+ const childConversationId = subagent && stringField2(subagent, "conversation_id");
20710
+ return {
20711
+ ...normalizedStep,
20712
+ // AGY's DONE means the invocation was accepted, not that the child has
20713
+ // finished. The authenticated stream emits it milliseconds after ACTIVE
20714
+ // while the child transcript is still growing.
20715
+ type: isActiveStep(normalizedStep) ? "subagent_started" : "subagent_launch_ack",
20716
+ antigravity_live: true,
20717
+ tool_id: toolId,
20718
+ task_id: childConversationId ?? toolId,
20719
+ role: subagent && stringField2(subagent, "role"),
20720
+ type_name: subagent && stringField2(subagent, "type_name"),
20721
+ prompt: subagent && (stringField2(subagent, "initial_prompt") ?? stringField2(subagent, "prompt")),
20722
+ workspace: subagent && stringField2(subagent, "workspace"),
20723
+ log_uri: subagent && stringField2(subagent, "log_uri"),
20724
+ status: isActiveStep(normalizedStep) ? "running" : "launched"
20725
+ };
20726
+ })
20727
+ ];
20728
+ }
20729
+ if (thinkingEvents.length > 0) return thinkingEvents;
20730
+ return [{ ...normalizedStep, type: "antigravity_step_update" }];
20731
+ }
20732
+ function handleAntigravityStructuredEvent(parsed, context, state) {
20733
+ const normalized = normalizeLiveAntigravityEvent(parsed);
20734
+ if (normalized) {
20735
+ return normalized.every((event) => handleAntigravityStructuredEvent(event, context, state));
20736
+ }
20737
+ const presenter = context.presenter;
20013
20738
  state.onNewOutput?.();
20014
20739
  const type = typeof parsed.type === "string" ? parsed.type : "";
20015
- if (!type) return;
20740
+ if (!type) return false;
20016
20741
  if (typeof parsed.session_id === "string") state.runtimeSessionId = parsed.session_id;
20017
20742
  if (typeof parsed.conversation_id === "string") state.runtimeSessionId = parsed.conversation_id;
20018
20743
  if (typeof parsed.model === "string") state.activeModel = parsed.model;
20744
+ if (typeof state.runtimeSessionId === "string" && state.runtimeSessionId.trim()) {
20745
+ registerAntigravityParentTranscript(state.runtimeSessionId, context, state);
20746
+ }
20019
20747
  switch (type) {
20020
20748
  case "init":
20021
20749
  case "session_start": {
@@ -20023,29 +20751,31 @@ function parseAntigravityStructuredLine(line, context, state) {
20023
20751
  void presenter.onLog(
20024
20752
  `[antigravity] Session initialized with ${formatAntigravityModelName(model)}`
20025
20753
  );
20026
- break;
20754
+ return true;
20027
20755
  }
20756
+ case "antigravity_step_update":
20757
+ return true;
20028
20758
  case "thinking":
20029
20759
  case "reasoning":
20030
20760
  case "thought": {
20031
20761
  const text = extractText(parsed);
20032
- if (!text) break;
20762
+ if (!text) return true;
20033
20763
  state.iterations = Math.max(state.iterations, 1);
20034
20764
  void presenter.onThinking(text);
20035
- break;
20765
+ return true;
20036
20766
  }
20037
20767
  case "message":
20038
20768
  case "assistant_message":
20039
20769
  case "text":
20040
20770
  case "content": {
20041
20771
  const role = typeof parsed.role === "string" ? parsed.role : "assistant";
20042
- if (role !== "assistant") break;
20772
+ if (role !== "assistant") return true;
20043
20773
  const content = extractText(parsed);
20044
- if (!content) break;
20774
+ if (!content) return true;
20045
20775
  state.iterations = Math.max(state.iterations, 1);
20046
20776
  state.summary += content;
20047
20777
  void presenter.onAssistantText(content);
20048
- break;
20778
+ return true;
20049
20779
  }
20050
20780
  case "tool_use":
20051
20781
  case "tool_call":
@@ -20054,7 +20784,7 @@ function parseAntigravityStructuredLine(line, context, state) {
20054
20784
  const toolId = extractToolId(parsed, state);
20055
20785
  state.iterations = Math.max(state.iterations, 1);
20056
20786
  void presenter.onToolUse(extractToolName(parsed), extractToolInput(parsed), toolId);
20057
- break;
20787
+ return true;
20058
20788
  }
20059
20789
  case "subagent_start":
20060
20790
  case "subagent_started":
@@ -20064,12 +20794,22 @@ function parseAntigravityStructuredLine(line, context, state) {
20064
20794
  case "background_subagent_started": {
20065
20795
  const toolId = extractToolId(parsed, state);
20066
20796
  state.iterations = Math.max(state.iterations, 1);
20797
+ registerBackgroundLauncher(state, toolId);
20798
+ registerBackgroundTaskRecord(state, { ...parsed, tool_use_id: toolId }, toolId);
20067
20799
  void presenter.onToolUse(
20068
20800
  `Subagent: ${extractSubagentName(parsed)}`,
20069
20801
  extractSubagentInput(parsed),
20070
20802
  toolId
20071
20803
  );
20072
- break;
20804
+ if (parsed.antigravity_live === true || stringField2(parsed, "log_uri")) {
20805
+ registerAntigravitySubagentTranscript(parsed, toolId, context, state);
20806
+ }
20807
+ return true;
20808
+ }
20809
+ case "subagent_launch_ack": {
20810
+ const toolId = extractToolId(parsed, state);
20811
+ registerAntigravitySubagentTranscript(parsed, toolId, context, state);
20812
+ return true;
20073
20813
  }
20074
20814
  case "tool_result":
20075
20815
  case "tool_response":
@@ -20078,24 +20818,52 @@ function parseAntigravityStructuredLine(line, context, state) {
20078
20818
  const toolId = extractToolId(parsed, state);
20079
20819
  state.iterations = Math.max(state.iterations, 1);
20080
20820
  void presenter.onToolResult?.(toolId, buildToolResultText(parsed));
20081
- break;
20821
+ return true;
20082
20822
  }
20083
20823
  case "subagent_result":
20084
20824
  case "subagent_complete":
20085
20825
  case "subagent_completed":
20086
20826
  case "background_subagent_result":
20087
20827
  case "background_subagent_completed": {
20088
- const toolId = extractToolId(parsed, state);
20089
20828
  state.iterations = Math.max(state.iterations, 1);
20090
- void presenter.onToolResult?.(toolId, buildToolResultText(parsed));
20091
- break;
20829
+ const toolId = extractToolId(parsed, state);
20830
+ const settledToolId = settleBackgroundTerminalNotification(
20831
+ "antigravity_cli",
20832
+ context,
20833
+ state,
20834
+ { ...parsed, tool_use_id: toolId },
20835
+ {
20836
+ resultText: buildSubagentResultText(parsed),
20837
+ isError: isFailedBackgroundStatus(parsed),
20838
+ emitToolResult: (toolId2, text, isError) => {
20839
+ void presenter.onToolResult?.(toolId2, text, isError);
20840
+ }
20841
+ }
20842
+ );
20843
+ if (settledToolId) state.antigravitySubagentTranscripts?.delete(settledToolId);
20844
+ return true;
20845
+ }
20846
+ case "subagent_status":
20847
+ case "background_subagent_status":
20848
+ case "background_task_status": {
20849
+ registerBackgroundTaskRecord(state, parsed);
20850
+ if (isTerminalBackgroundStatus(parsed)) {
20851
+ settleBackgroundTerminalNotification("antigravity_cli", context, state, parsed, {
20852
+ resultText: buildSubagentResultText(parsed),
20853
+ isError: isFailedBackgroundStatus(parsed),
20854
+ emitToolResult: (toolId, text, isError) => {
20855
+ void presenter.onToolResult?.(toolId, text, isError);
20856
+ }
20857
+ });
20858
+ }
20859
+ return true;
20092
20860
  }
20093
20861
  case "image_generation_end":
20094
20862
  case "generated_image":
20095
20863
  case "image": {
20096
20864
  const image = buildGeneratedImageFromAntigravityPayload(parsed);
20097
20865
  if (image) void presenter.onGeneratedImage?.(image);
20098
- break;
20866
+ return true;
20099
20867
  }
20100
20868
  case "error": {
20101
20869
  const errObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : null;
@@ -20109,20 +20877,31 @@ function parseAntigravityStructuredLine(line, context, state) {
20109
20877
  void presenter.onLog(`[antigravity/${severity}] ${message}`);
20110
20878
  }
20111
20879
  }
20112
- break;
20880
+ return true;
20113
20881
  }
20114
20882
  case "result":
20115
20883
  case "complete": {
20116
- const stats = typeof parsed.stats === "object" && parsed.stats !== null ? parsed.stats : parsed;
20117
- state.iterations = Math.max(state.iterations, 1);
20884
+ const stats = asRecord(parsed.usage) ?? asRecord(parsed.stats) ?? parsed;
20885
+ state.iterations = Math.max(
20886
+ state.iterations,
20887
+ typeof parsed.num_turns === "number" ? parsed.num_turns : 1
20888
+ );
20889
+ const resultText = typeof parsed.result === "string" ? parsed.result : "";
20890
+ if (resultText && !state.summary.trim()) {
20891
+ state.summary += resultText;
20892
+ void presenter.onAssistantText(resultText);
20893
+ }
20118
20894
  const usageModel = state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel : "antigravity");
20119
20895
  state.usage = {
20120
20896
  model: formatAntigravityModelName(usageModel),
20121
20897
  numTurns: Math.max(state.iterations, 1),
20898
+ // AGY's result.duration_seconds is conversation-scoped on resumed
20899
+ // sessions, so it is not a trustworthy per-turn duration. Keep this at
20900
+ // zero until the stream provides a dedicated turn-level metric.
20122
20901
  durationMs: typeof stats.duration_ms === "number" ? stats.duration_ms : 0,
20123
20902
  inputTokens: typeof stats.input_tokens === "number" ? stats.input_tokens : typeof stats.input === "number" ? stats.input : 0,
20124
20903
  outputTokens: typeof stats.output_tokens === "number" ? stats.output_tokens : 0,
20125
- cacheReadTokens: typeof stats.cached === "number" ? stats.cached : 0,
20904
+ cacheReadTokens: typeof stats.cache_read_tokens === "number" ? stats.cache_read_tokens : typeof stats.cached_input_tokens === "number" ? stats.cached_input_tokens : typeof stats.cached === "number" ? stats.cached : 0,
20126
20905
  cacheCreationTokens: 0,
20127
20906
  costUsd: 0
20128
20907
  };
@@ -20133,15 +20912,15 @@ function parseAntigravityStructuredLine(line, context, state) {
20133
20912
  cacheReadTokens: state.usage.cacheReadTokens,
20134
20913
  cacheCreationTokens: state.usage.cacheCreationTokens
20135
20914
  });
20136
- if (type === "complete" || parsed.status === "success") state.resultReceived = true;
20137
- state.onResultReceived?.();
20138
- if (typeof parsed.status === "string" && parsed.status !== "success" && !state.error) {
20915
+ const status = typeof parsed.status === "string" ? parsed.status.toLowerCase() : "";
20916
+ if (status && !["success", "completed", "complete"].includes(status) && !state.error) {
20139
20917
  const errObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : null;
20140
- const errMsg = typeof parsed.error === "string" && parsed.error.trim() || errObj && typeof errObj.message === "string" && errObj.message.trim() || typeof parsed.error_message === "string" && parsed.error_message.trim() || typeof parsed.message === "string" && parsed.message.trim() || typeof parsed.result === "string" && parsed.result.trim() || parsed.status;
20918
+ const errMsg = typeof parsed.error === "string" && parsed.error.trim() || errObj && typeof errObj.message === "string" && errObj.message.trim() || typeof parsed.error_message === "string" && parsed.error_message.trim() || typeof parsed.message === "string" && parsed.message.trim() || typeof parsed.result === "string" && parsed.result.trim() || status;
20141
20919
  state.error = errMsg;
20920
+ void presenter.onError(errMsg);
20142
20921
  console.error(
20143
20922
  "[antigravity] result status=",
20144
- parsed.status,
20923
+ status,
20145
20924
  "error:",
20146
20925
  JSON.stringify({
20147
20926
  error: parsed.error,
@@ -20150,12 +20929,23 @@ function parseAntigravityStructuredLine(line, context, state) {
20150
20929
  })
20151
20930
  );
20152
20931
  }
20153
- break;
20932
+ const completedSuccessfully = !status || ["success", "completed", "complete"].includes(status);
20933
+ if (type === "complete" || status) {
20934
+ settleAntigravitySubagentTranscripts(context, state, !completedSuccessfully);
20935
+ }
20936
+ if (type === "complete" || status === "success") {
20937
+ deferOrFinalizeStructuredResult("antigravity_cli", context, state);
20938
+ }
20939
+ return true;
20154
20940
  }
20155
20941
  default:
20156
- break;
20942
+ return false;
20157
20943
  }
20158
20944
  }
20945
+ var parseAntigravityStructuredLine = createStructuredLineParser(
20946
+ "antigravity_cli",
20947
+ handleAntigravityStructuredEvent
20948
+ );
20159
20949
  function parseAntigravityLine(line, context, state) {
20160
20950
  try {
20161
20951
  JSON.parse(line);
@@ -20204,7 +20994,14 @@ function detectAntigravityCliCapabilities(command, context) {
20204
20994
  version: versionOutput || void 0,
20205
20995
  supportsStructuredPrint: hasOutputFormat && hasStructuredFormat,
20206
20996
  supportsConversationResume: help.includes("--conversation") || help.includes("--continue"),
20207
- supportsReliableNonTtyPrint: help.includes("-p") || help.includes("--print") || help.includes("--print-timeout")
20997
+ supportsReliableNonTtyPrint: help.includes("-p") || help.includes("--print") || help.includes("--print-timeout"),
20998
+ supportsAddDir: help.includes("--add-dir"),
20999
+ supportsAgentSelection: help.includes("--agent"),
21000
+ supportsExecutionMode: help.includes("--mode"),
21001
+ supportsSandbox: help.includes("--sandbox"),
21002
+ supportsProject: help.includes("--project"),
21003
+ supportsNewProject: help.includes("--new-project"),
21004
+ supportsJsonSchema: help.includes("--json-schema")
20208
21005
  };
20209
21006
  capabilityCache.set(cacheKey, capabilities);
20210
21007
  return capabilities;
@@ -20229,7 +21026,33 @@ function buildAntigravityCliArgs(context, prompt, defaultArgs = [], capabilities
20229
21026
  if (effort && isEffortLevel(effort)) args.push("--effort", effort);
20230
21027
  }
20231
21028
  if (resumeId) args.push("--conversation", resumeId);
20232
- if (!shouldUseReadOnlyRuntimePermissions(context.config)) {
21029
+ const antigravity = context.config.antigravity;
21030
+ if (capabilities?.supportsAddDir) {
21031
+ const workspacePaths = Array.from(
21032
+ new Set(
21033
+ (antigravity?.additionalWorkspacePaths ?? []).map((path) => path.trim()).filter(Boolean)
21034
+ )
21035
+ );
21036
+ for (const path of workspacePaths) args.push("--add-dir", path);
21037
+ }
21038
+ const agent = antigravity?.agent?.trim();
21039
+ if (agent && capabilities?.supportsAgentSelection) args.push("--agent", agent);
21040
+ const project = antigravity?.project?.trim();
21041
+ if (project && capabilities?.supportsProject) {
21042
+ args.push("--project", project);
21043
+ } else if (antigravity?.newProject && capabilities?.supportsNewProject) {
21044
+ args.push("--new-project");
21045
+ }
21046
+ const jsonSchema = antigravity?.jsonSchema?.trim();
21047
+ if (jsonSchema && capabilities?.supportsJsonSchema) args.push("--json-schema", jsonSchema);
21048
+ const readOnly = shouldUseReadOnlyRuntimePermissions(context.config);
21049
+ if (capabilities?.supportsExecutionMode) {
21050
+ args.push("--mode", readOnly ? "plan" : "accept-edits");
21051
+ }
21052
+ if (readOnly && capabilities?.supportsSandbox) {
21053
+ args.push("--sandbox");
21054
+ }
21055
+ if (!readOnly) {
20233
21056
  args.push("--dangerously-skip-permissions");
20234
21057
  }
20235
21058
  if (capabilities?.supportsStructuredPrint) {
@@ -20243,7 +21066,11 @@ function buildAntigravityAugmentedPrompt(context, images) {
20243
21066
  context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim()
20244
21067
  );
20245
21068
  const base = buildResumeAwarePrompt(context.config, context.promptText, { isResume });
20246
- const prompt = context.config.mode === "plan" ? buildPlanModePrefix(base) : base;
21069
+ const workspaceInstructions = isResume ? void 0 : buildAntigravityWorkspaceInstructions(context.cwd);
21070
+ const withWorkspaceInstructions = workspaceInstructions ? `${workspaceInstructions}
21071
+
21072
+ ${base}` : base;
21073
+ const prompt = context.config.mode === "plan" ? buildPlanModePrefix(withWorkspaceInstructions) : withWorkspaceInstructions;
20247
21074
  return appendImagePathReferences(prompt, images);
20248
21075
  }
20249
21076
  function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
@@ -20278,18 +21105,18 @@ function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
20278
21105
  }
20279
21106
  function resolveClaudeHome(env, variant = "claude") {
20280
21107
  if (variant === "supatest") {
20281
- return (0, import_path4.join)((0, import_os4.homedir)(), ".supatest", "claude-internal");
21108
+ return (0, import_path6.join)((0, import_os5.homedir)(), ".supatest", "claude-internal");
20282
21109
  }
20283
- return env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || (0, import_path4.join)((0, import_os4.homedir)(), ".claude");
21110
+ return env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || (0, import_path6.join)((0, import_os5.homedir)(), ".claude");
20284
21111
  }
20285
21112
  function encodeClaudeProjectDir(cwd) {
20286
21113
  return cwd.replace(/[^a-zA-Z0-9]/g, "-");
20287
21114
  }
20288
21115
  function claudeSessionLogExists(input) {
20289
21116
  if (!input.sessionId || !input.cwd) return false;
20290
- const projectDir = (0, import_path4.join)(input.home, "projects", encodeClaudeProjectDir(input.cwd));
20291
- if (!(0, import_fs4.existsSync)(projectDir)) return false;
20292
- return (0, import_fs4.existsSync)((0, import_path4.join)(projectDir, `${input.sessionId}.jsonl`));
21117
+ const projectDir = (0, import_path6.join)(input.home, "projects", encodeClaudeProjectDir(input.cwd));
21118
+ if (!(0, import_fs6.existsSync)(projectDir)) return false;
21119
+ return (0, import_fs6.existsSync)((0, import_path6.join)(projectDir, `${input.sessionId}.jsonl`));
20293
21120
  }
20294
21121
  var execFileAsync = (0, import_util4.promisify)(import_child_process4.execFile);
20295
21122
  var flagSupportCache = /* @__PURE__ */ new Map();
@@ -20315,234 +21142,6 @@ async function cliSupportsFlag(command, flag, env = {}) {
20315
21142
  flagSupportCache.set(key, supported);
20316
21143
  return supported;
20317
21144
  }
20318
- function stringField(record2, key) {
20319
- const value2 = record2[key];
20320
- return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
20321
- }
20322
- function backgroundTaskKeys(record2) {
20323
- return [
20324
- stringField(record2, "task_id"),
20325
- stringField(record2, "taskId"),
20326
- stringField(record2, "tool_use_id"),
20327
- stringField(record2, "toolUseId"),
20328
- stringField(record2, "id")
20329
- ].filter((key) => Boolean(key));
20330
- }
20331
- function backgroundTaskId(record2) {
20332
- return stringField(record2, "task_id") ?? stringField(record2, "taskId");
20333
- }
20334
- function backgroundToolUseId(record2) {
20335
- return stringField(record2, "tool_use_id") ?? stringField(record2, "toolUseId");
20336
- }
20337
- function registerBackgroundTaskIds(state, keys) {
20338
- for (const key of keys) {
20339
- if (!key) continue;
20340
- if (!state.activeBackgroundTaskIds) state.activeBackgroundTaskIds = /* @__PURE__ */ new Set();
20341
- state.activeBackgroundTaskIds.add(key);
20342
- }
20343
- }
20344
- function registerBackgroundLauncher(state, toolUseId) {
20345
- registerBackgroundTaskIds(state, [toolUseId]);
20346
- if (!state.pendingLauncherToolIds) state.pendingLauncherToolIds = [];
20347
- if (!state.pendingLauncherToolIds.includes(toolUseId)) {
20348
- state.pendingLauncherToolIds.push(toolUseId);
20349
- }
20350
- }
20351
- function drainNextUnlinkedBackgroundLauncher(state) {
20352
- const launcherId = state.pendingLauncherToolIds?.shift();
20353
- if (state.pendingLauncherToolIds?.length === 0) state.pendingLauncherToolIds = void 0;
20354
- if (launcherId) clearBackgroundTaskIds(state, [launcherId]);
20355
- return launcherId;
20356
- }
20357
- function registerBackgroundTaskRecord(state, record2, launcherToolUseId) {
20358
- const taskId = backgroundTaskId(record2);
20359
- let toolUseId = backgroundToolUseId(record2) ?? launcherToolUseId ?? void 0;
20360
- if (!toolUseId && taskId) {
20361
- const nextLauncher = state.pendingLauncherToolIds?.[0];
20362
- if (nextLauncher) {
20363
- toolUseId = nextLauncher;
20364
- } else if (state.activeBackgroundTaskIds?.size === 1) {
20365
- const [candidate] = state.activeBackgroundTaskIds;
20366
- if (candidate && candidate !== taskId) toolUseId = candidate;
20367
- }
20368
- }
20369
- registerBackgroundTaskIds(state, backgroundTaskKeys(record2));
20370
- if (!taskId || !toolUseId) return;
20371
- if (state.pendingLauncherToolIds) {
20372
- const idx = state.pendingLauncherToolIds.indexOf(toolUseId);
20373
- if (idx >= 0) state.pendingLauncherToolIds.splice(idx, 1);
20374
- if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
20375
- }
20376
- if (!state.backgroundToolIdByTaskId) state.backgroundToolIdByTaskId = /* @__PURE__ */ new Map();
20377
- if (!state.backgroundTaskIdsByToolId) state.backgroundTaskIdsByToolId = /* @__PURE__ */ new Map();
20378
- state.backgroundToolIdByTaskId.set(taskId, toolUseId);
20379
- const taskIds = state.backgroundTaskIdsByToolId.get(toolUseId) ?? /* @__PURE__ */ new Set();
20380
- taskIds.add(taskId);
20381
- state.backgroundTaskIdsByToolId.set(toolUseId, taskIds);
20382
- }
20383
- function clearBackgroundTaskIds(state, keys) {
20384
- const activeIds = state.activeBackgroundTaskIds;
20385
- if (!activeIds) return;
20386
- for (const key of keys) {
20387
- if (!key) continue;
20388
- activeIds.delete(key);
20389
- const toolUseId = state.backgroundToolIdByTaskId?.get(key);
20390
- if (toolUseId) {
20391
- activeIds.delete(toolUseId);
20392
- state.backgroundToolIdByTaskId?.delete(key);
20393
- const taskIds2 = state.backgroundTaskIdsByToolId?.get(toolUseId);
20394
- taskIds2?.delete(key);
20395
- if (taskIds2?.size === 0) state.backgroundTaskIdsByToolId?.delete(toolUseId);
20396
- }
20397
- const taskIds = state.backgroundTaskIdsByToolId?.get(key);
20398
- if (taskIds) {
20399
- for (const taskId of taskIds) {
20400
- activeIds.delete(taskId);
20401
- state.backgroundToolIdByTaskId?.delete(taskId);
20402
- }
20403
- state.backgroundTaskIdsByToolId?.delete(key);
20404
- }
20405
- }
20406
- if (state.pendingLauncherToolIds) {
20407
- state.pendingLauncherToolIds = state.pendingLauncherToolIds.filter((id) => activeIds.has(id));
20408
- if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
20409
- }
20410
- if (activeIds.size === 0) state.activeBackgroundTaskIds = void 0;
20411
- }
20412
- function resolveBackgroundTaskToolUseId(state, record2) {
20413
- const explicitToolUseId = backgroundToolUseId(record2);
20414
- if (explicitToolUseId) return explicitToolUseId;
20415
- const taskId = backgroundTaskId(record2);
20416
- return taskId ? state.backgroundToolIdByTaskId?.get(taskId) : void 0;
20417
- }
20418
- var TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20419
- "complete",
20420
- "completed",
20421
- "done",
20422
- "success",
20423
- "succeeded",
20424
- "failed",
20425
- "failure",
20426
- "error",
20427
- "cancelled",
20428
- "canceled",
20429
- "aborted",
20430
- "interrupted",
20431
- "stopped"
20432
- ]);
20433
- var NON_TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20434
- "running",
20435
- "in_progress",
20436
- "inprogress",
20437
- "started",
20438
- "pending",
20439
- "active",
20440
- "working",
20441
- "queued"
20442
- ]);
20443
- var ASYNC_LAUNCH_ACK_RE = /^(async agent launched successfully|background (?:task|agent|subagent) (?:launched|started|running)|task (?:launched|started) successfully)/i;
20444
- function isTerminalBackgroundStatus(record2) {
20445
- const status = stringField(record2, "status")?.toLowerCase();
20446
- if (status && TERMINAL_BACKGROUND_STATUSES.has(status)) return true;
20447
- if (status && NON_TERMINAL_BACKGROUND_STATUSES.has(status)) return false;
20448
- return typeof record2.duration_ms === "number" || typeof record2.durationMs === "number" || typeof record2.total_tokens === "number" || typeof record2.totalTokens === "number" || typeof record2.tool_uses === "number" || typeof record2.toolUses === "number";
20449
- }
20450
- function isFailedBackgroundStatus(record2) {
20451
- const status = stringField(record2, "status")?.toLowerCase();
20452
- return status === "failed" || status === "failure" || status === "error" || status === "cancelled" || status === "canceled" || status === "aborted" || status === "interrupted";
20453
- }
20454
- function extractBackgroundTaskIdFromPayload(value2) {
20455
- if (typeof value2 === "string") {
20456
- const trimmed = value2.trim();
20457
- if (!trimmed) return void 0;
20458
- try {
20459
- return extractBackgroundTaskIdFromPayload(JSON.parse(trimmed));
20460
- } catch {
20461
- const match = trimmed.match(/\btask[_-]?id["']?\s*[:=]\s*["']?([A-Za-z0-9_.-]+)/i) ?? trimmed.match(/\btasks\/([A-Za-z0-9_.-]+)/i);
20462
- if (match?.[1]) return match[1];
20463
- if (/^[A-Za-z0-9_-]{6,128}$/.test(trimmed) && /(?:task|bg|async|job|agent)/i.test(trimmed)) {
20464
- return trimmed;
20465
- }
20466
- return void 0;
20467
- }
20468
- }
20469
- if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return void 0;
20470
- const record2 = value2;
20471
- return stringField(record2, "task_id") ?? stringField(record2, "taskId") ?? stringField(record2, "agentId") ?? stringField(record2, "agent_id") ?? extractBackgroundTaskIdFromPayload(record2.value) ?? extractBackgroundTaskIdFromPayload(record2.result) ?? extractBackgroundTaskIdFromPayload(record2.data) ?? extractBackgroundTaskIdFromPayload(record2.content);
20472
- }
20473
- function looksLikeBackgroundLaunchAck(options) {
20474
- const taskId = extractBackgroundTaskIdFromPayload(options.value) ?? extractBackgroundTaskIdFromPayload(options.content);
20475
- const content = options.content.trim();
20476
- const explicitAckText = ASYNC_LAUNCH_ACK_RE.test(content);
20477
- if (!options.trackedUnlinkedLauncher) return { isAck: false, taskId };
20478
- if (options.explicitBackground && taskId) return { isAck: true, taskId };
20479
- if (explicitAckText) return { isAck: true, taskId };
20480
- if (taskId && content.length > 0 && content.length < 400) {
20481
- const record2 = options.value && typeof options.value === "object" && !Array.isArray(options.value) ? options.value : null;
20482
- const looksStructured = record2 !== null || content.startsWith("{") || /^task[_-]?id\b/i.test(content) || content === taskId;
20483
- if (looksStructured) return { isAck: true, taskId };
20484
- }
20485
- return { isAck: false, taskId };
20486
- }
20487
- function settleBackgroundTerminalNotification(kind, context, state, record2, options) {
20488
- const toolUseId = resolveBackgroundTaskToolUseId(state, record2);
20489
- const keys = backgroundTaskKeys(record2);
20490
- const wasActive = !!toolUseId && state.activeBackgroundTaskIds?.has(toolUseId) === true || keys.some((key) => state.activeBackgroundTaskIds?.has(key) === true);
20491
- if (toolUseId && wasActive) {
20492
- options.emitToolResult(toolUseId, options.resultText, options.isError);
20493
- clearBackgroundTaskIds(state, keys);
20494
- maybeFinalizeDeferredResult(kind, context, state);
20495
- return toolUseId;
20496
- }
20497
- clearBackgroundTaskIds(state, keys);
20498
- const drainedLauncher = drainNextUnlinkedBackgroundLauncher(state);
20499
- if (drainedLauncher) {
20500
- options.emitToolResult(drainedLauncher, options.resultText, options.isError);
20501
- }
20502
- maybeFinalizeDeferredResult(kind, context, state);
20503
- return drainedLauncher;
20504
- }
20505
- function finalizeStructuredResult(kind, state) {
20506
- state.resultReceived = true;
20507
- state.onResultReceived?.();
20508
- if (state.stdin && !state.stdin.destroyed) {
20509
- state.stdin.end();
20510
- console.info(`[${kind}] Closed stdin after result event to signal CLI exit`);
20511
- }
20512
- }
20513
- function deferOrFinalizeStructuredResult(kind, context, state) {
20514
- const pendingAsks = context.presenter.pendingAskUserToolIds?.size ?? 0;
20515
- if (pendingAsks > 0) {
20516
- console.info(
20517
- `[${kind}] Keeping stdin open \u2014 ${pendingAsks} interactive question(s) awaiting user response`
20518
- );
20519
- state.resultDeferredOnPendingAnswer = true;
20520
- return "deferred_pending_answer";
20521
- }
20522
- const activeBackgroundTasks = state.activeBackgroundTaskIds?.size ?? 0;
20523
- if (activeBackgroundTasks > 0) {
20524
- console.info(
20525
- `[${kind}] Keeping stdin open \u2014 ${activeBackgroundTasks} background task(s) still active`
20526
- );
20527
- state.resultDeferredOnBackgroundWork = true;
20528
- return "deferred_background_work";
20529
- }
20530
- finalizeStructuredResult(kind, state);
20531
- return "finalized";
20532
- }
20533
- function maybeFinalizeDeferredResult(kind, context, state) {
20534
- if (!state.resultDeferredOnBackgroundWork && !state.resultDeferredOnPendingAnswer) return;
20535
- if (context.presenter.pendingAskUserToolIds?.size || state.activeBackgroundTaskIds?.size) return;
20536
- if (state.resultDeferredOnBackgroundWork) {
20537
- state.awaitingPostBackgroundSynthesis = true;
20538
- console.info(
20539
- `[${kind}] Background work drained \u2014 awaiting post-subagent synthesis before stdin close`
20540
- );
20541
- return;
20542
- }
20543
- state.resultDeferredOnPendingAnswer = false;
20544
- finalizeStructuredResult(kind, state);
20545
- }
20546
21145
  var DEBUG_ASK = process.env.ALAN_DEBUG_ASK === "1" || process.env.ALAN_DEBUG === "1";
20547
21146
  function debugAskLog(message) {
20548
21147
  if (DEBUG_ASK) console.info(message);
@@ -20580,22 +21179,22 @@ function extractToolResultContent(content) {
20580
21179
  return "";
20581
21180
  }).filter(Boolean).join("\n");
20582
21181
  }
20583
- function stringField2(record2, key) {
21182
+ function stringField3(record2, key) {
20584
21183
  const value2 = record2[key];
20585
21184
  return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
20586
21185
  }
20587
21186
  function isTerminalTaskNotification(record2) {
20588
- const status = stringField2(record2, "status")?.toLowerCase();
21187
+ const status = stringField3(record2, "status")?.toLowerCase();
20589
21188
  if (status && TERMINAL_TASK_NOTIFICATION_STATUSES.has(status)) return true;
20590
21189
  if (status && NON_TERMINAL_TASK_NOTIFICATION_STATUSES.has(status)) return false;
20591
21190
  return typeof record2.duration_ms === "number" || typeof record2.durationMs === "number" || typeof record2.total_tokens === "number" || typeof record2.totalTokens === "number" || typeof record2.tool_uses === "number" || typeof record2.toolUses === "number";
20592
21191
  }
20593
21192
  function isFailedTaskNotification(record2) {
20594
- const status = stringField2(record2, "status")?.toLowerCase();
21193
+ const status = stringField3(record2, "status")?.toLowerCase();
20595
21194
  return status === "failed" || status === "failure" || status === "error" || status === "cancelled" || status === "canceled";
20596
21195
  }
20597
21196
  function formatClaudeTaskNotificationResult(record2) {
20598
- const status = stringField2(record2, "status") ?? "completed";
21197
+ const status = stringField3(record2, "status") ?? "completed";
20599
21198
  const details = [`Subagent ${status}.`];
20600
21199
  const durationMs = record2.duration_ms ?? record2.durationMs;
20601
21200
  const toolUses = record2.tool_uses ?? record2.toolUses;
@@ -21032,29 +21631,29 @@ function normalizeCodexMcpToolResult(output) {
21032
21631
  return raw;
21033
21632
  }
21034
21633
  function resolveCodexHome(env) {
21035
- return env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path5.join)((0, import_os5.homedir)(), ".codex");
21634
+ return env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path7.join)((0, import_os6.homedir)(), ".codex");
21036
21635
  }
21037
21636
  function findCodexSessionLog(runtimeSessionId, codexHome) {
21038
- if (!runtimeSessionId || !(0, import_fs5.existsSync)(codexHome)) return null;
21039
- const root = (0, import_path5.join)(codexHome, "sessions");
21040
- if (!(0, import_fs5.existsSync)(root)) return null;
21637
+ if (!runtimeSessionId || !(0, import_fs7.existsSync)(codexHome)) return null;
21638
+ const root = (0, import_path7.join)(codexHome, "sessions");
21639
+ if (!(0, import_fs7.existsSync)(root)) return null;
21041
21640
  const matches = [];
21042
21641
  const stack = [root];
21043
21642
  while (stack.length > 0) {
21044
21643
  const dir = stack.pop();
21045
21644
  let entries;
21046
21645
  try {
21047
- entries = (0, import_fs5.readdirSync)(dir, { withFileTypes: true });
21646
+ entries = (0, import_fs7.readdirSync)(dir, { withFileTypes: true });
21048
21647
  } catch {
21049
21648
  continue;
21050
21649
  }
21051
21650
  for (const entry of entries) {
21052
- const path = (0, import_path5.join)(dir, entry.name);
21651
+ const path = (0, import_path7.join)(dir, entry.name);
21053
21652
  if (entry.isDirectory()) {
21054
21653
  stack.push(path);
21055
21654
  } else if (entry.isFile() && entry.name.includes(runtimeSessionId) && entry.name.endsWith(".jsonl")) {
21056
21655
  try {
21057
- matches.push({ path, mtimeMs: (0, import_fs5.statSync)(path).mtimeMs });
21656
+ matches.push({ path, mtimeMs: (0, import_fs7.statSync)(path).mtimeMs });
21058
21657
  } catch {
21059
21658
  matches.push({ path, mtimeMs: 0 });
21060
21659
  }
@@ -21108,21 +21707,21 @@ function firstUserMessageLineIndex(lines) {
21108
21707
  const line = lines[index];
21109
21708
  if (!line) continue;
21110
21709
  const entry = parseJsonObject(line);
21111
- const payload = asRecord(entry?.payload);
21710
+ const payload = asRecord2(entry?.payload);
21112
21711
  if (payload?.type === "message" && payload.role === "user" && !isSyntheticUserRolloutMessage(payload)) {
21113
21712
  return index;
21114
21713
  }
21115
21714
  }
21116
21715
  return -1;
21117
21716
  }
21118
- function asRecord(value2) {
21717
+ function asRecord2(value2) {
21119
21718
  return value2 && typeof value2 === "object" ? value2 : null;
21120
21719
  }
21121
21720
  function rolloutTextContent(content) {
21122
21721
  if (typeof content === "string") return content;
21123
21722
  if (!Array.isArray(content)) return "";
21124
21723
  return content.flatMap((block) => {
21125
- const record2 = asRecord(block);
21724
+ const record2 = asRecord2(block);
21126
21725
  const text = record2?.text;
21127
21726
  return typeof text === "string" ? [text] : [];
21128
21727
  }).join("");
@@ -21151,14 +21750,14 @@ function collectCodexWorkerReplays(lines, state) {
21151
21750
  const workersByThreadId = /* @__PURE__ */ new Map();
21152
21751
  for (const line of lines) {
21153
21752
  const entry = parseJsonObject(line);
21154
- const payload = asRecord(entry?.payload);
21753
+ const payload = asRecord2(entry?.payload);
21155
21754
  if (!payload) continue;
21156
21755
  if (entry?.type === "response_item" && payload.type === "function_call" && payload.name === "spawn_agent") {
21157
21756
  const namespace = typeof payload.namespace === "string" ? payload.namespace : "";
21158
21757
  if (namespace !== "collaboration" && namespace !== "multi_agent_v1") continue;
21159
21758
  const callId = typeof payload.call_id === "string" ? payload.call_id : "";
21160
21759
  if (!callId) continue;
21161
- const args = asRecord(parseMaybeJson(payload.arguments));
21760
+ const args = asRecord2(parseMaybeJson(payload.arguments));
21162
21761
  const taskName = typeof args?.task_name === "string" ? args.task_name : "";
21163
21762
  const message = typeof args?.message === "string" ? args.message : "";
21164
21763
  spawnByCallId.set(callId, {
@@ -21171,7 +21770,7 @@ function collectCodexWorkerReplays(lines, state) {
21171
21770
  const callId = typeof payload.call_id === "string" ? payload.call_id : "";
21172
21771
  const spawn32 = spawnByCallId.get(callId);
21173
21772
  if (!spawn32) continue;
21174
- const output = asRecord(parseMaybeJson(payload.output));
21773
+ const output = asRecord2(parseMaybeJson(payload.output));
21175
21774
  const threadId = typeof output?.agent_id === "string" ? output.agent_id : "";
21176
21775
  if (!threadId) continue;
21177
21776
  const nickname = typeof output?.nickname === "string" ? output.nickname : void 0;
@@ -21213,7 +21812,7 @@ function replayCodexWorkerTranscript(context, worker, codexHome, state) {
21213
21812
  if (!state.codexWorkerSessionLogPathByThreadId)
21214
21813
  state.codexWorkerSessionLogPathByThreadId = /* @__PURE__ */ new Map();
21215
21814
  state.codexWorkerSessionLogPathByThreadId.set(worker.threadId, logPath);
21216
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21815
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21217
21816
  const firstUserLineIndex = firstUserMessageLineIndex(allLines);
21218
21817
  const lines = firstUserLineIndex >= 0 ? allLines.slice(firstUserLineIndex + 1) : allLines;
21219
21818
  const emittedToolNames = /* @__PURE__ */ new Map();
@@ -21224,7 +21823,7 @@ function replayCodexWorkerTranscript(context, worker, codexHome, state) {
21224
21823
  if (!line) continue;
21225
21824
  const entry = parseJsonObject(line);
21226
21825
  if (entry?.type !== "response_item") continue;
21227
- const payload = asRecord(entry.payload);
21826
+ const payload = asRecord2(entry.payload);
21228
21827
  if (!payload) continue;
21229
21828
  if (payload.type === "message" && payload.role === "assistant") {
21230
21829
  const text = rolloutTextContent(payload.content);
@@ -21318,7 +21917,7 @@ function syncCodexWorkerEventsFromSessionLog(context, state) {
21318
21917
  const logPath = state.codexSessionLogPath ?? findCodexSessionLog(runtimeSessionId, codexHome);
21319
21918
  if (!logPath) return [];
21320
21919
  state.codexSessionLogPath = logPath;
21321
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21920
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21322
21921
  const latestUserLineIndex = latestUserMessageLineIndex(allLines);
21323
21922
  const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
21324
21923
  const workers = collectCodexWorkerReplays(lines, state);
@@ -21357,7 +21956,7 @@ async function replayCodexMcpToolEventsFromSessionLog(context, state) {
21357
21956
  const codexHome = resolveCodexHome(context.env);
21358
21957
  const logPath = findCodexSessionLog(runtimeSessionId, codexHome);
21359
21958
  if (!logPath) return;
21360
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21959
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21361
21960
  const latestUserLineIndex = latestUserMessageLineIndex(allLines);
21362
21961
  const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
21363
21962
  const streamedToolIds = state.codexStreamedToolIds ?? /* @__PURE__ */ new Set();
@@ -22207,7 +22806,7 @@ ${ctx.promptText}` : ctx.promptText;
22207
22806
  };
22208
22807
  }
22209
22808
  var explicitBackgroundLaunchers = /* @__PURE__ */ new WeakMap();
22210
- function asRecord2(value2) {
22809
+ function asRecord3(value2) {
22211
22810
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
22212
22811
  }
22213
22812
  function asString(value2) {
@@ -22338,7 +22937,7 @@ function handleCopilotStructuredEvent(parsed, context, state) {
22338
22937
  case "tool.execution_start": {
22339
22938
  const toolId = typeof data.toolCallId === "string" ? data.toolCallId : `copilot-tool-${Date.now()}`;
22340
22939
  const rawName = typeof data.toolName === "string" ? data.toolName : "Copilot Tool";
22341
- const rawArgs = asRecord2(data.arguments) ?? {};
22940
+ const rawArgs = asRecord3(data.arguments) ?? {};
22342
22941
  const softTrack = isCloudDelegateTool(rawName, rawArgs);
22343
22942
  const localBg = isLocalBackgroundLauncher(rawName, rawArgs);
22344
22943
  const args = softTrack || localBg ? normalizeLauncherArgs(rawArgs, softTrack) : rawArgs;
@@ -22497,7 +23096,7 @@ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
22497
23096
  }
22498
23097
  };
22499
23098
  }
22500
- function asRecord3(value2) {
23099
+ function asRecord4(value2) {
22501
23100
  return typeof value2 === "object" && value2 !== null ? value2 : null;
22502
23101
  }
22503
23102
  function extractCursorToolEntry(toolCall) {
@@ -22519,12 +23118,12 @@ function formatCursorToolName(rawName, payload) {
22519
23118
  return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^[a-z]/, (char) => char.toUpperCase());
22520
23119
  }
22521
23120
  function cursorTaskResultVariant(payload, variant) {
22522
- const result = asRecord3(payload.result);
23121
+ const result = asRecord4(payload.result);
22523
23122
  if (!result) return null;
22524
- const direct = asRecord3(result[variant]);
23123
+ const direct = asRecord4(result[variant]);
22525
23124
  if (direct) return direct;
22526
- const oneof = asRecord3(result.result);
22527
- return oneof?.case === variant ? asRecord3(oneof.value) : null;
23125
+ const oneof = asRecord4(result.result);
23126
+ return oneof?.case === variant ? asRecord4(oneof.value) : null;
22528
23127
  }
22529
23128
  function cursorSubagentType(value2) {
22530
23129
  const normalize = (candidate) => {
@@ -22535,18 +23134,18 @@ function cursorSubagentType(value2) {
22535
23134
  return trimmed;
22536
23135
  };
22537
23136
  if (typeof value2 === "string") return normalize(value2);
22538
- const record2 = asRecord3(value2);
23137
+ const record2 = asRecord4(value2);
22539
23138
  if (!record2) return void 0;
22540
23139
  if (typeof record2.case === "string" && record2.case) return normalize(record2.case);
22541
23140
  if (typeof record2.type === "string" && record2.type) return normalize(record2.type);
22542
- const nestedType = asRecord3(record2.type);
23141
+ const nestedType = asRecord4(record2.type);
22543
23142
  if (typeof nestedType?.case === "string" && nestedType.case) return normalize(nestedType.case);
22544
23143
  return normalize(
22545
23144
  Object.keys(nestedType ?? record2).find((key) => key !== "value" && key !== "case")
22546
23145
  );
22547
23146
  }
22548
23147
  function cursorToolArgs(entry) {
22549
- const args = asRecord3(entry.payload.args) ?? asRecord3(entry.payload.arguments) ?? entry.payload;
23148
+ const args = asRecord4(entry.payload.args) ?? asRecord4(entry.payload.arguments) ?? entry.payload;
22550
23149
  if (entry.rawName !== "taskToolCall") return args;
22551
23150
  const subagentType = cursorSubagentType(args.subagentType ?? args.subagent_type);
22552
23151
  return {
@@ -22557,15 +23156,15 @@ function cursorToolArgs(entry) {
22557
23156
  };
22558
23157
  }
22559
23158
  function cursorConversationStepValue(step, key) {
22560
- const direct = asRecord3(step[key]);
23159
+ const direct = asRecord4(step[key]);
22561
23160
  if (direct) return direct;
22562
- const message = asRecord3(step.message);
22563
- return message?.case === key ? asRecord3(message.value) : null;
23161
+ const message = asRecord4(step.message);
23162
+ return message?.case === key ? asRecord4(message.value) : null;
22564
23163
  }
22565
23164
  function cursorConversationStepText(steps) {
22566
23165
  if (!Array.isArray(steps)) return "";
22567
23166
  return steps.flatMap((step) => {
22568
- const record2 = asRecord3(step);
23167
+ const record2 = asRecord4(step);
22569
23168
  if (!record2) return [];
22570
23169
  const assistant = cursorConversationStepValue(record2, "assistantMessage");
22571
23170
  return typeof assistant?.text === "string" ? [assistant.text] : [];
@@ -22595,7 +23194,7 @@ function buildCursorToolResultText(result) {
22595
23194
  function emitCursorSubagentConversationSteps(steps, parentToolUseId, presenter) {
22596
23195
  if (!Array.isArray(steps)) return;
22597
23196
  steps.forEach((step, index) => {
22598
- const record2 = asRecord3(step);
23197
+ const record2 = asRecord4(step);
22599
23198
  if (!record2) return;
22600
23199
  const assistant = cursorConversationStepValue(record2, "assistantMessage");
22601
23200
  if (typeof assistant?.text === "string" && assistant.text) {
@@ -22636,7 +23235,7 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22636
23235
  }
22637
23236
  let lines;
22638
23237
  try {
22639
- lines = (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
23238
+ lines = (0, import_fs8.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
22640
23239
  if (lines.at(-1) === "") lines.pop();
22641
23240
  } catch {
22642
23241
  return { found: false, processedLineCount: startLine, emittedEventCount: 0 };
@@ -22657,10 +23256,10 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22657
23256
  }
22658
23257
  processedLineCount = lineIndex + 1;
22659
23258
  if (entry.role !== "assistant") continue;
22660
- const message = asRecord3(entry.message);
23259
+ const message = asRecord4(entry.message);
22661
23260
  const content = Array.isArray(message?.content) ? message.content : [];
22662
23261
  content.forEach((rawBlock, blockIndex) => {
22663
- const block = asRecord3(rawBlock);
23262
+ const block = asRecord4(rawBlock);
22664
23263
  if (!block) return;
22665
23264
  const type = typeof block.type === "string" ? block.type : "";
22666
23265
  const text = typeof block.text === "string" ? block.text : "";
@@ -22678,18 +23277,18 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22678
23277
  const name = typeof block.name === "string" && block.name ? block.name : "Cursor Tool";
22679
23278
  const toolId = typeof block.id === "string" && block.id || `${parentToolUseId}-transcript-${lineIndex}-${blockIndex}`;
22680
23279
  emittedEventCount += 1;
22681
- void presenter.onToolUse(name, asRecord3(block.input) ?? {}, toolId, parentToolUseId);
23280
+ void presenter.onToolUse(name, asRecord4(block.input) ?? {}, toolId, parentToolUseId);
22682
23281
  });
22683
23282
  }
22684
23283
  return { found: true, processedLineCount, emittedEventCount };
22685
23284
  }
22686
23285
  function cursorTranscriptsRoot(context) {
22687
23286
  const projectKey = context.cwd.replace(/^[/\\]+/, "").replace(/[/\\]+/g, "-");
22688
- const home = context.env.HOME || process.env.HOME || (0, import_os6.homedir)();
22689
- return (0, import_path6.join)(home, ".cursor", "projects", projectKey, "agent-transcripts");
23287
+ const home = context.env.HOME || process.env.HOME || (0, import_os7.homedir)();
23288
+ return (0, import_path8.join)(home, ".cursor", "projects", projectKey, "agent-transcripts");
22690
23289
  }
22691
23290
  function cursorTranscriptPathForAgent(context, agentId) {
22692
- return (0, import_path6.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
23291
+ return (0, import_path8.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
22693
23292
  }
22694
23293
  function resolveCursorSubagentTranscriptPath(success2, context) {
22695
23294
  const explicit = success2?.transcriptPath ?? success2?.transcript_path;
@@ -22699,14 +23298,14 @@ function resolveCursorSubagentTranscriptPath(success2, context) {
22699
23298
  }
22700
23299
  function cursorTranscriptUserText(transcriptPath) {
22701
23300
  try {
22702
- for (const line of (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/)) {
23301
+ for (const line of (0, import_fs8.readFileSync)(transcriptPath, "utf8").split(/\r?\n/)) {
22703
23302
  if (!line) continue;
22704
- const entry = asRecord3(JSON.parse(line));
23303
+ const entry = asRecord4(JSON.parse(line));
22705
23304
  if (entry?.role !== "user") continue;
22706
- const message = asRecord3(entry.message);
23305
+ const message = asRecord4(entry.message);
22707
23306
  const content = Array.isArray(message?.content) ? message.content : [];
22708
23307
  return content.flatMap((block) => {
22709
- const record2 = asRecord3(block);
23308
+ const record2 = asRecord4(block);
22710
23309
  return typeof record2?.text === "string" ? [record2.text] : [];
22711
23310
  }).join("");
22712
23311
  }
@@ -22716,13 +23315,13 @@ function cursorTranscriptUserText(transcriptPath) {
22716
23315
  }
22717
23316
  function discoverCursorSubagentTranscript(context, state, task) {
22718
23317
  const root = cursorTranscriptsRoot(context);
22719
- if (!(0, import_fs6.existsSync)(root)) return void 0;
23318
+ if (!(0, import_fs8.existsSync)(root)) return void 0;
22720
23319
  const prompt = task.prompt?.trim();
22721
23320
  const description = task.description?.trim().toLowerCase();
22722
23321
  const candidates = [];
22723
23322
  let entries;
22724
23323
  try {
22725
- entries = (0, import_fs6.readdirSync)(root, { withFileTypes: true });
23324
+ entries = (0, import_fs8.readdirSync)(root, { withFileTypes: true });
22726
23325
  } catch {
22727
23326
  return void 0;
22728
23327
  }
@@ -22731,7 +23330,7 @@ function discoverCursorSubagentTranscript(context, state, task) {
22731
23330
  const path = cursorTranscriptPathForAgent(context, entry.name);
22732
23331
  let mtimeMs;
22733
23332
  try {
22734
- mtimeMs = (0, import_fs6.statSync)(path).mtimeMs;
23333
+ mtimeMs = (0, import_fs8.statSync)(path).mtimeMs;
22735
23334
  } catch {
22736
23335
  continue;
22737
23336
  }
@@ -23157,7 +23756,7 @@ var DROID_TASK_OUTPUT_NAMES = /* @__PURE__ */ new Set(["taskoutput", "task_outpu
23157
23756
  var DROID_TASK_STOP_NAMES = /* @__PURE__ */ new Set(["taskstop", "task_stop"]);
23158
23757
  var pendingTaskIdByToolId = /* @__PURE__ */ new WeakMap();
23159
23758
  var explicitBackgroundLaunchers2 = /* @__PURE__ */ new WeakMap();
23160
- function asRecord4(value2) {
23759
+ function asRecord5(value2) {
23161
23760
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23162
23761
  }
23163
23762
  function asString2(value2) {
@@ -23309,7 +23908,7 @@ function handleDroidStructuredEvent(parsed, context, state) {
23309
23908
  const ack = looksLikeBackgroundLaunchAck({
23310
23909
  content,
23311
23910
  value: value2,
23312
- explicitBackground: wasExplicitBackground2(state, toolId) || boolish2(asRecord4(value2)?.run_in_background),
23911
+ explicitBackground: wasExplicitBackground2(state, toolId) || boolish2(asRecord5(value2)?.run_in_background),
23313
23912
  trackedUnlinkedLauncher: trackedLauncher && !linkedBackground
23314
23913
  });
23315
23914
  if (ack.isAck && ack.taskId) {
@@ -23451,7 +24050,7 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
23451
24050
  };
23452
24051
  }
23453
24052
  var ACP_PROTOCOL_VERSION = 1;
23454
- function asRecord5(value2) {
24053
+ function asRecord6(value2) {
23455
24054
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23456
24055
  }
23457
24056
  function asString3(value2) {
@@ -23461,7 +24060,7 @@ function resumeSessionId(context) {
23461
24060
  return context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim() || "";
23462
24061
  }
23463
24062
  function chunkText(content) {
23464
- const record2 = asRecord5(content);
24063
+ const record2 = asRecord6(content);
23465
24064
  if (!record2) return "";
23466
24065
  if (typeof record2.text === "string") return record2.text;
23467
24066
  return chunkText(record2.content);
@@ -23477,8 +24076,8 @@ function toolResultText(update) {
23477
24076
  return "";
23478
24077
  }
23479
24078
  function toolMetaName(update) {
23480
- const meta3 = asRecord5(update._meta);
23481
- const tool = asRecord5(meta3?.["x.ai/tool"]);
24079
+ const meta3 = asRecord6(update._meta);
24080
+ const tool = asRecord6(meta3?.["x.ai/tool"]);
23482
24081
  return asString3(tool?.name);
23483
24082
  }
23484
24083
  function normalizeToolKey2(name) {
@@ -23509,18 +24108,18 @@ function normalizeGrokSubagentInput(toolName, rawInput) {
23509
24108
  return input;
23510
24109
  }
23511
24110
  function resolvePermission(params, context) {
23512
- const record2 = asRecord5(params);
24111
+ const record2 = asRecord6(params);
23513
24112
  const options = Array.isArray(record2?.options) ? record2?.options : [];
23514
- const toolCall = asRecord5(record2?.toolCall);
23515
- const meta3 = asRecord5(toolCall?._meta);
23516
- const tool = asRecord5(meta3?.["x.ai/tool"]);
24113
+ const toolCall = asRecord6(record2?.toolCall);
24114
+ const meta3 = asRecord6(toolCall?._meta);
24115
+ const tool = asRecord6(meta3?.["x.ai/tool"]);
23517
24116
  const isReadOnlyTool = tool?.read_only === true || asString3(tool?.kind) === "read";
23518
24117
  const allow = !shouldUseReadOnlyRuntimePermissions(context.config) || isReadOnlyTool;
23519
24118
  const allowKinds = ["allow_always", "allow_once", "allow"];
23520
24119
  const rejectKinds = ["reject_always", "reject_once", "reject", "deny"];
23521
24120
  const wanted = allow ? allowKinds : rejectKinds;
23522
- const chosen = options.find((option) => wanted.includes(asString3(asRecord5(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
23523
- const optionId = asString3(asRecord5(chosen)?.optionId);
24121
+ const chosen = options.find((option) => wanted.includes(asString3(asRecord6(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
24122
+ const optionId = asString3(asRecord6(chosen)?.optionId);
23524
24123
  if (!optionId) return { outcome: { outcome: "cancelled" } };
23525
24124
  return { outcome: { outcome: "selected", optionId } };
23526
24125
  }
@@ -23613,9 +24212,9 @@ function createGrokAcpDriver(imageFiles) {
23613
24212
  forceFinalize(state);
23614
24213
  return;
23615
24214
  }
23616
- const result = asRecord5(message.result);
24215
+ const result = asRecord6(message.result);
23617
24216
  if (message.id === initId) {
23618
- const modelState = asRecord5(asRecord5(result?._meta)?.modelState);
24217
+ const modelState = asRecord6(asRecord6(result?._meta)?.modelState);
23619
24218
  const model = asString3(modelState?.currentModelId);
23620
24219
  if (model) state.activeModel = model;
23621
24220
  beginSession(context, state);
@@ -23629,7 +24228,7 @@ function createGrokAcpDriver(imageFiles) {
23629
24228
  return;
23630
24229
  }
23631
24230
  if (message.id === promptId) {
23632
- const meta3 = asRecord5(result?._meta);
24231
+ const meta3 = asRecord6(result?._meta);
23633
24232
  const model = asString3(meta3?.modelId) || state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel.trim() : "grok");
23634
24233
  const inputTokens = typeof meta3?.inputTokens === "number" ? meta3.inputTokens : 0;
23635
24234
  const outputTokens = typeof meta3?.outputTokens === "number" ? meta3.outputTokens : 0;
@@ -23676,8 +24275,8 @@ function createGrokAcpDriver(imageFiles) {
23676
24275
  }
23677
24276
  }
23678
24277
  function handleNotification(message, context, state) {
23679
- const params = asRecord5(message.params);
23680
- const update = asRecord5(params?.update);
24278
+ const params = asRecord6(message.params);
24279
+ const update = asRecord6(params?.update);
23681
24280
  if (!update || !isPromptActive) return;
23682
24281
  const presenter = context.presenter;
23683
24282
  switch (asString3(update.sessionUpdate)) {
@@ -23699,7 +24298,7 @@ function createGrokAcpDriver(imageFiles) {
23699
24298
  case "tool_call": {
23700
24299
  const toolId = asString3(update.toolCallId);
23701
24300
  const rawName = asString3(update.title) || toolMetaName(update) || "Grok Tool";
23702
- const rawInput = asRecord5(update.rawInput);
24301
+ const rawInput = asRecord6(update.rawInput);
23703
24302
  const isSubagent = isGrokSubagentTool(rawName, rawInput);
23704
24303
  const toolName = isSubagent ? presentGrokSubagentName(rawName) : rawName;
23705
24304
  const input = isSubagent ? normalizeGrokSubagentInput(rawName, rawInput) : rawInput ?? {};
@@ -23774,7 +24373,7 @@ function createGrokAcpDriver(imageFiles) {
23774
24373
  if (line.trim().length > 0) void context.presenter.onLog(`[grok_cli] ${line}`);
23775
24374
  return;
23776
24375
  }
23777
- const message = asRecord5(parsed);
24376
+ const message = asRecord6(parsed);
23778
24377
  if (!message) return;
23779
24378
  if (message.id !== void 0 && message.method === void 0) {
23780
24379
  handleResponse(message, context, state);
@@ -23841,9 +24440,9 @@ function buildGrokAgentArgs(config2, defaultArgs = []) {
23841
24440
  return args;
23842
24441
  }
23843
24442
  var DEFAULT_SKILL_ROOTS = [
23844
- (0, import_path7.join)((0, import_os7.homedir)(), ".agents", "skills"),
23845
- (0, import_path7.join)((0, import_os7.homedir)(), ".claude", "skills"),
23846
- (0, import_path7.join)((0, import_os7.homedir)(), ".config", "opencode", "skills")
24443
+ (0, import_path9.join)((0, import_os8.homedir)(), ".agents", "skills"),
24444
+ (0, import_path9.join)((0, import_os8.homedir)(), ".claude", "skills"),
24445
+ (0, import_path9.join)((0, import_os8.homedir)(), ".config", "opencode", "skills")
23847
24446
  ];
23848
24447
  function parseFrontmatter(content) {
23849
24448
  if (!content.startsWith("---\n")) return {};
@@ -23859,12 +24458,12 @@ function parseFrontmatter(content) {
23859
24458
  return result;
23860
24459
  }
23861
24460
  function listSkillFiles(root) {
23862
- if (!(0, import_fs7.existsSync)(root)) return [];
24461
+ if (!(0, import_fs9.existsSync)(root)) return [];
23863
24462
  const files = [];
23864
- for (const entry of (0, import_fs7.readdirSync)(root, { withFileTypes: true })) {
24463
+ for (const entry of (0, import_fs9.readdirSync)(root, { withFileTypes: true })) {
23865
24464
  if (!entry.isDirectory()) continue;
23866
- const skillPath = (0, import_path7.join)(root, entry.name, "SKILL.md");
23867
- if ((0, import_fs7.existsSync)(skillPath)) files.push(skillPath);
24465
+ const skillPath = (0, import_path9.join)(root, entry.name, "SKILL.md");
24466
+ if ((0, import_fs9.existsSync)(skillPath)) files.push(skillPath);
23868
24467
  }
23869
24468
  return files;
23870
24469
  }
@@ -23873,7 +24472,7 @@ function loadInstalledSkills(roots = DEFAULT_SKILL_ROOTS) {
23873
24472
  for (const root of roots) {
23874
24473
  for (const skillPath of listSkillFiles(root)) {
23875
24474
  try {
23876
- const frontmatter = parseFrontmatter((0, import_fs7.readFileSync)(skillPath, "utf8"));
24475
+ const frontmatter = parseFrontmatter((0, import_fs9.readFileSync)(skillPath, "utf8"));
23877
24476
  const name = frontmatter.name;
23878
24477
  const description = frontmatter.description;
23879
24478
  if (!name || !description || skills.has(name)) continue;
@@ -23912,7 +24511,7 @@ var KIMI_SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
23912
24511
  "subagent"
23913
24512
  ]);
23914
24513
  var explicitBackgroundLaunchers3 = /* @__PURE__ */ new WeakMap();
23915
- function asRecord6(value2) {
24514
+ function asRecord7(value2) {
23916
24515
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23917
24516
  }
23918
24517
  function asString4(value2) {
@@ -24094,7 +24693,7 @@ function handleKimiStructuredEvent(parsed, context, state) {
24094
24693
  );
24095
24694
  return true;
24096
24695
  }
24097
- const statusRecord = asRecord6(
24696
+ const statusRecord = asRecord7(
24098
24697
  (() => {
24099
24698
  try {
24100
24699
  return JSON.parse(content);
@@ -24427,10 +25026,18 @@ var parseOpencodeStructuredLine = createStructuredLineParser(
24427
25026
  "opencode_cli",
24428
25027
  handleOpencodeStructuredEvent
24429
25028
  );
25029
+ function normalizeOpenCodeVariant(value2) {
25030
+ const trimmed = value2?.trim();
25031
+ const containsControlCharacter = Array.from(trimmed ?? "").some((character) => {
25032
+ const code = character.charCodeAt(0);
25033
+ return code <= 31 || code === 127;
25034
+ });
25035
+ if (!trimmed || trimmed.length > 256 || containsControlCharacter) return null;
25036
+ return trimmed;
25037
+ }
24430
25038
  function buildOpencodeEffortArgs(selectedEffortLevel) {
24431
- const trimmed = selectedEffortLevel?.trim().toLowerCase();
24432
- if (!trimmed || !isEffortLevel(trimmed)) return [];
24433
- return ["--variant", trimmed];
25039
+ const variant = normalizeOpenCodeVariant(selectedEffortLevel);
25040
+ return variant ? ["--variant", variant] : [];
24434
25041
  }
24435
25042
  function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
24436
25043
  return {
@@ -24547,9 +25154,27 @@ var SERVER_LISTENING_PATTERN = /listening on (https?:\/\/\S+)/i;
24547
25154
  var STARTUP_TIMEOUT_MS = 2e4;
24548
25155
  var HEALTH_POLL_INTERVAL_MS = 200;
24549
25156
  var HEALTH_POLL_MAX_ATTEMPTS = 50;
25157
+ var LEASE_IDLE_TTL_MS = 10 * 60 * 1e3;
25158
+ var serveLeases = /* @__PURE__ */ new Map();
25159
+ function leaseKeyFor(context) {
25160
+ const conversationId = context.config.conversationId?.trim();
25161
+ return conversationId ? `conv:${conversationId}` : null;
25162
+ }
25163
+ function isLeaseUsable(lease) {
25164
+ const alive = lease.child.exitCode === null && lease.child.signalCode === null;
25165
+ const fresh = Date.now() - lease.lastUsedAtMs <= LEASE_IDLE_TTL_MS;
25166
+ return alive && fresh;
25167
+ }
25168
+ function evictLease(key) {
25169
+ if (!key) return;
25170
+ const lease = serveLeases.get(key);
25171
+ if (!lease) return;
25172
+ serveLeases.delete(key);
25173
+ killProcessTree(lease.child.pid, { signal: "SIGTERM", child: lease.child });
25174
+ }
24550
25175
  function startOpenCodeServer(command, context) {
24551
25176
  const child = spawnCli(command, ["serve", "--port", "0", "--hostname", "127.0.0.1"], context);
24552
- const ready = new Promise((resolve22, reject) => {
25177
+ const ready = new Promise((resolve42, reject) => {
24553
25178
  let settled = false;
24554
25179
  const timeout = setTimeout(() => {
24555
25180
  if (settled) return;
@@ -24567,7 +25192,7 @@ function startOpenCodeServer(command, context) {
24567
25192
  if (!match) return;
24568
25193
  settled = true;
24569
25194
  clearTimeout(timeout);
24570
- resolve22({ baseUrl: match[1].replace(/\/$/, "") });
25195
+ resolve42({ baseUrl: match[1].replace(/\/$/, "") });
24571
25196
  };
24572
25197
  stdoutRl.on("line", checkLine);
24573
25198
  stderrRl.on("line", (line) => {
@@ -24605,7 +25230,7 @@ async function waitForHealthy(baseUrl, signal) {
24605
25230
  }
24606
25231
  } catch {
24607
25232
  }
24608
- await new Promise((resolve22) => setTimeout(resolve22, HEALTH_POLL_INTERVAL_MS));
25233
+ await new Promise((resolve42) => setTimeout(resolve42, HEALTH_POLL_INTERVAL_MS));
24609
25234
  }
24610
25235
  throw new Error(`opencode server at ${baseUrl} did not become healthy in time`);
24611
25236
  }
@@ -24642,27 +25267,30 @@ function buildPromptParts(promptText, imageFiles, attachmentFiles) {
24642
25267
  type: "file",
24643
25268
  mime: file2.mimeType,
24644
25269
  filename: file2.filename,
24645
- url: (0, import_url.pathToFileURL)(file2.path).href
25270
+ url: (0, import_url2.pathToFileURL)(file2.path).href
24646
25271
  })
24647
25272
  );
24648
25273
  return [...attachments, { type: "text", text: promptText }];
24649
25274
  }
24650
- async function sendPrompt(baseUrl, sessionId, context, parts2, signal) {
25275
+ function buildOpenCodePromptRequest(context, parts2) {
24651
25276
  const model = context.config.selectedModel?.trim();
24652
25277
  const modelBody = model?.includes("/") ? (() => {
24653
25278
  const slashIndex = model.indexOf("/");
24654
25279
  return { providerID: model.slice(0, slashIndex), modelID: model.slice(slashIndex + 1) };
24655
25280
  })() : void 0;
24656
- const variant = context.config.selectedEffortLevel?.trim().toLowerCase();
25281
+ const variant = normalizeOpenCodeVariant(context.config.selectedEffortLevel);
25282
+ return {
25283
+ parts: parts2,
25284
+ ...modelBody ? { model: modelBody } : {},
25285
+ ...variant ? { variant } : {}
25286
+ };
25287
+ }
25288
+ async function sendPrompt(baseUrl, sessionId, context, parts2, signal) {
24657
25289
  const response = await fetch(`${baseUrl}/session/${encodeURIComponent(sessionId)}/message`, {
24658
25290
  method: "POST",
24659
25291
  signal,
24660
25292
  headers: { "Content-Type": "application/json" },
24661
- body: JSON.stringify({
24662
- parts: parts2,
24663
- ...modelBody ? { model: modelBody } : {},
24664
- ...variant && isEffortLevel(variant) ? { variant } : {}
24665
- })
25293
+ body: JSON.stringify(buildOpenCodePromptRequest(context, parts2))
24666
25294
  });
24667
25295
  if (!response.ok) {
24668
25296
  const text = await response.text().catch(() => "");
@@ -24679,6 +25307,18 @@ async function replyToPermission(baseUrl, requestId, reply, signal) {
24679
25307
  console.warn("[opencode_serve] Failed to reply to permission request", requestId, error2);
24680
25308
  });
24681
25309
  }
25310
+ var NON_INTERACTIVE_PERMISSION_KINDS = /* @__PURE__ */ new Set(["question", "plan_enter", "plan_exit"]);
25311
+ function decideAndReplyToPermission(presenter, baseUrl, properties, readOnly, signal, origin) {
25312
+ const requestId = getString(properties.id);
25313
+ if (!requestId) return;
25314
+ const permissionKind = getString(properties.permission) || "an action";
25315
+ const nonInteractive = NON_INTERACTIVE_PERMISSION_KINDS.has(permissionKind);
25316
+ const reply = nonInteractive || readOnly ? "reject" : "once";
25317
+ const subject = origin === "root" ? "OpenCode" : "OpenCode's background session";
25318
+ const message = nonInteractive ? `${subject} tried to ${permissionKind.replace(/_/g, " ")} \u2014 denied (Alan does not yet support interactive requests for OpenCode).` : readOnly ? `${subject} requested permission to ${permissionKind} \u2014 automatically denied (read-only session).` : `${subject} requested permission to ${permissionKind} \u2014 automatically approved (autonomous mode).`;
25319
+ emitSessionNotice(presenter, "permission_decision", message);
25320
+ void replyToPermission(baseUrl, requestId, reply, signal);
25321
+ }
24682
25322
  function buildAgentResult(state, sessionId, aborted2) {
24683
25323
  if (aborted2) {
24684
25324
  return {
@@ -24726,7 +25366,13 @@ function createOpencodeServeBackend(command = "opencode") {
24726
25366
  );
24727
25367
  const runContext = withAutonomousOpenCodePermissions(context);
24728
25368
  const readOnly = shouldUseReadOnlyRuntimePermissions(context.config);
24729
- const { child, ready } = startOpenCodeServer(command, runContext);
25369
+ const leaseKey = leaseKeyFor(context);
25370
+ const existingLease = leaseKey ? serveLeases.get(leaseKey) : void 0;
25371
+ const reuseLease = Boolean(existingLease && isLeaseUsable(existingLease));
25372
+ if (existingLease && !reuseLease) evictLease(leaseKey);
25373
+ const spawnedServer = reuseLease && existingLease ? null : startOpenCodeServer(command, runContext);
25374
+ const child = reuseLease && existingLease ? existingLease.child : spawnedServer.child;
25375
+ const ready = reuseLease && existingLease ? Promise.resolve({ baseUrl: existingLease.baseUrl }) : spawnedServer.ready;
24730
25376
  const state = { process: child, iterations: 0, summary: "" };
24731
25377
  context.onProcessSpawned?.(child);
24732
25378
  context.registerLivenessProbe?.(() => ({
@@ -24739,13 +25385,19 @@ function createOpencodeServeBackend(command = "opencode") {
24739
25385
  const onAbort = () => {
24740
25386
  aborted2 = true;
24741
25387
  sseClose?.();
25388
+ if (leaseKey) serveLeases.delete(leaseKey);
24742
25389
  killProcessTree(child.pid, { signal: "SIGTERM", child });
24743
25390
  };
24744
25391
  context.abortController.signal.addEventListener("abort", onAbort, { once: true });
24745
25392
  try {
24746
25393
  const server = await ready;
24747
25394
  state.lastRawOutputAtMs = Date.now();
24748
- await waitForHealthy(server.baseUrl, context.abortController.signal);
25395
+ if (!reuseLease) {
25396
+ await waitForHealthy(server.baseUrl, context.abortController.signal);
25397
+ }
25398
+ if (leaseKey) {
25399
+ serveLeases.set(leaseKey, { child, baseUrl: server.baseUrl, lastUsedAtMs: Date.now() });
25400
+ }
24749
25401
  const session = await resolveSession(
24750
25402
  server.baseUrl,
24751
25403
  runContext,
@@ -24803,17 +25455,94 @@ function createOpencodeServeBackend(command = "opencode") {
24803
25455
  } finally {
24804
25456
  context.abortController.signal.removeEventListener("abort", onAbort);
24805
25457
  sseClose?.();
24806
- killProcessTree(child.pid, { signal: "SIGTERM", child });
25458
+ const wasAborted = aborted2 || context.abortController.signal.aborted;
25459
+ if (wasAborted || !leaseKey) {
25460
+ if (leaseKey) serveLeases.delete(leaseKey);
25461
+ killProcessTree(child.pid, { signal: "SIGTERM", child });
25462
+ } else {
25463
+ const lease = serveLeases.get(leaseKey);
25464
+ if (lease) lease.lastUsedAtMs = Date.now();
25465
+ }
24807
25466
  cleanupImages();
24808
25467
  cleanupFiles();
24809
25468
  }
24810
25469
  }
24811
25470
  };
24812
25471
  }
25472
+ function resolveChildSessionLauncherToolId(state, eventSessionId) {
25473
+ const existing = state.backgroundToolIdByTaskId?.get(eventSessionId);
25474
+ if (existing) return existing;
25475
+ registerBackgroundTaskRecord(state, { task_id: eventSessionId });
25476
+ return state.backgroundToolIdByTaskId?.get(eventSessionId);
25477
+ }
25478
+ function handleOpenCodeChildSessionEvent(event, eventSessionId, context, state, readOnly, baseUrl) {
25479
+ const properties = event.properties;
25480
+ switch (event.type) {
25481
+ case "message.updated": {
25482
+ const info = getRecord(properties.info);
25483
+ if (getString(info?.role) === "user") {
25484
+ const messageId = getString(info?.id);
25485
+ if (messageId) {
25486
+ state.opencodeUserMessageIds ??= /* @__PURE__ */ new Set();
25487
+ state.opencodeUserMessageIds.add(messageId);
25488
+ }
25489
+ }
25490
+ return false;
25491
+ }
25492
+ case "message.part.updated": {
25493
+ const part = getRecord(properties.part);
25494
+ if (!part) return false;
25495
+ const messageId = getString(part.messageID);
25496
+ if (messageId && state.opencodeUserMessageIds?.has(messageId)) return false;
25497
+ const parentToolUseId = resolveChildSessionLauncherToolId(state, eventSessionId);
25498
+ if (!parentToolUseId && !state.opencodeUnlinkedChildSessionIds?.has(eventSessionId)) {
25499
+ state.opencodeUnlinkedChildSessionIds ??= /* @__PURE__ */ new Set();
25500
+ state.opencodeUnlinkedChildSessionIds.add(eventSessionId);
25501
+ void context.presenter.onLog(
25502
+ `[opencode] Background session ${eventSessionId} is active (no linked launcher \u2014 showing at top level)`
25503
+ );
25504
+ }
25505
+ mapOpencodePart(part, context, state, { parentToolUseId });
25506
+ return false;
25507
+ }
25508
+ case "message.part.delta":
25509
+ return false;
25510
+ case "permission.asked": {
25511
+ decideAndReplyToPermission(
25512
+ context.presenter,
25513
+ baseUrl,
25514
+ properties,
25515
+ readOnly,
25516
+ context.abortController.signal,
25517
+ "background session"
25518
+ );
25519
+ return false;
25520
+ }
25521
+ case "session.error": {
25522
+ const errorRecord = getRecord(properties.error);
25523
+ const message = getString(errorRecord?.message) || getString(properties.error) || "Background OpenCode session error.";
25524
+ void context.presenter.onLog(
25525
+ `[opencode] Background session ${eventSessionId} error: ${message}`
25526
+ );
25527
+ return false;
25528
+ }
25529
+ default:
25530
+ return false;
25531
+ }
25532
+ }
24813
25533
  function handleOpenCodeServeEvent(event, sessionId, context, state, readOnly, baseUrl) {
24814
25534
  const properties = event.properties;
24815
25535
  const eventSessionId = getString(properties.sessionID);
24816
- if (eventSessionId && eventSessionId !== sessionId) return false;
25536
+ if (eventSessionId && eventSessionId !== sessionId) {
25537
+ return handleOpenCodeChildSessionEvent(
25538
+ event,
25539
+ eventSessionId,
25540
+ context,
25541
+ state,
25542
+ readOnly,
25543
+ baseUrl
25544
+ );
25545
+ }
24817
25546
  switch (event.type) {
24818
25547
  // Live-verified: the SSE bus emits a message.updated (and matching
24819
25548
  // message.part.updated) for the USER's own message too, not just the
@@ -24843,15 +25572,14 @@ function handleOpenCodeServeEvent(event, sessionId, context, state, readOnly, ba
24843
25572
  case "message.part.delta":
24844
25573
  return false;
24845
25574
  case "permission.asked": {
24846
- const requestId = getString(properties.id);
24847
- if (requestId) {
24848
- void replyToPermission(
24849
- baseUrl,
24850
- requestId,
24851
- readOnly ? "reject" : "once",
24852
- context.abortController.signal
24853
- );
24854
- }
25575
+ decideAndReplyToPermission(
25576
+ context.presenter,
25577
+ baseUrl,
25578
+ properties,
25579
+ readOnly,
25580
+ context.abortController.signal,
25581
+ "root"
25582
+ );
24855
25583
  return false;
24856
25584
  }
24857
25585
  case "session.error": {
@@ -25024,22 +25752,31 @@ function parseRepoNamespace(command) {
25024
25752
  };
25025
25753
  }
25026
25754
  function hasSkillLayout(dir) {
25027
- return SKILL_LAYOUT_PARTS.some((parts2) => (0, import_fs8.existsSync)((0, import_path8.join)(dir, ...parts2)));
25755
+ return SKILL_LAYOUT_PARTS.some((parts2) => (0, import_fs10.existsSync)((0, import_path10.join)(dir, ...parts2)));
25028
25756
  }
25029
25757
  function isGitRepo(dir) {
25030
- return (0, import_fs8.existsSync)((0, import_path8.join)(dir, ".git"));
25758
+ return (0, import_fs10.existsSync)((0, import_path10.join)(dir, ".git"));
25031
25759
  }
25032
25760
  function isLeafProjectRoot(dir) {
25033
25761
  return isGitRepo(dir) || hasSkillLayout(dir);
25034
25762
  }
25035
25763
  function skillDirsForRoot(root) {
25036
- return SKILL_LAYOUT_PARTS.map((parts2) => (0, import_path8.join)(root, ...parts2));
25764
+ return SKILL_LAYOUT_PARTS.map((parts2) => (0, import_path10.join)(root, ...parts2));
25765
+ }
25766
+ function pluginSkillDirsForRoot(root) {
25767
+ const pluginsDir = (0, import_path10.join)(root, ".agents", "plugins");
25768
+ if (!(0, import_fs10.existsSync)(pluginsDir)) return [];
25769
+ try {
25770
+ return (0, import_fs10.readdirSync)(pluginsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_path10.join)(pluginsDir, entry.name, "skills"));
25771
+ } catch {
25772
+ return [];
25773
+ }
25037
25774
  }
25038
25775
  function listImmediateChildDirs(cwd) {
25039
- if (!(0, import_fs8.existsSync)(cwd)) return [];
25776
+ if (!(0, import_fs10.existsSync)(cwd)) return [];
25040
25777
  let entries = [];
25041
25778
  try {
25042
- entries = (0, import_fs8.readdirSync)(cwd, { withFileTypes: true });
25779
+ entries = (0, import_fs10.readdirSync)(cwd, { withFileTypes: true });
25043
25780
  } catch {
25044
25781
  return [];
25045
25782
  }
@@ -25047,40 +25784,50 @@ function listImmediateChildDirs(cwd) {
25047
25784
  for (const entry of entries) {
25048
25785
  if (!entry.isDirectory()) continue;
25049
25786
  if (entry.name.startsWith(".")) continue;
25050
- children.push((0, import_path8.join)(cwd, entry.name));
25787
+ children.push((0, import_path10.join)(cwd, entry.name));
25051
25788
  }
25052
25789
  return children;
25053
25790
  }
25054
25791
  function projectCandidateRoots(cwd) {
25055
25792
  if (!cwd) return [];
25056
- const roots = [...skillDirsForRoot(cwd)];
25793
+ const roots = [...skillDirsForRoot(cwd), ...pluginSkillDirsForRoot(cwd)];
25057
25794
  if (!isLeafProjectRoot(cwd)) {
25058
25795
  for (const child of listImmediateChildDirs(cwd)) {
25059
25796
  roots.push(...skillDirsForRoot(child));
25797
+ roots.push(...pluginSkillDirsForRoot(child));
25060
25798
  }
25061
25799
  }
25062
25800
  return Array.from(new Set(roots));
25063
25801
  }
25064
- function globalCandidateRoots() {
25065
- return skillDirsForRoot((0, import_os8.homedir)());
25802
+ function globalCandidateRoots(home) {
25803
+ const antigravityConfig = (0, import_path10.join)(home, ".gemini", "config");
25804
+ return Array.from(
25805
+ /* @__PURE__ */ new Set([
25806
+ ...skillDirsForRoot(home),
25807
+ (0, import_path10.join)(antigravityConfig, "skills"),
25808
+ ...pluginSkillDirsForRoot(antigravityConfig)
25809
+ ])
25810
+ );
25066
25811
  }
25067
25812
  function namespacedCandidateRoots(cwd, repoLabel) {
25068
25813
  const roots = [];
25069
25814
  if (cwd) {
25070
- roots.push(...skillDirsForRoot((0, import_path8.join)(cwd, repoLabel)));
25815
+ roots.push(...skillDirsForRoot((0, import_path10.join)(cwd, repoLabel)));
25816
+ roots.push(...pluginSkillDirsForRoot((0, import_path10.join)(cwd, repoLabel)));
25071
25817
  const base = cwd.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
25072
25818
  if (base === repoLabel) {
25073
25819
  roots.push(...skillDirsForRoot(cwd));
25820
+ roots.push(...pluginSkillDirsForRoot(cwd));
25074
25821
  }
25075
25822
  }
25076
25823
  return Array.from(new Set(roots));
25077
25824
  }
25078
25825
  function readSkillAt(root, command) {
25079
- const skillPath = (0, import_path8.join)(root, command, "SKILL.md");
25080
- if (!(0, import_fs8.existsSync)(skillPath)) return null;
25826
+ const skillPath = (0, import_path10.join)(root, command, "SKILL.md");
25827
+ if (!(0, import_fs10.existsSync)(skillPath)) return null;
25081
25828
  let content;
25082
25829
  try {
25083
- content = (0, import_fs8.readFileSync)(skillPath, "utf-8");
25830
+ content = (0, import_fs10.readFileSync)(skillPath, "utf-8");
25084
25831
  } catch {
25085
25832
  return null;
25086
25833
  }
@@ -25103,7 +25850,7 @@ function collectMatches(roots, command, userRequest) {
25103
25850
  }
25104
25851
  return matches;
25105
25852
  }
25106
- function resolveSkillInvocation(text, cwd) {
25853
+ function resolveSkillInvocation(text, cwd, home = (0, import_os9.homedir)()) {
25107
25854
  const parsed = parseSkillInvocation(text);
25108
25855
  if (!parsed) return null;
25109
25856
  const projectExact = collectMatches(
@@ -25115,7 +25862,11 @@ function resolveSkillInvocation(text, cwd) {
25115
25862
  if (projectExact.length > 1) {
25116
25863
  return null;
25117
25864
  }
25118
- const globalExact = collectMatches(globalCandidateRoots(), parsed.command, parsed.userRequest);
25865
+ const globalExact = collectMatches(
25866
+ globalCandidateRoots(home),
25867
+ parsed.command,
25868
+ parsed.userRequest
25869
+ );
25119
25870
  if (globalExact.length === 1) return globalExact[0];
25120
25871
  const namespaced = parseRepoNamespace(parsed.command);
25121
25872
  if (!namespaced) return null;
@@ -25132,8 +25883,8 @@ function resolveSkillInvocation(text, cwd) {
25132
25883
  }
25133
25884
  return null;
25134
25885
  }
25135
- function expandSkillInvocationPrompt(text, cwd) {
25136
- const invocation = resolveSkillInvocation(text, cwd);
25886
+ function expandSkillInvocationPrompt(text, cwd, home = (0, import_os9.homedir)()) {
25887
+ const invocation = resolveSkillInvocation(text, cwd, home);
25137
25888
  if (!invocation) return { text, invocation: null };
25138
25889
  const request = invocation.userRequest || "(No additional request text was provided.)";
25139
25890
  return {
@@ -25157,7 +25908,6 @@ var DROID_DEFAULT_MODEL = "claude-opus-4-7";
25157
25908
  var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
25158
25909
  function normalizeBackendKind(kind) {
25159
25910
  if (kind === "codex") return "codex_app_server";
25160
- if (kind === "gemini" || kind === "gemini_cli") return "antigravity_cli";
25161
25911
  return kind || "claude_cli";
25162
25912
  }
25163
25913
  function firstCatalogModelId(backendKind) {
@@ -25567,18 +26317,18 @@ ${runtimeConfig.task}` } : {}
25567
26317
  `[base-machine-agent] Transient error (attempt ${attempt + 1}/${_BaseMachineAgent.MAX_RETRIES + 1}), retrying in ${delayMs}ms: ${lastResult.error}`
25568
26318
  );
25569
26319
  void this.presenter.onLog(`Transient error, retrying in ${Math.round(delayMs / 1e3)}s...`);
25570
- await new Promise((resolve22) => {
26320
+ await new Promise((resolve42) => {
25571
26321
  const signal = this.abortController?.signal;
25572
26322
  if (signal?.aborted) {
25573
- resolve22();
26323
+ resolve42();
25574
26324
  return;
25575
26325
  }
25576
- const timeoutId = setTimeout(resolve22, delayMs);
26326
+ const timeoutId = setTimeout(resolve42, delayMs);
25577
26327
  signal?.addEventListener(
25578
26328
  "abort",
25579
26329
  () => {
25580
26330
  clearTimeout(timeoutId);
25581
- resolve22();
26331
+ resolve42();
25582
26332
  },
25583
26333
  { once: true }
25584
26334
  );
@@ -25748,14 +26498,14 @@ function normalizePath2(candidate, cwd) {
25748
26498
  } catch {
25749
26499
  }
25750
26500
  if (path.startsWith("~/")) return null;
25751
- if ((0, import_path9.isAbsolute)(path)) return path;
25752
- return cwd ? (0, import_path9.join)(cwd, path) : null;
26501
+ if ((0, import_path11.isAbsolute)(path)) return path;
26502
+ return cwd ? (0, import_path11.join)(cwd, path) : null;
25753
26503
  }
25754
26504
  function resolveToolCwd(cwd, toolInput) {
25755
26505
  if (!isRecord(toolInput)) return cwd;
25756
26506
  const raw = typeof toolInput.cwd === "string" ? toolInput.cwd : typeof toolInput.workdir === "string" ? toolInput.workdir : typeof toolInput.workingDirectory === "string" ? toolInput.workingDirectory : null;
25757
26507
  if (!raw) return cwd;
25758
- return (0, import_path9.isAbsolute)(raw) || !cwd ? raw : (0, import_path9.join)(cwd, raw);
26508
+ return (0, import_path11.isAbsolute)(raw) || !cwd ? raw : (0, import_path11.join)(cwd, raw);
25759
26509
  }
25760
26510
  function extractBrowserMediaPathHints(content, cwd, toolName, options = {}, kind = "video") {
25761
26511
  if (!isAgentBrowserMediaInvocation(toolName, content, options.toolInput, kind)) return [];
@@ -25798,19 +26548,19 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
25798
26548
  const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
25799
26549
  for (const candidate of extractPathCandidates(content, options)) {
25800
26550
  const path = normalizePath2(candidate, effectiveCwd);
25801
- if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
26551
+ if (!path || seen.has(path) || !(0, import_fs11.existsSync)(path)) continue;
25802
26552
  seen.add(path);
25803
- const ext = (0, import_path9.extname)(path).toLowerCase();
26553
+ const ext = (0, import_path11.extname)(path).toLowerCase();
25804
26554
  const mimeType = IMAGE_MIME_BY_EXT[ext];
25805
26555
  if (!mimeType) continue;
25806
- const stat = (0, import_fs9.statSync)(path);
26556
+ const stat = (0, import_fs11.statSync)(path);
25807
26557
  if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_GENERATED_IMAGE_BYTES) continue;
25808
- const buffer = (0, import_fs9.readFileSync)(path);
26558
+ const buffer = (0, import_fs11.readFileSync)(path);
25809
26559
  const { width, height } = readImageDimensions2(buffer, mimeType);
25810
26560
  images.push({
25811
26561
  type: "generated_image",
25812
26562
  id: (0, import_crypto4.randomUUID)(),
25813
- filename: (0, import_path9.basename)(path),
26563
+ filename: (0, import_path11.basename)(path),
25814
26564
  mimeType,
25815
26565
  size: buffer.length,
25816
26566
  width,
@@ -25837,20 +26587,20 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
25837
26587
  const mimeByExt = kind === "video" ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT;
25838
26588
  for (const candidate of extractPathCandidates(content, options, extensionsPattern)) {
25839
26589
  const path = normalizePath2(candidate, effectiveCwd);
25840
- if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
26590
+ if (!path || seen.has(path) || !(0, import_fs11.existsSync)(path)) continue;
25841
26591
  seen.add(path);
25842
- const ext = (0, import_path9.extname)(path).toLowerCase();
26592
+ const ext = (0, import_path11.extname)(path).toLowerCase();
25843
26593
  const mimeType = mimeByExt[ext];
25844
26594
  if (!mimeType) continue;
25845
- const stat = (0, import_fs9.statSync)(path);
26595
+ const stat = (0, import_fs11.statSync)(path);
25846
26596
  if (!stat.isFile() || stat.size <= 0 || stat.size > maxBytes) continue;
25847
- const buffer = (0, import_fs9.readFileSync)(path);
26597
+ const buffer = (0, import_fs11.readFileSync)(path);
25848
26598
  const dimensions = kind === "image" ? readImageDimensions2(buffer, mimeType) : null;
25849
26599
  media.push({
25850
26600
  type: "session_media",
25851
26601
  kind,
25852
26602
  id: (0, import_crypto4.randomUUID)(),
25853
- filename: (0, import_path9.basename)(path),
26603
+ filename: (0, import_path11.basename)(path),
25854
26604
  mimeType,
25855
26605
  size: buffer.length,
25856
26606
  width: dimensions?.width,
@@ -25896,6 +26646,14 @@ var MCP_INSPECTION_PLANS = {
25896
26646
  args: ["mcp", "list"],
25897
26647
  updateGuidance: "Update OpenCode CLI",
25898
26648
  requireExpectedUrl: false
26649
+ },
26650
+ opencode_serve: {
26651
+ backendKind: "opencode_serve",
26652
+ providerLabel: "OpenCode CLI",
26653
+ command: "opencode",
26654
+ args: ["mcp", "list"],
26655
+ updateGuidance: "Update OpenCode CLI",
26656
+ requireExpectedUrl: false
25899
26657
  }
25900
26658
  };
25901
26659
  var UNSUPPORTED_COMMAND_PATTERN = /unknown (?:command|subcommand)|unrecognized (?:command|subcommand)|unexpected argument|invalid command|not a recognized command/i;
@@ -26065,8 +26823,8 @@ async function withTimeout(promise2, timeoutMs, fallback) {
26065
26823
  try {
26066
26824
  return await Promise.race([
26067
26825
  promise2,
26068
- new Promise((resolve7) => {
26069
- timer = setTimeout(() => resolve7(fallback), timeoutMs);
26826
+ new Promise((resolve9) => {
26827
+ timer = setTimeout(() => resolve9(fallback), timeoutMs);
26070
26828
  })
26071
26829
  ]);
26072
26830
  } finally {
@@ -26079,7 +26837,7 @@ async function collectCodexLimits(env) {
26079
26837
  const codexCommand = resolveExecutable("codex", runtimeEnv, "ALAN_CODEX_PATH");
26080
26838
  if (!codexCommand)
26081
26839
  return [];
26082
- return withTimeout(new Promise((resolve7) => {
26840
+ return withTimeout(new Promise((resolve9) => {
26083
26841
  const child = (0, import_node_child_process2.spawn)(codexCommand, ["-s", "read-only", "-a", "untrusted", "app-server"], {
26084
26842
  env: runtimeEnv,
26085
26843
  stdio: ["pipe", "pipe", "ignore"]
@@ -26091,7 +26849,7 @@ async function collectCodexLimits(env) {
26091
26849
  pending.clear();
26092
26850
  if (!child.killed)
26093
26851
  child.kill();
26094
- resolve7(windows);
26852
+ resolve9(windows);
26095
26853
  };
26096
26854
  const request = (method, params = {}) => {
26097
26855
  const id = nextId++;
@@ -28924,9 +29682,9 @@ var Socket2 = class extends Emitter {
28924
29682
  * @return a Promise that will be fulfilled when the server acknowledges the event
28925
29683
  */
28926
29684
  emitWithAck(ev, ...args) {
28927
- return new Promise((resolve7, reject) => {
29685
+ return new Promise((resolve9, reject) => {
28928
29686
  const fn = (arg1, arg2) => {
28929
- return arg1 ? reject(arg1) : resolve7(arg2);
29687
+ return arg1 ? reject(arg1) : resolve9(arg2);
28930
29688
  };
28931
29689
  fn.withError = true;
28932
29690
  args.push(fn);
@@ -31066,7 +31824,9 @@ var INSTALLABLE_PROVIDER_PACKAGES = {
31066
31824
  claude_cli: { npmPackage: "@anthropic-ai/claude-code", command: "claude", label: "Claude Code" },
31067
31825
  codex_app_server: { npmPackage: "@openai/codex", command: "codex", label: "Codex" },
31068
31826
  copilot_cli: { npmPackage: "@github/copilot", command: "copilot", label: "Copilot" },
31069
- opencode_cli: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" }
31827
+ opencode_cli: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" },
31828
+ // Server transport installs the same "opencode" binary.
31829
+ opencode_serve: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" }
31070
31830
  };
31071
31831
  var INSTALL_TIMEOUT_MS = 12e4;
31072
31832
  var installOutcomes = /* @__PURE__ */ new Map();
@@ -31085,7 +31845,7 @@ function pinnedVersion(npmPackage) {
31085
31845
  return "latest";
31086
31846
  }
31087
31847
  function runNpmInstall(installSpec, env, timeoutMs) {
31088
- return new Promise((resolve7) => {
31848
+ return new Promise((resolve9) => {
31089
31849
  const isWin = (0, import_node_os5.platform)() === "win32";
31090
31850
  let child;
31091
31851
  try {
@@ -31097,7 +31857,7 @@ function runNpmInstall(installSpec, env, timeoutMs) {
31097
31857
  stdio: ["ignore", "pipe", "pipe"]
31098
31858
  });
31099
31859
  } catch (error2) {
31100
- resolve7({ status: null, stdout: "", stderr: "", error: error2 });
31860
+ resolve9({ status: null, stdout: "", stderr: "", error: error2 });
31101
31861
  return;
31102
31862
  }
31103
31863
  let stdout = "";
@@ -31108,10 +31868,10 @@ function runNpmInstall(installSpec, env, timeoutMs) {
31108
31868
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
31109
31869
  stderr += chunk;
31110
31870
  });
31111
- child.once("error", (error2) => resolve7({ status: null, stdout, stderr, error: error2 }));
31871
+ child.once("error", (error2) => resolve9({ status: null, stdout, stderr, error: error2 }));
31112
31872
  child.once(
31113
31873
  "close",
31114
- (status, signal) => resolve7({
31874
+ (status, signal) => resolve9({
31115
31875
  status,
31116
31876
  stdout,
31117
31877
  stderr,
@@ -45268,7 +46028,7 @@ var Protocol = class {
45268
46028
  return;
45269
46029
  }
45270
46030
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
45271
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
46031
+ await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
45272
46032
  options?.signal?.throwIfAborted();
45273
46033
  }
45274
46034
  } catch (error2) {
@@ -45285,7 +46045,7 @@ var Protocol = class {
45285
46045
  */
45286
46046
  request(request, resultSchema, options) {
45287
46047
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
45288
- return new Promise((resolve7, reject) => {
46048
+ return new Promise((resolve9, reject) => {
45289
46049
  const earlyReject = (error2) => {
45290
46050
  reject(error2);
45291
46051
  };
@@ -45363,7 +46123,7 @@ var Protocol = class {
45363
46123
  if (!parseResult.success) {
45364
46124
  reject(parseResult.error);
45365
46125
  } else {
45366
- resolve7(parseResult.data);
46126
+ resolve9(parseResult.data);
45367
46127
  }
45368
46128
  } catch (error2) {
45369
46129
  reject(error2);
@@ -45624,12 +46384,12 @@ var Protocol = class {
45624
46384
  }
45625
46385
  } catch {
45626
46386
  }
45627
- return new Promise((resolve7, reject) => {
46387
+ return new Promise((resolve9, reject) => {
45628
46388
  if (signal.aborted) {
45629
46389
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
45630
46390
  return;
45631
46391
  }
45632
- const timeoutId = setTimeout(resolve7, interval);
46392
+ const timeoutId = setTimeout(resolve9, interval);
45633
46393
  signal.addEventListener("abort", () => {
45634
46394
  clearTimeout(timeoutId);
45635
46395
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -47978,7 +48738,7 @@ function skipVoid(str, ptr, banNewLines, banComments) {
47978
48738
  }
47979
48739
  return ptr;
47980
48740
  }
47981
- function skipUntil(str, ptr, sep3, end, banNewLines = false) {
48741
+ function skipUntil(str, ptr, sep4, end, banNewLines = false) {
47982
48742
  if (!end) {
47983
48743
  ptr = indexOfNewline(str, ptr);
47984
48744
  return ptr < 0 ? str.length : ptr;
@@ -47987,7 +48747,7 @@ function skipUntil(str, ptr, sep3, end, banNewLines = false) {
47987
48747
  let c = str[i];
47988
48748
  if (c === "#") {
47989
48749
  i = indexOfNewline(str, i);
47990
- } else if (c === sep3) {
48750
+ } else if (c === sep4) {
47991
48751
  return i + 1;
47992
48752
  } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
47993
48753
  return i;
@@ -48716,7 +49476,7 @@ async function waitForConfigLock(lockPath) {
48716
49476
  if (Date.now() - startedAt >= CONFIG_LOCK_WAIT_MS) {
48717
49477
  throw new Error(`Alan could not safely update ${lockPath.slice(0, -".alan-lock".length)}`);
48718
49478
  }
48719
- await new Promise((resolve7) => setTimeout(resolve7, CONFIG_LOCK_POLL_MS));
49479
+ await new Promise((resolve9) => setTimeout(resolve9, CONFIG_LOCK_POLL_MS));
48720
49480
  }
48721
49481
  }
48722
49482
  }
@@ -48740,10 +49500,11 @@ function parseJsonObject2(path, content) {
48740
49500
  );
48741
49501
  }
48742
49502
  function mergeJsonConfig(path, existingContent, desiredContent) {
48743
- if (existingContent !== null) {
48744
- parseJsonObject2(path, existingContent);
49503
+ const normalizedExisting = existingContent?.trim() ? existingContent : null;
49504
+ if (normalizedExisting !== null) {
49505
+ parseJsonObject2(path, normalizedExisting);
48745
49506
  }
48746
- return mergeAlanMcpJsonConfig(existingContent, desiredContent);
49507
+ return mergeAlanMcpJsonConfig(normalizedExisting, desiredContent);
48747
49508
  }
48748
49509
  function assertValidExistingToml(path, content) {
48749
49510
  try {
@@ -49031,6 +49792,10 @@ function readAlanMcpRegistration(path) {
49031
49792
  const url4 = normalizeHttpUrl(server.httpUrl);
49032
49793
  return url4 ? { url: url4, headers } : null;
49033
49794
  }
49795
+ if (path.endsWith("/.gemini/config/mcp_config.json")) {
49796
+ const url4 = normalizeHttpUrl(server.serverUrl);
49797
+ return url4 ? { url: url4, headers } : null;
49798
+ }
49034
49799
  const url3 = server.type === "http" ? normalizeHttpUrl(server.url) : null;
49035
49800
  return url3 ? { url: url3, headers } : null;
49036
49801
  } catch {
@@ -49089,7 +49854,7 @@ function failureFromError(error2, paths) {
49089
49854
  };
49090
49855
  }
49091
49856
  async function waitBeforeRetry() {
49092
- await new Promise((resolve7) => setTimeout(resolve7, RETRY_DELAY_MS2));
49857
+ await new Promise((resolve9) => setTimeout(resolve9, RETRY_DELAY_MS2));
49093
49858
  }
49094
49859
  async function probeAlanMcpReadiness(registration, options = {}) {
49095
49860
  const paths = options.paths ?? [];
@@ -49630,11 +50395,25 @@ function parseOpenCodeVerboseModelOutput(text) {
49630
50395
  }
49631
50396
  return entries;
49632
50397
  }
50398
+ function extractOpenCodeModelCapabilitiesFromVerboseOutput(text) {
50399
+ return parseOpenCodeVerboseModelOutput(text).filter((entry) => entry.id.startsWith("opencode/")).map((entry) => ({
50400
+ id: entry.id,
50401
+ variants: entry.reasoning ? entry.variants.filter((variant) => {
50402
+ const trimmed = variant.trim();
50403
+ return Boolean(trimmed) && trimmed.length <= 256 && !Array.from(trimmed).some((character) => {
50404
+ const code = character.charCodeAt(0);
50405
+ return code <= 31 || code === 127;
50406
+ });
50407
+ }) : []
50408
+ }));
50409
+ }
49633
50410
  function extractOpenCodeDiscoveredModelIdsFromVerboseOutput(text) {
49634
- const entries = parseOpenCodeVerboseModelOutput(text);
50411
+ const entries = extractOpenCodeModelCapabilitiesFromVerboseOutput(text);
49635
50412
  const ids = [];
49636
50413
  for (const entry of entries) {
49637
- const knownVariants = entry.reasoning ? entry.variants.filter((variant) => OPENCODE_KNOWN_VARIANT_KEYS.has(variant)) : [];
50414
+ const knownVariants = entry.variants.filter(
50415
+ (variant) => OPENCODE_KNOWN_VARIANT_KEYS.has(variant)
50416
+ );
49638
50417
  if (knownVariants.length === 0) {
49639
50418
  ids.push(entry.id);
49640
50419
  continue;
@@ -49720,7 +50499,8 @@ function extractClaudeModelIdsFromExecutable(executable) {
49720
50499
  }
49721
50500
  }
49722
50501
  function getCatalogModelIds(provider) {
49723
- return [...CATALOG_MODEL_IDS_BY_PROVIDER[provider] ?? []];
50502
+ const catalogProvider = provider === "opencode_serve" ? "opencode_cli" : provider;
50503
+ return [...CATALOG_MODEL_IDS_BY_PROVIDER[catalogProvider] ?? []];
49724
50504
  }
49725
50505
  function withModelProbeEnv(env) {
49726
50506
  const term = env.TERM;
@@ -49810,14 +50590,14 @@ async function discoverGenericModels(executable, env) {
49810
50590
  }
49811
50591
  var CATALOG_ONLY_PROVIDERS = /* @__PURE__ */ new Set(["supatest_cli", "droid_cli", "copilot_cli"]);
49812
50592
  function supportsProviderModelDiscovery(provider) {
49813
- return provider in CATALOG_MODEL_IDS_BY_PROVIDER;
50593
+ return provider === "opencode_serve" || provider in CATALOG_MODEL_IDS_BY_PROVIDER;
49814
50594
  }
49815
50595
  async function discoverProviderModels(provider, executable, env) {
49816
50596
  if (CATALOG_ONLY_PROVIDERS.has(provider)) {
49817
50597
  return getCatalogModelIds(provider);
49818
50598
  }
49819
50599
  let probed = [];
49820
- if (provider === "opencode_cli") {
50600
+ if (provider === "opencode_cli" || provider === "opencode_serve") {
49821
50601
  probed = await discoverOpenCodeModels(executable, env);
49822
50602
  } else if (provider === "antigravity_cli") {
49823
50603
  probed = await discoverAntigravityModels(executable, env);
@@ -50003,8 +50783,8 @@ var RunStartGate = class {
50003
50783
  async acquire() {
50004
50784
  const previous = this.tail;
50005
50785
  let releaseCurrent;
50006
- const current = new Promise((resolve7) => {
50007
- releaseCurrent = resolve7;
50786
+ const current = new Promise((resolve9) => {
50787
+ releaseCurrent = resolve9;
50008
50788
  });
50009
50789
  this.tail = previous.then(() => current);
50010
50790
  await previous;
@@ -50331,7 +51111,7 @@ var SuspensionDetector = class {
50331
51111
  };
50332
51112
 
50333
51113
  // src/version.ts
50334
- var AGENT_VERSION = "0.1.53";
51114
+ var AGENT_VERSION = "0.1.55";
50335
51115
 
50336
51116
  // src/workspace-relocation.ts
50337
51117
  var import_node_child_process6 = require("child_process");
@@ -50415,6 +51195,9 @@ var WORKSPACE_LEASE_GIT_TIMEOUT_MS = parsePositiveMs(
50415
51195
  process.env.ALAN_WORKSPACE_LEASE_GIT_TIMEOUT_MS,
50416
51196
  2e3
50417
51197
  );
51198
+ function applicationCodeForWorkspaceLeaseFailure(code) {
51199
+ return code === "workspace_lease_branch_changed" ? "app.workspace.branch_changed" : "app.workspace.missing";
51200
+ }
50418
51201
  function gitValue(cwd, args) {
50419
51202
  const result = (0, import_node_child_process7.spawnSync)("git", ["-C", cwd, ...args], {
50420
51203
  encoding: "utf8",
@@ -50439,8 +51222,8 @@ var DEFAULT_PROBE2 = {
50439
51222
  const repositoryRoot = gitValue(canonicalWorkspacePath, ["rev-parse", "--show-toplevel"]);
50440
51223
  const gitDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-dir"]);
50441
51224
  const commonDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-common-dir"]);
50442
- const branch = gitValue(canonicalWorkspacePath, ["rev-parse", "--abbrev-ref", "HEAD"]);
50443
- if (!repositoryRoot || !gitDirectory || !commonDirectory || !branch) return null;
51225
+ const branch = gitValue(canonicalWorkspacePath, ["branch", "--show-current"]) ?? "";
51226
+ if (!repositoryRoot || !gitDirectory || !commonDirectory) return null;
50444
51227
  const remote = gitValue(canonicalWorkspacePath, ["config", "--get", "remote.origin.url"]);
50445
51228
  const remoteIdentity = remote ? normalizeRepositoryIdentity(remote) : null;
50446
51229
  return {
@@ -50464,18 +51247,22 @@ var DEFAULT_PROBE2 = {
50464
51247
  }
50465
51248
  }
50466
51249
  };
50467
- function unavailableFailure(target) {
51250
+ var IDENTITY_FAILURE_MESSAGES = {
51251
+ workspace_lease_unavailable: "The workspace or Git checkout became unavailable while the run was active. Restore it and start a new run.",
51252
+ workspace_lease_path_changed: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
51253
+ workspace_lease_repository_changed: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run."
51254
+ };
51255
+ function identityFailure(code, target) {
50468
51256
  return {
50469
- code: "workspace_lease_unavailable",
50470
- message: "The workspace or Git checkout became unavailable while the run was active. Restore it and start a new run.",
50471
- workspacePath: target.workspacePath,
50472
- expectedBranch: target.expectedBranch
51257
+ code,
51258
+ message: IDENTITY_FAILURE_MESSAGES[code],
51259
+ workspacePath: target.workspacePath
50473
51260
  };
50474
51261
  }
50475
51262
  function branchFailure(target, expectedBranch, actualBranch) {
50476
51263
  return {
50477
51264
  code: "workspace_lease_branch_changed",
50478
- message: `The workspace branch changed from ${expectedBranch} to ${actualBranch} while the run was active. Restore ${expectedBranch} and start a new run.`,
51265
+ message: `The workspace branch changed from ${expectedBranch} to ${actualBranch || "detached HEAD"} while the run was active. Restore ${expectedBranch} and start a new run.`,
50479
51266
  workspacePath: target.workspacePath,
50480
51267
  expectedBranch,
50481
51268
  actualBranch
@@ -50491,7 +51278,12 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
50491
51278
  for (const target of targets) {
50492
51279
  const normalizedTarget = { ...target, workspacePath: (0, import_node_path11.resolve)(target.workspacePath) };
50493
51280
  const identity = probe.snapshot(normalizedTarget.workspacePath);
50494
- if (!identity) return { lease: null, failure: unavailableFailure(normalizedTarget) };
51281
+ if (!identity) {
51282
+ return {
51283
+ lease: null,
51284
+ failure: identityFailure("workspace_lease_unavailable", normalizedTarget)
51285
+ };
51286
+ }
50495
51287
  if (normalizedTarget.expectedBranch && identity.branch !== normalizedTarget.expectedBranch) {
50496
51288
  return {
50497
51289
  lease: null,
@@ -50512,81 +51304,49 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
50512
51304
  /**
50513
51305
  * Classify the lease state for the run monitor.
50514
51306
  *
50515
- * - `transient: true`a null snapshot while the workspace path still exists:
50516
- * the git probe timed out or failed transiently (OS throttling / IO
50517
- * contention), NOT a vanished checkout. The monitor should retry (require N
50518
- * consecutive transient failures) before declaring the workspace lost.
50519
- * - `transient: false` a definitive change: the path is genuinely missing
50520
- * (ENOENT), or the workspace/repository/worktree/branch identity changed.
50521
- * These are real and fail fast.
51307
+ * Checks workspace identity only path, repository, worktree. The branch is
51308
+ * deliberately not checked here: it is working state, not identity, and the supervised
51309
+ * process is a coding agent. A conflicted rebase leaves HEAD detached for as long as
51310
+ * the agent takes to resolve it, so any mid-run branch assertion kills that run. What
51311
+ * keeps work in the right place is the worktree's path and git-dir identity, both
51312
+ * fenced below, plus `assertExpectedBranch` in binding-switch-git.ts at apply time.
51313
+ * `capture()` still refuses to start a run on the wrong branch.
51314
+ *
51315
+ * `transient: true` means retryable — a git probe that timed out under OS throttling
51316
+ * while the path still exists. `transient: false` is definitive and fails fast.
50522
51317
  */
50523
51318
  verifyDetailed() {
50524
- for (const captured of this.captured) {
50525
- const current = this.probe.snapshot(captured.target.workspacePath);
51319
+ for (const { target, identity } of this.captured) {
51320
+ const current = this.probe.snapshot(target.workspacePath);
50526
51321
  if (!current) {
50527
- const pathGone = this.probe.pathExists?.(captured.target.workspacePath) === false;
50528
- return { failure: unavailableFailure(captured.target), transient: !pathGone };
50529
- }
50530
- if (current.workspaceIdentity !== captured.identity.workspaceIdentity) {
51322
+ const pathGone = this.probe.pathExists?.(target.workspacePath) === false;
50531
51323
  return {
50532
- failure: {
50533
- code: "workspace_lease_path_changed",
50534
- message: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
50535
- workspacePath: captured.target.workspacePath,
50536
- expectedBranch: captured.identity.branch,
50537
- actualBranch: current.branch
50538
- },
50539
- transient: false
51324
+ failure: identityFailure("workspace_lease_unavailable", target),
51325
+ transient: !pathGone
50540
51326
  };
50541
51327
  }
50542
- if (current.repositoryIdentity !== captured.identity.repositoryIdentity || current.worktreeIdentity !== captured.identity.worktreeIdentity) {
51328
+ if (current.workspaceIdentity !== identity.workspaceIdentity) {
50543
51329
  return {
50544
- failure: {
50545
- code: "workspace_lease_repository_changed",
50546
- message: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run.",
50547
- workspacePath: captured.target.workspacePath,
50548
- expectedBranch: captured.identity.branch,
50549
- actualBranch: current.branch
50550
- },
51330
+ failure: identityFailure("workspace_lease_path_changed", target),
50551
51331
  transient: false
50552
51332
  };
50553
51333
  }
50554
- if (current.branch !== captured.identity.branch) {
51334
+ if (current.repositoryIdentity !== identity.repositoryIdentity || current.worktreeIdentity !== identity.worktreeIdentity) {
50555
51335
  return {
50556
- failure: branchFailure(captured.target, captured.identity.branch, current.branch),
51336
+ failure: identityFailure("workspace_lease_repository_changed", target),
50557
51337
  transient: false
50558
51338
  };
50559
51339
  }
50560
51340
  }
50561
51341
  return { failure: null, transient: false };
50562
51342
  }
51343
+ /**
51344
+ * Failure-only view of {@link verifyDetailed}. Kept as a thin delegation rather than a
51345
+ * second copy of the checks: the two implementations previously duplicated all four
51346
+ * comparisons and had to be edited in lockstep.
51347
+ */
50563
51348
  verify() {
50564
- for (const captured of this.captured) {
50565
- const current = this.probe.snapshot(captured.target.workspacePath);
50566
- if (!current) return unavailableFailure(captured.target);
50567
- if (current.workspaceIdentity !== captured.identity.workspaceIdentity) {
50568
- return {
50569
- code: "workspace_lease_path_changed",
50570
- message: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
50571
- workspacePath: captured.target.workspacePath,
50572
- expectedBranch: captured.identity.branch,
50573
- actualBranch: current.branch
50574
- };
50575
- }
50576
- if (current.repositoryIdentity !== captured.identity.repositoryIdentity || current.worktreeIdentity !== captured.identity.worktreeIdentity) {
50577
- return {
50578
- code: "workspace_lease_repository_changed",
50579
- message: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run.",
50580
- workspacePath: captured.target.workspacePath,
50581
- expectedBranch: captured.identity.branch,
50582
- actualBranch: current.branch
50583
- };
50584
- }
50585
- if (current.branch !== captured.identity.branch) {
50586
- return branchFailure(captured.target, captured.identity.branch, current.branch);
50587
- }
50588
- }
50589
- return null;
51349
+ return this.verifyDetailed().failure;
50590
51350
  }
50591
51351
  };
50592
51352
  var FRESH_LEASE_MONITOR_STATE = {
@@ -52037,11 +52797,10 @@ function getLocalApiPort(args, stored) {
52037
52797
  }
52038
52798
  function sleep(ms) {
52039
52799
  if (ms <= 0) return Promise.resolve();
52040
- return new Promise((resolve7) => setTimeout(resolve7, ms));
52800
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
52041
52801
  }
52042
52802
  function normalizeBackendKind2(backendKind) {
52043
52803
  if (backendKind === "codex") return "codex_app_server";
52044
- if (backendKind === "gemini" || backendKind === "gemini_cli") return "antigravity_cli";
52045
52804
  return backendKind;
52046
52805
  }
52047
52806
  function providerModelCacheKey(provider, executable) {
@@ -52523,7 +53282,10 @@ var RuntimePresenter = class {
52523
53282
  }
52524
53283
  failWorkspaceLease(failure) {
52525
53284
  return this.failApplicationProblem({
52526
- code: "app.workspace.missing",
53285
+ // A branch change is not a missing workspace. Reporting both as
53286
+ // `app.workspace.missing` told the user to "choose or relocate the project
53287
+ // folder" for a folder that never moved.
53288
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
52527
53289
  detail: failure.message,
52528
53290
  component: "agent-manager-workspace-lease",
52529
53291
  phase: "delivery"
@@ -52776,7 +53538,7 @@ async function setupDaemon(args) {
52776
53538
  }
52777
53539
  const retriableStatus = response && (response.status === 408 || response.status === 429 || response.status >= 500);
52778
53540
  if (response && (!retriableStatus || response.ok) || attempt === 3) break;
52779
- await new Promise((resolve7) => setTimeout(resolve7, attempt * 100));
53541
+ await new Promise((resolve9) => setTimeout(resolve9, attempt * 100));
52780
53542
  }
52781
53543
  if (!response) {
52782
53544
  const detail = transportError instanceof Error ? transportError.message : String(transportError);
@@ -53145,7 +53907,11 @@ async function startDaemon(args) {
53145
53907
  try {
53146
53908
  response = await fetch(`${stored.apiUrl}/public/runtimes/${runtimeId}/tokens/renew`, {
53147
53909
  method: "POST",
53148
- headers: { authorization: `Bearer ${runtimeRenewalToken}` },
53910
+ headers: {
53911
+ authorization: `Bearer ${runtimeRenewalToken}`,
53912
+ "content-type": "application/json"
53913
+ },
53914
+ body: "{}",
53149
53915
  signal: AbortSignal.timeout(1e4)
53150
53916
  });
53151
53917
  transportError = null;
@@ -53820,7 +54586,8 @@ async function startDaemon(args) {
53820
54586
  const runFailure = buildApplicationRunFailure({
53821
54587
  conversationId: payload.conversationId,
53822
54588
  runId: payload.runId,
53823
- code: "app.workspace.missing",
54589
+ // A run dispatched onto the wrong branch is also not a missing workspace.
54590
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
53824
54591
  detail: failure.message,
53825
54592
  component: "agent-manager-workspace-lease",
53826
54593
  phase: "dispatch"
@@ -54297,7 +55064,7 @@ async function startDaemon(args) {
54297
55064
  `${describeOccupiedLocalDaemon(localApiPort)} The token in ${getConfigPath()} no longer matches the running daemon; quit Alan desktop or run setup again.`
54298
55065
  );
54299
55066
  }
54300
- const localApiListening = new Promise((resolve7, reject) => {
55067
+ const localApiListening = new Promise((resolve9, reject) => {
54301
55068
  const onError = (error2) => {
54302
55069
  clearInterval(heartbeat);
54303
55070
  clearInterval(versionRefresh);
@@ -54327,7 +55094,7 @@ async function startDaemon(args) {
54327
55094
  if (address && typeof address === "object") localApiPort = address.port;
54328
55095
  pushLog(`local_api listening port=${localApiPort}`);
54329
55096
  console.info("[alan-agent] Local daemon API listening", { port: localApiPort });
54330
- resolve7();
55097
+ resolve9();
54331
55098
  });
54332
55099
  });
54333
55100
  try {
@@ -54347,7 +55114,7 @@ async function startDaemon(args) {
54347
55114
  clearInterval(workspaceLeaseMonitor);
54348
55115
  suspensionDetector.stop();
54349
55116
  socket.disconnect();
54350
- await new Promise((resolve7) => localServer.close(() => resolve7()));
55117
+ await new Promise((resolve9) => localServer.close(() => resolve9()));
54351
55118
  releaseOwnerLease();
54352
55119
  releaseStartupLease();
54353
55120
  throw error2;
@@ -54367,8 +55134,8 @@ async function startDaemon(args) {
54367
55134
  }
54368
55135
  activeAgents.clear();
54369
55136
  socket.disconnect();
54370
- await new Promise((resolve7) => {
54371
- localServer.close(() => resolve7());
55137
+ await new Promise((resolve9) => {
55138
+ localServer.close(() => resolve9());
54372
55139
  });
54373
55140
  } finally {
54374
55141
  sleepInhibitor.dispose();
@@ -55313,9 +56080,9 @@ var WSClient = class {
55313
56080
  });
55314
56081
  }
55315
56082
  waitForConnection(timeoutMs = 15e3) {
55316
- return new Promise((resolve7, reject) => {
56083
+ return new Promise((resolve9, reject) => {
55317
56084
  if (this.socket.connected) {
55318
- resolve7();
56085
+ resolve9();
55319
56086
  return;
55320
56087
  }
55321
56088
  const timeout = setTimeout(
@@ -55324,7 +56091,7 @@ var WSClient = class {
55324
56091
  );
55325
56092
  this.socket.once("connect", () => {
55326
56093
  clearTimeout(timeout);
55327
- resolve7();
56094
+ resolve9();
55328
56095
  });
55329
56096
  this.socket.once("connect_error", (err) => {
55330
56097
  clearTimeout(timeout);
@@ -55506,9 +56273,9 @@ async function runSandbox(config2) {
55506
56273
  onUserMessage: (payload) => {
55507
56274
  if (payload === null) {
55508
56275
  if (pendingMessageResolve) {
55509
- const resolve7 = pendingMessageResolve;
56276
+ const resolve9 = pendingMessageResolve;
55510
56277
  pendingMessageResolve = null;
55511
- resolve7(null);
56278
+ resolve9(null);
55512
56279
  }
55513
56280
  return;
55514
56281
  }
@@ -55530,9 +56297,9 @@ async function runSandbox(config2) {
55530
56297
  fileCount: payload.files?.length ?? 0
55531
56298
  });
55532
56299
  if (pendingMessageResolve) {
55533
- const resolve7 = pendingMessageResolve;
56300
+ const resolve9 = pendingMessageResolve;
55534
56301
  pendingMessageResolve = null;
55535
- resolve7(payload);
56302
+ resolve9(payload);
55536
56303
  } else {
55537
56304
  queuedMessages.push(payload);
55538
56305
  }
@@ -55751,8 +56518,8 @@ async function runSandbox(config2) {
55751
56518
  });
55752
56519
  if (stopped) break;
55753
56520
  }
55754
- const nextPayload = queuedMessages.shift() ?? await new Promise((resolve7) => {
55755
- pendingMessageResolve = resolve7;
56521
+ const nextPayload = queuedMessages.shift() ?? await new Promise((resolve9) => {
56522
+ pendingMessageResolve = resolve9;
55756
56523
  });
55757
56524
  if (nextPayload === null || stopped) {
55758
56525
  break;