weacpx 0.4.0-beta.1 → 0.4.0-beta.3

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/cli.js CHANGED
@@ -9477,211 +9477,6 @@ function readVersion(moduleUrl = import.meta.url) {
9477
9477
  var PACKAGE_NAME = "weacpx";
9478
9478
  var init_version = () => {};
9479
9479
 
9480
- // src/formatting/render-text.ts
9481
- function renderAgents(config2) {
9482
- const names = Object.keys(config2.agents);
9483
- if (names.length === 0) {
9484
- return "还没有注册任何 Agent。";
9485
- }
9486
- return ["已注册的 Agent:", ...names.map((name) => `- ${name}`)].join(`
9487
- `);
9488
- }
9489
- function renderWorkspaces(config2) {
9490
- const names = Object.entries(config2.workspaces);
9491
- if (names.length === 0) {
9492
- return "还没有注册任何工作区。";
9493
- }
9494
- return ["已注册的工作区:", ...names.map(([name, workspace]) => `- ${name}: ${workspace.cwd}`)].join(`
9495
- `);
9496
- }
9497
- function renderOrchestrationUnavailable() {
9498
- return "当前未启用任务编排服务。";
9499
- }
9500
- function renderDelegateSuccess(taskId, workerSession) {
9501
- return [`已创建委派任务「${taskId}」`, `worker 会话:${workerSession}`].join(`
9502
- `);
9503
- }
9504
- function renderGroupCreated(group) {
9505
- return [`已创建任务组「${group.groupId}」`, `- 标题:${group.title}`].join(`
9506
- `);
9507
- }
9508
- function renderGroupList(groups) {
9509
- if (groups.length === 0) {
9510
- return "当前协调会话下还没有任务组。";
9511
- }
9512
- return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem(group))].join(`
9513
- `);
9514
- }
9515
- function renderGroupSummary(summary) {
9516
- const { group, tasks } = summary;
9517
- const lines = [
9518
- `任务组「${group.groupId}」`,
9519
- `- 标题:${group.title}`,
9520
- `- 协调会话:${group.coordinatorSession}`,
9521
- `- 总任务数:${summary.totalTasks}`,
9522
- `- 待确认:${summary.pendingApprovalTasks}`,
9523
- `- 运行中:${summary.runningTasks}`,
9524
- `- 已完成:${summary.completedTasks}`,
9525
- `- 已失败:${summary.failedTasks}`,
9526
- `- 已取消:${summary.cancelledTasks}`,
9527
- `- 是否终态:${summary.terminal ? "是" : "否"}`
9528
- ];
9529
- if (group.injectionPending !== undefined) {
9530
- lines.push(`- 注入待处理:${group.injectionPending ? "是" : "否"}`);
9531
- }
9532
- if (group.injectionAppliedAt) {
9533
- lines.push(`- 注入完成时间:${group.injectionAppliedAt}`);
9534
- }
9535
- if (group.lastInjectionError) {
9536
- lines.push(`- 最近注入错误:${group.lastInjectionError}`);
9537
- }
9538
- if (tasks.length > 0) {
9539
- lines.push("- 成员:");
9540
- for (const task of tasks) {
9541
- lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
9542
- }
9543
- }
9544
- return lines.join(`
9545
- `);
9546
- }
9547
- function renderGroupCancelSuccess(input) {
9548
- return [
9549
- `任务组「${input.summary.group.groupId}」已发起取消`,
9550
- `- 已请求取消:${input.cancelledTaskIds.length}`,
9551
- `- 已跳过终态任务:${input.skippedTaskIds.length}`
9552
- ].join(`
9553
- `);
9554
- }
9555
- function renderTaskList(tasks) {
9556
- if (tasks.length === 0) {
9557
- return "当前协调会话下还没有任务。";
9558
- }
9559
- return ["当前协调会话的任务:", ...tasks.map((task) => renderTaskListItem(task))].join(`
9560
- `);
9561
- }
9562
- function renderTaskSummary(task) {
9563
- const header = [
9564
- `任务「${task.taskId}」`,
9565
- `- 状态:${task.status}`,
9566
- `- 协调会话:${task.coordinatorSession}`,
9567
- `- worker 会话:${task.workerSession ?? "未分配"}`,
9568
- `- 目标 Agent:${task.targetAgent}`
9569
- ];
9570
- if (task.role)
9571
- header.push(`- 角色:${task.role}`);
9572
- if (task.groupId)
9573
- header.push(`- 任务组:${task.groupId}`);
9574
- if (task.status === "needs_confirmation") {
9575
- header.push(`- 来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
9576
- }
9577
- header.push(`- 任务:${task.task}`);
9578
- if (task.summary.trim().length > 0)
9579
- header.push(`- 摘要:${task.summary}`);
9580
- if (task.resultText.trim().length > 0)
9581
- header.push(`- 结果:${task.resultText}`);
9582
- const events = [];
9583
- events.push({ at: task.createdAt, event: "created" });
9584
- if (task.workerSession && task.status !== "needs_confirmation") {
9585
- events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
9586
- }
9587
- if (task.lastProgressAt)
9588
- events.push({ at: task.lastProgressAt, event: "last_progress" });
9589
- if (task.cancelRequestedAt)
9590
- events.push({ at: task.cancelRequestedAt, event: "cancel_requested" });
9591
- if (task.cancelCompletedAt)
9592
- events.push({ at: task.cancelCompletedAt, event: "cancel_completed" });
9593
- if (task.lastCancelError)
9594
- events.push({ at: task.updatedAt, event: "cancel_failed", detail: task.lastCancelError });
9595
- if (task.status === "completed")
9596
- events.push({ at: task.updatedAt, event: "completed" });
9597
- if (task.status === "failed")
9598
- events.push({ at: task.updatedAt, event: "failed" });
9599
- if (task.noticeSentAt)
9600
- events.push({ at: task.noticeSentAt, event: "notice_sent", detail: task.deliveryAccountId });
9601
- if (task.lastNoticeError)
9602
- events.push({ at: task.updatedAt, event: "notice_failed", detail: task.lastNoticeError });
9603
- if (task.injectionAppliedAt)
9604
- events.push({ at: task.injectionAppliedAt, event: "injection_applied" });
9605
- if (task.lastInjectionError)
9606
- events.push({ at: task.updatedAt, event: "injection_failed", detail: task.lastInjectionError });
9607
- events.sort((a, b) => a.at.localeCompare(b.at));
9608
- const timeline = events.length > 0 ? ["- 时间线:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
9609
- return [...header, ...timeline].join(`
9610
- `);
9611
- }
9612
- function renderTaskCancelSuccess(task) {
9613
- if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
9614
- return [`任务「${task.taskId}」已结束。`, `- 当前状态:${task.status}`].join(`
9615
- `);
9616
- }
9617
- if (task.cancelRequestedAt) {
9618
- return [`已请求取消任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
9619
- `);
9620
- }
9621
- return [`任务「${task.taskId}」已取消。`, `- 当前状态:${task.status}`].join(`
9622
- `);
9623
- }
9624
- function renderTaskApprovalSuccess(task) {
9625
- return [`已批准任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
9626
- `);
9627
- }
9628
- function renderTaskRejectionSuccess(task) {
9629
- return [`已拒绝任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
9630
- `);
9631
- }
9632
- function renderTaskConfirmationUnavailable(task) {
9633
- return [`任务「${task.taskId}」当前不是待确认状态。`, `- 当前状态:${task.status}`].join(`
9634
- `);
9635
- }
9636
- function renderTasksCleanResult(removedTasks, removedBindings) {
9637
- if (removedTasks === 0 && removedBindings === 0) {
9638
- return "当前协调会话下没有可清理的任务。";
9639
- }
9640
- const lines = [];
9641
- if (removedTasks > 0) {
9642
- lines.push(`已清理 ${removedTasks} 个已结束的任务。`);
9643
- }
9644
- if (removedBindings > 0) {
9645
- lines.push(`已释放 ${removedBindings} 个无效的 worker 绑定。`);
9646
- }
9647
- return lines.join(`
9648
- `);
9649
- }
9650
- function renderTaskListItem(task) {
9651
- const role = task.role ? ` / ${task.role}` : "";
9652
- const group = task.groupId ? `;组:${task.groupId}` : "";
9653
- const summary = task.summary.trim().length > 0 ? `:${task.summary}` : "";
9654
- const source = task.status === "needs_confirmation" ? `;来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}` : "";
9655
- const reliability = [
9656
- task.noticePending ? "通知待重试" : "",
9657
- task.injectionPending ? "注入待重试" : "",
9658
- task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "取消中" : ""
9659
- ].filter(Boolean).map((item) => `;${item}`).join("");
9660
- return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "未分配"}${group}${source}${summary}${reliability}`;
9661
- }
9662
- function renderGroupListItem(group) {
9663
- const reliability = [
9664
- group.group.injectionPending ? "注入待重试" : ""
9665
- ].filter(Boolean).map((item) => `;${item}`).join("");
9666
- return [
9667
- `- ${group.group.groupId}`,
9668
- group.group.title,
9669
- `总计 ${group.totalTasks}`,
9670
- `待确认 ${group.pendingApprovalTasks}`,
9671
- `运行中 ${group.runningTasks}`,
9672
- `完成 ${group.completedTasks}`,
9673
- `失败 ${group.failedTasks}`,
9674
- `取消 ${group.cancelledTasks}${reliability}`
9675
- ].join(" | ");
9676
- }
9677
- function renderTaskProgress(task, summary) {
9678
- return `⏳ 任务「${task.taskId}」(${task.targetAgent}):${summary}`;
9679
- }
9680
- function renderTaskHeartbeat(task, elapsedSeconds) {
9681
- const minutes = Math.floor(elapsedSeconds / 60);
9682
- return `⏳ 任务「${task.taskId}」已运行 ${minutes} 分钟,等待中...`;
9683
- }
9684
-
9685
9480
  // src/orchestration/task-wait-timeouts.ts
9686
9481
  var DEFAULT_TASK_WAIT_TIMEOUT_MS, MAX_TASK_WAIT_TIMEOUT_MS, DEFAULT_TASK_WAIT_POLL_INTERVAL_MS = 1000, MAX_TASK_WAIT_POLL_INTERVAL_MS = 1e4, TASK_WAIT_RPC_TIMEOUT_PADDING_MS = 5000;
9687
9482
  var init_task_wait_timeouts = __esm(() => {
@@ -14358,7 +14153,7 @@ import { dirname as dirname6, join as join3 } from "node:path";
14358
14153
  import { homedir as homedir3 } from "node:os";
14359
14154
  function createWeixinConsumerLock(options = {}) {
14360
14155
  const lockFilePath = options.lockFilePath ?? join3(homedir3(), ".weacpx", "runtime", "weixin-consumer.lock.json");
14361
- const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning3;
14156
+ const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning4;
14362
14157
  const onDiagnostic = options.onDiagnostic;
14363
14158
  return {
14364
14159
  async acquire(meta2) {
@@ -14445,7 +14240,7 @@ async function loadLockMetadata(path13) {
14445
14240
  return null;
14446
14241
  }
14447
14242
  }
14448
- function defaultIsProcessRunning3(pid) {
14243
+ function defaultIsProcessRunning4(pid) {
14449
14244
  try {
14450
14245
  process.kill(pid, 0);
14451
14246
  return true;
@@ -16774,8 +16569,10 @@ async function handleSessionRemove(context, chatKey, alias) {
16774
16569
  return { text: lines.join(`
16775
16570
  `) };
16776
16571
  }
16777
- async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal) {
16572
+ async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent) {
16778
16573
  const effectiveReplyMode = session.replyMode ?? context.config?.channel.replyMode ?? "verbose";
16574
+ if (!session.replyMode)
16575
+ session.replyMode = effectiveReplyMode;
16779
16576
  const transportReply = effectiveReplyMode !== "final" ? reply : undefined;
16780
16577
  if (context.orchestration) {
16781
16578
  try {
@@ -16796,8 +16593,8 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
16796
16593
  }
16797
16594
  const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session, chatKey, text, replyContextToken, accountId);
16798
16595
  try {
16799
- const replyContext = transportReply && context.quota ? { chatKey, quota: context.quota } : undefined;
16800
- const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal);
16596
+ const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
16597
+ const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal, onToolEvent);
16801
16598
  if (claimHumanReply) {
16802
16599
  try {
16803
16600
  await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
@@ -16817,17 +16614,17 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
16817
16614
  throw error2;
16818
16615
  }
16819
16616
  }
16820
- async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal) {
16617
+ async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent) {
16821
16618
  const session = await context.sessions.getCurrentSession(chatKey);
16822
16619
  if (!session) {
16823
16620
  return { text: NO_CURRENT_SESSION_TEXT };
16824
16621
  }
16825
16622
  try {
16826
- return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal);
16623
+ return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
16827
16624
  } catch (error2) {
16828
16625
  const recovered = await context.recovery.tryRecoverMissingSession(session, error2);
16829
16626
  if (recovered) {
16830
- return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal);
16627
+ return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
16831
16628
  }
16832
16629
  return context.recovery.renderTransportError(session, error2);
16833
16630
  }
@@ -16957,6 +16754,211 @@ var init_session_handler = __esm(() => {
16957
16754
  };
16958
16755
  });
16959
16756
 
16757
+ // src/formatting/render-text.ts
16758
+ function renderAgents(config2) {
16759
+ const names = Object.keys(config2.agents);
16760
+ if (names.length === 0) {
16761
+ return "还没有注册任何 Agent。";
16762
+ }
16763
+ return ["已注册的 Agent:", ...names.map((name) => `- ${name}`)].join(`
16764
+ `);
16765
+ }
16766
+ function renderWorkspaces(config2) {
16767
+ const names = Object.entries(config2.workspaces);
16768
+ if (names.length === 0) {
16769
+ return "还没有注册任何工作区。";
16770
+ }
16771
+ return ["已注册的工作区:", ...names.map(([name, workspace]) => `- ${name}: ${workspace.cwd}`)].join(`
16772
+ `);
16773
+ }
16774
+ function renderOrchestrationUnavailable() {
16775
+ return "当前未启用任务编排服务。";
16776
+ }
16777
+ function renderDelegateSuccess2(taskId, workerSession) {
16778
+ return [`已创建委派任务「${taskId}」`, `worker 会话:${workerSession}`].join(`
16779
+ `);
16780
+ }
16781
+ function renderGroupCreated2(group) {
16782
+ return [`已创建任务组「${group.groupId}」`, `- 标题:${group.title}`].join(`
16783
+ `);
16784
+ }
16785
+ function renderGroupList2(groups) {
16786
+ if (groups.length === 0) {
16787
+ return "当前协调会话下还没有任务组。";
16788
+ }
16789
+ return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem2(group))].join(`
16790
+ `);
16791
+ }
16792
+ function renderGroupSummary2(summary) {
16793
+ const { group, tasks } = summary;
16794
+ const lines = [
16795
+ `任务组「${group.groupId}」`,
16796
+ `- 标题:${group.title}`,
16797
+ `- 协调会话:${group.coordinatorSession}`,
16798
+ `- 总任务数:${summary.totalTasks}`,
16799
+ `- 待确认:${summary.pendingApprovalTasks}`,
16800
+ `- 运行中:${summary.runningTasks}`,
16801
+ `- 已完成:${summary.completedTasks}`,
16802
+ `- 已失败:${summary.failedTasks}`,
16803
+ `- 已取消:${summary.cancelledTasks}`,
16804
+ `- 是否终态:${summary.terminal ? "是" : "否"}`
16805
+ ];
16806
+ if (group.injectionPending !== undefined) {
16807
+ lines.push(`- 注入待处理:${group.injectionPending ? "是" : "否"}`);
16808
+ }
16809
+ if (group.injectionAppliedAt) {
16810
+ lines.push(`- 注入完成时间:${group.injectionAppliedAt}`);
16811
+ }
16812
+ if (group.lastInjectionError) {
16813
+ lines.push(`- 最近注入错误:${group.lastInjectionError}`);
16814
+ }
16815
+ if (tasks.length > 0) {
16816
+ lines.push("- 成员:");
16817
+ for (const task of tasks) {
16818
+ lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
16819
+ }
16820
+ }
16821
+ return lines.join(`
16822
+ `);
16823
+ }
16824
+ function renderGroupCancelSuccess2(input) {
16825
+ return [
16826
+ `任务组「${input.summary.group.groupId}」已发起取消`,
16827
+ `- 已请求取消:${input.cancelledTaskIds.length}`,
16828
+ `- 已跳过终态任务:${input.skippedTaskIds.length}`
16829
+ ].join(`
16830
+ `);
16831
+ }
16832
+ function renderTaskList2(tasks) {
16833
+ if (tasks.length === 0) {
16834
+ return "当前协调会话下还没有任务。";
16835
+ }
16836
+ return ["当前协调会话的任务:", ...tasks.map((task) => renderTaskListItem2(task))].join(`
16837
+ `);
16838
+ }
16839
+ function renderTaskSummary2(task) {
16840
+ const header = [
16841
+ `任务「${task.taskId}」`,
16842
+ `- 状态:${task.status}`,
16843
+ `- 协调会话:${task.coordinatorSession}`,
16844
+ `- worker 会话:${task.workerSession ?? "未分配"}`,
16845
+ `- 目标 Agent:${task.targetAgent}`
16846
+ ];
16847
+ if (task.role)
16848
+ header.push(`- 角色:${task.role}`);
16849
+ if (task.groupId)
16850
+ header.push(`- 任务组:${task.groupId}`);
16851
+ if (task.status === "needs_confirmation") {
16852
+ header.push(`- 来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
16853
+ }
16854
+ header.push(`- 任务:${task.task}`);
16855
+ if (task.summary.trim().length > 0)
16856
+ header.push(`- 摘要:${task.summary}`);
16857
+ if (task.resultText.trim().length > 0)
16858
+ header.push(`- 结果:${task.resultText}`);
16859
+ const events = [];
16860
+ events.push({ at: task.createdAt, event: "created" });
16861
+ if (task.workerSession && task.status !== "needs_confirmation") {
16862
+ events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
16863
+ }
16864
+ if (task.lastProgressAt)
16865
+ events.push({ at: task.lastProgressAt, event: "last_progress" });
16866
+ if (task.cancelRequestedAt)
16867
+ events.push({ at: task.cancelRequestedAt, event: "cancel_requested" });
16868
+ if (task.cancelCompletedAt)
16869
+ events.push({ at: task.cancelCompletedAt, event: "cancel_completed" });
16870
+ if (task.lastCancelError)
16871
+ events.push({ at: task.updatedAt, event: "cancel_failed", detail: task.lastCancelError });
16872
+ if (task.status === "completed")
16873
+ events.push({ at: task.updatedAt, event: "completed" });
16874
+ if (task.status === "failed")
16875
+ events.push({ at: task.updatedAt, event: "failed" });
16876
+ if (task.noticeSentAt)
16877
+ events.push({ at: task.noticeSentAt, event: "notice_sent", detail: task.deliveryAccountId });
16878
+ if (task.lastNoticeError)
16879
+ events.push({ at: task.updatedAt, event: "notice_failed", detail: task.lastNoticeError });
16880
+ if (task.injectionAppliedAt)
16881
+ events.push({ at: task.injectionAppliedAt, event: "injection_applied" });
16882
+ if (task.lastInjectionError)
16883
+ events.push({ at: task.updatedAt, event: "injection_failed", detail: task.lastInjectionError });
16884
+ events.sort((a, b) => a.at.localeCompare(b.at));
16885
+ const timeline = events.length > 0 ? ["- 时间线:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
16886
+ return [...header, ...timeline].join(`
16887
+ `);
16888
+ }
16889
+ function renderTaskCancelSuccess(task) {
16890
+ if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
16891
+ return [`任务「${task.taskId}」已结束。`, `- 当前状态:${task.status}`].join(`
16892
+ `);
16893
+ }
16894
+ if (task.cancelRequestedAt) {
16895
+ return [`已请求取消任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
16896
+ `);
16897
+ }
16898
+ return [`任务「${task.taskId}」已取消。`, `- 当前状态:${task.status}`].join(`
16899
+ `);
16900
+ }
16901
+ function renderTaskApprovalSuccess2(task) {
16902
+ return [`已批准任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
16903
+ `);
16904
+ }
16905
+ function renderTaskRejectionSuccess2(task) {
16906
+ return [`已拒绝任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
16907
+ `);
16908
+ }
16909
+ function renderTaskConfirmationUnavailable(task) {
16910
+ return [`任务「${task.taskId}」当前不是待确认状态。`, `- 当前状态:${task.status}`].join(`
16911
+ `);
16912
+ }
16913
+ function renderTasksCleanResult(removedTasks, removedBindings) {
16914
+ if (removedTasks === 0 && removedBindings === 0) {
16915
+ return "当前协调会话下没有可清理的任务。";
16916
+ }
16917
+ const lines = [];
16918
+ if (removedTasks > 0) {
16919
+ lines.push(`已清理 ${removedTasks} 个已结束的任务。`);
16920
+ }
16921
+ if (removedBindings > 0) {
16922
+ lines.push(`已释放 ${removedBindings} 个无效的 worker 绑定。`);
16923
+ }
16924
+ return lines.join(`
16925
+ `);
16926
+ }
16927
+ function renderTaskListItem2(task) {
16928
+ const role = task.role ? ` / ${task.role}` : "";
16929
+ const group = task.groupId ? `;组:${task.groupId}` : "";
16930
+ const summary = task.summary.trim().length > 0 ? `:${task.summary}` : "";
16931
+ const source = task.status === "needs_confirmation" ? `;来源:${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}` : "";
16932
+ const reliability = [
16933
+ task.noticePending ? "通知待重试" : "",
16934
+ task.injectionPending ? "注入待重试" : "",
16935
+ task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "取消中" : ""
16936
+ ].filter(Boolean).map((item) => `;${item}`).join("");
16937
+ return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "未分配"}${group}${source}${summary}${reliability}`;
16938
+ }
16939
+ function renderGroupListItem2(group) {
16940
+ const reliability = [
16941
+ group.group.injectionPending ? "注入待重试" : ""
16942
+ ].filter(Boolean).map((item) => `;${item}`).join("");
16943
+ return [
16944
+ `- ${group.group.groupId}`,
16945
+ group.group.title,
16946
+ `总计 ${group.totalTasks}`,
16947
+ `待确认 ${group.pendingApprovalTasks}`,
16948
+ `运行中 ${group.runningTasks}`,
16949
+ `完成 ${group.completedTasks}`,
16950
+ `失败 ${group.failedTasks}`,
16951
+ `取消 ${group.cancelledTasks}${reliability}`
16952
+ ].join(" | ");
16953
+ }
16954
+ function renderTaskProgress(task, summary) {
16955
+ return `⏳ 任务「${task.taskId}」(${task.targetAgent}):${summary}`;
16956
+ }
16957
+ function renderTaskHeartbeat(task, elapsedSeconds) {
16958
+ const minutes = Math.floor(elapsedSeconds / 60);
16959
+ return `⏳ 任务「${task.taskId}」已运行 ${minutes} 分钟,等待中...`;
16960
+ }
16961
+
16960
16962
  // src/commands/handlers/orchestration-handler.ts
16961
16963
  async function handleDelegateRequest(context, chatKey, targetAgent, task, role, groupId, replyContextToken, accountId) {
16962
16964
  const session = await getCurrentSession(context, chatKey);
@@ -16980,7 +16982,7 @@ async function handleDelegateRequest(context, chatKey, targetAgent, task, role,
16980
16982
  ...replyContextToken ? { replyContextToken } : {},
16981
16983
  ...accountId ? { accountId } : {}
16982
16984
  });
16983
- return { text: renderDelegateSuccess(result.taskId, result.workerSession) };
16985
+ return { text: renderDelegateSuccess2(result.taskId, result.workerSession) };
16984
16986
  }
16985
16987
  async function handleGroupCreate(context, chatKey, title) {
16986
16988
  const session = await getCurrentSession(context, chatKey);
@@ -16995,7 +16997,7 @@ async function handleGroupCreate(context, chatKey, title) {
16995
16997
  coordinatorSession: session.transportSession,
16996
16998
  title
16997
16999
  });
16998
- return { text: renderGroupCreated(group) };
17000
+ return { text: renderGroupCreated2(group) };
16999
17001
  }
17000
17002
  async function handleGroupList(context, chatKey, filter) {
17001
17003
  const session = await getCurrentSession(context, chatKey);
@@ -17010,7 +17012,7 @@ async function handleGroupList(context, chatKey, filter) {
17010
17012
  coordinatorSession: session.transportSession,
17011
17013
  ...filter ?? {}
17012
17014
  });
17013
- return { text: renderGroupList(groups) };
17015
+ return { text: renderGroupList2(groups) };
17014
17016
  }
17015
17017
  async function handleGroupGet(context, chatKey, groupId) {
17016
17018
  const session = await getCurrentSession(context, chatKey);
@@ -17028,7 +17030,7 @@ async function handleGroupGet(context, chatKey, groupId) {
17028
17030
  if (!group) {
17029
17031
  return { text: GROUP_NOT_FOUND_TEXT };
17030
17032
  }
17031
- return { text: renderGroupSummary(group) };
17033
+ return { text: renderGroupSummary2(group) };
17032
17034
  }
17033
17035
  async function handleGroupCancel(context, chatKey, groupId) {
17034
17036
  const session = await getCurrentSession(context, chatKey);
@@ -17050,7 +17052,7 @@ async function handleGroupCancel(context, chatKey, groupId) {
17050
17052
  groupId,
17051
17053
  coordinatorSession: session.transportSession
17052
17054
  });
17053
- return { text: renderGroupCancelSuccess(cancelled) };
17055
+ return { text: renderGroupCancelSuccess2(cancelled) };
17054
17056
  }
17055
17057
  async function handleGroupDelegate(context, chatKey, groupId, targetAgent, task, role, replyContextToken, accountId) {
17056
17058
  const session = await getCurrentSession(context, chatKey);
@@ -17083,7 +17085,7 @@ async function handleTaskList(context, chatKey, filter) {
17083
17085
  coordinatorSession: session.transportSession,
17084
17086
  ...filter ?? {}
17085
17087
  });
17086
- return { text: renderTaskList(tasks) };
17088
+ return { text: renderTaskList2(tasks) };
17087
17089
  }
