weacpx 0.4.6 → 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.
@@ -60,6 +60,10 @@ function encodeBridgePromptToolEvent(event) {
60
60
  return `${JSON.stringify(event)}
61
61
  `;
62
62
  }
63
+ function encodeBridgePromptThoughtEvent(event) {
64
+ return `${JSON.stringify(event)}
65
+ `;
66
+ }
63
67
  function encodeBridgeSessionProgressEvent(event) {
64
68
  return `${JSON.stringify(event)}
65
69
  `;
@@ -366,6 +370,7 @@ var init_tool_kind_emoji = __esm(() => {
366
370
  function createStreamingPromptState(formatToolCalls = false, options) {
367
371
  let toolEventMode;
368
372
  let onToolEvent;
373
+ let onThought;
369
374
  if (options === undefined) {
370
375
  toolEventMode = "text";
371
376
  onToolEvent = undefined;
@@ -374,6 +379,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
374
379
  toolEventMode = "structured";
375
380
  } else {
376
381
  onToolEvent = options.onToolEvent;
382
+ onThought = options.onThought;
377
383
  toolEventMode = resolveToolEventMode({
378
384
  toolEventMode: options.mode,
379
385
  onToolEvent
@@ -388,6 +394,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
388
394
  emittedToolCallIds: new Set,
389
395
  toolEventMode,
390
396
  onToolEvent,
397
+ onThought,
391
398
  finalize() {
392
399
  if (this.pendingLine.trim().length > 0) {
393
400
  parseStreamingChunks(this, this.pendingLine);
@@ -446,6 +453,14 @@ function parseStreamingChunks(state, line) {
446
453
  }
447
454
  return;
448
455
  }
456
+ const isThoughtChunk = update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
457
+ if (isThoughtChunk) {
458
+ const chunk2 = update.content.text;
459
+ if (chunk2.length > 0) {
460
+ state.onThought?.(chunk2);
461
+ }
462
+ return;
463
+ }
449
464
  const isMessageChunk = update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
450
465
  if (!isMessageChunk)
451
466
  return;
@@ -473,7 +488,7 @@ function formatToolCallEvent(update, sessionUpdate) {
473
488
  if (title.length === 0)
474
489
  return null;
475
490
  const emoji = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
476
- const inputSummary = summarizeToolInput(update.rawInput, title);
491
+ const inputSummary = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
477
492
  const status = readString(update, "status");
478
493
  if (!inputSummary && status === "pending")
479
494
  return null;
@@ -504,15 +519,23 @@ function buildToolUseEvent(update) {
504
519
  })();
505
520
  const title = (update.title ?? "").trim();
506
521
  const toolName = title || "Tool";
507
- const summaryRaw = summarizeToolInput(update.rawInput, title);
522
+ const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
508
523
  const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
509
524
  const statusRaw = readString(update, "status");
510
525
  const status = statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : "running";
526
+ const rawInput = update.rawInput;
527
+ const content = update.content;
528
+ const rawOutput = update.rawOutput;
529
+ const locations = update.locations;
511
530
  return {
512
531
  toolCallId,
513
532
  toolName,
514
533
  kind,
515
534
  ...summary ? { summary } : {},
535
+ ...rawInput !== undefined ? { rawInput } : {},
536
+ ...content !== undefined ? { content } : {},
537
+ ...rawOutput !== undefined ? { rawOutput } : {},
538
+ ...locations !== undefined ? { locations } : {},
516
539
  status
517
540
  };
518
541
  }
@@ -831,6 +854,8 @@ function buildQueueOwnerPayload(input) {
831
854
  nonInteractivePermissions: input.nonInteractivePermissions,
832
855
  ttlMs: input.ttlMs ?? 300000,
833
856
  maxQueueDepth: input.maxQueueDepth ?? 16,
857
+ ...Number.isFinite(input.promptRetries) ? { promptRetries: input.promptRetries } : {},
858
+ ...input.sessionOptions ? { sessionOptions: input.sessionOptions } : {},
834
859
  mcpServers: input.mcpServers
835
860
  };
836
861
  }
@@ -1113,6 +1138,7 @@ class BridgeRuntime {
1113
1138
  async updatePermissionPolicy(policy) {
1114
1139
  this.options.permissionMode = policy.permissionMode;
1115
1140
  this.options.nonInteractivePermissions = policy.nonInteractivePermissions;
1141
+ this.options.permissionPolicy = policy.permissionPolicy;
1116
1142
  return {};
1117
1143
  }
1118
1144
  async hasSession(input) {
@@ -1124,6 +1150,26 @@ class BridgeRuntime {
1124
1150
  const result = await this.run(spawnSpec.command, spawnSpec.args);
1125
1151
  return { exists: result.code === 0 };
1126
1152
  }
1153
+ async tailSessionHistory(input) {
1154
+ const candidates = [
1155
+ ["sessions", "history", "quiet", "-s", input.name, String(input.lines)],
1156
+ ["sessions", "history", "quiet", input.name, String(input.lines)],
1157
+ ["sessions", "history", "-s", input.name, "--tail", String(input.lines)],
1158
+ ["sessions", "history", input.name, "--tail", String(input.lines)],
1159
+ ["sessions", "history", "--name", input.name, "--tail", String(input.lines)]
1160
+ ];
1161
+ let lastResult;
1162
+ for (const tailArgs of candidates) {
1163
+ const spawnSpec = resolveSpawnCommand(this.command, this.buildSessionArgs(input, tailArgs));
1164
+ const result = await this.run(spawnSpec.command, spawnSpec.args);
1165
+ if (result.code === 0) {
1166
+ return { text: result.stdout.trimEnd() };
1167
+ }
1168
+ lastResult = result;
1169
+ }
1170
+ const message = lastResult?.stderr || lastResult?.stdout || "sessions history failed";
1171
+ throw new Error(message);
1172
+ }
1127
1173
  async ensureSession(input, onProgress) {
1128
1174
  onProgress?.("spawn");
1129
1175
  const onStderrLine = onProgress ? (line) => {
@@ -1346,7 +1392,11 @@ class BridgeRuntime {
1346
1392
  const permissionMode = this.options.permissionMode ?? "approve-all";
1347
1393
  const nonInteractivePermissions = this.options.nonInteractivePermissions ?? "deny";
1348
1394
  const modeFlag = permissionModeToFlag(permissionMode);
1349
- return [modeFlag, "--non-interactive-permissions", nonInteractivePermissions];
1395
+ const args = [modeFlag, "--non-interactive-permissions", nonInteractivePermissions];
1396
+ if (typeof this.options.permissionPolicy === "string" && this.options.permissionPolicy.trim().length > 0) {
1397
+ args.push("--permission-policy", this.options.permissionPolicy);
1398
+ }
1399
+ return args;
1350
1400
  }
1351
1401
  }
1352
1402
  function spawnCapture(command, args, options) {
@@ -1398,7 +1448,8 @@ async function runStreamingPrompt(command, args, onEvent, options = {}) {
1398
1448
  const toolEventMode = options.toolEventMode ?? "text";
1399
1449
  const state = createStreamingPromptState(options.formatToolCalls ?? false, {
1400
1450
  mode: toolEventMode,
1401
- ...onEvent && (toolEventMode === "structured" || toolEventMode === "both") ? { onToolEvent: (toolEvent) => onEvent({ type: "prompt.tool_event", event: toolEvent }) } : {}
1451
+ ...onEvent && (toolEventMode === "structured" || toolEventMode === "both") ? { onToolEvent: (toolEvent) => onEvent({ type: "prompt.tool_event", event: toolEvent }) } : {},
1452
+ ...onEvent ? { onThought: (chunk) => onEvent({ type: "prompt.thought", text: chunk }) } : {}
1402
1453
  });
1403
1454
  let lastReplyAt = now();
1404
1455
  const flushBuffer = () => {
@@ -1514,6 +1565,7 @@ var BRIDGE_METHODS = new Set([
1514
1565
  "updatePermissionPolicy",
1515
1566
  "hasSession",
1516
1567
  "ensureSession",
1568
+ "tailSessionHistory",
1517
1569
  "prompt",
1518
1570
  "setMode",
1519
1571
  "cancel",
@@ -1522,6 +1574,7 @@ var BRIDGE_METHODS = new Set([
1522
1574
  var SESSION_SCOPED_METHODS = new Set([
1523
1575
  "hasSession",
1524
1576
  "ensureSession",
1577
+ "tailSessionHistory",
1525
1578
  "prompt",
1526
1579
  "setMode",
1527
1580
  "cancel",
@@ -1596,6 +1649,14 @@ class BridgeServer {
1596
1649
  cwd: requireString(params, "cwd"),
1597
1650
  name: requireString(params, "name")
1598
1651
  });
1652
+ case "tailSessionHistory":
1653
+ return await this.runtime.tailSessionHistory({
1654
+ agent: requireString(params, "agent"),
1655
+ agentCommand: asOptionalString(params.agentCommand),
1656
+ cwd: requireString(params, "cwd"),
1657
+ name: requireString(params, "name"),
1658
+ lines: requirePositiveInt(params, "lines")
1659
+ });
1599
1660
  case "ensureSession":
1600
1661
  return await this.runtime.ensureSession({
1601
1662
  agent: requireString(params, "agent"),
@@ -1647,6 +1708,12 @@ class BridgeServer {
1647
1708
  event: "prompt.tool_event",
1648
1709
  toolEvent: event.event
1649
1710
  }));
1711
+ } else if (event.type === "prompt.thought") {
1712
+ writeLine?.(encodeBridgePromptThoughtEvent({
1713
+ id: requestId,
1714
+ event: "prompt.thought",
1715
+ text: event.text
1716
+ }));
1650
1717
  }
1651
1718
  });
1652
1719
  case "setMode":
@@ -1745,6 +1812,13 @@ function requireString(params, key) {
1745
1812
  }
1746
1813
  return value;
1747
1814
  }
1815
+ function requirePositiveInt(params, key) {
1816
+ const value = params[key];
1817
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
1818
+ throw new BridgeInvalidRequestError(`${key} must be a positive integer`);
1819
+ }
1820
+ return value;
1821
+ }
1748
1822
  function requirePromptText(params, media) {
1749
1823
  const value = params.text;
1750
1824
  if (typeof value !== "string") {
@@ -71,6 +71,10 @@ export interface ToolUseEvent {
71
71
  kind: ToolUseKind;
72
72
  /** Best-effort one-line summary derived from `rawInput`. */
73
73
  summary?: string;
74
+ rawInput?: unknown;
75
+ content?: unknown;
76
+ rawOutput?: unknown;
77
+ locations?: unknown;
74
78
  status: ToolUseStatus;
75
79
  /** Set when status transitions out of "running". */
76
80
  durationMs?: number;
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"),
@@ -10044,6 +10050,31 @@ function resolveWeixinStateDir() {
10044
10050
  function resolveAccountIndexPath() {
10045
10051
  return path4.join(resolveWeixinStateDir(), "accounts.json");
10046
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
+ }
10047
10078
  function listIndexedWeixinAccountIds() {
10048
10079
  const filePath = resolveAccountIndexPath();
10049
10080
  try {
@@ -10053,7 +10084,7 @@ function listIndexedWeixinAccountIds() {
10053
10084
  const parsed = JSON.parse(raw);
10054
10085
  if (!Array.isArray(parsed))
10055
10086
  return [];
10056
- return parsed.filter((id) => typeof id === "string" && id.trim() !== "");
10087
+ return uniqueAccountIds(parsed.filter((id) => typeof id === "string" && id.trim() !== ""));
10057
10088
  } catch {
10058
10089
  return [];
10059
10090
  }
@@ -10128,7 +10159,10 @@ function clearWeixinAccount(accountId) {
10128
10159
  } catch {}
10129
10160
  }
10130
10161
  function clearAllWeixinAccounts() {
10131
- const ids = listIndexedWeixinAccountIds();
10162
+ const ids = uniqueAccountIds([
10163
+ ...listIndexedWeixinAccountIds(),
10164
+ ...listAccountFileIds()
10165
+ ]);
10132
10166
  for (const id of ids) {
10133
10167
  clearWeixinAccount(id);
10134
10168
  }
@@ -10169,7 +10203,10 @@ function loadConfigRouteTag(accountId) {
10169
10203
  }
10170
10204
  }
10171
10205
  function listWeixinAccountIds() {
10172
- return listIndexedWeixinAccountIds();
10206
+ const indexed = listIndexedWeixinAccountIds();
10207
+ if (indexed.length > 0)
10208
+ return indexed;
10209
+ return listAccountFileIds();
10173
10210
  }
10174
10211
  function resolveWeixinAccount(accountId) {
10175
10212
  const raw = accountId?.trim();
@@ -15672,6 +15709,18 @@ function parseCommand(input) {
15672
15709
  return { kind: "workspaces" };
15673
15710
  if (command === "/session" && parts[1] === "reset" && parts.length === 2)
15674
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
+ }
15675
15724
  if (command === "/session" && parts[1] === "rm" && parts[2] && parts.length === 3) {
15676
15725
  return { kind: "session.rm", alias: parts[2] };
15677
15726
  }
@@ -15981,6 +16030,16 @@ function tokenizeCommand(input) {
15981
16030
  }
15982
16031
  return tokens;
15983
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
+ }
15984
16043
  function parseListFilterFlags(parts, validStatuses) {
15985
16044
  const filter = {};
15986
16045
  let i = 1;
@@ -16104,6 +16163,7 @@ var init_command_policy = __esm(() => {
16104
16163
  "agents",
16105
16164
  "workspaces",
16106
16165
  "sessions",
16166
+ "session.tail",
16107
16167
  "status",
16108
16168
  "mode.show",
16109
16169
  "replymode.show",
@@ -16120,6 +16180,7 @@ var init_command_policy = __esm(() => {
16120
16180
  COMMAND_KIND_TO_LABEL = {
16121
16181
  "session.reset": "/clear",
16122
16182
  "session.rm": "/session rm",
16183
+ "session.tail": "/session tail",
16123
16184
  "replymode.set": "/replymode",
16124
16185
  "replymode.reset": "/replymode reset",
16125
16186
  "mode.set": "/mode",
@@ -16256,7 +16317,7 @@ async function handleConfigSet(context, path13, rawValue) {
16256
16317
  return { text: result.error };
16257
16318
  }
16258
16319
  await context.configStore.save(updated);
16259
- if (path13 === "transport.permissionMode" || path13 === "transport.nonInteractivePermissions") {
16320
+ if (path13 === "transport.permissionMode" || path13 === "transport.nonInteractivePermissions" || path13 === "transport.permissionPolicy") {
16260
16321
  try {
16261
16322
  await context.transport.updatePermissionPolicy?.(updated.transport);
16262
16323
  } catch (error2) {
@@ -16303,6 +16364,11 @@ function applySupportedConfigUpdate(config2, path13, rawValue) {
16303
16364
  config2.transport.nonInteractivePermissions = parsed;
16304
16365
  return { renderedValue: parsed };
16305
16366
  }
16367
+ case "transport.permissionPolicy":
16368
+ if (!rawValue.trim())
16369
+ return { error: "transport.permissionPolicy 不能为空。" };
16370
+ config2.transport.permissionPolicy = rawValue;
16371
+ return { renderedValue: rawValue };
16306
16372
  case "logging.level": {
16307
16373
  const parsed = parseEnum(rawValue, ["error", "info", "debug"]);
16308
16374
  if (!parsed)
@@ -16412,6 +16478,7 @@ var init_config_handler = __esm(() => {
16412
16478
  "transport.sessionInitTimeoutMs",
16413
16479
  "transport.permissionMode",
16414
16480
  "transport.nonInteractivePermissions",
16481
+ "transport.permissionPolicy",
16415
16482
  "logging.level",
16416
16483
  "logging.maxSizeBytes",
16417
16484
  "logging.maxFiles",
@@ -16966,6 +17033,15 @@ async function handleCancel(context, chatKey) {
16966
17033
  async function handleSessionReset(context, chatKey) {
16967
17034
  return await context.lifecycle.resetCurrentSession(chatKey);
16968
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
+ }
16969
17045
  async function handleSessionRemove(context, chatKey, alias) {
16970
17046
  const internalAlias = await context.sessions.resolveAliasForChat(chatKey, alias);
16971
17047
  const session = await context.sessions.getSession(internalAlias);
@@ -17036,7 +17112,7 @@ async function handleSessionRemove(context, chatKey, alias) {
17036
17112
  return { text: lines.join(`
17037
17113
  `) };
17038
17114
  }
17039
- 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) {
17040
17116
  const effectiveReplyMode = session.replyMode ?? context.config?.channel.replyMode ?? "verbose";
17041
17117
  if (!session.replyMode)
17042
17118
  session.replyMode = effectiveReplyMode;
@@ -17061,7 +17137,7 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
17061
17137
  const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session, chatKey, text, replyContextToken, accountId);
17062
17138
  try {
17063
17139
  const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
17064
- 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);
17065
17141
  if (claimHumanReply) {
17066
17142
  try {
17067
17143
  await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
@@ -17081,17 +17157,17 @@ async function promptWithSession(context, session, chatKey, text, reply, replyCo
17081
17157
  throw error2;
17082
17158
  }
17083
17159
  }
17084
- 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) {
17085
17161
  const session = await context.sessions.getCurrentSession(chatKey);
17086
17162
  if (!session) {
17087
17163
  return { text: NO_CURRENT_SESSION_TEXT };
17088
17164
  }
17089
17165
  try {
17090
- 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);
17091
17167
  } catch (error2) {
17092
17168
  const recovered = await context.recovery.tryRecoverMissingSession(session, error2);
17093
17169
  if (recovered) {
17094
- 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);
17095
17171
  }
17096
17172
  return context.recovery.renderTransportError(session, error2);
17097
17173
  }
@@ -17158,7 +17234,7 @@ async function markCoordinatorResultsInjectionFailed(context, taskIds, groupIds,
17158
17234
  });
17159
17235
  }
17160
17236
  }
17161
- 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;
17162
17238
  var init_session_handler = __esm(() => {
17163
17239
  init_build_coordinator_prompt();
17164
17240
  init_channel_scope();
@@ -17173,6 +17249,7 @@ var init_session_handler = __esm(() => {
17173
17249
  { usage: "/ss new <agent> (-d <path> | --ws <name>)", description: "强制新建会话" },
17174
17250
  { usage: "/ss new <alias> -a <name> --ws <name>", description: "按指定配置新建会话" },
17175
17251
  { usage: "/ss attach <alias> -a <name> --ws <name> --name <transport-session>", description: "绑定已有会话" },
17252
+ { usage: "/session tail [N]", description: "补拉当前会话的历史输出(默认 50 行)" },
17176
17253
  { usage: "/session rm <alias>", description: "删除逻辑会话" },
17177
17254
  { usage: "/use <alias>", description: "切换当前会话" },
17178
17255
  { usage: "/session reset 或 /clear", description: "重置当前会话上下文" }
@@ -18595,7 +18672,7 @@ class CommandRouter {
18595
18672
  this.quota = quota;
18596
18673
  this.logger = logger2 ?? createNoopAppLogger();
18597
18674
  }
18598
- 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) {
18599
18676
  const startedAt = Date.now();
18600
18677
  const command = parseCommand(input);
18601
18678
  await this.logger.debug("command.parsed", "parsed inbound command", {
@@ -18685,6 +18762,8 @@ class CommandRouter {
18685
18762
  return await handleCancel(this.createSessionHandlerContext(undefined, perfSpan), chatKey);
18686
18763
  case "session.reset":
18687
18764
  return await handleSessionReset(this.createSessionHandlerContext(reply, perfSpan), chatKey);
18765
+ case "session.tail":
18766
+ return await handleSessionTail(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.lines);
18688
18767
  case "session.rm":
18689
18768
  return await handleSessionRemove(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias);
18690
18769
  case "groups":
@@ -18712,7 +18791,7 @@ class CommandRouter {
18712
18791
  case "task.cancel":
18713
18792
  return await handleTaskCancel(this.createHandlerContext(), chatKey, command.taskId);
18714
18793
  case "prompt":
18715
- 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);
18716
18795
  }
18717
18796
  });
18718
18797
  }
@@ -18765,7 +18844,7 @@ class CommandRouter {
18765
18844
  return {
18766
18845
  setModeTransportSession: (session, modeId) => this.setModeTransportSession(session, modeId),
18767
18846
  cancelTransportSession: (session) => this.cancelTransportSession(session),
18768
- 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)
18769
18848
  };
18770
18849
  }
18771
18850
  createSessionRenderRecoveryOps() {
@@ -18943,7 +19022,7 @@ class CommandRouter {
18943
19022
  async checkTransportSession(session) {
18944
19023
  return await this.measureTransportCall("has_session", session, () => this.transport.hasSession(session));
18945
19024
  }
18946
- async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, perfSpan) {
19025
+ async promptTransportSession(session, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan) {
18947
19026
  session.mcpCoordinatorSession ??= session.transportSession;
18948
19027
  let done = false;
18949
19028
  let abortRequested = false;
@@ -18999,7 +19078,8 @@ class CommandRouter {
18999
19078
  return await this.measureTransportCall("prompt", session, () => this.transport.prompt(session, text, reply, replyContext, {
19000
19079
  ...media ? { media } : {},
19001
19080
  ...reply ? { onSegment } : {},
19002
- ...onToolEvent ? { onToolEvent } : {}
19081
+ ...onToolEvent ? { onToolEvent } : {},
19082
+ ...onThought ? { onThought } : {}
19003
19083
  }));
19004
19084
  } catch (error2) {
19005
19085
  localOutcome = isAbortError2(error2) || abortRequested ? "aborted" : "error";
@@ -19165,7 +19245,7 @@ class ConsoleAgent {
19165
19245
  ...m.fileName ? { fileName: m.fileName } : {}
19166
19246
  })) : undefined;
19167
19247
  request.perfSpan?.mark("agent.dispatched");
19168
- 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);
19169
19249
  }
19170
19250
  isKnownCommand(text) {
19171
19251
  return isKnownWeacpxCommandText(text);
@@ -23333,6 +23413,10 @@ function encodeBridgePromptToolEvent(event) {
23333
23413
  return `${JSON.stringify(event)}
23334
23414
  `;
23335
23415
  }
23416
+ function encodeBridgePromptThoughtEvent(event) {
23417
+ return `${JSON.stringify(event)}
23418
+ `;
23419
+ }
23336
23420
  function encodeBridgeSessionProgressEvent(event) {
23337
23421
  return `${JSON.stringify(event)}
23338
23422
  `;
@@ -23405,6 +23489,11 @@ class AcpxBridgeClient {
23405
23489
  type: "prompt.tool_event",
23406
23490
  event: message.toolEvent
23407
23491
  });
23492
+ } else if (message.event === "prompt.thought") {
23493
+ pending.onEvent?.({
23494
+ type: "prompt.thought",
23495
+ text: message.text
23496
+ });
23408
23497
  } else if (message.event === "session.progress") {
23409
23498
  pending.onEvent?.({
23410
23499
  type: "session.progress",
@@ -23754,6 +23843,12 @@ class AcpxBridgeTransport {
23754
23843
  }
23755
23844
  } : undefined);
23756
23845
  }
23846
+ async tailSessionHistory(session, lines) {
23847
+ return await this.client.request("tailSessionHistory", {
23848
+ ...this.toParams(session),
23849
+ lines
23850
+ });
23851
+ }
23757
23852
  async prompt(session, text, reply, replyContext, options) {
23758
23853
  const sink = reply ? createQuotaGatedReplySink({
23759
23854
  reply,
@@ -23763,6 +23858,8 @@ class AcpxBridgeTransport {
23763
23858
  let segmentChain = Promise.resolve();
23764
23859
  let toolEventError;
23765
23860
  let toolEventChain = Promise.resolve();
23861
+ let thoughtError;
23862
+ let thoughtChain = Promise.resolve();
23766
23863
  let toolEventMode = resolveToolEventMode(options);
23767
23864
  if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
23768
23865
  toolEventMode = "text";
@@ -23795,9 +23892,20 @@ class AcpxBridgeTransport {
23795
23892
  }
23796
23893
  return;
23797
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
+ }
23798
23905
  });
23799
23906
  await segmentChain;
23800
23907
  await toolEventChain;
23908
+ await thoughtChain;
23801
23909
  if (sink) {
23802
23910
  const { overflowCount } = sink.finalize();
23803
23911
  await sink.drain({ timeoutMs: 30000 });
@@ -23812,6 +23920,9 @@ class AcpxBridgeTransport {
23812
23920
  if (toolEventError) {
23813
23921
  throw toolEventError;
23814
23922
  }
23923
+ if (thoughtError) {
23924
+ throw thoughtError;
23925
+ }
23815
23926
  return { text: summary ? `${summary}
23816
23927
 
23817
23928
  ${result.text}` : "" };
@@ -23822,6 +23933,9 @@ ${result.text}` : "" };
23822
23933
  if (toolEventError) {
23823
23934
  throw toolEventError;
23824
23935
  }
23936
+ if (thoughtError) {
23937
+ throw thoughtError;
23938
+ }
23825
23939
  return result;
23826
23940
  }
23827
23941
  async setMode(session, modeId) {
@@ -24026,6 +24140,7 @@ var init_tool_kind_emoji = __esm(() => {
24026
24140
  function createStreamingPromptState(formatToolCalls = false, options) {
24027
24141
  let toolEventMode;
24028
24142
  let onToolEvent;
24143
+ let onThought;
24029
24144
  if (options === undefined) {
24030
24145
  toolEventMode = "text";
24031
24146
  onToolEvent = undefined;
@@ -24034,6 +24149,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
24034
24149
  toolEventMode = "structured";
24035
24150
  } else {
24036
24151
  onToolEvent = options.onToolEvent;
24152
+ onThought = options.onThought;
24037
24153
  toolEventMode = resolveToolEventMode({
24038
24154
  toolEventMode: options.mode,
24039
24155
  onToolEvent
@@ -24048,6 +24164,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
24048
24164
  emittedToolCallIds: new Set,
24049
24165
  toolEventMode,
24050
24166
  onToolEvent,
24167
+ onThought,
24051
24168
  finalize() {
24052
24169
  if (this.pendingLine.trim().length > 0) {
24053
24170
  parseStreamingChunks(this, this.pendingLine);
@@ -24106,6 +24223,14 @@ function parseStreamingChunks(state, line) {
24106
24223
  }
24107
24224
  return;
24108
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
+ }
24109
24234
  const isMessageChunk = update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
24110
24235
  if (!isMessageChunk)
24111
24236
  return;
@@ -24133,7 +24258,7 @@ function formatToolCallEvent(update, sessionUpdate) {
24133
24258
  if (title.length === 0)
24134
24259
  return null;
24135
24260
  const emoji2 = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
24136
- const inputSummary = summarizeToolInput(update.rawInput, title);
24261
+ const inputSummary = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
24137
24262
  const status = readString(update, "status");
24138
24263
  if (!inputSummary && status === "pending")
24139
24264
  return null;
@@ -24164,15 +24289,23 @@ function buildToolUseEvent(update) {
24164
24289
  })();
24165
24290
  const title = (update.title ?? "").trim();
24166
24291
  const toolName = title || "Tool";
24167
- const summaryRaw = summarizeToolInput(update.rawInput, title);
24292
+ const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
24168
24293
  const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
24169
24294
  const statusRaw = readString(update, "status");
24170
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;
24171
24300
  return {
24172
24301
  toolCallId,
24173
24302
  toolName,
24174
24303
  kind,
24175
24304
  ...summary ? { summary } : {},
24305
+ ...rawInput !== undefined ? { rawInput } : {},
24306
+ ...content !== undefined ? { content } : {},
24307
+ ...rawOutput !== undefined ? { rawOutput } : {},
24308
+ ...locations !== undefined ? { locations } : {},
24176
24309
  status
24177
24310
  };
24178
24311
  }
@@ -24333,6 +24466,8 @@ function buildQueueOwnerPayload(input) {
24333
24466
  nonInteractivePermissions: input.nonInteractivePermissions,
24334
24467
  ttlMs: input.ttlMs ?? 300000,
24335
24468
  maxQueueDepth: input.maxQueueDepth ?? 16,
24469
+ ...Number.isFinite(input.promptRetries) ? { promptRetries: input.promptRetries } : {},
24470
+ ...input.sessionOptions ? { sessionOptions: input.sessionOptions } : {},
24336
24471
  mcpServers: input.mcpServers
24337
24472
  };
24338
24473
  }
@@ -24585,6 +24720,7 @@ class AcpxCliTransport {
24585
24720
  sessionInitTimeoutMs;
24586
24721
  permissionMode;
24587
24722
  nonInteractivePermissions;
24723
+ permissionPolicy;
24588
24724
  runCommand;
24589
24725
  runPtyCommand;
24590
24726
  queueOwnerLauncher;
@@ -24594,6 +24730,7 @@ class AcpxCliTransport {
24594
24730
  this.sessionInitTimeoutMs = options.sessionInitTimeoutMs ?? 120000;
24595
24731
  this.permissionMode = options.permissionMode ?? "approve-all";
24596
24732
  this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
24733
+ this.permissionPolicy = options.permissionPolicy;
24597
24734
  this.runCommand = runCommand;
24598
24735
  this.runPtyCommand = runPtyCommand;
24599
24736
  this.queueOwnerLauncher = queueOwnerLauncher ?? new AcpxQueueOwnerLauncher({
@@ -24613,18 +24750,38 @@ class AcpxCliTransport {
24613
24750
  timeoutMs: this.sessionInitTimeoutMs
24614
24751
  });
24615
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
+ }
24616
24773
  async prompt(session, text, reply, replyContext, options) {
24617
24774
  await this.launchMcpQueueOwnerIfNeeded(session);
24618
24775
  const structuredPrompt = await createStructuredPromptFile(text, options?.media);
24619
24776
  const args = this.buildPromptArgs(session, text, structuredPrompt?.filePath);
24620
24777
  try {
24621
- if (reply || options?.onSegment || options?.onToolEvent) {
24778
+ if (reply || options?.onSegment || options?.onToolEvent || options?.onThought) {
24622
24779
  const formatToolCalls = (session.replyMode ?? "verbose") === "verbose";
24623
24780
  let toolEventMode = resolveToolEventMode(options);
24624
24781
  if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
24625
24782
  toolEventMode = "text";
24626
24783
  }
24627
- 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);
24628
24785
  const baseText = getPromptText(result2);
24629
24786
  if (!reply) {
24630
24787
  return { text: baseText };
@@ -24664,6 +24821,7 @@ ${baseText}` : "" };
24664
24821
  async updatePermissionPolicy(policy) {
24665
24822
  this.permissionMode = policy.permissionMode;
24666
24823
  this.nonInteractivePermissions = policy.nonInteractivePermissions;
24824
+ this.permissionPolicy = policy.permissionPolicy;
24667
24825
  }
24668
24826
  async removeSession(session) {
24669
24827
  const result = await this.runCommand(this.command, this.buildArgs(session, [
@@ -24761,7 +24919,7 @@ ${baseText}` : "" };
24761
24919
  })
24762
24920
  ]);
24763
24921
  }
24764
- 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) {
24765
24923
  const hooks = this.streamingHooks;
24766
24924
  const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn9(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
24767
24925
  const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
@@ -24779,7 +24937,10 @@ ${baseText}` : "" };
24779
24937
  let segmentError;
24780
24938
  let toolEventChain = Promise.resolve();
24781
24939
  let toolEventError;
24940
+ let thoughtChain = Promise.resolve();
24941
+ let thoughtError;
24782
24942
  const userOnToolEvent = onToolEvent;
24943
+ const userOnThought = onThought;
24783
24944
  const state = createStreamingPromptState(formatToolCalls, {
24784
24945
  mode: toolEventMode,
24785
24946
  ...userOnToolEvent ? {
@@ -24788,6 +24949,13 @@ ${baseText}` : "" };
24788
24949
  toolEventError ??= error2;
24789
24950
  });
24790
24951
  }
24952
+ } : {},
24953
+ ...userOnThought ? {
24954
+ onThought: (chunk) => {
24955
+ thoughtChain = thoughtChain.then(() => userOnThought(chunk)).catch((error2) => {
24956
+ thoughtError ??= error2;
24957
+ });
24958
+ }
24791
24959
  } : {}
24792
24960
  });
24793
24961
  const sink = reply ? createQuotaGatedReplySink({
@@ -24840,7 +25008,8 @@ ${baseText}` : "" };
24840
25008
  Promise.all([
24841
25009
  sink?.drain({ timeoutMs: 30000 }) ?? Promise.resolve(),
24842
25010
  segmentChain,
24843
- toolEventChain
25011
+ toolEventChain,
25012
+ thoughtChain
24844
25013
  ]).then(() => {
24845
25014
  const deferred = sink?.getPendingError();
24846
25015
  if (deferred) {
@@ -24855,6 +25024,10 @@ ${baseText}` : "" };
24855
25024
  reject(toolEventError);
24856
25025
  return;
24857
25026
  }
25027
+ if (thoughtError) {
25028
+ reject(thoughtError);
25029
+ return;
25030
+ }
24858
25031
  resolve3({
24859
25032
  result: { code: code ?? 1, stdout: stdout2, stderr },
24860
25033
  overflowCount
@@ -24895,7 +25068,11 @@ ${baseText}` : "" };
24895
25068
  }
24896
25069
  buildPermissionArgs() {
24897
25070
  const modeFlag = permissionModeToFlag(this.permissionMode);
24898
- 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;
24899
25076
  }
24900
25077
  }
24901
25078
  function isMissingAcpxSessionError(stderr, stdout2) {
@@ -25876,7 +26053,11 @@ import { fileURLToPath as fileURLToPath5 } from "node:url";
25876
26053
  import { homedir as homedir10 } from "node:os";
25877
26054
  async function checkDaemon(options = {}) {
25878
26055
  const home = options.home ?? process.env.HOME ?? homedir10();
25879
- 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
+ });
25880
26061
  const controller = createDaemonController(paths, {
25881
26062
  processExecPath: options.processExecPath ?? process.execPath,
25882
26063
  cliEntryPath: options.cliEntryPath ?? resolveCliEntryPath(),
@@ -26028,7 +26209,11 @@ import { dirname as dirname14 } from "node:path";
26028
26209
  import { homedir as homedir11 } from "node:os";
26029
26210
  async function checkRuntime(options = {}) {
26030
26211
  const home = options.home ?? process.env.HOME ?? homedir11();
26031
- 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
+ });
26032
26217
  const probe = options.probe ?? createRuntimeFsProbe();
26033
26218
  const platform = options.platform ?? process.platform;
26034
26219
  const checks3 = [
@@ -26591,10 +26776,12 @@ async function runDoctor(options = {}, deps = {}) {
26591
26776
  resolveRuntimePaths: () => runtimePaths
26592
26777
  }));
26593
26778
  checks3.push(await (deps.checkRuntime ?? checkRuntime)({
26594
- home
26779
+ home,
26780
+ configPath: runtimePaths.configPath
26595
26781
  }));
26596
26782
  checks3.push(await (deps.checkDaemon ?? checkDaemon)({
26597
- home
26783
+ home,
26784
+ configPath: runtimePaths.configPath
26598
26785
  }));
26599
26786
  checks3.push(await (deps.checkWechat ?? checkWechat)({
26600
26787
  verbose: options.verbose
@@ -42311,7 +42498,7 @@ async function runCli(args, deps = {}) {
42311
42498
  case "mcp-stdio":
42312
42499
  return await (deps.mcpStdio ?? ((subArgs) => defaultMcpStdio(subArgs, { stderr: deps.stderr })))(args.slice(1));
42313
42500
  case "start": {
42314
- const controller = deps.controller ?? createDefaultController();
42501
+ const controller = deps.controller ?? createDefaultController(deps);
42315
42502
  try {
42316
42503
  const isInteractive = deps.isInteractive ?? defaultIsInteractive;
42317
42504
  const status = await controller.getStatus();
@@ -42354,7 +42541,7 @@ async function runCli(args, deps = {}) {
42354
42541
  }
42355
42542
  }
42356
42543
  case "status": {
42357
- const controller = deps.controller ?? createDefaultController();
42544
+ const controller = deps.controller ?? createDefaultController(deps);
42358
42545
  const status = await controller.getStatus();
42359
42546
  if (status.state === "indeterminate") {
42360
42547
  print("weacpx 进程仍在运行,但状态元数据缺失");
@@ -42377,7 +42564,7 @@ async function runCli(args, deps = {}) {
42377
42564
  return 0;
42378
42565
  }
42379
42566
  case "stop": {
42380
- const controller = deps.controller ?? createDefaultController();
42567
+ const controller = deps.controller ?? createDefaultController(deps);
42381
42568
  const result = await controller.stop();
42382
42569
  if (result.detail === "not-running") {
42383
42570
  print("weacpx 未运行");
@@ -42387,7 +42574,7 @@ async function runCli(args, deps = {}) {
42387
42574
  return 0;
42388
42575
  }
42389
42576
  case "restart": {
42390
- const controller = deps.controller ?? createDefaultController();
42577
+ const controller = deps.controller ?? createDefaultController(deps);
42391
42578
  try {
42392
42579
  return await restartDaemonCli(controller, print);
42393
42580
  } catch (error2) {
@@ -42600,8 +42787,18 @@ async function agentRemove(rawName, print) {
42600
42787
  print(`Agent「${name}」已删除`);
42601
42788
  return 0;
42602
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
+ }
42603
42800
  async function createCliConfigStore() {
42604
- const configPath = process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
42801
+ const configPath = resolveConfigPathForCurrentEnv();
42605
42802
  await ensureConfigExists(configPath);
42606
42803
  return new ConfigStore(configPath);
42607
42804
  }
@@ -42636,7 +42833,7 @@ async function defaultRun(options = {}) {
42636
42833
  await loadConfiguredPlugins2({ plugins: config2.plugins });
42637
42834
  const { createMessageChannels: createMessageChannels2 } = await Promise.resolve().then(() => (init_create_channel(), exports_create_channel));
42638
42835
  const { MessageChannelRegistry: MessageChannelRegistry2 } = await Promise.resolve().then(() => (init_channel_registry(), exports_channel_registry));
42639
- const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
42836
+ const daemonPaths = resolveDaemonPathsForCurrentConfig();
42640
42837
  const daemonRuntime = new DaemonRuntime(daemonPaths, { pid: process.pid });
42641
42838
  const { channelDeps } = await prepareChannelMedia2(runtimePaths.configPath, config2);
42642
42839
  const channelRegistry = new MessageChannelRegistry2(createMessageChannels2(config2.channels, channelDeps));
@@ -42882,13 +43079,14 @@ async function defaultPromptSecret(message) {
42882
43079
  process.stdin.on("data", onData);
42883
43080
  });
42884
43081
  }
42885
- function createDefaultController() {
42886
- const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
43082
+ function createDefaultController(deps = {}) {
43083
+ const daemonPaths = resolveDaemonPathsForCurrentConfig();
42887
43084
  const controller = createDaemonController(daemonPaths, {
42888
43085
  processExecPath: process.execPath,
42889
43086
  cliEntryPath: resolveCliEntryPath2(),
42890
43087
  cwd: process.cwd(),
42891
- env: process.env
43088
+ env: process.env,
43089
+ ...deps.isProcessRunning ? { isProcessRunning: deps.isProcessRunning } : {}
42892
43090
  });
42893
43091
  return {
42894
43092
  getStatus: () => controller.getStatus(),
@@ -42944,8 +43142,8 @@ function printDaemonLogHints(print) {
42944
43142
  }
42945
43143
  function safeDaemonLogPaths() {
42946
43144
  try {
42947
- const configPath = process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
42948
- const paths = resolveDaemonPaths({ home: requireHome2() });
43145
+ const configPath = resolveConfigPathForCurrentEnv();
43146
+ const paths = resolveDaemonPathsForCurrentConfig();
42949
43147
  return {
42950
43148
  appLog: join16(dirname15(configPath), "runtime", "app.log"),
42951
43149
  stderrLog: paths.stderrLog
@@ -18,6 +18,7 @@ export interface TransportConfig {
18
18
  sessionInitTimeoutMs?: number;
19
19
  permissionMode: PermissionMode;
20
20
  nonInteractivePermissions: NonInteractivePermissions;
21
+ permissionPolicy?: string;
21
22
  }
22
23
  export type LoggingLevel = "error" | "info" | "debug";
23
24
  export interface PerfLogConfig {
@@ -46,6 +46,8 @@ export interface ChatRequest {
46
46
  abortSignal?: AbortSignal;
47
47
  /** Structured tool-use side-channel; see PromptOptions.onToolEvent. */
48
48
  onToolEvent?: (event: ToolUseEvent) => void | Promise<void>;
49
+ /** Structured thinking side-channel; see PromptOptions.onThought. */
50
+ onThought?: (chunk: string) => void | Promise<void>;
49
51
  /**
50
52
  * Optional per-turn performance tracing span. When `logging.perf.enabled` is
51
53
  * true, the channel handler attaches a `PerfSpan` so downstream layers can
@@ -57,7 +57,7 @@ export type ResolvedWeixinAccount = {
57
57
  /** true when a token has been obtained via QR login. */
58
58
  configured: boolean;
59
59
  };
60
- /** List accountIds from the index file (written at QR login). */
60
+ /** List accountIds from the index file (written at QR login), with a credential-file fallback for legacy/broken indexes. */
61
61
  export declare function listWeixinAccountIds(): string[];
62
62
  /** Resolve a weixin account by ID, reading stored credentials. */
63
63
  export declare function resolveWeixinAccount(accountId?: string | null): ResolvedWeixinAccount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weacpx",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "使用微信 ClawBot 随时随地通过 `acpx` 控制 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@modelcontextprotocol/sdk": "^1.29.0",
68
- "acpx": "^0.6.1",
68
+ "acpx": "^0.8.0",
69
69
  "node-pty": "^1.1.0",
70
70
  "proper-lockfile": "^4.1.2",
71
71
  "protobufjs": "^7.5.6",