@bolloon/bolloon-agent 0.4.30 → 0.4.31
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/agents/agent-gateway.js +5 -0
- package/dist/agents/agent-manifest-protocol.js +29 -0
- package/dist/agents/economic-policy.js +7 -0
- package/dist/agents/gateway-network.js +6 -0
- package/dist/agents/local-signer.js +59 -0
- package/dist/agents/network-pulse.js +450 -0
- package/dist/agents/task-contract.js +322 -0
- package/dist/agents/task-inbox.js +267 -0
- package/dist/agents/task-transport.js +280 -0
- package/dist/agents/x402/transaction-store.js +8 -1
- package/dist/cli/commands/agent.js +230 -0
- package/dist/cli/commands/index.js +61 -0
- package/dist/cli/commands/mcp.js +98 -0
- package/dist/cli/commands/network.js +334 -0
- package/dist/cli/commands/payment.js +125 -0
- package/dist/cli/commands/tasks.js +1236 -0
- package/dist/cli/commands/trade.js +229 -0
- package/dist/cli/commands/wallet.js +450 -0
- package/dist/cli/mcp/bridge.js +105 -0
- package/dist/cli/mcp/server.js +185 -0
- package/dist/cli/mcp/tools.js +612 -0
- package/dist/cli/protocol-envelope.js +346 -0
- package/dist/cli-entry.js +141 -17
- package/dist/electron-build/agents/agent-gateway.js +5 -0
- package/dist/electron-build/agents/agent-gateway.js.map +1 -1
- package/dist/electron-build/agents/agent-manifest-protocol.js +62 -0
- package/dist/electron-build/agents/agent-manifest-protocol.js.map +1 -1
- package/dist/electron-build/agents/economic-policy.js +7 -0
- package/dist/electron-build/agents/economic-policy.js.map +1 -1
- package/dist/electron-build/agents/gateway-network.js +6 -0
- package/dist/electron-build/agents/gateway-network.js.map +1 -1
- package/dist/electron-build/agents/network-pulse.js +504 -0
- package/dist/electron-build/agents/network-pulse.js.map +1 -0
- package/dist/electron-build/agents/x402/transaction-store.js +8 -1
- package/dist/electron-build/agents/x402/transaction-store.js.map +1 -1
- package/dist/web/server.js +29 -0
- package/dist/web/task-frame-server.js +211 -0
- package/package.json +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* protocol-envelope.ts — P3 统一输出层 (P1 §2 冻结 JSON 信封 + §3 错误码 + §2.3 next_action 词表)
|
|
3
|
+
*
|
|
4
|
+
* 权威口径: `docs/wiki/access-protocol-v1.md`。本文件**只做四件事**, 不含任何业务逻辑:
|
|
5
|
+
* ① 全局选项解析: `--json` / `--quiet` / `--request-id <id>` / `--timeout <ms>`
|
|
6
|
+
* ② 信封构造: `{ ok, code, message, data, evidence, next_action }` (字段顺序与 §2 一致)
|
|
7
|
+
* ③ 输出: `--json` 信封 · `--quiet` 只出结果 · 默认人类可读 (既有体验是基线, 不许坏)
|
|
8
|
+
* ④ 兜底: 超时/异常也必须是**结构化失败** (§2 硬规则 1); 私钥类字段一律不进 stdout
|
|
9
|
+
*
|
|
10
|
+
* 2026-09-21 (P3): 此前 `src/` 里**没有任何** §3 错误码常量 (P1 §0 表逐条核对过) —— 本文件把它们落成常量。
|
|
11
|
+
*
|
|
12
|
+
* 三条不许破的规矩 (P1 §2 硬规则):
|
|
13
|
+
* 1. 成功和失败都必须结构化 —— 失败也要 `ok:false` + `code` + `next_action`
|
|
14
|
+
* 2. "已付款" ≠ "任务成功" —— `paid`/`delivered` 都不是成功; 成功判据是 §5.2 (任务层: state=verified ∧ 事实∈{fully_settled,payment_verified})
|
|
15
|
+
* 3. 客户端必须忽略未知 `code` —— 所以本文件新增的码是**追加**, 不改任何冻结码的含义
|
|
16
|
+
*/
|
|
17
|
+
import { AUDIT_FORBIDDEN_KEYS } from '../agents/task-contract.js';
|
|
18
|
+
// ── §3 冻结错误码 (字面量与 P1 表逐条一致; 改含义 = 必须 bump 协议版本) ──────────
|
|
19
|
+
/** P1 §3 表里的码 (含成功码)。这些的含义**冻结**, 不许在 CLI 层重新解释。 */
|
|
20
|
+
export const FROZEN_CODES = [
|
|
21
|
+
'TASK_SUBMITTED', 'TASK_ACCEPTED', 'TASK_COMPLETED', 'TASK_VERIFIED',
|
|
22
|
+
'PAYMENT_REQUIRED', 'PAYMENT_PENDING', 'POLICY_DENIED', 'BUDGET_EXCEEDED',
|
|
23
|
+
'NETWORK_NOT_JOINED', 'CAPABILITY_NOT_FOUND', 'RESULT_UNVERIFIED',
|
|
24
|
+
'PROTOCOL_VERSION_UNSUPPORTED', 'PAYMENT_UNCERTAIN', 'DUPLICATE_REQUEST',
|
|
25
|
+
'TASK_TRANSITION_REJECTED', 'SIGNATURE_REQUIRED', 'SIGNATURE_INVALID',
|
|
26
|
+
'DEADLINE_EXPIRED', 'WALLET_UNAVAILABLE', 'AGENT_NOT_AUTHORIZED',
|
|
27
|
+
'LOCAL_DEV_NOT_CHAIN', 'DISPUTE_OPEN', 'DELIVERY_FAILED',
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* P3 新增码 (P1 §1.3「新增错误码不 bump 版本」允许; 老客户端按 `ok:false` + `next_action` 处理, 不崩不猜)。
|
|
31
|
+
* 只加**表里确实没有对应语义**的: 命令组自身的成败、参数错、找不到、超时、未实现。
|
|
32
|
+
*/
|
|
33
|
+
export const CLI_CODES = [
|
|
34
|
+
// 命令组成功码
|
|
35
|
+
'OK', 'NETWORK_JOINED', 'NETWORK_NODE_READY', 'AGENT_REGISTERED',
|
|
36
|
+
'POLICY_UPDATED', 'PAYMENT_APPROVED', 'PAYMENT_REJECTED', 'RECOVERY_PLANNED',
|
|
37
|
+
'WALLET_SIGNED', 'TASK_DELIVERED',
|
|
38
|
+
// 任务态里 §3 没有单列的终态 (字面量取自冻结的 14 态状态机)
|
|
39
|
+
'TASK_REJECTED', 'TASK_FAILED', 'TASK_CANCELLED',
|
|
40
|
+
// 传输层 (§1.3「新增错误码不 bump 版本」): 帧没送到 / 没有可用传输
|
|
41
|
+
'TRANSPORT_UNAVAILABLE', 'TRANSPORT_FAILED',
|
|
42
|
+
// 通用失败码
|
|
43
|
+
'C_NOT_IMPLEMENTED', 'INVALID_ARGUMENT', 'NOT_FOUND', 'TIMEOUT', 'INTERNAL_ERROR',
|
|
44
|
+
];
|
|
45
|
+
/** §2.3 受控词表。`verify_result` 出现在 §3 表 (TASK_COMPLETED 行) 但 §2.3 表漏列 —— 以 §3 为准。 */
|
|
46
|
+
export const NEXT_ACTIONS = [
|
|
47
|
+
'reconcile', 'approve_payment', 'needs_human', 'retry_same_request',
|
|
48
|
+
'rejoin_network', 'redefine_capability', 'raise_budget', 'upgrade_client',
|
|
49
|
+
'wait', 'verify_result',
|
|
50
|
+
];
|
|
51
|
+
/** 带参数的词表项 (字面量在 payment-recovery.ts:299-300) */
|
|
52
|
+
export const NEXT_ACTION_PARAM_PREFIXES = ['x402_payment_retry:', 'x402_continue:'];
|
|
53
|
+
/** 带值的选项 (解析时要知道下一个 token 是不是值) */
|
|
54
|
+
const OPTIONS_WITH_VALUE = new Set([
|
|
55
|
+
'--request-id', '--timeout', '--budget', '--per-purchase', '--daily', '--input',
|
|
56
|
+
'--capability', '--name', '--price', '--per', '--description', '--wallet', '--endpoint',
|
|
57
|
+
'--link', '--url', '--instruction', '--provider', '--amount', '--currency', '--network',
|
|
58
|
+
'--per-tx', '--allow-recipient', '--allow-service', '--rate-limit', '--reason',
|
|
59
|
+
// 2026-09-21 (P3 收尾): bolloon-task/1 真收发 + wallet sign 用到的选项
|
|
60
|
+
'--payload', '--message', '--mode', '--task-id', '--deadline', '--salt', '--reply-to',
|
|
61
|
+
'--peer', '--via', '--eta', '--deliver',
|
|
62
|
+
]);
|
|
63
|
+
export function parseFlags(args) {
|
|
64
|
+
const flags = { json: false, quiet: false, positionals: [], options: new Map(), raw: args };
|
|
65
|
+
for (let i = 0; i < args.length; i++) {
|
|
66
|
+
const a = args[i];
|
|
67
|
+
if (a === '--json') {
|
|
68
|
+
flags.json = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (a === '--quiet' || a === '-q') {
|
|
72
|
+
flags.quiet = true;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (a.startsWith('--')) {
|
|
76
|
+
const eq = a.indexOf('=');
|
|
77
|
+
const key = eq > 0 ? a.slice(0, eq) : a;
|
|
78
|
+
let value = eq > 0 ? a.slice(eq + 1) : undefined;
|
|
79
|
+
if (value === undefined && OPTIONS_WITH_VALUE.has(key) && i + 1 < args.length && !args[i + 1].startsWith('--')) {
|
|
80
|
+
value = args[++i];
|
|
81
|
+
}
|
|
82
|
+
const list = flags.options.get(key) || [];
|
|
83
|
+
list.push(value === undefined ? 'true' : value);
|
|
84
|
+
flags.options.set(key, list);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
flags.positionals.push(a);
|
|
88
|
+
}
|
|
89
|
+
const rid = flags.options.get('--request-id')?.[0];
|
|
90
|
+
if (rid && rid !== 'true')
|
|
91
|
+
flags.requestId = rid;
|
|
92
|
+
const t = flags.options.get('--timeout')?.[0];
|
|
93
|
+
if (t && t !== 'true') {
|
|
94
|
+
const n = Number(t);
|
|
95
|
+
if (Number.isFinite(n) && n > 0)
|
|
96
|
+
flags.timeoutMs = Math.floor(n);
|
|
97
|
+
}
|
|
98
|
+
return flags;
|
|
99
|
+
}
|
|
100
|
+
/** 取单个选项值 (取最后一次出现的) */
|
|
101
|
+
export function opt(flags, name) {
|
|
102
|
+
const v = flags.options.get(name)?.slice(-1)[0];
|
|
103
|
+
return v === 'true' ? undefined : v;
|
|
104
|
+
}
|
|
105
|
+
/** 取可重复选项的全部值 */
|
|
106
|
+
export function optAll(flags, name) {
|
|
107
|
+
return (flags.options.get(name) || []).filter((v) => v !== 'true');
|
|
108
|
+
}
|
|
109
|
+
export function has(flags, name) {
|
|
110
|
+
return flags.options.has(name);
|
|
111
|
+
}
|
|
112
|
+
export function okEnvelope(code, message, data = {}, evidence = [], next_action = null) {
|
|
113
|
+
return { ok: true, code, message, data, evidence, next_action };
|
|
114
|
+
}
|
|
115
|
+
export function failEnvelope(code, message, data = {}, evidence = [], next_action = null) {
|
|
116
|
+
return { ok: false, code, message, data, evidence, next_action };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 按"这个码是不是成功码"决定 `ok` (P1 §2.1: `ok` 是唯一分派位; §3 表把成功码与失败码分开)。
|
|
120
|
+
* 状态类命令用它: 例如 `policy_denied` 必须是 `ok:false` —— 不许让客户端把被拒当成完成。
|
|
121
|
+
*/
|
|
122
|
+
export function envelopeForState(ok, code, message, data = {}, evidence = [], next_action = null) {
|
|
123
|
+
return ok ? okEnvelope(code, message, data, evidence, next_action) : failEnvelope(code, message, data, evidence, next_action);
|
|
124
|
+
}
|
|
125
|
+
/** `C_NOT_IMPLEMENTED` 的统一说法: 如实说没实现 + 指出现成可用的替代路径 (绝不假装成功) */
|
|
126
|
+
export function notImplemented(message, data = {}) {
|
|
127
|
+
return failEnvelope('C_NOT_IMPLEMENTED', message, { reason: message, ...data }, [], 'upgrade_client');
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 私钥类字段兜底剥离 (P1 §5.5): 复用契约层的 `AUDIT_FORBIDDEN_KEYS`
|
|
131
|
+
* (`privateKey`/`secret`/`instruction`/`taskText`/`mnemonic`/`seed`) —— 绝不让它们进 stdout。
|
|
132
|
+
* 命中即替换成 `[redacted]`, 并**不静默**: 顶层补 `redacted_fields` 供审计。
|
|
133
|
+
*/
|
|
134
|
+
export function redactSecrets(value, hits = [], path = '$') {
|
|
135
|
+
if (Array.isArray(value))
|
|
136
|
+
return value.map((v, i) => redactSecrets(v, hits, `${path}[${i}]`));
|
|
137
|
+
if (value && typeof value === 'object') {
|
|
138
|
+
const out = {};
|
|
139
|
+
for (const [k, v] of Object.entries(value)) {
|
|
140
|
+
if (AUDIT_FORBIDDEN_KEYS.includes(k)) {
|
|
141
|
+
hits.push(`${path}.${k}`);
|
|
142
|
+
out[k] = '[redacted]';
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
out[k] = redactSecrets(v, hits, `${path}.${k}`);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
/** 收敛成冻结字段顺序 + 兜底剥离 (所有对外输出都必须过这里) */
|
|
152
|
+
export function finalizeEnvelope(env, flags) {
|
|
153
|
+
const hits = [];
|
|
154
|
+
const data = redactSecrets(env.data || {}, hits);
|
|
155
|
+
if (hits.length)
|
|
156
|
+
data.redacted_fields = hits;
|
|
157
|
+
// `--request-id`: 幂等键原样透传/回显 (真实用它的命令会把它写进自己的查询路径)
|
|
158
|
+
if (flags?.requestId && data.requestId === undefined)
|
|
159
|
+
data.requestId = flags.requestId;
|
|
160
|
+
return {
|
|
161
|
+
ok: env.ok,
|
|
162
|
+
code: env.code,
|
|
163
|
+
message: env.message,
|
|
164
|
+
data,
|
|
165
|
+
evidence: Array.isArray(env.evidence) ? env.evidence : [],
|
|
166
|
+
next_action: env.next_action ?? null,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** 老命令 (task/trace/p2p/x402) 的 `--json`: **保留既有顶层键** (基线兼容), 追加 §2 的 code/message/evidence/next_action */
|
|
170
|
+
export function legacyJson(payload, extra) {
|
|
171
|
+
const hits = [];
|
|
172
|
+
const redacted = redactSecrets({ ...payload, code: extra.code, message: extra.message, evidence: extra.evidence || [], next_action: extra.next_action ?? null }, hits);
|
|
173
|
+
if (hits.length)
|
|
174
|
+
redacted.redacted_fields = hits;
|
|
175
|
+
return redacted;
|
|
176
|
+
}
|
|
177
|
+
// ── 输出 ────────────────────────────────────────────────────────────────────
|
|
178
|
+
const RESET = '\x1b[0m';
|
|
179
|
+
const BOLD = '\x1b[1m';
|
|
180
|
+
// 与 cli-entry.ts 同一套 truecolor (#ef4444 / #c4d640) —— 注意必须写成十进制 RGB, 不能写 0x 字面量
|
|
181
|
+
const RED = '\x1b[38;2;239;68;68m';
|
|
182
|
+
const CYAN = '\x1b[38;2;196;214;64m';
|
|
183
|
+
/**
|
|
184
|
+
* 打印命令结果并给出退出码 (0/1)。
|
|
185
|
+
* · `--json` → 完整信封 (2 空格缩进, 字段顺序与 §2 一致)
|
|
186
|
+
* · `--quiet` → 只出结果 (payload 的 JSON)
|
|
187
|
+
* · 默认 → 人类可读 (命令自带); 失败时补一行 机器可读的 code/next_action, 方便不解析 JSON 也能分派
|
|
188
|
+
*/
|
|
189
|
+
export function emit(env, flags, human = '') {
|
|
190
|
+
const e = finalizeEnvelope(env, flags);
|
|
191
|
+
if (flags.json) {
|
|
192
|
+
console.log(JSON.stringify(e, null, 2));
|
|
193
|
+
}
|
|
194
|
+
else if (flags.quiet) {
|
|
195
|
+
console.log(JSON.stringify(e.data));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
if (human.trim())
|
|
199
|
+
console.log(human.trimEnd());
|
|
200
|
+
if (!e.ok)
|
|
201
|
+
console.log(`\n${RED}✗ ${e.message}${RESET}\n code=${e.code} next_action=${e.next_action ?? 'null'}`);
|
|
202
|
+
}
|
|
203
|
+
return e.ok ? 0 : 1;
|
|
204
|
+
}
|
|
205
|
+
/** 异常兜底: 任何没被命令自己处理的错都变成结构化失败 (§2 硬规则 1) */
|
|
206
|
+
export function errorEnvelope(err) {
|
|
207
|
+
const msg = String(err?.message || err).slice(0, 300);
|
|
208
|
+
return failEnvelope('INTERNAL_ERROR', `命令内部异常: ${msg}`, { error: msg }, [], 'needs_human');
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* 跑一条命令: 统一套 `--timeout` (§ 超时也是结构化失败) 与异常兜底, 但**不打印**。
|
|
212
|
+
* 2026-09-21 (P4): 从 `runCommand` 抽出 —— MCP 适配层要的是信封本身 (它不能往 stdout 打字,
|
|
213
|
+
* stdout 是 JSON-RPC 流), 而超时/异常兜底必须与 CLI 是同一条实现 (绝不允许两套语义)。
|
|
214
|
+
*/
|
|
215
|
+
export async function commandResult(flags, fn) {
|
|
216
|
+
try {
|
|
217
|
+
if (flags.timeoutMs)
|
|
218
|
+
return await raceTimeout(fn(flags), flags.timeoutMs);
|
|
219
|
+
return await fn(flags);
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
if (err instanceof CommandTimeout) {
|
|
223
|
+
return {
|
|
224
|
+
envelope: failEnvelope('TIMEOUT', `命令超时 (--timeout ${flags.timeoutMs}ms): 已经处理的部分结果没有落盘保证`, { timeoutMs: flags.timeoutMs ?? null }, [], 'retry_same_request'),
|
|
225
|
+
human: '',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return { envelope: errorEnvelope(err), human: '' };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 跑一条命令: 统一套 `--timeout` (§ 超时也是结构化失败) 与异常兜底, 然后按 `--json`/`--quiet`/默认输出。
|
|
233
|
+
* 返回进程退出码 (0 = ok, 1 = 失败; 但**判据永远是 `ok`/`code`, 不是退出码**)。
|
|
234
|
+
*/
|
|
235
|
+
export async function runCommand(flags, fn) {
|
|
236
|
+
const result = await commandResult(flags, fn);
|
|
237
|
+
return emit(result.envelope, flags, result.human);
|
|
238
|
+
}
|
|
239
|
+
class CommandTimeout extends Error {
|
|
240
|
+
constructor() { super('command timeout'); this.name = 'CommandTimeout'; }
|
|
241
|
+
}
|
|
242
|
+
function raceTimeout(work, ms) {
|
|
243
|
+
return new Promise((resolve, reject) => {
|
|
244
|
+
let settled = false;
|
|
245
|
+
const timer = setTimeout(() => { if (!settled) {
|
|
246
|
+
settled = true;
|
|
247
|
+
reject(new CommandTimeout());
|
|
248
|
+
} }, ms);
|
|
249
|
+
work.then((v) => { if (!settled) {
|
|
250
|
+
settled = true;
|
|
251
|
+
clearTimeout(timer);
|
|
252
|
+
resolve(v);
|
|
253
|
+
} })
|
|
254
|
+
.catch((e) => { if (!settled) {
|
|
255
|
+
settled = true;
|
|
256
|
+
clearTimeout(timer);
|
|
257
|
+
reject(e);
|
|
258
|
+
} });
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/** 人类可读输出的小工具 (与 cli-entry.ts 的配色一致) */
|
|
262
|
+
export const tone = { reset: RESET, bold: BOLD, red: RED, cyan: CYAN };
|
|
263
|
+
/** 把带 ANSI 色的帮助文本变成纯文本 (放进 `--json` 的 data 里时必须先过它) */
|
|
264
|
+
export function plain(t) {
|
|
265
|
+
// eslint-disable-next-line no-control-regex
|
|
266
|
+
return String(t).replace(/\u001b\[[0-9;]*m/g, '');
|
|
267
|
+
}
|
|
268
|
+
export function line(label, value) {
|
|
269
|
+
return ` ${String(label).padEnd(14)} ${value === undefined || value === null || value === '' ? '(无)' : String(value)}`;
|
|
270
|
+
}
|
|
271
|
+
export function title(t) {
|
|
272
|
+
return `\n${BOLD}${t}${RESET}`;
|
|
273
|
+
}
|
|
274
|
+
export function hint(t) {
|
|
275
|
+
return `${CYAN}${t}${RESET}`;
|
|
276
|
+
}
|
|
277
|
+
/** 一行内看结论的失败摘要 (人读模式常用) */
|
|
278
|
+
export function failHuman(head, env) {
|
|
279
|
+
return `${head}\n 原因: ${env.message}\n code: ${env.code} · 下一步: ${env.next_action ?? '无需额外动作'}`;
|
|
280
|
+
}
|
|
281
|
+
/** 任务 14 态 (§4.1) → 对外 4 态 */
|
|
282
|
+
export function publicStatusForTask(state, nextAction) {
|
|
283
|
+
switch (state) {
|
|
284
|
+
case 'discovered':
|
|
285
|
+
case 'quoted':
|
|
286
|
+
return '准备中';
|
|
287
|
+
case 'submitted':
|
|
288
|
+
case 'accepted':
|
|
289
|
+
case 'paid':
|
|
290
|
+
return '正在获取能力';
|
|
291
|
+
case 'paying':
|
|
292
|
+
return nextAction === 'reconcile' ? '需要你处理' : '正在获取能力';
|
|
293
|
+
case 'payment_required':
|
|
294
|
+
case 'policy_denied':
|
|
295
|
+
case 'rejected':
|
|
296
|
+
case 'failed':
|
|
297
|
+
case 'cancelled':
|
|
298
|
+
return '需要你处理';
|
|
299
|
+
case 'running':
|
|
300
|
+
return '正在执行';
|
|
301
|
+
case 'delivered':
|
|
302
|
+
return '已完成或需要你处理';
|
|
303
|
+
case 'verified':
|
|
304
|
+
return '已完成';
|
|
305
|
+
default:
|
|
306
|
+
return '需要你处理';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/** 交易 11 态 (§4.2) → 对外 4 态 */
|
|
310
|
+
export function publicStatusForTrade(status, nextAction) {
|
|
311
|
+
switch (status) {
|
|
312
|
+
case 'discovered':
|
|
313
|
+
case 'quoted':
|
|
314
|
+
return '准备中';
|
|
315
|
+
case 'paying':
|
|
316
|
+
case 'settled':
|
|
317
|
+
return nextAction === 'reconcile' ? '需要你处理' : '正在获取能力';
|
|
318
|
+
case 'delivered':
|
|
319
|
+
return '已完成或需要你处理';
|
|
320
|
+
case 'verified':
|
|
321
|
+
return '已完成';
|
|
322
|
+
case 'payment_required':
|
|
323
|
+
case 'policy_denied':
|
|
324
|
+
case 'delivery_failed':
|
|
325
|
+
case 'verification_failed':
|
|
326
|
+
case 'disputed':
|
|
327
|
+
case 'failed':
|
|
328
|
+
return '需要你处理';
|
|
329
|
+
default:
|
|
330
|
+
return '需要你处理';
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* 交易记录的对外口径 —— **local-dev 一律标 `local-dev`, 绝不冒充链上** (P1 §5.1 第 3 条)。
|
|
335
|
+
* `success` 用 §7.1 的判据: `status==='verified'` ∧ 事实 ∈ {fully_settled, payment_verified}。
|
|
336
|
+
*/
|
|
337
|
+
export function settlementLabel(rec) {
|
|
338
|
+
if (rec.paymentMode === 'local-dev')
|
|
339
|
+
return 'local-dev';
|
|
340
|
+
if (rec.chainSettled === true && ['payment_verified', 'partially_settled', 'fully_settled'].includes(String(rec.settlementFact || '')))
|
|
341
|
+
return 'chain';
|
|
342
|
+
return 'none';
|
|
343
|
+
}
|
|
344
|
+
export function isTradeSuccessful(rec) {
|
|
345
|
+
return String(rec.status) === 'verified' && ['fully_settled', 'payment_verified'].includes(String(rec.settlementFact || ''));
|
|
346
|
+
}
|
package/dist/cli-entry.js
CHANGED
|
@@ -22,8 +22,15 @@ import { discoverEngines, delegateToEngine } from './external-engines/index.js';
|
|
|
22
22
|
import { x402CheckBalance, x402Fetch } from './agents/x402/x402Pay.js';
|
|
23
23
|
import { runVersionCommand, runUpdateCommand, runDoctorCommand, runRuntimeCommand, UPDATE_HELP } from './cli/update-commands.js';
|
|
24
24
|
import { collectVersionInfo } from './utils/version-info.js';
|
|
25
|
+
// 2026-09-21 (P3): 统一 JSON 信封 + 命令组 (network/agent/task/wallet/payment/trade)
|
|
26
|
+
import { runServiceGroup, GROUPS_HELP } from './cli/commands/index.js';
|
|
27
|
+
// 2026-09-21 (P4): MCP 适配层 (`bolloon mcp serve` = stdio, 只调 P3 服务层)
|
|
28
|
+
import { runMcpCommand } from './cli/commands/mcp.js';
|
|
29
|
+
import { legacyJson } from './cli/protocol-envelope.js';
|
|
25
30
|
import { createRequire } from 'module';
|
|
26
31
|
const _require = createRequire(import.meta.url);
|
|
32
|
+
/** P3 `bolloon task <子命令>` 的已知子命令 —— 其它一律当 M1 任务正文 (既有体验不动) */
|
|
33
|
+
const TASK_SUBCOMMANDS = new Set(['send', 'list', 'status', 'cancel', 'retry', 'result', 'inbox', 'accept', 'reject', 'run', 'complete']);
|
|
27
34
|
const isWindows = process.platform === 'win32';
|
|
28
35
|
// ANSI 颜色 — Bolloon Web UI 配色 truecolor
|
|
29
36
|
function _fg(r, g, b) { return `\x1b[38;2;${r};${g};${b}m`; }
|
|
@@ -68,6 +75,10 @@ ${BOLD}命令:${RESET}
|
|
|
68
75
|
bolloon engine run <prompt> 委派任务给智能体
|
|
69
76
|
bolloon x402 fetch <url> x402 自动支付 HTTP 请求
|
|
70
77
|
bolloon x402 balance <address> 查询 x402 钱包余额
|
|
78
|
+
bolloon mcp serve MCP server (stdio) —— 给 MCP 客户端接本机 Agent 能力
|
|
79
|
+
bolloon mcp tools 列出 MCP 暴露的 tools/resources (只读清单)
|
|
80
|
+
|
|
81
|
+
${GROUPS_HELP}
|
|
71
82
|
|
|
72
83
|
${BOLD}示例:${RESET}
|
|
73
84
|
bolloon # 启动图形界面
|
|
@@ -78,6 +89,8 @@ ${BOLD}示例:${RESET}
|
|
|
78
89
|
bolloon update plan # 看更新计划与风险检查
|
|
79
90
|
bolloon update now # 真正执行更新
|
|
80
91
|
bolloon doctor # 我这台机器的 Bolloon 是否自洽
|
|
92
|
+
bolloon network join --json # 入网 (失败也结构化: ok:false + code + next_action)
|
|
93
|
+
bolloon task --request-id <id> "…" # 用给定幂等键跑 M1 任务 (同一 requestId 不会付两次)
|
|
81
94
|
${UPDATE_HELP}
|
|
82
95
|
|
|
83
96
|
${BOLD}环境变量:${RESET}
|
|
@@ -169,6 +182,20 @@ function parseArgs() {
|
|
|
169
182
|
// 2026-09-18: M1 唯一入口 —— 一个任务 → 一个 Skill → 一个报告卡
|
|
170
183
|
case 'task':
|
|
171
184
|
return { mode: 'task', args: args.slice(1) };
|
|
185
|
+
// 2026-09-21: P3 命令组 (统一信封 + 全局选项; 薄包装现有服务)
|
|
186
|
+
case 'network':
|
|
187
|
+
return { mode: 'network', args: args.slice(1) };
|
|
188
|
+
case 'agent':
|
|
189
|
+
return { mode: 'agent', args: args.slice(1) };
|
|
190
|
+
case 'wallet':
|
|
191
|
+
return { mode: 'wallet', args: args.slice(1) };
|
|
192
|
+
case 'payment':
|
|
193
|
+
return { mode: 'payment', args: args.slice(1) };
|
|
194
|
+
case 'trade':
|
|
195
|
+
return { mode: 'trade', args: args.slice(1) };
|
|
196
|
+
// 2026-09-21: P4 MCP 适配层 (`bolloon mcp serve` = stdio MCP server; 只调 P3 服务层)
|
|
197
|
+
case 'mcp':
|
|
198
|
+
return { mode: 'mcp', args: args.slice(1) };
|
|
172
199
|
// 2026-09-13: 初始化向导 (用户身份 + 模型供应商 + API key)
|
|
173
200
|
case 'setup':
|
|
174
201
|
case 'init':
|
|
@@ -250,7 +277,18 @@ async function handleX402Command(x402Args) {
|
|
|
250
277
|
rpcUrl: readOption(rest, '--rpc-url'),
|
|
251
278
|
});
|
|
252
279
|
if (hasFlag(rest, '--json')) {
|
|
253
|
-
|
|
280
|
+
// 2026-09-21 (P3): 保留既有 {success,data,status,error,paymentInfo,...}, 追加 code/message/next_action
|
|
281
|
+
console.log(JSON.stringify(legacyJson(result, {
|
|
282
|
+
code: result.success ? 'OK' : 'INTERNAL_ERROR',
|
|
283
|
+
message: result.success ? `x402 请求完成 (status=${result.status})` : `x402 请求失败: ${result.error || ''}`,
|
|
284
|
+
evidence: [],
|
|
285
|
+
next_action: result.success ? null : 'retry_same_request',
|
|
286
|
+
}), null, 2));
|
|
287
|
+
if (!result.success)
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
else if (hasFlag(rest, '--quiet')) {
|
|
291
|
+
console.log(JSON.stringify(result));
|
|
254
292
|
if (!result.success)
|
|
255
293
|
process.exit(1);
|
|
256
294
|
}
|
|
@@ -280,7 +318,17 @@ async function handleX402Command(x402Args) {
|
|
|
280
318
|
rpcUrl: readOption(rest, '--rpc-url'),
|
|
281
319
|
});
|
|
282
320
|
if (hasFlag(rest, '--json')) {
|
|
283
|
-
console.log(JSON.stringify(result,
|
|
321
|
+
console.log(JSON.stringify(legacyJson(result, {
|
|
322
|
+
code: result.success ? 'OK' : 'INTERNAL_ERROR',
|
|
323
|
+
message: result.success ? `余额查询完成 (${result.network})` : `余额查询失败: ${result.error || ''}`,
|
|
324
|
+
evidence: [address],
|
|
325
|
+
next_action: result.success ? null : 'retry_same_request',
|
|
326
|
+
}), null, 2));
|
|
327
|
+
if (!result.success)
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
else if (hasFlag(rest, '--quiet')) {
|
|
331
|
+
console.log(JSON.stringify(result));
|
|
284
332
|
if (!result.success)
|
|
285
333
|
process.exit(1);
|
|
286
334
|
}
|
|
@@ -317,6 +365,7 @@ async function handleX402Command(x402Args) {
|
|
|
317
365
|
async function handleTaskCommand(taskArgs) {
|
|
318
366
|
const { runTask, resumeTask } = await import('./agents/task/task-runner.js');
|
|
319
367
|
const wantJson = taskArgs.includes('--json');
|
|
368
|
+
const wantQuiet = taskArgs.includes('--quiet');
|
|
320
369
|
const flag = (name) => {
|
|
321
370
|
const i = taskArgs.indexOf(name);
|
|
322
371
|
return i >= 0 ? taskArgs[i + 1] : undefined;
|
|
@@ -326,6 +375,8 @@ async function handleTaskCommand(taskArgs) {
|
|
|
326
375
|
const perPurchase = flag('--per-purchase');
|
|
327
376
|
const daily = flag('--daily');
|
|
328
377
|
const inputRaw = flag('--input');
|
|
378
|
+
// 2026-09-21 (P3): 幂等键透传 —— 同一 requestId 重发不会产生第二笔付款 (契约层派生逻辑不变)
|
|
379
|
+
const requestId = flag('--request-id');
|
|
329
380
|
let input;
|
|
330
381
|
if (inputRaw !== undefined) {
|
|
331
382
|
try {
|
|
@@ -338,14 +389,24 @@ async function handleTaskCommand(taskArgs) {
|
|
|
338
389
|
}
|
|
339
390
|
const STAGE_LABEL = { prepare: '准备中', acquire: '正在获取能力', execute: '正在执行', report: '报告' };
|
|
340
391
|
const onStage = (stage, note) => {
|
|
341
|
-
if (wantJson)
|
|
392
|
+
if (wantJson || wantQuiet)
|
|
342
393
|
return;
|
|
343
394
|
console.error(` ${CYAN}${STAGE_LABEL[stage] || stage}${RESET} ${note}`);
|
|
344
395
|
};
|
|
345
396
|
if (resumeId) {
|
|
346
397
|
const r = await resumeTask({ goalId: resumeId, input, allowLocalDev: true });
|
|
347
|
-
|
|
348
|
-
|
|
398
|
+
const verdict = legacyTaskVerdict(r);
|
|
399
|
+
const payload = {
|
|
400
|
+
resumed: r.resumed, action: r.action, reason: r.reason, mustNotRepay: r.mustNotRepay, card: r.card,
|
|
401
|
+
goalId: r.goalId, runId: r.runId ?? null, transactionId: r.transactionId ?? null,
|
|
402
|
+
};
|
|
403
|
+
if (wantQuiet)
|
|
404
|
+
console.log(JSON.stringify(payload));
|
|
405
|
+
else if (wantJson)
|
|
406
|
+
console.log(JSON.stringify(legacyJson(payload, {
|
|
407
|
+
code: verdict.code, message: verdict.message, next_action: verdict.next,
|
|
408
|
+
evidence: [r.goalId, r.runId, r.transactionId].filter(Boolean),
|
|
409
|
+
}), null, 2));
|
|
349
410
|
else {
|
|
350
411
|
console.log('');
|
|
351
412
|
console.log(r.text);
|
|
@@ -357,7 +418,7 @@ async function handleTaskCommand(taskArgs) {
|
|
|
357
418
|
if (a.startsWith('--'))
|
|
358
419
|
return false;
|
|
359
420
|
const prev = taskArgs[i - 1];
|
|
360
|
-
return !['--budget', '--per-purchase', '--daily', '--input'].includes(prev || '');
|
|
421
|
+
return !['--budget', '--per-purchase', '--daily', '--input', '--request-id', '--timeout'].includes(prev || '');
|
|
361
422
|
});
|
|
362
423
|
const task = words.join(' ').trim();
|
|
363
424
|
if (!task) {
|
|
@@ -372,19 +433,27 @@ ${CYAN}bolloon task --resume <goalId>${RESET}
|
|
|
372
433
|
--per-purchase <USDC> 单次购买上限 (M1 硬上限 0.02)
|
|
373
434
|
--daily <USDC> 当日预算 (M1 硬上限 0.10)
|
|
374
435
|
--input '<json>' 显式给技能输入 (跳过自动推导)
|
|
375
|
-
--
|
|
436
|
+
--request-id <id> 指定幂等键 (同一 requestId 重发不会产生第二笔付款)
|
|
437
|
+
--json 机器可读输出 (+ code/next_action/evidence; 失败也结构化)
|
|
376
438
|
`);
|
|
377
439
|
return;
|
|
378
440
|
}
|
|
379
|
-
const r = await runTask({ task, budget, perPurchase, daily, input, allowLocalDev: true, onStage });
|
|
380
|
-
|
|
381
|
-
|
|
441
|
+
const r = await runTask({ task, budget, perPurchase, daily, input, requestId, allowLocalDev: true, onStage });
|
|
442
|
+
const verdict = legacyTaskVerdict(r);
|
|
443
|
+
if (wantQuiet) {
|
|
444
|
+
console.log(JSON.stringify({ ok: r.ok, goalId: r.goalId, runId: r.runId, transactionId: r.transactionId, card: r.card, payment: r.payment }));
|
|
445
|
+
}
|
|
446
|
+
else if (wantJson) {
|
|
447
|
+
console.log(JSON.stringify(legacyJson({
|
|
382
448
|
ok: r.ok, status: r.card.status, conclusion: r.card.conclusion, card: r.card,
|
|
383
449
|
goalId: r.goalId, runId: r.runId, transactionId: r.transactionId,
|
|
384
450
|
advisor: r.advisor, payment: r.payment, outputIssues: r.outputIssues,
|
|
385
451
|
budget: { taskBudget: r.budget.taskBudget, perPurchase: r.budget.perPurchase, daily: r.budget.daily, clamped: r.budget.clamped },
|
|
386
452
|
stages: r.stages,
|
|
387
|
-
},
|
|
453
|
+
}, {
|
|
454
|
+
code: verdict.code, message: verdict.message, next_action: verdict.next,
|
|
455
|
+
evidence: [r.goalId, r.runId, r.transactionId].filter(Boolean),
|
|
456
|
+
}), null, 2));
|
|
388
457
|
}
|
|
389
458
|
else {
|
|
390
459
|
console.log('');
|
|
@@ -394,17 +463,39 @@ ${CYAN}bolloon task --resume <goalId>${RESET}
|
|
|
394
463
|
// 一次性命令: 显式收尾 (DIAP/HTTP 句柄不该吊住进程)
|
|
395
464
|
process.exit(r.ok ? 0 : 1);
|
|
396
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* 老 M1 命令 (`bolloon task`) 的 §3 码映射 (P1 §3 + §5.1 红线):
|
|
468
|
+
* local-dev 最高到 `delivered` → 一律 `TASK_COMPLETED` + `verify_result`, **绝不** TASK_VERIFIED。
|
|
469
|
+
*/
|
|
470
|
+
function legacyTaskVerdict(r) {
|
|
471
|
+
const chain = r.payment?.chainSettled === true || r.card?.payment?.chainSettled === true;
|
|
472
|
+
if (r.ok) {
|
|
473
|
+
return chain
|
|
474
|
+
? { code: 'TASK_VERIFIED', message: 'Task verified', next: null }
|
|
475
|
+
: { code: 'TASK_COMPLETED', message: 'Task delivered (local-dev: 链上未结算, 不算成功)', next: 'verify_result' };
|
|
476
|
+
}
|
|
477
|
+
return r.card?.hardGate === 'bought_not_executed'
|
|
478
|
+
? { code: 'DELIVERY_FAILED', message: '已付款但没有交付 → 绝不重付, 交人处理', next: 'needs_human' }
|
|
479
|
+
: { code: 'RESULT_UNVERIFIED', message: '任务没走完/未过验真门', next: 'needs_human' };
|
|
480
|
+
}
|
|
397
481
|
async function handleTraceCommand(traceArgs) {
|
|
398
482
|
const { listRuns, readRun } = await import('./agents/run-store.js');
|
|
399
483
|
const { runToTraceText, runToTraceJson, summarizeTrace } = await import('./agents/trace-export.js');
|
|
400
484
|
const wantJson = traceArgs.includes('--json');
|
|
485
|
+
const wantQuiet = traceArgs.includes('--quiet');
|
|
401
486
|
const lastIdx = traceArgs.indexOf('--last');
|
|
402
487
|
const last = lastIdx >= 0 ? Number(traceArgs[lastIdx + 1]) : undefined;
|
|
403
488
|
const runId = traceArgs.find((a) => !a.startsWith('--') && a !== String(last));
|
|
404
489
|
if (!runId) {
|
|
405
490
|
const runs = await listRuns({ limit: 20 });
|
|
491
|
+
const payloads = runs.map((r) => runToTraceJson(r));
|
|
492
|
+
if (wantQuiet) {
|
|
493
|
+
console.log(JSON.stringify(payloads));
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
406
496
|
if (wantJson) {
|
|
407
|
-
|
|
497
|
+
// 2026-09-21 (P3): 列表形式也走统一信封 (此前是裸数组; `data` 里仍是同样的 payload 数组)
|
|
498
|
+
console.log(JSON.stringify({ ok: true, code: 'OK', message: `最近 ${runs.length} 次运行`, data: payloads, evidence: payloads.map((p) => p.runId).filter(Boolean), next_action: null }, null, 2));
|
|
408
499
|
return;
|
|
409
500
|
}
|
|
410
501
|
console.log(`\n${BOLD}最近 ${runs.length} 次运行的执行轨迹${RESET}\n`);
|
|
@@ -425,12 +516,19 @@ async function handleTraceCommand(traceArgs) {
|
|
|
425
516
|
const run = await readRun(runId);
|
|
426
517
|
if (!run) {
|
|
427
518
|
console.error(`${MAGENTA}没有这个运行: ${runId}${RESET}`);
|
|
519
|
+
if (wantJson)
|
|
520
|
+
console.log(JSON.stringify({ ok: false, code: 'NOT_FOUND', message: `没有这个运行: ${runId}`, data: { runId }, evidence: [], next_action: 'retry_same_request' }, null, 2));
|
|
428
521
|
process.exitCode = 1;
|
|
429
522
|
return;
|
|
430
523
|
}
|
|
431
|
-
|
|
432
|
-
if (
|
|
433
|
-
|
|
524
|
+
const j = runToTraceJson(run);
|
|
525
|
+
if (wantQuiet)
|
|
526
|
+
console.log(JSON.stringify(j));
|
|
527
|
+
else if (wantJson)
|
|
528
|
+
console.log(JSON.stringify(legacyJson(j, { code: 'OK', message: `运行 ${runId} 轨迹`, evidence: [runId], next_action: null }), null, 2));
|
|
529
|
+
else
|
|
530
|
+
console.log(runToTraceText(run, { limit: last }));
|
|
531
|
+
if (!wantJson && !wantQuiet) {
|
|
434
532
|
console.error(`\n${CYAN}(${j.counts.total} 步 · ✓${j.counts.ok} / ✗${j.counts.fail} · ${j.counts.totalMs}ms · 状态 ${j.status})${RESET}`);
|
|
435
533
|
}
|
|
436
534
|
}
|
|
@@ -442,8 +540,19 @@ async function handleTraceCommand(traceArgs) {
|
|
|
442
540
|
async function handleP2pCommand(p2pArgs) {
|
|
443
541
|
const { getLocalP2pInfo, formatP2pInfoText, formatP2pInfoJson } = await import('./agents/p2p-info.js');
|
|
444
542
|
const info = await getLocalP2pInfo();
|
|
445
|
-
if (p2pArgs.includes('--
|
|
446
|
-
console.log(formatP2pInfoJson(info));
|
|
543
|
+
if (p2pArgs.includes('--quiet')) {
|
|
544
|
+
console.log(JSON.stringify(JSON.parse(formatP2pInfoJson(info))));
|
|
545
|
+
}
|
|
546
|
+
else if (p2pArgs.includes('--json')) {
|
|
547
|
+
// 2026-09-21 (P3): 保留 bolloon-p2p-info/1 的全部既有字段, 追加 §2 的 code/message/evidence/next_action
|
|
548
|
+
const payload = JSON.parse(formatP2pInfoJson(info));
|
|
549
|
+
console.log(JSON.stringify(legacyJson(payload, {
|
|
550
|
+
code: 'OK',
|
|
551
|
+
message: info.ok ? `本机 P2P 信息 (peerId=${String(info.peerId).slice(0, 16)}…)` : '还没有本机 peerId',
|
|
552
|
+
evidence: info.peerId ? [String(info.peerId)] : [],
|
|
553
|
+
next_action: info.ok ? null : 'rejoin_network',
|
|
554
|
+
}), null, 2));
|
|
555
|
+
}
|
|
447
556
|
else
|
|
448
557
|
console.log(formatP2pInfoText(info));
|
|
449
558
|
// 一次性信息命令必须自己收尾: 读运行中节点会 import network/p2p (libp2p),
|
|
@@ -755,8 +864,23 @@ async function main() {
|
|
|
755
864
|
break;
|
|
756
865
|
// 2026-09-18: M1 任务闭环 (bolloon task "<任务>" --budget 0.05 / --resume <goalId>)
|
|
757
866
|
case 'task':
|
|
867
|
+
// 2026-09-21 (P3): 已知子命令 → 命令组 (统一信封); 其它一律当 M1 任务正文 (既有体验不动)
|
|
868
|
+
if (args[0] && TASK_SUBCOMMANDS.has(args[0]))
|
|
869
|
+
process.exit(await runServiceGroup('task', args));
|
|
758
870
|
await handleTaskCommand(args);
|
|
759
871
|
break;
|
|
872
|
+
// 2026-09-21 (P3): 命令组 (network/agent/wallet/payment/trade) —— 统一信封 + 薄包装现有服务
|
|
873
|
+
case 'network':
|
|
874
|
+
case 'agent':
|
|
875
|
+
case 'wallet':
|
|
876
|
+
case 'payment':
|
|
877
|
+
case 'trade':
|
|
878
|
+
process.exit(await runServiceGroup(mode, args));
|
|
879
|
+
break;
|
|
880
|
+
// 2026-09-21 (P4): MCP 适配层 (`bolloon mcp serve` = stdio MCP server; tools/resources 只调 P3 服务层)
|
|
881
|
+
case 'mcp':
|
|
882
|
+
process.exit(await runMcpCommand(args));
|
|
883
|
+
break;
|
|
760
884
|
// 2026-09-13: bolloon setup — 首次运行初始化向导
|
|
761
885
|
case 'setup':
|
|
762
886
|
await handleSetupCommand(args);
|
|
@@ -151,6 +151,11 @@ async function gatewayCallAgent(opts) {
|
|
|
151
151
|
return { success: false, error: r.error, provider: provider.agentId, decision: 'allow' };
|
|
152
152
|
// 7. Reputation: 记录成功
|
|
153
153
|
await (0, agent_reputation_js_1.recordServiceOutcome)(provider.agentId, provider.service?.name || 'service', 'success', registry).catch(() => { });
|
|
154
|
+
// 2026-09-18: 委派完成 → 网络脉冲 (只记"发生过一次成功委派", 不记任务内容/对端地址; 失败静默)
|
|
155
|
+
try {
|
|
156
|
+
void Promise.resolve().then(() => __importStar(require('./network-pulse.js'))).then((np) => np.recordNetworkEvent({ type: 'delegation_completed', did: String(opts.toPublicKey || provider.agentId || 'unknown-node') })).catch(() => { });
|
|
157
|
+
}
|
|
158
|
+
catch { /* ignore */ }
|
|
154
159
|
return { success: true, provider: provider.agentId, decision: 'allow', output: r.output };
|
|
155
160
|
}
|
|
156
161
|
catch (e) {
|