17088
17090
  async function handleTaskGet(context, chatKey, taskId) {
17089
17091
  const session = await getCurrentSession(context, chatKey);
@@ -17098,7 +17100,7 @@ async function handleTaskGet(context, chatKey, taskId) {
17098
17100
  if (!task || task.coordinatorSession !== session.transportSession) {
17099
17101
  return { text: TASK_NOT_FOUND_TEXT };
17100
17102
  }
17101
- return { text: renderTaskSummary(task) };
17103
+ return { text: renderTaskSummary2(task) };
17102
17104
  }
17103
17105
  async function handleTaskApprove(context, chatKey, taskId) {
17104
17106
  const session = await getCurrentSession(context, chatKey);
@@ -17120,7 +17122,7 @@ async function handleTaskApprove(context, chatKey, taskId) {
17120
17122
  taskId,
17121
17123
  coordinatorSession: session.transportSession
17122
17124
  });
17123
- return { text: renderTaskApprovalSuccess(approved) };
17125
+ return { text: renderTaskApprovalSuccess2(approved) };
17124
17126
  }
17125
17127
  async function handleTaskReject(context, chatKey, taskId) {
17126
17128
  const session = await getCurrentSession(context, chatKey);
@@ -17142,7 +17144,7 @@ async function handleTaskReject(context, chatKey, taskId) {
17142
17144
  taskId,
17143
17145
  coordinatorSession: session.transportSession
17144
17146
  });
