@aiden-ade/sandbox-agent 0.1.53 → 0.1.54

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 +1395 -622
  2. package/package.json +18 -17
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;
@@ -17310,6 +17331,55 @@ function getAlanAgentPrompt(agentId) {
17310
17331
  return getAgentSystemPrompt(agentId);
17311
17332
  }
17312
17333
 
17334
+ // ../shared/dist/constants/agent.js
17335
+ var INTERACTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
17336
+ "askuserquestion",
17337
+ "askquestion",
17338
+ "exitplanmode",
17339
+ "enterplanmode"
17340
+ ]);
17341
+ var HARNESS_ASK_TOOL_NAMES = /* @__PURE__ */ new Set(["askuserquestion", "askquestion"]);
17342
+ function normalizeToolName2(name) {
17343
+ const lower = name.toLowerCase();
17344
+ const mcp = lower.match(/^mcp__[a-z0-9-]+__(.+)$/);
17345
+ const bare = mcp ? mcp[1] : lower;
17346
+ return bare.replace(/[_\s-]/g, "");
17347
+ }
17348
+ function toolNameFromInput(input) {
17349
+ if (!input || typeof input !== "object")
17350
+ return null;
17351
+ const rec = input;
17352
+ if (typeof rec.toolName === "string" && rec.toolName.trim())
17353
+ return rec.toolName;
17354
+ if (typeof rec.name === "string" && rec.name.trim())
17355
+ return rec.name;
17356
+ return null;
17357
+ }
17358
+ function inputLooksLikeAskUserQuestion(input) {
17359
+ if (!input || typeof input !== "object")
17360
+ return false;
17361
+ const rec = input;
17362
+ const args = typeof rec.args === "object" && rec.args !== null ? rec.args : rec;
17363
+ return Array.isArray(args.questions) && args.questions.length > 0;
17364
+ }
17365
+ function isAskUserQuestionTool(name, input) {
17366
+ if (HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(name)))
17367
+ return true;
17368
+ const nested = toolNameFromInput(input);
17369
+ if (nested && nested !== name && HARNESS_ASK_TOOL_NAMES.has(normalizeToolName2(nested))) {
17370
+ return true;
17371
+ }
17372
+ return inputLooksLikeAskUserQuestion(input);
17373
+ }
17374
+ function isInteractiveToolName(name, input) {
17375
+ const normalized = normalizeToolName2(name);
17376
+ if (INTERACTIVE_TOOL_NAMES.has(normalized))
17377
+ return true;
17378
+ return isAskUserQuestionTool(name, input);
17379
+ }
17380
+ var ALAN_AGENT_WORKOS_USER_ID_PREFIX = "alan-agent:";
17381
+ var ALAN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${ALAN_AGENT_WORKOS_USER_ID_PREFIX}%`;
17382
+
17313
17383
  // ../shared/dist/effort.js
17314
17384
  var EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
17315
17385
  var CLAUDE_EFFORT_LEVELS = [
@@ -17736,6 +17806,9 @@ var PROVIDER_MODELS = {
17736
17806
  cursor_agent_cli: CURSOR_AGENT_MODELS,
17737
17807
  antigravity_cli: ANTIGRAVITY_CLI_SEED_MODELS,
17738
17808
  opencode_cli: OPENCODE_ZEN_MODELS,
17809
+ // Server transport dispatches the same "opencode" binary/models as opencode_cli —
17810
+ // share the catalog reference rather than duplicating it.
17811
+ opencode_serve: OPENCODE_ZEN_MODELS,
17739
17812
  droid_cli: [
17740
17813
  { id: "claude-opus-4-8", name: "Claude Opus 4.8" },
17741
17814
  { id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5" },
@@ -17946,17 +18019,17 @@ var CODEX_APP_SERVER_PICKER_FALLBACK_MODELS = [
17946
18019
  var ANTIGRAVITY_CLI_PICKER_FALLBACK_MODELS = [
17947
18020
  { id: "", name: "CLI default", capabilities: caps([]) },
17948
18021
  {
17949
- id: "Antigravity 3.5 Flash",
18022
+ id: "gemini-3.5-flash",
17950
18023
  name: "Antigravity 3.5 Flash",
17951
18024
  capabilities: caps(ANTIGRAVITY_EFFORT)
17952
18025
  },
17953
18026
  {
17954
- id: "Antigravity 3.1 Pro",
18027
+ id: "gemini-3.1-pro",
17955
18028
  name: "Antigravity 3.1 Pro",
17956
18029
  capabilities: caps(ANTIGRAVITY_EFFORT)
17957
18030
  },
17958
18031
  {
17959
- id: "Antigravity 3 Flash",
18032
+ id: "gemini-3-flash",
17960
18033
  name: "Antigravity 3 Flash",
17961
18034
  capabilities: caps(ANTIGRAVITY_EFFORT)
17962
18035
  },
@@ -18027,14 +18100,16 @@ var DISCOVERY_SEED_PROVIDERS = /* @__PURE__ */ new Set([
18027
18100
  "antigravity_cli",
18028
18101
  "cursor_agent_cli",
18029
18102
  "opencode_cli",
18103
+ "opencode_serve",
18030
18104
  "kimi_cli",
18031
18105
  "grok_cli",
18032
18106
  "copilot_cli",
18033
18107
  "droid_cli"
18034
18108
  ]);
18035
18109
  function baseCatalogForProvider(providerKind) {
18036
- const fallback = getProviderPickerFallbackModels(providerKind);
18037
- const staticCatalog = PROVIDER_MODELS[providerKind] ?? [];
18110
+ const catalogProvider = providerKind === "opencode_serve" ? "opencode_cli" : providerKind;
18111
+ const fallback = getProviderPickerFallbackModels(catalogProvider);
18112
+ const staticCatalog = PROVIDER_MODELS[catalogProvider] ?? [];
18038
18113
  if (staticCatalog.length === 0) {
18039
18114
  return fallback;
18040
18115
  }
@@ -18063,68 +18138,25 @@ var import_os2 = require("os");
18063
18138
  var import_path2 = require("path");
18064
18139
  var import_child_process = require("child_process");
18065
18140
  var import_fs3 = require("fs");
18066
- var import_os3 = require("os");
18067
18141
  var import_path3 = require("path");
18142
+ var import_fs4 = require("fs");
18143
+ var import_os3 = require("os");
18144
+ var import_path4 = require("path");
18068
18145
  var import_readline = require("readline");
18069
18146
  var import_crypto2 = require("crypto");
18070
18147
  var import_child_process2 = require("child_process");
18071
18148
  var import_child_process3 = require("child_process");
18072
- var import_crypto3 = require("crypto");
18073
- var import_fs4 = require("fs");
18149
+ var import_fs5 = require("fs");
18074
18150
  var import_os4 = require("os");
18075
- var import_path4 = require("path");
18151
+ var import_path5 = require("path");
18152
+ var import_url = require("url");
18153
+ var import_crypto3 = require("crypto");
18154
+ var import_fs6 = require("fs");
18155
+ var import_os5 = require("os");
18156
+ var import_path6 = require("path");
18076
18157
  var import_child_process4 = require("child_process");
18077
18158
  var import_util4 = require("util");
18078
18159
 
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
18160
  // ../shared/dist/constants/colors.js
18129
18161
  var CATEGORICAL_COLORS = {
18130
18162
  slate: "#7280a0",
@@ -18368,23 +18400,23 @@ var PRIORITY_OPTIONS = [
18368
18400
  ];
18369
18401
 
18370
18402
  // ../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
18403
  var import_fs7 = require("fs");
18378
- var import_os7 = require("os");
18404
+ var import_os6 = require("os");
18379
18405
  var import_path7 = require("path");
18380
- var import_readline2 = require("readline");
18381
- var import_url = require("url");
18382
18406
  var import_fs8 = require("fs");
18383
- var import_os8 = require("os");
18407
+ var import_os7 = require("os");
18384
18408
  var import_path8 = require("path");
18385
- var import_crypto4 = require("crypto");
18386
18409
  var import_fs9 = require("fs");
18410
+ var import_os8 = require("os");
18387
18411
  var import_path9 = require("path");
18412
+ var import_readline2 = require("readline");
18413
+ var import_url2 = require("url");
18414
+ var import_fs10 = require("fs");
18415
+ var import_os9 = require("os");
18416
+ var import_path10 = require("path");
18417
+ var import_crypto4 = require("crypto");
18418
+ var import_fs11 = require("fs");
18419
+ var import_path11 = require("path");
18388
18420
  var MANAGED_ALAN_MCP_SERVER_NAMES = [
18389
18421
  "alan",
18390
18422
  "alan-prod",
@@ -18438,7 +18470,7 @@ async function acquireConfigLock(path) {
18438
18470
  if (Date.now() - startedAt >= 2e3) {
18439
18471
  throw new Error(`Alan could not safely update ${path}`);
18440
18472
  }
18441
- await new Promise((resolve22) => setTimeout(resolve22, 20));
18473
+ await new Promise((resolve42) => setTimeout(resolve42, 20));
18442
18474
  }
18443
18475
  }
18444
18476
  }
@@ -18674,23 +18706,10 @@ function buildJsonTargets(home) {
18674
18706
  server.headers = headers;
18675
18707
  }
18676
18708
  },
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
18709
  {
18691
18710
  cli: "Antigravity CLI",
18692
- configPath: (0, import_path2.join)(home, ".gemini", "antigravity-cli", "settings.json"),
18693
- guardDir: (0, import_path2.join)(home, ".gemini"),
18711
+ configPath: (0, import_path2.join)(home, ".gemini", "config", "mcp_config.json"),
18712
+ guardDir: (0, import_path2.join)(home, ".gemini", "config"),
18694
18713
  readServers: (config2) => config2.mcpServers ?? {},
18695
18714
  writeServers: (config2, servers) => {
18696
18715
  config2.mcpServers = servers;
@@ -18736,8 +18755,8 @@ var mcpConfigWriteGateTail = Promise.resolve();
18736
18755
  function acquireMcpConfigWriteGate() {
18737
18756
  const previous = mcpConfigWriteGateTail;
18738
18757
  let releaseCurrent;
18739
- const current = new Promise((resolve22) => {
18740
- releaseCurrent = resolve22;
18758
+ const current = new Promise((resolve42) => {
18759
+ releaseCurrent = resolve42;
18741
18760
  });
18742
18761
  mcpConfigWriteGateTail = previous.then(() => current);
18743
18762
  return previous.then(() => {
@@ -18749,6 +18768,64 @@ function acquireMcpConfigWriteGate() {
18749
18768
  };
18750
18769
  });
18751
18770
  }
18771
+ var AGENT_INSTRUCTIONS_FILE = "AGENTS.md";
18772
+ var MAX_INSTRUCTION_CHARS = 48e3;
18773
+ function isWorkspaceRoot(dir) {
18774
+ return (0, import_fs3.existsSync)((0, import_path3.join)(dir, ".git"));
18775
+ }
18776
+ function findWorkspaceRoot(cwd) {
18777
+ let current = (0, import_path3.resolve)(cwd);
18778
+ while (true) {
18779
+ if (isWorkspaceRoot(current)) return current;
18780
+ const parent = (0, import_path3.dirname)(current);
18781
+ if (parent === current) return (0, import_path3.resolve)(cwd);
18782
+ current = parent;
18783
+ }
18784
+ }
18785
+ function instructionPaths(cwd) {
18786
+ const root = findWorkspaceRoot(cwd);
18787
+ const paths = [];
18788
+ let current = (0, import_path3.resolve)(cwd);
18789
+ while (true) {
18790
+ const path = (0, import_path3.join)(current, AGENT_INSTRUCTIONS_FILE);
18791
+ try {
18792
+ if ((0, import_fs3.existsSync)(path) && (0, import_fs3.statSync)(path).isFile()) paths.unshift(path);
18793
+ } catch {
18794
+ }
18795
+ if (current === root) return paths;
18796
+ const parent = (0, import_path3.dirname)(current);
18797
+ if (parent === current) return paths;
18798
+ current = parent;
18799
+ }
18800
+ }
18801
+ function buildAntigravityWorkspaceInstructions(cwd) {
18802
+ let remaining = MAX_INSTRUCTION_CHARS;
18803
+ const sections = [];
18804
+ for (const path of instructionPaths(cwd)) {
18805
+ if (remaining <= 0) break;
18806
+ let content;
18807
+ try {
18808
+ content = (0, import_fs3.readFileSync)(path, "utf8").trim();
18809
+ } catch {
18810
+ continue;
18811
+ }
18812
+ if (!content) continue;
18813
+ const included = content.slice(0, remaining);
18814
+ sections.push(
18815
+ [
18816
+ `<workspace_agent_instructions source="${path}">`,
18817
+ included,
18818
+ "</workspace_agent_instructions>"
18819
+ ].join("\n")
18820
+ );
18821
+ remaining -= included.length;
18822
+ }
18823
+ if (sections.length === 0) return void 0;
18824
+ return [
18825
+ "Treat the following repository agent instructions as active for this session.",
18826
+ ...sections
18827
+ ].join("\n\n");
18828
+ }
18752
18829
  function buildPromptWithSystem(config2, promptText) {
18753
18830
  const parts2 = [
18754
18831
  config2.systemPrompt?.trim(),
@@ -18780,16 +18857,16 @@ function imageFileExtension(mimeType) {
18780
18857
  }
18781
18858
  function createImageTempDirectory(cwd) {
18782
18859
  const candidates = [
18783
- cwd ? (0, import_path3.join)(cwd, ".alan-images-") : null,
18784
- (0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-")
18860
+ cwd ? (0, import_path4.join)(cwd, ".alan-images-") : null,
18861
+ (0, import_path4.join)((0, import_os3.tmpdir)(), "alan-images-")
18785
18862
  ].filter((value2) => Boolean(value2));
18786
18863
  for (const candidate of candidates) {
18787
18864
  try {
18788
- return (0, import_fs3.mkdtempSync)(candidate);
18865
+ return (0, import_fs4.mkdtempSync)(candidate);
18789
18866
  } catch {
18790
18867
  }
18791
18868
  }
18792
- return (0, import_fs3.mkdtempSync)((0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-"));
18869
+ return (0, import_fs4.mkdtempSync)((0, import_path4.join)((0, import_os3.tmpdir)(), "alan-images-"));
18793
18870
  }
18794
18871
  function safeFilename(filename) {
18795
18872
  const safe = filename.replace(/[^a-zA-Z0-9._-]/g, "_").replace(/^_+/, "");
@@ -18803,8 +18880,8 @@ function writeImagesToTempFiles(images, cwd) {
18803
18880
  const files = [];
18804
18881
  for (const img of images) {
18805
18882
  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"));
18883
+ const filePath = (0, import_path4.join)(directory, `alan-img-${img.id}.${ext}`);
18884
+ (0, import_fs4.writeFileSync)(filePath, Buffer.from(img.data, "base64"));
18808
18885
  paths.push(filePath);
18809
18886
  files.push({
18810
18887
  filename: img.filename,
@@ -18819,7 +18896,7 @@ function writeImagesToTempFiles(images, cwd) {
18819
18896
  files,
18820
18897
  cleanup: () => {
18821
18898
  try {
18822
- (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
18899
+ (0, import_fs4.rmSync)(directory, { recursive: true, force: true });
18823
18900
  } catch {
18824
18901
  }
18825
18902
  }
@@ -18845,8 +18922,8 @@ function writeFilesToTempFiles(files, cwd) {
18845
18922
  }
18846
18923
  for (const file2 of dataFiles) {
18847
18924
  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"));
18925
+ const filePath = (0, import_path4.join)(directory, `${file2.id}-${safeFilename(file2.filename)}`);
18926
+ (0, import_fs4.writeFileSync)(filePath, Buffer.from(file2.data, "base64"));
18850
18927
  paths.push(filePath);
18851
18928
  tempFiles.push({
18852
18929
  filename: file2.filename,
@@ -18861,7 +18938,7 @@ function writeFilesToTempFiles(files, cwd) {
18861
18938
  cleanup: () => {
18862
18939
  if (!directory) return;
18863
18940
  try {
18864
- (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
18941
+ (0, import_fs4.rmSync)(directory, { recursive: true, force: true });
18865
18942
  } catch {
18866
18943
  }
18867
18944
  }
@@ -19322,15 +19399,15 @@ var SPAWN_RETRY_DELAYS_BY_CODE = {
19322
19399
  ETXTBSY: [250, 750, 1500, 3e3, 5e3],
19323
19400
  ENOENT: [250, 750]
19324
19401
  };
19325
- var delay = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
19402
+ var delay = (ms) => new Promise((resolve42) => setTimeout(resolve42, ms));
19326
19403
  var SPAWN_OUTCOME_TIMEOUT_MS = 2e3;
19327
19404
  function waitForSpawnOutcome(child, timeoutMs = SPAWN_OUTCOME_TIMEOUT_MS) {
19328
- return new Promise((resolve22) => {
19329
- const timer = setTimeout(() => resolve22(null), timeoutMs);
19405
+ return new Promise((resolve42) => {
19406
+ const timer = setTimeout(() => resolve42(null), timeoutMs);
19330
19407
  timer.unref?.();
19331
19408
  const settle = (value2) => {
19332
19409
  clearTimeout(timer);
19333
- resolve22(value2);
19410
+ resolve42(value2);
19334
19411
  };
19335
19412
  child.once("spawn", () => settle(null));
19336
19413
  child.once("error", (error2) => settle(error2));
@@ -19457,36 +19534,36 @@ function createGenericCliBackend(options) {
19457
19534
  let idleTimedOut = false;
19458
19535
  let idleTimeoutReason = null;
19459
19536
  try {
19460
- const exitPromise = new Promise((resolve22, reject) => {
19537
+ const exitPromise = new Promise((resolve42, reject) => {
19461
19538
  child.on("error", (error2) => {
19462
19539
  reject(formatCliSpawnError(options.command, error2));
19463
19540
  });
19464
- child.on("close", (exitCode2, signal) => resolve22({ exitCode: exitCode2, signal }));
19541
+ child.on("close", (exitCode2, signal) => resolve42({ exitCode: exitCode2, signal }));
19465
19542
  const onAbort = () => {
19466
19543
  killProcessTree(child.pid, { signal: "SIGTERM", child });
19467
19544
  };
19468
19545
  context.abortController.signal.addEventListener("abort", onAbort, { once: true });
19469
19546
  });
19470
19547
  if (options.keepStdinOpen) {
19471
- const resultPromise = new Promise((resolve22) => {
19472
- state.onResultReceived = () => resolve22("result_received");
19473
- if (state.resultReceived) resolve22("result_received");
19548
+ const resultPromise = new Promise((resolve42) => {
19549
+ state.onResultReceived = () => resolve42("result_received");
19550
+ if (state.resultReceived) resolve42("result_received");
19474
19551
  });
19475
19552
  const IDLE_MS = options.resultIdleTimeoutMs ?? 10 * 60 * 1e3;
19476
19553
  let idleTimer = null;
19477
- const idlePromise = new Promise((resolve22) => {
19554
+ const idlePromise = new Promise((resolve42) => {
19478
19555
  const armIdleTimer = () => {
19479
19556
  if (idleTimer) clearTimeout(idleTimer);
19480
19557
  idleTimer = setTimeout(() => {
19481
19558
  if (presenter.pendingAskUserToolIds?.size) {
19482
19559
  idleTimeoutReason = "pending_user_answer";
19483
- resolve22("idle_timeout");
19560
+ resolve42("idle_timeout");
19484
19561
  } else if (state.awaitingPostBackgroundSynthesis || state.resultDeferredOnBackgroundWork && state.activeBackgroundTaskIds?.size) {
19485
19562
  idleTimeoutReason = state.awaitingPostBackgroundSynthesis ? "post_subagent_synthesis" : "background_task";
19486
- resolve22("idle_timeout");
19563
+ resolve42("idle_timeout");
19487
19564
  } else if (options.postStartupSilenceTimeoutMs && sawStdoutLine && typeof state.lastRawOutputAtMs === "number" && Date.now() - state.lastRawOutputAtMs >= options.postStartupSilenceTimeoutMs) {
19488
19565
  idleTimeoutReason = "post_startup_silence";
19489
- resolve22("idle_timeout");
19566
+ resolve42("idle_timeout");
19490
19567
  } else {
19491
19568
  armIdleTimer();
19492
19569
  }
@@ -19507,14 +19584,14 @@ function createGenericCliBackend(options) {
19507
19584
  processExit = await Promise.race([
19508
19585
  exitPromise,
19509
19586
  new Promise(
19510
- (resolve22) => setTimeout(() => resolve22({ exitCode: null, signal: "SIGKILL" }), 5e3)
19587
+ (resolve42) => setTimeout(() => resolve42({ exitCode: null, signal: "SIGKILL" }), 5e3)
19511
19588
  )
19512
19589
  ]);
19513
19590
  } else if (raceResult === "result_received") {
19514
19591
  const GRACE_MS = 5e3;
19515
19592
  const gracedExit = await Promise.race([
19516
19593
  exitPromise,
19517
- new Promise((resolve22) => setTimeout(() => resolve22(null), GRACE_MS))
19594
+ new Promise((resolve42) => setTimeout(() => resolve42(null), GRACE_MS))
19518
19595
  ]);
19519
19596
  if (gracedExit) processExit = gracedExit;
19520
19597
  if (child.exitCode === null && !child.killed) {
@@ -19832,6 +19909,234 @@ function createGenericCliBackend(options) {
19832
19909
  }
19833
19910
  };
19834
19911
  }
19912
+ function stringField(record2, key) {
19913
+ const value2 = record2[key];
19914
+ return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
19915
+ }
19916
+ function backgroundTaskKeys(record2) {
19917
+ return [
19918
+ stringField(record2, "task_id"),
19919
+ stringField(record2, "taskId"),
19920
+ stringField(record2, "tool_use_id"),
19921
+ stringField(record2, "toolUseId"),
19922
+ stringField(record2, "id")
19923
+ ].filter((key) => Boolean(key));
19924
+ }
19925
+ function backgroundTaskId(record2) {
19926
+ return stringField(record2, "task_id") ?? stringField(record2, "taskId");
19927
+ }
19928
+ function backgroundToolUseId(record2) {
19929
+ return stringField(record2, "tool_use_id") ?? stringField(record2, "toolUseId");
19930
+ }
19931
+ function registerBackgroundTaskIds(state, keys) {
19932
+ for (const key of keys) {
19933
+ if (!key) continue;
19934
+ if (!state.activeBackgroundTaskIds) state.activeBackgroundTaskIds = /* @__PURE__ */ new Set();
19935
+ state.activeBackgroundTaskIds.add(key);
19936
+ }
19937
+ }
19938
+ function registerBackgroundLauncher(state, toolUseId) {
19939
+ registerBackgroundTaskIds(state, [toolUseId]);
19940
+ if (!state.pendingLauncherToolIds) state.pendingLauncherToolIds = [];
19941
+ if (!state.pendingLauncherToolIds.includes(toolUseId)) {
19942
+ state.pendingLauncherToolIds.push(toolUseId);
19943
+ }
19944
+ }
19945
+ function drainNextUnlinkedBackgroundLauncher(state) {
19946
+ const launcherId = state.pendingLauncherToolIds?.shift();
19947
+ if (state.pendingLauncherToolIds?.length === 0) state.pendingLauncherToolIds = void 0;
19948
+ if (launcherId) clearBackgroundTaskIds(state, [launcherId]);
19949
+ return launcherId;
19950
+ }
19951
+ function registerBackgroundTaskRecord(state, record2, launcherToolUseId) {
19952
+ const taskId = backgroundTaskId(record2);
19953
+ let toolUseId = backgroundToolUseId(record2) ?? launcherToolUseId ?? void 0;
19954
+ if (!toolUseId && taskId) {
19955
+ const nextLauncher = state.pendingLauncherToolIds?.[0];
19956
+ if (nextLauncher) {
19957
+ toolUseId = nextLauncher;
19958
+ } else if (state.activeBackgroundTaskIds?.size === 1) {
19959
+ const [candidate] = state.activeBackgroundTaskIds;
19960
+ if (candidate && candidate !== taskId) toolUseId = candidate;
19961
+ }
19962
+ }
19963
+ registerBackgroundTaskIds(state, backgroundTaskKeys(record2));
19964
+ if (!taskId || !toolUseId) return;
19965
+ if (state.pendingLauncherToolIds) {
19966
+ const idx = state.pendingLauncherToolIds.indexOf(toolUseId);
19967
+ if (idx >= 0) state.pendingLauncherToolIds.splice(idx, 1);
19968
+ if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
19969
+ }
19970
+ if (!state.backgroundToolIdByTaskId) state.backgroundToolIdByTaskId = /* @__PURE__ */ new Map();
19971
+ if (!state.backgroundTaskIdsByToolId) state.backgroundTaskIdsByToolId = /* @__PURE__ */ new Map();
19972
+ state.backgroundToolIdByTaskId.set(taskId, toolUseId);
19973
+ const taskIds = state.backgroundTaskIdsByToolId.get(toolUseId) ?? /* @__PURE__ */ new Set();
19974
+ taskIds.add(taskId);
19975
+ state.backgroundTaskIdsByToolId.set(toolUseId, taskIds);
19976
+ }
19977
+ function clearBackgroundTaskIds(state, keys) {
19978
+ const activeIds = state.activeBackgroundTaskIds;
19979
+ if (!activeIds) return;
19980
+ for (const key of keys) {
19981
+ if (!key) continue;
19982
+ activeIds.delete(key);
19983
+ const toolUseId = state.backgroundToolIdByTaskId?.get(key);
19984
+ if (toolUseId) {
19985
+ activeIds.delete(toolUseId);
19986
+ state.backgroundToolIdByTaskId?.delete(key);
19987
+ const taskIds2 = state.backgroundTaskIdsByToolId?.get(toolUseId);
19988
+ taskIds2?.delete(key);
19989
+ if (taskIds2?.size === 0) state.backgroundTaskIdsByToolId?.delete(toolUseId);
19990
+ }
19991
+ const taskIds = state.backgroundTaskIdsByToolId?.get(key);
19992
+ if (taskIds) {
19993
+ for (const taskId of taskIds) {
19994
+ activeIds.delete(taskId);
19995
+ state.backgroundToolIdByTaskId?.delete(taskId);
19996
+ }
19997
+ state.backgroundTaskIdsByToolId?.delete(key);
19998
+ }
19999
+ }
20000
+ if (state.pendingLauncherToolIds) {
20001
+ state.pendingLauncherToolIds = state.pendingLauncherToolIds.filter((id) => activeIds.has(id));
20002
+ if (state.pendingLauncherToolIds.length === 0) state.pendingLauncherToolIds = void 0;
20003
+ }
20004
+ if (activeIds.size === 0) state.activeBackgroundTaskIds = void 0;
20005
+ }
20006
+ function resolveBackgroundTaskToolUseId(state, record2) {
20007
+ const explicitToolUseId = backgroundToolUseId(record2);
20008
+ if (explicitToolUseId) return explicitToolUseId;
20009
+ const taskId = backgroundTaskId(record2);
20010
+ return taskId ? state.backgroundToolIdByTaskId?.get(taskId) : void 0;
20011
+ }
20012
+ var TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20013
+ "complete",
20014
+ "completed",
20015
+ "done",
20016
+ "success",
20017
+ "succeeded",
20018
+ "failed",
20019
+ "failure",
20020
+ "error",
20021
+ "cancelled",
20022
+ "canceled",
20023
+ "aborted",
20024
+ "interrupted",
20025
+ "stopped"
20026
+ ]);
20027
+ var NON_TERMINAL_BACKGROUND_STATUSES = /* @__PURE__ */ new Set([
20028
+ "running",
20029
+ "in_progress",
20030
+ "inprogress",
20031
+ "started",
20032
+ "pending",
20033
+ "active",
20034
+ "working",
20035
+ "queued"
20036
+ ]);
20037
+ var ASYNC_LAUNCH_ACK_RE = /^(async agent launched successfully|background (?:task|agent|subagent) (?:launched|started|running)|task (?:launched|started) successfully)/i;
20038
+ function isTerminalBackgroundStatus(record2) {
20039
+ const status = stringField(record2, "status")?.toLowerCase();
20040
+ if (status && TERMINAL_BACKGROUND_STATUSES.has(status)) return true;
20041
+ if (status && NON_TERMINAL_BACKGROUND_STATUSES.has(status)) return false;
20042
+ 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";
20043
+ }
20044
+ function isFailedBackgroundStatus(record2) {
20045
+ const status = stringField(record2, "status")?.toLowerCase();
20046
+ return status === "failed" || status === "failure" || status === "error" || status === "cancelled" || status === "canceled" || status === "aborted" || status === "interrupted";
20047
+ }
20048
+ function extractBackgroundTaskIdFromPayload(value2) {
20049
+ if (typeof value2 === "string") {
20050
+ const trimmed = value2.trim();
20051
+ if (!trimmed) return void 0;
20052
+ try {
20053
+ return extractBackgroundTaskIdFromPayload(JSON.parse(trimmed));
20054
+ } catch {
20055
+ const match = trimmed.match(/\btask[_-]?id["']?\s*[:=]\s*["']?([A-Za-z0-9_.-]+)/i) ?? trimmed.match(/\btasks\/([A-Za-z0-9_.-]+)/i);
20056
+ if (match?.[1]) return match[1];
20057
+ if (/^[A-Za-z0-9_-]{6,128}$/.test(trimmed) && /(?:task|bg|async|job|agent)/i.test(trimmed)) {
20058
+ return trimmed;
20059
+ }
20060
+ return void 0;
20061
+ }
20062
+ }
20063
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return void 0;
20064
+ const record2 = value2;
20065
+ 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);
20066
+ }
20067
+ function looksLikeBackgroundLaunchAck(options) {
20068
+ const taskId = extractBackgroundTaskIdFromPayload(options.value) ?? extractBackgroundTaskIdFromPayload(options.content);
20069
+ const content = options.content.trim();
20070
+ const explicitAckText = ASYNC_LAUNCH_ACK_RE.test(content);
20071
+ if (!options.trackedUnlinkedLauncher) return { isAck: false, taskId };
20072
+ if (options.explicitBackground && taskId) return { isAck: true, taskId };
20073
+ if (explicitAckText) return { isAck: true, taskId };
20074
+ if (taskId && content.length > 0 && content.length < 400) {
20075
+ const record2 = options.value && typeof options.value === "object" && !Array.isArray(options.value) ? options.value : null;
20076
+ const looksStructured = record2 !== null || content.startsWith("{") || /^task[_-]?id\b/i.test(content) || content === taskId;
20077
+ if (looksStructured) return { isAck: true, taskId };
20078
+ }
20079
+ return { isAck: false, taskId };
20080
+ }
20081
+ function settleBackgroundTerminalNotification(kind, context, state, record2, options) {
20082
+ const toolUseId = resolveBackgroundTaskToolUseId(state, record2);
20083
+ const keys = backgroundTaskKeys(record2);
20084
+ const wasActive = !!toolUseId && state.activeBackgroundTaskIds?.has(toolUseId) === true || keys.some((key) => state.activeBackgroundTaskIds?.has(key) === true);
20085
+ if (toolUseId && wasActive) {
20086
+ options.emitToolResult(toolUseId, options.resultText, options.isError);
20087
+ clearBackgroundTaskIds(state, keys);
20088
+ maybeFinalizeDeferredResult(kind, context, state);
20089
+ return toolUseId;
20090
+ }
20091
+ clearBackgroundTaskIds(state, keys);
20092
+ const drainedLauncher = drainNextUnlinkedBackgroundLauncher(state);
20093
+ if (drainedLauncher) {
20094
+ options.emitToolResult(drainedLauncher, options.resultText, options.isError);
20095
+ }
20096
+ maybeFinalizeDeferredResult(kind, context, state);
20097
+ return drainedLauncher;
20098
+ }
20099
+ function finalizeStructuredResult(kind, state) {
20100
+ state.resultReceived = true;
20101
+ state.onResultReceived?.();
20102
+ if (state.stdin && !state.stdin.destroyed) {
20103
+ state.stdin.end();
20104
+ console.info(`[${kind}] Closed stdin after result event to signal CLI exit`);
20105
+ }
20106
+ }
20107
+ function deferOrFinalizeStructuredResult(kind, context, state) {
20108
+ const pendingAsks = context.presenter.pendingAskUserToolIds?.size ?? 0;
20109
+ if (pendingAsks > 0) {
20110
+ console.info(
20111
+ `[${kind}] Keeping stdin open \u2014 ${pendingAsks} interactive question(s) awaiting user response`
20112
+ );
20113
+ state.resultDeferredOnPendingAnswer = true;
20114
+ return "deferred_pending_answer";
20115
+ }
20116
+ const activeBackgroundTasks = state.activeBackgroundTaskIds?.size ?? 0;
20117
+ if (activeBackgroundTasks > 0) {
20118
+ console.info(
20119
+ `[${kind}] Keeping stdin open \u2014 ${activeBackgroundTasks} background task(s) still active`
20120
+ );
20121
+ state.resultDeferredOnBackgroundWork = true;
20122
+ return "deferred_background_work";
20123
+ }
20124
+ finalizeStructuredResult(kind, state);
20125
+ return "finalized";
20126
+ }
20127
+ function maybeFinalizeDeferredResult(kind, context, state) {
20128
+ if (!state.resultDeferredOnBackgroundWork && !state.resultDeferredOnPendingAnswer) return;
20129
+ if (context.presenter.pendingAskUserToolIds?.size || state.activeBackgroundTaskIds?.size) return;
20130
+ if (state.resultDeferredOnBackgroundWork) {
20131
+ state.awaitingPostBackgroundSynthesis = true;
20132
+ console.info(
20133
+ `[${kind}] Background work drained \u2014 awaiting post-subagent synthesis before stdin close`
20134
+ );
20135
+ return;
20136
+ }
20137
+ state.resultDeferredOnPendingAnswer = false;
20138
+ finalizeStructuredResult(kind, state);
20139
+ }
19835
20140
  var MAX_INLINE_GENERATED_IMAGE_BYTES = 20 * 1024 * 1024;
19836
20141
  function inferImageMimeType(buffer) {
19837
20142
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
@@ -19947,6 +20252,20 @@ function buildToolResultText(parsed) {
19947
20252
  const status = typeof parsed.status === "string" ? parsed.status.trim() : "";
19948
20253
  return status || "Tool completed";
19949
20254
  }
20255
+ function buildSubagentResultText(parsed) {
20256
+ const output = buildToolResultText(parsed);
20257
+ const status = typeof parsed.status === "string" ? parsed.status.trim() : "";
20258
+ const details = [
20259
+ typeof parsed.duration_ms === "number" ? `Duration: ${parsed.duration_ms}ms.` : "",
20260
+ typeof parsed.durationMs === "number" ? `Duration: ${parsed.durationMs}ms.` : "",
20261
+ typeof parsed.tool_uses === "number" ? `Tool uses: ${parsed.tool_uses}.` : "",
20262
+ typeof parsed.toolUses === "number" ? `Tool uses: ${parsed.toolUses}.` : "",
20263
+ typeof parsed.total_tokens === "number" ? `Tokens: ${parsed.total_tokens}.` : "",
20264
+ typeof parsed.totalTokens === "number" ? `Tokens: ${parsed.totalTokens}.` : ""
20265
+ ].filter(Boolean);
20266
+ if (output !== "Tool completed") return output;
20267
+ return [`Subagent ${status || "completed"}.`, ...details].join(" ");
20268
+ }
19950
20269
  function extractText(parsed) {
19951
20270
  for (const key of ["text", "delta", "content", "message", "result"]) {
19952
20271
  const value2 = parsed[key];
@@ -19993,6 +20312,286 @@ function extractSubagentInput(parsed) {
19993
20312
  workspace: parsed.workspace
19994
20313
  };
19995
20314
  }
20315
+ function antigravityTranscriptRoot(context) {
20316
+ const home = context.env.HOME || process.env.HOME || (0, import_os4.homedir)();
20317
+ return (0, import_path5.resolve)(home, ".gemini", "antigravity-cli", "brain");
20318
+ }
20319
+ function resolveAntigravityTranscriptPath(parsed, context) {
20320
+ const logUri = stringField2(parsed, "log_uri");
20321
+ const conversationId = stringField2(parsed, "task_id") ?? stringField2(parsed, "conversation_id");
20322
+ if (!logUri || !conversationId) return void 0;
20323
+ try {
20324
+ const url3 = new URL(logUri);
20325
+ if (url3.protocol !== "file:") return void 0;
20326
+ const root = antigravityTranscriptRoot(context);
20327
+ const transcriptPath = (0, import_path5.resolve)((0, import_url.fileURLToPath)(url3));
20328
+ const pathFromRoot = (0, import_path5.relative)(root, transcriptPath);
20329
+ const segments = pathFromRoot.split(import_path5.sep);
20330
+ 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") {
20331
+ return void 0;
20332
+ }
20333
+ return transcriptPath;
20334
+ } catch {
20335
+ return void 0;
20336
+ }
20337
+ }
20338
+ function antigravityTranscriptToolId(parentToolUseId, lineIndex, toolIndex) {
20339
+ return `${parentToolUseId}-transcript-${lineIndex}-${toolIndex}`;
20340
+ }
20341
+ var ANTIGRAVITY_TOOL_RESULT_TYPES = /* @__PURE__ */ new Set([
20342
+ "LIST_DIRECTORY",
20343
+ "VIEW_FILE",
20344
+ "MCP_TOOL",
20345
+ "INVOKE_SUBAGENT",
20346
+ "RUN_COMMAND",
20347
+ "GENERIC",
20348
+ "GREP_SEARCH",
20349
+ "CODE_ACTION",
20350
+ "SEND_MESSAGE"
20351
+ ]);
20352
+ function isAntigravityToolResultEntry(entry) {
20353
+ const type = stringField2(entry, "type")?.toUpperCase();
20354
+ if (type && ANTIGRAVITY_TOOL_RESULT_TYPES.has(type)) return true;
20355
+ const content = stringField2(entry, "content");
20356
+ return Boolean(content?.startsWith("Created At:"));
20357
+ }
20358
+ function stripAntigravityToolResultEnvelope(content) {
20359
+ const stripped = content.replace(/^(?:Created At:[^\n]*\n|Completed At:[^\n]*\n)+/u, "");
20360
+ return stripped.trim().length > 0 ? stripped : content;
20361
+ }
20362
+ function readAntigravityTranscriptLines(transcriptPath) {
20363
+ try {
20364
+ const lines = (0, import_fs5.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
20365
+ if (lines.at(-1) === "") lines.pop();
20366
+ return lines;
20367
+ } catch {
20368
+ return void 0;
20369
+ }
20370
+ }
20371
+ function syncAntigravitySubagentTranscript(transcriptPath, parentToolUseId, presenter, startLine = 0, pendingToolIds = []) {
20372
+ const lines = readAntigravityTranscriptLines(transcriptPath);
20373
+ if (!lines) {
20374
+ return { processedLineCount: startLine, emittedEventCount: 0, pendingToolIds };
20375
+ }
20376
+ let processedLineCount = startLine > lines.length ? 0 : startLine;
20377
+ let emittedEventCount = 0;
20378
+ for (let lineIndex = processedLineCount; lineIndex < lines.length; lineIndex += 1) {
20379
+ const line = lines[lineIndex];
20380
+ if (!line) {
20381
+ processedLineCount = lineIndex + 1;
20382
+ continue;
20383
+ }
20384
+ let entry;
20385
+ try {
20386
+ entry = JSON.parse(line);
20387
+ } catch {
20388
+ break;
20389
+ }
20390
+ processedLineCount = lineIndex + 1;
20391
+ if (stringField2(entry, "source") !== "MODEL") continue;
20392
+ const thinking = stringField2(entry, "thinking") ?? stringField2(entry, "thinking_delta");
20393
+ if (thinking) {
20394
+ emittedEventCount += 1;
20395
+ void presenter.onThinking(thinking, parentToolUseId);
20396
+ }
20397
+ const toolCalls = Array.isArray(entry.tool_calls) ? entry.tool_calls : [];
20398
+ toolCalls.forEach((rawToolCall, toolIndex) => {
20399
+ const toolCall = asRecord(rawToolCall);
20400
+ const toolName = toolCall && stringField2(toolCall, "name");
20401
+ if (!toolName) return;
20402
+ const toolId = antigravityTranscriptToolId(parentToolUseId, lineIndex, toolIndex);
20403
+ pendingToolIds.push(toolId);
20404
+ emittedEventCount += 1;
20405
+ void presenter.onToolUse(
20406
+ toolName,
20407
+ toolCall?.args ?? toolCall?.parameters ?? {},
20408
+ toolId,
20409
+ parentToolUseId
20410
+ );
20411
+ });
20412
+ const content = stringField2(entry, "content");
20413
+ if (content && isAntigravityToolResultEntry(entry)) {
20414
+ const toolId = pendingToolIds.shift();
20415
+ if (toolId) {
20416
+ emittedEventCount += 1;
20417
+ void presenter.onToolResult?.(
20418
+ toolId,
20419
+ stripAntigravityToolResultEnvelope(content),
20420
+ void 0,
20421
+ parentToolUseId
20422
+ );
20423
+ }
20424
+ continue;
20425
+ }
20426
+ if (!content) continue;
20427
+ const entryType = stringField2(entry, "type")?.toUpperCase();
20428
+ if (entryType === "SYSTEM_MESSAGE") continue;
20429
+ emittedEventCount += 1;
20430
+ void presenter.onAssistantText(content, parentToolUseId);
20431
+ }
20432
+ return { processedLineCount, emittedEventCount, pendingToolIds };
20433
+ }
20434
+ function resolveAntigravityParentTranscriptPath(conversationId, context) {
20435
+ return (0, import_path5.resolve)(
20436
+ antigravityTranscriptRoot(context),
20437
+ conversationId,
20438
+ ".system_generated",
20439
+ "logs",
20440
+ "transcript.jsonl"
20441
+ );
20442
+ }
20443
+ function syncAntigravityParentThinkingFromTranscript(context, state) {
20444
+ const parent = state.antigravityParentTranscript;
20445
+ if (!parent?.transcriptPath) return 0;
20446
+ const lines = readAntigravityTranscriptLines(parent.transcriptPath);
20447
+ if (!lines) return 0;
20448
+ let processedLineCount = parent.replayedLineCount > lines.length ? 0 : parent.replayedLineCount;
20449
+ let emittedEventCount = 0;
20450
+ for (let lineIndex = processedLineCount; lineIndex < lines.length; lineIndex += 1) {
20451
+ const line = lines[lineIndex];
20452
+ if (!line) {
20453
+ processedLineCount = lineIndex + 1;
20454
+ continue;
20455
+ }
20456
+ let entry;
20457
+ try {
20458
+ entry = JSON.parse(line);
20459
+ } catch {
20460
+ break;
20461
+ }
20462
+ processedLineCount = lineIndex + 1;
20463
+ if (stringField2(entry, "source") !== "MODEL") continue;
20464
+ const thinking = stringField2(entry, "thinking") ?? stringField2(entry, "thinking_delta");
20465
+ if (!thinking) continue;
20466
+ emittedEventCount += 1;
20467
+ void context.presenter.onThinking(thinking);
20468
+ }
20469
+ parent.replayedLineCount = processedLineCount;
20470
+ return emittedEventCount;
20471
+ }
20472
+ function syncAntigravitySubagentEventsFromTranscripts(context, state) {
20473
+ let emittedEventCount = syncAntigravityParentThinkingFromTranscript(context, state);
20474
+ for (const [launcherId, task] of state.antigravitySubagentTranscripts ?? []) {
20475
+ if (!task.transcriptPath) continue;
20476
+ const replay = syncAntigravitySubagentTranscript(
20477
+ task.transcriptPath,
20478
+ launcherId,
20479
+ context.presenter,
20480
+ task.replayedLineCount,
20481
+ task.pendingToolIds ?? []
20482
+ );
20483
+ task.replayedLineCount = replay.processedLineCount;
20484
+ task.pendingToolIds = replay.pendingToolIds;
20485
+ task.emittedEventCount += replay.emittedEventCount;
20486
+ emittedEventCount += replay.emittedEventCount;
20487
+ }
20488
+ if (emittedEventCount > 0) state.onNewOutput?.();
20489
+ return emittedEventCount;
20490
+ }
20491
+ function ensureAntigravitySubagentTranscriptPolling(context, state) {
20492
+ if (state.providerTranscriptPollTimer) {
20493
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20494
+ return;
20495
+ }
20496
+ const poll = () => {
20497
+ try {
20498
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20499
+ state.providerTranscriptPollErrorLogged = false;
20500
+ } catch (error2) {
20501
+ if (!state.providerTranscriptPollErrorLogged) {
20502
+ console.warn("[antigravity_cli] Failed to poll child transcript:", error2);
20503
+ state.providerTranscriptPollErrorLogged = true;
20504
+ }
20505
+ }
20506
+ };
20507
+ poll();
20508
+ const timer = setInterval(poll, 750);
20509
+ timer.unref?.();
20510
+ state.providerTranscriptPollTimer = timer;
20511
+ }
20512
+ function clearAntigravityTranscriptPollingIfIdle(state) {
20513
+ const hasChildren = (state.antigravitySubagentTranscripts?.size ?? 0) > 0;
20514
+ const hasParent = Boolean(state.antigravityParentTranscript);
20515
+ if (hasChildren || hasParent) return;
20516
+ if (state.providerTranscriptPollTimer) clearInterval(state.providerTranscriptPollTimer);
20517
+ state.providerTranscriptPollTimer = void 0;
20518
+ }
20519
+ function registerAntigravityParentTranscript(conversationId, context, state) {
20520
+ if (!conversationId) return;
20521
+ const existing = state.antigravityParentTranscript;
20522
+ if (existing?.conversationId === conversationId) {
20523
+ ensureAntigravitySubagentTranscriptPolling(context, state);
20524
+ return;
20525
+ }
20526
+ state.antigravityParentTranscript = {
20527
+ conversationId,
20528
+ transcriptPath: resolveAntigravityParentTranscriptPath(conversationId, context),
20529
+ // Skip historical rows from prior turns on resume; only stream new thinking.
20530
+ replayedLineCount: readAntigravityTranscriptLines(
20531
+ resolveAntigravityParentTranscriptPath(conversationId, context)
20532
+ )?.length ?? 0
20533
+ };
20534
+ ensureAntigravitySubagentTranscriptPolling(context, state);
20535
+ }
20536
+ function registerAntigravitySubagentTranscript(parsed, toolId, context, state) {
20537
+ if (!state.antigravitySubagentTranscripts) state.antigravitySubagentTranscripts = /* @__PURE__ */ new Map();
20538
+ const task = state.antigravitySubagentTranscripts.get(toolId) ?? {
20539
+ replayedLineCount: 0,
20540
+ emittedEventCount: 0,
20541
+ pendingToolIds: []
20542
+ };
20543
+ const incomingConversationId = stringField2(parsed, "task_id");
20544
+ if (task.conversationId && incomingConversationId && incomingConversationId !== task.conversationId) {
20545
+ if (!state.antigravityCorrelationWarnLogged) {
20546
+ console.warn(
20547
+ `[antigravity_cli] Subagent launcher ${toolId} saw a conversation id change (${task.conversationId} -> ${incomingConversationId}); keeping the original transcript association.`
20548
+ );
20549
+ state.antigravityCorrelationWarnLogged = true;
20550
+ }
20551
+ return;
20552
+ }
20553
+ task.conversationId = incomingConversationId ?? task.conversationId;
20554
+ const resolvedPath = resolveAntigravityTranscriptPath(parsed, context);
20555
+ if (!resolvedPath && !task.transcriptPath && stringField2(parsed, "log_uri")) {
20556
+ if (!state.antigravityTranscriptPathWarnLogged) {
20557
+ console.warn(
20558
+ `[antigravity_cli] Subagent log_uri for ${toolId} did not match the expected Antigravity transcript path layout; its live stream will not be tailed.`
20559
+ );
20560
+ state.antigravityTranscriptPathWarnLogged = true;
20561
+ }
20562
+ }
20563
+ task.transcriptPath = resolvedPath ?? task.transcriptPath;
20564
+ state.antigravitySubagentTranscripts.set(toolId, task);
20565
+ if (task.transcriptPath) ensureAntigravitySubagentTranscriptPolling(context, state);
20566
+ }
20567
+ function settleAntigravitySubagentTranscripts(context, state, isError = false) {
20568
+ syncAntigravitySubagentEventsFromTranscripts(context, state);
20569
+ for (const [toolId, task] of state.antigravitySubagentTranscripts ?? []) {
20570
+ settleBackgroundTerminalNotification(
20571
+ "antigravity_cli",
20572
+ context,
20573
+ state,
20574
+ {
20575
+ tool_use_id: toolId,
20576
+ ...task.conversationId ? { task_id: task.conversationId } : {},
20577
+ status: isError ? "error" : "completed"
20578
+ },
20579
+ {
20580
+ resultText: isError ? "Subagent ended because the parent run failed" : "Subagent completed",
20581
+ isError: isError || void 0,
20582
+ emitToolResult: (id, text, error2) => {
20583
+ void context.presenter.onToolResult?.(id, text, error2);
20584
+ }
20585
+ }
20586
+ );
20587
+ state.antigravitySubagentTranscripts?.delete(toolId);
20588
+ }
20589
+ if (state.antigravitySubagentTranscripts?.size === 0) {
20590
+ state.antigravitySubagentTranscripts = void 0;
20591
+ }
20592
+ state.antigravityParentTranscript = void 0;
20593
+ clearAntigravityTranscriptPollingIfIdle(state);
20594
+ }
19996
20595
  function extractToolId(parsed, state) {
19997
20596
  for (const key of ["tool_id", "toolId", "id", "call_id"]) {
19998
20597
  const value2 = parsed[key];
@@ -20001,21 +20600,140 @@ function extractToolId(parsed, state) {
20001
20600
  state.iterations += 1;
20002
20601
  return `antigravity-tool-${state.iterations}`;
20003
20602
  }
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;
20603
+ function asRecord(value2) {
20604
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
20605
+ }
20606
+ function stringField2(value2, key) {
20607
+ const field = value2[key];
20608
+ return typeof field === "string" && field.trim() ? field : void 0;
20609
+ }
20610
+ function liveStepId(step, subagentIndex) {
20611
+ const conversationId = stringField2(step, "conversation_id") ?? "unknown";
20612
+ const stepIndex = typeof step.step_index === "number" ? step.step_index : "unknown";
20613
+ const base = `antigravity-${conversationId}-step-${stepIndex}`;
20614
+ return typeof subagentIndex === "number" ? `${base}-subagent-${subagentIndex}` : base;
20615
+ }
20616
+ function isActiveStep(step) {
20617
+ return stringField2(step, "state")?.toLowerCase() === "active";
20618
+ }
20619
+ function normalizeLiveAntigravityEvent(parsed) {
20620
+ const event = stringField2(parsed, "event");
20621
+ if (!event) return void 0;
20622
+ const conversationId = stringField2(parsed, "conversation_id");
20623
+ if (event === "init") {
20624
+ return [
20625
+ {
20626
+ ...asRecord(parsed.init) ?? {},
20627
+ type: "init",
20628
+ ...conversationId ? { conversation_id: conversationId } : {}
20629
+ }
20630
+ ];
20631
+ }
20632
+ if (event === "result") {
20633
+ const result = asRecord(parsed.result) ?? {};
20634
+ return [
20635
+ {
20636
+ ...result,
20637
+ type: "complete",
20638
+ ...conversationId && !stringField2(result, "conversation_id") ? { conversation_id: conversationId } : {},
20639
+ ...typeof result.response === "string" && typeof result.result !== "string" ? { result: result.response } : {}
20640
+ }
20641
+ ];
20642
+ }
20643
+ if (event !== "step_update") return [{ type: `antigravity_event:${event}` }];
20644
+ const step = asRecord(parsed.step_update);
20645
+ if (!step) return [{ type: "antigravity_step_update" }];
20646
+ const normalizedStep = {
20647
+ ...step,
20648
+ ...conversationId && !stringField2(step, "conversation_id") ? { conversation_id: conversationId } : {}
20649
+ };
20650
+ const stepType = stringField2(normalizedStep, "step_type")?.toLowerCase();
20651
+ const thinkingText = stringField2(normalizedStep, "thinking_delta") ?? stringField2(normalizedStep, "thinking");
20652
+ const thinkingEvents = thinkingText ? [{ type: "thinking", text: thinkingText, content: thinkingText }] : [];
20653
+ if (stepType === "agent_response") {
20654
+ return [
20655
+ ...thinkingEvents,
20656
+ {
20657
+ ...normalizedStep,
20658
+ type: "assistant_message",
20659
+ ...typeof normalizedStep.text_delta === "string" ? { content: normalizedStep.text_delta } : {}
20660
+ }
20661
+ ];
20012
20662
  }
20663
+ if (stepType === "tool") {
20664
+ const toolInfo = asRecord(normalizedStep.tool_info) ?? {};
20665
+ const toolName = stringField2(normalizedStep, "tool_name") ?? stringField2(toolInfo, "name") ?? "Antigravity Tool";
20666
+ const toolId = liveStepId(normalizedStep);
20667
+ if (isActiveStep(normalizedStep)) {
20668
+ return [
20669
+ ...thinkingEvents,
20670
+ {
20671
+ ...normalizedStep,
20672
+ ...toolInfo,
20673
+ type: "tool_call",
20674
+ tool_id: toolId,
20675
+ tool_name: toolName,
20676
+ parameters: toolInfo.parameters ?? normalizedStep.parameters ?? {}
20677
+ }
20678
+ ];
20679
+ }
20680
+ const toolOutput = stringField2(toolInfo, "output") ?? stringField2(normalizedStep, "output") ?? `${toolName} completed`;
20681
+ return [
20682
+ ...thinkingEvents,
20683
+ {
20684
+ ...normalizedStep,
20685
+ type: "tool_result",
20686
+ tool_id: toolId,
20687
+ output: toolOutput
20688
+ }
20689
+ ];
20690
+ }
20691
+ if (stepType === "subagent") {
20692
+ const subagents = asRecord(normalizedStep.subagent_info)?.subagents;
20693
+ const children = Array.isArray(subagents) ? subagents.map(asRecord).filter((subagent) => Boolean(subagent)) : [];
20694
+ const entries = children.length > 0 ? children : [void 0];
20695
+ return [
20696
+ ...thinkingEvents,
20697
+ ...entries.map((subagent, index) => {
20698
+ const toolId = liveStepId(normalizedStep, index);
20699
+ const childConversationId = subagent && stringField2(subagent, "conversation_id");
20700
+ return {
20701
+ ...normalizedStep,
20702
+ // AGY's DONE means the invocation was accepted, not that the child has
20703
+ // finished. The authenticated stream emits it milliseconds after ACTIVE
20704
+ // while the child transcript is still growing.
20705
+ type: isActiveStep(normalizedStep) ? "subagent_started" : "subagent_launch_ack",
20706
+ antigravity_live: true,
20707
+ tool_id: toolId,
20708
+ task_id: childConversationId ?? toolId,
20709
+ role: subagent && stringField2(subagent, "role"),
20710
+ type_name: subagent && stringField2(subagent, "type_name"),
20711
+ prompt: subagent && (stringField2(subagent, "initial_prompt") ?? stringField2(subagent, "prompt")),
20712
+ workspace: subagent && stringField2(subagent, "workspace"),
20713
+ log_uri: subagent && stringField2(subagent, "log_uri"),
20714
+ status: isActiveStep(normalizedStep) ? "running" : "launched"
20715
+ };
20716
+ })
20717
+ ];
20718
+ }
20719
+ if (thinkingEvents.length > 0) return thinkingEvents;
20720
+ return [{ ...normalizedStep, type: "antigravity_step_update" }];
20721
+ }
20722
+ function handleAntigravityStructuredEvent(parsed, context, state) {
20723
+ const normalized = normalizeLiveAntigravityEvent(parsed);
20724
+ if (normalized) {
20725
+ return normalized.every((event) => handleAntigravityStructuredEvent(event, context, state));
20726
+ }
20727
+ const presenter = context.presenter;
20013
20728
  state.onNewOutput?.();
20014
20729
  const type = typeof parsed.type === "string" ? parsed.type : "";
20015
- if (!type) return;
20730
+ if (!type) return false;
20016
20731
  if (typeof parsed.session_id === "string") state.runtimeSessionId = parsed.session_id;
20017
20732
  if (typeof parsed.conversation_id === "string") state.runtimeSessionId = parsed.conversation_id;
20018
20733
  if (typeof parsed.model === "string") state.activeModel = parsed.model;
20734
+ if (typeof state.runtimeSessionId === "string" && state.runtimeSessionId.trim()) {
20735
+ registerAntigravityParentTranscript(state.runtimeSessionId, context, state);
20736
+ }
20019
20737
  switch (type) {
20020
20738
  case "init":
20021
20739
  case "session_start": {
@@ -20023,29 +20741,31 @@ function parseAntigravityStructuredLine(line, context, state) {
20023
20741
  void presenter.onLog(
20024
20742
  `[antigravity] Session initialized with ${formatAntigravityModelName(model)}`
20025
20743
  );
20026
- break;
20744
+ return true;
20027
20745
  }
20746
+ case "antigravity_step_update":
20747
+ return true;
20028
20748
  case "thinking":
20029
20749
  case "reasoning":
20030
20750
  case "thought": {
20031
20751
  const text = extractText(parsed);
20032
- if (!text) break;
20752
+ if (!text) return true;
20033
20753
  state.iterations = Math.max(state.iterations, 1);
20034
20754
  void presenter.onThinking(text);
20035
- break;
20755
+ return true;
20036
20756
  }
20037
20757
  case "message":
20038
20758
  case "assistant_message":
20039
20759
  case "text":
20040
20760
  case "content": {
20041
20761
  const role = typeof parsed.role === "string" ? parsed.role : "assistant";
20042
- if (role !== "assistant") break;
20762
+ if (role !== "assistant") return true;
20043
20763
  const content = extractText(parsed);
20044
- if (!content) break;
20764
+ if (!content) return true;
20045
20765
  state.iterations = Math.max(state.iterations, 1);
20046
20766
  state.summary += content;
20047
20767
  void presenter.onAssistantText(content);
20048
- break;
20768
+ return true;
20049
20769
  }
20050
20770
  case "tool_use":
20051
20771
  case "tool_call":
@@ -20054,7 +20774,7 @@ function parseAntigravityStructuredLine(line, context, state) {
20054
20774
  const toolId = extractToolId(parsed, state);
20055
20775
  state.iterations = Math.max(state.iterations, 1);
20056
20776
  void presenter.onToolUse(extractToolName(parsed), extractToolInput(parsed), toolId);
20057
- break;
20777
+ return true;
20058
20778
  }
20059
20779
  case "subagent_start":
20060
20780
  case "subagent_started":
@@ -20064,12 +20784,22 @@ function parseAntigravityStructuredLine(line, context, state) {
20064
20784
  case "background_subagent_started": {
20065
20785
  const toolId = extractToolId(parsed, state);
20066
20786
  state.iterations = Math.max(state.iterations, 1);
20787
+ registerBackgroundLauncher(state, toolId);
20788
+ registerBackgroundTaskRecord(state, { ...parsed, tool_use_id: toolId }, toolId);
20067
20789
  void presenter.onToolUse(
20068
20790
  `Subagent: ${extractSubagentName(parsed)}`,
20069
20791
  extractSubagentInput(parsed),
20070
20792
  toolId
20071
20793
  );
20072
- break;
20794
+ if (parsed.antigravity_live === true || stringField2(parsed, "log_uri")) {
20795
+ registerAntigravitySubagentTranscript(parsed, toolId, context, state);
20796
+ }
20797
+ return true;
20798
+ }
20799
+ case "subagent_launch_ack": {
20800
+ const toolId = extractToolId(parsed, state);
20801
+ registerAntigravitySubagentTranscript(parsed, toolId, context, state);
20802
+ return true;
20073
20803
  }
20074
20804
  case "tool_result":
20075
20805
  case "tool_response":
@@ -20078,24 +20808,52 @@ function parseAntigravityStructuredLine(line, context, state) {
20078
20808
  const toolId = extractToolId(parsed, state);
20079
20809
  state.iterations = Math.max(state.iterations, 1);
20080
20810
  void presenter.onToolResult?.(toolId, buildToolResultText(parsed));
20081
- break;
20811
+ return true;
20082
20812
  }
20083
20813
  case "subagent_result":
20084
20814
  case "subagent_complete":
20085
20815
  case "subagent_completed":
20086
20816
  case "background_subagent_result":
20087
20817
  case "background_subagent_completed": {
20088
- const toolId = extractToolId(parsed, state);
20089
20818
  state.iterations = Math.max(state.iterations, 1);
20090
- void presenter.onToolResult?.(toolId, buildToolResultText(parsed));
20091
- break;
20819
+ const toolId = extractToolId(parsed, state);
20820
+ const settledToolId = settleBackgroundTerminalNotification(
20821
+ "antigravity_cli",
20822
+ context,
20823
+ state,
20824
+ { ...parsed, tool_use_id: toolId },
20825
+ {
20826
+ resultText: buildSubagentResultText(parsed),
20827
+ isError: isFailedBackgroundStatus(parsed),
20828
+ emitToolResult: (toolId2, text, isError) => {
20829
+ void presenter.onToolResult?.(toolId2, text, isError);
20830
+ }
20831
+ }
20832
+ );
20833
+ if (settledToolId) state.antigravitySubagentTranscripts?.delete(settledToolId);
20834
+ return true;
20835
+ }
20836
+ case "subagent_status":
20837
+ case "background_subagent_status":
20838
+ case "background_task_status": {
20839
+ registerBackgroundTaskRecord(state, parsed);
20840
+ if (isTerminalBackgroundStatus(parsed)) {
20841
+ settleBackgroundTerminalNotification("antigravity_cli", context, state, parsed, {
20842
+ resultText: buildSubagentResultText(parsed),
20843
+ isError: isFailedBackgroundStatus(parsed),
20844
+ emitToolResult: (toolId, text, isError) => {
20845
+ void presenter.onToolResult?.(toolId, text, isError);
20846
+ }
20847
+ });
20848
+ }
20849
+ return true;
20092
20850
  }
20093
20851
  case "image_generation_end":
20094
20852
  case "generated_image":
20095
20853
  case "image": {
20096
20854
  const image = buildGeneratedImageFromAntigravityPayload(parsed);
20097
20855
  if (image) void presenter.onGeneratedImage?.(image);
20098
- break;
20856
+ return true;
20099
20857
  }
20100
20858
  case "error": {
20101
20859
  const errObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : null;
@@ -20109,20 +20867,31 @@ function parseAntigravityStructuredLine(line, context, state) {
20109
20867
  void presenter.onLog(`[antigravity/${severity}] ${message}`);
20110
20868
  }
20111
20869
  }
20112
- break;
20870
+ return true;
20113
20871
  }
20114
20872
  case "result":
20115
20873
  case "complete": {
20116
- const stats = typeof parsed.stats === "object" && parsed.stats !== null ? parsed.stats : parsed;
20117
- state.iterations = Math.max(state.iterations, 1);
20874
+ const stats = asRecord(parsed.usage) ?? asRecord(parsed.stats) ?? parsed;
20875
+ state.iterations = Math.max(
20876
+ state.iterations,
20877
+ typeof parsed.num_turns === "number" ? parsed.num_turns : 1
20878
+ );
20879
+ const resultText = typeof parsed.result === "string" ? parsed.result : "";
20880
+ if (resultText && !state.summary.trim()) {
20881
+ state.summary += resultText;
20882
+ void presenter.onAssistantText(resultText);
20883
+ }
20118
20884
  const usageModel = state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel : "antigravity");
20119
20885
  state.usage = {
20120
20886
  model: formatAntigravityModelName(usageModel),
20121
20887
  numTurns: Math.max(state.iterations, 1),
20888
+ // AGY's result.duration_seconds is conversation-scoped on resumed
20889
+ // sessions, so it is not a trustworthy per-turn duration. Keep this at
20890
+ // zero until the stream provides a dedicated turn-level metric.
20122
20891
  durationMs: typeof stats.duration_ms === "number" ? stats.duration_ms : 0,
20123
20892
  inputTokens: typeof stats.input_tokens === "number" ? stats.input_tokens : typeof stats.input === "number" ? stats.input : 0,
20124
20893
  outputTokens: typeof stats.output_tokens === "number" ? stats.output_tokens : 0,
20125
- cacheReadTokens: typeof stats.cached === "number" ? stats.cached : 0,
20894
+ 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
20895
  cacheCreationTokens: 0,
20127
20896
  costUsd: 0
20128
20897
  };
@@ -20133,15 +20902,15 @@ function parseAntigravityStructuredLine(line, context, state) {
20133
20902
  cacheReadTokens: state.usage.cacheReadTokens,
20134
20903
  cacheCreationTokens: state.usage.cacheCreationTokens
20135
20904
  });
20136
- if (type === "complete" || parsed.status === "success") state.resultReceived = true;
20137
- state.onResultReceived?.();
20138
- if (typeof parsed.status === "string" && parsed.status !== "success" && !state.error) {
20905
+ const status = typeof parsed.status === "string" ? parsed.status.toLowerCase() : "";
20906
+ if (status && !["success", "completed", "complete"].includes(status) && !state.error) {
20139
20907
  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;
20908
+ 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
20909
  state.error = errMsg;
20910
+ void presenter.onError(errMsg);
20142
20911
  console.error(
20143
20912
  "[antigravity] result status=",
20144
- parsed.status,
20913
+ status,
20145
20914
  "error:",
20146
20915
  JSON.stringify({
20147
20916
  error: parsed.error,
@@ -20150,12 +20919,23 @@ function parseAntigravityStructuredLine(line, context, state) {
20150
20919
  })
20151
20920
  );
20152
20921
  }
20153
- break;
20922
+ const completedSuccessfully = !status || ["success", "completed", "complete"].includes(status);
20923
+ if (type === "complete" || status) {
20924
+ settleAntigravitySubagentTranscripts(context, state, !completedSuccessfully);
20925
+ }
20926
+ if (type === "complete" || status === "success") {
20927
+ deferOrFinalizeStructuredResult("antigravity_cli", context, state);
20928
+ }
20929
+ return true;
20154
20930
  }
20155
20931
  default:
20156
- break;
20932
+ return false;
20157
20933
  }
20158
20934
  }
20935
+ var parseAntigravityStructuredLine = createStructuredLineParser(
20936
+ "antigravity_cli",
20937
+ handleAntigravityStructuredEvent
20938
+ );
20159
20939
  function parseAntigravityLine(line, context, state) {
20160
20940
  try {
20161
20941
  JSON.parse(line);
@@ -20204,7 +20984,14 @@ function detectAntigravityCliCapabilities(command, context) {
20204
20984
  version: versionOutput || void 0,
20205
20985
  supportsStructuredPrint: hasOutputFormat && hasStructuredFormat,
20206
20986
  supportsConversationResume: help.includes("--conversation") || help.includes("--continue"),
20207
- supportsReliableNonTtyPrint: help.includes("-p") || help.includes("--print") || help.includes("--print-timeout")
20987
+ supportsReliableNonTtyPrint: help.includes("-p") || help.includes("--print") || help.includes("--print-timeout"),
20988
+ supportsAddDir: help.includes("--add-dir"),
20989
+ supportsAgentSelection: help.includes("--agent"),
20990
+ supportsExecutionMode: help.includes("--mode"),
20991
+ supportsSandbox: help.includes("--sandbox"),
20992
+ supportsProject: help.includes("--project"),
20993
+ supportsNewProject: help.includes("--new-project"),
20994
+ supportsJsonSchema: help.includes("--json-schema")
20208
20995
  };
20209
20996
  capabilityCache.set(cacheKey, capabilities);
20210
20997
  return capabilities;
@@ -20229,7 +21016,33 @@ function buildAntigravityCliArgs(context, prompt, defaultArgs = [], capabilities
20229
21016
  if (effort && isEffortLevel(effort)) args.push("--effort", effort);
20230
21017
  }
20231
21018
  if (resumeId) args.push("--conversation", resumeId);
20232
- if (!shouldUseReadOnlyRuntimePermissions(context.config)) {
21019
+ const antigravity = context.config.antigravity;
21020
+ if (capabilities?.supportsAddDir) {
21021
+ const workspacePaths = Array.from(
21022
+ new Set(
21023
+ (antigravity?.additionalWorkspacePaths ?? []).map((path) => path.trim()).filter(Boolean)
21024
+ )
21025
+ );
21026
+ for (const path of workspacePaths) args.push("--add-dir", path);
21027
+ }
21028
+ const agent = antigravity?.agent?.trim();
21029
+ if (agent && capabilities?.supportsAgentSelection) args.push("--agent", agent);
21030
+ const project = antigravity?.project?.trim();
21031
+ if (project && capabilities?.supportsProject) {
21032
+ args.push("--project", project);
21033
+ } else if (antigravity?.newProject && capabilities?.supportsNewProject) {
21034
+ args.push("--new-project");
21035
+ }
21036
+ const jsonSchema = antigravity?.jsonSchema?.trim();
21037
+ if (jsonSchema && capabilities?.supportsJsonSchema) args.push("--json-schema", jsonSchema);
21038
+ const readOnly = shouldUseReadOnlyRuntimePermissions(context.config);
21039
+ if (capabilities?.supportsExecutionMode) {
21040
+ args.push("--mode", readOnly ? "plan" : "accept-edits");
21041
+ }
21042
+ if (readOnly && capabilities?.supportsSandbox) {
21043
+ args.push("--sandbox");
21044
+ }
21045
+ if (!readOnly) {
20233
21046
  args.push("--dangerously-skip-permissions");
20234
21047
  }
20235
21048
  if (capabilities?.supportsStructuredPrint) {
@@ -20243,7 +21056,11 @@ function buildAntigravityAugmentedPrompt(context, images) {
20243
21056
  context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim()
20244
21057
  );
20245
21058
  const base = buildResumeAwarePrompt(context.config, context.promptText, { isResume });
20246
- const prompt = context.config.mode === "plan" ? buildPlanModePrefix(base) : base;
21059
+ const workspaceInstructions = isResume ? void 0 : buildAntigravityWorkspaceInstructions(context.cwd);
21060
+ const withWorkspaceInstructions = workspaceInstructions ? `${workspaceInstructions}
21061
+
21062
+ ${base}` : base;
21063
+ const prompt = context.config.mode === "plan" ? buildPlanModePrefix(withWorkspaceInstructions) : withWorkspaceInstructions;
20247
21064
  return appendImagePathReferences(prompt, images);
20248
21065
  }
20249
21066
  function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
@@ -20278,18 +21095,18 @@ function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
20278
21095
  }
20279
21096
  function resolveClaudeHome(env, variant = "claude") {
20280
21097
  if (variant === "supatest") {
20281
- return (0, import_path4.join)((0, import_os4.homedir)(), ".supatest", "claude-internal");
21098
+ return (0, import_path6.join)((0, import_os5.homedir)(), ".supatest", "claude-internal");
20282
21099
  }
20283
- return env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || (0, import_path4.join)((0, import_os4.homedir)(), ".claude");
21100
+ return env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || (0, import_path6.join)((0, import_os5.homedir)(), ".claude");
20284
21101
  }
20285
21102
  function encodeClaudeProjectDir(cwd) {
20286
21103
  return cwd.replace(/[^a-zA-Z0-9]/g, "-");
20287
21104
  }
20288
21105
  function claudeSessionLogExists(input) {
20289
21106
  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`));
