@ycodium-ai/agent-grok 0.2.3598 → 0.2.3614

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -77,7 +77,9 @@ var GROK_CARD = {
77
77
  nativeModeSwitch: true,
78
78
  // 压缩走 CLI 宣告过的 `/compact` 命令(见 `compactContext`),进度与结果由执行器按
79
79
  // 压缩生命周期事件报;CLI 没宣告这条命令时 `compactContext` 拒绝,不退回发文本。
80
- contextCompaction: "native"
80
+ contextCompaction: "native",
81
+ // 子 agent 经父会话上的 subagent_* 通知报成 task.*(grokSubagents.ts)。
82
+ reportsSpawnedAgents: true
81
83
  },
82
84
  // 凭据由 CLI 自己保管在 `<GROK_HOME>/auth.json`,宿主读它只认 `/token`。
83
85
  credentialSources: [
@@ -204,13 +206,13 @@ function createApprovalGate(input2) {
204
206
  };
205
207
  const settleAll = (outcome) => {
206
208
  const entries = list();
207
- const settled = [];
209
+ const settled2 = [];
208
210
  for (const entry of entries) {
209
211
  if (settle2(entry, outcome)) {
210
- settled.push(entry);
212
+ settled2.push(entry);
211
213
  }
212
214
  }
213
- return settled;
215
+ return settled2;
214
216
  };
215
217
  return {
216
218
  add,
@@ -651,13 +653,14 @@ function extractToolCallCommand(rawInput, title) {
651
653
  }
652
654
  var TOOL_CALL_CONTENT_MAX_CHARS = 8e3;
653
655
  var TOOL_CALL_CONTENT_TRUNCATION_MARKER = "[Earlier output truncated]\n\n";
654
- function boundToolCallOutputText(text3) {
655
- if (text3.length <= TOOL_CALL_CONTENT_MAX_CHARS) {
656
- return text3;
656
+ function boundTailText(text4, limit = TOOL_CALL_CONTENT_MAX_CHARS) {
657
+ if (text4.length <= limit) {
658
+ return text4;
657
659
  }
658
- const tail = text3.slice(text3.length - TOOL_CALL_CONTENT_MAX_CHARS);
660
+ const tail = text4.slice(text4.length - limit);
659
661
  return `${TOOL_CALL_CONTENT_TRUNCATION_MARKER}${tail}`;
660
662
  }
663
+ var boundToolCallOutputText = (text4) => boundTailText(text4);
661
664
  var RAW_OUTPUT_TEXT_FIELDS = ["content", "stdout", "stderr", "output"];
662
665
  function boundToolCallRawOutput(rawOutput) {
663
666
  if (!isRecord(rawOutput)) {
@@ -687,9 +690,9 @@ function extractTextContentFromToolCallContent(content) {
687
690
  const typed = content;
688
691
  const chunks = [];
689
692
  for (const entry of typed) {
690
- const text3 = toolCallContentText(entry)?.trim();
691
- if (text3) {
692
- chunks.push(text3);
693
+ const text4 = toolCallContentText(entry)?.trim();
694
+ if (text4) {
695
+ chunks.push(text4);
693
696
  }
694
697
  }
695
698
  if (chunks.length === 0) {
@@ -769,6 +772,7 @@ function makeToolCallState(input2, options) {
769
772
  ...status ? { status } : {},
770
773
  ...command ? { command } : {},
771
774
  ...presentation?.detail ? { detail: presentation.detail } : {},
775
+ ...textContent ? { contentText: textContent } : {},
772
776
  data
773
777
  };
774
778
  }
@@ -779,6 +783,7 @@ function mergeToolCallState(previous, next) {
779
783
  const status = next.status ?? previous?.status;
780
784
  const command = next.command ?? previous?.command;
781
785
  const detail = next.detail ?? previous?.detail;
786
+ const contentText = "content" in next.data ? next.contentText : previous?.contentText;
782
787
  return {
783
788
  toolCallId: next.toolCallId,
784
789
  ...kind ? { kind } : {},
@@ -786,6 +791,7 @@ function mergeToolCallState(previous, next) {
786
791
  ...status ? { status } : {},
787
792
  ...command ? { command } : {},
788
793
  ...detail ? { detail } : {},
794
+ ...contentText ? { contentText } : {},
789
795
  data: {
790
796
  ...previous?.data,
791
797
  ...next.data
@@ -1063,11 +1069,11 @@ function parseSessionUpdateEvent(params) {
1063
1069
  const contentType = content?.["type"];
1064
1070
  const streamKind = kind === "agent_thought_chunk" ? "reasoning_text" : "assistant_text";
1065
1071
  if (contentType === "text") {
1066
- const text3 = typeof content?.["text"] === "string" ? content["text"] : "";
1067
- if (text3.length > 0) {
1072
+ const text4 = typeof content?.["text"] === "string" ? content["text"] : "";
1073
+ if (text4.length > 0) {
1068
1074
  events.push({
1069
1075
  _tag: "ContentDelta",
1070
- text: text3,
1076
+ text: text4,
1071
1077
  streamKind,
1072
1078
  rawPayload: params
1073
1079
  });
@@ -1100,9 +1106,9 @@ function parseSessionUpdateEvent(params) {
1100
1106
  case "compaction_summary_chunk": {
1101
1107
  const compactionId = readAcpText(upd, "compactionId");
1102
1108
  const content = isRecord(upd["content"]) ? upd["content"] : void 0;
1103
- const text3 = content?.["type"] === "text" ? content["text"] : void 0;
1104
- if (compactionId === void 0 || typeof text3 !== "string" || text3.length === 0) break;
1105
- events.push({ _tag: "CompactionSummaryChunk", compactionId, text: text3 });
1109
+ const text4 = content?.["type"] === "text" ? content["text"] : void 0;
1110
+ if (compactionId === void 0 || typeof text4 !== "string" || text4.length === 0) break;
1111
+ events.push({ _tag: "CompactionSummaryChunk", compactionId, text: text4 });
1106
1112
  break;
1107
1113
  }
1108
1114
  default:
@@ -1332,6 +1338,54 @@ function retainToolCallUpdate(toolCalls, next, seen) {
1332
1338
  return { nextToolCall, decision };
1333
1339
  }
1334
1340
 
1341
+ // ../../packages/ycodium-acp-executor/src/executor/child-sessions.ts
1342
+ var CHILD_LIMIT = 256;
1343
+ var active = (status) => status === "running" || status === "waiting";
1344
+ function createChildSessionRegistry(limit = CHILD_LIMIT) {
1345
+ const records = /* @__PURE__ */ new Map();
1346
+ const evictOne = (keep) => {
1347
+ const protectedIds = /* @__PURE__ */ new Set();
1348
+ for (const [id, record4] of records) {
1349
+ if (!active(record4.observed)) continue;
1350
+ protectedIds.add(id);
1351
+ let parent = record4.parentAgentId;
1352
+ while (parent !== void 0 && !protectedIds.has(parent)) {
1353
+ protectedIds.add(parent);
1354
+ parent = records.get(parent)?.parentAgentId;
1355
+ }
1356
+ }
1357
+ for (const id of records.keys()) {
1358
+ if (id === keep || protectedIds.has(id)) continue;
1359
+ records.delete(id);
1360
+ return;
1361
+ }
1362
+ };
1363
+ const add = (sessionId, record4) => {
1364
+ records.set(sessionId, record4);
1365
+ if (records.size > limit) evictOne(sessionId);
1366
+ };
1367
+ return {
1368
+ has: (sessionId) => records.has(sessionId),
1369
+ get: (sessionId) => records.get(sessionId),
1370
+ mark: (sessionId) => {
1371
+ if (records.has(sessionId)) return;
1372
+ add(sessionId, {
1373
+ turnId: void 0,
1374
+ title: void 0,
1375
+ description: void 0,
1376
+ parentAgentId: void 0,
1377
+ observed: void 0,
1378
+ reported: void 0,
1379
+ reportedError: void 0,
1380
+ announced: false,
1381
+ pendingMetadata: false
1382
+ });
1383
+ },
1384
+ add,
1385
+ entries: () => records.entries()
1386
+ };
1387
+ }
1388
+
1335
1389
  // ../../node_modules/.pnpm/@agentclientprotocol+sdk@1.4.0_zod@4.6.5/node_modules/@agentclientprotocol/sdk/dist/schema/index.js
1336
1390
  var AGENT_METHODS = {
1337
1391
  initialize: "initialize",
@@ -2598,14 +2652,14 @@ function codePointLength(str) {
2598
2652
  const units = str.length;
2599
2653
  if (!highSurrogate.test(str))
2600
2654
  return units;
2601
- let count2 = units;
2655
+ let count3 = units;
2602
2656
  for (let i = 0; i < units - 1; i++) {
2603
2657
  if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
2604
- count2--;
2658
+ count3--;
2605
2659
  i++;
2606
2660
  }
2607
2661
  }
2608
- return count2;
2662
+ return count3;
2609
2663
  }
2610
2664
  function getLengthableOrigin(input2) {
2611
2665
  if (Array.isArray(input2))
@@ -6960,8 +7014,8 @@ function az_default() {
6960
7014
  }
6961
7015
 
6962
7016
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/be.js
6963
- function getBelarusianPlural(count2, one, few, many) {
6964
- const absCount = Math.abs(count2);
7017
+ function getBelarusianPlural(count3, one, few, many) {
7018
+ const absCount = Math.abs(count3);
6965
7019
  const lastDigit = absCount % 10;
6966
7020
  const lastTwoDigits = absCount % 100;
6967
7021
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -9608,8 +9662,8 @@ function hu_default() {
9608
9662
  }
9609
9663
 
9610
9664
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hy.js
9611
- function getArmenianPlural(count2, one, many) {
9612
- return Math.abs(count2) === 1 ? one : many;
9665
+ function getArmenianPlural(count3, one, many) {
9666
+ return Math.abs(count3) === 1 ? one : many;
9613
9667
  }
9614
9668
  function withDefiniteArticle(word) {
9615
9669
  if (!word)
@@ -10693,8 +10747,8 @@ function ko_default() {
10693
10747
  }
10694
10748
 
10695
10749
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/lt.js
10696
- var capitalizeFirstCharacter = (text3) => {
10697
- return text3.charAt(0).toUpperCase() + text3.slice(1);
10750
+ var capitalizeFirstCharacter = (text4) => {
10751
+ return text4.charAt(0).toUpperCase() + text4.slice(1);
10698
10752
  };
10699
10753
  function getUnitTypeFromNumber(number4) {
10700
10754
  const abs = Math.abs(number4);
@@ -12347,8 +12401,8 @@ function ro_default() {
12347
12401
  }
12348
12402
 
12349
12403
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ru.js
12350
- function getRussianPlural(count2, one, few, many) {
12351
- const absCount = Math.abs(count2);
12404
+ function getRussianPlural(count3, one, few, many) {
12405
+ const absCount = Math.abs(count3);
12352
12406
  const lastDigit = absCount % 10;
12353
12407
  const lastTwoDigits = absCount % 100;
12354
12408
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -17988,8 +18042,8 @@ function rewriteKeyNames(ctx) {
17988
18042
  bySchema.set(entry.schema, entry);
17989
18043
  }
17990
18044
  const rewrites = /* @__PURE__ */ new Map();
17991
- for (const record3 of pendingRecords.get(ctx) ?? []) {
17992
- const seen = ctx.seen.get(record3);
18045
+ for (const record4 of pendingRecords.get(ctx) ?? []) {
18046
+ const seen = ctx.seen.get(record4);
17993
18047
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
17994
18048
  if (!names || names === true || rewrites.has(names))
17995
18049
  continue;
@@ -23289,9 +23343,9 @@ var Connection = class {
23289
23343
  return;
23290
23344
  }
23291
23345
  const responseBatch = isResponseBatch(batch);
23292
- const responseCount = responseBatch ? 0 : batch.reduce((count2, message) => count2 + (isNotificationMessage(message) ? 0 : 1), 0);
23346
+ const responseCount = responseBatch ? 0 : batch.reduce((count3, message) => count3 + (isNotificationMessage(message) ? 0 : 1), 0);
23293
23347
  let remaining = responseCount;
23294
- let remainingNotifications = batch.reduce((count2, message) => count2 + (isNotificationMessage(message) ? 1 : 0), 0);
23348
+ let remainingNotifications = batch.reduce((count3, message) => count3 + (isNotificationMessage(message) ? 1 : 0), 0);
23295
23349
  let responseSent = false;
23296
23350
  const responses = [];
23297
23351
  const sendResponsesIfReady = async () => {
@@ -25054,8 +25108,8 @@ function createAcpConnection(options) {
25054
25108
  }
25055
25109
  await dispatchMessage(value);
25056
25110
  };
25057
- const pullEnqueued = async (count2) => {
25058
- for (let i = 0; i < count2; i += 1) {
25111
+ const pullEnqueued = async (count3) => {
25112
+ for (let i = 0; i < count3; i += 1) {
25059
25113
  const { value, done } = await incoming.read();
25060
25114
  if (done || value === void 0) {
25061
25115
  return;
@@ -25314,7 +25368,9 @@ function createExecutorLifecycle({
25314
25368
  eventStream,
25315
25369
  onInputDead,
25316
25370
  shared,
25317
- promptResults
25371
+ promptResults,
25372
+ settleToolSubagents,
25373
+ settleSessionEnded
25318
25374
  }) {
25319
25375
  const cancel = async (turnId) => {
25320
25376
  failIfDisposed();
@@ -25334,8 +25390,8 @@ function createExecutorLifecycle({
25334
25390
  await promptResults.wait(targetTurnId);
25335
25391
  if (targetTurnId !== void 0 && shared.activeTurnId !== targetTurnId && !interruptedTurnIds.has(targetTurnId))
25336
25392
  return;
25337
- const settled = await waitForPromptIdle(cancelGraceMs);
25338
- if (!settled) {
25393
+ const settled2 = await waitForPromptIdle(cancelGraceMs);
25394
+ if (!settled2) {
25339
25395
  throw new AcpExecutorCancelTimeoutError();
25340
25396
  }
25341
25397
  if (targetTurnId !== void 0 && isLive(started.generation)) {
@@ -25345,6 +25401,7 @@ function createExecutorLifecycle({
25345
25401
  shared.promptsInFlight = 0;
25346
25402
  shared.activeTurnId = void 0;
25347
25403
  shared.status = "ready";
25404
+ settleToolSubagents("turn-interrupted", targetTurnId);
25348
25405
  emit({
25349
25406
  type: "turn.completed",
25350
25407
  ...stamp(),
@@ -25378,7 +25435,7 @@ function createExecutorLifecycle({
25378
25435
  "Cannot compact while a turn or another compaction is running"
25379
25436
  );
25380
25437
  }
25381
- const record3 = {
25438
+ const record4 = {
25382
25439
  snapshotId: randomId(),
25383
25440
  trigger: "manual",
25384
25441
  startedAtMs: nowMs(),
@@ -25388,7 +25445,7 @@ function createExecutorLifecycle({
25388
25445
  adopted: false
25389
25446
  };
25390
25447
  await promptMutex.acquire();
25391
- shared.manualCompaction = record3;
25448
+ shared.manualCompaction = record4;
25392
25449
  const emitSessionState = (state) => {
25393
25450
  emit({
25394
25451
  type: "session.state.changed",
@@ -25401,7 +25458,7 @@ function createExecutorLifecycle({
25401
25458
  try {
25402
25459
  failIfDisposed();
25403
25460
  emitSessionState("compacting");
25404
- emitCompactionState(record3, "compacting");
25461
+ emitCompactionState(record4, "compacting");
25405
25462
  let response;
25406
25463
  try {
25407
25464
  response = await sendPromptRpc(started.sessionId, [
@@ -25415,13 +25472,13 @@ function createExecutorLifecycle({
25415
25472
  if (response.stopReason === "cancelled") {
25416
25473
  return;
25417
25474
  }
25418
- if (!record3.finished) {
25419
- record3.finished = true;
25420
- emitCompactionState(record3, "compacted");
25475
+ if (!record4.finished) {
25476
+ record4.finished = true;
25477
+ emitCompactionState(record4, "compacted");
25421
25478
  }
25422
25479
  } finally {
25423
25480
  for (const [agentId, tracked] of compactions) {
25424
- if (tracked === record3) compactions.delete(agentId);
25481
+ if (tracked === record4) compactions.delete(agentId);
25425
25482
  }
25426
25483
  shared.manualCompaction = void 0;
25427
25484
  promptMutex.release();
@@ -25456,6 +25513,7 @@ function createExecutorLifecycle({
25456
25513
  shared.abortLocalPrompt?.();
25457
25514
  promptResults.finishUnreceived();
25458
25515
  await promptResults.wait();
25516
+ settleSessionEnded();
25459
25517
  emit({
25460
25518
  type: "session.exited",
25461
25519
  ...stamp(),
@@ -25508,10 +25566,10 @@ function selectAutoApprovedAcpPermissionOption(request) {
25508
25566
  }
25509
25567
  function parseAcpResumeCursor(raw, schemaVersion) {
25510
25568
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
25511
- const record3 = raw;
25512
- if (record3["schemaVersion"] !== schemaVersion) return void 0;
25513
- if (typeof record3["sessionId"] !== "string" || !record3["sessionId"].trim()) return void 0;
25514
- return { sessionId: record3["sessionId"].trim() };
25569
+ const record4 = raw;
25570
+ if (record4["schemaVersion"] !== schemaVersion) return void 0;
25571
+ if (typeof record4["sessionId"] !== "string" || !record4["sessionId"].trim()) return void 0;
25572
+ return { sessionId: record4["sessionId"].trim() };
25515
25573
  }
25516
25574
  function acpPromptSettlementBelongsToContext(input2) {
25517
25575
  return input2.liveAcpSessionId === input2.expectedAcpSessionId && (input2.liveActiveTurnId === input2.turnId || input2.liveSessionActiveTurnId === input2.turnId);
@@ -25520,18 +25578,18 @@ function isAcpRequestPermissionParams(value) {
25520
25578
  if (typeof value !== "object" || value === null) {
25521
25579
  return false;
25522
25580
  }
25523
- const record3 = value;
25524
- if (typeof record3["sessionId"] !== "string") {
25581
+ const record4 = value;
25582
+ if (typeof record4["sessionId"] !== "string") {
25525
25583
  return false;
25526
25584
  }
25527
- const toolCall = record3["toolCall"];
25585
+ const toolCall = record4["toolCall"];
25528
25586
  if (typeof toolCall !== "object" || toolCall === null) {
25529
25587
  return false;
25530
25588
  }
25531
25589
  if (typeof toolCall["toolCallId"] !== "string") {
25532
25590
  return false;
25533
25591
  }
25534
- return Array.isArray(record3["options"]);
25592
+ return Array.isArray(record4["options"]);
25535
25593
  }
25536
25594
 
25537
25595
  // ../../packages/ycodium-acp-executor/src/failureCategory.ts
@@ -25559,6 +25617,304 @@ var acpPromptFailureCategory = (error62, input2) => {
25559
25617
  return error62 instanceof AcpConnectionClosedError ? acpTransportIfEstablished(input2.sessionEstablished, input2.disposed) : void 0;
25560
25618
  };
25561
25619
 
25620
+ // ../../packages/ycodium-acp-executor/src/tool-subagents.ts
25621
+ var EXCLUDED = /* @__PURE__ */ Symbol("excluded");
25622
+ var sealedHidden = (entry) => ({
25623
+ sealed: true,
25624
+ keepToolRow: false,
25625
+ turnId: entry.turnId,
25626
+ kind: entry.kind,
25627
+ taskId: entry.taskId,
25628
+ facts: entry.facts
25629
+ });
25630
+ function toolSubagentSettlementOfTurn(state, failureCategory) {
25631
+ if (state === "cancelled") return "turn-interrupted";
25632
+ return state === "failed" && failureCategory === "transport" ? "session-ended" : "turn-ended";
25633
+ }
25634
+ var sameFacts = (a, b) => a.title === b.title && a.description === b.description && a.summary === b.summary && a.role === b.role && a.model === b.model && a.effort === b.effort && a.rosterKind === b.rosterKind;
25635
+ function linkage(taskId, toolCallId, facts) {
25636
+ return {
25637
+ taskId,
25638
+ taskType: "subagent",
25639
+ toolUseId: toolCallId,
25640
+ title: facts.title,
25641
+ ...facts.role === void 0 ? {} : { role: facts.role },
25642
+ ...facts.model === void 0 ? {} : { model: facts.model },
25643
+ ...facts.effort === void 0 ? {} : { effort: facts.effort },
25644
+ ...facts.rosterKind === void 0 ? {} : { rosterKind: facts.rosterKind }
25645
+ };
25646
+ }
25647
+ var isEntry = (value) => value !== EXCLUDED && !("sealed" in value);
25648
+ function createToolSubagentTracker(spec) {
25649
+ const calls = /* @__PURE__ */ new Map();
25650
+ const agentTasks = /* @__PURE__ */ new Map();
25651
+ const rememberAgent = (ref, taskId, facts) => {
25652
+ agentTasks.set(ref, { taskId, facts });
25653
+ };
25654
+ const turnOf = (turnId) => turnId === void 0 ? {} : { turnId };
25655
+ const onToolCallUpdated = (call) => {
25656
+ const tracked = calls.get(call.toolCallId);
25657
+ if (tracked === EXCLUDED) return void 0;
25658
+ if (tracked !== void 0 && !isEntry(tracked)) {
25659
+ const late = spec.resolve?.(call, tracked.kind, { known: true, background: false });
25660
+ if (late !== void 0 && late.type !== "hold" && late.agentRef !== void 0) {
25661
+ rememberAgent(late.agentRef, tracked.taskId, tracked.facts);
25662
+ }
25663
+ const repeatedTerminal = call.status === "completed" || call.status === "failed";
25664
+ const events2 = [];
25665
+ const final = tracked.final;
25666
+ if (repeatedTerminal && final !== void 0 && final.summary === void 0 && late?.type === "final" && late.status === final.status && late.summary !== void 0) {
25667
+ final.summary = late.summary;
25668
+ events2.push({
25669
+ type: "task.completed",
25670
+ ...turnOf(tracked.turnId),
25671
+ payload: {
25672
+ ...linkage(tracked.taskId, call.toolCallId, tracked.facts),
25673
+ status: final.status,
25674
+ summary: late.summary
25675
+ }
25676
+ });
25677
+ }
25678
+ return {
25679
+ events: events2,
25680
+ handled: !tracked.keepToolRow || repeatedTerminal,
25681
+ ...turnOf(tracked.turnId)
25682
+ };
25683
+ }
25684
+ let known = tracked;
25685
+ let kind;
25686
+ if (known === void 0) {
25687
+ const recognized = spec.recognize(call);
25688
+ if (recognized === void 0) return void 0;
25689
+ if (recognized === "exclude") {
25690
+ calls.set(call.toolCallId, EXCLUDED);
25691
+ return void 0;
25692
+ }
25693
+ kind = recognized;
25694
+ } else {
25695
+ kind = known.kind;
25696
+ }
25697
+ const resolution = spec.resolve?.(call, kind, {
25698
+ known: known?.announced === true,
25699
+ background: known?.background ?? false
25700
+ });
25701
+ if (known?.phase === "idle" && resolution?.type !== "final") {
25702
+ if (resolution?.type === "background" && resolution.agentRef !== void 0) {
25703
+ rememberAgent(resolution.agentRef, known.taskId, known.facts);
25704
+ }
25705
+ return { events: [], handled: true };
25706
+ }
25707
+ let carriedTurn;
25708
+ if (known === void 0 || !known.announced) {
25709
+ if (resolution === void 0 && !(spec.ready?.(call, kind) ?? true)) {
25710
+ if (known === void 0) {
25711
+ calls.set(call.toolCallId, {
25712
+ kind,
25713
+ taskId: call.toolCallId,
25714
+ turnId: call.turnId,
25715
+ facts: spec.facts(call, kind, void 0),
25716
+ phase: "open",
25717
+ status: void 0,
25718
+ background: false,
25719
+ announced: false
25720
+ });
25721
+ }
25722
+ return { events: [], handled: true };
25723
+ }
25724
+ carriedTurn = known?.turnId;
25725
+ calls.delete(call.toolCallId);
25726
+ known = void 0;
25727
+ }
25728
+ const events = [];
25729
+ const ref = known === void 0 ? spec.resumes?.(call, kind) : void 0;
25730
+ const prior = ref === void 0 ? void 0 : agentTasks.get(ref);
25731
+ const facts = spec.facts(call, kind, prior?.facts ?? known?.facts);
25732
+ const turnId = known?.turnId ?? carriedTurn ?? call.turnId;
25733
+ const turn = turnOf(turnId);
25734
+ let entry;
25735
+ if (known !== void 0) {
25736
+ entry = known;
25737
+ } else if (prior !== void 0) {
25738
+ for (const [id, other] of calls) {
25739
+ if (other === EXCLUDED || other.taskId !== prior.taskId) continue;
25740
+ if (isEntry(other)) calls.set(id, sealedHidden(other));
25741
+ else if (other.final !== void 0) {
25742
+ const { final: _superseded, ...rest } = other;
25743
+ calls.set(id, rest);
25744
+ }
25745
+ }
25746
+ entry = {
25747
+ kind,
25748
+ taskId: prior.taskId,
25749
+ turnId,
25750
+ facts,
25751
+ phase: "open",
25752
+ status: "running",
25753
+ background: false,
25754
+ announced: true
25755
+ };
25756
+ calls.set(call.toolCallId, entry);
25757
+ events.push({
25758
+ type: "task.updated",
25759
+ ...turn,
25760
+ payload: {
25761
+ ...linkage(entry.taskId, call.toolCallId, facts),
25762
+ description: facts.description,
25763
+ status: "running"
25764
+ }
25765
+ });
25766
+ } else {
25767
+ entry = {
25768
+ kind,
25769
+ taskId: call.toolCallId,
25770
+ turnId,
25771
+ facts,
25772
+ phase: "open",
25773
+ status: void 0,
25774
+ background: false,
25775
+ announced: true
25776
+ };
25777
+ calls.set(call.toolCallId, entry);
25778
+ if (spec.announce === "started") {
25779
+ events.push({
25780
+ type: "task.started",
25781
+ ...turn,
25782
+ payload: {
25783
+ ...linkage(entry.taskId, call.toolCallId, facts),
25784
+ description: facts.description
25785
+ }
25786
+ });
25787
+ }
25788
+ }
25789
+ const seen = known !== void 0 || prior !== void 0;
25790
+ const wasStatus = entry.status;
25791
+ entry.turnId = turnId;
25792
+ if (resolution?.type === "hold") {
25793
+ entry.facts = facts;
25794
+ return { events, handled: true };
25795
+ }
25796
+ if (resolution?.type === "background") {
25797
+ entry.facts = resolution.role === void 0 ? facts : { ...facts, role: resolution.role };
25798
+ if (!entry.background) {
25799
+ events.push({
25800
+ type: "task.updated",
25801
+ ...turn,
25802
+ payload: {
25803
+ ...linkage(entry.taskId, call.toolCallId, entry.facts),
25804
+ status: "running",
25805
+ isBackgrounded: true
25806
+ }
25807
+ });
25808
+ }
25809
+ entry.background = true;
25810
+ entry.status = "running";
25811
+ if (resolution.agentRef !== void 0)
25812
+ rememberAgent(resolution.agentRef, entry.taskId, entry.facts);
25813
+ return { events, handled: true };
25814
+ }
25815
+ if (resolution?.type === "final") {
25816
+ const finalFacts = resolution.role === void 0 ? facts : { ...facts, role: resolution.role };
25817
+ const keepToolRow = resolution.keepToolRow === true;
25818
+ const base = linkage(entry.taskId, call.toolCallId, finalFacts);
25819
+ if (resolution.agentRef !== void 0)
25820
+ rememberAgent(resolution.agentRef, entry.taskId, finalFacts);
25821
+ calls.set(call.toolCallId, {
25822
+ sealed: true,
25823
+ keepToolRow,
25824
+ ...keepToolRow && (resolution.status === "completed" || resolution.status === "failed") ? { final: { status: resolution.status, summary: resolution.summary } } : {},
25825
+ turnId,
25826
+ kind,
25827
+ taskId: entry.taskId,
25828
+ facts: finalFacts
25829
+ });
25830
+ if (resolution.status === "completed" || resolution.status === "failed") {
25831
+ events.push({
25832
+ type: "task.completed",
25833
+ ...turn,
25834
+ payload: {
25835
+ ...base,
25836
+ status: resolution.status,
25837
+ ...resolution.summary === void 0 ? {} : { summary: resolution.summary }
25838
+ }
25839
+ });
25840
+ } else {
25841
+ events.push({
25842
+ type: "task.updated",
25843
+ ...turn,
25844
+ payload: {
25845
+ ...base,
25846
+ status: resolution.status,
25847
+ ...resolution.status === "idle" ? { outcomeUnknown: true } : {},
25848
+ ...resolution.description === void 0 ? {} : { description: resolution.description },
25849
+ ...resolution.timelineBypass === true ? { timelineBypass: true } : {}
25850
+ }
25851
+ });
25852
+ }
25853
+ return { events, handled: !keepToolRow, ...turn };
25854
+ }
25855
+ const status = call.status === "pending" && wasStatus !== "running" ? "pending" : "running";
25856
+ const changed = !seen && spec.announce === "progress" ? true : seen && (wasStatus !== status || !sameFacts(entry.facts, facts));
25857
+ entry.facts = facts;
25858
+ entry.status = status;
25859
+ if (changed) {
25860
+ events.push({
25861
+ type: "task.progress",
25862
+ ...turn,
25863
+ payload: {
25864
+ ...linkage(entry.taskId, call.toolCallId, facts),
25865
+ description: facts.description,
25866
+ ...facts.summary === void 0 ? {} : { summary: facts.summary },
25867
+ status
25868
+ }
25869
+ });
25870
+ }
25871
+ return { events, handled: true };
25872
+ };
25873
+ const settle2 = (settlement, turnId) => {
25874
+ const events = [];
25875
+ for (const [toolCallId, entry] of calls) {
25876
+ if (!isEntry(entry)) continue;
25877
+ if (settlement !== "session-ended" && turnId !== void 0 && entry.turnId !== void 0 && entry.turnId !== turnId) {
25878
+ continue;
25879
+ }
25880
+ const interrupted = settlement === "turn-interrupted";
25881
+ const ended = settlement === "session-ended" || interrupted && spec.interruptedMayStillRun !== true;
25882
+ if (!entry.announced) {
25883
+ if (ended) calls.set(toolCallId, sealedHidden(entry));
25884
+ else entry.phase = "idle";
25885
+ continue;
25886
+ }
25887
+ const base = linkage(entry.taskId, toolCallId, entry.facts);
25888
+ const turn = turnOf(entry.turnId);
25889
+ if (ended) {
25890
+ events.push({ type: "task.updated", ...turn, payload: { ...base, status: "cancelled" } });
25891
+ calls.set(toolCallId, sealedHidden(entry));
25892
+ continue;
25893
+ }
25894
+ if (entry.phase === "idle") continue;
25895
+ const note = spec.endNote({ interrupted, background: entry.background });
25896
+ events.push({
25897
+ type: "task.updated",
25898
+ ...turn,
25899
+ payload: {
25900
+ ...base,
25901
+ status: "idle",
25902
+ outcomeUnknown: true,
25903
+ description: note.description,
25904
+ ...note.timelineBypass === true ? { timelineBypass: true } : {}
25905
+ }
25906
+ });
25907
+ entry.phase = "idle";
25908
+ }
25909
+ return events;
25910
+ };
25911
+ const mayStillRun = () => {
25912
+ for (const entry of calls.values()) if (isEntry(entry)) return true;
25913
+ return false;
25914
+ };
25915
+ return { onToolCallUpdated, settle: settle2, mayStillRun };
25916
+ }
25917
+
25562
25918
  // ../../packages/ycodium-acp-executor/src/executor/prompt.ts
25563
25919
  function createExecutorPrompt({
25564
25920
  isLive,
@@ -25578,7 +25934,8 @@ function createExecutorPrompt({
25578
25934
  applyRequestedModel,
25579
25935
  notifyPromptSettled,
25580
25936
  shared,
25581
- promptResults
25937
+ promptResults,
25938
+ settleToolSubagents
25582
25939
  }) {
25583
25940
  const settleTurn = (input2) => {
25584
25941
  if (!isLive(input2.expectedGeneration) || input2.record.finished) {
@@ -25602,6 +25959,10 @@ function createExecutorPrompt({
25602
25959
  shared.status = "ready";
25603
25960
  }
25604
25961
  const interrupted = promptResults.hasInterrupted(input2.turnId);
25962
+ settleToolSubagents(
25963
+ toolSubagentSettlementOfTurn(interrupted ? "cancelled" : input2.state, input2.failureCategory),
25964
+ input2.turnId
25965
+ );
25605
25966
  emit({
25606
25967
  type: "turn.completed",
25607
25968
  ...stamp(),
@@ -25619,7 +25980,7 @@ function createExecutorPrompt({
25619
25980
  promptResults.forget(input2.turnId);
25620
25981
  return true;
25621
25982
  };
25622
- const sendPromptRpc = async (sessionId, promptParts, onWritten, record3) => {
25983
+ const sendPromptRpc = async (sessionId, promptParts, onWritten, record4) => {
25623
25984
  const settlementHooks = hooks.promptSettlement;
25624
25985
  const promptKey = settlementHooks === void 0 ? void 0 : randomId();
25625
25986
  const pending = connection.begin(
@@ -25629,7 +25990,7 @@ function createExecutorPrompt({
25629
25990
  prompt: promptParts,
25630
25991
  ...settlementHooks !== void 0 && promptKey !== void 0 ? settlementHooks.requestFields(promptKey) : {}
25631
25992
  },
25632
- record3?.promptId
25993
+ record4?.promptId
25633
25994
  );
25634
25995
  void pending.written.then(onWritten, () => void 0);
25635
25996
  const promptRpc = pending.response;
@@ -25641,10 +26002,10 @@ function createExecutorPrompt({
25641
26002
  promptKey,
25642
26003
  sessionId,
25643
26004
  settle: settleEarly,
25644
- ...record3 === void 0 ? {} : {
25645
- onResponse: (response) => promptResults.receive(record3.promptId, response),
25646
- onError: () => promptResults.reject(record3.promptId),
25647
- hasResult: () => record3.response !== void 0
26005
+ ...record4 === void 0 ? {} : {
26006
+ onResponse: (response) => promptResults.receive(record4.promptId, response),
26007
+ onError: () => promptResults.reject(record4.promptId),
26008
+ hasResult: () => record4.response !== void 0
25648
26009
  }
25649
26010
  };
25650
26011
  try {
@@ -25672,11 +26033,11 @@ function createExecutorPrompt({
25672
26033
  failIfPromptUnavailable();
25673
26034
  const started = requireStarted();
25674
26035
  let sessionId = started.sessionId;
25675
- let record3;
26036
+ let record4;
25676
26037
  const settle2 = (rest) => settleTurn({
25677
26038
  expectedGeneration: started.generation,
25678
26039
  expectedSessionId: sessionId,
25679
- record: record3,
26040
+ record: record4,
25680
26041
  ...rest
25681
26042
  });
25682
26043
  let turnId;
@@ -25689,7 +26050,7 @@ function createExecutorPrompt({
25689
26050
  randomId
25690
26051
  );
25691
26052
  shared.promptsInFlight += 1;
25692
- record3 = promptResults.add(
26053
+ record4 = promptResults.add(
25693
26054
  {
25694
26055
  promptId: randomId(),
25695
26056
  sessionId: started.sessionId,
@@ -25718,9 +26079,9 @@ function createExecutorPrompt({
25718
26079
  const promptParts = input2.prompt ?? (input2.text !== void 0 ? [{ type: "text", text: input2.text }] : [{ type: "text", text: "" }]);
25719
26080
  let contextWindow;
25720
26081
  const finishPrompt = () => {
25721
- if (!isLive(started.generation) || record3.finished) throw new AcpExecutorDisposedError();
25722
- const response2 = record3.response;
25723
- if (record3.interrupted || response2 === void 0) {
26082
+ if (!isLive(started.generation) || record4.finished) throw new AcpExecutorDisposedError();
26083
+ const response2 = record4.response;
26084
+ if (record4.interrupted || response2 === void 0) {
25724
26085
  settle2({ turnId, stopReason: "cancelled", state: "cancelled" });
25725
26086
  return { threadId: options.threadId, turnId, stopReason: "cancelled" };
25726
26087
  }
@@ -25769,7 +26130,7 @@ function createExecutorPrompt({
25769
26130
  });
25770
26131
  shared.modelSelectionState = applied.state;
25771
26132
  sessionId = applied.sessionId;
25772
- record3.sessionId = applied.sessionId;
26133
+ record4.sessionId = applied.sessionId;
25773
26134
  } catch (error62) {
25774
26135
  const failureCategory = readAcpFailureCategory(error62);
25775
26136
  if (failureCategory === "model-unavailable") {
@@ -25801,7 +26162,7 @@ function createExecutorPrompt({
25801
26162
  written = true;
25802
26163
  input2.onDispatched?.(turnId);
25803
26164
  },
25804
- record3
26165
+ record4
25805
26166
  );
25806
26167
  } catch (error62) {
25807
26168
  if (shared.disposed) {
@@ -25841,7 +26202,7 @@ function createExecutorPrompt({
25841
26202
  if (turnId === void 0) {
25842
26203
  throw new AcpExecutorError("internal", "ACP prompt settled without a turn id");
25843
26204
  }
25844
- if (record3.finished) throw new AcpExecutorDisposedError();
26205
+ if (record4.finished) throw new AcpExecutorDisposedError();
25845
26206
  if (hooks.readContextWindow !== void 0) {
25846
26207
  try {
25847
26208
  contextWindow = await hooks.readContextWindow({
@@ -25877,7 +26238,7 @@ function createPromptResults({
25877
26238
  const prompts = /* @__PURE__ */ new Map();
25878
26239
  const add = (identity, finish) => {
25879
26240
  const { promise: done, resolve: resolve2 } = Promise.withResolvers();
25880
- const record3 = {
26241
+ const record4 = {
25881
26242
  ...identity,
25882
26243
  finish,
25883
26244
  done,
@@ -25886,49 +26247,49 @@ function createPromptResults({
25886
26247
  interrupted: false,
25887
26248
  finished: false
25888
26249
  };
25889
- prompts.set(record3.promptId, record3);
25890
- return record3;
26250
+ prompts.set(record4.promptId, record4);
26251
+ return record4;
25891
26252
  };
25892
26253
  const receive = (promptId, response) => {
25893
- const record3 = prompts.get(promptId);
25894
- if (!record3 || record3.finished || record3.rejected || record3.response !== void 0) return;
25895
- if (shared.disposed || shared.generation !== record3.generation || shared.sessionId !== record3.sessionId)
26254
+ const record4 = prompts.get(promptId);
26255
+ if (!record4 || record4.finished || record4.rejected || record4.response !== void 0) return;
26256
+ if (shared.disposed || shared.generation !== record4.generation || shared.sessionId !== record4.sessionId)
25896
26257
  return;
25897
- record3.response = response;
26258
+ record4.response = response;
25898
26259
  };
25899
26260
  const reject = (promptId) => {
25900
- const record3 = prompts.get(promptId);
25901
- if (record3 && record3.response === void 0) record3.rejected = true;
26261
+ const record4 = prompts.get(promptId);
26262
+ if (record4 && record4.response === void 0) record4.rejected = true;
25902
26263
  };
25903
26264
  const stop = (turnId) => {
25904
- for (const record3 of prompts.values()) {
25905
- if (!record3.finished && (turnId === void 0 || record3.turnId === turnId) && record3.response === void 0) {
25906
- record3.interrupted = true;
26265
+ for (const record4 of prompts.values()) {
26266
+ if (!record4.finished && (turnId === void 0 || record4.turnId === turnId) && record4.response === void 0) {
26267
+ record4.interrupted = true;
25907
26268
  }
25908
26269
  }
25909
26270
  };
25910
- const complete = (record3) => {
25911
- record3.finished = true;
25912
- record3.resolve();
26271
+ const complete = (record4) => {
26272
+ record4.finished = true;
26273
+ record4.resolve();
25913
26274
  };
25914
- const hasInterrupted = (turnId) => [...prompts.values()].some((record3) => record3.turnId === turnId && record3.interrupted);
26275
+ const hasInterrupted = (turnId) => [...prompts.values()].some((record4) => record4.turnId === turnId && record4.interrupted);
25915
26276
  const forget = (turnId) => {
25916
- for (const [id, record3] of prompts) {
25917
- if (record3.turnId === turnId) {
25918
- complete(record3);
26277
+ for (const [id, record4] of prompts) {
26278
+ if (record4.turnId === turnId) {
26279
+ complete(record4);
25919
26280
  prompts.delete(id);
25920
26281
  }
25921
26282
  }
25922
26283
  };
25923
26284
  const wait = async (turnId, includeUnreceived = false) => {
25924
26285
  const claimed = [...prompts.values()].filter(
25925
- (record3) => !record3.finished && (includeUnreceived || record3.response !== void 0) && (turnId === void 0 || record3.turnId === turnId)
26286
+ (record4) => !record4.finished && (includeUnreceived || record4.response !== void 0) && (turnId === void 0 || record4.turnId === turnId)
25926
26287
  );
25927
26288
  if (claimed.length === 0) return;
25928
26289
  let timer;
25929
26290
  try {
25930
26291
  const drained = await Promise.race([
25931
- Promise.all(claimed.map((record3) => record3.done)).then(() => true),
26292
+ Promise.all(claimed.map((record4) => record4.done)).then(() => true),
25932
26293
  new Promise((resolve2) => {
25933
26294
  timer = setTimeout(
25934
26295
  () => resolve2(false),
@@ -25938,19 +26299,19 @@ function createPromptResults({
25938
26299
  ]);
25939
26300
  if (drained) return;
25940
26301
  options.log?.warn?.("ACP result settlement timed out", { threadId: options.threadId });
25941
- for (const record3 of claimed) if (!record3.finished) record3.finish();
26302
+ for (const record4 of claimed) if (!record4.finished) record4.finish();
25942
26303
  } finally {
25943
26304
  clearTimeout(timer);
25944
26305
  }
25945
26306
  };
25946
26307
  const finishUnreceived = () => {
25947
26308
  const claimedTurns = new Set(
25948
- [...prompts.values()].filter((record3) => !record3.finished && record3.response !== void 0).map((record3) => record3.turnId)
26309
+ [...prompts.values()].filter((record4) => !record4.finished && record4.response !== void 0).map((record4) => record4.turnId)
25949
26310
  );
25950
- for (const record3 of prompts.values()) {
25951
- if (!record3.finished && record3.response === void 0) {
25952
- if (claimedTurns.has(record3.turnId)) record3.finish();
25953
- else complete(record3);
26311
+ for (const record4 of prompts.values()) {
26312
+ if (!record4.finished && record4.response === void 0) {
26313
+ if (claimedTurns.has(record4.turnId)) record4.finish();
26314
+ else complete(record4);
25954
26315
  }
25955
26316
  }
25956
26317
  };
@@ -26490,11 +26851,19 @@ function acpInitializePayload(clientInfo, overrides) {
26490
26851
  writeTextFile: false,
26491
26852
  ...overrides?.fs
26492
26853
  },
26493
- terminal: overrides?.terminal ?? false
26854
+ terminal: overrides?.terminal ?? false,
26855
+ ...overrides?.subagents === true ? { subagents: {} } : {}
26494
26856
  },
26495
26857
  clientInfo
26496
26858
  };
26497
26859
  }
26860
+ function acpCapabilityOverrides(input2) {
26861
+ const rest = {
26862
+ ...input2.clientCapabilities
26863
+ };
26864
+ delete rest.subagents;
26865
+ return input2.subagentSessions === true ? { ...rest, subagents: true } : rest;
26866
+ }
26498
26867
 
26499
26868
  // ../../packages/ycodium-acp-executor/src/refreshDeadline.ts
26500
26869
  var MODEL_CATALOG_REFRESH_TIMEOUT_MS = 9e4;
@@ -26576,6 +26945,20 @@ function createExecutorSession({
26576
26945
  failIfDisposed,
26577
26946
  shared
26578
26947
  }) {
26948
+ const requestSession = async (method, params) => {
26949
+ const knownSessionId = params["sessionId"];
26950
+ if (typeof knownSessionId === "string") shared.ownSessionIds.add(knownSessionId);
26951
+ shared.sessionOpensInFlight += 1;
26952
+ try {
26953
+ const result = await connection.request(method, params);
26954
+ const sessionId = result?.sessionId;
26955
+ if (typeof sessionId === "string" && sessionId.length > 0)
26956
+ shared.ownSessionIds.add(sessionId);
26957
+ return result;
26958
+ } finally {
26959
+ shared.sessionOpensInFlight -= 1;
26960
+ }
26961
+ };
26579
26962
  const openFreshSession = async (expectedGeneration) => {
26580
26963
  const initialized = shared.initializeResult;
26581
26964
  if (initialized === void 0) {
@@ -26586,7 +26969,7 @@ function createExecutorSession({
26586
26969
  initialized.agentCapabilities
26587
26970
  );
26588
26971
  const additionalDirectories = options.additionalDirectories !== void 0 && options.additionalDirectories.length > 0 ? { additionalDirectories: options.additionalDirectories } : {};
26589
- const created = await connection.request("session/new", {
26972
+ const created = await requestSession("session/new", {
26590
26973
  cwd: options.cwd,
26591
26974
  mcpServers,
26592
26975
  ...additionalDirectories
@@ -26703,7 +27086,13 @@ function createExecutorSession({
26703
27086
  return applyOnce(input2.state, input2.acpSessionId, input2.setup, false);
26704
27087
  };
26705
27088
  const startOnce = async (expectedGeneration) => {
26706
- const initializePayload = acpInitializePayload(options.clientInfo, options.clientCapabilities);
27089
+ const initializePayload = acpInitializePayload(
27090
+ options.clientInfo,
27091
+ acpCapabilityOverrides({
27092
+ clientCapabilities: options.clientCapabilities,
27093
+ subagentSessions: options.subagentSessions
27094
+ })
27095
+ );
26707
27096
  const initialized = await connection.request(
26708
27097
  "initialize",
26709
27098
  initializePayload
@@ -26727,7 +27116,7 @@ function createExecutorSession({
26727
27116
  let setup;
26728
27117
  let nextSessionId;
26729
27118
  if (options.resumeSessionId && options.resumeMethod === "session/resume") {
26730
- setup = await connection.request("session/resume", {
27119
+ setup = await requestSession("session/resume", {
26731
27120
  sessionId: options.resumeSessionId,
26732
27121
  cwd: options.cwd,
26733
27122
  mcpServers,
@@ -26737,7 +27126,7 @@ function createExecutorSession({
26737
27126
  } else if (options.resumeSessionId) {
26738
27127
  shared.sessionLoadInFlight = true;
26739
27128
  try {
26740
- setup = await connection.request("session/load", {
27129
+ setup = await requestSession("session/load", {
26741
27130
  sessionId: options.resumeSessionId,
26742
27131
  cwd: options.cwd,
26743
27132
  mcpServers,
@@ -26752,7 +27141,7 @@ function createExecutorSession({
26752
27141
  });
26753
27142
  nextSessionId = options.resumeSessionId;
26754
27143
  } else {
26755
- const created = await connection.request("session/new", {
27144
+ const created = await requestSession("session/new", {
26756
27145
  cwd: options.cwd,
26757
27146
  mcpServers,
26758
27147
  ...additionalDirectories
@@ -26937,6 +27326,127 @@ function createExecutorSettlement({
26937
27326
  return { rememberSettledPromptKey, abortPendingSettlement, settleFromNotification };
26938
27327
  }
26939
27328
 
27329
+ // ../../packages/ycodium-acp-executor/src/executor/subagent-sessions.ts
27330
+ function parseState(raw) {
27331
+ if (!isRecord(raw)) return { status: void 0, error: void 0 };
27332
+ const state = raw["state"];
27333
+ if (state === "running") return { status: "running", error: void 0 };
27334
+ if (state === "requires_action") return { status: "waiting", error: void 0 };
27335
+ if (state !== "idle") return { status: void 0, error: void 0 };
27336
+ const stopReason = raw["stopReason"];
27337
+ const error62 = isRecord(raw["error"]) ? asTrimmedString(raw["error"]["message"]) : void 0;
27338
+ if (stopReason === "error" || isRecord(raw["error"])) return { status: "failed", error: error62 };
27339
+ if (stopReason === "cancelled") return { status: "cancelled", error: void 0 };
27340
+ return { status: "idle", error: void 0 };
27341
+ }
27342
+ function childLinkage(childId, record4) {
27343
+ return {
27344
+ taskType: "subagent",
27345
+ rosterKind: "subagent",
27346
+ nativeSessionId: childId,
27347
+ timelineBypass: true,
27348
+ ...record4.title === void 0 ? {} : { title: record4.title }
27349
+ };
27350
+ }
27351
+ function createSubagentSessionTracker(registry2) {
27352
+ const observe = (notification, ctx) => {
27353
+ const update = notification.update;
27354
+ if (!isRecord(update) || update["sessionUpdate"] !== "subagent_update") return [];
27355
+ const childId = asTrimmedString(update["sessionId"]);
27356
+ if (childId === void 0 || ctx.ownSessionIds.has(childId)) return [];
27357
+ const outerId = notification.sessionId;
27358
+ const nested = registry2.has(outerId);
27359
+ if (ctx.foreign && !nested) return [];
27360
+ if (outerId === childId) return [];
27361
+ const title = asTrimmedString(update["title"]);
27362
+ const description = asTrimmedString(update["description"]);
27363
+ const state = parseState(update["state"]);
27364
+ let record4 = registry2.get(childId);
27365
+ if (record4 === void 0) {
27366
+ record4 = {
27367
+ turnId: ctx.turnId,
27368
+ title,
27369
+ description,
27370
+ parentAgentId: nested ? outerId : void 0,
27371
+ observed: state.status,
27372
+ reported: void 0,
27373
+ reportedError: void 0,
27374
+ // 重放里恢复的身份:宿主早有这一行,不再发 started。
27375
+ announced: ctx.silent,
27376
+ pendingMetadata: false
27377
+ };
27378
+ registry2.add(childId, record4);
27379
+ }
27380
+ record4.turnId ??= ctx.turnId;
27381
+ if (!ctx.silent) {
27382
+ if (title !== void 0 && title !== record4.title || description !== void 0 && description !== record4.description) {
27383
+ record4.pendingMetadata = true;
27384
+ }
27385
+ }
27386
+ if (title !== void 0) record4.title = title;
27387
+ if (description !== void 0) record4.description = description;
27388
+ if (state.status !== void 0) record4.observed = state.status;
27389
+ if (ctx.silent) return [];
27390
+ const linkage2 = childLinkage(childId, record4);
27391
+ const turn = record4.turnId === void 0 ? {} : { turnId: record4.turnId };
27392
+ const events = [];
27393
+ if (!record4.announced && state.status === void 0) return events;
27394
+ if (!record4.announced) {
27395
+ record4.announced = true;
27396
+ record4.pendingMetadata = false;
27397
+ events.push({
27398
+ type: "task.started",
27399
+ ...turn,
27400
+ payload: {
27401
+ taskId: childId,
27402
+ ...linkage2,
27403
+ ...record4.description === void 0 ? {} : { description: record4.description }
27404
+ }
27405
+ });
27406
+ }
27407
+ const statusChanged = state.status !== void 0 && (state.status !== record4.reported || record4.pendingMetadata || state.error !== void 0 && state.error !== record4.reportedError);
27408
+ if (statusChanged) {
27409
+ record4.pendingMetadata = false;
27410
+ record4.reported = state.status;
27411
+ record4.reportedError = state.status === "failed" ? state.error ?? record4.reportedError : void 0;
27412
+ events.push({
27413
+ type: "task.updated",
27414
+ ...turn,
27415
+ payload: {
27416
+ taskId: childId,
27417
+ status: state.status,
27418
+ ...state.error === void 0 ? {} : { error: state.error },
27419
+ ...record4.description === void 0 ? {} : { description: record4.description },
27420
+ ...linkage2
27421
+ }
27422
+ });
27423
+ }
27424
+ return events;
27425
+ };
27426
+ const settleSessionEnded = () => {
27427
+ const events = [];
27428
+ for (const [childId, record4] of registry2.entries()) {
27429
+ const last = record4.reported ?? record4.observed;
27430
+ if (!record4.announced || last !== "running" && last !== "waiting") continue;
27431
+ record4.reported = "idle";
27432
+ record4.observed = "idle";
27433
+ events.push({
27434
+ type: "task.updated",
27435
+ ...record4.turnId === void 0 ? {} : { turnId: record4.turnId },
27436
+ payload: {
27437
+ taskId: childId,
27438
+ status: "idle",
27439
+ outcomeUnknown: true,
27440
+ ...record4.description === void 0 ? {} : { description: record4.description },
27441
+ ...childLinkage(childId, record4)
27442
+ }
27443
+ });
27444
+ }
27445
+ return events;
27446
+ };
27447
+ return { observe, settleSessionEnded };
27448
+ }
27449
+
26940
27450
  // ../../packages/ycodium-acp-executor/src/executor/updates.ts
26941
27451
  var COMPACTION_SUMMARY_MAX_CHARS = 8e3;
26942
27452
  var SHOWN_TOOL_CALL_LIMIT = 256;
@@ -26955,8 +27465,10 @@ function createExecutorUpdates({
26955
27465
  shared
26956
27466
  }) {
26957
27467
  const shownToolCallIds = /* @__PURE__ */ new Set();
26958
- const emitCompactionState = (record3, state) => {
26959
- const summary = record3.summary?.trim() ?? "";
27468
+ const markChildSession = shared.childSessions.mark;
27469
+ const subagentSessions = options.subagentSessions === true ? createSubagentSessionTracker(shared.childSessions) : void 0;
27470
+ const emitCompactionState = (record4, state) => {
27471
+ const summary = record4.summary?.trim() ?? "";
26960
27472
  const truncated = summary.length > COMPACTION_SUMMARY_MAX_CHARS;
26961
27473
  emit({
26962
27474
  type: "thread.state.changed",
@@ -26967,9 +27479,9 @@ function createExecutorUpdates({
26967
27479
  payload: {
26968
27480
  state,
26969
27481
  compaction: {
26970
- compactionId: record3.snapshotId,
26971
- trigger: record3.trigger,
26972
- ...state === "compacted" ? { durationMs: Math.max(0, nowMs() - record3.startedAtMs) } : {},
27482
+ compactionId: record4.snapshotId,
27483
+ trigger: record4.trigger,
27484
+ ...state === "compacted" ? { durationMs: Math.max(0, nowMs() - record4.startedAtMs) } : {},
26973
27485
  ...summary.length > 0 ? {
26974
27486
  summary: truncated ? summary.slice(0, COMPACTION_SUMMARY_MAX_CHARS) : summary,
26975
27487
  ...truncated ? { summaryTruncated: true } : {}
@@ -26979,13 +27491,13 @@ function createExecutorUpdates({
26979
27491
  });
26980
27492
  };
26981
27493
  const applyCompactionUpdate = (event) => {
26982
- let record3 = compactions.get(event.compactionId);
26983
- if (record3 === void 0) {
27494
+ let record4 = compactions.get(event.compactionId);
27495
+ if (record4 === void 0) {
26984
27496
  if (shared.manualCompaction !== void 0 && !shared.manualCompaction.adopted) {
26985
27497
  shared.manualCompaction.adopted = true;
26986
- record3 = shared.manualCompaction;
27498
+ record4 = shared.manualCompaction;
26987
27499
  } else {
26988
- record3 = {
27500
+ record4 = {
26989
27501
  snapshotId: randomId(),
26990
27502
  trigger: "automatic",
26991
27503
  startedAtMs: nowMs(),
@@ -26995,25 +27507,25 @@ function createExecutorUpdates({
26995
27507
  adopted: false
26996
27508
  };
26997
27509
  }
26998
- compactions.set(event.compactionId, record3);
27510
+ compactions.set(event.compactionId, record4);
26999
27511
  }
27000
- if (event.summary !== void 0) record3.summary = event.summary ?? void 0;
27512
+ if (event.summary !== void 0) record4.summary = event.summary ?? void 0;
27001
27513
  switch (event.status) {
27002
27514
  case "in_progress":
27003
- if (!record3.announced) {
27004
- record3.announced = true;
27005
- emitCompactionState(record3, "compacting");
27515
+ if (!record4.announced) {
27516
+ record4.announced = true;
27517
+ emitCompactionState(record4, "compacting");
27006
27518
  }
27007
27519
  return;
27008
27520
  case "completed":
27009
- record3.announced = true;
27010
- record3.finished = true;
27521
+ record4.announced = true;
27522
+ record4.finished = true;
27011
27523
  compactions.delete(event.compactionId);
27012
- emitCompactionState(record3, "compacted");
27524
+ emitCompactionState(record4, "compacted");
27013
27525
  return;
27014
27526
  case "failed":
27015
27527
  case "cancelled":
27016
- record3.finished = true;
27528
+ record4.finished = true;
27017
27529
  compactions.delete(event.compactionId);
27018
27530
  emit({
27019
27531
  type: "runtime.warning",
@@ -27040,6 +27552,30 @@ function createExecutorUpdates({
27040
27552
  return;
27041
27553
  }
27042
27554
  };
27555
+ const emitTaskEvents = (taskEvents) => {
27556
+ for (const taskEvent of taskEvents ?? []) {
27557
+ emit({
27558
+ type: taskEvent.type,
27559
+ ...stamp(),
27560
+ provider: options.provider,
27561
+ threadId: options.threadId,
27562
+ ...taskEvent.turnId !== void 0 ? { turnId: taskEvent.turnId } : {},
27563
+ payload: taskEvent.payload
27564
+ });
27565
+ }
27566
+ };
27567
+ const toolSubagents = hooks.toolSubagents === void 0 ? void 0 : createToolSubagentTracker(hooks.toolSubagents);
27568
+ const settleToolSubagents = (settlement, turnId) => emitTaskEvents(toolSubagents?.settle(settlement, turnId));
27569
+ const settleSessionEnded = () => {
27570
+ settleToolSubagents("session-ended");
27571
+ emitTaskEvents(subagentSessions?.settleSessionEnded());
27572
+ emitTaskEvents(hooks.onSessionEnded?.());
27573
+ };
27574
+ const observeContext = () => ({
27575
+ turnId: shared.activeTurnId,
27576
+ sessionId: shared.sessionId,
27577
+ markChildSession
27578
+ });
27043
27579
  const handleSessionUpdate = (params) => {
27044
27580
  const parsed = parseSessionUpdateEvent(params);
27045
27581
  if (parsed.modeId && shared.modeState) {
@@ -27066,43 +27602,39 @@ function createExecutorUpdates({
27066
27602
  rawTitle: params.update.title,
27067
27603
  nowMs
27068
27604
  });
27069
- const hookResult = hooks.onToolCallUpdated?.({
27605
+ const hasToolHooks = toolSubagents !== void 0 || hooks.onToolCallUpdated !== void 0;
27606
+ const call = !hasToolHooks ? void 0 : {
27070
27607
  toolCallId: nextToolCall.toolCallId,
27071
27608
  status: nextToolCall.status,
27072
27609
  title: nextToolCall.title,
27073
27610
  kind: nextToolCall.kind,
27074
27611
  rawInput: nextToolCall.data["rawInput"],
27075
27612
  rawOutput: nextToolCall.data["rawOutput"],
27613
+ contentText: nextToolCall.contentText,
27076
27614
  meta: params.update._meta,
27077
27615
  turnId: shared.activeTurnId
27078
- });
27079
- const taskEvents = hookResult === void 0 ? [] : "events" in hookResult ? hookResult.events : hookResult;
27616
+ };
27617
+ const hookResult = call === void 0 ? void 0 : toolSubagents?.onToolCallUpdated(call) ?? hooks.onToolCallUpdated?.(call);
27080
27618
  const handledByHook = hookResult !== void 0 && "events" in hookResult && hookResult.handled === true;
27081
- for (const taskEvent of taskEvents) {
27082
- emit({
27083
- type: taskEvent.type,
27084
- ...stamp(),
27085
- provider: options.provider,
27086
- threadId: options.threadId,
27087
- ...taskEvent.turnId !== void 0 ? { turnId: taskEvent.turnId } : {},
27088
- payload: taskEvent.payload
27089
- });
27090
- }
27619
+ emitTaskEvents(
27620
+ hookResult === void 0 ? [] : "events" in hookResult ? hookResult.events : hookResult
27621
+ );
27091
27622
  if (nextToolCall.status === "completed" && hookResult && "artifacts" in hookResult)
27092
27623
  emitArtifacts(hookResult.artifacts ?? [], nextToolCall.toolCallId);
27093
27624
  if (handledByHook || !decision.emit) {
27094
27625
  continue;
27095
27626
  }
27627
+ const toolTurnId = (hookResult !== void 0 && "events" in hookResult ? hookResult.turnId : void 0) ?? shared.activeTurnId;
27096
27628
  if (!shownToolCallIds.has(nextToolCall.toolCallId)) {
27097
27629
  rememberShownToolCall(nextToolCall.toolCallId);
27098
- closeActiveAssistantSegment(shared.activeTurnId);
27630
+ if (toolTurnId === shared.activeTurnId) closeActiveAssistantSegment(shared.activeTurnId);
27099
27631
  }
27100
27632
  emit(
27101
27633
  makeAcpToolCallEvent({
27102
27634
  stamp: stamp(),
27103
27635
  provider: options.provider,
27104
27636
  threadId: options.threadId,
27105
- turnId: shared.activeTurnId,
27637
+ turnId: toolTurnId,
27106
27638
  toolCall: nextToolCall,
27107
27639
  rawPayload: event.rawPayload
27108
27640
  })
@@ -27118,9 +27650,9 @@ function createExecutorUpdates({
27118
27650
  continue;
27119
27651
  }
27120
27652
  if (event._tag === "CompactionSummaryChunk") {
27121
- const record3 = compactions.get(event.compactionId);
27122
- if (record3 !== void 0 && !record3.finished) {
27123
- record3.summary = (record3.summary ?? "") + event.text;
27653
+ const record4 = compactions.get(event.compactionId);
27654
+ if (record4 !== void 0 && !record4.finished) {
27655
+ record4.summary = (record4.summary ?? "") + event.text;
27124
27656
  }
27125
27657
  continue;
27126
27658
  }
@@ -27179,7 +27711,36 @@ function createExecutorUpdates({
27179
27711
  }
27180
27712
  }
27181
27713
  };
27182
- return { emitCompactionState, handleSessionUpdate };
27714
+ const receiveSessionUpdate = (params) => {
27715
+ const foreign = !shared.ownSessionIds.has(params.sessionId) && (shared.childSessions.has(params.sessionId) || shared.sessionOpensInFlight === 0 && shared.ownSessionIds.size > 0);
27716
+ emitTaskEvents(
27717
+ subagentSessions?.observe(params, {
27718
+ turnId: shared.activeTurnId,
27719
+ foreign,
27720
+ ownSessionIds: shared.ownSessionIds,
27721
+ silent: shared.sessionLoadInFlight
27722
+ })
27723
+ );
27724
+ if (!shared.sessionLoadInFlight) {
27725
+ if (hooks.onSessionUpdate) {
27726
+ emitTaskEvents(hooks.onSessionUpdate(params, { ...observeContext(), foreign }));
27727
+ }
27728
+ }
27729
+ if (!foreign) handleSessionUpdate(params);
27730
+ };
27731
+ const receiveExtensionNotification = (method, params) => {
27732
+ if (shared.sessionLoadInFlight || !hooks.onExtensionNotification) return;
27733
+ const result = hooks.onExtensionNotification(method, params, observeContext());
27734
+ if (Array.isArray(result)) emitTaskEvents(result);
27735
+ };
27736
+ return {
27737
+ emitCompactionState,
27738
+ receiveSessionUpdate,
27739
+ receiveExtensionNotification,
27740
+ settleToolSubagents,
27741
+ settleSessionEnded,
27742
+ toolSubagentsMayRun: () => toolSubagents?.mayStillRun() ?? false
27743
+ };
27183
27744
  }
27184
27745
 
27185
27746
  // ../../packages/ycodium-acp-executor/src/openCommands.ts
@@ -27328,7 +27889,10 @@ function createAcpExecutor(options) {
27328
27889
  abortLocalPrompt: void 0,
27329
27890
  connectionClosed: false,
27330
27891
  sessionLoadInFlight: false,
27331
- droppedReplayUpdates: 0
27892
+ droppedReplayUpdates: 0,
27893
+ ownSessionIds: /* @__PURE__ */ new Set(),
27894
+ childSessions: createChildSessionRegistry(),
27895
+ sessionOpensInFlight: 0
27332
27896
  };
27333
27897
  const interruptedTurnIds = /* @__PURE__ */ new Set();
27334
27898
  const approvals = createApprovalGate({
@@ -27358,7 +27922,14 @@ function createAcpExecutor(options) {
27358
27922
  promptMutex,
27359
27923
  shared
27360
27924
  });
27361
- const { emitCompactionState, handleSessionUpdate } = createExecutorUpdates({
27925
+ const {
27926
+ emitCompactionState,
27927
+ receiveSessionUpdate,
27928
+ receiveExtensionNotification,
27929
+ settleToolSubagents,
27930
+ settleSessionEnded,
27931
+ toolSubagentsMayRun
27932
+ } = createExecutorUpdates({
27362
27933
  emit,
27363
27934
  stamp,
27364
27935
  options,
@@ -27421,11 +27992,11 @@ function createAcpExecutor(options) {
27421
27992
  if (notification.method === "session/update") {
27422
27993
  const params = notification.params;
27423
27994
  const transformed = hooks.transformSessionUpdate ? hooks.transformSessionUpdate(params) : params;
27424
- if (transformed !== void 0) handleSessionUpdate(transformed);
27995
+ if (transformed !== void 0) receiveSessionUpdate(transformed);
27425
27996
  return;
27426
27997
  }
27427
27998
  if (settleFromNotification(notification.method, notification.params)) return;
27428
- void hooks.onExtensionNotification?.(notification.method, notification.params);
27999
+ receiveExtensionNotification(notification.method, notification.params);
27429
28000
  },
27430
28001
  onRequest: async (method, params) => {
27431
28002
  if (method === CLIENT_METHODS.session_request_permission) {
@@ -27481,6 +28052,7 @@ function createAcpExecutor(options) {
27481
28052
  });
27482
28053
  const { sendPromptRpc, prompt } = createExecutorPrompt({
27483
28054
  promptResults,
28055
+ settleToolSubagents,
27484
28056
  isLive,
27485
28057
  closeActiveAssistantSegment,
27486
28058
  emit,
@@ -27505,6 +28077,8 @@ function createAcpExecutor(options) {
27505
28077
  dispose: disposeLifecycle
27506
28078
  } = createExecutorLifecycle({
27507
28079
  promptResults,
28080
+ settleToolSubagents,
28081
+ settleSessionEnded,
27508
28082
  failIfDisposed,
27509
28083
  requireStarted,
27510
28084
  interruptedTurnIds,
@@ -27553,6 +28127,7 @@ function createAcpExecutor(options) {
27553
28127
  setNativeMode,
27554
28128
  compact,
27555
28129
  openToolCalls: () => readOpenToolCalls(toolCalls, shared.activeTurnId),
28130
+ toolSubagentsMayRun,
27556
28131
  dispose: (exitCode) => {
27557
28132
  disposeOnce ??= (async () => {
27558
28133
  try {
@@ -27769,7 +28344,13 @@ async function openAcpProbeHandshake(input2) {
27769
28344
  });
27770
28345
  try {
27771
28346
  const initializeResult = await withProbeTimeout(
27772
- connection.request("initialize", acpInitializePayload(input2.clientInfo)),
28347
+ connection.request(
28348
+ "initialize",
28349
+ acpInitializePayload(
28350
+ input2.clientInfo,
28351
+ acpCapabilityOverrides({ subagentSessions: input2.subagentSessions })
28352
+ )
28353
+ ),
27773
28354
  input2.requestTimeoutMs,
27774
28355
  "ACP probe request 'initialize'",
27775
28356
  input2.signal
@@ -27795,13 +28376,13 @@ function parseCliVersion(output2) {
27795
28376
  }
27796
28377
  async function collectCappedText(stream, maxBytes) {
27797
28378
  const decoder = new TextDecoder();
27798
- let text3 = "";
28379
+ let text4 = "";
27799
28380
  let total = 0;
27800
28381
  for await (const chunk of stream) {
27801
28382
  total += chunk.byteLength;
27802
- if (total <= maxBytes) text3 += decoder.decode(chunk, { stream: true });
28383
+ if (total <= maxBytes) text4 += decoder.decode(chunk, { stream: true });
27803
28384
  }
27804
- return { text: text3 + decoder.decode(), overflowed: total > maxBytes };
28385
+ return { text: text4 + decoder.decode(), overflowed: total > maxBytes };
27805
28386
  }
27806
28387
  async function collectProbeProcess(child, input2) {
27807
28388
  const stdinClosed = Promise.resolve().then(() => child.closeStdin());
@@ -27831,8 +28412,8 @@ async function collectProbeProcess(child, input2) {
27831
28412
  } catch {
27832
28413
  await child.kill("SIGKILL");
27833
28414
  }
27834
- const settled = await Promise.allSettled([term, ...tasks]);
27835
- const termination = settled[0];
28415
+ const settled2 = await Promise.allSettled([term, ...tasks]);
28416
+ const termination = settled2[0];
27836
28417
  if (termination?.status === "rejected") throw termination.reason;
27837
28418
  })();
27838
28419
  try {
@@ -27969,7 +28550,7 @@ function readDeviceCodeOutput(stdout, onText) {
27969
28550
  const outputWentQuiet = new Promise((resolve2) => {
27970
28551
  onQuiet = resolve2;
27971
28552
  });
27972
- const text3 = (async () => {
28553
+ const text4 = (async () => {
27973
28554
  const decoder = new TextDecoder();
27974
28555
  for await (const chunk of stdout) {
27975
28556
  const piece = decoder.decode(chunk, { stream: true });
@@ -27990,7 +28571,7 @@ function readDeviceCodeOutput(stdout, onText) {
27990
28571
  let silentCap;
27991
28572
  await Promise.race([
27992
28573
  codeFound,
27993
- text3.then(() => void 0),
28574
+ text4.then(() => void 0),
27994
28575
  outputWentQuiet,
27995
28576
  new Promise((resolve2) => {
27996
28577
  silentCap = setTimeout(resolve2, SILENT_CAP_MS);
@@ -28007,7 +28588,7 @@ function readDeviceCodeOutput(stdout, onText) {
28007
28588
  ...verificationUrl === void 0 ? {} : { verificationUrl }
28008
28589
  };
28009
28590
  })();
28010
- return { text: text3, code };
28591
+ return { text: text4, code };
28011
28592
  }
28012
28593
 
28013
28594
  // src/grokHome.ts
@@ -28021,8 +28602,8 @@ import * as NodeFS2 from "node:fs";
28021
28602
  import * as NodePath3 from "node:path";
28022
28603
  var AUTH_FILE_NAME = "auth.json";
28023
28604
  var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28024
- var readString2 = (record3, key) => {
28025
- const value = record3[key];
28605
+ var readString2 = (record4, key) => {
28606
+ const value = record4[key];
28026
28607
  if (typeof value !== "string") return void 0;
28027
28608
  const trimmed3 = value.trim();
28028
28609
  return trimmed3.length > 0 ? trimmed3 : void 0;
@@ -28064,9 +28645,9 @@ var unreadableProbe = (exists) => ({
28064
28645
  name: void 0,
28065
28646
  expiresAt: void 0
28066
28647
  });
28067
- var joinName = (record3) => {
28068
- const first = readString2(record3, "first_name");
28069
- const last = readString2(record3, "last_name");
28648
+ var joinName = (record4) => {
28649
+ const first = readString2(record4, "first_name");
28650
+ const last = readString2(record4, "last_name");
28070
28651
  const joined = [first, last].filter((part) => part !== void 0).join(" ");
28071
28652
  return joined.length > 0 ? joined : void 0;
28072
28653
  };
@@ -28187,7 +28768,7 @@ function makeGrokSignIn(input2) {
28187
28768
  });
28188
28769
  const output2 = readDeviceCodeOutput(
28189
28770
  handle.stdout,
28190
- (text3) => host.log.info("sign-in output", { text: text3 })
28771
+ (text4) => host.log.info("sign-in output", { text: text4 })
28191
28772
  );
28192
28773
  const operationId = `grok-sign-in-${Date.now().toString(36)}-${operations.size}`;
28193
28774
  let closing;
@@ -28214,15 +28795,15 @@ function makeGrokSignIn(input2) {
28214
28795
  await operations.get(operationId)?.close();
28215
28796
  },
28216
28797
  verify: async (signal) => {
28217
- const active = [...operations.values()];
28798
+ const active2 = [...operations.values()];
28218
28799
  try {
28219
- for (const operation of active) {
28800
+ for (const operation of active2) {
28220
28801
  const code = await raceAbort(operation.handle.exited, signal);
28221
28802
  if (code !== 0) throw new Error(`Grok sign-in exited with code ${String(code)}`);
28222
28803
  }
28223
28804
  return await input2.probe(signal);
28224
28805
  } finally {
28225
- await Promise.all(active.map((operation) => operation.close()));
28806
+ await Promise.all(active2.map((operation) => operation.close()));
28226
28807
  }
28227
28808
  }
28228
28809
  };
@@ -28255,9 +28836,9 @@ var parseJson = (raw) => {
28255
28836
  }
28256
28837
  };
28257
28838
  var extractGrokToken = (auth) => {
28258
- const record3 = asObject(auth);
28259
- if (record3 === null) return null;
28260
- for (const [key, value] of Object.entries(record3)) {
28839
+ const record4 = asObject(auth);
28840
+ if (record4 === null) return null;
28841
+ for (const [key, value] of Object.entries(record4)) {
28261
28842
  if (!key.startsWith(GROK_ISSUER_PREFIX)) continue;
28262
28843
  const nestedKey = asString3(asObject(value)?.["key"]);
28263
28844
  if (nestedKey !== null) return nestedKey;
@@ -28472,8 +29053,8 @@ var GROK_EMPTY_PLAN_TEXT = "The agent exited plan mode without writing a plan.";
28472
29053
  var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28473
29054
  var trimmed = (value) => {
28474
29055
  if (typeof value !== "string") return void 0;
28475
- const text3 = value.trim();
28476
- return text3.length > 0 ? text3 : void 0;
29056
+ const text4 = value.trim();
29057
+ return text4.length > 0 ? text4 : void 0;
28477
29058
  };
28478
29059
  function parseXAiExitPlanModeParams(params) {
28479
29060
  const candidates = [params, ...isRecord9(params) ? [params["params"]] : []];
@@ -28519,11 +29100,11 @@ function makeXAiExitPlanModeResponse(params, resolution) {
28519
29100
  if (resolution.kind === "cancelled") return abandoned();
28520
29101
  const answer = resolution.answers[params.toolCallId];
28521
29102
  const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
28522
- const text3 = trimmed(selected);
28523
- if (text3 === void 0) return abandoned();
28524
- if (text3 === GROK_PLAN_APPROVE_OPTION_ID) return { outcome: "approved" };
28525
- if (text3 === GROK_PLAN_ABANDON_OPTION_ID) return abandoned();
28526
- return { outcome: "request_changes", feedback: text3 };
29103
+ const text4 = trimmed(selected);
29104
+ if (text4 === void 0) return abandoned();
29105
+ if (text4 === GROK_PLAN_APPROVE_OPTION_ID) return { outcome: "approved" };
29106
+ if (text4 === GROK_PLAN_ABANDON_OPTION_ID) return abandoned();
29107
+ return { outcome: "request_changes", feedback: text4 };
28527
29108
  }
28528
29109
 
28529
29110
  // src/grokReasoningEffort.ts
@@ -28533,8 +29114,8 @@ import { REASONING_OPTION_LABEL, reasoningEffortShortLabel } from "@ycodium-ai/p
28533
29114
  var isRecord10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28534
29115
  var trimmed2 = (value) => {
28535
29116
  if (typeof value !== "string") return void 0;
28536
- const text3 = value.trim();
28537
- return text3.length > 0 ? text3 : void 0;
29117
+ const text4 = value.trim();
29118
+ return text4.length > 0 ? text4 : void 0;
28538
29119
  };
28539
29120
 
28540
29121
  // src/grokReasoningEffort.ts
@@ -28576,6 +29157,11 @@ function grokReasoningEffortArgs(effort) {
28576
29157
  // src/grokBackgroundTasks.ts
28577
29158
  var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
28578
29159
  var text2 = (value) => typeof value === "string" ? value.trim() || void 0 : void 0;
29160
+ var isSubagentCommand = (command) => command !== void 0 && /^\[subagent[:\]]/.test(command);
29161
+ var taskResults = (output2) => {
29162
+ const results = record2(output2["MultiResult"])["results"];
29163
+ return (Array.isArray(results) ? results : [output2["Result"]]).map(record2);
29164
+ };
28579
29165
  var lifecycle = (status, exitCode) => {
28580
29166
  switch (text2(status)?.toLowerCase()) {
28581
29167
  case "pending":
@@ -28640,9 +29226,7 @@ function buildGrokBackgroundTaskEvents(input2) {
28640
29226
  const command = text2(output2["command"]);
28641
29227
  if (id && command) start(id, "shell", command.split("\n")[0].slice(0, 200), toolCallId);
28642
29228
  } else if (output2["type"] === "TaskOutput" || output2["type"] === "KillTask") {
28643
- const results = record2(output2["MultiResult"])["results"];
28644
- for (const value of Array.isArray(results) ? results : [output2["Result"]]) {
28645
- const result = record2(value);
29229
+ for (const result of taskResults(output2)) {
28646
29230
  const id = text2(result["task_id"]);
28647
29231
  if (!id) continue;
28648
29232
  if (output2["type"] === "KillTask") {
@@ -28654,7 +29238,7 @@ function buildGrokBackgroundTaskEvents(input2) {
28654
29238
  }
28655
29239
  const command = text2(result["command"]);
28656
29240
  const status = lifecycle(result["status"], result["exit_code"]);
28657
- if (!command || !status || command.startsWith("[subagent:")) continue;
29241
+ if (!command || !status || isSubagentCommand(command)) continue;
28658
29242
  const task = start(id, /^\[monitor[:\]]/.test(command) ? "monitor" : "shell", command);
28659
29243
  const summary = text2(result["output"])?.split("\n").find((line) => line.trim())?.trim();
28660
29244
  if (status === "running") {
@@ -28705,6 +29289,281 @@ function grokImageArtifacts(rawOutput) {
28705
29289
  return [{ path, name: filename, ...linkBase !== void 0 ? { linkBase } : {} }];
28706
29290
  }
28707
29291
 
29292
+ // src/grokSubagents.ts
29293
+ var SPAWN_TOOL = "spawn_subagent";
29294
+ var SPAWN_ACK_ID = /^subagent_id:\s*(\S+)\s*$/m;
29295
+ var MACHINE_BLOCKS = /<subagent_(meta|result)>[\s\S]*?<\/subagent_\1>/g;
29296
+ var ordinal = (attemptId) => {
29297
+ const match = attemptId === void 0 ? null : /^at(\d+)\./.exec(attemptId);
29298
+ return match === null ? void 0 : Number(match[1]);
29299
+ };
29300
+ var MAX_SUMMARY_CHARS = 8e3;
29301
+ var MAX_EARLY_FINISHES = 32;
29302
+ var FALLBACK_TITLE = "Subagent";
29303
+ var NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
29304
+ "x.ai/session_notification",
29305
+ "x.ai/session/update"
29306
+ ]);
29307
+ var record3 = (value) => isRecord10(value) ? value : {};
29308
+ var text3 = trimmed2;
29309
+ var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
29310
+ var replyText = (value) => {
29311
+ const reply = typeof value === "string" ? value.replace(MACHINE_BLOCKS, "").trim() : "";
29312
+ if (reply.length === 0) return void 0;
29313
+ return reply.length > MAX_SUMMARY_CHARS ? `${reply.slice(0, MAX_SUMMARY_CHARS - 1)}\u2026` : reply;
29314
+ };
29315
+ var settled = (status) => {
29316
+ const state = lifecycle(status, void 0);
29317
+ return state === "running" ? void 0 : state;
29318
+ };
29319
+ var usageOf = (update) => {
29320
+ const totalTokens = count2(update["tokens_used"]);
29321
+ if (!totalTokens) return void 0;
29322
+ const toolUses = count2(update["tool_call_count"] ?? update["tool_calls"]);
29323
+ const durationMs = count2(update["duration_ms"]);
29324
+ return {
29325
+ totalTokens,
29326
+ ...toolUses === void 0 ? {} : { toolUses },
29327
+ ...durationMs === void 0 ? {} : { durationMs }
29328
+ };
29329
+ };
29330
+ var mergeFinal = (first, next) => first === void 0 ? next : {
29331
+ outcome: first.outcome,
29332
+ // 不同终态的说明(比如取消原因)不能填进已锁定的结局。
29333
+ summary: first.summary ?? (next.outcome === first.outcome ? next.summary : void 0),
29334
+ usage: first.usage ?? next.usage
29335
+ };
29336
+ function createGrokSubagents() {
29337
+ const agents = /* @__PURE__ */ new Map();
29338
+ const spawnCalls = /* @__PURE__ */ new Set();
29339
+ const earlyFinishes = /* @__PURE__ */ new Map();
29340
+ let tick = 0;
29341
+ const linkage2 = (agent) => {
29342
+ const identity = agent.current.identity;
29343
+ return {
29344
+ taskId: agent.id,
29345
+ taskType: "subagent",
29346
+ rosterKind: "subagent",
29347
+ timelineBypass: true,
29348
+ title: identity.title,
29349
+ nativeSessionId: identity.nativeSessionId,
29350
+ ...identity.role === void 0 ? {} : { role: identity.role },
29351
+ ...identity.model === void 0 ? {} : { model: identity.model }
29352
+ };
29353
+ };
29354
+ const attribution = (agent, turnId) => agent.current.turnId !== void 0 && agent.current.turnId === turnId ? { turnId } : {};
29355
+ const running = (agent, turnId) => ({
29356
+ type: "task.updated",
29357
+ ...attribution(agent, turnId),
29358
+ payload: { ...linkage2(agent), status: "running", description: agent.current.identity.title }
29359
+ });
29360
+ const completed = (agent, final, turnId) => ({
29361
+ type: "task.completed",
29362
+ ...attribution(agent, turnId),
29363
+ payload: {
29364
+ ...linkage2(agent),
29365
+ status: final.outcome,
29366
+ ...final.summary === void 0 ? {} : { summary: final.summary },
29367
+ ...final.usage === void 0 ? {} : { typedUsage: final.usage }
29368
+ }
29369
+ });
29370
+ const earlyKey = (id, attemptId) => `${id}|${attemptId ?? ""}`;
29371
+ const withEarlyFinish = (agent, events, turnId) => {
29372
+ const key = earlyKey(agent.id, agent.current.id);
29373
+ const early = earlyFinishes.get(key);
29374
+ if (early === void 0) return events;
29375
+ earlyFinishes.delete(key);
29376
+ agent.current.final = early.final;
29377
+ return [...events, completed(agent, early.final, turnId)];
29378
+ };
29379
+ const onSpawned = (update, ctx) => {
29380
+ const turnId = ctx.turnId;
29381
+ const id = text3(update["subagent_id"]);
29382
+ if (id === void 0) return [];
29383
+ const childSessionId = text3(update["child_session_id"]);
29384
+ if (childSessionId !== void 0) ctx.markChildSession(childSessionId);
29385
+ const attemptId = text3(update["attempt_id"]);
29386
+ const incoming = {
29387
+ title: text3(update["description"]) ?? text3(update["subagent_type"]) ?? FALLBACK_TITLE,
29388
+ role: text3(update["subagent_type"]),
29389
+ model: text3(update["model"]),
29390
+ nativeSessionId: text3(update["child_session_id"])
29391
+ };
29392
+ const newAttempt = (identity) => ({
29393
+ id: attemptId,
29394
+ startedAt: ++tick,
29395
+ identity,
29396
+ turnId,
29397
+ final: void 0,
29398
+ progressKey: void 0
29399
+ });
29400
+ const agent = agents.get(id);
29401
+ if (agent === void 0) {
29402
+ const attempt = newAttempt({ ...incoming, nativeSessionId: incoming.nativeSessionId ?? id });
29403
+ const created = { id, current: attempt, seen: /* @__PURE__ */ new Set() };
29404
+ if (attemptId !== void 0) created.seen.add(attemptId);
29405
+ agents.set(id, created);
29406
+ return withEarlyFinish(
29407
+ created,
29408
+ [
29409
+ {
29410
+ type: "task.started",
29411
+ ...attribution(created, turnId),
29412
+ payload: { ...linkage2(created), description: incoming.title }
29413
+ },
29414
+ running(created, turnId)
29415
+ ],
29416
+ turnId
29417
+ );
29418
+ }
29419
+ const isNew = attemptId !== void 0 && !agent.seen.has(attemptId);
29420
+ const have = ordinal(agent.current.id);
29421
+ const got = ordinal(attemptId);
29422
+ const ordered = have !== void 0 && got !== void 0;
29423
+ if (isNew && (ordered ? got <= have : agent.current.final === void 0)) {
29424
+ agent.seen.add(attemptId);
29425
+ earlyFinishes.delete(earlyKey(id, attemptId));
29426
+ return [];
29427
+ }
29428
+ if (isNew) {
29429
+ const early = earlyFinishes.get(earlyKey(id, attemptId));
29430
+ if (!ordered && early !== void 0 && early.at < agent.current.startedAt) {
29431
+ agent.seen.add(attemptId);
29432
+ earlyFinishes.delete(earlyKey(id, attemptId));
29433
+ return [];
29434
+ }
29435
+ agent.seen.add(attemptId);
29436
+ const before2 = agent.current.identity;
29437
+ agent.current = newAttempt({
29438
+ title: incoming.title,
29439
+ role: incoming.role ?? before2.role,
29440
+ model: incoming.model ?? before2.model,
29441
+ nativeSessionId: incoming.nativeSessionId ?? before2.nativeSessionId
29442
+ });
29443
+ return withEarlyFinish(agent, [running(agent, turnId)], turnId);
29444
+ }
29445
+ const known = agent.current;
29446
+ if (attemptId !== void 0 && known.id !== attemptId || known.final !== void 0) return [];
29447
+ const before = JSON.stringify(linkage2(agent));
29448
+ for (const [key, value] of Object.entries(incoming)) {
29449
+ if (value !== void 0) Object.assign(known.identity, { [key]: value });
29450
+ }
29451
+ if (JSON.stringify(linkage2(agent)) === before) return [];
29452
+ return [
29453
+ {
29454
+ type: "task.progress",
29455
+ ...attribution(agent, turnId),
29456
+ payload: { ...linkage2(agent), description: known.identity.title }
29457
+ }
29458
+ ];
29459
+ };
29460
+ const isCurrent = (agent, attemptId) => attemptId === void 0 || agent.current.id === attemptId;
29461
+ const onProgress = (update, turnId) => {
29462
+ const agent = agents.get(text3(update["subagent_id"]) ?? "");
29463
+ if (agent === void 0 || !isCurrent(agent, text3(update["attempt_id"]))) return [];
29464
+ const attempt = agent.current;
29465
+ if (attempt.final !== void 0) return [];
29466
+ const tools = Array.isArray(update["tools_used"]) ? update["tools_used"] : [];
29467
+ const lastToolName = text3(tools.at(-1));
29468
+ const usage = usageOf(update);
29469
+ const key = [
29470
+ usage?.totalTokens,
29471
+ usage?.toolUses,
29472
+ count2(update["turn_count"]),
29473
+ lastToolName
29474
+ ].join("|");
29475
+ if (key === attempt.progressKey) return [];
29476
+ attempt.progressKey = key;
29477
+ return [
29478
+ {
29479
+ type: "task.progress",
29480
+ ...attribution(agent, turnId),
29481
+ payload: {
29482
+ ...linkage2(agent),
29483
+ description: attempt.identity.title,
29484
+ ...usage === void 0 ? {} : { typedUsage: usage },
29485
+ ...lastToolName === void 0 ? {} : { lastToolName }
29486
+ }
29487
+ }
29488
+ ];
29489
+ };
29490
+ const onFinished = (update, turnId) => {
29491
+ const id = text3(update["subagent_id"]);
29492
+ const outcome = settled(update["status"]);
29493
+ if (id === void 0 || outcome === void 0) return [];
29494
+ const attemptId = text3(update["attempt_id"]);
29495
+ const reply = replyText(update["output"]);
29496
+ const reason = text3(update["error"]);
29497
+ const final = {
29498
+ outcome,
29499
+ summary: outcome === "completed" ? reply : outcome === "failed" ? reason ?? reply : reason,
29500
+ usage: usageOf(update)
29501
+ };
29502
+ const agent = agents.get(id);
29503
+ if (agent !== void 0) {
29504
+ if (attemptId === void 0 || agent.current.id === attemptId) {
29505
+ return finishCurrent(agent, final, turnId);
29506
+ }
29507
+ if (agent.seen.has(attemptId)) return [];
29508
+ }
29509
+ const key = earlyKey(id, attemptId);
29510
+ const first = earlyFinishes.get(key);
29511
+ earlyFinishes.set(key, { final: mergeFinal(first?.final, final), at: first?.at ?? ++tick });
29512
+ if (earlyFinishes.size > MAX_EARLY_FINISHES) {
29513
+ earlyFinishes.delete(earlyFinishes.keys().next().value);
29514
+ }
29515
+ return [];
29516
+ };
29517
+ const finishCurrent = (agent, final, turnId) => {
29518
+ const attempt = agent.current;
29519
+ const merged = mergeFinal(attempt.final, final);
29520
+ const changed = attempt.final === void 0 || merged.summary !== attempt.final.summary || merged.usage !== attempt.final.usage;
29521
+ attempt.final = merged;
29522
+ return changed ? [completed(agent, merged, turnId)] : [];
29523
+ };
29524
+ const fromEnvelope = (params, ctx) => {
29525
+ const envelope = record3(params);
29526
+ if (record3(envelope["_meta"])["isReplay"] === true) return void 0;
29527
+ const sessionId = text3(envelope["sessionId"]);
29528
+ if (ctx.sessionId !== void 0 && sessionId !== ctx.sessionId) return void 0;
29529
+ const update = record3(envelope["update"]);
29530
+ switch (update["sessionUpdate"]) {
29531
+ case "subagent_spawned":
29532
+ return onSpawned(update, ctx);
29533
+ case "subagent_progress":
29534
+ return onProgress(update, ctx.turnId);
29535
+ case "subagent_finished":
29536
+ return onFinished(update, ctx.turnId);
29537
+ default:
29538
+ return void 0;
29539
+ }
29540
+ };
29541
+ return {
29542
+ onExtensionNotification: (method, params, ctx) => NOTIFICATION_METHODS.has(method.startsWith("_") ? method.slice(1) : method) ? fromEnvelope(params, ctx) : void 0,
29543
+ onSessionUpdate: (notification, ctx) => ctx.foreign ? void 0 : fromEnvelope(notification, ctx),
29544
+ handlesToolCall: (input2) => {
29545
+ if (!spawnCalls.has(input2.toolCallId) && (record3(record3(input2.meta)["x.ai/tool"])["name"] === SPAWN_TOOL || record3(input2.rawInput)["variant"] === "Task")) {
29546
+ spawnCalls.add(input2.toolCallId);
29547
+ }
29548
+ if (!spawnCalls.has(input2.toolCallId)) return false;
29549
+ if (input2.status !== "completed" && input2.status !== "failed") return true;
29550
+ if (input2.status === "failed") return false;
29551
+ const output2 = record3(input2.rawOutput);
29552
+ const ack = typeof output2["text"] === "string" ? SPAWN_ACK_ID.exec(output2["text"]) : null;
29553
+ return output2["type"] === "SubagentCompleted" && text3(output2["subagent_id"]) !== void 0 || output2["type"] === "Text" && ack !== null;
29554
+ },
29555
+ onSessionEnded: () => {
29556
+ const events = [];
29557
+ for (const agent of agents.values()) {
29558
+ if (agent.current.final !== void 0) continue;
29559
+ agent.current.final = { outcome: "stopped", summary: void 0, usage: void 0 };
29560
+ events.push({ type: "task.updated", payload: { ...linkage2(agent), status: "cancelled" } });
29561
+ }
29562
+ return events;
29563
+ }
29564
+ };
29565
+ }
29566
+
28708
29567
  // src/grokSupport.ts
28709
29568
  import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
28710
29569
  var GROK_NATIVE_MODE_BY_RUNTIME_MODE = {
@@ -28917,12 +29776,12 @@ function extractXAiAskUserQuestions(params) {
28917
29776
  var answerValues = (answer) => {
28918
29777
  if (Array.isArray(answer)) {
28919
29778
  return answer.flatMap((entry) => {
28920
- const text4 = trimmed2(entry);
28921
- return text4 === void 0 ? [] : [text4];
29779
+ const text5 = trimmed2(entry);
29780
+ return text5 === void 0 ? [] : [text5];
28922
29781
  });
28923
29782
  }
28924
- const text3 = trimmed2(answer);
28925
- return text3 === void 0 ? [] : [text3];
29783
+ const text4 = trimmed2(answer);
29784
+ return text4 === void 0 ? [] : [text4];
28926
29785
  };
28927
29786
  function makeXAiAskUserQuestionResponse(params, answers) {
28928
29787
  const normalized = params.questions.flatMap((question) => {
@@ -29585,6 +30444,7 @@ var createGrokInstance = (config2, host) => {
29585
30444
  const requestedModelId = modelIdFromSelection(input2.modelSelection);
29586
30445
  let initializeResult;
29587
30446
  const backgroundTasks = /* @__PURE__ */ new Map();
30447
+ const subagents = createGrokSubagents();
29588
30448
  const turnUsage = createGrokTurnUsageCollector(grokPromptSettlement);
29589
30449
  const executor = createAcpExecutor({
29590
30450
  readable,
@@ -29606,6 +30466,7 @@ var createGrokInstance = (config2, host) => {
29606
30466
  authMethodId: resolveGrokAuthMethodId,
29607
30467
  hooks: {
29608
30468
  promptSettlement: turnUsage.settlement,
30469
+ // 派发子 agent 的调用由子 agent 名单接管,不再画成普通工具。
29609
30470
  onToolCallUpdated: (update) => ({
29610
30471
  events: buildGrokBackgroundTaskEvents({
29611
30472
  tasks: backgroundTasks,
@@ -29615,8 +30476,12 @@ var createGrokInstance = (config2, host) => {
29615
30476
  toolCallStatus: update.status,
29616
30477
  turnId: update.turnId
29617
30478
  }),
29618
- artifacts: grokImageArtifacts(update.rawOutput)
30479
+ artifacts: grokImageArtifacts(update.rawOutput),
30480
+ ...subagents.handlesToolCall(update) ? { handled: true } : {}
29619
30481
  }),
30482
+ onExtensionNotification: subagents.onExtensionNotification,
30483
+ onSessionUpdate: subagents.onSessionUpdate,
30484
+ onSessionEnded: subagents.onSessionEnded,
29620
30485
  onExtensionRequest: async (method, params, ctx) => {
29621
30486
  if (XAI_EXIT_PLAN_MODE_METHODS.includes(method)) {
29622
30487
  const plan = parseXAiExitPlanModeParams(params);
@@ -29831,7 +30696,7 @@ var executors = [
29831
30696
  ];
29832
30697
  var index_default = definePlugin({
29833
30698
  id: "agent-grok",
29834
- apiVersion: 48,
30699
+ apiVersion: 49,
29835
30700
  executors,
29836
30701
  activate(ctx) {
29837
30702
  ctx.log.info("grok executor ready");