17145
- return { text: renderTaskRejectionSuccess(rejected) };
17147
+ return { text: renderTaskRejectionSuccess2(rejected) };
17146
17148
  }
17147
17149
  async function handleTaskCancel(context, chatKey, taskId) {
17148
17150
  const session = await getCurrentSession(context, chatKey);
@@ -18148,7 +18150,7 @@ class CommandRouter {
18148
18150
  this.quota = quota;
18149
18151
  this.logger = logger2 ?? createNoopAppLogger();
18150
18152
  }
18151
- async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal) {
18153
+ async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent) {
18152
18154
  const startedAt = Date.now();
18153
18155
  const command = parseCommand(input);
18154
18156
  await this.logger.debug("command.parsed", "parsed inbound command", {
@@ -18262,7 +18264,7 @@ class CommandRouter {
18262
18264
  case "task.cancel":
18263
18265
  return await handleTaskCancel(this.createHandlerContext(), chatKey, command.taskId);
18264
18266
  case "prompt":
18265
- return await handlePrompt(this.createSessionHandlerContext(), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal);
18267
+ return await handlePrompt(this.createSessionHandlerContext(), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent);
18266
18268
  }
18267
18269
  });
18268
18270
  }
@@ -18314,7 +18316,7 @@ class CommandRouter {
18314
18316
  return {
18315
18317
  setModeTransportSession: (session, modeId) => this.setModeTransportSession(session, modeId),
18316
18318
  cancelTransportSession: (session) => this.cancelTransportSession(session),
18317
- promptTransportSession: (session, text, reply, replyContext, media, abortSignal) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal)
18319
+ promptTransportSession: (session, text, reply, replyContext, media, abortSignal, onToolEvent) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent)
18318
18320
  };
18319
18321
  }
18320
18322
  createSessionRenderRecoveryOps() {
@@ -18477,7 +18479,7 @@ class CommandRouter {
18477
18479
  async checkTransportSession(session) {
18478
18480
  return await this.measureTransportCall("has_session", session, () => this.transport.hasSession(session));
18479
18481
  }
18480
- async promptTransportSession(session, text, reply, replyContext, media, abortSignal) {
18482
+ async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent) {
18481
18483
  session.mcpCoordinatorSession ??= session.transportSession;
18482
18484
  let done = false;
18483
18485
  let cancelOnAbort;
@@ -18514,7 +18516,10 @@ class CommandRouter {
18514
18516
  abortSignal.addEventListener("abort", cancelOnAbort, { once: true });
18515
18517
  }
18516
18518
  try {
18517
- return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext, media ? { media } : undefined));
18519
+ return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext, {
18520
+ ...media ? { media } : {},
18521
+ ...onToolEvent ? { onToolEvent } : {}
18522
+ }));
18518
18523
  } finally {
18519
18524
  done = true;
18520
18525
  if (cancelOnAbort && abortSignal) {
@@ -18665,7 +18670,7 @@ class ConsoleAgent {
18665
18670
  mimeType: m.mimeType,
18666
18671
  ...m.fileName ? { fileName: m.fileName } : {}
18667
18672
  })) : undefined;
18668
- return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal);
18673
+ return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent);
18669
18674
  }
