weacpx 0.4.5 → 0.4.8

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
@@ -2201,6 +2201,11 @@ function parseConfig(raw, options = {}) {
2201
2201
  if ("nonInteractivePermissions" in transport && transport.nonInteractivePermissions !== "deny" && transport.nonInteractivePermissions !== "fail") {
2202
2202
  throw new Error("transport.nonInteractivePermissions must be deny or fail");
2203
2203
  }
2204
+ if ("permissionPolicy" in transport && transport.permissionPolicy !== undefined) {
2205
+ if (typeof transport.permissionPolicy !== "string" || transport.permissionPolicy.trim().length === 0) {
2206
+ throw new Error("transport.permissionPolicy must be a non-empty string");
2207
+ }
2208
+ }
2204
2209
  if (!isRecord(raw.agents)) {
2205
2210
  throw new Error("agents must be an object");
2206
2211
  }
@@ -2294,6 +2299,7 @@ function parseConfig(raw, options = {}) {
2294
2299
  transport: {
2295
2300
  ...typeof transport.command === "string" ? { command: transport.command } : {},
2296
2301
  ...typeof transport.sessionInitTimeoutMs === "number" ? { sessionInitTimeoutMs: transport.sessionInitTimeoutMs } : {},
2302
+ ...typeof transport.permissionPolicy === "string" ? { permissionPolicy: transport.permissionPolicy } : {},
2297
2303
  type: transportType,
2298
2304
  permissionMode,
2299
2305
  nonInteractivePermissions
@@ -3096,7 +3102,7 @@ var init_orchestration_ipc = () => {};
3096
3102
  // src/daemon/daemon-files.ts
3097
3103
  import { dirname as dirname4, join as join2 } from "node:path";
3098
3104
  function resolveDaemonPaths(options) {
3099
- const runtimeDir = options.runtimeDir ?? join2(options.home, ".weacpx", "runtime");
3105
+ const runtimeDir = options.runtimeDir ?? (options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : join2(options.home, ".weacpx", "runtime"));
3100
3106
  return {
3101
3107
  runtimeDir,
3102
3108
  pidFile: join2(runtimeDir, "daemon.pid"),
@@ -9617,11 +9623,9 @@ function readVersion(moduleUrl = import.meta.url) {
9617
9623
  var PACKAGE_NAME = "weacpx";
9618
9624
  var init_version = () => {};
9619
9625
 
9620
- // src/orchestration/task-wait-timeouts.ts
9621
- 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, DEFAULT_TASK_WATCH_TIMEOUT_MS = 60000, MAX_TASK_WATCH_TIMEOUT_MS, DEFAULT_TASK_WATCH_POLL_INTERVAL_MS = 1000, MAX_TASK_WATCH_POLL_INTERVAL_MS = 1e4, TASK_WATCH_RPC_TIMEOUT_PADDING_MS = 5000;
9622
- var init_task_wait_timeouts = __esm(() => {
9623
- DEFAULT_TASK_WAIT_TIMEOUT_MS = 5 * 60000;
9624
- MAX_TASK_WAIT_TIMEOUT_MS = 20 * 60000;
9626
+ // src/orchestration/task-watch-timeouts.ts
9627
+ var DEFAULT_TASK_WATCH_TIMEOUT_MS = 60000, MAX_TASK_WATCH_TIMEOUT_MS, DEFAULT_TASK_WATCH_POLL_INTERVAL_MS = 1000, MAX_TASK_WATCH_POLL_INTERVAL_MS = 1e4, TASK_WATCH_RPC_TIMEOUT_PADDING_MS = 5000;
9628
+ var init_task_watch_timeouts = __esm(() => {
9625
9629
  MAX_TASK_WATCH_TIMEOUT_MS = 20 * 60000;
9626
9630
  });
9627
9631
 
@@ -10046,6 +10050,31 @@ function resolveWeixinStateDir() {
10046
10050
  function resolveAccountIndexPath() {
10047
10051
  return path4.join(resolveWeixinStateDir(), "accounts.json");
10048
10052
  }
10053
+ function listAccountFileIds() {
10054
+ const dir = resolveAccountsDir();
10055
+ try {
10056
+ if (!fs3.existsSync(dir))
10057
+ return [];
10058
+ return fs3.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => ({
10059
+ id: entry.name.slice(0, -5),
10060
+ data: readAccountFile(path4.join(dir, entry.name))
10061
+ })).filter((entry) => entry.id.trim() !== "" && Boolean(entry.data?.token?.trim())).map((entry) => entry.id).sort();
10062
+ } catch {
10063
+ return [];
10064
+ }
10065
+ }
10066
+ function uniqueAccountIds(ids) {
10067
+ const seen = new Set;
10068
+ const result = [];
10069
+ for (const raw of ids) {
10070
+ const id = raw.trim();
10071
+ if (!id || seen.has(id))
10072
+ continue;
10073
+ seen.add(id);
10074
+ result.push(id);
10075
+ }
10076
+ return result;
10077
+ }
10049
10078
  function listIndexedWeixinAccountIds() {
10050
10079
  const filePath = resolveAccountIndexPath();
10051
10080
  try {
@@ -10055,7 +10084,7 @@ function listIndexedWeixinAccountIds() {
10055
10084
  const parsed = JSON.parse(raw);
10056
10085
  if (!Array.isArray(parsed))
10057
10086
  return [];
10058
- return parsed.filter((id) => typeof id === "string" && id.trim() !== "");
10087
+ return uniqueAccountIds(parsed.filter((id) => typeof id === "string" && id.trim() !== ""));
10059
10088
  } catch {
10060
10089
  return [];
10061
10090
  }
@@ -10130,7 +10159,10 @@ function clearWeixinAccount(accountId) {
10130
10159
  } catch {}
10131
10160
  }
10132
10161
  function clearAllWeixinAccounts() {
10133
- const ids = listIndexedWeixinAccountIds();
10162
+ const ids = uniqueAccountIds([
10163
+ ...listIndexedWeixinAccountIds(),
10164
+ ...listAccountFileIds()
10165
+ ]);
10134
10166
  for (const id of ids) {
10135
10167
  clearWeixinAccount(id);
10136
10168
  }
@@ -10171,7 +10203,10 @@ function loadConfigRouteTag(accountId) {
10171
10203
  }
10172
10204
  }
10173
10205
  function listWeixinAccountIds() {
10174
- return listIndexedWeixinAccountIds();
10206
+ const indexed = listIndexedWeixinAccountIds();
10207
+ if (indexed.length > 0)
10208
+ return indexed;
10209
+ return listAccountFileIds();
10175
10210
  }
10176
10211
  function resolveWeixinAccount(accountId) {
10177
10212
  const raw = accountId?.trim();
@@ -14019,7 +14054,7 @@ ${buildFinalHeadsUp({
14019
14054
  sendWeixinErrorNotice({
14020
14055
  to,
14021
14056
  contextToken,
14022
- message: `⚠️ 过程失败:${err instanceof Error ? err.message : JSON.stringify(err)}`,
14057
+ message: `⚠️ 执行出错:${err instanceof Error ? err.message : JSON.stringify(err)}`,
14023
14058
  baseUrl: deps.baseUrl,
14024
14059
  token: deps.token,
14025
14060
  errLog: deps.errLog
@@ -15553,8 +15588,12 @@ function extractJsonRpcErrorMessages(output) {
15553
15588
  `).map((line) => line.trim()).filter((line) => line.length > 0).flatMap((line) => {
15554
15589
  try {
15555
15590
  const payload = JSON.parse(line);
15556
- if (typeof payload.error?.message === "string" && payload.error.message.length > 0) {
15557
- return [payload.error.message];
15591
+ const err = payload.error;
15592
+ const dataMsg = typeof err?.data?.message === "string" && err.data.message.length > 0 ? err.data.message : undefined;
15593
+ const baseMsg = typeof err?.message === "string" && err.message.length > 0 ? err.message : undefined;
15594
+ const chosen = dataMsg && dataMsg !== baseMsg ? dataMsg : baseMsg;
15595
+ if (chosen) {
15596
+ return [chosen];
15558
15597
  }
15559
15598
  } catch {
15560
15599
  return [];
@@ -15670,6 +15709,18 @@ function parseCommand(input) {
15670
15709
  return { kind: "workspaces" };
15671
15710
  if (command === "/session" && parts[1] === "reset" && parts.length === 2)
15672
15711
  return { kind: "session.reset" };
15712
+ if (command === "/session" && parts[1] === "tail") {
15713
+ if (parts.length === 2) {
15714
+ return { kind: "session.tail" };
15715
+ }
15716
+ if (parts.length === 3) {
15717
+ const lines = parsePositiveInt(parts[2]);
15718
+ if (lines !== null) {
15719
+ return { kind: "session.tail", lines };
15720
+ }
15721
+ }
15722
+ return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
15723
+ }
15673
15724
  if (command === "/session" && parts[1] === "rm" && parts[2] && parts.length === 3) {
15674
15725
  return { kind: "session.rm", alias: parts[2] };
15675
15726
  }
@@ -15979,6 +16030,16 @@ function tokenizeCommand(input) {
15979
16030
  }
15980
16031
  return tokens;
15981
16032
  }
16033
+ function parsePositiveInt(value) {
16034
+ if (!value)
16035
+ return null;
16036
+ if (!/^\d+$/.test(value))
16037
+ return null;
16038
+ const parsed = Number(value);
16039
+ if (!Number.isFinite(parsed) || parsed <= 0)
16040
+ return null;
16041
+ return parsed;
16042
+ }
15982
16043
  function parseListFilterFlags(parts, validStatuses) {
15983
16044
  const filter = {};
15984
16045
  let i = 1;
@@ -16102,6 +16163,7 @@ var init_command_policy = __esm(() => {
16102
16163
  "agents",
16103
16164
  "workspaces",
16104
16165
  "sessions",
16166
+ "session.tail",
16105
16167
  "status",
16106
16168
  "mode.show",
16107
16169
  "replymode.show",
@@ -16118,6 +16180,7 @@ var init_command_policy = __esm(() => {
16118
16180
  COMMAND_KIND_TO_LABEL = {
16119
16181
  "session.reset": "/clear",
16120
16182
  "session.rm": "/session rm",
16183
+ "session.tail": "/session tail",
16121
16184
  "replymode.set": "/replymode",
16122
16185
  "replymode.reset": "/replymode reset",
16123
16186
  "mode.set": "/mode",
@@ -16254,7 +16317,7 @@ async function handleConfigSet(context, path13, rawValue) {
16254
16317
  return { text: result.error };
16255
16318
  }
16256
16319
  await context.configStore.save(updated);
16257
- if (path13 === "transport.permissionMode" || path13 === "transport.nonInteractivePermissions") {
16320
+ if (path13 === "transport.permissionMode" || path13 === "transport.nonInteractivePermissions" || path13 === "transport.permissionPolicy") {
16258
16321
  try {
16259
16322
  await context.transport.updatePermissionPolicy?.(updated.transport);
16260
16323
  } catch (error2) {
@@ -16301,6 +16364,11 @@ function applySupportedConfigUpdate(config2, path13, rawValue) {
16301
16364
  config2.transport.nonInteractivePermissions = parsed;
16302
16365
  return { renderedValue: parsed };
16303
16366
  }
16367
+ case "transport.permissionPolicy":
16368
+ if (!rawValue.trim())
16369
+ return { error: "transport.permissionPolicy 不能为空。" };
16370
+ config2.transport.permissionPolicy = rawValue;
16371
+ return { renderedValue: rawValue };
16304
16372
  case "logging.level": {
16305
16373
  const parsed = parseEnum(rawValue, ["error", "info", "debug"]);
16306
16374
  if (!parsed)
@@ -16410,6 +16478,7 @@ var init_config_handler = __esm(() => {
16410
16478
  "transport.sessionInitTimeoutMs",
16411
16479
  "transport.permissionMode",
16412
16480
  "transport.nonInteractivePermissions",
16481
+ "transport.permissionPolicy",
16413
16482
  "logging.level",
16414
16483
  "logging.maxSizeBytes",
16415
16484
  "logging.maxFiles",
@@ -16964,6 +17033,15 @@ async function handleCancel(context, chatKey) {
16964
17033
  async function handleSessionReset(context, chatKey) {
16965
17034
  return await context.lifecycle.resetCurrentSession(chatKey);
16966
17035
  }
17036
+ async function handleSessionTail(context, chatKey, lines) {
17037
+ const session = await context.sessions.getCurrentSession(chatKey);
17038
+ if (!session) {
17039
+ return { text: NO_CURRENT_SESSION_TEXT };
17040
+ }
17041
+ const resolvedLines = Math.min(Math.max(lines ?? DEFAULT_SESSION_TAIL_LINES, 1), MAX_SESSION_TAIL_LINES);
17042
+ const result = await context.transport.tailSessionHistory(session, resolvedLines);
17043
+ return { text: result.text };
17044
+ }
16967
17045
  async function handleSessionRemove(context, chatKey, alias) {
16968
17046
  const internalAlias = await context.sessions.resolveAliasForChat(chatKey, alias);
16969
17047
  const session = await context.sessions.getSession(internalAlias);
@@ -17034,7 +17112,7 @@ async function handleSessionRemove(context, chatKey, alias) {
17034
17112
  return { text: lines.join(`
17035
17113
  `) };
17036
17114
  }
17037
- async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, perfSpan) {
17115
+ async function promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan) {
17038
17116
  const effectiveReplyMode = session.replyMode ?? context.config?.channel.replyMode ?? "verbose";
17039
17117
  if (!session.replyMode)
17040
17118
  session.replyMode = effectiveReplyMode;
@@ -17059,7 +17137,7 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
17059
17137
  const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session, chatKey, text, replyContextToken, accountId);
17060
17138
  try {
17061
17139
  const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
17062
- const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, perfSpan);
17140
+ const result = await context.interaction.promptTransportSession(session, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan);
17063
17141
  if (claimHumanReply) {
17064
17142
  try {
17065
17143
  await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
@@ -17079,17 +17157,17 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
17079
17157
  throw error2;
17080
17158
  }
17081
17159
  }
17082
- async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, perfSpan) {
17160
+ async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan) {
17083
17161
  const session = await context.sessions.getCurrentSession(chatKey);
17084
17162
  if (!session) {
17085
17163
  return { text: NO_CURRENT_SESSION_TEXT };
17086
17164
  }
17087
17165
  try {
17088
- return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, perfSpan);
17166
+ return await promptWithSession(context, session, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan);
17089
17167
  } catch (error2) {
17090
17168
  const recovered = await context.recovery.tryRecoverMissingSession(session, error2);
17091
17169
  if (recovered) {
17092
- return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, perfSpan);
17170
+ return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan);
17093
17171
  }
17094
17172
  return context.recovery.renderTransportError(session, error2);
17095
17173
  }
@@ -17156,7 +17234,7 @@ async function markCoordinatorResultsInjectionFailed(context, taskIds, groupIds,
17156
17234
  });
17157
17235
  }
17158
17236
  }
17159
- var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", sessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
17237
+ var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500, sessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
17160
17238
  var init_session_handler = __esm(() => {
17161
17239
  init_build_coordinator_prompt();
17162
17240
  init_channel_scope();
@@ -17171,6 +17249,7 @@ var init_session_handler = __esm(() => {
17171
17249
  { usage: "/ss new <agent> (-d <path> | --ws <name>)", description: "强制新建会话" },
17172
17250
  { usage: "/ss new <alias> -a <name> --ws <name>", description: "按指定配置新建会话" },
17173
17251
  { usage: "/ss attach <alias> -a <name> --ws <name> --name <transport-session>", description: "绑定已有会话" },
17252
+ { usage: "/session tail [N]", description: "补拉当前会话的历史输出(默认 50 行)" },
17174
17253
  { usage: "/session rm <alias>", description: "删除逻辑会话" },
17175
17254
  { usage: "/use <alias>", description: "切换当前会话" },
17176
17255
  { usage: "/session reset 或 /clear", description: "重置当前会话上下文" }
@@ -17243,18 +17322,18 @@ function renderDelegateSuccess2(taskId, workerSession) {
17243
17322
  return [`已创建委派任务「${taskId}」`, `worker 会话:${workerSession}`].join(`
17244
17323
  `);
17245
17324
  }
17246
- function renderGroupCreated2(group) {
17325
+ function renderGroupCreated(group) {
17247
17326
  return [`已创建任务组「${group.groupId}」`, `- 标题:${group.title}`].join(`
17248
17327
  `);
17249
17328
  }
17250
- function renderGroupList2(groups) {
17329
+ function renderGroupList(groups) {
17251
17330
  if (groups.length === 0) {
17252
17331
  return "当前协调会话下还没有任务组。";
17253
17332
  }
17254
- return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem2(group))].join(`
17333
+ return ["当前协调会话的任务组:", ...groups.map((group) => renderGroupListItem(group))].join(`
17255
17334
  `);
17256
17335
  }
17257
- function renderGroupSummary2(summary) {
17336
+ function renderGroupSummary(summary) {
17258
17337
  const { group, tasks } = summary;
17259
17338
  const lines = [
17260
17339
  `任务组「${group.groupId}」`,
@@ -17286,7 +17365,7 @@ function renderGroupSummary2(summary) {
17286
17365
  return lines.join(`
17287
17366
  `);
17288
17367
  }
17289
- function renderGroupCancelSuccess2(input) {
17368
+ function renderGroupCancelSuccess(input) {
17290
17369
  return [
17291
17370
  `任务组「${input.summary.group.groupId}」已发起取消`,
17292
17371
  `- 已请求取消:${input.cancelledTaskIds.length}`,
@@ -17369,7 +17448,7 @@ function renderTaskApprovalSuccess2(task) {
17369
17448
  return [`已批准任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
17370
17449
  `);
17371
17450
  }
17372
- function renderTaskRejectionSuccess2(task) {
17451
+ function renderTaskRejectSuccess(task) {
17373
17452
  return [`已拒绝任务「${task.taskId}」。`, `- 当前状态:${task.status}`].join(`
17374
17453
  `);
17375
17454
  }
@@ -17403,7 +17482,7 @@ function renderTaskListItem2(task) {
17403
17482
  ].filter(Boolean).map((item) => `;${item}`).join("");
17404
17483
  return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "未分配"}${group}${source}${summary}${reliability}`;
17405
17484
  }
17406
- function renderGroupListItem2(group) {
17485
+ function renderGroupListItem(group) {
17407
17486
  const reliability = [
17408
17487
  group.group.injectionPending ? "注入待重试" : ""
17409
17488
  ].filter(Boolean).map((item) => `;${item}`).join("");
@@ -17464,7 +17543,7 @@ async function handleGroupCreate(context, chatKey, title) {
17464
17543
  coordinatorSession: session.transportSession,
17465
17544
  title
17466
17545
  });
17467
- return { text: renderGroupCreated2(group) };
17546
+ return { text: renderGroupCreated(group) };
17468
17547
  }
17469
17548
  async function handleGroupList(context, chatKey, filter) {
17470
17549
  const session = await getCurrentSession(context, chatKey);
@@ -17479,7 +17558,7 @@ async function handleGroupList(context, chatKey, filter) {
17479
17558
  coordinatorSession: session.transportSession,
17480
17559
  ...filter ?? {}
17481
17560
  });
17482
- return { text: renderGroupList2(groups) };
17561
+ return { text: renderGroupList(groups) };
17483
17562
  }
17484
17563
  async function handleGroupGet(context, chatKey, groupId) {
17485
17564
  const session = await getCurrentSession(context, chatKey);
@@ -17497,7 +17576,7 @@ async function handleGroupGet(context, chatKey, groupId) {
17497
17576
  if (!group) {
17498
17577
  return { text: GROUP_NOT_FOUND_TEXT };
17499
17578
  }
17500
- return { text: renderGroupSummary2(group) };
17579
+ return { text: renderGroupSummary(group) };
17501
17580
  }
17502
17581
  async function handleGroupCancel(context, chatKey, groupId) {
17503
17582
  const session = await getCurrentSession(context, chatKey);
@@ -17519,7 +17598,7 @@ async function handleGroupCancel(context, chatKey, groupId) {
17519
17598
  groupId,
17520
17599
  coordinatorSession: session.transportSession
17521
17600
  });
17522
- return { text: renderGroupCancelSuccess2(cancelled) };
17601
+ return { text: renderGroupCancelSuccess(cancelled) };
17523
17602
  }
17524
17603
  async function handleGroupDelegate(context, chatKey, groupId, targetAgent, task, role, replyContextToken, accountId) {
17525
17604
  const session = await getCurrentSession(context, chatKey);
@@ -17607,11 +17686,11 @@ async function handleTaskReject(context, chatKey, taskId) {
17607
17686
  if (task.status !== "needs_confirmation") {
17608
17687
  return { text: renderTaskConfirmationUnavailable(task) };
17609
17688
  }
17610
- const rejected = await orchestration.rejectTask({
17689
+ const rejected = await orchestration.cancelTask({
17611
17690
  taskId,
17612
17691
  coordinatorSession: session.transportSession
17613
17692
  });
17614
- return { text: renderTaskRejectionSuccess2(rejected) };
17693
+ return { text: renderTaskRejectSuccess(rejected) };
17615
17694
  }
17616
17695
  async function handleTaskCancel(context, chatKey, taskId) {
17617
17696
  const session = await getCurrentSession(context, chatKey);
@@ -18593,7 +18672,7 @@ class CommandRouter {
18593
18672
  this.quota = quota;
18594
18673
  this.logger = logger2 ?? createNoopAppLogger();
18595
18674
  }
18596
- async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, perfSpan) {
18675
+ async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan) {
18597
18676
  const startedAt = Date.now();
18598
18677
  const command = parseCommand(input);
18599
18678
  await this.logger.debug("command.parsed", "parsed inbound command", {
@@ -18683,6 +18762,8 @@ class CommandRouter {
18683
18762
  return await handleCancel(this.createSessionHandlerContext(undefined, perfSpan), chatKey);
18684
18763
  case "session.reset":
18685
18764
  return await handleSessionReset(this.createSessionHandlerContext(reply, perfSpan), chatKey);
18765
+ case "session.tail":
18766
+ return await handleSessionTail(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.lines);
18686
18767
  case "session.rm":
18687
18768
  return await handleSessionRemove(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias);
18688
18769
  case "groups":
@@ -18710,7 +18791,7 @@ class CommandRouter {
18710
18791
  case "task.cancel":
18711
18792
  return await handleTaskCancel(this.createHandlerContext(), chatKey, command.taskId);
18712
18793
  case "prompt":
18713
- return await handlePrompt(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, perfSpan);
18794
+ return await handlePrompt(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan);
18714
18795
  }
18715
18796
  });
18716
18797
  }
@@ -18763,7 +18844,7 @@ class CommandRouter {
18763
18844
  return {
18764
18845
  setModeTransportSession: (session, modeId) => this.setModeTransportSession(session, modeId),
18765
18846
  cancelTransportSession: (session) => this.cancelTransportSession(session),
18766
- promptTransportSession: (session, text, reply, replyContext, media, abortSignal, onToolEvent, perfSpanOverride) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, perfSpanOverride ?? perfSpan)
18847
+ promptTransportSession: (session, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride) => this.promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride ?? perfSpan)
18767
18848
  };
18768
18849
  }
18769
18850
  createSessionRenderRecoveryOps() {
@@ -18941,7 +19022,7 @@ class CommandRouter {
18941
19022
  async checkTransportSession(session) {
18942
19023
  return await this.measureTransportCall("has_session", session, () => this.transport.hasSession(session));
18943
19024
  }
18944
- async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, perfSpan) {
19025
+ async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan) {
18945
19026
  session.mcpCoordinatorSession ??= session.transportSession;
18946
19027
  let done = false;
18947
19028
  let abortRequested = false;
@@ -18997,7 +19078,8 @@ class CommandRouter {
18997
19078
  return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext, {
18998
19079
  ...media ? { media } : {},
18999
19080
  ...reply ? { onSegment } : {},
19000
- ...onToolEvent ? { onToolEvent } : {}
19081
+ ...onToolEvent ? { onToolEvent } : {},
19082
+ ...onThought ? { onThought } : {}
19001
19083
  }));
19002
19084
  } catch (error2) {
19003
19085
  localOutcome = isAbortError2(error2) || abortRequested ? "aborted" : "error";
@@ -19163,7 +19245,7 @@ class ConsoleAgent {
19163
19245
  ...m.fileName ? { fileName: m.fileName } : {}
19164
19246
  })) : undefined;
19165
19247
  request.perfSpan?.mark("agent.dispatched");
19166
- return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.perfSpan);
19248
+ return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan);
19167
19249
  }
19168
19250
  isKnownCommand(text) {
19169
19251
  return isKnownWeacpxCommandText(text);
@@ -19309,8 +19391,6 @@ class OrchestrationServer {
19309
19391
  return await this.dispatchTaskGet(params);
19310
19392
  case "task.list":
19311
19393
  return await this.handlers.listTasks(this.parseTaskListFilter(params));
19312
- case "task.wait":
19313
- return await this.handlers.waitTask(this.parseWaitTaskInput(params));
19314
19394
  case "task.watch":
19315
19395
  return await this.handlers.watchTask(this.parseWatchTaskInput(params));
19316
19396
  case "task.approve":
@@ -19319,12 +19399,6 @@ class OrchestrationServer {
19319
19399
  taskId: requireString(params, "taskId"),
19320
19400
  coordinatorSession: requireString(params, "coordinatorSession")
19321
19401
  });
19322
- case "task.reject":
19323
- requireOnlyKeys(params, ["taskId", "coordinatorSession"], "params");
19324
- return await this.handlers.rejectTask({
19325
- taskId: requireString(params, "taskId"),
19326
- coordinatorSession: requireString(params, "coordinatorSession")
19327
- });
19328
19402
  case "task.cancel":
19329
19403
  return await this.handlers.cancelTask(this.parseCancelTaskInput(params));
19330
19404
  case "worker.reply":
@@ -19357,15 +19431,6 @@ class OrchestrationServer {
19357
19431
  ...expectedActivePackageId !== undefined ? { expectedActivePackageId } : {}
19358
19432
  });
19359
19433
  }
19360
- case "coordinator.follow_up_human_package":
19361
- requireOnlyKeys(params, ["coordinatorSession", "packageId", "priorMessageId", "taskQuestions", "promptText"], "params");
19362
- return await this.handlers.coordinatorFollowUpHumanPackage({
19363
- coordinatorSession: requireString(params, "coordinatorSession"),
19364
- packageId: requireString(params, "packageId"),
19365
- priorMessageId: requireString(params, "priorMessageId"),
19366
- taskQuestions: requireTaskQuestions(params, "taskQuestions"),
19367
- promptText: requireString(params, "promptText")
19368
- });
19369
19434
  case "coordinator.review_contested_result":
19370
19435
  requireOnlyKeys(params, ["coordinatorSession", "taskId", "reviewId", "decision"], "params");
19371
19436
  return await this.handlers.coordinatorReviewContestedResult({
@@ -19380,20 +19445,6 @@ class OrchestrationServer {
19380
19445
  coordinatorSession: requireString(params, "coordinatorSession"),
19381
19446
  title: requireString(params, "title")
19382
19447
  });
19383
- case "group.get":
19384
- requireOnlyKeys(params, ["coordinatorSession", "groupId"], "params");
19385
- return await this.handlers.getGroupSummary({
19386
- coordinatorSession: requireString(params, "coordinatorSession"),
19387
- groupId: requireString(params, "groupId")
19388
- });
19389
- case "group.list":
19390
- return await this.handlers.listGroupSummaries(this.parseGroupListFilter(params));
19391
- case "group.cancel":
19392
- requireOnlyKeys(params, ["coordinatorSession", "groupId"], "params");
19393
- return await this.handlers.cancelGroup({
19394
- coordinatorSession: requireString(params, "coordinatorSession"),
19395
- groupId: requireString(params, "groupId")
19396
- });
19397
19448
  default:
19398
19449
  throw new OrchestrationInvalidRequestError(`unsupported orchestration method: ${method}`);
19399
19450
  }
@@ -19488,17 +19539,6 @@ class OrchestrationServer {
19488
19539
  ...resultText !== undefined ? { resultText } : {}
19489
19540
  };
19490
19541
  }
19491
- parseWaitTaskInput(params) {
19492
- requireOnlyKeys(params, ["coordinatorSession", "taskId", "timeoutMs", "pollIntervalMs"], "params");
19493
- const timeoutMs = requireOptionalIntegerInRange(params, "timeoutMs", 0, MAX_TASK_WAIT_TIMEOUT_MS);
19494
- const pollIntervalMs = requireOptionalIntegerInRange(params, "pollIntervalMs", 1, MAX_TASK_WAIT_POLL_INTERVAL_MS);
19495
- return {
19496
- coordinatorSession: requireString(params, "coordinatorSession"),
19497
- taskId: requireString(params, "taskId"),
19498
- ...timeoutMs !== undefined ? { timeoutMs } : {},
19499
- ...pollIntervalMs !== undefined ? { pollIntervalMs } : {}
19500
- };
19501
- }
19502
19542
  parseWatchTaskInput(params) {
19503
19543
  requireOnlyKeys(params, ["coordinatorSession", "taskId", "afterSeq", "mode", "includeProgress", "timeoutMs", "pollIntervalMs"], "params");
19504
19544
  const afterSeq = requireOptionalIntegerInRange(params, "afterSeq", 0, Number.MAX_SAFE_INTEGER);
@@ -19526,20 +19566,6 @@ class OrchestrationServer {
19526
19566
  whatIsNeeded: requireString(params, "whatIsNeeded")
19527
19567
  };
19528
19568
  }
19529
- parseGroupListFilter(params) {
19530
- requireOnlyKeys(params, ["coordinatorSession", "status", "stuck", "sort", "order"], "params");
19531
- const status = requireOptionalEnum(params, "status", ["pending", "running", "terminal"]);
19532
- const stuck = requireOptionalBoolean(params, "stuck");
19533
- const sort = requireOptionalEnum(params, "sort", ["updatedAt", "createdAt"]);
19534
- const order = requireOptionalEnum(params, "order", ["asc", "desc"]);
19535
- return {
19536
- coordinatorSession: requireString(params, "coordinatorSession"),
19537
- ...status !== undefined ? { status } : {},
19538
- ...stuck !== undefined ? { stuck } : {},
19539
- ...sort !== undefined ? { sort } : {},
19540
- ...order !== undefined ? { order } : {}
19541
- };
19542
- }
19543
19569
  async cleanupEndpoint() {
19544
19570
  if (this.endpoint.kind !== "unix") {
19545
19571
  return;
@@ -19750,7 +19776,7 @@ function isServerNotRunningError(error2) {
19750
19776
  var OrchestrationInvalidRequestError, ORCHESTRATION_RPC_METHODS;
19751
19777
  var init_orchestration_server = __esm(() => {
19752
19778
  init_orchestration_ipc();
19753
- init_task_wait_timeouts();
19779
+ init_task_watch_timeouts();
19754
19780
  OrchestrationInvalidRequestError = class OrchestrationInvalidRequestError extends Error {
19755
19781
  };
19756
19782
  ORCHESTRATION_RPC_METHODS = new Set([
@@ -19758,22 +19784,16 @@ var init_orchestration_server = __esm(() => {
19758
19784
  "delegate.request",
19759
19785
  "task.get",
19760
19786
  "task.list",
19761
- "task.wait",
19762
19787
  "task.watch",
19763
19788
  "task.approve",
19764
- "task.reject",
19765
19789
  "task.cancel",
19766
19790
  "worker.reply",
19767
19791
  "worker.raise_question",
19768
19792
  "coordinator.answer_question",
19769
19793
  "coordinator.retract_answer",
19770
19794
  "coordinator.request_human_input",
19771
- "coordinator.follow_up_human_package",
19772
19795
  "coordinator.review_contested_result",
19773
- "group.new",
19774
- "group.get",
19775
- "group.list",
19776
- "group.cancel"
19796
+ "group.new"
19777
19797
  ]);
19778
19798
  });
19779
19799
 
@@ -19950,15 +19970,6 @@ class OrchestrationService {
19950
19970
  this.logEvent("orchestration.group.created", "group created", this.groupContext(group));
19951
19971
  return group;
19952
19972
  }
19953
- async getGroup(groupId) {
19954
- const state = await this.deps.loadState();
19955
- const group = this.ensureGroups(state)[groupId];
19956
- return group ? { ...group } : null;
19957
- }
19958
- async listGroups(coordinatorSession) {
19959
- const state = await this.deps.loadState();
19960
- return Object.values(this.ensureGroups(state)).filter((group) => coordinatorSession === undefined || group.coordinatorSession === coordinatorSession).sort((left, right) => left.createdAt.localeCompare(right.createdAt)).map((group) => ({ ...group }));
19961
- }
19962
19973
  async getGroupSummary(input) {
19963
19974
  const state = await this.deps.loadState();
19964
19975
  const group = this.ensureGroups(state)[input.groupId];
@@ -20597,30 +20608,6 @@ class OrchestrationService {
20597
20608
  const task = state.orchestration.tasks[taskId];
20598
20609
  return task ? { ...task } : null;
20599
20610
  }
20600
- async waitTask(input) {
20601
- const timeoutMs = clampWaitTimeout(input.timeoutMs);
20602
- const pollIntervalMs = clampPollInterval(input.pollIntervalMs);
20603
- const deadline = Date.now() + timeoutMs;
20604
- while (true) {
20605
- const state = await this.deps.loadState();
20606
- const task = state.orchestration.tasks[input.taskId];
20607
- if (!task || task.coordinatorSession !== input.coordinatorSession) {
20608
- return { status: "not_found", task: null };
20609
- }
20610
- const snapshot = { ...task };
20611
- if (isTerminalTaskStatus2(task.status) && task.reviewPending === undefined) {
20612
- return { status: "terminal", task: snapshot };
20613
- }
20614
- if (isAttentionRequiredTask(task)) {
20615
- return { status: "attention_required", task: snapshot };
20616
- }
20617
- const remainingMs = deadline - Date.now();
20618
- if (remainingMs <= 0) {
20619
- return { status: "timeout", task: snapshot };
20620
- }
20621
- await sleep2(Math.min(pollIntervalMs, remainingMs));
20622
- }
20623
- }
20624
20611
  async watchTask(input) {
20625
20612
  const timeoutMs = clampWatchTimeout(input.timeoutMs);
20626
20613
  const pollIntervalMs = clampWatchPollInterval(input.pollIntervalMs);
@@ -21039,88 +21026,6 @@ class OrchestrationService {
21039
21026
  queuedTaskIds: prepared.queuedTaskIds
21040
21027
  };
21041
21028
  }
21042
- async coordinatorFollowUpHumanPackage(input) {
21043
- const promptText = input.promptText.trim();
21044
- if (promptText.length === 0) {
21045
- throw new Error("promptText must be a non-empty string");
21046
- }
21047
- if (input.taskQuestions.length === 0) {
21048
- throw new Error("taskQuestions must contain at least one question");
21049
- }
21050
- const prepared = await this.mutate(async () => {
21051
- const state = await this.deps.loadState();
21052
- if (this.isExternalCoordinatorSession(state, input.coordinatorSession)) {
21053
- throw new Error("human input routing is not configured for external coordinator");
21054
- }
21055
- const coordinatorState = this.ensureCoordinatorQuestionState(state, input.coordinatorSession);
21056
- if (coordinatorState.activePackageId !== input.packageId) {
21057
- throw new Error(`package "${input.packageId}" is not the active package for coordinator "${input.coordinatorSession}"`);
21058
- }
21059
- const packageRecord = this.ensureHumanQuestionPackages(state)[input.packageId];
21060
- if (!packageRecord || packageRecord.status !== "active") {
21061
- throw new Error(`package "${input.packageId}" is not active`);
21062
- }
21063
- const latestMessage = packageRecord.messages.at(-1);
21064
- if (!latestMessage || latestMessage.messageId !== input.priorMessageId) {
21065
- throw new Error(`package "${input.packageId}" latest message is "${latestMessage?.messageId ?? ""}", not "${input.priorMessageId}"`);
21066
- }
21067
- if (!latestMessage.deliveredAt) {
21068
- throw new Error(`package "${input.packageId}" latest message "${latestMessage.messageId}" is not delivered yet`);
21069
- }
21070
- const tasks = input.taskQuestions.map(({ taskId, questionId }) => {
21071
- const task = state.orchestration.tasks[taskId];
21072
- if (!task) {
21073
- throw new Error(`task "${taskId}" does not exist`);
21074
- }
21075
- this.assertCoordinatorOwnership(task, input.coordinatorSession);
21076
- if (!packageRecord.openTaskIds.includes(taskId)) {
21077
- throw new Error(`task "${taskId}" does not belong to active package "${input.packageId}"`);
21078
- }
21079
- this.assertCoordinatorQuestionMatch(task, questionId);
21080
- return task;
21081
- });
21082
- const now = this.deps.now().toISOString();
21083
- const route = this.resolveFrozenPackageMessageRoute(latestMessage);
21084
- const messageId = this.deps.createId();
21085
- const message = {
21086
- messageId,
21087
- kind: "follow_up",
21088
- promptText,
21089
- createdAt: now,
21090
- taskQuestions: input.taskQuestions.map((entry) => ({ ...entry })),
21091
- ...route ? this.serializeFrozenDeliveryRoute(route) : {}
21092
- };
21093
- packageRecord.messages.push(message);
21094
- packageRecord.awaitingReplyMessageId = undefined;
21095
- packageRecord.updatedAt = now;
21096
- for (const task of tasks) {
21097
- task.status = "waiting_for_human";
21098
- task.openQuestion = {
21099
- ...task.openQuestion,
21100
- packageId: input.packageId
21101
- };
21102
- task.updatedAt = now;
21103
- this.appendTaskEvent(task, now, "attention_required", {
21104
- status: "waiting_for_human",
21105
- message: task.openQuestion.question
21106
- });
21107
- this.bumpGroupUpdated(state, task.groupId, now);
21108
- }
21109
- await this.deps.saveState(state);
21110
- return {
21111
- coordinatorSession: input.coordinatorSession,
21112
- packageId: input.packageId,
21113
- messageId,
21114
- promptText,
21115
- route
21116
- };
21117
- });
21118
- await this.deliverHumanQuestionPackageMessage(prepared);
21119
- return {
21120
- packageId: prepared.packageId,
21121
- messageId: prepared.messageId
21122
- };
21123
- }
21124
21029
  async retryHumanQuestionPackageDelivery(input) {
21125
21030
  const prepared = await this.mutate(async () => {
21126
21031
  const state = await this.deps.loadState();
@@ -21760,7 +21665,11 @@ class OrchestrationService {
21760
21665
  return { task: { ...task }, shouldPropagate, closedPackageId: undefined };
21761
21666
  }
21762
21667
  const closedPackageId = this.detachTaskFromQuestionFlows(state, task, now);
21668
+ const wasNeedsConfirmation = task.status === "needs_confirmation";
21763
21669
  task.status = "cancelled";
21670
+ if (wasNeedsConfirmation && task.summary.trim().length === 0) {
21671
+ task.summary = "rejected";
21672
+ }
21764
21673
  task.openQuestion = undefined;
21765
21674
  task.cancelRequestedAt = task.cancelRequestedAt ?? now;
21766
21675
  task.cancelCompletedAt = now;
@@ -21980,29 +21889,6 @@ class OrchestrationService {
21980
21889
  this.logEvent("orchestration.task.approved", "task approved", this.taskContext(prepared.task));
21981
21890
  return prepared.task;
21982
21891
  }
21983
- async rejectTask(input) {
21984
- const task = await this.mutate(async () => {
21985
- const state = await this.deps.loadState();
21986
- const task2 = state.orchestration.tasks[input.taskId];
21987
- if (!task2) {
21988
- throw new Error(`task "${input.taskId}" does not exist`);
21989
- }
21990
- this.assertCoordinatorOwnership(task2, input.coordinatorSession);
21991
- this.assertNeedsConfirmation(task2);
21992
- task2.status = "cancelled";
21993
- task2.summary = "rejected";
21994
- task2.updatedAt = this.deps.now().toISOString();
21995
- this.appendTaskEvent(task2, task2.updatedAt, "status_changed", {
21996
- status: "cancelled",
21997
- summary: "rejected",
21998
- message: "Task rejected"
21999
- });
22000
- await this.deps.saveState(state);
22001
- return { ...task2 };
22002
- });
22003
- this.logEvent("orchestration.task.rejected", "task rejected", this.taskContext(task));
22004
- return task;
22005
- }
22006
21892
  async resolveWorkerSession(input) {
22007
21893
  const role = this.normalizeRole(input.role);
22008
21894
  const reusable = await this.deps.findReusableWorkerSession?.({
@@ -22946,24 +22832,6 @@ function isTerminalTaskStatus2(status) {
22946
22832
  function isAttentionRequiredTask(task) {
22947
22833
  return task.reviewPending !== undefined || task.status === "needs_confirmation" || task.status === "blocked" || task.status === "waiting_for_human";
22948
22834
  }
22949
- function clampWaitTimeout(timeoutMs) {
22950
- if (timeoutMs === undefined) {
22951
- return DEFAULT_TASK_WAIT_TIMEOUT_MS;
22952
- }
22953
- if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
22954
- return 0;
22955
- }
22956
- return Math.min(Math.floor(timeoutMs), MAX_TASK_WAIT_TIMEOUT_MS);
22957
- }
22958
- function clampPollInterval(pollIntervalMs) {
22959
- if (pollIntervalMs === undefined) {
22960
- return DEFAULT_TASK_WAIT_POLL_INTERVAL_MS;
22961
- }
22962
- if (!Number.isFinite(pollIntervalMs) || pollIntervalMs <= 0) {
22963
- return 1;
22964
- }
22965
- return Math.min(Math.floor(pollIntervalMs), MAX_TASK_WAIT_POLL_INTERVAL_MS);
22966
- }
22967
22835
  async function sleep2(ms) {
22968
22836
  await new Promise((resolve3) => setTimeout(resolve3, ms));
22969
22837
  }
@@ -22973,7 +22841,7 @@ function isRequestDelegateInput(input) {
22973
22841
  var MAX_TASK_EVENTS_PER_TASK = 200;
22974
22842
  var init_orchestration_service = __esm(() => {
22975
22843
  init_quota_errors();
22976
- init_task_wait_timeouts();
22844
+ init_task_watch_timeouts();
22977
22845
  });
22978
22846
 
22979
22847
  // src/orchestration/worker-prompts.ts
@@ -23545,6 +23413,10 @@ function encodeBridgePromptToolEvent(event) {
23545
23413
  return `${JSON.stringify(event)}
23546
23414
  `;
23547
23415
  }
23416
+ function encodeBridgePromptThoughtEvent(event) {
23417
+ return `${JSON.stringify(event)}
23418
+ `;
23419
+ }
23548
23420
  function encodeBridgeSessionProgressEvent(event) {
23549
23421
  return `${JSON.stringify(event)}
23550
23422
  `;
@@ -23617,6 +23489,11 @@ class AcpxBridgeClient {
23617
23489
  type: "prompt.tool_event",
23618
23490
  event: message.toolEvent
23619
23491
  });
23492
+ } else if (message.event === "prompt.thought") {
23493
+ pending.onEvent?.({
23494
+ type: "prompt.thought",
23495
+ text: message.text
23496
+ });
23620
23497
  } else if (message.event === "session.progress") {
23621
23498
  pending.onEvent?.({
23622
23499
  type: "session.progress",
@@ -23966,6 +23843,12 @@ class AcpxBridgeTransport {
23966
23843
  }
23967
23844
  } : undefined);
23968
23845
  }
23846
+ async tailSessionHistory(session, lines) {
23847
+ return await this.client.request("tailSessionHistory", {
23848
+ ...this.toParams(session),
23849
+ lines
23850
+ });
23851
+ }
23969
23852
  async prompt(session, text, reply, replyContext, options) {
23970
23853
  const sink = reply ? createQuotaGatedReplySink({
23971
23854
  reply,
@@ -23975,6 +23858,8 @@ class AcpxBridgeTransport {
23975
23858
  let segmentChain = Promise.resolve();
23976
23859
  let toolEventError;
23977
23860
  let toolEventChain = Promise.resolve();
23861
+ let thoughtError;
23862
+ let thoughtChain = Promise.resolve();
23978
23863
  let toolEventMode = resolveToolEventMode(options);
23979
23864
  if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
23980
23865
  toolEventMode = "text";
@@ -24007,9 +23892,20 @@ class AcpxBridgeTransport {
24007
23892
  }
24008
23893
  return;
24009
23894
  }
23895
+ if (event.type === "prompt.thought") {
23896
+ const onThought = options?.onThought;
23897
+ if (onThought) {
23898
+ const thoughtText = event.text;
23899
+ thoughtChain = thoughtChain.then(() => onThought(thoughtText)).catch((error2) => {
23900
+ thoughtError ??= error2;
23901
+ });
23902
+ }
23903
+ return;
23904
+ }
24010
23905
  });
24011
23906
  await segmentChain;
24012
23907
  await toolEventChain;
23908
+ await thoughtChain;
24013
23909
  if (sink) {
24014
23910
  const { overflowCount } = sink.finalize();
24015
23911
  await sink.drain({ timeoutMs: 30000 });
@@ -24024,6 +23920,9 @@ class AcpxBridgeTransport {
24024
23920
  if (toolEventError) {
24025
23921
  throw toolEventError;
24026
23922
  }
23923
+ if (thoughtError) {
23924
+ throw thoughtError;
23925
+ }
24027
23926
  return { text: summary ? `${summary}
24028
23927
 
24029
23928
  ${result.text}` : "" };
@@ -24034,6 +23933,9 @@ ${result.text}` : "" };
24034
23933
  if (toolEventError) {
24035
23934
  throw toolEventError;
24036
23935
  }
23936
+ if (thoughtError) {
23937
+ throw thoughtError;
23938
+ }
24037
23939
  return result;
24038
23940
  }
24039
23941
  async setMode(session, modeId) {
@@ -24238,6 +24140,7 @@ var init_tool_kind_emoji = __esm(() => {
24238
24140
  function createStreamingPromptState(formatToolCalls = false, options) {
24239
24141
  let toolEventMode;
24240
24142
  let onToolEvent;
24143
+ let onThought;
24241
24144
  if (options === undefined) {
24242
24145
  toolEventMode = "text";
24243
24146
  onToolEvent = undefined;
@@ -24246,6 +24149,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
24246
24149
  toolEventMode = "structured";
24247
24150
  } else {
24248
24151
  onToolEvent = options.onToolEvent;
24152
+ onThought = options.onThought;
24249
24153
  toolEventMode = resolveToolEventMode({
24250
24154
  toolEventMode: options.mode,
24251
24155
  onToolEvent
@@ -24260,6 +24164,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
24260
24164
  emittedToolCallIds: new Set,
24261
24165
  toolEventMode,
24262
24166
  onToolEvent,
24167
+ onThought,
24263
24168
  finalize() {
24264
24169
  if (this.pendingLine.trim().length > 0) {
24265
24170
  parseStreamingChunks(this, this.pendingLine);
@@ -24318,6 +24223,14 @@ function parseStreamingChunks(state, line) {
24318
24223
  }
24319
24224
  return;
24320
24225
  }
24226
+ const isThoughtChunk = update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
24227
+ if (isThoughtChunk) {
24228
+ const chunk2 = update.content.text;
24229
+ if (chunk2.length > 0) {
24230
+ state.onThought?.(chunk2);
24231
+ }
24232
+ return;
24233
+ }
24321
24234
  const isMessageChunk = update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
24322
24235
  if (!isMessageChunk)
24323
24236
  return;
@@ -24345,7 +24258,7 @@ function formatToolCallEvent(update, sessionUpdate) {
24345
24258
  if (title.length === 0)
24346
24259
  return null;
24347
24260
  const emoji2 = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
24348
- const inputSummary = summarizeToolInput(update.rawInput, title);
24261
+ const inputSummary = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
24349
24262
  const status = readString(update, "status");
24350
24263
  if (!inputSummary && status === "pending")
24351
24264
  return null;
@@ -24376,15 +24289,23 @@ function buildToolUseEvent(update) {
24376
24289
  })();
24377
24290
  const title = (update.title ?? "").trim();
24378
24291
  const toolName = title || "Tool";
24379
- const summaryRaw = summarizeToolInput(update.rawInput, title);
24292
+ const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
24380
24293
  const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
24381
24294
  const statusRaw = readString(update, "status");
24382
24295
  const status = statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : "running";
24296
+ const rawInput = update.rawInput;
24297
+ const content = update.content;
24298
+ const rawOutput = update.rawOutput;
24299
+ const locations = update.locations;
24383
24300
  return {
24384
24301
  toolCallId,
24385
24302
  toolName,
24386
24303
  kind,
24387
24304
  ...summary ? { summary } : {},
24305
+ ...rawInput !== undefined ? { rawInput } : {},
24306
+ ...content !== undefined ? { content } : {},
24307
+ ...rawOutput !== undefined ? { rawOutput } : {},
24308
+ ...locations !== undefined ? { locations } : {},
24388
24309
  status
24389
24310
  };
24390
24311
  }
@@ -24545,6 +24466,8 @@ function buildQueueOwnerPayload(input) {
24545
24466
  nonInteractivePermissions: input.nonInteractivePermissions,
24546
24467
  ttlMs: input.ttlMs ?? 300000,
24547
24468
  maxQueueDepth: input.maxQueueDepth ?? 16,
24469
+ ...Number.isFinite(input.promptRetries) ? { promptRetries: input.promptRetries } : {},
24470
+ ...input.sessionOptions ? { sessionOptions: input.sessionOptions } : {},
24548
24471
  mcpServers: input.mcpServers
24549
24472
  };
24550
24473
  }
@@ -24797,6 +24720,7 @@ class AcpxCliTransport {
24797
24720
  sessionInitTimeoutMs;
24798
24721
  permissionMode;
24799
24722
  nonInteractivePermissions;
24723
+ permissionPolicy;
24800
24724
  runCommand;
24801
24725
  runPtyCommand;
24802
24726
  queueOwnerLauncher;
@@ -24806,6 +24730,7 @@ class AcpxCliTransport {
24806
24730
  this.sessionInitTimeoutMs = options.sessionInitTimeoutMs ?? 120000;
24807
24731
  this.permissionMode = options.permissionMode ?? "approve-all";
24808
24732
  this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
24733
+ this.permissionPolicy = options.permissionPolicy;
24809
24734
  this.runCommand = runCommand;
24810
24735
  this.runPtyCommand = runPtyCommand;
24811
24736
  this.queueOwnerLauncher = queueOwnerLauncher ?? new AcpxQueueOwnerLauncher({
@@ -24825,18 +24750,38 @@ class AcpxCliTransport {
24825
24750
  timeoutMs: this.sessionInitTimeoutMs
24826
24751
  });
24827
24752
  }
24753
+ async tailSessionHistory(session, lines) {
24754
+ const candidates = [
24755
+ ["sessions", "history", "quiet", "-s", session.transportSession, String(lines)],
24756
+ ["sessions", "history", "quiet", session.transportSession, String(lines)],
24757
+ ["sessions", "history", "-s", session.transportSession, "--tail", String(lines)],
24758
+ ["sessions", "history", session.transportSession, "--tail", String(lines)],
24759
+ ["sessions", "history", "--name", session.transportSession, "--tail", String(lines)]
24760
+ ];
24761
+ let lastResult;
24762
+ for (const tail2 of candidates) {
24763
+ const args = this.buildArgs(session, tail2);
24764
+ const result = await this.runCommandWithTimeout(this.runCommand, args);
24765
+ if (result.code === 0) {
24766
+ return { text: result.stdout.trimEnd() };
24767
+ }
24768
+ lastResult = result;
24769
+ }
24770
+ const detail = lastResult ? normalizeCommandError(lastResult) ?? `command failed with exit code ${lastResult.code}` : "command failed";
24771
+ throw new Error(detail);
24772
+ }
24828
24773
  async prompt(session, text, reply, replyContext, options) {
24829
24774
  await this.launchMcpQueueOwnerIfNeeded(session);
24830
24775
  const structuredPrompt = await createStructuredPromptFile(text, options?.media);
24831
24776
  const args = this.buildPromptArgs(session, text, structuredPrompt?.filePath);
24832
24777
  try {
24833
- if (reply || options?.onSegment || options?.onToolEvent) {
24778
+ if (reply || options?.onSegment || options?.onToolEvent || options?.onThought) {
24834
24779
  const formatToolCalls = (session.replyMode ?? "verbose") === "verbose";
24835
24780
  let toolEventMode = resolveToolEventMode(options);
24836
24781
  if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
24837
24782
  toolEventMode = "text";
24838
24783
  }
24839
- const { result: result2, overflowCount } = await this.runStreamingPrompt(this.command, args, reply, formatToolCalls, toolEventMode, replyContext, options?.onSegment, options?.onToolEvent);
24784
+ const { result: result2, overflowCount } = await this.runStreamingPrompt(this.command, args, reply, formatToolCalls, toolEventMode, replyContext, options?.onSegment, options?.onToolEvent, options?.onThought);
24840
24785
  const baseText = getPromptText(result2);
24841
24786
  if (!reply) {
24842
24787
  return { text: baseText };
@@ -24876,6 +24821,7 @@ ${baseText}` : "" };
24876
24821
  async updatePermissionPolicy(policy) {
24877
24822
  this.permissionMode = policy.permissionMode;
24878
24823
  this.nonInteractivePermissions = policy.nonInteractivePermissions;
24824
+ this.permissionPolicy = policy.permissionPolicy;
24879
24825
  }
24880
24826
  async removeSession(session) {
24881
24827
  const result = await this.runCommand(this.command, this.buildArgs(session, [
@@ -24973,7 +24919,7 @@ ${baseText}` : "" };
24973
24919
  })
24974
24920
  ]);
24975
24921
  }
24976
- async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent) {
24922
+ async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent, onThought) {
24977
24923
  const hooks = this.streamingHooks;
24978
24924
  const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn9(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
24979
24925
  const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
@@ -24991,7 +24937,10 @@ ${baseText}` : "" };
24991
24937
  let segmentError;
24992
24938
  let toolEventChain = Promise.resolve();
24993
24939
  let toolEventError;
24940
+ let thoughtChain = Promise.resolve();
24941
+ let thoughtError;
24994
24942
  const userOnToolEvent = onToolEvent;
24943
+ const userOnThought = onThought;
24995
24944
  const state = createStreamingPromptState(formatToolCalls, {
24996
24945
  mode: toolEventMode,
24997
24946
  ...userOnToolEvent ? {
@@ -25000,6 +24949,13 @@ ${baseText}` : "" };
25000
24949
  toolEventError ??= error2;
25001
24950
  });
25002
24951
  }
24952
+ } : {},
24953
+ ...userOnThought ? {
24954
+ onThought: (chunk) => {
24955
+ thoughtChain = thoughtChain.then(() => userOnThought(chunk)).catch((error2) => {
24956
+ thoughtError ??= error2;
24957
+ });
24958
+ }
25003
24959
  } : {}
25004
24960
  });
25005
24961
  const sink = reply ? createQuotaGatedReplySink({
@@ -25052,7 +25008,8 @@ ${baseText}` : "" };
25052
25008
  Promise.all([
25053
25009
  sink?.drain({ timeoutMs: 30000 }) ?? Promise.resolve(),
25054
25010
  segmentChain,
25055
- toolEventChain
25011
+ toolEventChain,
25012
+ thoughtChain
25056
25013
  ]).then(() => {
25057
25014
  const deferred = sink?.getPendingError();
25058
25015
  if (deferred) {
@@ -25067,6 +25024,10 @@ ${baseText}` : "" };
25067
25024
  reject(toolEventError);
25068
25025
  return;
25069
25026
  }
25027
+ if (thoughtError) {
25028
+ reject(thoughtError);
25029
+ return;
25030
+ }
25070
25031
  resolve3({
25071
25032
  result: { code: code ?? 1, stdout: stdout2, stderr },
25072
25033
  overflowCount
@@ -25107,7 +25068,11 @@ ${baseText}` : "" };
25107
25068
  }
25108
25069
  buildPermissionArgs() {
25109
25070
  const modeFlag = permissionModeToFlag(this.permissionMode);
25110
- return [modeFlag, "--non-interactive-permissions", this.nonInteractivePermissions];
25071
+ const args = [modeFlag, "--non-interactive-permissions", this.nonInteractivePermissions];
25072
+ if (typeof this.permissionPolicy === "string" && this.permissionPolicy.trim().length > 0) {
25073
+ args.push("--permission-policy", this.permissionPolicy);
25074
+ }
25075
+ return args;
25111
25076
  }
25112
25077
  }
25113
25078
  function isMissingAcpxSessionError(stderr, stdout2) {
@@ -26088,7 +26053,11 @@ import { fileURLToPath as fileURLToPath5 } from "node:url";
26088
26053
  import { homedir as homedir10 } from "node:os";
26089
26054
  async function checkDaemon(options = {}) {
26090
26055
  const home = options.home ?? process.env.HOME ?? homedir10();
26091
- const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({ home });
26056
+ const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
26057
+ const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
26058
+ home,
26059
+ ...runtimeDir ? { runtimeDir } : {}
26060
+ });
26092
26061
  const controller = createDaemonController(paths, {
26093
26062
  processExecPath: options.processExecPath ?? process.execPath,
26094
26063
  cliEntryPath: options.cliEntryPath ?? resolveCliEntryPath(),
@@ -26240,7 +26209,11 @@ import { dirname as dirname14 } from "node:path";
26240
26209
  import { homedir as homedir11 } from "node:os";
26241
26210
  async function checkRuntime(options = {}) {
26242
26211
  const home = options.home ?? process.env.HOME ?? homedir11();
26243
- const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({ home });
26212
+ const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
26213
+ const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
26214
+ home,
26215
+ ...runtimeDir ? { runtimeDir } : {}
26216
+ });
26244
26217
  const probe = options.probe ?? createRuntimeFsProbe();
26245
26218
  const platform = options.platform ?? process.platform;
26246
26219
  const checks3 = [
@@ -26803,10 +26776,12 @@ async function runDoctor(options = {}, deps = {}) {
26803
26776
  resolveRuntimePaths: () => runtimePaths
26804
26777
  }));
26805
26778
  checks3.push(await (deps.checkRuntime ?? checkRuntime)({
26806
- home
26779
+ home,
26780
+ configPath: runtimePaths.configPath
26807
26781
  }));
26808
26782
  checks3.push(await (deps.checkDaemon ?? checkDaemon)({
26809
- home
26783
+ home,
26784
+ configPath: runtimePaths.configPath
26810
26785
  }));
26811
26786
  checks3.push(await (deps.checkWechat ?? checkWechat)({
26812
26787
  verbose: options.verbose
@@ -39387,9 +39362,8 @@ function requireHome(env) {
39387
39362
  }
39388
39363
 
39389
39364
  // src/mcp/weacpx-mcp-tools.ts
39390
- init_task_wait_timeouts();
39365
+ init_task_watch_timeouts();
39391
39366
  init_quota_errors();
39392
- var groupStatusSchema = exports_external.enum(["pending", "running", "terminal"]);
39393
39367
  var taskStatusSchema = exports_external.enum([
39394
39368
  "needs_confirmation",
39395
39369
  "running",
@@ -39412,7 +39386,7 @@ function buildWeacpxMcpToolRegistry(input) {
39412
39386
  const tools = [
39413
39387
  {
39414
39388
  name: "delegate_request",
39415
- description: `Delegate a subtask to another agent under the current coordinator. Pass an absolute workingDirectory for the worker. Supports MCP Tasks when the client requests task execution: the tool can return a native task handle immediately, then clients can use tasks/get, tasks/result, tasks/list, and tasks/cancel. For legacy clients, after this returns status=running, keep the returned taskId and use task_get/task_list for non-blocking progress snapshots; call task_wait only when the user explicitly wants you to wait/block until completion or attention is required. If status=needs_confirmation, wait for the user to approve (task_approve / task_reject) and do not call task_wait yet.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
39389
+ description: `Delegate a subtask to another agent under the current coordinator. Pass an absolute workingDirectory for the worker. Supports MCP Tasks when the client requests task execution: the tool can return a native task handle immediately, then clients can use tasks/get, tasks/result, tasks/list, and tasks/cancel.${availableAgents && availableAgents.length > 0 ? ` Available agents: ${availableAgents.join(", ")}.` : ""}`,
39416
39390
  execution: { taskSupport: "optional" },
39417
39391
  inputSchema: exports_external.object({
39418
39392
  targetAgent: exports_external.string().min(1),
@@ -39432,66 +39406,41 @@ function buildWeacpxMcpToolRegistry(input) {
39432
39406
  })
39433
39407
  },
39434
39408
  {
39435
- name: "group_new",
39436
- description: "Create a new task group under the current coordinator. Use to batch multiple delegate_request calls together; pass the resulting groupId on each delegate so they share lifecycle and cancellation.",
39437
- inputSchema: exports_external.object({
39438
- title: exports_external.string().min(1)
39439
- }).strict(),
39440
- handler: async (args) => await asToolResult(async () => {
39441
- const group = await transport.createGroup({
39442
- coordinatorSession,
39443
- title: args.title
39444
- });
39445
- return createSuccessResult(renderGroupCreated(group), group);
39446
- })
39447
- },
39448
- {
39449
- name: "group_get",
39450
- description: "Fetch a single task-group summary under the current coordinator. Use to check aggregate progress when waiting on a batch of delegations.",
39409
+ name: "delegate_batch",
39410
+ description: `Delegate several subtasks at once. Pass a "tasks" array; when it holds 2+ tasks they are bound to one auto-created group, so their results are reported back to you together when the whole batch finishes — one handoff instead of one interruption per task. Use this whenever you have multiple parallel delegations. Returns one result per task in input order; a task that fails to start carries an "error" field and does not abort the rest. Legacy-style only: it does not support MCP task execution — use delegate_request for a single native task handle.`,
39451
39411
  inputSchema: exports_external.object({
39452
- groupId: exports_external.string().min(1)
39412
+ title: exports_external.string().min(1).optional(),
39413
+ tasks: exports_external.array(exports_external.object({
39414
+ targetAgent: exports_external.string().min(1),
39415
+ task: exports_external.string().min(1),
39416
+ workingDirectory: exports_external.string().min(1).optional(),
39417
+ role: exports_external.string().min(1).optional()
39418
+ }).strict()).min(1)
39453
39419
  }).strict(),
39454
39420
  handler: async (args) => await asToolResult(async () => {
39455
- const summary = await transport.getGroup({
39421
+ const { title, tasks } = args;
39422
+ const groupId = tasks.length >= 2 ? (await transport.createGroup({
39456
39423
  coordinatorSession,
39457
- groupId: args.groupId
39458
- });
39459
- return createSuccessResult(summary ? renderGroupSummary(summary) : "Group not found.", { group: summary });
39460
- })
39461
- },
39462
- {
39463
- name: "group_list",
39464
- description: "List task groups under the current coordinator. Use to recover groupIds for an earlier batch.",
39465
- inputSchema: exports_external.object({
39466
- status: groupStatusSchema.optional(),
39467
- stuck: exports_external.boolean().optional(),
39468
- sort: sortSchema.optional(),
39469
- order: orderSchema.optional()
39470
- }).strict(),
39471
- handler: async (args) => await asToolResult(async () => {
39472
- const { status, stuck, sort, order } = args;
39473
- const summaries = await transport.listGroups({
39474
- coordinatorSession,
39475
- ...status !== undefined ? { status } : {},
39476
- ...stuck !== undefined ? { stuck } : {},
39477
- ...sort !== undefined ? { sort } : {},
39478
- ...order !== undefined ? { order } : {}
39479
- });
39480
- return createSuccessResult(renderGroupList(summaries), { groups: summaries });
39481
- })
39482
- },
39483
- {
39484
- name: "group_cancel",
39485
- description: "Cancel all unfinished tasks in a task group under the current coordinator. Use to abort a batch started via group_new + delegate_request.",
39486
- inputSchema: exports_external.object({
39487
- groupId: exports_external.string().min(1)
39488
- }).strict(),
39489
- handler: async (args) => await asToolResult(async () => {
39490
- const result = await transport.cancelGroup({
39491
- coordinatorSession,
39492
- groupId: args.groupId
39493
- });
39494
- return createSuccessResult(renderGroupCancelSuccess(result), result);
39424
+ title: title ?? `Batch delegation (${tasks.length} tasks)`
39425
+ })).groupId : undefined;
39426
+ const results = [];
39427
+ for (const [index, entry] of tasks.entries()) {
39428
+ try {
39429
+ const result = await transport.delegateRequest({
39430
+ coordinatorSession,
39431
+ ...sourceHandle ? { sourceHandle } : {},
39432
+ targetAgent: entry.targetAgent,
39433
+ task: entry.task,
39434
+ ...entry.workingDirectory ? { workingDirectory: entry.workingDirectory } : {},
39435
+ ...entry.role ? { role: entry.role } : {},
39436
+ ...groupId ? { groupId } : {}
39437
+ });
39438
+ results.push({ index, taskId: result.taskId, status: result.status });
39439
+ } catch (error2) {
39440
+ results.push({ index, error: formatToolError(error2) });
39441
+ }
39442
+ }
39443
+ return createSuccessResult(renderDelegateBatchSuccess(groupId, results), { ...groupId ? { groupId } : {}, tasks: results });
39495
39444
  })
39496
39445
  },
39497
39446
  {
@@ -39531,7 +39480,7 @@ function buildWeacpxMcpToolRegistry(input) {
39531
39480
  },
39532
39481
  {
39533
39482
  name: "task_approve",
39534
- description: "Approve a pending task under the current coordinator. Use when delegate_request returned status=needs_confirmation and the user has authorized it; after approval, use task_get/task_list for snapshots or task_wait only if intentionally blocking.",
39483
+ description: "Approve a task that delegate_request returned as needs_confirmation, once the user has authorized it. The task then starts running.",
39535
39484
  inputSchema: exports_external.object({
39536
39485
  taskId: exports_external.string().min(1)
39537
39486
  }).strict(),
@@ -39543,23 +39492,9 @@ function buildWeacpxMcpToolRegistry(input) {
39543
39492
  return createSuccessResult(renderTaskApprovalSuccess(task), task);
39544
39493
  })
39545
39494
  },
39546
- {
39547
- name: "task_reject",
39548
- description: "Reject a pending task under the current coordinator. Use when delegate_request returned status=needs_confirmation and the user declined; no task_wait is needed afterwards.",
39549
- inputSchema: exports_external.object({
39550
- taskId: exports_external.string().min(1)
39551
- }).strict(),
39552
- handler: async (args) => await asToolResult(async () => {
39553
- const task = await transport.rejectTask({
39554
- coordinatorSession,
39555
- taskId: args.taskId
39556
- });
39557
- return createSuccessResult(renderTaskRejectionSuccess(task), task);
39558
- })
39559
- },
39560
39495
  {
39561
39496
  name: "task_cancel",
39562
- description: "Request cancellation for a task under the current coordinator. Use to abort a running delegation; the task transitions to a terminal state shortly after.",
39497
+ description: "Cancel a task under the current coordinator. Works in any non-terminal state: a running delegation is aborted, and a task still waiting for approval (needs_confirmation) is rejected. The task transitions to a terminal state shortly after.",
39563
39498
  inputSchema: exports_external.object({
39564
39499
  taskId: exports_external.string().min(1)
39565
39500
  }).strict(),
@@ -39571,25 +39506,9 @@ function buildWeacpxMcpToolRegistry(input) {
39571
39506
  return createSuccessResult(renderTaskCancelRequest(task), task);
39572
39507
  })
39573
39508
  },
39574
- {
39575
- name: "task_wait",
39576
- description: `Wait for a task to finish or require attention. This is a blocking legacy compatibility tool; do not call it automatically after delegate_request when the user only asked to start/delegate work. Use task_get/task_list for non-blocking progress snapshots; call task_wait when the user explicitly asks to wait, or when your next step truly depends on completion. Returns status=terminal (done; call task_get for the result), status=attention_required (call task_get first to read the task's current status, then branch: needs_confirmation -> task_approve or task_reject; blocked or waiting_for_human -> coordinator_answer_question; reviewPending set -> coordinator_review_contested_result; after resolving, use task_get/task_list snapshots or task_wait only if intentionally blocking), or status=timeout (still running; use task_get for a snapshot, or task_wait only if intentionally blocking). 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.`,
39577
- inputSchema: exports_external.object({
39578
- taskId: exports_external.string().min(1),
39579
- timeoutMs: exports_external.number().int().min(0).max(MAX_TASK_WAIT_TIMEOUT_MS).optional(),
39580
- pollIntervalMs: exports_external.number().int().min(1).max(MAX_TASK_WAIT_POLL_INTERVAL_MS).optional()
39581
- }).strict(),
39582
- handler: async (args) => await asToolResult(async () => {
39583
- const result = await transport.waitTask({
39584
- coordinatorSession,
39585
- ...args
39586
- });
39587
- return createSuccessResult(renderTaskWaitResult(result), result);
39588
- })
39589
- },
39590
39509
  {
39591
39510
  name: "task_watch",
39592
- description: `Long-poll a task for the next event, attention-required state, or terminal state. This is the recommended legacy way to watch a delegated task without repeatedly calling task_wait. For MCP-task-capable clients, request task execution for this tool to create a background watcher: the call returns a native task handle immediately, and tasks/result returns when the watch condition is met. The native watcher is single-shot: it runs one watch cycle then terminates, so to keep watching start another task_watch with afterSeq set to the returned nextAfterSeq. Defaults: timeout ${DEFAULT_TASK_WATCH_TIMEOUT_MS} ms, poll interval ${DEFAULT_TASK_WATCH_POLL_INTERVAL_MS} ms. Maximums: timeout ${MAX_TASK_WATCH_TIMEOUT_MS} ms, poll interval ${MAX_TASK_WATCH_POLL_INTERVAL_MS} ms.`,
39511
+ description: `Long-poll a task for the next event, attention-required state, or terminal state. For MCP-task-capable clients, request task execution for this tool to create a background watcher: the call returns a native task handle immediately, and tasks/result returns when the watch condition is met. The native watcher is single-shot: it runs one watch cycle then terminates, so to keep watching start another task_watch with afterSeq set to the returned nextAfterSeq. Defaults: timeout ${DEFAULT_TASK_WATCH_TIMEOUT_MS} ms, poll interval ${DEFAULT_TASK_WATCH_POLL_INTERVAL_MS} ms. Maximums: timeout ${MAX_TASK_WATCH_TIMEOUT_MS} ms, poll interval ${MAX_TASK_WATCH_POLL_INTERVAL_MS} ms.`,
39593
39512
  execution: { taskSupport: "optional" },
39594
39513
  inputSchema: exports_external.object({
39595
39514
  taskId: exports_external.string().min(1),
@@ -39609,7 +39528,7 @@ function buildWeacpxMcpToolRegistry(input) {
39609
39528
  },
39610
39529
  {
39611
39530
  name: "worker_raise_question",
39612
- description: "Raise a blocker question for the current bound worker session. Worker-side only: call this from inside a delegated task when you are blocked and need the coordinator's input. Coordinators waiting on a delegation should not call this; use task_get/task_list for snapshots, or task_wait only if intentionally blocking.",
39531
+ description: "Raise a blocker question for the current bound worker session. Worker-side only: call this from inside a delegated task when you are blocked and need the coordinator's input.",
39613
39532
  inputSchema: exports_external.object({
39614
39533
  taskId: exports_external.string().min(1),
39615
39534
  question: exports_external.string().min(1),
@@ -39629,7 +39548,7 @@ function buildWeacpxMcpToolRegistry(input) {
39629
39548
  },
39630
39549
  {
39631
39550
  name: "coordinator_answer_question",
39632
- description: "Answer a blocked worker question under the current coordinator. Use when task_get shows a pending question; after answering, use task_get/task_list for snapshots or task_wait only if intentionally blocking for the worker to finish.",
39551
+ description: "Answer a blocked worker question under the current coordinator. Use when task_get shows a pending question.",
39633
39552
  inputSchema: exports_external.object({
39634
39553
  taskId: exports_external.string().min(1),
39635
39554
  questionId: exports_external.string().min(1),
@@ -39659,23 +39578,6 @@ function buildWeacpxMcpToolRegistry(input) {
39659
39578
  return createSuccessResult(renderCoordinatorRequestHumanInputSuccess(result), result);
39660
39579
  })
39661
39580
  },
39662
- {
39663
- name: "coordinator_follow_up_human_package",
39664
- description: "Append a follow-up message to the active human question package under the current coordinator. Use to clarify or add context to an in-flight package created via coordinator_request_human_input.",
39665
- inputSchema: exports_external.object({
39666
- packageId: exports_external.string().min(1),
39667
- priorMessageId: exports_external.string().min(1),
39668
- taskQuestions: exports_external.array(taskQuestionSchema).min(1),
39669
- promptText: exports_external.string().min(1)
39670
- }).strict(),
39671
- handler: async (args) => await asToolResult(async () => {
39672
- const result = await transport.coordinatorFollowUpHumanPackage({
39673
- coordinatorSession,
39674
- ...args
39675
- });
39676
- return createSuccessResult(renderCoordinatorFollowUpHumanPackageSuccess(result), result);
39677
- })
39678
- },
39679
39581
  {
39680
39582
  name: "coordinator_review_contested_result",
39681
39583
  description: "Review a contested result under the current coordinator. Use when a worker's result has been challenged and the coordinator must decide accept or discard.",
@@ -39697,8 +39599,7 @@ function buildWeacpxMcpToolRegistry(input) {
39697
39599
  ];
39698
39600
  if (isExternalCoordinator) {
39699
39601
  const externalCoordinatorIncompatibleTools = new Set([
39700
- "coordinator_request_human_input",
39701
- "coordinator_follow_up_human_package"
39602
+ "coordinator_request_human_input"
39702
39603
  ]);
39703
39604
  return tools.filter((tool) => !externalCoordinatorIncompatibleTools.has(tool.name));
39704
39605
  }
@@ -39723,37 +39624,6 @@ async function asToolResult(action) {
39723
39624
  return createErrorResult(formatToolError(error2));
39724
39625
  }
39725
39626
  }
39726
- function renderTaskWaitResult(result) {
39727
- if (result.status === "not_found") {
39728
- return "Task not found.";
39729
- }
39730
- if (!result.task) {
39731
- return `Task wait ${result.status.replace("_", " ")}; current state is unavailable.`;
39732
- }
39733
- if (result.status === "timeout") {
39734
- return [
39735
- `Task ${result.task.taskId} wait timed out; current state is ${result.task.status}.`,
39736
- `Next: call task_get for a snapshot, or call task_wait again only if you intentionally want to keep blocking.`
39737
- ].join(`
39738
- `);
39739
- }
39740
- if (result.status === "attention_required") {
39741
- return [
39742
- `Task ${result.task.taskId} requires attention; current state is ${result.task.status}.`,
39743
- `Next: call task_get to read the task's current status and any reviewPending / openQuestion fields, then branch by what you see:`,
39744
- ` - status=needs_confirmation -> task_approve or task_reject`,
39745
- ` - status=blocked or waiting_for_human -> coordinator_answer_question`,
39746
- ` - reviewPending set -> coordinator_review_contested_result`,
39747
- `After resolving, use task_get/task_list for snapshots, or call task_wait again only if you intentionally want to keep blocking.`
39748
- ].join(`
39749
- `);
39750
- }
39751
- return [
39752
- `Task ${result.task.taskId} reached terminal state ${result.task.status}.`,
39753
- `Next: call task_get to read the worker's final result before reporting back to the user.`
39754
- ].join(`
39755
- `);
39756
- }
39757
39627
  function renderTaskWatchResult(result) {
39758
39628
  if (result.status === "not_found" || !result.task) {
39759
39629
  return "Task not found.";
@@ -39787,72 +39657,16 @@ function createErrorResult(message) {
39787
39657
  };
39788
39658
  }
39789
39659
  function renderDelegateSuccess(result) {
39790
- const next = result.status === "needs_confirmation" ? `Next: this delegation requires user approval; do not call task_wait yet. Tell the user, then call task_approve or task_reject based on their response.` : `Next: task "${result.taskId}" is running. Return this taskId to the user, or call task_get/task_list for non-blocking progress snapshots (or task_watch to long-poll for the next event). Call task_wait only if the user explicitly asks you to wait/block until completion.`;
39660
+ const next = result.status === "needs_confirmation" ? `Next: this delegation requires user approval. Tell the user, then call task_approve or task_cancel based on their response.` : `Next: task "${result.taskId}" is running. Return this taskId to the user, call task_get/task_list for non-blocking progress snapshots, or task_watch to long-poll for the next event or terminal state.`;
39791
39661
  return [`Delegation task "${result.taskId}" created.`, `- Status: ${result.status}`, next].join(`
39792
39662
  `);
39793
39663
  }
39794
- function renderGroupCreated(group) {
39795
- return [`Task group "${group.groupId}" created.`, `- Title: ${group.title}`].join(`
39796
- `);
39797
- }
39798
- function renderGroupSummary(summary) {
39799
- const { group, tasks } = summary;
39800
- const lines = [
39801
- `Task group "${group.groupId}"`,
39802
- `- Title: ${group.title}`,
39803
- `- Coordinator session: ${group.coordinatorSession}`,
39804
- `- Total tasks: ${summary.totalTasks}`,
39805
- `- Pending approval: ${summary.pendingApprovalTasks}`,
39806
- `- Running: ${summary.runningTasks}`,
39807
- `- Completed: ${summary.completedTasks}`,
39808
- `- Failed: ${summary.failedTasks}`,
39809
- `- Cancelled: ${summary.cancelledTasks}`,
39810
- `- Terminal: ${summary.terminal ? "yes" : "no"}`
39811
- ];
39812
- if (group.injectionPending !== undefined) {
39813
- lines.push(`- Injection pending: ${group.injectionPending ? "yes" : "no"}`);
39814
- }
39815
- if (group.injectionAppliedAt) {
39816
- lines.push(`- Injection completed at: ${group.injectionAppliedAt}`);
39817
- }
39818
- if (group.lastInjectionError) {
39819
- lines.push(`- Last injection error: ${group.lastInjectionError}`);
39820
- }
39821
- if (tasks.length > 0) {
39822
- lines.push("- Members:");
39823
- for (const task of tasks) {
39824
- lines.push(` - ${task.taskId} [${task.status}] ${task.targetAgent}`);
39825
- }
39826
- }
39827
- return lines.join(`
39828
- `);
39829
- }
39830
- function renderGroupList(groups) {
39831
- if (groups.length === 0) {
39832
- return "There are no task groups under the current coordinator.";
39833
- }
39834
- return ["Task groups for the current coordinator:", ...groups.map((group) => renderGroupListItem(group))].join(`
39835
- `);
39836
- }
39837
- function renderGroupListItem(group) {
39838
- const reliability = group.group.injectionPending ? " | injection pending" : "";
39839
- return [
39840
- `- ${group.group.groupId}`,
39841
- group.group.title,
39842
- `total ${group.totalTasks}`,
39843
- `pending ${group.pendingApprovalTasks}`,
39844
- `running ${group.runningTasks}`,
39845
- `completed ${group.completedTasks}`,
39846
- `failed ${group.failedTasks}`,
39847
- `cancelled ${group.cancelledTasks}${reliability}`
39848
- ].join(" | ");
39849
- }
39850
- function renderGroupCancelSuccess(input) {
39851
- return [
39852
- `Task group "${input.summary.group.groupId}" cancellation requested.`,
39853
- `- Cancel requested: ${input.cancelledTaskIds.length}`,
39854
- `- Skipped terminal tasks: ${input.skippedTaskIds.length}`
39855
- ].join(`
39664
+ function renderDelegateBatchSuccess(groupId, results) {
39665
+ const lines = results.map((entry) => entry.error ? ` - #${entry.index}: failed to start — ${entry.error}` : ` - #${entry.index}: task "${entry.taskId}" (${entry.status})`);
39666
+ const started = results.filter((entry) => entry.taskId).length;
39667
+ const header = groupId ? `Batch delegation created group "${groupId}" with ${started}/${results.length} tasks started.` : `Delegation: ${started}/${results.length} task started.`;
39668
+ const next = started > 0 ? "Next: track the started tasks with task_get/task_list, or task_watch to long-poll. The group reports all results back together once every task is terminal." : "Next: every task failed to start — fix the errors above and retry.";
39669
+ return [header, "- Tasks:", ...lines, next].join(`
39856
39670
  `);
39857
39671
  }
39858
39672
  function renderTaskList(tasks) {
@@ -39923,7 +39737,9 @@ function renderTaskSummary(task) {
39923
39737
  events.push({ at: task.updatedAt, event: "injection failed", detail: task.lastInjectionError });
39924
39738
  events.sort((a, b) => a.at.localeCompare(b.at));
39925
39739
  const timeline = events.length > 0 ? ["- Timeline:", ...events.map((e) => ` - [${e.at}] ${e.event}${e.detail ? `: ${e.detail}` : ""}`)] : [];
39926
- return [...header, ...timeline].join(`
39740
+ const isTerminal2 = task.status === "completed" || task.status === "failed" || task.status === "cancelled";
39741
+ const next = isTerminal2 ? ["Next: summarize this result for the user."] : [];
39742
+ return [...header, ...timeline, ...next].join(`
39927
39743
  `);
39928
39744
  }
39929
39745
  function renderTaskCancelRequest(task) {
@@ -39938,14 +39754,10 @@ function renderTaskApprovalSuccess(task) {
39938
39754
  return [
39939
39755
  `Task "${task.taskId}" approved.`,
39940
39756
  `- Current status: ${task.status}`,
39941
- `Next: use task_get/task_list for non-blocking progress snapshots, or call task_wait only if you intentionally want to block until the worker finishes; then task_get to read the final result.`
39757
+ `Next: use task_get/task_list for non-blocking progress snapshots, or task_watch to long-poll until the worker finishes; then task_get to read the final result.`
39942
39758
  ].join(`
39943
39759
  `);
39944
39760
  }
39945
- function renderTaskRejectionSuccess(task) {
39946
- return [`Task "${task.taskId}" rejected.`, `- Current status: ${task.status}`].join(`
39947
- `);
39948
- }
39949
39761
  function renderWorkerRaiseQuestionSuccess(task) {
39950
39762
  return [`Blocker question submitted for task "${task.taskId}".`, `- questionId: ${task.questionId}`].join(`
39951
39763
  `);
@@ -39959,10 +39771,6 @@ function renderCoordinatorRequestHumanInputSuccess(result) {
39959
39771
  `) : [`Queued the question in the current human question queue.`, `- Queued tasks: ${result.queuedTaskIds.length}`].join(`
39960
39772
  `);
39961
39773
  }
39962
- function renderCoordinatorFollowUpHumanPackageSuccess(result) {
39963
- return [`Appended follow-up to human package "${result.packageId}".`, `- messageId: ${result.messageId}`].join(`
39964
- `);
39965
- }
39966
39774
  function renderCoordinatorReviewContestedResultSuccess(task, decision) {
39967
39775
  const actionText = decision === "accept" ? "Accepted" : "Discarded";
39968
39776
  return [`${actionText} contested result for task "${task.taskId}".`, `- Current status: ${task.status}`].join(`
@@ -39980,7 +39788,7 @@ function formatToolError(error2) {
39980
39788
 
39981
39789
  // src/orchestration/orchestration-client.ts
39982
39790
  init_orchestration_ipc();
39983
- init_task_wait_timeouts();
39791
+ init_task_watch_timeouts();
39984
39792
  import { randomUUID } from "node:crypto";
39985
39793
  import { createConnection } from "node:net";
39986
39794
 
@@ -40005,18 +39813,12 @@ class OrchestrationClient {
40005
39813
  async listTasks(filter) {
40006
39814
  return await this.request("task.list", { filter });
40007
39815
  }
40008
- async waitTask(input) {
40009
- return await this.request("task.wait", input, getWaitRequestTimeoutMs(input.timeoutMs, this.timeoutMs));
40010
- }
40011
39816
  async watchTask(input) {
40012
39817
  return await this.request("task.watch", input, getWatchRequestTimeoutMs(input.timeoutMs, this.timeoutMs));
40013
39818
  }
40014
39819
  async approveTask(input) {
40015
39820
  return await this.request("task.approve", input);
40016
39821
  }
40017
- async rejectTask(input) {
40018
- return await this.request("task.reject", input);
40019
- }
40020
39822
  async cancelTask(input) {
40021
39823
  return await this.request("task.cancel", input);
40022
39824
  }
@@ -40038,24 +39840,12 @@ class OrchestrationClient {
40038
39840
  async coordinatorRequestHumanInput(input) {
40039
39841
  return await this.request("coordinator.request_human_input", input);
40040
39842
  }
40041
- async coordinatorFollowUpHumanPackage(input) {
40042
- return await this.request("coordinator.follow_up_human_package", input);
40043
- }
40044
39843
  async coordinatorReviewContestedResult(input) {
40045
39844
  return await this.request("coordinator.review_contested_result", input);
40046
39845
  }
40047
39846
  async createGroup(input) {
40048
39847
  return await this.request("group.new", input);
40049
39848
  }
40050
- async getGroup(input) {
40051
- return await this.request("group.get", input);
40052
- }
40053
- async listGroups(input) {
40054
- return await this.request("group.list", input);
40055
- }
40056
- async cancelGroup(input) {
40057
- return await this.request("group.cancel", input);
40058
- }
40059
39849
  async request(method, params, timeoutMs = this.timeoutMs) {
40060
39850
  const id = this.createId();
40061
39851
  return await new Promise((resolve, reject) => {
@@ -40122,11 +39912,6 @@ class OrchestrationClient {
40122
39912
  });
40123
39913
  }
40124
39914
  }
40125
- function getWaitRequestTimeoutMs(waitTimeoutMs, defaultTimeoutMs) {
40126
- const requestedWaitTimeoutMs = waitTimeoutMs === undefined ? undefined : Number.isFinite(waitTimeoutMs) ? waitTimeoutMs : 0;
40127
- const boundedWaitTimeoutMs = Math.min(Math.max(Math.floor(requestedWaitTimeoutMs ?? DEFAULT_TASK_WAIT_TIMEOUT_MS), 0), MAX_TASK_WAIT_TIMEOUT_MS);
40128
- return Math.max(defaultTimeoutMs, boundedWaitTimeoutMs + TASK_WAIT_RPC_TIMEOUT_PADDING_MS);
40129
- }
40130
39915
  function getWatchRequestTimeoutMs(watchTimeoutMs, defaultTimeoutMs) {
40131
39916
  const requestedWatchTimeoutMs = watchTimeoutMs === undefined ? undefined : Number.isFinite(watchTimeoutMs) ? watchTimeoutMs : 0;
40132
39917
  const boundedWatchTimeoutMs = Math.min(Math.max(Math.floor(requestedWatchTimeoutMs ?? DEFAULT_TASK_WATCH_TIMEOUT_MS), 0), MAX_TASK_WATCH_TIMEOUT_MS);
@@ -40146,9 +39931,6 @@ function createOrchestrationTransport(endpoint, deps = {}) {
40146
39931
  ...input.groupId !== undefined ? { groupId: input.groupId } : {}
40147
39932
  }),
40148
39933
  createGroup: async (input) => await client.createGroup(input),
40149
- getGroup: async (input) => await client.getGroup(input),
40150
- listGroups: async (input) => await client.listGroups(input),
40151
- cancelGroup: async (input) => await client.cancelGroup(input),
40152
39934
  getTask: async (input) => await client.getTaskForCoordinator(input),
40153
39935
  listTasks: async (input) => await client.listTasks({
40154
39936
  coordinatorSession: input.coordinatorSession,
@@ -40158,9 +39940,7 @@ function createOrchestrationTransport(endpoint, deps = {}) {
40158
39940
  ...input.order !== undefined ? { order: input.order } : {}
40159
39941
  }),
40160
39942
  approveTask: async (input) => await client.approveTask(input),
40161
- rejectTask: async (input) => await client.rejectTask(input),
40162
39943
  cancelTask: async (input) => await client.cancelTaskForCoordinator(input),
40163
- waitTask: async (input) => await client.waitTask(input),
40164
39944
  watchTask: async (input) => await client.watchTask(input),
40165
39945
  workerRaiseQuestion: async (input) => {
40166
39946
  const sourceHandle = input.sourceHandle.trim();
@@ -40177,7 +39957,6 @@ function createOrchestrationTransport(endpoint, deps = {}) {
40177
39957
  },
40178
39958
  coordinatorAnswerQuestion: async (input) => await client.coordinatorAnswerQuestion(input),
40179
39959
  coordinatorRequestHumanInput: async (input) => await client.coordinatorRequestHumanInput(input),
40180
- coordinatorFollowUpHumanPackage: async (input) => await client.coordinatorFollowUpHumanPackage(input),
40181
39960
  coordinatorReviewContestedResult: async (input) => await client.coordinatorReviewContestedResult(input)
40182
39961
  };
40183
39962
  }
@@ -40189,32 +39968,12 @@ var WATCH_TASKS_CACHE_LIMIT = 256;
40189
39968
  var WEACPX_MCP_SERVER_INSTRUCTIONS = [
40190
39969
  "Use these tools to orchestrate work across other agents under your coordinator session.",
40191
39970
  "",
40192
- "Typical lifecycle for a single delegation:",
40193
- "Preferred MCP Tasks lifecycle (for clients that support task-augmented tools/call):",
40194
- "1. Call delegate_request with task execution requested. It returns a native MCP task handle immediately.",
40195
- "2. Use task_watch with MCP task execution to start a background watcher, or use tasks/get / tasks/list to poll status. Use tasks/result after terminal status, or on input_required to receive an actionable next-step package; use tasks/cancel to cancel.",
40196
- " - When tasks/result returns input_required, that result stream is complete. Call the recommended tool, then resume polling with tasks/get / tasks/result.",
40197
- "3. Status mapping: working = running, input_required = needs_confirmation / blocked / waiting_for_human / contested review, completed / failed / cancelled are terminal.",
40198
- "",
40199
- "Legacy tool lifecycle for clients without MCP Tasks support:",
40200
- "1. delegate_request → returns { taskId, status }.",
40201
- " - status=running: the worker has started. Return the taskId to the user, use task_get / task_list for non-blocking snapshots, or task_watch to long-poll for the next event; only go to step 2 when you intentionally want to block waiting.",
40202
- " - status=needs_confirmation: tell the user, then call task_approve or task_reject based on their response. After task_approve, use task_get/task_list for snapshots or step 2 only if intentionally blocking. Do not call task_wait before approval.",
40203
- "2. Optional blocking wait: task_wait(taskId) → blocks until the task is done, needs attention, or times out. Do not call it automatically when the user asked to delegate and continue.",
40204
- " - status=terminal: go to step 3.",
40205
- " - status=attention_required: the task is in needs_confirmation / blocked / waiting_for_human, or has reviewPending set. Call task_get(taskId) to read the actual status and any openQuestion / reviewPending fields, then branch:",
40206
- " * needs_confirmation -> task_approve or task_reject (after approval, use snapshots or optional blocking wait only if needed)",
40207
- " * blocked or waiting_for_human -> coordinator_answer_question (the answer can come from you or be relayed from a human you consulted)",
40208
- " * reviewPending set -> coordinator_review_contested_result with accept or discard",
40209
- " After resolving, use task_get / task_list for snapshots, or step 2 only if intentionally blocking.",
40210
- " - status=timeout: the task is still running. Use task_get for a snapshot, or call task_wait again only if you still intentionally want to block.",
40211
- "3. The task is terminal. Call task_get(taskId) to read the worker's final result, then summarize it for the user. Do not invent results that did not come from task_get.",
39971
+ "Delegate with delegate_request (one task) or delegate_batch (several at once). Each returns a taskId and a status.",
39972
+ "Then follow the task: clients that support MCP Tasks should request task execution on delegate_request / task_watch and poll with tasks/get / tasks/list / tasks/result; other clients use task_get / task_list for snapshots or task_watch to long-poll.",
40212
39973
  "",
40213
- "Batching: use group_new before a wave of delegate_request calls and pass groupId on each, then group_get / group_list / group_cancel to manage the batch.",
40214
- "Cancellation: task_cancel aborts a single running task; group_cancel aborts the whole batch.",
40215
- "Discovery: task_list / group_list recover taskIds and groupIds from earlier in the session.",
39974
+ "Most tool results end with a 'Next:' line telling you the concrete next step follow it when present. In short: status=needs_confirmation needs task_approve or task_cancel; a task that needs attention (blocked / waiting_for_human / a contested review) is resolved with coordinator_answer_question or coordinator_review_contested_result; a terminal task is read with task_get. Never report a result you did not read from task_get.",
40216
39975
  "",
40217
- "worker_raise_question is worker-side only — call it from inside a delegated task when you are blocked, not from the coordinator that is waiting on a delegation."
39976
+ "worker_raise_question is worker-side only — call it from inside a delegated task when you are blocked, not from the coordinator waiting on a delegation."
40218
39977
  ].join(`
40219
39978
  `);
40220
39979
  function createWeacpxMcpServer(options) {
@@ -40627,7 +40386,7 @@ function renderInputRequiredTaskResult(task) {
40627
40386
  function inputRequiredActions(task) {
40628
40387
  const actions = [];
40629
40388
  if (task.status === "needs_confirmation") {
40630
- actions.push("task_approve", "task_reject");
40389
+ actions.push("task_approve", "task_cancel");
40631
40390
  }
40632
40391
  if (task.status === "blocked" || task.status === "waiting_for_human" || task.openQuestion) {
40633
40392
  actions.push("coordinator_answer_question");
@@ -42739,7 +42498,7 @@ async function runCli(args, deps = {}) {
42739
42498
  case "mcp-stdio":
42740
42499
  return await (deps.mcpStdio ?? ((subArgs) => defaultMcpStdio(subArgs, { stderr: deps.stderr })))(args.slice(1));
42741
42500
  case "start": {
42742
- const controller = deps.controller ?? createDefaultController();
42501
+ const controller = deps.controller ?? createDefaultController(deps);
42743
42502
  try {
42744
42503
  const isInteractive = deps.isInteractive ?? defaultIsInteractive;
42745
42504
  const status = await controller.getStatus();
@@ -42782,7 +42541,7 @@ async function runCli(args, deps = {}) {
42782
42541
  }
42783
42542
  }
42784
42543
  case "status": {
42785
- const controller = deps.controller ?? createDefaultController();
42544
+ const controller = deps.controller ?? createDefaultController(deps);
42786
42545
  const status = await controller.getStatus();
42787
42546
  if (status.state === "indeterminate") {
42788
42547
  print("weacpx 进程仍在运行,但状态元数据缺失");
@@ -42805,7 +42564,7 @@ async function runCli(args, deps = {}) {
42805
42564
  return 0;
42806
42565
  }
42807
42566
  case "stop": {
42808
- const controller = deps.controller ?? createDefaultController();
42567
+ const controller = deps.controller ?? createDefaultController(deps);
42809
42568
  const result = await controller.stop();
42810
42569
  if (result.detail === "not-running") {
42811
42570
  print("weacpx 未运行");
@@ -42815,7 +42574,7 @@ async function runCli(args, deps = {}) {
42815
42574
  return 0;
42816
42575
  }
42817
42576
  case "restart": {
42818
- const controller = deps.controller ?? createDefaultController();
42577
+ const controller = deps.controller ?? createDefaultController(deps);
42819
42578
  try {
42820
42579
  return await restartDaemonCli(controller, print);
42821
42580
  } catch (error2) {
@@ -43028,8 +42787,18 @@ async function agentRemove(rawName, print) {
43028
42787
  print(`Agent「${name}」已删除`);
43029
42788
  return 0;
43030
42789
  }
42790
+ function resolveConfigPathForCurrentEnv() {
42791
+ return process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
42792
+ }
42793
+ function resolveDaemonPathsForCurrentConfig() {
42794
+ const configPath = resolveConfigPathForCurrentEnv();
42795
+ return resolveDaemonPaths({
42796
+ home: requireHome2(),
42797
+ runtimeDir: resolveRuntimeDirFromConfigPath(configPath)
42798
+ });
42799
+ }
43031
42800
  async function createCliConfigStore() {
43032
- const configPath = process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
42801
+ const configPath = resolveConfigPathForCurrentEnv();
43033
42802
  await ensureConfigExists(configPath);
43034
42803
  return new ConfigStore(configPath);
43035
42804
  }
@@ -43064,7 +42833,7 @@ async function defaultRun(options = {}) {
43064
42833
  await loadConfiguredPlugins2({ plugins: config2.plugins });
43065
42834
  const { createMessageChannels: createMessageChannels2 } = await Promise.resolve().then(() => (init_create_channel(), exports_create_channel));
43066
42835
  const { MessageChannelRegistry: MessageChannelRegistry2 } = await Promise.resolve().then(() => (init_channel_registry(), exports_channel_registry));
43067
- const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
42836
+ const daemonPaths = resolveDaemonPathsForCurrentConfig();
43068
42837
  const daemonRuntime = new DaemonRuntime(daemonPaths, { pid: process.pid });
43069
42838
  const { channelDeps } = await prepareChannelMedia2(runtimePaths.configPath, config2);
43070
42839
  const channelRegistry = new MessageChannelRegistry2(createMessageChannels2(config2.channels, channelDeps));
@@ -43310,13 +43079,14 @@ async function defaultPromptSecret(message) {
43310
43079
  process.stdin.on("data", onData);
43311
43080
  });
43312
43081
  }
43313
- function createDefaultController() {
43314
- const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
43082
+ function createDefaultController(deps = {}) {
43083
+ const daemonPaths = resolveDaemonPathsForCurrentConfig();
43315
43084
  const controller = createDaemonController(daemonPaths, {
43316
43085
  processExecPath: process.execPath,
43317
43086
  cliEntryPath: resolveCliEntryPath2(),
43318
43087
  cwd: process.cwd(),
43319
- env: process.env
43088
+ env: process.env,
43089
+ ...deps.isProcessRunning ? { isProcessRunning: deps.isProcessRunning } : {}
43320
43090
  });
43321
43091
  return {
43322
43092
  getStatus: () => controller.getStatus(),
@@ -43372,8 +43142,8 @@ function printDaemonLogHints(print) {
43372
43142
  }
43373
43143
  function safeDaemonLogPaths() {
43374
43144
  try {
43375
- const configPath = process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
43376
- const paths = resolveDaemonPaths({ home: requireHome2() });
43145
+ const configPath = resolveConfigPathForCurrentEnv();
43146
+ const paths = resolveDaemonPathsForCurrentConfig();
43377
43147
  return {
43378
43148
  appLog: join16(dirname15(configPath), "runtime", "app.log"),
43379
43149
  stderrLog: paths.stderrLog