21107
+ const projectDir = (0, import_path6.join)(input.home, "projects", encodeClaudeProjectDir(input.cwd));
21108
+ if (!(0, import_fs6.existsSync)(projectDir)) return false;
21109
+ return (0, import_fs6.existsSync)((0, import_path6.join)(projectDir, `${input.sessionId}.jsonl`));
20293
21110
  }
20294
21111
  var execFileAsync = (0, import_util4.promisify)(import_child_process4.execFile);
20295
21112
  var flagSupportCache = /* @__PURE__ */ new Map();
@@ -20315,234 +21132,6 @@ async function cliSupportsFlag(command, flag, env = {}) {
20315
21132
  flagSupportCache.set(key, supported);
20316
21133
  return supported;
20317
21134
  }
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
21135
  var DEBUG_ASK = process.env.ALAN_DEBUG_ASK === "1" || process.env.ALAN_DEBUG === "1";
20547
21136
  function debugAskLog(message) {
20548
21137
  if (DEBUG_ASK) console.info(message);
@@ -20580,22 +21169,22 @@ function extractToolResultContent(content) {
20580
21169
  return "";
20581
21170
  }).filter(Boolean).join("\n");
20582
21171
  }
20583
- function stringField2(record2, key) {
21172
+ function stringField3(record2, key) {
20584
21173
  const value2 = record2[key];
20585
21174
  return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
20586
21175
  }
20587
21176
  function isTerminalTaskNotification(record2) {
20588
- const status = stringField2(record2, "status")?.toLowerCase();
21177
+ const status = stringField3(record2, "status")?.toLowerCase();
20589
21178
  if (status && TERMINAL_TASK_NOTIFICATION_STATUSES.has(status)) return true;
20590
21179
  if (status && NON_TERMINAL_TASK_NOTIFICATION_STATUSES.has(status)) return false;
20591
21180
  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
21181
  }
20593
21182
  function isFailedTaskNotification(record2) {
20594
- const status = stringField2(record2, "status")?.toLowerCase();
21183
+ const status = stringField3(record2, "status")?.toLowerCase();
20595
21184
  return status === "failed" || status === "failure" || status === "error" || status === "cancelled" || status === "canceled";
20596
21185
  }
20597
21186
  function formatClaudeTaskNotificationResult(record2) {
20598
- const status = stringField2(record2, "status") ?? "completed";
21187
+ const status = stringField3(record2, "status") ?? "completed";
20599
21188
  const details = [`Subagent ${status}.`];
20600
21189
  const durationMs = record2.duration_ms ?? record2.durationMs;
20601
21190
  const toolUses = record2.tool_uses ?? record2.toolUses;
@@ -21032,29 +21621,29 @@ function normalizeCodexMcpToolResult(output) {
21032
21621
  return raw;
21033
21622
  }
21034
21623
  function resolveCodexHome(env) {
21035
- return env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path5.join)((0, import_os5.homedir)(), ".codex");
21624
+ return env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path7.join)((0, import_os6.homedir)(), ".codex");
21036
21625
  }