18670
18675
  isKnownCommand(text) {
18671
18676
  return isKnownWeacpxCommandText(text);
@@ -22765,6 +22770,10 @@ function encodeBridgePromptSegmentEvent(event) {
22765
22770
  return `${JSON.stringify(event)}
22766
22771
  `;
22767
22772
  }
22773
+ function encodeBridgePromptToolEvent(event) {
22774
+ return `${JSON.stringify(event)}
22775
+ `;
22776
+ }
22768
22777
  function encodeBridgeSessionProgressEvent(event) {
22769
22778
  return `${JSON.stringify(event)}
22770
22779
  `;
@@ -22832,6 +22841,11 @@ class AcpxBridgeClient {
22832
22841
  type: "prompt.segment",
22833
22842
  text: message.text
22834
22843
  });
22844
+ } else if (message.event === "prompt.tool_event") {
22845
+ pending.onEvent?.({
22846
+ type: "prompt.tool_event",
22847
+ event: message.toolEvent
22848
+ });
22835
22849
  } else if (message.event === "session.progress") {
22836
22850
  pending.onEvent?.({
22837
22851
  type: "session.progress",
@@ -23155,6 +23169,17 @@ var init_quota_gated_reply_sink = __esm(() => {
23155
23169
  ADAPTIVE_WINDOW_SCHEDULE_MS = [3000, 6000, 12000, 24000, 48000, 60000];
23156
23170
  });
23157
23171
 
23172
+ // src/transport/tool-event-mode.ts
23173
+ function resolveToolEventMode(input) {
23174
+ if (input?.toolEventMode !== undefined) {
23175
+ return input.toolEventMode;
23176
+ }
23177
+ if (input?.onToolEvent !== undefined) {
23178
+ return "structured";
23179
+ }
23180
+ return "text";
23181
+ }
23182
+
23158
23183
  // src/transport/acpx-bridge/acpx-bridge-transport.ts
23159
23184
  class AcpxBridgeTransport {
23160
23185
  client;
@@ -23177,10 +23202,18 @@ class AcpxBridgeTransport {
23177
23202
  }) : null;
23178
23203
  let segmentError;
23179
23204
  let segmentChain = Promise.resolve();
23205
+ let toolEventError;
23206
+ let toolEventChain = Promise.resolve();
23207
+ let toolEventMode = resolveToolEventMode(options);
23208
+ if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
23209
+ toolEventMode = "text";
23210
+ }
23180
23211
  const result = await this.client.request("prompt", {
23181
23212
  ...this.toParams(session),
23182
23213
  text,
23183
- ...options?.media ? { media: options.media } : {}
23214
+ ...options?.media ? { media: options.media } : {},
23215
+ ...toolEventMode === "structured" || toolEventMode === "both" ? { toolEvents: true } : {},
23216
+ toolEventMode
23184
23217
  }, (event) => {
23185
23218
  if (event.type === "prompt.segment") {
23186
23219
  const onSegment = options?.onSegment;
@@ -23191,9 +23224,21 @@ class AcpxBridgeTransport {
23191
23224
  });
23192
23225
  }
23193
23226
  sink?.feedSegment(event.text);
23227
+ return;
23228
+ }
23229
+ if (event.type === "prompt.tool_event") {
23230
+ const onToolEvent = options?.onToolEvent;
23231
+ if (onToolEvent) {
23232
+ const toolEvent = event.event;
23233
+ toolEventChain = toolEventChain.then(() => onToolEvent(toolEvent)).catch((error2) => {
23234
+ toolEventError ??= error2;
23235
+ });
23236
+ }
23237
+ return;
23194
23238
  }
23195
23239
  });
23196
23240
  await segmentChain;
23241
+ await toolEventChain;
23197
23242
  if (sink) {
23198
23243
  const { overflowCount } = sink.finalize();
23199
23244
  await sink.drain({ timeoutMs: 30000 });
@@ -23205,6 +23250,9 @@ class AcpxBridgeTransport {
23205
23250
  if (segmentError) {
23206
23251
  throw segmentError;
23207
23252
  }
23253
+ if (toolEventError) {
23254
+ throw toolEventError;
23255
+ }
23208
23256
  return { text: summary ? `${summary}
23209
23257
 
23210
23258
  ${result.text}` : "" };
@@ -23212,6 +23260,9 @@ ${result.text}` : "" };
23212
23260
  if (segmentError) {
23213
23261
  throw segmentError;
23214
23262
  }
23263
+ if (toolEventError) {
23264
+ throw toolEventError;
23265
+ }
23215
23266
  return result;
23216
23267
  }
23217
23268
  async setMode(session, modeId) {
@@ -23244,7 +23295,7 @@ ${result.text}` : "" };
23244
23295
  name: session.transportSession,
23245
23296
  mcpCoordinatorSession: session.mcpCoordinatorSession,
23246
23297
  mcpSourceHandle: session.mcpSourceHandle,
23247
- ...session.replyMode ? { replyMode: session.replyMode } : {}
23298
+ replyMode: session.replyMode ?? "verbose"
23248
23299
  };
23249
23300
  }
23250
23301
  }
@@ -23398,8 +23449,37 @@ var init_prompt_media = __esm(() => {
23398
23449
  };
23399
23450
  });
23400
23451
 
23452
+ // src/transport/tool-kind-emoji.ts
23453
+ var TOOL_KIND_EMOJI, DEFAULT_TOOL_EMOJI;
23454
+ var init_tool_kind_emoji = __esm(() => {
23455
+ TOOL_KIND_EMOJI = {
23456
+ read: "\uD83D\uDCD6",
23457
+ search: "\uD83D\uDD0D",
23458
+ execute: "\uD83D\uDCBB",
23459
+ edit: "✏️",
23460
+ think: "\uD83E\uDDE0",
23461
+ other: "\uD83D\uDD27"
23462
+ };
23463
+ DEFAULT_TOOL_EMOJI = TOOL_KIND_EMOJI.other;
23464
+ });
23465
+
23401
23466
  // src/transport/streaming-prompt.ts
