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/README.md +5 -12
- package/dist/bridge/bridge-main.js +84 -6
- package/dist/channels/types.d.ts +4 -0
- package/dist/cli.js +323 -553
- package/dist/config/types.d.ts +1 -0
- package/dist/weixin/agent/interface.d.ts +2 -0
- package/dist/weixin/auth/accounts.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ weacpx restart
|
|
|
169
169
|
| `weacpx status` | 查看后台状态、PID、配置路径、日志路径 |
|
|
170
170
|
| `weacpx stop` | 停止后台实例 |
|
|
171
171
|
| `weacpx restart` | 重启后台实例,让频道配置变更生效 |
|
|
172
|
-
| `weacpx update [--all
|
|
172
|
+
| `weacpx update [--all\|<name>]` | 检查并更新 weacpx 与已安装插件;安装了插件时会交互式选择更新项 |
|
|
173
173
|
| `weacpx channel list` | 查看已配置的消息频道 |
|
|
174
174
|
| `weacpx plugin known` | 查看官方插件清单(飞书/元宝包名) |
|
|
175
175
|
| `weacpx plugin add @ganglion/weacpx-channel-feishu && weacpx channel add feishu` | 安装并添加飞书频道,会提示输入飞书应用凭据 |
|
|
@@ -351,22 +351,15 @@ README 里只保留用户视角的最常用命令。
|
|
|
351
351
|
| 命令 | 说明 |
|
|
352
352
|
|------|------|
|
|
353
353
|
| `/dg <agent> <task>` | 快速委派一个子任务 |
|
|
354
|
-
| `/group new <title>` | 创建任务组 |
|
|
355
|
-
| `/group add <groupId> <agent> <task>` | 往任务组里加子任务 |
|
|
356
|
-
| `/groups` | 查看任务组列表 |
|
|
357
|
-
| `/group <id>` | 查看单个任务组 |
|
|
358
|
-
| `/group cancel <groupId>` | 取消组内未结束任务 |
|
|
359
354
|
| `/tasks` | 查看当前主线下的任务 |
|
|
360
355
|
| `/task <id>` | 查看单个任务详情 |
|
|
361
356
|
| `/task approve <id>` | 批准 `needs_confirmation` 任务 |
|
|
362
|
-
| `/task cancel <id>` |
|
|
357
|
+
| `/task cancel <id>` | 取消任务;取消一个尚未批准的任务等同于拒绝 |
|
|
363
358
|
|
|
364
359
|
最常见例子:
|
|
365
360
|
|
|
366
361
|
```text
|
|
367
362
|
/dg claude 审查当前方案的 3 个高风险点
|
|
368
|
-
/group new review
|
|
369
|
-
/group add review claude 审查接口设计
|
|
370
363
|
/tasks
|
|
371
364
|
/task approve task_123
|
|
372
365
|
```
|
|
@@ -376,9 +369,9 @@ README 里只保留用户视角的最常用命令。
|
|
|
376
369
|
- 当前会话就是主控会话
|
|
377
370
|
- 被委派出去的是独立子任务会话
|
|
378
371
|
- agent 发起的委派请求默认需要人工确认
|
|
379
|
-
-
|
|
372
|
+
- 如果你在用外部 MCP host(Codex / Claude Code),用 `delegate_batch` 一次派发多个并行子任务:传一个 `tasks` 数组,底层自动建组,全部结果一次性回注,无需手动维护 groupId
|
|
380
373
|
|
|
381
|
-
如果你想先理解什么时候该用 delegate
|
|
374
|
+
如果你想先理解什么时候该用 delegate、什么时候应该并行派出多个子任务,请看:
|
|
382
375
|
|
|
383
376
|
- [docs/weacpx-group-usage-guide.md](./docs/weacpx-group-usage-guide.md)
|
|
384
377
|
|
|
@@ -387,7 +380,7 @@ README 里只保留用户视角的最常用命令。
|
|
|
387
380
|
|
|
388
381
|
如果你想让 Codex、Claude Code 等外部 MCP host 直接使用 weacpx 的多 Agent 编排能力,可以把 `weacpx mcp-stdio` 配成一个 stdio MCP server。
|
|
389
382
|
|
|
390
|
-
`delegate_request` 支持 MCP Tasks:支持该能力的 host 可以让委派请求立即返回原生 task handle,之后通过 `tasks/get` / `tasks/result` / `tasks/cancel` 获取状态、结果或取消任务;worker 输出的 `[PROGRESS] ...` 会显示在 `tasks/get` / `tasks/list` 的 `statusMessage` 里;`input_required` 状态下的 `tasks/result` 会返回下一步操作提示并结束本次 result stream,而不是长时间阻塞;client 按提示调用 `task_get` / `task_approve` / `coordinator_answer_question` 等工具后,再继续 `tasks/get` / `tasks/result` 轮询。不支持 MCP Tasks 的 host 仍可使用兼容工具 `task_get` / `
|
|
383
|
+
`delegate_request` 支持 MCP Tasks:支持该能力的 host 可以让委派请求立即返回原生 task handle,之后通过 `tasks/get` / `tasks/result` / `tasks/cancel` 获取状态、结果或取消任务;worker 输出的 `[PROGRESS] ...` 会显示在 `tasks/get` / `tasks/list` 的 `statusMessage` 里;`input_required` 状态下的 `tasks/result` 会返回下一步操作提示并结束本次 result stream,而不是长时间阻塞;client 按提示调用 `task_get` / `task_approve` / `coordinator_answer_question` 等工具后,再继续 `tasks/get` / `tasks/result` 轮询。不支持 MCP Tasks 的 host 仍可使用兼容工具 `task_get` / `task_list` / `task_watch` / `task_cancel`。
|
|
391
384
|
|
|
392
385
|
先启动 daemon:
|
|
393
386
|
|
|
@@ -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
|
`;
|
|
@@ -162,8 +166,12 @@ function extractJsonRpcErrorMessages(output) {
|
|
|
162
166
|
`).map((line) => line.trim()).filter((line) => line.length > 0).flatMap((line) => {
|
|
163
167
|
try {
|
|
164
168
|
const payload = JSON.parse(line);
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
const err = payload.error;
|
|
170
|
+
const dataMsg = typeof err?.data?.message === "string" && err.data.message.length > 0 ? err.data.message : undefined;
|
|
171
|
+
const baseMsg = typeof err?.message === "string" && err.message.length > 0 ? err.message : undefined;
|
|
172
|
+
const chosen = dataMsg && dataMsg !== baseMsg ? dataMsg : baseMsg;
|
|
173
|
+
if (chosen) {
|
|
174
|
+
return [chosen];
|
|
167
175
|
}
|
|
168
176
|
} catch {
|
|
169
177
|
return [];
|
|
@@ -362,6 +370,7 @@ var init_tool_kind_emoji = __esm(() => {
|
|
|
362
370
|
function createStreamingPromptState(formatToolCalls = false, options) {
|
|
363
371
|
let toolEventMode;
|
|
364
372
|
let onToolEvent;
|
|
373
|
+
let onThought;
|
|
365
374
|
if (options === undefined) {
|
|
366
375
|
toolEventMode = "text";
|
|
367
376
|
onToolEvent = undefined;
|
|
@@ -370,6 +379,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
370
379
|
toolEventMode = "structured";
|
|
371
380
|
} else {
|
|
372
381
|
onToolEvent = options.onToolEvent;
|
|
382
|
+
onThought = options.onThought;
|
|
373
383
|
toolEventMode = resolveToolEventMode({
|
|
374
384
|
toolEventMode: options.mode,
|
|
375
385
|
onToolEvent
|
|
@@ -384,6 +394,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
384
394
|
emittedToolCallIds: new Set,
|
|
385
395
|
toolEventMode,
|
|
386
396
|
onToolEvent,
|
|
397
|
+
onThought,
|
|
387
398
|
finalize() {
|
|
388
399
|
if (this.pendingLine.trim().length > 0) {
|
|
389
400
|
parseStreamingChunks(this, this.pendingLine);
|
|
@@ -442,6 +453,14 @@ function parseStreamingChunks(state, line) {
|
|
|
442
453
|
}
|
|
443
454
|
return;
|
|
444
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
|
+
}
|
|
445
464
|
const isMessageChunk = update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
|
|
446
465
|
if (!isMessageChunk)
|
|
447
466
|
return;
|
|
@@ -469,7 +488,7 @@ function formatToolCallEvent(update, sessionUpdate) {
|
|
|
469
488
|
if (title.length === 0)
|
|
470
489
|
return null;
|
|
471
490
|
const emoji = TOOL_KIND_EMOJI[kind] ?? DEFAULT_TOOL_EMOJI;
|
|
472
|
-
const inputSummary = summarizeToolInput(update.rawInput, title);
|
|
491
|
+
const inputSummary = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
|
|
473
492
|
const status = readString(update, "status");
|
|
474
493
|
if (!inputSummary && status === "pending")
|
|
475
494
|
return null;
|
|
@@ -500,15 +519,23 @@ function buildToolUseEvent(update) {
|
|
|
500
519
|
})();
|
|
501
520
|
const title = (update.title ?? "").trim();
|
|
502
521
|
const toolName = title || "Tool";
|
|
503
|
-
const summaryRaw = summarizeToolInput(update.rawInput, title);
|
|
522
|
+
const summaryRaw = summarizeToolInput(update.rawInput, title) || summarizeToolInput(update.rawOutput, title);
|
|
504
523
|
const summary = summaryRaw && summaryRaw !== title ? summaryRaw : undefined;
|
|
505
524
|
const statusRaw = readString(update, "status");
|
|
506
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;
|
|
507
530
|
return {
|
|
508
531
|
toolCallId,
|
|
509
532
|
toolName,
|
|
510
533
|
kind,
|
|
511
534
|
...summary ? { summary } : {},
|
|
535
|
+
...rawInput !== undefined ? { rawInput } : {},
|
|
536
|
+
...content !== undefined ? { content } : {},
|
|
537
|
+
...rawOutput !== undefined ? { rawOutput } : {},
|
|
538
|
+
...locations !== undefined ? { locations } : {},
|
|
512
539
|
status
|
|
513
540
|
};
|
|
514
541
|
}
|
|
@@ -827,6 +854,8 @@ function buildQueueOwnerPayload(input) {
|
|
|
827
854
|
nonInteractivePermissions: input.nonInteractivePermissions,
|
|
828
855
|
ttlMs: input.ttlMs ?? 300000,
|
|
829
856
|
maxQueueDepth: input.maxQueueDepth ?? 16,
|
|
857
|
+
...Number.isFinite(input.promptRetries) ? { promptRetries: input.promptRetries } : {},
|
|
858
|
+
...input.sessionOptions ? { sessionOptions: input.sessionOptions } : {},
|
|
830
859
|
mcpServers: input.mcpServers
|
|
831
860
|
};
|
|
832
861
|
}
|
|
@@ -1109,6 +1138,7 @@ class BridgeRuntime {
|
|
|
1109
1138
|
async updatePermissionPolicy(policy) {
|
|
1110
1139
|
this.options.permissionMode = policy.permissionMode;
|
|
1111
1140
|
this.options.nonInteractivePermissions = policy.nonInteractivePermissions;
|
|
1141
|
+
this.options.permissionPolicy = policy.permissionPolicy;
|
|
1112
1142
|
return {};
|
|
1113
1143
|
}
|
|
1114
1144
|
async hasSession(input) {
|
|
@@ -1120,6 +1150,26 @@ class BridgeRuntime {
|
|
|
1120
1150
|
const result = await this.run(spawnSpec.command, spawnSpec.args);
|
|
1121
1151
|
return { exists: result.code === 0 };
|
|
1122
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
|
+
}
|
|
1123
1173
|
async ensureSession(input, onProgress) {
|
|
1124
1174
|
onProgress?.("spawn");
|
|
1125
1175
|
const onStderrLine = onProgress ? (line) => {
|
|
@@ -1342,7 +1392,11 @@ class BridgeRuntime {
|
|
|
1342
1392
|
const permissionMode = this.options.permissionMode ?? "approve-all";
|
|
1343
1393
|
const nonInteractivePermissions = this.options.nonInteractivePermissions ?? "deny";
|
|
1344
1394
|
const modeFlag = permissionModeToFlag(permissionMode);
|
|
1345
|
-
|
|
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;
|
|
1346
1400
|
}
|
|
1347
1401
|
}
|
|
1348
1402
|
function spawnCapture(command, args, options) {
|
|
@@ -1394,7 +1448,8 @@ async function runStreamingPrompt(command, args, onEvent, options = {}) {
|
|
|
1394
1448
|
const toolEventMode = options.toolEventMode ?? "text";
|
|
1395
1449
|
const state = createStreamingPromptState(options.formatToolCalls ?? false, {
|
|
1396
1450
|
mode: toolEventMode,
|
|
1397
|
-
...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 }) } : {}
|
|
1398
1453
|
});
|
|
1399
1454
|
let lastReplyAt = now();
|
|
1400
1455
|
const flushBuffer = () => {
|
|
@@ -1510,6 +1565,7 @@ var BRIDGE_METHODS = new Set([
|
|
|
1510
1565
|
"updatePermissionPolicy",
|
|
1511
1566
|
"hasSession",
|
|
1512
1567
|
"ensureSession",
|
|
1568
|
+
"tailSessionHistory",
|
|
1513
1569
|
"prompt",
|
|
1514
1570
|
"setMode",
|
|
1515
1571
|
"cancel",
|
|
@@ -1518,6 +1574,7 @@ var BRIDGE_METHODS = new Set([
|
|
|
1518
1574
|
var SESSION_SCOPED_METHODS = new Set([
|
|
1519
1575
|
"hasSession",
|
|
1520
1576
|
"ensureSession",
|
|
1577
|
+
"tailSessionHistory",
|
|
1521
1578
|
"prompt",
|
|
1522
1579
|
"setMode",
|
|
1523
1580
|
"cancel",
|
|
@@ -1592,6 +1649,14 @@ class BridgeServer {
|
|
|
1592
1649
|
cwd: requireString(params, "cwd"),
|
|
1593
1650
|
name: requireString(params, "name")
|
|
1594
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
|
+
});
|
|
1595
1660
|
case "ensureSession":
|
|
1596
1661
|
return await this.runtime.ensureSession({
|
|
1597
1662
|
agent: requireString(params, "agent"),
|
|
@@ -1643,6 +1708,12 @@ class BridgeServer {
|
|
|
1643
1708
|
event: "prompt.tool_event",
|
|
1644
1709
|
toolEvent: event.event
|
|
1645
1710
|
}));
|
|
1711
|
+
} else if (event.type === "prompt.thought") {
|
|
1712
|
+
writeLine?.(encodeBridgePromptThoughtEvent({
|
|
1713
|
+
id: requestId,
|
|
1714
|
+
event: "prompt.thought",
|
|
1715
|
+
text: event.text
|
|
1716
|
+
}));
|
|
1646
1717
|
}
|
|
1647
1718
|
});
|
|
1648
1719
|
case "setMode":
|
|
@@ -1741,6 +1812,13 @@ function requireString(params, key) {
|
|
|
1741
1812
|
}
|
|
1742
1813
|
return value;
|
|
1743
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
|
+
}
|
|
1744
1822
|
function requirePromptText(params, media) {
|
|
1745
1823
|
const value = params.text;
|
|
1746
1824
|
if (typeof value !== "string") {
|
package/dist/channels/types.d.ts
CHANGED
|
@@ -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;
|