21037
21626
  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;
21627
+ if (!runtimeSessionId || !(0, import_fs7.existsSync)(codexHome)) return null;
21628
+ const root = (0, import_path7.join)(codexHome, "sessions");
21629
+ if (!(0, import_fs7.existsSync)(root)) return null;
21041
21630
  const matches = [];
21042
21631
  const stack = [root];
21043
21632
  while (stack.length > 0) {
21044
21633
  const dir = stack.pop();
21045
21634
  let entries;
21046
21635
  try {
21047
- entries = (0, import_fs5.readdirSync)(dir, { withFileTypes: true });
21636
+ entries = (0, import_fs7.readdirSync)(dir, { withFileTypes: true });
21048
21637
  } catch {
21049
21638
  continue;
21050
21639
  }
21051
21640
  for (const entry of entries) {
21052
- const path = (0, import_path5.join)(dir, entry.name);
21641
+ const path = (0, import_path7.join)(dir, entry.name);
21053
21642
  if (entry.isDirectory()) {
21054
21643
  stack.push(path);
21055
21644
  } else if (entry.isFile() && entry.name.includes(runtimeSessionId) && entry.name.endsWith(".jsonl")) {
21056
21645
  try {
21057
- matches.push({ path, mtimeMs: (0, import_fs5.statSync)(path).mtimeMs });
21646
+ matches.push({ path, mtimeMs: (0, import_fs7.statSync)(path).mtimeMs });
21058
21647
  } catch {
21059
21648
  matches.push({ path, mtimeMs: 0 });
21060
21649
  }
@@ -21108,21 +21697,21 @@ function firstUserMessageLineIndex(lines) {
21108
21697
  const line = lines[index];
21109
21698
  if (!line) continue;
21110
21699
  const entry = parseJsonObject(line);
21111
- const payload = asRecord(entry?.payload);
21700
+ const payload = asRecord2(entry?.payload);
21112
21701
  if (payload?.type === "message" && payload.role === "user" && !isSyntheticUserRolloutMessage(payload)) {
21113
21702
  return index;
21114
21703
  }
21115
21704
  }
21116
21705
  return -1;
21117
21706
  }
21118
- function asRecord(value2) {
21707
+ function asRecord2(value2) {
21119
21708
  return value2 && typeof value2 === "object" ? value2 : null;
21120
21709
  }
21121
21710
  function rolloutTextContent(content) {
21122
21711
  if (typeof content === "string") return content;
21123
21712
  if (!Array.isArray(content)) return "";
21124
21713
  return content.flatMap((block) => {
21125
- const record2 = asRecord(block);
21714
+ const record2 = asRecord2(block);
21126
21715
  const text = record2?.text;
21127
21716
  return typeof text === "string" ? [text] : [];
21128
21717
  }).join("");
@@ -21151,14 +21740,14 @@ function collectCodexWorkerReplays(lines, state) {
21151
21740
  const workersByThreadId = /* @__PURE__ */ new Map();
21152
21741
  for (const line of lines) {
21153
21742
  const entry = parseJsonObject(line);
21154
- const payload = asRecord(entry?.payload);
21743
+ const payload = asRecord2(entry?.payload);
21155
21744
  if (!payload) continue;
21156
21745
  if (entry?.type === "response_item" && payload.type === "function_call" && payload.name === "spawn_agent") {
21157
21746
  const namespace = typeof payload.namespace === "string" ? payload.namespace : "";
21158
21747
  if (namespace !== "collaboration" && namespace !== "multi_agent_v1") continue;
21159
21748
  const callId = typeof payload.call_id === "string" ? payload.call_id : "";
21160
21749
  if (!callId) continue;
21161
- const args = asRecord(parseMaybeJson(payload.arguments));
21750
+ const args = asRecord2(parseMaybeJson(payload.arguments));
21162
21751
  const taskName = typeof args?.task_name === "string" ? args.task_name : "";
21163
21752
  const message = typeof args?.message === "string" ? args.message : "";
21164
21753
  spawnByCallId.set(callId, {
@@ -21171,7 +21760,7 @@ function collectCodexWorkerReplays(lines, state) {
21171
21760
  const callId = typeof payload.call_id === "string" ? payload.call_id : "";
21172
21761
  const spawn32 = spawnByCallId.get(callId);
21173
21762
  if (!spawn32) continue;
21174
- const output = asRecord(parseMaybeJson(payload.output));
21763
+ const output = asRecord2(parseMaybeJson(payload.output));
21175
21764
  const threadId = typeof output?.agent_id === "string" ? output.agent_id : "";
21176
21765
  if (!threadId) continue;
21177
21766
  const nickname = typeof output?.nickname === "string" ? output.nickname : void 0;
@@ -21213,7 +21802,7 @@ function replayCodexWorkerTranscript(context, worker, codexHome, state) {
21213
21802
  if (!state.codexWorkerSessionLogPathByThreadId)
21214
21803
  state.codexWorkerSessionLogPathByThreadId = /* @__PURE__ */ new Map();
21215
21804
  state.codexWorkerSessionLogPathByThreadId.set(worker.threadId, logPath);
21216
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21805
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21217
21806
  const firstUserLineIndex = firstUserMessageLineIndex(allLines);
21218
21807
  const lines = firstUserLineIndex >= 0 ? allLines.slice(firstUserLineIndex + 1) : allLines;
21219
21808
  const emittedToolNames = /* @__PURE__ */ new Map();
@@ -21224,7 +21813,7 @@ function replayCodexWorkerTranscript(context, worker, codexHome, state) {
21224
21813
  if (!line) continue;
21225
21814
  const entry = parseJsonObject(line);
21226
21815
  if (entry?.type !== "response_item") continue;
21227
- const payload = asRecord(entry.payload);
21816
+ const payload = asRecord2(entry.payload);
21228
21817
  if (!payload) continue;
21229
21818
  if (payload.type === "message" && payload.role === "assistant") {
21230
21819
  const text = rolloutTextContent(payload.content);
@@ -21318,7 +21907,7 @@ function syncCodexWorkerEventsFromSessionLog(context, state) {
21318
21907
  const logPath = state.codexSessionLogPath ?? findCodexSessionLog(runtimeSessionId, codexHome);
21319
21908
  if (!logPath) return [];
21320
21909
  state.codexSessionLogPath = logPath;
21321
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21910
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21322
21911
  const latestUserLineIndex = latestUserMessageLineIndex(allLines);
21323
21912
  const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
21324
21913
  const workers = collectCodexWorkerReplays(lines, state);
@@ -21357,7 +21946,7 @@ async function replayCodexMcpToolEventsFromSessionLog(context, state) {
21357
21946
  const codexHome = resolveCodexHome(context.env);
21358
21947
  const logPath = findCodexSessionLog(runtimeSessionId, codexHome);
21359
21948
  if (!logPath) return;
21360
- const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21949
+ const allLines = (0, import_fs7.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
21361
21950
  const latestUserLineIndex = latestUserMessageLineIndex(allLines);
21362
21951
  const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
21363
21952
  const streamedToolIds = state.codexStreamedToolIds ?? /* @__PURE__ */ new Set();
@@ -22207,7 +22796,7 @@ ${ctx.promptText}` : ctx.promptText;
22207
22796
  };
22208
22797
  }
22209
22798
  var explicitBackgroundLaunchers = /* @__PURE__ */ new WeakMap();
22210
- function asRecord2(value2) {
22799
+ function asRecord3(value2) {
22211
22800
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
22212
22801
  }
22213
22802
  function asString(value2) {
@@ -22338,7 +22927,7 @@ function handleCopilotStructuredEvent(parsed, context, state) {
22338
22927
  case "tool.execution_start": {
22339
22928
  const toolId = typeof data.toolCallId === "string" ? data.toolCallId : `copilot-tool-${Date.now()}`;
22340
22929
  const rawName = typeof data.toolName === "string" ? data.toolName : "Copilot Tool";
22341
- const rawArgs = asRecord2(data.arguments) ?? {};
22930
+ const rawArgs = asRecord3(data.arguments) ?? {};
22342
22931
  const softTrack = isCloudDelegateTool(rawName, rawArgs);
22343
22932
  const localBg = isLocalBackgroundLauncher(rawName, rawArgs);
22344
22933
  const args = softTrack || localBg ? normalizeLauncherArgs(rawArgs, softTrack) : rawArgs;
@@ -22497,7 +23086,7 @@ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
22497
23086
  }
22498
23087
  };
22499
23088
  }
22500
- function asRecord3(value2) {
23089
+ function asRecord4(value2) {
22501
23090
  return typeof value2 === "object" && value2 !== null ? value2 : null;
22502
23091
  }
22503
23092
  function extractCursorToolEntry(toolCall) {
@@ -22519,12 +23108,12 @@ function formatCursorToolName(rawName, payload) {
22519
23108
  return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^[a-z]/, (char) => char.toUpperCase());
22520
23109
  }
22521
23110
  function cursorTaskResultVariant(payload, variant) {
22522
- const result = asRecord3(payload.result);
23111
+ const result = asRecord4(payload.result);
22523
23112
  if (!result) return null;
22524
- const direct = asRecord3(result[variant]);
23113
+ const direct = asRecord4(result[variant]);
22525
23114
  if (direct) return direct;
22526
- const oneof = asRecord3(result.result);
22527
- return oneof?.case === variant ? asRecord3(oneof.value) : null;
23115
+ const oneof = asRecord4(result.result);
23116
+ return oneof?.case === variant ? asRecord4(oneof.value) : null;
22528
23117
  }
22529
23118
  function cursorSubagentType(value2) {
22530
23119
  const normalize = (candidate) => {
@@ -22535,18 +23124,18 @@ function cursorSubagentType(value2) {
22535
23124
  return trimmed;
22536
23125
  };
22537
23126
  if (typeof value2 === "string") return normalize(value2);
22538
- const record2 = asRecord3(value2);
23127
+ const record2 = asRecord4(value2);
22539
23128
  if (!record2) return void 0;
22540
23129
  if (typeof record2.case === "string" && record2.case) return normalize(record2.case);
22541
23130
  if (typeof record2.type === "string" && record2.type) return normalize(record2.type);
22542
- const nestedType = asRecord3(record2.type);
23131
+ const nestedType = asRecord4(record2.type);
22543
23132
  if (typeof nestedType?.case === "string" && nestedType.case) return normalize(nestedType.case);
22544
23133
  return normalize(
22545
23134
  Object.keys(nestedType ?? record2).find((key) => key !== "value" && key !== "case")
22546
23135
  );
22547
23136
  }
22548
23137
  function cursorToolArgs(entry) {
22549
- const args = asRecord3(entry.payload.args) ?? asRecord3(entry.payload.arguments) ?? entry.payload;
23138
+ const args = asRecord4(entry.payload.args) ?? asRecord4(entry.payload.arguments) ?? entry.payload;
22550
23139
  if (entry.rawName !== "taskToolCall") return args;
22551
23140
  const subagentType = cursorSubagentType(args.subagentType ?? args.subagent_type);
22552
23141
  return {
@@ -22557,15 +23146,15 @@ function cursorToolArgs(entry) {
22557
23146
  };
22558
23147
  }
22559
23148
  function cursorConversationStepValue(step, key) {
22560
- const direct = asRecord3(step[key]);
23149
+ const direct = asRecord4(step[key]);
22561
23150
  if (direct) return direct;
22562
- const message = asRecord3(step.message);
22563
- return message?.case === key ? asRecord3(message.value) : null;
23151
+ const message = asRecord4(step.message);
23152
+ return message?.case === key ? asRecord4(message.value) : null;
22564
23153
  }
22565
23154
  function cursorConversationStepText(steps) {
22566
23155
  if (!Array.isArray(steps)) return "";
22567
23156
  return steps.flatMap((step) => {
22568
- const record2 = asRecord3(step);
23157
+ const record2 = asRecord4(step);
22569
23158
  if (!record2) return [];
22570
23159
  const assistant = cursorConversationStepValue(record2, "assistantMessage");
22571
23160
  return typeof assistant?.text === "string" ? [assistant.text] : [];
@@ -22595,7 +23184,7 @@ function buildCursorToolResultText(result) {
22595
23184
  function emitCursorSubagentConversationSteps(steps, parentToolUseId, presenter) {
22596
23185
  if (!Array.isArray(steps)) return;
22597
23186
  steps.forEach((step, index) => {
22598
- const record2 = asRecord3(step);
23187
+ const record2 = asRecord4(step);
22599
23188
  if (!record2) return;
22600
23189
  const assistant = cursorConversationStepValue(record2, "assistantMessage");
22601
23190
  if (typeof assistant?.text === "string" && assistant.text) {
@@ -22636,7 +23225,7 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22636
23225
  }
22637
23226
  let lines;
22638
23227
  try {
22639
- lines = (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
23228
+ lines = (0, import_fs8.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
22640
23229
  if (lines.at(-1) === "") lines.pop();
22641
23230
  } catch {
22642
23231
  return { found: false, processedLineCount: startLine, emittedEventCount: 0 };
@@ -22657,10 +23246,10 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22657
23246
  }
22658
23247
  processedLineCount = lineIndex + 1;
22659
23248
  if (entry.role !== "assistant") continue;
22660
- const message = asRecord3(entry.message);
23249
+ const message = asRecord4(entry.message);
22661
23250
  const content = Array.isArray(message?.content) ? message.content : [];
22662
23251
  content.forEach((rawBlock, blockIndex) => {
22663
- const block = asRecord3(rawBlock);
23252
+ const block = asRecord4(rawBlock);
22664
23253
  if (!block) return;
22665
23254
  const type = typeof block.type === "string" ? block.type : "";
22666
23255
  const text = typeof block.text === "string" ? block.text : "";
@@ -22678,18 +23267,18 @@ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter
22678
23267
  const name = typeof block.name === "string" && block.name ? block.name : "Cursor Tool";
22679
23268
  const toolId = typeof block.id === "string" && block.id || `${parentToolUseId}-transcript-${lineIndex}-${blockIndex}`;
22680
23269
  emittedEventCount += 1;
22681
- void presenter.onToolUse(name, asRecord3(block.input) ?? {}, toolId, parentToolUseId);
23270
+ void presenter.onToolUse(name, asRecord4(block.input) ?? {}, toolId, parentToolUseId);
22682
23271
  });
22683
23272
  }
22684
23273
  return { found: true, processedLineCount, emittedEventCount };
22685
23274
  }
22686
23275
  function cursorTranscriptsRoot(context) {
22687
23276
  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");
23277
+ const home = context.env.HOME || process.env.HOME || (0, import_os7.homedir)();
23278
+ return (0, import_path8.join)(home, ".cursor", "projects", projectKey, "agent-transcripts");
22690
23279
  }
22691
23280
  function cursorTranscriptPathForAgent(context, agentId) {
22692
- return (0, import_path6.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
23281
+ return (0, import_path8.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
22693
23282
  }
22694
23283
  function resolveCursorSubagentTranscriptPath(success2, context) {
22695
23284
  const explicit = success2?.transcriptPath ?? success2?.transcript_path;
@@ -22699,14 +23288,14 @@ function resolveCursorSubagentTranscriptPath(success2, context) {
22699
23288
  }
22700
23289
  function cursorTranscriptUserText(transcriptPath) {
22701
23290
  try {
22702
- for (const line of (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/)) {
23291
+ for (const line of (0, import_fs8.readFileSync)(transcriptPath, "utf8").split(/\r?\n/)) {
22703
23292
  if (!line) continue;
22704
- const entry = asRecord3(JSON.parse(line));
23293
+ const entry = asRecord4(JSON.parse(line));
22705
23294
  if (entry?.role !== "user") continue;
22706
- const message = asRecord3(entry.message);
23295
+ const message = asRecord4(entry.message);
22707
23296
  const content = Array.isArray(message?.content) ? message.content : [];
22708
23297
  return content.flatMap((block) => {
22709
- const record2 = asRecord3(block);
23298
+ const record2 = asRecord4(block);
22710
23299
  return typeof record2?.text === "string" ? [record2.text] : [];
22711
23300
  }).join("");
22712
23301
  }
@@ -22716,13 +23305,13 @@ function cursorTranscriptUserText(transcriptPath) {
22716
23305
  }
22717
23306
  function discoverCursorSubagentTranscript(context, state, task) {
22718
23307
  const root = cursorTranscriptsRoot(context);
22719
- if (!(0, import_fs6.existsSync)(root)) return void 0;
23308
+ if (!(0, import_fs8.existsSync)(root)) return void 0;
22720
23309
  const prompt = task.prompt?.trim();
22721
23310
  const description = task.description?.trim().toLowerCase();
22722
23311
  const candidates = [];
22723
23312
  let entries;
22724
23313
  try {
22725
- entries = (0, import_fs6.readdirSync)(root, { withFileTypes: true });
23314
+ entries = (0, import_fs8.readdirSync)(root, { withFileTypes: true });
22726
23315
  } catch {
22727
23316
  return void 0;
22728
23317
  }
@@ -22731,7 +23320,7 @@ function discoverCursorSubagentTranscript(context, state, task) {
22731
23320
  const path = cursorTranscriptPathForAgent(context, entry.name);
22732
23321
  let mtimeMs;
22733
23322
  try {
22734
- mtimeMs = (0, import_fs6.statSync)(path).mtimeMs;
23323
+ mtimeMs = (0, import_fs8.statSync)(path).mtimeMs;
22735
23324
  } catch {
22736
23325
  continue;
22737
23326
  }
@@ -23157,7 +23746,7 @@ var DROID_TASK_OUTPUT_NAMES = /* @__PURE__ */ new Set(["taskoutput", "task_outpu
23157
23746
  var DROID_TASK_STOP_NAMES = /* @__PURE__ */ new Set(["taskstop", "task_stop"]);
23158
23747
  var pendingTaskIdByToolId = /* @__PURE__ */ new WeakMap();
23159
23748
  var explicitBackgroundLaunchers2 = /* @__PURE__ */ new WeakMap();
23160
- function asRecord4(value2) {
23749
+ function asRecord5(value2) {
23161
23750
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23162
23751
  }
23163
23752
  function asString2(value2) {
@@ -23309,7 +23898,7 @@ function handleDroidStructuredEvent(parsed, context, state) {
23309
23898
  const ack = looksLikeBackgroundLaunchAck({
23310
23899
  content,
23311
23900
  value: value2,
23312
- explicitBackground: wasExplicitBackground2(state, toolId) || boolish2(asRecord4(value2)?.run_in_background),
23901
+ explicitBackground: wasExplicitBackground2(state, toolId) || boolish2(asRecord5(value2)?.run_in_background),
23313
23902
  trackedUnlinkedLauncher: trackedLauncher && !linkedBackground
23314
23903
  });
23315
23904
  if (ack.isAck && ack.taskId) {
@@ -23451,7 +24040,7 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
23451
24040
  };
23452
24041
  }
23453
24042
  var ACP_PROTOCOL_VERSION = 1;
23454
- function asRecord5(value2) {
24043
+ function asRecord6(value2) {
23455
24044
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23456
24045
  }
23457
24046
  function asString3(value2) {
@@ -23461,7 +24050,7 @@ function resumeSessionId(context) {
23461
24050
  return context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim() || "";
23462
24051
  }
23463
24052
  function chunkText(content) {
23464
- const record2 = asRecord5(content);
24053
+ const record2 = asRecord6(content);
23465
24054
  if (!record2) return "";
23466
24055
  if (typeof record2.text === "string") return record2.text;
23467
24056
  return chunkText(record2.content);
@@ -23477,8 +24066,8 @@ function toolResultText(update) {
23477
24066
  return "";
23478
24067
  }
23479
24068
  function toolMetaName(update) {
23480
- const meta3 = asRecord5(update._meta);
23481
- const tool = asRecord5(meta3?.["x.ai/tool"]);
24069
+ const meta3 = asRecord6(update._meta);
24070
+ const tool = asRecord6(meta3?.["x.ai/tool"]);
23482
24071
  return asString3(tool?.name);
23483
24072
  }
23484
24073
  function normalizeToolKey2(name) {
@@ -23509,18 +24098,18 @@ function normalizeGrokSubagentInput(toolName, rawInput) {
23509
24098
  return input;
23510
24099
  }
23511
24100
  function resolvePermission(params, context) {
23512
- const record2 = asRecord5(params);
24101
+ const record2 = asRecord6(params);
23513
24102
  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"]);
24103
+ const toolCall = asRecord6(record2?.toolCall);
24104
+ const meta3 = asRecord6(toolCall?._meta);
24105
+ const tool = asRecord6(meta3?.["x.ai/tool"]);
23517
24106
  const isReadOnlyTool = tool?.read_only === true || asString3(tool?.kind) === "read";
23518
24107
  const allow = !shouldUseReadOnlyRuntimePermissions(context.config) || isReadOnlyTool;
23519
24108
  const allowKinds = ["allow_always", "allow_once", "allow"];
23520
24109
  const rejectKinds = ["reject_always", "reject_once", "reject", "deny"];
23521
24110
  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);
24111
+ const chosen = options.find((option) => wanted.includes(asString3(asRecord6(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
24112
+ const optionId = asString3(asRecord6(chosen)?.optionId);
23524
24113
  if (!optionId) return { outcome: { outcome: "cancelled" } };
23525
24114
  return { outcome: { outcome: "selected", optionId } };
23526
24115
  }
@@ -23613,9 +24202,9 @@ function createGrokAcpDriver(imageFiles) {
23613
24202
  forceFinalize(state);
23614
24203
  return;
23615
24204
  }
23616
- const result = asRecord5(message.result);
24205
+ const result = asRecord6(message.result);
23617
24206
  if (message.id === initId) {
23618
- const modelState = asRecord5(asRecord5(result?._meta)?.modelState);
24207
+ const modelState = asRecord6(asRecord6(result?._meta)?.modelState);
23619
24208
  const model = asString3(modelState?.currentModelId);
23620
24209
  if (model) state.activeModel = model;
23621
24210
  beginSession(context, state);
@@ -23629,7 +24218,7 @@ function createGrokAcpDriver(imageFiles) {
23629
24218
  return;
23630
24219
  }
23631
24220
  if (message.id === promptId) {
23632
- const meta3 = asRecord5(result?._meta);
24221
+ const meta3 = asRecord6(result?._meta);
23633
24222
  const model = asString3(meta3?.modelId) || state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel.trim() : "grok");
23634
24223
  const inputTokens = typeof meta3?.inputTokens === "number" ? meta3.inputTokens : 0;
23635
24224
  const outputTokens = typeof meta3?.outputTokens === "number" ? meta3.outputTokens : 0;
@@ -23676,8 +24265,8 @@ function createGrokAcpDriver(imageFiles) {
23676
24265
  }
23677
24266
  }
23678
24267
  function handleNotification(message, context, state) {
23679
- const params = asRecord5(message.params);
23680
- const update = asRecord5(params?.update);
24268
+ const params = asRecord6(message.params);
24269
+ const update = asRecord6(params?.update);
23681
24270
  if (!update || !isPromptActive) return;
23682
24271
  const presenter = context.presenter;
23683
24272
  switch (asString3(update.sessionUpdate)) {
@@ -23699,7 +24288,7 @@ function createGrokAcpDriver(imageFiles) {
23699
24288
  case "tool_call": {
23700
24289
  const toolId = asString3(update.toolCallId);
23701
24290
  const rawName = asString3(update.title) || toolMetaName(update) || "Grok Tool";
23702
- const rawInput = asRecord5(update.rawInput);
24291
+ const rawInput = asRecord6(update.rawInput);
23703
24292
  const isSubagent = isGrokSubagentTool(rawName, rawInput);
23704
24293
  const toolName = isSubagent ? presentGrokSubagentName(rawName) : rawName;
23705
24294
  const input = isSubagent ? normalizeGrokSubagentInput(rawName, rawInput) : rawInput ?? {};
@@ -23774,7 +24363,7 @@ function createGrokAcpDriver(imageFiles) {
23774
24363
  if (line.trim().length > 0) void context.presenter.onLog(`[grok_cli] ${line}`);
23775
24364
  return;
23776
24365
  }
23777
- const message = asRecord5(parsed);
24366
+ const message = asRecord6(parsed);
23778
24367
  if (!message) return;
23779
24368
  if (message.id !== void 0 && message.method === void 0) {
23780
24369
  handleResponse(message, context, state);
@@ -23841,9 +24430,9 @@ function buildGrokAgentArgs(config2, defaultArgs = []) {
23841
24430
  return args;
23842
24431
  }
23843
24432
  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")
24433
+ (0, import_path9.join)((0, import_os8.homedir)(), ".agents", "skills"),
24434
+ (0, import_path9.join)((0, import_os8.homedir)(), ".claude", "skills"),
24435
+ (0, import_path9.join)((0, import_os8.homedir)(), ".config", "opencode", "skills")
23847
24436
  ];
23848
24437
  function parseFrontmatter(content) {
23849
24438
  if (!content.startsWith("---\n")) return {};
@@ -23859,12 +24448,12 @@ function parseFrontmatter(content) {
23859
24448
  return result;
23860
24449
  }
23861
24450
  function listSkillFiles(root) {
23862
- if (!(0, import_fs7.existsSync)(root)) return [];
24451
+ if (!(0, import_fs9.existsSync)(root)) return [];
23863
24452
  const files = [];
23864
- for (const entry of (0, import_fs7.readdirSync)(root, { withFileTypes: true })) {
24453
+ for (const entry of (0, import_fs9.readdirSync)(root, { withFileTypes: true })) {
23865
24454
  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);
24455
+ const skillPath = (0, import_path9.join)(root, entry.name, "SKILL.md");
24456
+ if ((0, import_fs9.existsSync)(skillPath)) files.push(skillPath);
23868
24457
  }
23869
24458
  return files;
23870
24459
  }
@@ -23873,7 +24462,7 @@ function loadInstalledSkills(roots = DEFAULT_SKILL_ROOTS) {
23873
24462
  for (const root of roots) {
23874
24463
  for (const skillPath of listSkillFiles(root)) {
23875
24464
  try {
23876
- const frontmatter = parseFrontmatter((0, import_fs7.readFileSync)(skillPath, "utf8"));
24465
+ const frontmatter = parseFrontmatter((0, import_fs9.readFileSync)(skillPath, "utf8"));
23877
24466
  const name = frontmatter.name;
23878
24467
  const description = frontmatter.description;
23879
24468
  if (!name || !description || skills.has(name)) continue;
@@ -23912,7 +24501,7 @@ var KIMI_SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
23912
24501
  "subagent"
23913
24502
  ]);
23914
24503
  var explicitBackgroundLaunchers3 = /* @__PURE__ */ new WeakMap();
23915
- function asRecord6(value2) {
24504
+ function asRecord7(value2) {
23916
24505
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
23917
24506
  }
23918
24507
  function asString4(value2) {
@@ -24094,7 +24683,7 @@ function handleKimiStructuredEvent(parsed, context, state) {
24094
24683
  );
24095
24684
  return true;
24096
24685
  }
24097
- const statusRecord = asRecord6(
24686
+ const statusRecord = asRecord7(
24098
24687
  (() => {
24099
24688
  try {
24100
24689
  return JSON.parse(content);
@@ -24427,10 +25016,18 @@ var parseOpencodeStructuredLine = createStructuredLineParser(
24427
25016
  "opencode_cli",
24428
25017
  handleOpencodeStructuredEvent
24429
25018
  );
25019
+ function normalizeOpenCodeVariant(value2) {
25020
+ const trimmed = value2?.trim();
25021
+ const containsControlCharacter = Array.from(trimmed ?? "").some((character) => {
25022
+ const code = character.charCodeAt(0);
25023
+ return code <= 31 || code === 127;
25024
+ });
25025
+ if (!trimmed || trimmed.length > 256 || containsControlCharacter) return null;
25026
+ return trimmed;
25027
+ }
24430
25028
  function buildOpencodeEffortArgs(selectedEffortLevel) {
24431
- const trimmed = selectedEffortLevel?.trim().toLowerCase();
24432
- if (!trimmed || !isEffortLevel(trimmed)) return [];
24433
- return ["--variant", trimmed];
25029
+ const variant = normalizeOpenCodeVariant(selectedEffortLevel);
25030
+ return variant ? ["--variant", variant] : [];
24434
25031
  }
24435
25032
  function createOpencodeCliBackend(command = "opencode", defaultArgs = []) {
24436
25033
  return {
@@ -24547,9 +25144,27 @@ var SERVER_LISTENING_PATTERN = /listening on (https?:\/\/\S+)/i;
24547
25144
  var STARTUP_TIMEOUT_MS = 2e4;
24548
25145
  var HEALTH_POLL_INTERVAL_MS = 200;
24549
25146
  var HEALTH_POLL_MAX_ATTEMPTS = 50;
25147
+ var LEASE_IDLE_TTL_MS = 10 * 60 * 1e3;
25148
+ var serveLeases = /* @__PURE__ */ new Map();
25149
+ function leaseKeyFor(context) {
25150
+ const conversationId = context.config.conversationId?.trim();
25151
+ return conversationId ? `conv:${conversationId}` : null;
25152
+ }
25153
+ function isLeaseUsable(lease) {
25154
+ const alive = lease.child.exitCode === null && lease.child.signalCode === null;
25155
+ const fresh = Date.now() - lease.lastUsedAtMs <= LEASE_IDLE_TTL_MS;
25156
+ return alive && fresh;
25157
+ }
25158
+ function evictLease(key) {
25159
+ if (!key) return;
25160
+ const lease = serveLeases.get(key);
25161
+ if (!lease) return;
25162
+ serveLeases.delete(key);
25163
+ killProcessTree(lease.child.pid, { signal: "SIGTERM", child: lease.child });
25164
+ }
24550
25165
  function startOpenCodeServer(command, context) {
24551
25166
  const child = spawnCli(command, ["serve", "--port", "0", "--hostname", "127.0.0.1"], context);
24552
- const ready = new Promise((resolve22, reject) => {
25167
+ const ready = new Promise((resolve42, reject) => {
24553
25168
  let settled = false;
24554
25169
  const timeout = setTimeout(() => {
24555
25170
  if (settled) return;
@@ -24567,7 +25182,7 @@ function startOpenCodeServer(command, context) {
24567
25182
  if (!match) return;
24568
25183
  settled = true;
24569
25184
  clearTimeout(timeout);
24570
- resolve22({ baseUrl: match[1].replace(/\/$/, "") });
25185
+ resolve42({ baseUrl: match[1].replace(/\/$/, "") });
24571
25186
  };
24572
25187
  stdoutRl.on("line", checkLine);
24573
25188
  stderrRl.on("line", (line) => {
@@ -24605,7 +25220,7 @@ async function waitForHealthy(baseUrl, signal) {
24605
25220
  }
24606
25221
  } catch {
24607
25222
  }
24608
- await new Promise((resolve22) => setTimeout(resolve22, HEALTH_POLL_INTERVAL_MS));
25223
+ await new Promise((resolve42) => setTimeout(resolve42, HEALTH_POLL_INTERVAL_MS));
24609
25224
  }
24610
25225
  throw new Error(`opencode server at ${baseUrl} did not become healthy in time`);
24611
25226
  }
@@ -24642,27 +25257,30 @@ function buildPromptParts(promptText, imageFiles, attachmentFiles) {
24642
25257
  type: "file",
24643
25258
  mime: file2.mimeType,
24644
25259
  filename: file2.filename,
24645
- url: (0, import_url.pathToFileURL)(file2.path).href
25260
+ url: (0, import_url2.pathToFileURL)(file2.path).href
24646
25261
  })
24647
25262
  );
24648
25263
  return [...attachments, { type: "text", text: promptText }];
24649
25264
  }
24650
- async function sendPrompt(baseUrl, sessionId, context, parts2, signal) {
25265
+ function buildOpenCodePromptRequest(context, parts2) {
24651
25266
  const model = context.config.selectedModel?.trim();
24652
25267
  const modelBody = model?.includes("/") ? (() => {
24653
25268
  const slashIndex = model.indexOf("/");
24654
25269
  return { providerID: model.slice(0, slashIndex), modelID: model.slice(slashIndex + 1) };
24655
25270
  })() : void 0;
24656
- const variant = context.config.selectedEffortLevel?.trim().toLowerCase();
25271
+ const variant = normalizeOpenCodeVariant(context.config.selectedEffortLevel);
25272
+ return {
25273
+ parts: parts2,
25274
+ ...modelBody ? { model: modelBody } : {},
25275
+ ...variant ? { variant } : {}
25276
+ };
25277
+ }
25278
+ async function sendPrompt(baseUrl, sessionId, context, parts2, signal) {
24657
25279
  const response = await fetch(`${baseUrl}/session/${encodeURIComponent(sessionId)}/message`, {
24658
25280
  method: "POST",
24659
25281
  signal,
24660
25282
  headers: { "Content-Type": "application/json" },
24661
- body: JSON.stringify({
24662
- parts: parts2,
24663
- ...modelBody ? { model: modelBody } : {},
24664
- ...variant && isEffortLevel(variant) ? { variant } : {}
24665
- })
25283
+ body: JSON.stringify(buildOpenCodePromptRequest(context, parts2))
24666
25284
  });
24667
25285
  if (!response.ok) {
24668
25286
  const text = await response.text().catch(() => "");
@@ -24679,6 +25297,18 @@ async function replyToPermission(baseUrl, requestId, reply, signal) {
24679
25297
  console.warn("[opencode_serve] Failed to reply to permission request", requestId, error2);
24680
25298
  });
24681
25299
  }
25300
+ var NON_INTERACTIVE_PERMISSION_KINDS = /* @__PURE__ */ new Set(["question", "plan_enter", "plan_exit"]);
25301
+ function decideAndReplyToPermission(presenter, baseUrl, properties, readOnly, signal, origin) {
25302
+ const requestId = getString(properties.id);
25303
+ if (!requestId) return;
25304
+ const permissionKind = getString(properties.permission) || "an action";
25305
+ const nonInteractive = NON_INTERACTIVE_PERMISSION_KINDS.has(permissionKind);
25306
+ const reply = nonInteractive || readOnly ? "reject" : "once";
25307
+ const subject = origin === "root" ? "OpenCode" : "OpenCode's background session";
25308
+ 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).`;
25309
+ emitSessionNotice(presenter, "permission_decision", message);
25310
+ void replyToPermission(baseUrl, requestId, reply, signal);
25311
+ }
24682
25312
  function buildAgentResult(state, sessionId, aborted2) {
24683
25313
  if (aborted2) {
24684
25314
  return {
@@ -24726,7 +25356,13 @@ function createOpencodeServeBackend(command = "opencode") {
24726
25356
  );
24727
25357
  const runContext = withAutonomousOpenCodePermissions(context);
24728
25358
  const readOnly = shouldUseReadOnlyRuntimePermissions(context.config);
24729
- const { child, ready } = startOpenCodeServer(command, runContext);
25359
+ const leaseKey = leaseKeyFor(context);
25360
+ const existingLease = leaseKey ? serveLeases.get(leaseKey) : void 0;
25361
+ const reuseLease = Boolean(existingLease && isLeaseUsable(existingLease));
25362
+ if (existingLease && !reuseLease) evictLease(leaseKey);
25363
+ const spawnedServer = reuseLease && existingLease ? null : startOpenCodeServer(command, runContext);
25364
+ const child = reuseLease && existingLease ? existingLease.child : spawnedServer.child;
25365
+ const ready = reuseLease && existingLease ? Promise.resolve({ baseUrl: existingLease.baseUrl }) : spawnedServer.ready;
24730
25366
  const state = { process: child, iterations: 0, summary: "" };
24731
25367
  context.onProcessSpawned?.(child);
24732
25368
  context.registerLivenessProbe?.(() => ({
@@ -24739,13 +25375,19 @@ function createOpencodeServeBackend(command = "opencode") {
24739
25375
  const onAbort = () => {
24740
25376
  aborted2 = true;
24741
25377
  sseClose?.();
25378
+ if (leaseKey) serveLeases.delete(leaseKey);
24742
25379
  killProcessTree(child.pid, { signal: "SIGTERM", child });
24743
25380
  };
24744
25381
  context.abortController.signal.addEventListener("abort", onAbort, { once: true });
24745
25382
  try {
24746
25383
  const server = await ready;
24747
25384
  state.lastRawOutputAtMs = Date.now();
24748
- await waitForHealthy(server.baseUrl, context.abortController.signal);
25385
+ if (!reuseLease) {
25386
+ await waitForHealthy(server.baseUrl, context.abortController.signal);
25387
+ }
25388
+ if (leaseKey) {
25389
+ serveLeases.set(leaseKey, { child, baseUrl: server.baseUrl, lastUsedAtMs: Date.now() });
25390
+ }
24749
25391
  const session = await resolveSession(
24750
25392
  server.baseUrl,
24751
25393
  runContext,
@@ -24803,17 +25445,94 @@ function createOpencodeServeBackend(command = "opencode") {
24803
25445
  } finally {
24804
25446
  context.abortController.signal.removeEventListener("abort", onAbort);
24805
25447
  sseClose?.();
24806
- killProcessTree(child.pid, { signal: "SIGTERM", child });
25448
+ const wasAborted = aborted2 || context.abortController.signal.aborted;
25449
+ if (wasAborted || !leaseKey) {
25450
+ if (leaseKey) serveLeases.delete(leaseKey);
25451
+ killProcessTree(child.pid, { signal: "SIGTERM", child });
25452
+ } else {
25453
+ const lease = serveLeases.get(leaseKey);
25454
+ if (lease) lease.lastUsedAtMs = Date.now();
25455
+ }
24807
25456
  cleanupImages();
24808
25457
  cleanupFiles();
24809
25458
  }
24810
25459
  }
24811
25460
  };
24812
25461
  }
25462
+ function resolveChildSessionLauncherToolId(state, eventSessionId) {
25463
+ const existing = state.backgroundToolIdByTaskId?.get(eventSessionId);
25464
+ if (existing) return existing;
25465
+ registerBackgroundTaskRecord(state, { task_id: eventSessionId });
25466
+ return state.backgroundToolIdByTaskId?.get(eventSessionId);
25467
+ }
25468
+ function handleOpenCodeChildSessionEvent(event, eventSessionId, context, state, readOnly, baseUrl) {
25469
+ const properties = event.properties;
25470
+ switch (event.type) {
25471
+ case "message.updated": {
25472
+ const info = getRecord(properties.info);
25473
+ if (getString(info?.role) === "user") {
25474
+ const messageId = getString(info?.id);
25475
+ if (messageId) {
25476
+ state.opencodeUserMessageIds ??= /* @__PURE__ */ new Set();
25477
+ state.opencodeUserMessageIds.add(messageId);
25478
+ }
25479
+ }
25480
+ return false;
25481
+ }
25482
+ case "message.part.updated": {
25483
+ const part = getRecord(properties.part);
25484
+ if (!part) return false;
25485
+ const messageId = getString(part.messageID);
25486
+ if (messageId && state.opencodeUserMessageIds?.has(messageId)) return false;
25487
+ const parentToolUseId = resolveChildSessionLauncherToolId(state, eventSessionId);
25488
+ if (!parentToolUseId && !state.opencodeUnlinkedChildSessionIds?.has(eventSessionId)) {
25489
+ state.opencodeUnlinkedChildSessionIds ??= /* @__PURE__ */ new Set();
25490
+ state.opencodeUnlinkedChildSessionIds.add(eventSessionId);
25491
+ void context.presenter.onLog(
25492
+ `[opencode] Background session ${eventSessionId} is active (no linked launcher \u2014 showing at top level)`
25493
+ );
25494
+ }
25495
+ mapOpencodePart(part, context, state, { parentToolUseId });
25496
+ return false;
25497
+ }
25498
+ case "message.part.delta":
25499
+ return false;
25500
+ case "permission.asked": {
25501
+ decideAndReplyToPermission(
25502
+ context.presenter,
25503
+ baseUrl,
25504
+ properties,
25505
+ readOnly,
25506
+ context.abortController.signal,
25507
+ "background session"
25508
+ );
25509
+ return false;
25510
+ }
25511
+ case "session.error": {
25512
+ const errorRecord = getRecord(properties.error);
25513
+ const message = getString(errorRecord?.message) || getString(properties.error) || "Background OpenCode session error.";
25514
+ void context.presenter.onLog(
25515
+ `[opencode] Background session ${eventSessionId} error: ${message}`
25516
+ );
25517
+ return false;
25518
+ }
25519
+ default:
25520
+ return false;
25521
+ }
25522
+ }
24813
25523
  function handleOpenCodeServeEvent(event, sessionId, context, state, readOnly, baseUrl) {
24814
25524
  const properties = event.properties;
24815
25525
  const eventSessionId = getString(properties.sessionID);
24816
- if (eventSessionId && eventSessionId !== sessionId) return false;
25526
+ if (eventSessionId && eventSessionId !== sessionId) {
25527
+ return handleOpenCodeChildSessionEvent(
25528
+ event,
25529
+ eventSessionId,
25530
+ context,
25531
+ state,
25532
+ readOnly,
25533
+ baseUrl
25534
+ );
25535
+ }
24817
25536
  switch (event.type) {
24818
25537
  // Live-verified: the SSE bus emits a message.updated (and matching
24819
25538
  // message.part.updated) for the USER's own message too, not just the
@@ -24843,15 +25562,14 @@ function handleOpenCodeServeEvent(event, sessionId, context, state, readOnly, ba
24843
25562
  case "message.part.delta":
24844
25563
  return false;
24845
25564
  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
- }
25565
+ decideAndReplyToPermission(
25566
+ context.presenter,
25567
+ baseUrl,
25568
+ properties,
25569
+ readOnly,
25570
+ context.abortController.signal,
25571
+ "root"
25572
+ );
24855
25573
  return false;
24856
25574
  }
24857
25575
  case "session.error": {
@@ -25024,22 +25742,31 @@ function parseRepoNamespace(command) {
25024
25742
  };
25025
25743
  }
25026
25744
  function hasSkillLayout(dir) {
25027
- return SKILL_LAYOUT_PARTS.some((parts2) => (0, import_fs8.existsSync)((0, import_path8.join)(dir, ...parts2)));
25745
+ return SKILL_LAYOUT_PARTS.some((parts2) => (0, import_fs10.existsSync)((0, import_path10.join)(dir, ...parts2)));
25028
25746
  }
25029
25747
  function isGitRepo(dir) {
25030
- return (0, import_fs8.existsSync)((0, import_path8.join)(dir, ".git"));
25748
+ return (0, import_fs10.existsSync)((0, import_path10.join)(dir, ".git"));
25031
25749
  }
25032
25750
  function isLeafProjectRoot(dir) {
25033
25751
  return isGitRepo(dir) || hasSkillLayout(dir);
25034
25752
  }
25035
25753
  function skillDirsForRoot(root) {
25036
- return SKILL_LAYOUT_PARTS.map((parts2) => (0, import_path8.join)(root, ...parts2));
25754
+ return SKILL_LAYOUT_PARTS.map((parts2) => (0, import_path10.join)(root, ...parts2));
25755
+ }
25756
+ function pluginSkillDirsForRoot(root) {
25757
+ const pluginsDir = (0, import_path10.join)(root, ".agents", "plugins");
25758
+ if (!(0, import_fs10.existsSync)(pluginsDir)) return [];
25759
+ try {
25760
+ return (0, import_fs10.readdirSync)(pluginsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_path10.join)(pluginsDir, entry.name, "skills"));
25761
+ } catch {
25762
+ return [];
25763
+ }
25037
25764
  }
25038
25765
  function listImmediateChildDirs(cwd) {
25039
- if (!(0, import_fs8.existsSync)(cwd)) return [];
25766
+ if (!(0, import_fs10.existsSync)(cwd)) return [];
25040
25767
  let entries = [];
25041
25768
  try {
25042
- entries = (0, import_fs8.readdirSync)(cwd, { withFileTypes: true });
25769
+ entries = (0, import_fs10.readdirSync)(cwd, { withFileTypes: true });
25043
25770
  } catch {
25044
25771
  return [];
25045
25772
  }
@@ -25047,40 +25774,50 @@ function listImmediateChildDirs(cwd) {
25047
25774
  for (const entry of entries) {
25048
25775
  if (!entry.isDirectory()) continue;
25049
25776
  if (entry.name.startsWith(".")) continue;
25050
- children.push((0, import_path8.join)(cwd, entry.name));
25777
+ children.push((0, import_path10.join)(cwd, entry.name));
25051
25778
  }
25052
25779
  return children;
25053
25780
  }
25054
25781
  function projectCandidateRoots(cwd) {
25055
25782
  if (!cwd) return [];
25056
- const roots = [...skillDirsForRoot(cwd)];
25783
+ const roots = [...skillDirsForRoot(cwd), ...pluginSkillDirsForRoot(cwd)];
25057
25784
  if (!isLeafProjectRoot(cwd)) {
25058
25785
  for (const child of listImmediateChildDirs(cwd)) {
25059
25786
  roots.push(...skillDirsForRoot(child));
25787
+ roots.push(...pluginSkillDirsForRoot(child));
25060
25788
  }
25061
25789
  }
25062
25790
  return Array.from(new Set(roots));
25063
25791
  }
25064
- function globalCandidateRoots() {
25065
- return skillDirsForRoot((0, import_os8.homedir)());
25792
+ function globalCandidateRoots(home) {
25793
+ const antigravityConfig = (0, import_path10.join)(home, ".gemini", "config");
25794
+ return Array.from(
25795
+ /* @__PURE__ */ new Set([
25796
+ ...skillDirsForRoot(home),
25797
+ (0, import_path10.join)(antigravityConfig, "skills"),
25798
+ ...pluginSkillDirsForRoot(antigravityConfig)
25799
+ ])
25800
+ );
25066
25801
  }
25067
25802
  function namespacedCandidateRoots(cwd, repoLabel) {
25068
25803
  const roots = [];
25069
25804
  if (cwd) {
25070
- roots.push(...skillDirsForRoot((0, import_path8.join)(cwd, repoLabel)));
25805
+ roots.push(...skillDirsForRoot((0, import_path10.join)(cwd, repoLabel)));
25806
+ roots.push(...pluginSkillDirsForRoot((0, import_path10.join)(cwd, repoLabel)));
25071
25807
  const base = cwd.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
25072
25808
  if (base === repoLabel) {
25073
25809
  roots.push(...skillDirsForRoot(cwd));
25810
+ roots.push(...pluginSkillDirsForRoot(cwd));
25074
25811
  }
25075
25812
  }
25076
25813
  return Array.from(new Set(roots));
25077
25814
  }
25078
25815
  function readSkillAt(root, command) {
25079
- const skillPath = (0, import_path8.join)(root, command, "SKILL.md");
25080
- if (!(0, import_fs8.existsSync)(skillPath)) return null;
25816
+ const skillPath = (0, import_path10.join)(root, command, "SKILL.md");
25817
+ if (!(0, import_fs10.existsSync)(skillPath)) return null;
25081
25818
  let content;
25082
25819
  try {
25083
- content = (0, import_fs8.readFileSync)(skillPath, "utf-8");
25820
+ content = (0, import_fs10.readFileSync)(skillPath, "utf-8");
25084
25821
  } catch {
25085
25822
  return null;
25086
25823
  }
@@ -25103,7 +25840,7 @@ function collectMatches(roots, command, userRequest) {
25103
25840
  }
25104
25841
  return matches;
25105
25842
  }
25106
- function resolveSkillInvocation(text, cwd) {
25843
+ function resolveSkillInvocation(text, cwd, home = (0, import_os9.homedir)()) {
25107
25844
  const parsed = parseSkillInvocation(text);
25108
25845
  if (!parsed) return null;
25109
25846
  const projectExact = collectMatches(
@@ -25115,7 +25852,11 @@ function resolveSkillInvocation(text, cwd) {
25115
25852
  if (projectExact.length > 1) {
25116
25853
  return null;
25117
25854
  }
25118
- const globalExact = collectMatches(globalCandidateRoots(), parsed.command, parsed.userRequest);
25855
+ const globalExact = collectMatches(
25856
+ globalCandidateRoots(home),
25857
+ parsed.command,
25858
+ parsed.userRequest
25859
+ );
25119
25860
  if (globalExact.length === 1) return globalExact[0];
25120
25861
  const namespaced = parseRepoNamespace(parsed.command);
25121
25862
  if (!namespaced) return null;
@@ -25132,8 +25873,8 @@ function resolveSkillInvocation(text, cwd) {
25132
25873
  }
25133
25874
  return null;
25134
25875
  }
25135
- function expandSkillInvocationPrompt(text, cwd) {
25136
- const invocation = resolveSkillInvocation(text, cwd);
25876
+ function expandSkillInvocationPrompt(text, cwd, home = (0, import_os9.homedir)()) {
25877
+ const invocation = resolveSkillInvocation(text, cwd, home);
25137
25878
  if (!invocation) return { text, invocation: null };
25138
25879
  const request = invocation.userRequest || "(No additional request text was provided.)";
25139
25880
  return {
@@ -25157,7 +25898,6 @@ var DROID_DEFAULT_MODEL = "claude-opus-4-7";
25157
25898
  var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
25158
25899
  function normalizeBackendKind(kind) {
25159
25900
  if (kind === "codex") return "codex_app_server";
25160
- if (kind === "gemini" || kind === "gemini_cli") return "antigravity_cli";
25161
25901
  return kind || "claude_cli";
25162
25902
  }
25163
25903
  function firstCatalogModelId(backendKind) {
@@ -25567,18 +26307,18 @@ ${runtimeConfig.task}` } : {}
25567
26307
  `[base-machine-agent] Transient error (attempt ${attempt + 1}/${_BaseMachineAgent.MAX_RETRIES + 1}), retrying in ${delayMs}ms: ${lastResult.error}`
25568
26308
  );
25569
26309
  void this.presenter.onLog(`Transient error, retrying in ${Math.round(delayMs / 1e3)}s...`);
25570
- await new Promise((resolve22) => {
26310
+ await new Promise((resolve42) => {
25571
26311
  const signal = this.abortController?.signal;
25572
26312
  if (signal?.aborted) {
25573
- resolve22();
26313
+ resolve42();
25574
26314
  return;
25575
26315
  }
25576
- const timeoutId = setTimeout(resolve22, delayMs);
26316
+ const timeoutId = setTimeout(resolve42, delayMs);
25577
26317
  signal?.addEventListener(
25578
26318
  "abort",
25579
26319
  () => {
25580
26320
  clearTimeout(timeoutId);
25581
- resolve22();
26321
+ resolve42();
25582
26322
  },
25583
26323
  { once: true }
25584
26324
  );
@@ -25748,14 +26488,14 @@ function normalizePath2(candidate, cwd) {
25748
26488
  } catch {
25749
26489
  }
25750
26490
  if (path.startsWith("~/")) return null;
25751
- if ((0, import_path9.isAbsolute)(path)) return path;
25752
- return cwd ? (0, import_path9.join)(cwd, path) : null;
26491
+ if ((0, import_path11.isAbsolute)(path)) return path;
26492
+ return cwd ? (0, import_path11.join)(cwd, path) : null;
25753
26493
  }
25754
26494
  function resolveToolCwd(cwd, toolInput) {
25755
26495
  if (!isRecord(toolInput)) return cwd;
25756
26496
  const raw = typeof toolInput.cwd === "string" ? toolInput.cwd : typeof toolInput.workdir === "string" ? toolInput.workdir : typeof toolInput.workingDirectory === "string" ? toolInput.workingDirectory : null;
25757
26497
  if (!raw) return cwd;
25758
- return (0, import_path9.isAbsolute)(raw) || !cwd ? raw : (0, import_path9.join)(cwd, raw);
26498
+ return (0, import_path11.isAbsolute)(raw) || !cwd ? raw : (0, import_path11.join)(cwd, raw);
25759
26499
  }
25760
26500
  function extractBrowserMediaPathHints(content, cwd, toolName, options = {}, kind = "video") {
25761
26501
  if (!isAgentBrowserMediaInvocation(toolName, content, options.toolInput, kind)) return [];
@@ -25798,19 +26538,19 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
25798
26538
  const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
25799
26539
  for (const candidate of extractPathCandidates(content, options)) {
25800
26540
  const path = normalizePath2(candidate, effectiveCwd);
25801
- if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
26541
+ if (!path || seen.has(path) || !(0, import_fs11.existsSync)(path)) continue;
25802
26542
  seen.add(path);
25803
- const ext = (0, import_path9.extname)(path).toLowerCase();
26543
+ const ext = (0, import_path11.extname)(path).toLowerCase();
25804
26544
  const mimeType = IMAGE_MIME_BY_EXT[ext];
25805
26545
  if (!mimeType) continue;
25806
- const stat = (0, import_fs9.statSync)(path);
26546
+ const stat = (0, import_fs11.statSync)(path);
25807
26547
  if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_GENERATED_IMAGE_BYTES) continue;
25808
- const buffer = (0, import_fs9.readFileSync)(path);
26548
+ const buffer = (0, import_fs11.readFileSync)(path);
25809
26549
  const { width, height } = readImageDimensions2(buffer, mimeType);
25810
26550
  images.push({
25811
26551
  type: "generated_image",
25812
26552
  id: (0, import_crypto4.randomUUID)(),
25813
- filename: (0, import_path9.basename)(path),
26553
+ filename: (0, import_path11.basename)(path),
25814
26554
  mimeType,
25815
26555
  size: buffer.length,
25816
26556
  width,
@@ -25837,20 +26577,20 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
25837
26577
  const mimeByExt = kind === "video" ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT;
25838
26578
  for (const candidate of extractPathCandidates(content, options, extensionsPattern)) {
25839
26579
  const path = normalizePath2(candidate, effectiveCwd);
25840
- if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
26580
+ if (!path || seen.has(path) || !(0, import_fs11.existsSync)(path)) continue;
25841
26581
  seen.add(path);
25842
- const ext = (0, import_path9.extname)(path).toLowerCase();
26582
+ const ext = (0, import_path11.extname)(path).toLowerCase();
25843
26583
  const mimeType = mimeByExt[ext];
25844
26584
  if (!mimeType) continue;
25845
- const stat = (0, import_fs9.statSync)(path);
26585
+ const stat = (0, import_fs11.statSync)(path);
25846
26586
  if (!stat.isFile() || stat.size <= 0 || stat.size > maxBytes) continue;
25847
- const buffer = (0, import_fs9.readFileSync)(path);
26587
+ const buffer = (0, import_fs11.readFileSync)(path);
25848
26588
  const dimensions = kind === "image" ? readImageDimensions2(buffer, mimeType) : null;
25849
26589
  media.push({
25850
26590
  type: "session_media",
25851
26591
  kind,
25852
26592
  id: (0, import_crypto4.randomUUID)(),
25853
- filename: (0, import_path9.basename)(path),
26593
+ filename: (0, import_path11.basename)(path),
25854
26594
  mimeType,
25855
26595
  size: buffer.length,
25856
26596
  width: dimensions?.width,
@@ -25896,6 +26636,14 @@ var MCP_INSPECTION_PLANS = {
25896
26636
  args: ["mcp", "list"],
25897
26637
  updateGuidance: "Update OpenCode CLI",
25898
26638
  requireExpectedUrl: false
26639
+ },
26640
+ opencode_serve: {
26641
+ backendKind: "opencode_serve",
26642
+ providerLabel: "OpenCode CLI",
26643
+ command: "opencode",
26644
+ args: ["mcp", "list"],
26645
+ updateGuidance: "Update OpenCode CLI",
26646
+ requireExpectedUrl: false
25899
26647
  }
25900
26648
  };
25901
26649
  var UNSUPPORTED_COMMAND_PATTERN = /unknown (?:command|subcommand)|unrecognized (?:command|subcommand)|unexpected argument|invalid command|not a recognized command/i;
@@ -26065,8 +26813,8 @@ async function withTimeout(promise2, timeoutMs, fallback) {
26065
26813
  try {
26066
26814
  return await Promise.race([
26067
26815
  promise2,
26068
- new Promise((resolve7) => {
26069
- timer = setTimeout(() => resolve7(fallback), timeoutMs);
26816
+ new Promise((resolve9) => {
26817
+ timer = setTimeout(() => resolve9(fallback), timeoutMs);
26070
26818
  })
26071
26819
  ]);
26072
26820
  } finally {
@@ -26079,7 +26827,7 @@ async function collectCodexLimits(env) {
26079
26827
  const codexCommand = resolveExecutable("codex", runtimeEnv, "ALAN_CODEX_PATH");
26080
26828
  if (!codexCommand)
26081
26829
  return [];
26082
- return withTimeout(new Promise((resolve7) => {
26830
+ return withTimeout(new Promise((resolve9) => {
26083
26831
  const child = (0, import_node_child_process2.spawn)(codexCommand, ["-s", "read-only", "-a", "untrusted", "app-server"], {
26084
26832
  env: runtimeEnv,
26085
26833
  stdio: ["pipe", "pipe", "ignore"]
@@ -26091,7 +26839,7 @@ async function collectCodexLimits(env) {
26091
26839
  pending.clear();
26092
26840
  if (!child.killed)
26093
26841
  child.kill();
26094
- resolve7(windows);
26842
+ resolve9(windows);
26095
26843
  };
26096
26844
  const request = (method, params = {}) => {
26097
26845
  const id = nextId++;
@@ -28924,9 +29672,9 @@ var Socket2 = class extends Emitter {
28924
29672
  * @return a Promise that will be fulfilled when the server acknowledges the event
28925
29673
  */
28926
29674
  emitWithAck(ev, ...args) {
28927
- return new Promise((resolve7, reject) => {
29675
+ return new Promise((resolve9, reject) => {
28928
29676
  const fn = (arg1, arg2) => {
28929
- return arg1 ? reject(arg1) : resolve7(arg2);
29677
+ return arg1 ? reject(arg1) : resolve9(arg2);
28930
29678
  };
28931
29679
  fn.withError = true;
28932
29680
  args.push(fn);
@@ -31066,7 +31814,9 @@ var INSTALLABLE_PROVIDER_PACKAGES = {
31066
31814
  claude_cli: { npmPackage: "@anthropic-ai/claude-code", command: "claude", label: "Claude Code" },
31067
31815
  codex_app_server: { npmPackage: "@openai/codex", command: "codex", label: "Codex" },
31068
31816
  copilot_cli: { npmPackage: "@github/copilot", command: "copilot", label: "Copilot" },
31069
- opencode_cli: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" }
31817
+ opencode_cli: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" },
31818
+ // Server transport installs the same "opencode" binary.
31819
+ opencode_serve: { npmPackage: "opencode-ai", command: "opencode", label: "opencode" }
31070
31820
  };
31071
31821
  var INSTALL_TIMEOUT_MS = 12e4;
31072
31822
  var installOutcomes = /* @__PURE__ */ new Map();
@@ -31085,7 +31835,7 @@ function pinnedVersion(npmPackage) {
31085
31835
  return "latest";
31086
31836
  }
31087
31837
  function runNpmInstall(installSpec, env, timeoutMs) {
31088
- return new Promise((resolve7) => {
31838
+ return new Promise((resolve9) => {
31089
31839
  const isWin = (0, import_node_os5.platform)() === "win32";
31090
31840
  let child;
31091
31841
  try {
@@ -31097,7 +31847,7 @@ function runNpmInstall(installSpec, env, timeoutMs) {
31097
31847
  stdio: ["ignore", "pipe", "pipe"]
31098
31848
  });
31099
31849
  } catch (error2) {
31100
- resolve7({ status: null, stdout: "", stderr: "", error: error2 });
31850
+ resolve9({ status: null, stdout: "", stderr: "", error: error2 });
31101
31851
  return;
31102
31852
  }
31103
31853
  let stdout = "";
@@ -31108,10 +31858,10 @@ function runNpmInstall(installSpec, env, timeoutMs) {
31108
31858
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
31109
31859
  stderr += chunk;
31110
31860
  });
31111
- child.once("error", (error2) => resolve7({ status: null, stdout, stderr, error: error2 }));
31861
+ child.once("error", (error2) => resolve9({ status: null, stdout, stderr, error: error2 }));
31112
31862
  child.once(
31113
31863
  "close",
31114
- (status, signal) => resolve7({
31864
+ (status, signal) => resolve9({
31115
31865
  status,
31116
31866
  stdout,
31117
31867
  stderr,
@@ -45268,7 +46018,7 @@ var Protocol = class {
45268
46018
  return;
45269
46019
  }
45270
46020
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
45271
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
46021
+ await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
45272
46022
  options?.signal?.throwIfAborted();
45273
46023
  }
45274
46024
  } catch (error2) {
@@ -45285,7 +46035,7 @@ var Protocol = class {
45285
46035
  */
45286
46036
  request(request, resultSchema, options) {
45287
46037
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
45288
- return new Promise((resolve7, reject) => {
46038
+ return new Promise((resolve9, reject) => {
45289
46039
  const earlyReject = (error2) => {
45290
46040
  reject(error2);
45291
46041
  };
@@ -45363,7 +46113,7 @@ var Protocol = class {
45363
46113
  if (!parseResult.success) {
45364
46114
  reject(parseResult.error);
45365
46115
  } else {
45366
- resolve7(parseResult.data);
46116
+ resolve9(parseResult.data);
45367
46117
  }
45368
46118
  } catch (error2) {
45369
46119
  reject(error2);
@@ -45624,12 +46374,12 @@ var Protocol = class {
45624
46374
  }
45625
46375
  } catch {
45626
46376
  }
45627
- return new Promise((resolve7, reject) => {
46377
+ return new Promise((resolve9, reject) => {
45628
46378
  if (signal.aborted) {
45629
46379
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
45630
46380
  return;
45631
46381
  }
45632
- const timeoutId = setTimeout(resolve7, interval);
46382
+ const timeoutId = setTimeout(resolve9, interval);
45633
46383
  signal.addEventListener("abort", () => {
45634
46384
  clearTimeout(timeoutId);
45635
46385
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -47978,7 +48728,7 @@ function skipVoid(str, ptr, banNewLines, banComments) {
47978
48728
  }
47979
48729
  return ptr;
47980
48730
  }
47981
- function skipUntil(str, ptr, sep3, end, banNewLines = false) {
48731
+ function skipUntil(str, ptr, sep4, end, banNewLines = false) {
47982
48732
  if (!end) {
47983
48733
  ptr = indexOfNewline(str, ptr);
47984
48734
  return ptr < 0 ? str.length : ptr;
@@ -47987,7 +48737,7 @@ function skipUntil(str, ptr, sep3, end, banNewLines = false) {
47987
48737
  let c = str[i];
47988
48738
  if (c === "#") {
47989
48739
  i = indexOfNewline(str, i);
47990
- } else if (c === sep3) {
48740
+ } else if (c === sep4) {
47991
48741
  return i + 1;
47992
48742
  } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
47993
48743
  return i;
@@ -48716,7 +49466,7 @@ async function waitForConfigLock(lockPath) {
48716
49466
  if (Date.now() - startedAt >= CONFIG_LOCK_WAIT_MS) {
48717
49467
  throw new Error(`Alan could not safely update ${lockPath.slice(0, -".alan-lock".length)}`);
48718
49468
  }
48719
- await new Promise((resolve7) => setTimeout(resolve7, CONFIG_LOCK_POLL_MS));
49469
+ await new Promise((resolve9) => setTimeout(resolve9, CONFIG_LOCK_POLL_MS));
48720
49470
  }
48721
49471
  }
48722
49472
  }
@@ -48740,10 +49490,11 @@ function parseJsonObject2(path, content) {
48740
49490
  );
48741
49491
  }
48742
49492
  function mergeJsonConfig(path, existingContent, desiredContent) {
48743
- if (existingContent !== null) {
48744
- parseJsonObject2(path, existingContent);
49493
+ const normalizedExisting = existingContent?.trim() ? existingContent : null;
49494
+ if (normalizedExisting !== null) {
49495
+ parseJsonObject2(path, normalizedExisting);
48745
49496
  }
48746
- return mergeAlanMcpJsonConfig(existingContent, desiredContent);
49497
+ return mergeAlanMcpJsonConfig(normalizedExisting, desiredContent);
48747
49498
  }
48748
49499
  function assertValidExistingToml(path, content) {
48749
49500
  try {
@@ -49031,6 +49782,10 @@ function readAlanMcpRegistration(path) {
49031
49782
  const url4 = normalizeHttpUrl(server.httpUrl);
49032
49783
  return url4 ? { url: url4, headers } : null;
49033
49784
  }
49785
+ if (path.endsWith("/.gemini/config/mcp_config.json")) {
49786
+ const url4 = normalizeHttpUrl(server.serverUrl);
49787
+ return url4 ? { url: url4, headers } : null;
49788
+ }
49034
49789
  const url3 = server.type === "http" ? normalizeHttpUrl(server.url) : null;
49035
49790
  return url3 ? { url: url3, headers } : null;
49036
49791
  } catch {
@@ -49089,7 +49844,7 @@ function failureFromError(error2, paths) {
49089
49844
  };
49090
49845
  }
49091
49846
  async function waitBeforeRetry() {
49092
- await new Promise((resolve7) => setTimeout(resolve7, RETRY_DELAY_MS2));
49847
+ await new Promise((resolve9) => setTimeout(resolve9, RETRY_DELAY_MS2));
49093
49848
  }
49094
49849
  async function probeAlanMcpReadiness(registration, options = {}) {
49095
49850
  const paths = options.paths ?? [];
@@ -49630,11 +50385,25 @@ function parseOpenCodeVerboseModelOutput(text) {
49630
50385
  }
49631
50386
  return entries;
49632
50387
  }
50388
+ function extractOpenCodeModelCapabilitiesFromVerboseOutput(text) {
50389
+ return parseOpenCodeVerboseModelOutput(text).filter((entry) => entry.id.startsWith("opencode/")).map((entry) => ({
50390
+ id: entry.id,
50391
+ variants: entry.reasoning ? entry.variants.filter((variant) => {
50392
+ const trimmed = variant.trim();
50393
+ return Boolean(trimmed) && trimmed.length <= 256 && !Array.from(trimmed).some((character) => {
50394
+ const code = character.charCodeAt(0);
50395
+ return code <= 31 || code === 127;
50396
+ });
50397
+ }) : []
50398
+ }));
50399
+ }
49633
50400
  function extractOpenCodeDiscoveredModelIdsFromVerboseOutput(text) {
49634
- const entries = parseOpenCodeVerboseModelOutput(text);
50401
+ const entries = extractOpenCodeModelCapabilitiesFromVerboseOutput(text);
49635
50402
  const ids = [];
49636
50403
  for (const entry of entries) {
49637
- const knownVariants = entry.reasoning ? entry.variants.filter((variant) => OPENCODE_KNOWN_VARIANT_KEYS.has(variant)) : [];
50404
+ const knownVariants = entry.variants.filter(
50405
+ (variant) => OPENCODE_KNOWN_VARIANT_KEYS.has(variant)
50406
+ );
49638
50407
  if (knownVariants.length === 0) {
49639
50408
  ids.push(entry.id);
49640
50409
  continue;
@@ -49720,7 +50489,8 @@ function extractClaudeModelIdsFromExecutable(executable) {
49720
50489
  }
49721
50490
  }
49722
50491
  function getCatalogModelIds(provider) {
49723
- return [...CATALOG_MODEL_IDS_BY_PROVIDER[provider] ?? []];
50492
+ const catalogProvider = provider === "opencode_serve" ? "opencode_cli" : provider;
50493
+ return [...CATALOG_MODEL_IDS_BY_PROVIDER[catalogProvider] ?? []];
49724
50494
  }
49725
50495
  function withModelProbeEnv(env) {
49726
50496
  const term = env.TERM;
@@ -49810,14 +50580,14 @@ async function discoverGenericModels(executable, env) {
49810
50580
  }
49811
50581
  var CATALOG_ONLY_PROVIDERS = /* @__PURE__ */ new Set(["supatest_cli", "droid_cli", "copilot_cli"]);
49812
50582
  function supportsProviderModelDiscovery(provider) {
49813
- return provider in CATALOG_MODEL_IDS_BY_PROVIDER;
50583
+ return provider === "opencode_serve" || provider in CATALOG_MODEL_IDS_BY_PROVIDER;
49814
50584
  }
49815
50585
  async function discoverProviderModels(provider, executable, env) {
49816
50586
  if (CATALOG_ONLY_PROVIDERS.has(provider)) {
49817
50587
  return getCatalogModelIds(provider);
49818
50588
  }
49819
50589
  let probed = [];
49820
- if (provider === "opencode_cli") {
50590
+ if (provider === "opencode_cli" || provider === "opencode_serve") {
49821
50591
  probed = await discoverOpenCodeModels(executable, env);
49822
50592
  } else if (provider === "antigravity_cli") {
49823
50593
  probed = await discoverAntigravityModels(executable, env);
@@ -50003,8 +50773,8 @@ var RunStartGate = class {
50003
50773
  async acquire() {
50004
50774
  const previous = this.tail;
50005
50775
  let releaseCurrent;
50006
- const current = new Promise((resolve7) => {
50007
- releaseCurrent = resolve7;
50776
+ const current = new Promise((resolve9) => {
50777
+ releaseCurrent = resolve9;
50008
50778
  });
50009
50779
  this.tail = previous.then(() => current);
50010
50780
  await previous;
@@ -50331,7 +51101,7 @@ var SuspensionDetector = class {
50331
51101
  };
50332
51102
 
50333
51103
  // src/version.ts
50334
- var AGENT_VERSION = "0.1.53";
51104
+ var AGENT_VERSION = "0.1.54";
50335
51105
 
50336
51106
  // src/workspace-relocation.ts
50337
51107
  var import_node_child_process6 = require("child_process");
@@ -52037,11 +52807,10 @@ function getLocalApiPort(args, stored) {
52037
52807
  }
52038
52808
  function sleep(ms) {
52039
52809
  if (ms <= 0) return Promise.resolve();
52040
- return new Promise((resolve7) => setTimeout(resolve7, ms));
52810
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
52041
52811
  }
52042
52812
  function normalizeBackendKind2(backendKind) {
52043
52813
  if (backendKind === "codex") return "codex_app_server";
52044
- if (backendKind === "gemini" || backendKind === "gemini_cli") return "antigravity_cli";
52045
52814
  return backendKind;
52046
52815
  }
52047
52816
  function providerModelCacheKey(provider, executable) {
@@ -52776,7 +53545,7 @@ async function setupDaemon(args) {
52776
53545
  }
52777
53546
  const retriableStatus = response && (response.status === 408 || response.status === 429 || response.status >= 500);
52778
53547
  if (response && (!retriableStatus || response.ok) || attempt === 3) break;
52779
- await new Promise((resolve7) => setTimeout(resolve7, attempt * 100));
53548
+ await new Promise((resolve9) => setTimeout(resolve9, attempt * 100));
52780
53549
  }
52781
53550
  if (!response) {
52782
53551
  const detail = transportError instanceof Error ? transportError.message : String(transportError);
@@ -53145,7 +53914,11 @@ async function startDaemon(args) {
53145
53914
  try {
53146
53915
  response = await fetch(`${stored.apiUrl}/public/runtimes/${runtimeId}/tokens/renew`, {
53147
53916
  method: "POST",
53148
- headers: { authorization: `Bearer ${runtimeRenewalToken}` },
53917
+ headers: {
53918
+ authorization: `Bearer ${runtimeRenewalToken}`,
53919
+ "content-type": "application/json"
53920
+ },
53921
+ body: "{}",
53149
53922
  signal: AbortSignal.timeout(1e4)
53150
53923
  });
53151
53924
  transportError = null;
@@ -54297,7 +55070,7 @@ async function startDaemon(args) {
54297
55070
  `${describeOccupiedLocalDaemon(localApiPort)} The token in ${getConfigPath()} no longer matches the running daemon; quit Alan desktop or run setup again.`
54298
55071
  );
54299
55072
  }
54300
- const localApiListening = new Promise((resolve7, reject) => {
55073
+ const localApiListening = new Promise((resolve9, reject) => {
54301
55074
  const onError = (error2) => {
54302
55075
  clearInterval(heartbeat);
54303
55076
  clearInterval(versionRefresh);
@@ -54327,7 +55100,7 @@ async function startDaemon(args) {
54327
55100
  if (address && typeof address === "object") localApiPort = address.port;
54328
55101
  pushLog(`local_api listening port=${localApiPort}`);
54329
55102
  console.info("[alan-agent] Local daemon API listening", { port: localApiPort });
54330
- resolve7();
55103
+ resolve9();
54331
55104
  });
54332
55105
  });
54333
55106
  try {
@@ -54347,7 +55120,7 @@ async function startDaemon(args) {
54347
55120
  clearInterval(workspaceLeaseMonitor);
54348
55121
  suspensionDetector.stop();
54349
55122
  socket.disconnect();
54350
- await new Promise((resolve7) => localServer.close(() => resolve7()));
55123
+ await new Promise((resolve9) => localServer.close(() => resolve9()));
54351
55124
  releaseOwnerLease();
54352
55125
  releaseStartupLease();
54353
55126
  throw error2;
@@ -54367,8 +55140,8 @@ async function startDaemon(args) {
54367
55140
  }
54368
55141
  activeAgents.clear();
54369
55142
  socket.disconnect();
54370
- await new Promise((resolve7) => {
54371
- localServer.close(() => resolve7());
55143
+ await new Promise((resolve9) => {
55144
+ localServer.close(() => resolve9());
54372
55145
  });
54373
55146
  } finally {
54374
55147
  sleepInhibitor.dispose();
@@ -55313,9 +56086,9 @@ var WSClient = class {
55313
56086
  });
55314
56087
  }
55315
56088
  waitForConnection(timeoutMs = 15e3) {
55316
- return new Promise((resolve7, reject) => {
56089
+ return new Promise((resolve9, reject) => {
55317
56090
  if (this.socket.connected) {
55318
- resolve7();
56091
+ resolve9();
55319
56092
  return;
55320
56093
  }
55321
56094
  const timeout = setTimeout(
@@ -55324,7 +56097,7 @@ var WSClient = class {
55324
56097
  );
55325
56098
  this.socket.once("connect", () => {
55326
56099
  clearTimeout(timeout);
55327
- resolve7();
56100
+ resolve9();
55328
56101
  });
55329
56102
  this.socket.once("connect_error", (err) => {
55330
56103
  clearTimeout(timeout);
@@ -55506,9 +56279,9 @@ async function runSandbox(config2) {
55506
56279
  onUserMessage: (payload) => {
55507
56280
  if (payload === null) {
55508
56281
  if (pendingMessageResolve) {
55509
- const resolve7 = pendingMessageResolve;
56282
+ const resolve9 = pendingMessageResolve;
55510
56283
  pendingMessageResolve = null;
55511
- resolve7(null);
56284
+ resolve9(null);
55512
56285
  }
55513
56286
  return;
55514
56287
  }
@@ -55530,9 +56303,9 @@ async function runSandbox(config2) {
55530
56303
  fileCount: payload.files?.length ?? 0
55531
56304
  });
55532
56305
  if (pendingMessageResolve) {
55533
- const resolve7 = pendingMessageResolve;
56306
+ const resolve9 = pendingMessageResolve;
55534
56307
  pendingMessageResolve = null;
55535
- resolve7(payload);
56308
+ resolve9(payload);
55536
56309
  } else {
55537
56310
  queuedMessages.push(payload);
55538
56311
  }
@@ -55751,8 +56524,8 @@ async function runSandbox(config2) {
55751
56524
  });
55752
56525
  if (stopped) break;
55753
56526
  }
55754
- const nextPayload = queuedMessages.shift() ?? await new Promise((resolve7) => {
55755
- pendingMessageResolve = resolve7;
56527
+ const nextPayload = queuedMessages.shift() ?? await new Promise((resolve9) => {
56528
+ pendingMessageResolve = resolve9;
55756
56529
  });
55757
56530
  if (nextPayload === null || stopped) {
55758
56531
  break;