23402
- function createStreamingPromptState(formatToolCalls = false) {
23467
+ function createStreamingPromptState(formatToolCalls = false, options) {
23468
+ let toolEventMode;
23469
+ let onToolEvent;
23470
+ if (options === undefined) {
23471
+ toolEventMode = "text";
23472
+ onToolEvent = undefined;
23473
+ } else if (typeof options === "function") {
23474
+ onToolEvent = options;
23475
+ toolEventMode = "structured";
23476
+ } else {
23477
+ onToolEvent = options.onToolEvent;
23478
+ toolEventMode = resolveToolEventMode({
23479
+ toolEventMode: options.mode,
23480
+ onToolEvent
23481
+ });
23482
+ }
23403
23483
  return {
23404
23484
  buffer: "",
23405
23485
  segments: [],
@@ -23407,6 +23487,8 @@ function createStreamingPromptState(formatToolCalls = false) {
23407
23487
  pendingLine: "",
23408
23488
  formatToolCalls,
23409
23489
  emittedToolCallIds: new Set,
23490
+ toolEventMode,
23491
+ onToolEvent,
23410
23492
  finalize() {
23411
23493
  if (this.pendingLine.trim().length > 0) {
23412
23494
  parseStreamingChunks(this, this.pendingLine);
@@ -23444,15 +23526,24 @@ function parseStreamingChunks(state, line) {
23444
23526
  if (!update)
23445
23527
  return;
23446
23528
  if (state.formatToolCalls && (update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update")) {
23447
- const formatted = formatToolCallEvent(update, update.sessionUpdate);
23448
- if (formatted) {
23449
- const toolCallId = update.toolCallId;
23450
- if (toolCallId) {
23451
- if (state.emittedToolCallIds.has(toolCallId))
23452
- return;
23453
- state.emittedToolCallIds.add(toolCallId);
23529
+ const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
23530
+ const wantsText = state.toolEventMode === "text" || state.toolEventMode === "both";
23531
+ if (wantsStructured && state.onToolEvent) {
23532
+ const toolEvent = buildToolUseEvent(update);
23533
+ if (toolEvent)
23534
+ state.onToolEvent(toolEvent);
23535
+ }
23536
+ if (wantsText) {
23537
+ const formatted = formatToolCallEvent(update, update.sessionUpdate);
23538
+ if (formatted) {
23539
+ const toolCallId = update.toolCallId;
23540
+ if (toolCallId) {
23541
+ if (state.emittedToolCallIds.has(toolCallId))
23542
+ return;
23543
+ state.emittedToolCallIds.add(toolCallId);
23544
+ }
23545
+ state.segments.push(formatted);
23454
23546
  }
23455
- state.segments.push(formatted);
23456
23547
  }
23457
23548
  return;
23458
23549
  }
@@ -23482,27 +23573,71 @@ function formatToolCallEvent(update, sessionUpdate) {
23482
23573
  const title = update.title ?? "";
23483
23574
  if (title.length === 0)
23484
23575
  return null;
23485
- const emoji2 = KIND_EMOJI[kind] ?? "\uD83D\uDD27";
23486
- const command = getToolDisplayCommand(update);
23487
- if (command) {
23488
- return `${emoji2} ${truncateToolDisplay(command)}`;
23489
- }
23490
- if (sessionUpdate === "tool_call_update" || isGenericToolTitle(kind, title))
23576
+ const emoji2 = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
23577
+ const inputSummary = summarizeToolInput(update.rawInput, title);
23578
+ const status = readString(update, "status");
23579
+ if (!inputSummary && status === "pending")
23491
23580
  return null;
23492
- return `${emoji2} ${title}`;
23581
+ if (!inputSummary && isGenericToolTitle(kind, title))
23582
+ return null;
23583
+ const summaryText = inputSummary && inputSummary !== title ? `: ${truncateToolDisplay(inputSummary)}` : "";
23584
+ const statusText = status ? ` (${status})` : "";
23585
+ return `${emoji2} ${title}${statusText}${summaryText}`;
23493
23586
  }
23494
- function getToolDisplayCommand(update) {
23587
+ function buildToolUseEvent(update) {
23495
23588
  if (!update)
23496
23589
  return null;
23497
- const command = update.rawInput?.command;
23498
- if (typeof command === "string" && command.length > 0) {
23499
- return command;
23590
+ const toolCallId = update.toolCallId;
23591
+ if (!toolCallId)
23592
+ return null;
23593
+ const kindRaw = update.kind ?? "";
23594
+ const kind = (() => {
23595
+ switch (kindRaw) {
23596
+ case "read":
23597
+ case "search":
23598
+ case "execute":
23599
+ case "edit":
23600
+ case "think":
23601
+ return kindRaw;
23602
+ default:
23603
+ return "other";
23604
+ }
23605
+ })();
23606
+ const title = (update.title ?? "").trim();
23607
+ const toolName = title || "Tool";
23608
+ const summaryRaw = summarizeToolInput(update.rawInput, title);
23609
+ const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
23610
+ const statusRaw = readString(update, "status");
23611
+ const status = statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : "running";
23612
+ return {
23613
+ toolCallId,
23614
+ toolName,
23615
+ kind,
23616
+ ...summary ? { summary } : {},
23617
+ status
23618
+ };
23619
+ }
23620
+ function summarizeToolInput(rawInput, title = "") {
23621
+ if (rawInput == null)
23622
+ return;
23623
+ if (typeof rawInput === "string" || typeof rawInput === "number" || typeof rawInput === "boolean") {
23624
+ return String(rawInput);
23625
+ }
23626
+ if (!isRecord3(rawInput))
23627
+ return;
23628
+ const taskSummary = summarizeTaskInput(rawInput, title);
23629
+ if (taskSummary)
23630
+ return taskSummary;
23631
+ const command = readFirstString(rawInput, ["command", "cmd", "program"]);
23632
+ const args = readFirstStringArray(rawInput, ["args", "arguments"]);
23633
+ if (command) {
23634
+ return [command, ...args ?? []].join(" ");
23500
23635
  }
23501
- const parsedCmd = update.rawInput?.parsed_cmd;
23502
- if (parsedCmd && parsedCmd.length > 0) {
23636
+ const parsedCmd = rawInput.parsed_cmd;
23637
+ if (Array.isArray(parsedCmd) && parsedCmd.length > 0) {
23503
23638
  const parts = [];
23504
23639
  for (const entry of parsedCmd) {
23505
- if (entry && typeof entry.cmd === "string" && entry.cmd.length > 0) {
23640
+ if (isRecord3(entry) && typeof entry.cmd === "string" && entry.cmd.length > 0) {
23506
23641
  parts.push(entry.cmd);
23507
23642
  }
23508
23643
  }
@@ -23510,7 +23645,62 @@ function getToolDisplayCommand(update) {
23510
23645
  return parts.join(" ");
23511
23646
  }
23512
23647
  }
23513
- return null;
23648
+ return readFirstString(rawInput, [
23649
+ "path",
23650
+ "file",
23651
+ "filePath",
23652
+ "filepath",
23653
+ "file_path",
23654
+ "target",
23655
+ "uri",
23656
+ "url",
23657
+ "query",
23658
+ "pattern",
23659
+ "text",
23660
+ "search",
23661
+ "name",
23662
+ "description"
23663
+ ]);
23664
+ }
23665
+ function summarizeTaskInput(rawInput, title) {
23666
+ const subagentType = readFirstString(rawInput, ["subagent_type", "subagentType", "agent", "agentType"]);
23667
+ const description = readFirstString(rawInput, ["description", "task", "summary"]);
23668
+ if (subagentType && description) {
23669
+ return description === title ? subagentType : `${subagentType}: ${description}`;
23670
+ }
23671
+ if (subagentType)
23672
+ return subagentType;
23673
+ return;
23674
+ }
23675
+ function readFirstString(record3, keys) {
23676
+ for (const key of keys) {
23677
+ const value = record3[key];
23678
+ if (typeof value === "string" && value.trim().length > 0) {
23679
+ return value.trim();
23680
+ }
23681
+ }
23682
+ return;
23683
+ }
23684
+ function readFirstStringArray(record3, keys) {
23685
+ for (const key of keys) {
23686
+ const value = record3[key];
23687
+ if (!Array.isArray(value))
23688
+ continue;
23689
+ const entries = value.map((entry) => typeof entry === "string" && entry.trim().length > 0 ? entry.trim() : undefined).filter((entry) => entry !== undefined);
23690
+ if (entries.length > 0) {
23691
+ return entries;
23692
+ }
23693
+ }
23694
+ return;
23695
+ }
23696
+ function isRecord3(value) {
23697
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23698
+ }
23699
+ function readString(rawInput, key) {
23700
+ if (!isRecord3(rawInput))
23701
+ return;
23702
+ const value = rawInput[key];
23703
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
23514
23704
  }
23515
23705
  function truncateToolDisplay(text) {
23516
23706
  return text.length > 60 ? `${text.slice(0, 57)}...` : text;
@@ -23528,14 +23718,8 @@ function isGenericToolTitle(kind, title) {
23528
23718
  }
23529
23719
  return false;
23530
23720
  }
23531
- var KIND_EMOJI;
23532
23721
  var init_streaming_prompt = __esm(() => {
23533
- KIND_EMOJI = {
23534
- read: "\uD83D\uDCD6",
23535
- search: "\uD83D\uDD0D",
23536
- execute: "\uD83D\uDCBB",
23537
- edit: "✏️"
23538
- };
23722
+ init_tool_kind_emoji();
23539
23723
  });
23540
23724
 
23541
23725
  // src/transport/acpx-cli/node-pty-helper.ts
@@ -23845,7 +24029,8 @@ class AcpxCliTransport {
23845
24029
  runCommand;
23846
24030
  runPtyCommand;
23847
24031
  queueOwnerLauncher;
23848
- constructor(options, runCommand = defaultRunner, runPtyCommand = defaultPtyRunner, queueOwnerLauncher) {
24032
+ streamingHooks;
24033
+ constructor(options, runCommand = defaultRunner, runPtyCommand = defaultPtyRunner, queueOwnerLauncher, streamingHooks = {}) {
23849
24034
  this.command = options.command ?? "acpx";
23850
24035
  this.sessionInitTimeoutMs = options.sessionInitTimeoutMs ?? 120000;
23851
24036
  this.permissionMode = options.permissionMode ?? "approve-all";
@@ -23855,6 +24040,7 @@ class AcpxCliTransport {
23855
24040
  this.queueOwnerLauncher = queueOwnerLauncher ?? new AcpxQueueOwnerLauncher({
23856
24041
  acpxCommand: this.command
23857
24042
  });
24043
+ this.streamingHooks = streamingHooks;
23858
24044
  }
23859
24045
  async ensureSession(session, _onProgress) {
23860
24046
  const args = this.buildArgs(session, [
@@ -23873,9 +24059,13 @@ class AcpxCliTransport {
23873
24059
  const structuredPrompt = await createStructuredPromptFile(text, options?.media);
23874
24060
  const args = this.buildPromptArgs(session, text, structuredPrompt?.filePath);
23875
24061
  try {
23876
- if (reply || options?.onSegment) {
23877
- const formatToolCalls = session.replyMode === "verbose";
23878
- const { result: result2, overflowCount } = await this.runStreamingPrompt(this.command, args, reply, 30000, formatToolCalls, replyContext, options?.onSegment);
24062
+ if (reply || options?.onSegment || options?.onToolEvent) {
24063
+ const formatToolCalls = (session.replyMode ?? "verbose") === "verbose";
24064
+ let toolEventMode = resolveToolEventMode(options);
24065
+ if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
24066
+ toolEventMode = "text";
24067
+ }
24068
+ const { result: result2, overflowCount } = await this.runStreamingPrompt(this.command, args, reply, formatToolCalls, toolEventMode, replyContext, options?.onSegment, options?.onToolEvent);
23879
24069
  const baseText = getPromptText(result2);
23880
24070
  if (!reply) {
23881
24071
  return { text: baseText };
@@ -24012,16 +24202,35 @@ ${baseText}` : "" };
24012
24202
  })
24013
24203
  ]);
24014
24204
  }
24015
- async runStreamingPrompt(command, args, reply, maxSegmentWaitMs = 30000, formatToolCalls = false, replyContext, onSegment) {
24205
+ async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent) {
24206
+ const hooks = this.streamingHooks;
24207
+ const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn8(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
24208
+ const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
24209
+ const clearIntervalFn = hooks.clearIntervalFn ?? ((timer) => clearInterval(timer));
24210
+ const maxSegmentWaitMs = hooks.maxSegmentWaitMs ?? 30000;
24211
+ const flushCheckIntervalMs = hooks.flushCheckIntervalMs ?? 5000;
24212
+ const now = hooks.now ?? (() => Date.now());
24016
24213
  return await new Promise((resolve3, reject) => {
24017
24214
  const spawnSpec = resolveSpawnCommand(command, args);
24018
- const child = spawn8(spawnSpec.command, spawnSpec.args, { stdio: ["ignore", "pipe", "pipe"] });
24215
+ const child = doSpawn(spawnSpec.command, spawnSpec.args);
24019
24216
  let stdout2 = "";
24020
24217
  let stderr = "";
24021
- const state = createStreamingPromptState(formatToolCalls);
24022
- let lastReplyAt = Date.now();
24218
+ let lastReplyAt = now();
24023
24219
  let segmentChain = Promise.resolve();
24024
24220
  let segmentError;
24221
+ let toolEventChain = Promise.resolve();
24222
+ let toolEventError;
24223
+ const userOnToolEvent = onToolEvent;
24224
+ const state = createStreamingPromptState(formatToolCalls, {
24225
+ mode: toolEventMode,
24226
+ ...userOnToolEvent ? {
24227
+ onToolEvent: (event) => {
24228
+ toolEventChain = toolEventChain.then(() => userOnToolEvent(event)).catch((error2) => {
24229
+ toolEventError ??= error2;
24230
+ });
24231
+ }
24232
+ } : {}
24233
+ });
24025
24234
  const sink = reply ? createQuotaGatedReplySink({
24026
24235
  reply,
24027
24236
  ...replyContext ? { replyContext } : {}
@@ -24033,7 +24242,7 @@ ${baseText}` : "" };
24033
24242
  });
24034
24243
  }
24035
24244
  sink?.feedSegment(segment);
24036
- lastReplyAt = Date.now();
24245
+ lastReplyAt = now();
24037
24246
  };
24038
24247
  const flushBuffer = () => {
24039
24248
  const remaining = state.buffer.trim();
@@ -24042,11 +24251,11 @@ ${baseText}` : "" };
24042
24251
  feedSegment(remaining);
24043
24252
  }
24044
24253
  };
24045
- const timer = setInterval(() => {
24046
- if (state.buffer.trim().length > 0 && Date.now() - lastReplyAt >= maxSegmentWaitMs) {
24254
+ const timer = setIntervalFn(() => {
24255
+ if (state.buffer.trim().length > 0 && now() - lastReplyAt >= maxSegmentWaitMs) {
24047
24256
  flushBuffer();
24048
24257
  }
24049
- }, 5000);
24258
+ }, flushCheckIntervalMs);
24050
24259
  child.stdout.setEncoding("utf8");
24051
24260
  child.stdout.on("data", (chunk) => {
24052
24261
  stdout2 += String(chunk);
@@ -24059,11 +24268,11 @@ ${baseText}` : "" };
24059
24268
  stderr += String(chunk);
24060
24269
  });
24061
24270
  child.on("error", (err) => {
24062
- clearInterval(timer);
24271
+ clearIntervalFn(timer);
24063
24272
  reject(err);
24064
24273
  });
24065
24274
  child.on("close", (code) => {
24066
- clearInterval(timer);
24275
+ clearIntervalFn(timer);
24067
24276
  const remaining = state.finalize();
24068
24277
  if (remaining.length > 0) {
24069
24278
  feedSegment(remaining);
@@ -24071,7 +24280,8 @@ ${baseText}` : "" };
24071
24280
  const { overflowCount } = sink?.finalize() ?? { overflowCount: 0 };
24072
24281
  Promise.all([
24073
24282
  sink?.drain({ timeoutMs: 30000 }) ?? Promise.resolve(),
24074
- segmentChain
24283
+ segmentChain,
24284
+ toolEventChain
24075
24285
  ]).then(() => {
24076
24286
  const deferred = sink?.getPendingError();
24077
24287
  if (deferred) {
@@ -24082,6 +24292,10 @@ ${baseText}` : "" };
24082
24292
  reject(segmentError);
24083
24293
  return;
24084
24294
  }
24295
+ if (toolEventError) {
24296
+ reject(toolEventError);
24297
+ return;
24298
+ }
24085
24299
  resolve3({
24086
24300
  result: { code: code ?? 1, stdout: stdout2, stderr },
24087
24301
  overflowCount
@@ -25068,7 +25282,7 @@ async function checkDaemon(options = {}) {
25068
25282
  cliEntryPath: options.cliEntryPath ?? resolveCliEntryPath(),
25069
25283
  cwd: options.cwd ?? process.cwd(),
25070
25284
  env: options.env ?? process.env,
25071
- isProcessRunning: options.isProcessRunning ?? defaultIsProcessRunning4
25285
+ isProcessRunning: options.isProcessRunning ?? defaultIsProcessRunning5
25072
25286
  });
25073
25287
  try {
25074
25288
  const status = await controller.getStatus();
@@ -25139,7 +25353,7 @@ async function checkDaemon(options = {}) {
25139
25353
  };
25140
25354
  }
25141
25355
  }
25142
- function defaultIsProcessRunning4(pid) {
25356
+ function defaultIsProcessRunning5(pid) {
25143
25357
  try {
25144
25358
  process.kill(pid, 0);
25145
25359
  return true;
@@ -38385,7 +38599,7 @@ function buildWeacpxMcpToolRegistry(input) {
38385
38599
  return [
38386
38600
  {
38387
38601
  name: "delegate_request",
38388
- description: `Delegate a subtask to another agent under the current coordinator.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
38602
+ description: `Delegate a subtask to another agent under the current coordinator. Pass an absolute workingDirectory for the worker.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
38389
38603
  inputSchema: exports_external.object({
38390
38604
  targetAgent: exports_external.string().min(1),
38391
38605
  task: exports_external.string().min(1),
@@ -38400,12 +38614,12 @@ function buildWeacpxMcpToolRegistry(input) {
38400
38614
  ...sourceHandle ? { sourceHandle } : {},
38401
38615
  ...input2
38402
38616
  });
38403
- return createSuccessResult(`Delegation task ${result.taskId} is ${result.status}.`, result);
38617
+ return createSuccessResult(renderDelegateSuccess(result), result);
38404
38618
  })
38405
38619
  },
38406
38620
  {
38407
38621
  name: "group_new",
38408
- description: "Create a new task group for the current coordinator.",
38622
+ description: "Create a new task group under the current coordinator.",
38409
38623
  inputSchema: exports_external.object({
38410
38624
  title: exports_external.string().min(1)
38411
38625
  }).strict(),
@@ -38414,12 +38628,12 @@ function buildWeacpxMcpToolRegistry(input) {
38414
38628
  coordinatorSession,
38415
38629
  title: args.title
38416
38630
  });
38417
- return createSuccessResult(`Group ${group.groupId} created (title: ${group.title}).`, group);
38631
+ return createSuccessResult(renderGroupCreated(group), group);
38418
38632
  })
38419
38633
  },
38420
38634
  {
38421
38635
  name: "group_get",
38422
- description: "Fetch a single task group summary for the current coordinator.",
38636
+ description: "Fetch a single task-group summary under the current coordinator.",
38423
38637
  inputSchema: exports_external.object({
38424
38638
  groupId: exports_external.string().min(1)
38425
38639
  }).strict(),
@@ -38433,7 +38647,7 @@ function buildWeacpxMcpToolRegistry(input) {
38433
38647
  },
38434
38648
  {
38435
38649
  name: "group_list",
38436
- description: "List task groups for the current coordinator.",
38650
+ description: "List task groups under the current coordinator.",
38437
38651
  inputSchema: exports_external.object({
38438
38652
  status: groupStatusSchema.optional(),
38439
38653
  stuck: exports_external.boolean().optional(),
@@ -38454,7 +38668,7 @@ function buildWeacpxMcpToolRegistry(input) {
38454
38668
  },
38455
38669
  {
38456
38670
  name: "group_cancel",
38457
- description: "Cancel all unfinished tasks in a task group for the current coordinator.",
38671
+ description: "Cancel all unfinished tasks in a task group under the current coordinator.",
38458
38672
  inputSchema: exports_external.object({
38459
38673
  groupId: exports_external.string().min(1)
38460
38674
  }).strict(),
@@ -38468,7 +38682,7 @@ function buildWeacpxMcpToolRegistry(input) {
38468
38682
  },
38469
38683
  {
38470
38684
  name: "task_get",
38471
- description: "Fetch a single orchestration task for the current coordinator.",
38685
+ description: "Fetch a single task under the current coordinator.",
38472
38686
  inputSchema: exports_external.object({
38473
38687
  taskId: exports_external.string().min(1)
38474
38688
  }).strict(),
@@ -38482,7 +38696,7 @@ function buildWeacpxMcpToolRegistry(input) {
38482
38696
  },
38483
38697
  {
38484
38698
  name: "task_list",
38485
- description: "List orchestration tasks for the current coordinator.",
38699
+ description: "List tasks under the current coordinator.",
38486
38700
  inputSchema: exports_external.object({
38487
38701
  status: taskStatusSchema.optional(),
38488
38702
  stuck: exports_external.boolean().optional(),
@@ -38503,7 +38717,7 @@ function buildWeacpxMcpToolRegistry(input) {
38503
38717
  },
38504
38718
  {
38505
38719
  name: "task_approve",
38506
- description: "Approve a pending orchestration task for the current coordinator.",
38720
+ description: "Approve a pending task under the current coordinator.",
38507
38721
  inputSchema: exports_external.object({
38508
38722
  taskId: exports_external.string().min(1)
38509
38723
  }).strict(),
@@ -38517,7 +38731,7 @@ function buildWeacpxMcpToolRegistry(input) {
38517
38731
  },
38518
38732
  {
38519
38733
  name: "task_reject",
38520
- description: "Reject a pending orchestration task for the current coordinator.",
38734
+ description: "Reject a pending task under the current coordinator.",
38521
38735
  inputSchema: exports_external.object({
38522
38736
  taskId: exports_external.string().min(1)
38523
38737
  }).strict(),
@@ -38531,7 +38745,7 @@ function buildWeacpxMcpToolRegistry(input) {
38531
38745
  },
38532
38746
  {
38533
38747
  name: "task_cancel",
38534
- description: "Request cancellation for an orchestration task under the current coordinator.",
38748
+ description: "Request cancellation for a task under the current coordinator.",
38535
38749
  inputSchema: exports_external.object({
38536
38750
  taskId: exports_external.string().min(1)
38537
38751
  }).strict(),
@@ -38540,12 +38754,12 @@ function buildWeacpxMcpToolRegistry(input) {
38540
38754
  coordinatorSession,
38541
38755
  taskId: args.taskId
38542
38756
  });
38543
- return createSuccessResult(`任务「${task.taskId}」已请求取消。`, task);
38757
+ return createSuccessResult(renderTaskCancelRequest(task), task);
38544
38758
  })
38545
38759
  },
38546
38760
  {
38547
38761
  name: "task_wait",
38548
- description: "Wait for an orchestration task to finish or require attention using a bounded timeout.",
38762
+ description: `Wait for a task to finish or require attention. Defaults: timeout ${DEFAULT_TASK_WAIT_TIMEOUT_MS} ms, poll interval ${DEFAULT_TASK_WAIT_POLL_INTERVAL_MS} ms. Maximums: timeout ${MAX_TASK_WAIT_TIMEOUT_MS} ms, poll interval ${MAX_TASK_WAIT_POLL_INTERVAL_MS} ms.`,
38549
38763
  inputSchema: exports_external.object({
38550
38764
  taskId: exports_external.string().min(1),
38551
38765
  timeoutMs: exports_external.number().int().min(0).max(MAX_TASK_WAIT_TIMEOUT_MS).optional(),
@@ -38561,7 +38775,7 @@ function buildWeacpxMcpToolRegistry(input) {
38561
38775
  },
38562
38776
  {
38563
38777
  name: "worker_raise_question",
38564
- description: "Raise a blocker question for the current bound session.",
38778
+ description: "Raise a blocker question for the current bound worker session.",
38565
38779
  inputSchema: exports_external.object({
38566
38780
  taskId: exports_external.string().min(1),
38567
38781
  question: exports_external.string().min(1),
@@ -38576,8 +38790,7 @@ function buildWeacpxMcpToolRegistry(input) {
38576
38790
  sourceHandle,
38577
38791
  ...args
38578
38792
  });
38579
- return createSuccessResult([`任务「${result.taskId}」已提交 blocker 问题。`, `- questionId:${result.questionId}`].join(`
38580
- `), result);
38793
+ return createSuccessResult(renderWorkerRaiseQuestionSuccess(result), result);
38581
38794
  })
38582
38795
  },
38583
38796
  {
@@ -38593,8 +38806,7 @@ function buildWeacpxMcpToolRegistry(input) {
38593
38806
  coordinatorSession,
38594
38807
  ...args
38595
38808
  });
38596
- return createSuccessResult([`已回答任务「${task.taskId}」的 blocker 问题。`, `- 当前状态:${task.status}`].join(`
38597
- `), task);
38809
+ return createSuccessResult(renderCoordinatorAnswerQuestionSuccess(task), task);
38598
38810
  })
38599
38811
  },
38600
38812
  {
@@ -38610,10 +38822,7 @@ function buildWeacpxMcpToolRegistry(input) {
38610
38822
  coordinatorSession,
38611
38823
  ...args
38612
38824
  });
38613
- const text = result.packageId ? [`已创建 human question package「${result.packageId}」。`, `- 已排队任务:${result.queuedTaskIds.length}`].join(`
38614
- `) : [`问题已加入当前 human question queue。`, `- 已排队任务:${result.queuedTaskIds.length}`].join(`
38615
- `);
38616
- return createSuccessResult(text, result);
38825
+ return createSuccessResult(renderCoordinatorRequestHumanInputSuccess(result), result);
38617
38826
  })
38618
38827
  },
38619
38828
  {
@@ -38630,13 +38839,12 @@ function buildWeacpxMcpToolRegistry(input) {
38630
38839
  coordinatorSession,
38631
38840
  ...args
38632
38841
  });
38633
- return createSuccessResult([`已追加 human package「${result.packageId}」跟进消息。`, `- messageId:${result.messageId}`].join(`
38634
- `), result);
38842
+ return createSuccessResult(renderCoordinatorFollowUpHumanPackageSuccess(result), result);
38635
38843
  })
38636
38844
  },
38637
38845
  {
38638
38846
  name: "coordinator_review_contested_result",
38639
- description: "Review a contested coordinator result under the current coordinator.",
38847
+ description: "Review a contested result under the current coordinator.",
38640
38848
  inputSchema: exports_external.object({
38641
38849
  taskId: exports_external.string().min(1),
38642
38850
  reviewId: exports_external.string().min(1),
@@ -38649,9 +38857,7 @@ function buildWeacpxMcpToolRegistry(input) {
38649
38857
  decision,
38650
38858
  ...rest
38651
38859
  });
38652
- const actionText = decision === "accept" ? "已接受" : "已丢弃";
38653
- return createSuccessResult([`${actionText}任务「${task.taskId}」的 contested result。`, `- 当前状态:${task.status}`].join(`
38654
- `), task);
38860
+ return createSuccessResult(renderCoordinatorReviewContestedResultSuccess(task, decision), task);
38655
38861
  })
38656
38862
  }
38657
38863
  ];
@@ -38702,10 +38908,185 @@ function createErrorResult(message) {
38702
38908
  isError: true
38703
38909
  };
38704
38910
  }
38911
+ function renderDelegateSuccess(result) {
38912
+ return [`Delegation task "${result.taskId}" created.`, `- Status: ${result.status}`].join(`
38913
+ `);
38914
+ }
38915
+ function renderGroupCreated(group) {
38916
+ return [`Task group "${group.groupId}" created.`, `- Title: ${group.title}`].join(`
38917
+ `);
38918
+ }
38919
+ function renderGroupSummary(summary) {
38920
+ const { group, tasks } = summary;
38921
+ const lines = [
38922
+ `Task group "${group.groupId}"`,
38923
+ `- Title: ${group.title}`,
38924
+ `- Coordinator session: ${group.coordinatorSession}`,
38925
+ `- Total tasks: ${summary.totalTasks}`,
38926
+ `- Pending approval: ${summary.pendingApprovalTasks}`,
38927
+ `- Running: ${summary.runningTasks}`,
38928
+ `- Completed: ${summary.completedTasks}`,
38929
+ `- Failed: ${summary.failedTasks}`,
38930
+ `- Cancelled: ${summary.cancelledTasks}`,
38931
+ `- Terminal: ${summary.terminal ? "yes" : "no"}`
38932
+ ];
38933
+ if (group.injectionPending !== undefined) {
38934
+ lines.push(`- Injection pending: ${group.injectionPending ? "yes" : "no"}`);
38935
+ }
38936
+ if (group.injectionAppliedAt) {
38937
+ lines.push(`- Injection completed at: ${group.injectionAppliedAt}`);
38938
+ }
38939
+ if (group.lastInjectionError) {
38940
+ lines.push(`- Last injection error: ${group.lastInjectionError}`);
38941
+ }
38942
+ if (tasks.length > 0) {
38943
+ lines.push("- Members:");
38944
+ for (const task of tasks) {
38945
+ lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
38946
+ }
38947
+ }
38948
+ return lines.join(`
38949
+ `);
38950
+ }
38951
+ function renderGroupList(groups) {
38952
+ if (groups.length === 0) {
38953
+ return "There are no task groups under the current coordinator.";
38954
+ }
38955
+ return ["Task groups for the current coordinator:", ...groups.map((group) => renderGroupListItem(group))].join(`
38956
+ `);
38957
+ }
38958
+ function renderGroupListItem(group) {
38959
+ const reliability = group.group.injectionPending ? " | injection pending" : "";
38960
+ return [
38961
+ `- ${group.group.groupId}`,
38962
+ group.group.title,
38963
+ `total ${group.totalTasks}`,
38964
+ `pending ${group.pendingApprovalTasks}`,
38965
+ `running ${group.runningTasks}`,
38966
+ `completed ${group.completedTasks}`,
38967
+ `failed ${group.failedTasks}`,
38968
+ `cancelled ${group.cancelledTasks}${reliability}`
38969
+ ].join(" | ");
38970
+ }
38971
+ function renderGroupCancelSuccess(input) {
38972
+ return [
38973
+ `Task group "${input.summary.group.groupId}" cancellation requested.`,
38974
+ `- Cancel requested: ${input.cancelledTaskIds.length}`,
38975
+ `- Skipped terminal tasks: ${input.skippedTaskIds.length}`
38976
+ ].join(`
38977
+ `);
38978
+ }
38979
+ function renderTaskList(tasks) {
38980
+ if (tasks.length === 0) {
38981
+ return "There are no tasks under the current coordinator.";
38982
+ }
38983
+ return ["Tasks for the current coordinator:", ...tasks.map((task) => renderTaskListItem(task))].join(`
38984
+ `);
38985
+ }
38986
+ function renderTaskListItem(task) {
38987
+ const role = task.role ? ` / ${task.role}` : "";
38988
+ const group = task.groupId ? `; group: ${task.groupId}` : "";
38989
+ const summary = task.summary.trim().length > 0 ? `: ${task.summary}` : "";
38990
+ const source = task.status === "needs_confirmation" ? `; source: ${task.targetAgent}${task.role ? ` / ${task.role}` : ""}` : "";
38991
+ const reliability = [
38992
+ task.noticePending ? "notice pending retry" : "",
38993
+ task.injectionPending ? "injection pending retry" : "",
38994
+ task.cancelRequestedAt && !task.cancelCompletedAt && task.status === "running" ? "cancelling" : ""
38995
+ ].filter(Boolean).map((item) => `; ${item}`).join("");
38996
+ return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "unassigned"}${group}${source}${summary}${reliability}`;
38997
+ }
38998
+ function renderTaskSummary(task) {
38999
+ const header = [
39000
+ `Task "${task.taskId}"`,
39001
+ `- Status: ${task.status}`,
39002
+ `- Coordinator session: ${task.coordinatorSession}`,
39003
+ `- Worker session: ${task.workerSession ?? "unassigned"}`,
39004
+ `- Target agent: ${task.targetAgent}`
39005
+ ];
39006
+ if (task.role)
39007
+ header.push(`- Role: ${task.role}`);
39008
+ if (task.groupId)
39009
+ header.push(`- Group: ${task.groupId}`);
39010
+ if (task.status === "needs_confirmation") {
39011
+ header.push(`- Source: ${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
39012
+ }
39013
+ header.push(`- Task: ${task.task}`);
39014
+ if (task.summary.trim().length > 0)
39015
+ header.push(`- Summary: ${task.summary}`);
39016
+ if (task.resultText.trim().length > 0)
39017
+ header.push(`- Result: ${task.resultText}`);
39018
+ const events = [];
39019
+ events.push({ at: task.createdAt, event: "created" });
39020
+ if (task.workerSession && task.status !== "needs_confirmation") {
39021
+ events.push({ at: task.createdAt, event: "dispatched", detail: task.workerSession });
39022
+ }
39023
+ if (task.lastProgressAt)
39024
+ events.push({ at: task.lastProgressAt, event: "last progress" });
39025
+ if (task.cancelRequestedAt)
39026
+ events.push({ at: task.cancelRequestedAt, event: "cancel requested" });
39027
+ if (task.cancelCompletedAt)
39028
+ events.push({ at: task.cancelCompletedAt, event: "cancel completed" });
39029
+ if (task.lastCancelError)
39030
+ events.push({ at: task.updatedAt, event: "cancel failed", detail: task.lastCancelError });
39031
+ if (task.status === "completed")
39032
+ events.push({ at: task.updatedAt, event: "completed" });
39033
+ if (task.status === "failed")
39034
+ events.push({ at: task.updatedAt, event: "failed" });
39035
+ if (task.noticeSentAt)
39036
+ events.push({ at: task.noticeSentAt, event: "notice sent", detail: task.deliveryAccountId });
39037
+ if (task.lastNoticeError)
39038
+ events.push({ at: task.updatedAt, event: "notice failed", detail: task.lastNoticeError });
39039
+ if (task.injectionAppliedAt)
39040
+ events.push({ at: task.injectionAppliedAt, event: "injection applied" });
39041
+ if (task.lastInjectionError)
39042
+ events.push({ at: task.updatedAt, event: "injection failed", detail: task.lastInjectionError });
39043
+ events.sort((a, b) => a.at.localeCompare(b.at));
39044
+ const timeline = events.length > 0 ? ["- Timeline:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
39045
+ return [...header, ...timeline].join(`
39046
+ `);
39047
+ }
39048
+ function renderTaskCancelRequest(task) {
39049
+ if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
39050
+ return [`Task "${task.taskId}" has already finished.`, `- Current status: ${task.status}`].join(`
39051
+ `);
39052
+ }
39053
+ return [`Cancellation requested for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
39054
+ `);
39055
+ }
39056
+ function renderTaskApprovalSuccess(task) {
39057
+ return [`Task "${task.taskId}" approved.`, `- Current status: ${task.status}`].join(`
39058
+ `);
39059
+ }
39060
+ function renderTaskRejectionSuccess(task) {
39061
+ return [`Task "${task.taskId}" rejected.`, `- Current status: ${task.status}`].join(`
39062
+ `);
39063
+ }
39064
+ function renderWorkerRaiseQuestionSuccess(task) {
39065
+ return [`Blocker question submitted for task "${task.taskId}".`, `- questionId: ${task.questionId}`].join(`
39066
+ `);
39067
+ }
39068
+ function renderCoordinatorAnswerQuestionSuccess(task) {
39069
+ return [`Answered the blocker question for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
39070
+ `);
39071
+ }
39072
+ function renderCoordinatorRequestHumanInputSuccess(result) {
39073
+ return result.packageId ? [`Created human question package "${result.packageId}".`, `- Queued tasks: ${result.queuedTaskIds.length}`].join(`
39074
+ `) : [`Queued the question in the current human question queue.`, `- Queued tasks: ${result.queuedTaskIds.length}`].join(`
39075
+ `);
39076
+ }
39077
+ function renderCoordinatorFollowUpHumanPackageSuccess(result) {
39078
+ return [`Appended follow-up to human package "${result.packageId}".`, `- messageId: ${result.messageId}`].join(`
39079
+ `);
39080
+ }
39081
+ function renderCoordinatorReviewContestedResultSuccess(task, decision) {
39082
+ const actionText = decision === "accept" ? "Accepted" : "Discarded";
39083
+ return [`${actionText} contested result for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
39084
+ `);
39085
+ }
38705
39086
  function formatToolError(error2) {
38706
39087
  const message = error2 instanceof Error ? error2.message : String(error2);
38707
39088
  if (/ECONNREFUSED|ENOENT|server closed without a response|socket hang up|connect /i.test(message)) {
38708
- return `无法连接到 orchestration daemon:${message}`;
39089
+ return `Failed to connect to the orchestration daemon: ${message}`;
38709
39090
  }
38710
39091
  return message;
38711
39092
  }
@@ -38925,6 +39306,9 @@ function createWeacpxMcpServer(options) {
38925
39306
  return await toolStatePromise;
38926
39307
  }
38927
39308
  toolStatePromise = resolveMcpIdentity(server, options).then((identity) => {
39309
+ if (!options.transport) {
39310
+ throw new Error("weacpx MCP transport is not configured");
39311
+ }
38928
39312
  toolState = buildToolState({
38929
39313
  transport: options.transport,
38930
39314
  coordinatorSession: identity.coordinatorSession,
@@ -38983,8 +39367,84 @@ async function resolveMcpIdentity(server, options) {
38983
39367
  }
38984
39368
  throw new McpError(ErrorCode.InvalidRequest, "weacpx MCP identity is not configured; run through `weacpx mcp-stdio` or provide --coordinator-session");
38985
39369
  }
39370
+ function installMcpStdioShutdownHooks(options) {
39371
+ const platform = options.platform ?? process.platform;
39372
+ const signalSource = options.signalSource ?? process;
39373
+ const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning3;
39374
+ const setIntervalFn = options.setIntervalFn ?? ((callback, ms) => setInterval(callback, ms));
39375
+ const clearIntervalFn = options.clearIntervalFn ?? ((handle) => clearInterval(handle));
39376
+ const parentPid = options.parentPid ?? process.ppid;
39377
+ const parentCheckIntervalMs = options.parentCheckIntervalMs ?? parseParentCheckIntervalMs(process.env.WEACPX_MCP_PARENT_CHECK_INTERVAL_MS);
39378
+ let disposed = false;
39379
+ const triggerShutdown = (reason, context) => {
39380
+ if (disposed)
39381
+ return;
39382
+ options.onDiagnostic?.("mcp.stdio.shutdown", { reason, ...context ?? {} });
39383
+ options.shutdown();
39384
+ };
39385
+ const onStreamEnd = () => triggerShutdown("stdin.end");
39386
+ const onStreamClose = () => triggerShutdown("stdin.close");
39387
+ const onStdinError = (error2) => triggerShutdown("stdin.error", errorContext(error2));
39388
+ const onStdoutError = (error2) => triggerShutdown("stdout.error", errorContext(error2));
39389
+ const onSignal = (signal) => triggerShutdown("signal", { signal });
39390
+ options.stdin.on("end", onStreamEnd);
39391
+ options.stdin.on("close", onStreamClose);
39392
+ options.stdin.on("error", onStdinError);
39393
+ options.stdout.on("error", onStdoutError);
39394
+ const signals = platform === "win32" ? ["SIGINT", "SIGTERM", "SIGBREAK"] : ["SIGINT", "SIGTERM", "SIGHUP"];
39395
+ const signalListeners = signals.map((signal) => ({ signal, listener: () => onSignal(signal) }));
39396
+ for (const { signal, listener } of signalListeners) {
39397
+ signalSource.on(signal, listener);
39398
+ }
39399
+ let parentTimer;
39400
+ if (parentPid > 1 && parentCheckIntervalMs > 0) {
39401
+ parentTimer = setIntervalFn(() => {
39402
+ if (!isProcessRunning(parentPid)) {
39403
+ triggerShutdown("parent_dead", { parentPid });
39404
+ }
39405
+ }, parentCheckIntervalMs);
39406
+ parentTimer.unref?.();
39407
+ }
39408
+ return () => {
39409
+ if (disposed)
39410
+ return;
39411
+ disposed = true;
39412
+ options.stdin.off("end", onStreamEnd);
39413
+ options.stdin.off("close", onStreamClose);
39414
+ options.stdin.off("error", onStdinError);
39415
+ options.stdout.off("error", onStdoutError);
39416
+ for (const { signal, listener } of signalListeners) {
39417
+ signalSource.off(signal, listener);
39418
+ }
39419
+ if (parentTimer) {
39420
+ clearIntervalFn(parentTimer);
39421
+ }
39422
+ };
39423
+ }
39424
+ function parseParentCheckIntervalMs(raw) {
39425
+ if (raw === undefined || raw.trim().length === 0)
39426
+ return 5000;
39427
+ const parsed = Number(raw);
39428
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 5000;
39429
+ }
39430
+ function errorContext(error2) {
39431
+ const record3 = error2;
39432
+ return {
39433
+ ...typeof record3?.code === "string" ? { code: record3.code } : {},
39434
+ ...typeof record3?.message === "string" ? { message: record3.message } : {}
39435
+ };
39436
+ }
39437
+ function defaultIsProcessRunning3(pid) {
39438
+ try {
39439
+ process.kill(pid, 0);
39440
+ return true;
39441
+ } catch (error2) {
39442
+ const code = error2?.code;
39443
+ return code !== "ESRCH";
39444
+ }
39445
+ }
38986
39446
  async function runWeacpxMcpServer(options) {
38987
- const transport = createOrchestrationTransport(options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform));
39447
+ const transport = options.transport ?? createOrchestrationTransport(options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform));
38988
39448
  const server = createWeacpxMcpServer({
38989
39449
  transport,
38990
39450
  ...options.coordinatorSession ? { coordinatorSession: options.coordinatorSession } : {},
@@ -38993,11 +39453,14 @@ async function runWeacpxMcpServer(options) {
38993
39453
  ...options.availableAgents ? { availableAgents: options.availableAgents } : {}
38994
39454
  });
38995
39455
  const stdio = new StdioServerTransport(stdin, stdout);
39456
+ let cleanupShutdownHooks;
38996
39457
  let shuttingDown = false;
38997
39458
  const shutdown = async () => {
38998
39459
  if (shuttingDown)
38999
39460
  return;
39000
39461
  shuttingDown = true;
39462
+ cleanupShutdownHooks?.();
39463
+ options.onDiagnostic?.("mcp.stdio.stopping");
39001
39464
  const forceExit = setTimeout(() => process.exit(0), 3000);
39002
39465
  forceExit.unref();
39003
39466
  try {
@@ -39005,11 +39468,16 @@ async function runWeacpxMcpServer(options) {
39005
39468
  await stdio.close();
39006
39469
  } catch {}
39007
39470
  clearTimeout(forceExit);
39471
+ options.onDiagnostic?.("mcp.stdio.stopped");
39008
39472
  process.exit(0);
39009
39473
  };
39010
- stdin.on("end", () => void shutdown());
39011
- process.on("SIGTERM", () => void shutdown());
39012
- process.on("SIGINT", () => void shutdown());
39474
+ options.onDiagnostic?.("mcp.stdio.start", { parentPid: process.ppid, platform: process.platform });
39475
+ cleanupShutdownHooks = installMcpStdioShutdownHooks({
39476
+ stdin,
39477
+ stdout,
39478
+ shutdown,
39479
+ onDiagnostic: options.onDiagnostic
39480
+ });
39013
39481
  await server.connect(stdio);
39014
39482
  }
39015
39483
  function normalizeInputSchemaJson(schema) {
@@ -40765,6 +41233,7 @@ async function defaultMcpStdio(args, deps = {}) {
40765
41233
  let coordinatorSession;
40766
41234
  let sourceHandle;
40767
41235
  let endpoint;
41236
+ let transport;
40768
41237
  let identityResolver;
40769
41238
  let availableAgents;
40770
41239
  try {
@@ -40773,6 +41242,7 @@ async function defaultMcpStdio(args, deps = {}) {
40773
41242
  const workspace = parseCoordinatorWorkspace(args, process.env);
40774
41243
  endpoint = resolveDefaultOrchestrationEndpoint(process.env, process.platform);
40775
41244
  const client = new OrchestrationClient(endpoint);
41245
+ transport = createOrchestrationTransport(endpoint, { client });
40776
41246
  const runtimePaths = (await init_main().then(() => exports_main)).resolveRuntimePaths();
40777
41247
  await ensureConfigExists(runtimePaths.configPath);
40778
41248
  const config2 = await loadConfig(runtimePaths.configPath);
@@ -40786,7 +41256,7 @@ async function defaultMcpStdio(args, deps = {}) {
40786
41256
  state,
40787
41257
  client
40788
41258
  });
40789
- const eagerIdentity = parsedCoordinatorSession && workspace ? await resolveIdentity({ clientName: undefined, listRoots: async () => [] }) : null;
41259
+ const eagerIdentity = parsedCoordinatorSession ? await resolveIdentity({ clientName: undefined, listRoots: async () => [] }) : null;
40790
41260
  coordinatorSession = eagerIdentity?.coordinatorSession ?? "";
40791
41261
  identityResolver = eagerIdentity ? undefined : resolveIdentity;
40792
41262
  } catch (error2) {
@@ -40795,11 +41265,16 @@ async function defaultMcpStdio(args, deps = {}) {
40795
41265
  return 2;
40796
41266
  }
40797
41267
  await runWeacpxMcpServer({
40798
- endpoint,
41268
+ transport,
40799
41269
  ...coordinatorSession ? { coordinatorSession } : {},
40800
41270
  ...sourceHandle ? { sourceHandle } : {},
40801
41271
  ...identityResolver ? { resolveIdentity: identityResolver } : {},
40802
- ...availableAgents ? { availableAgents } : {}
41272
+ ...availableAgents ? { availableAgents } : {},
41273
+ onDiagnostic: (event, context) => {
41274
+ const suffix = context && Object.keys(context).length > 0 ? ` ${JSON.stringify(context)}` : "";
41275
+ (deps.stderr ?? ((text) => process.stderr.write(text)))(`[weacpx:mcp] ${event}${suffix}
41276
+ `);
41277
+ }
40803
41278
  });
40804
41279
  return 0;
40805
41280
  }