@itpay/cli 2.0.37 → 2.0.39
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 +10 -3
- package/dist/src/client/backend.js +3 -0
- package/dist/src/commands/catalog.js +7 -0
- package/dist/src/commands/checkout_handoff.js +3 -0
- package/dist/src/commands/install.js +2 -0
- package/dist/src/commands/readyz.js +1 -1
- package/dist/src/commands/services.js +94 -3
- package/dist/src/commands/vault_handoff.js +18 -0
- package/dist/src/main.js +38 -1
- package/dist/src/state/client_context.js +2 -0
- package/dist/src/state/config.js +13 -13
- package/docs/agent/buyer/identity-and-sessions.json +3 -3
- package/docs/agent/buyer/install-and-setup.json +6 -5
- package/docs/agent/buyer/quickstart.json +2 -2
- package/docs/agent/buyer/render-hosts.json +7 -0
- package/docs/cli-reference/agent-types.md +6 -1
- package/docs/cli-reference/commands/buy.md +1 -0
- package/docs/cli-reference/commands/catalog/list.md +1 -1
- package/docs/cli-reference/commands/checkout.md +1 -0
- package/docs/cli-reference/commands/device.md +1 -1
- package/docs/cli-reference/commands/install.md +6 -4
- package/docs/cli-reference/commands/readyz.md +8 -8
- package/docs/cli-reference/commands/services/checkout.md +7 -0
- package/docs/cli-reference/commands/services/get.md +1 -1
- package/docs/cli-reference/commands/services/index.md +3 -2
- package/docs/cli-reference/commands/services/next.md +6 -6
- package/docs/cli-reference/commands/services/quote.md +2 -2
- package/docs/cli-reference/commands/services/run.md +74 -0
- package/docs/cli-reference/commands/services/start.md +1 -1
- package/docs/cli-reference/commands/vault/access.md +5 -1
- package/docs/cli-reference/conventions.md +1 -1
- package/docs/cli-reference/index.md +1 -0
- package/docs/skill-bundle-rollout/04-first-wave-platforms.md +2 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Official Agent install prompt(可直接复制给 Agent):
|
|
|
25
25
|
Use a separate test prompt to set the exact official Dev Backend. Never put a
|
|
26
26
|
Dev override in the public install prompt.
|
|
27
27
|
|
|
28
|
-
The CLI defaults to the production Backend `https://app.itpay.ai`. Explicit
|
|
28
|
+
The CLI defaults to the production Backend `https://app.itpay.ai`. Explicit sandbox runs may set `ITPAY_BACKEND_URL=https://sandbox.itpay.ai`; every other Backend URL is rejected before network or local state access.
|
|
29
29
|
|
|
30
30
|
## Output Contract
|
|
31
31
|
|
|
@@ -54,6 +54,7 @@ Normative per-command contracts: [CLI Command Reference](docs/cli-reference/inde
|
|
|
54
54
|
| `claude-code-cli` | `terminal` |
|
|
55
55
|
| `workbuddy` | `plain-chat` |
|
|
56
56
|
| `zcode` | `plain-chat` |
|
|
57
|
+
| `doubao-work` | `plain-chat` |
|
|
57
58
|
| `kimi-code` | `terminal` |
|
|
58
59
|
| `openclaw` | 必须显式提供 |
|
|
59
60
|
|
|
@@ -90,12 +91,12 @@ itpay --agent-type <agent_type> services checkout <service_execution_id> --resum
|
|
|
90
91
|
itpay checkout --id <checkout_id> --token <display_token> --json
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
The local `~/.itpay-v3` directory stores one owner-only signing key, Backend-scoped Device registrations and Agent instances, idempotency operations, and recovery handles. Production uses `cart.json` / `operations.json`;
|
|
94
|
+
The local `~/.itpay-v3` directory stores one owner-only signing key, Backend-scoped Device registrations and Agent instances, idempotency operations, and recovery handles. Production uses `cart.json` / `operations.json`; sandbox uses `cart.sandbox.json` / `operations.sandbox.json`. Backend state remains authoritative. Do not delete or rotate this identity to recover quota.
|
|
94
95
|
|
|
95
96
|
## Environment
|
|
96
97
|
|
|
97
98
|
- `ITPAY_AGENT_TYPE`: stable alternative to global `--agent-type`.
|
|
98
|
-
- `ITPAY_BACKEND_URL`: optional
|
|
99
|
+
- `ITPAY_BACKEND_URL`: optional sandbox override; only the exact official URL `https://sandbox.itpay.ai` is accepted. Unset it for production.
|
|
99
100
|
- `ITPAY_BEARER_TOKEN`: optional account-scoped browser session for legacy account reads. Local Agents normally use signed Device Authority plus the time-limited human authorization returned by `vault access`.
|
|
100
101
|
- `ITPAY_CART_SESSION_PATH`: local recovery-state path override.
|
|
101
102
|
- `ITPAY_CURRENCY`: ordinary Cart currency, default `CNY`.
|
|
@@ -127,3 +128,9 @@ Source boundaries:
|
|
|
127
128
|
- `src/state`: local Device Authority, idempotency journal, and recovery handles.
|
|
128
129
|
- `docs/cli-reference`: normative command contracts.
|
|
129
130
|
- `docs/agent/buyer`: packaged progressive workflow guidance.
|
|
131
|
+
|
|
132
|
+
### Run a published service
|
|
133
|
+
|
|
134
|
+
Use `itpay services run <service_id> --input-json ./input.json --json` for a published workflow. The input file must contain a JSON object matching the service input schema. With no input file, the CLI reports required fields and a command to continue the same execution.
|
|
135
|
+
|
|
136
|
+
Use `itpay services run <service_id> --execution <execution_id> --json` to resume. At payment, the CLI uses the existing Checkout QR/card handoff. The backend continues after verified payment even if the CLI exits. `--timeout <seconds>` controls initial status polling (default 120, maximum 600). Use existing order/refund commands for refund requests; an application is not a successful refund until its final status confirms success.
|
|
@@ -108,6 +108,9 @@ export class BackendClient {
|
|
|
108
108
|
startServiceExecution(input) {
|
|
109
109
|
return this.http.post("/v1/service-executions", input);
|
|
110
110
|
}
|
|
111
|
+
advanceServiceExecution(id, input, idempotencyKey) {
|
|
112
|
+
return this.http.post(`/v1/service-executions/${encodeURIComponent(id)}/advance`, { input, idempotency_key: idempotencyKey });
|
|
113
|
+
}
|
|
111
114
|
invokeServiceCapability(serviceExecutionID, capabilityID, input) {
|
|
112
115
|
return this.http.post(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/capabilities/${encodeURIComponent(capabilityID)}/invoke`, input, { replaySafe: Boolean(input.idempotency_key) });
|
|
113
116
|
}
|
|
@@ -25,6 +25,7 @@ export async function runCatalogList(backend, options = {}) {
|
|
|
25
25
|
}
|
|
26
26
|
function summarizeService(item) {
|
|
27
27
|
const flow = item.service_flow;
|
|
28
|
+
const offer = item.variants?.[0];
|
|
28
29
|
return {
|
|
29
30
|
service_id: item.service_id ?? null,
|
|
30
31
|
title: item.title,
|
|
@@ -43,6 +44,12 @@ function summarizeService(item) {
|
|
|
43
44
|
description: flow.primary_service.description,
|
|
44
45
|
price: formatProductMoney(flow.primary_service.amount_minor, flow.primary_service.currency),
|
|
45
46
|
},
|
|
47
|
+
} : offer ? {
|
|
48
|
+
primary_offer: {
|
|
49
|
+
title: offer.title || item.title,
|
|
50
|
+
description: item.description ?? "",
|
|
51
|
+
price: formatProductMoney(offer.amount_minor, offer.currency),
|
|
52
|
+
},
|
|
46
53
|
} : {}),
|
|
47
54
|
};
|
|
48
55
|
}
|
|
@@ -50,6 +50,9 @@ function checkoutHandoffInstruction(agentType, platform, amount) {
|
|
|
50
50
|
if (isZCodePlainChat(agentType, platform)) {
|
|
51
51
|
return `Backend 尚未确认付款。立即用 ZCode 内置浏览器打开 handoff.url,让用户完成付款;确认已发起打开后说明金额 ${amount},然后停止等待。不要只粘贴文字链接,不要下载、解析或重建二维码,不要创建新 Checkout、Payment Intent 或 Execution。只有内置浏览器明确不可用时,才展示同一个可点击 handoff.url。只有用户明确表示已付款或要求查询状态时,才执行 next.command;用户的话不是付款成功证明。`;
|
|
52
52
|
}
|
|
53
|
+
if (agentType?.trim().toLowerCase() === "doubao-work" && platform === "plain_chat") {
|
|
54
|
+
return `Backend 尚未确认付款。在当前豆包工作对话中展示两个有标签的官方入口:将 handoff.url 标为“手机直接打开收银台”,将 handoff.qr_image_url 标为“二维码图片(保存或用另一台设备扫码)”。说明金额 ${amount} 后停止等待。不要解析或单独输出 URL credential,不要下载或重建二维码,不要调用 pay,不要创建新 Checkout、Payment Intent 或 Execution。只有用户明确表示已付款或要求查询状态时,才执行 next.command;用户的话不是付款成功证明。`;
|
|
55
|
+
}
|
|
53
56
|
if (platform === "markdown") {
|
|
54
57
|
return `Backend 尚未确认付款。把 handoff.markdown 原样发送到当前桌面对话,确认二维码、付款链接和金额 ${amount} 均已实际对用户可见,然后停止等待。不要创建新 Checkout、Payment Intent 或 Execution;只有用户明确表示已付款或要求查询状态时,才执行 next.command;用户的话不是付款成功证明。`;
|
|
55
58
|
}
|
|
@@ -8,6 +8,7 @@ export const INSTALL_AGENT_TYPES = [
|
|
|
8
8
|
"claude-code-cli",
|
|
9
9
|
"workbuddy",
|
|
10
10
|
"zcode",
|
|
11
|
+
"doubao-work",
|
|
11
12
|
"kimi-code",
|
|
12
13
|
"openclaw",
|
|
13
14
|
];
|
|
@@ -18,6 +19,7 @@ const INSTRUCTIONS = {
|
|
|
18
19
|
"claude-code-cli": "在 Claude Code CLI 中始终传这个 Agent Type;付款交接只应显示在用户可见终端。",
|
|
19
20
|
workbuddy: "在 WorkBuddy 中始终传这个 Agent Type。运行会持久化 ~/.itpay-v3 的 ItPay Bash 命令前,把 Shell 工具参数 dangerouslyDisableSandbox 设为 true;用户拒绝权限时停止,不要切换 Node、删除 identity 或处理 lock。Checkout 返回已渲染的付款 Card Link 和 present_files action;原样执行一次 action 打开 handoff.url,不要检查本地二维码文件。",
|
|
20
21
|
zcode: "在 ZCode 中始终传这个 Agent Type。Checkout 或授权返回 handoff.url 后,立即用 ZCode 内置浏览器打开;不要只粘贴文字链接或重建二维码。只有内置浏览器不可用时才展示同一个可点击链接。",
|
|
22
|
+
"doubao-work": "在豆包工作中始终传这个 Agent Type。Checkout 或授权返回后,同时展示 handoff.url 和 handoff.qr_image_url 两个有标签的官方入口;优先让用户在手机上直接打开链接,二维码供保存或另一台设备扫码。",
|
|
21
23
|
"kimi-code": "保持 kimi-code Agent Type,使用标准 CLI 命令和终端付款交接;不要切换到其他平台身份。",
|
|
22
24
|
openclaw: "保持 openclaw Agent Type;每个展示命令都从当前可信会话上下文显式传 --host,IM 入口同时传 --target。Telegram 使用返回的原生 message action,其他入口展示标准二维码和付款链接。",
|
|
23
25
|
};
|
|
@@ -8,7 +8,7 @@ export async function runReadyz(backend, options = {}) {
|
|
|
8
8
|
status: response.status,
|
|
9
9
|
result: { backend: "available", backend_url: backendURL, environment, ...(options.agentType ? { agent_type: options.agentType } : {}) },
|
|
10
10
|
instruction: environment === "development"
|
|
11
|
-
? "ItPay
|
|
11
|
+
? "ItPay sandbox 可用。先完整读取内置 Skill,再根据用户意图选择新服务、已购内容、订单或退款入口;后续必须执行返回的完整命令并保持同一 sandbox Backend。"
|
|
12
12
|
: "ItPay 可用。先完整读取内置 Skill,再根据用户意图选择新服务、已购内容、订单或退款入口;不要默认开始购买。",
|
|
13
13
|
next: { command: "itpay skill show itpay --json", reason: "加载完整操作与安全规则" },
|
|
14
14
|
recovery: [],
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { HttpError } from "../client/http.js";
|
|
2
|
+
import { HttpTransportError } from "../client/transport.js";
|
|
1
3
|
import { operationID } from "../state/config.js";
|
|
2
4
|
import { validateContext } from "../state/client_context.js";
|
|
3
5
|
import { dispatchRender } from "../render/index.js";
|
|
@@ -20,6 +22,10 @@ export async function runServicesStart(backend, serviceID, options = {}) {
|
|
|
20
22
|
...(options.clientContext ?? {}),
|
|
21
23
|
},
|
|
22
24
|
});
|
|
25
|
+
if (response.workflow_entry) {
|
|
26
|
+
writeCommandEnvelope({ status: "input_required", result: { service_execution_id: response.execution.service_execution_id, service_id: serviceID, input_schema: response.workflow_entry.input_schema }, instruction: "根据服务声明填写输入,然后继续同一服务执行。", next: { command: `itpay services run ${serviceID} --execution ${response.execution.service_execution_id} --input-json <file> --json`, reason: "提交买家输入" }, recovery: [] }, { ...options });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
23
29
|
const capability = response.capabilities.find((item) => item.phase === response.execution.phase && !item.requires_payment);
|
|
24
30
|
const requiredInput = requiredInputFields(capability?.input_schema);
|
|
25
31
|
const command = capability
|
|
@@ -384,6 +390,10 @@ export async function runServicesCheckout(backend, config, serviceExecutionID, c
|
|
|
384
390
|
...(options.deliveryContact ?? {}),
|
|
385
391
|
...(options.email ? { email: options.email } : {}),
|
|
386
392
|
};
|
|
393
|
+
if (!options.resume && !capabilityID) {
|
|
394
|
+
const model = await backend.getServiceExecution(serviceExecutionID);
|
|
395
|
+
capabilityID = model.workflow_entry?.capability_id;
|
|
396
|
+
}
|
|
387
397
|
if (!options.resume && !capabilityID) {
|
|
388
398
|
throw new CommandContractError("capability_required", "--capability is required when creating a service checkout", "使用当前 Service Execution 返回的付费 capability;恢复已有 Checkout 时改用 --resume。", [{ command: `itpay services next ${serviceExecutionID} --json`, reason: "读取当前允许的付费 capability" }]);
|
|
389
399
|
}
|
|
@@ -395,7 +405,7 @@ export async function runServicesCheckout(backend, config, serviceExecutionID, c
|
|
|
395
405
|
}
|
|
396
406
|
const lockedInput = options.lockedInput ?? {};
|
|
397
407
|
const missingInput = missingRequiredInput(capability.input_schema, lockedInput);
|
|
398
|
-
if (missingInput.length > 0 && readModel.execution.next_action !== "create_checkout") {
|
|
408
|
+
if (missingInput.length > 0 && !readModel.workflow_entry && readModel.execution.next_action !== "create_checkout") {
|
|
399
409
|
throw new CommandContractError("capability_input_invalid", `missing required capability input: ${missingInput.join(", ")}`, "补齐付费 capability 的 required_input;本次没有创建 quote、Checkout 或订单。", [{ command: checkoutCommand(serviceExecutionID, capability, lockedInput), reason: "提交完整且会被锁定的服务输入" }]);
|
|
400
410
|
}
|
|
401
411
|
if (capability.delivery_email_required && String(deliveryContact.email ?? "").trim() === "") {
|
|
@@ -642,6 +652,32 @@ function servicesNextEnvelope(model) {
|
|
|
642
652
|
const execution = model.execution;
|
|
643
653
|
const currentDelivery = model.current_delivery ?? model.delivery_bindings.at(-1);
|
|
644
654
|
const lockedRefund = model.refunds.find((refund) => refund.access_locked);
|
|
655
|
+
if (model.workflow_entry && !lockedRefund && !["completed", "delivery"].includes(model.workflow?.status ?? "")) {
|
|
656
|
+
const id = execution.service_execution_id;
|
|
657
|
+
const state = model.workflow?.status ?? "input_required";
|
|
658
|
+
const recovery = state === "recovery_required" || state === "failed";
|
|
659
|
+
let command = `itpay services next ${id} --json`;
|
|
660
|
+
if (state === "payment")
|
|
661
|
+
command = `itpay services checkout ${id} --json`;
|
|
662
|
+
if (state === "input_required")
|
|
663
|
+
command = `itpay services run ${execution.service_id} --execution ${id} --input-json <file> --json`;
|
|
664
|
+
return {
|
|
665
|
+
status: state,
|
|
666
|
+
result: {
|
|
667
|
+
service_execution_id: id,
|
|
668
|
+
service_id: execution.service_id,
|
|
669
|
+
workflow: model.workflow,
|
|
670
|
+
...(state === "input_required" ? { input_schema: model.workflow_entry.input_schema } : {}),
|
|
671
|
+
},
|
|
672
|
+
instruction: recovery
|
|
673
|
+
? "执行未完成,请按步骤错误处理;不要重建执行或重复调用。"
|
|
674
|
+
: state === "payment"
|
|
675
|
+
? "服务已到付款步骤,使用现有 Checkout 完成扫码付款。"
|
|
676
|
+
: "继续读取同一执行;缺少输入时按服务声明补齐。",
|
|
677
|
+
next: recovery ? null : { command, reason: "继续当前流程" },
|
|
678
|
+
recovery: [],
|
|
679
|
+
};
|
|
680
|
+
}
|
|
645
681
|
if (lockedRefund) {
|
|
646
682
|
const terminal = lockedRefund.status === "succeeded";
|
|
647
683
|
return {
|
|
@@ -747,12 +783,12 @@ function servicesNextEnvelope(model) {
|
|
|
747
783
|
? appendFeedbackPostmortemInstruction(items.length > 0
|
|
748
784
|
? selection
|
|
749
785
|
? "搜索已完成。用编号、名称和可公开字段向用户说明结果,然后停止。只有用户明确选择候选并要求继续时才执行 next.command;不要提及 safe_payload。"
|
|
750
|
-
: "这一步的结果已经可用。用普通语言解释可公开字段并停止;不要提及
|
|
786
|
+
: "这一步的结果已经可用。用普通语言解释可公开字段并停止;不要提及 Arazzo、safe_payload 或内部 ID。"
|
|
751
787
|
: "告诉用户本次查询得到 0 个结果并停止。Agent 不读取其他交付、不重放当前查询、修改输入或创建新查询。", "delivered")
|
|
752
788
|
: items.length > 0
|
|
753
789
|
? selection
|
|
754
790
|
? "搜索已完成。用编号、名称和可公开字段向用户说明结果,然后停止。只有用户明确选择候选并要求继续时才执行 next.command;不要提及 safe_payload。"
|
|
755
|
-
: "这一步的结果已经可用。用普通语言解释可公开字段并停止;不要提及
|
|
791
|
+
: "这一步的结果已经可用。用普通语言解释可公开字段并停止;不要提及 Arazzo、safe_payload 或内部 ID。"
|
|
756
792
|
: "告诉用户本次查询得到 0 个结果并停止。Agent 不读取其他交付、不重放当前查询、修改输入或创建新查询。",
|
|
757
793
|
next: selection ? {
|
|
758
794
|
command: `itpay services action ${execution.service_execution_id} --action select_candidate --actor-type human --status approved --candidate <rank> --json`,
|
|
@@ -1066,3 +1102,58 @@ function tokenizedCheckoutURL(checkoutURL, displayToken, qrPayload) {
|
|
|
1066
1102
|
return `${checkoutURL}${separator}display_token=${encodeURIComponent(displayToken)}`;
|
|
1067
1103
|
}
|
|
1068
1104
|
}
|
|
1105
|
+
export async function runServicesRun(backend, config, serviceID, input, options = {}) {
|
|
1106
|
+
let id = options.executionID;
|
|
1107
|
+
try {
|
|
1108
|
+
if (!id) {
|
|
1109
|
+
const started = await backend.startServiceExecution({
|
|
1110
|
+
service_id: serviceID,
|
|
1111
|
+
client_context: { host: options.host ?? "terminal", ...(options.target ? { target: options.target } : {}) },
|
|
1112
|
+
});
|
|
1113
|
+
id = started.execution.service_execution_id;
|
|
1114
|
+
if (!started.workflow_entry) {
|
|
1115
|
+
await runServicesNext(backend, id, options);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
let model = await backend.getServiceExecution(id);
|
|
1120
|
+
if (model.execution.service_id !== serviceID)
|
|
1121
|
+
throw new Error("execution belongs to another service");
|
|
1122
|
+
if (!model.workflow_entry || (input === undefined && !model.workflow)) {
|
|
1123
|
+
await runServicesNext(backend, id, options);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (input !== undefined) {
|
|
1127
|
+
model = await backend.advanceServiceExecution(id, input, `workflow-input:${id}`);
|
|
1128
|
+
}
|
|
1129
|
+
const until = Date.now() + (options.timeoutSeconds ?? 120) * 1000;
|
|
1130
|
+
const sleep = options.sleep ?? ((milliseconds) => new Promise(resolve => setTimeout(resolve, milliseconds)));
|
|
1131
|
+
while (["queued", "running"].includes(model.workflow?.status ?? "") && Date.now() < until) {
|
|
1132
|
+
await sleep(options.pollIntervalMS ?? 1500);
|
|
1133
|
+
model = await backend.getServiceExecution(id);
|
|
1134
|
+
}
|
|
1135
|
+
if (model.refunds.some(refund => refund.access_locked)) {
|
|
1136
|
+
await runServicesNext(backend, id, options);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
if (model.workflow?.status === "payment") {
|
|
1140
|
+
await runServicesCheckout(backend, config, id, model.workflow_entry?.capability_id, {
|
|
1141
|
+
...options,
|
|
1142
|
+
...(config.agentType ? { agentType: config.agentType } : {}),
|
|
1143
|
+
resume: model.checkout_bindings.length > 0,
|
|
1144
|
+
});
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
await runServicesNext(backend, id, options);
|
|
1148
|
+
}
|
|
1149
|
+
catch (cause) {
|
|
1150
|
+
if (cause instanceof CommandContractError || cause instanceof HttpError)
|
|
1151
|
+
throw cause;
|
|
1152
|
+
if (cause instanceof HttpTransportError && !id) {
|
|
1153
|
+
throw new CommandContractError("workflow_start_outcome_unknown", cause.message, "创建服务执行时没有收到完整响应。先查询当前身份可见的执行;不要直接重跑并创建替代执行。", [{ command: "itpay services list --json", reason: "查找可能已经创建的服务执行" }]);
|
|
1154
|
+
}
|
|
1155
|
+
if (cause instanceof HttpTransportError)
|
|
1156
|
+
throw cause;
|
|
1157
|
+
throw new CommandContractError("workflow_run_failed", cause instanceof Error ? cause.message : "workflow run failed", "保留当前执行并按错误处理,不要重复创建服务执行。", [{ command: `itpay services run ${serviceID} --execution ${id} --json`, reason: "恢复同一执行" }]);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
@@ -20,6 +20,13 @@ export async function buildVaultHandoff(input) {
|
|
|
20
20
|
instruction: "向用户说明这是查看已购内容的只读授权,然后立即用 ZCode 内置浏览器打开 handoff.url。确认已发起打开后停止等待;不要只粘贴文字链接,也不要下载或重建二维码。只有内置浏览器明确不可用时,才展示同一个可点击 handoff.url。用户完成后重新运行最初的读取命令,不要再次创建授权请求。",
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
if (input.agentType?.trim().toLowerCase() === "doubao-work" && platform === "plain_chat") {
|
|
24
|
+
handoff.qr_image_url = input.qrPNGURL ?? vaultQRURL(input.authorizationURL, input.requestID);
|
|
25
|
+
return {
|
|
26
|
+
handoff,
|
|
27
|
+
instruction: "向用户说明这是查看已购内容的只读授权。在当前豆包工作对话中将 handoff.url 标为“直接打开授权页”,将 handoff.qr_image_url 标为“授权二维码图片(保存或用另一台设备扫码)”,然后停止等待。不要解析 URL credential、下载或重建二维码,也不要重复创建授权请求;用户完成后重新运行最初的读取命令。",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
23
30
|
if (platform === "markdown") {
|
|
24
31
|
const downloaded = input.imageAttachEnabled && input.qrPNGURL
|
|
25
32
|
? await downloadBrandQRToTmp(input.qrPNGURL, "auth", input.requestID, {
|
|
@@ -53,6 +60,17 @@ export async function buildVaultHandoff(input) {
|
|
|
53
60
|
...(platform === "terminal" ? { terminalQR: await renderTerminalQR(input.authorizationURL, input.qrFormat ?? "unicode") } : {}),
|
|
54
61
|
};
|
|
55
62
|
}
|
|
63
|
+
function vaultQRURL(authorizationURL, requestID) {
|
|
64
|
+
const url = new URL(authorizationURL);
|
|
65
|
+
const startToken = url.searchParams.get("start_token");
|
|
66
|
+
if (!startToken)
|
|
67
|
+
throw new Error("Backend did not return a usable Vault authorization QR URL");
|
|
68
|
+
url.pathname = `/v1/vault/access-requests/${encodeURIComponent(requestID)}/qr.png`;
|
|
69
|
+
url.search = "";
|
|
70
|
+
url.searchParams.set("start_token", startToken);
|
|
71
|
+
url.hash = "";
|
|
72
|
+
return url.toString();
|
|
73
|
+
}
|
|
56
74
|
function authorizationMarkdown(url, localPath) {
|
|
57
75
|
const lines = ["### ItPay 已购内容授权"];
|
|
58
76
|
if (localPath)
|
package/dist/src/main.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readFileSync as readWorkflowInputFile } from "node:fs";
|
|
2
|
+
import { runServicesRun } from "./commands/services.js";
|
|
1
3
|
// V3 CLI entrypoint. Each command maps 1:1 to a route family in
|
|
2
4
|
// services/backend/internal/httpapi/handlers/*.go. Commands only
|
|
3
5
|
// orchestrate; HTTP and rendering live in src/client and src/render.
|
|
@@ -202,7 +204,7 @@ function reportCLIError(error, contract) {
|
|
|
202
204
|
? "临时网络故障;CLI 已仅对可安全重放的操作完成有限自动重试,但仍未获得完整响应。按 recovery 查询同一资源的权威状态;不要创建替代 Checkout、Execution、Payment 或 Refund。"
|
|
203
205
|
: "网络在完整响应前中断;当前写操作没有安全重放合同,因此 CLI 未自动重试。按 recovery 查询权威状态;不要原样重放或创建替代 Checkout、Execution、Payment 或 Refund。"
|
|
204
206
|
: backendOverrideError
|
|
205
|
-
? "移除 ITPAY_BACKEND_URL 使用正式环境,或准确设置为 https://
|
|
207
|
+
? "移除 ITPAY_BACKEND_URL 使用正式环境,或准确设置为 https://sandbox.itpay.ai。"
|
|
206
208
|
: commandError?.instruction ?? authorizationInstruction ?? contract?.instruction ?? "检查命令参数后重试。",
|
|
207
209
|
next: null,
|
|
208
210
|
recovery: incompatible
|
|
@@ -1215,6 +1217,41 @@ vault
|
|
|
1215
1217
|
});
|
|
1216
1218
|
// --- service execution ----------------------------------------------------
|
|
1217
1219
|
const services = program.command("services").description("Generic V3 Service Execution commands");
|
|
1220
|
+
services
|
|
1221
|
+
.command("run")
|
|
1222
|
+
.description("Run a published service and present Checkout when payment is required")
|
|
1223
|
+
.argument("<service_id>")
|
|
1224
|
+
.option("--input-json <file>", "JSON object containing the service input")
|
|
1225
|
+
.option("--execution <execution_id>", "resume the same execution")
|
|
1226
|
+
.option("--timeout <seconds>", "maximum wait before returning current progress", Number, 120)
|
|
1227
|
+
.option("--host <host>")
|
|
1228
|
+
.option("--target <target>")
|
|
1229
|
+
.option("--json", "output JSON")
|
|
1230
|
+
.action(async (serviceID, options) => {
|
|
1231
|
+
const config = loadConfig();
|
|
1232
|
+
try {
|
|
1233
|
+
const input = options.inputJson ? JSON.parse(readWorkflowInputFile(options.inputJson, "utf8")) : undefined;
|
|
1234
|
+
if (input !== undefined && (!input || typeof input !== "object" || Array.isArray(input))) {
|
|
1235
|
+
throw new Error("input JSON must be an object");
|
|
1236
|
+
}
|
|
1237
|
+
if (!Number.isFinite(options.timeout) || options.timeout < 0 || options.timeout > 600) {
|
|
1238
|
+
throw new Error("timeout must be between 0 and 600 seconds");
|
|
1239
|
+
}
|
|
1240
|
+
await runServicesRun(newBackendClient(config), config, serviceID, input, {
|
|
1241
|
+
...(options.execution ? { executionID: options.execution } : {}),
|
|
1242
|
+
jsonOutput: Boolean(options.json),
|
|
1243
|
+
host: withHost(options.host, config.agentType, options.target),
|
|
1244
|
+
...(options.target ? { target: options.target } : {}),
|
|
1245
|
+
timeoutSeconds: options.timeout,
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
catch (error) {
|
|
1249
|
+
reportCLIError(error, {
|
|
1250
|
+
jsonOutput: Boolean(options.json), code: "workflow_run_failed",
|
|
1251
|
+
instruction: "按服务输入声明补齐参数;已有 execution 时继续该执行。", recovery: [],
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1218
1255
|
services
|
|
1219
1256
|
.command("start")
|
|
1220
1257
|
.description("Start a contract-backed service execution")
|
|
@@ -64,6 +64,8 @@ export function defaultHostForAgentType(agentType) {
|
|
|
64
64
|
return "plain-chat";
|
|
65
65
|
if (normalized === "zcode")
|
|
66
66
|
return "plain-chat";
|
|
67
|
+
if (normalized === "doubao-work")
|
|
68
|
+
return "plain-chat";
|
|
67
69
|
if (normalized === "openclaw")
|
|
68
70
|
return undefined;
|
|
69
71
|
return "terminal";
|
package/dist/src/state/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// CLI configuration loader. Production defaults to app.itpay.ai; the only
|
|
2
|
-
// allowed override is the official
|
|
2
|
+
// allowed override is the official sandbox Backend. Checkout
|
|
3
3
|
// display-token persistence belongs to the cart session file, protected with
|
|
4
4
|
// owner-only permissions. Provider secrets are explicitly out of scope here.
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -11,9 +11,9 @@ import { declaredAgentType } from "./agent_type.js";
|
|
|
11
11
|
import { DeviceAuthority } from "./device_authority.js";
|
|
12
12
|
import { OperationJournal } from "./operation_journal.js";
|
|
13
13
|
export const DEFAULT_BASE_URL = "https://app.itpay.ai";
|
|
14
|
-
export const
|
|
15
|
-
export const CLI_VERSION = "2.0.
|
|
16
|
-
export const API_CONTRACT_REVISION = "sha256:
|
|
14
|
+
export const SANDBOX_BASE_URL = "https://sandbox.itpay.ai";
|
|
15
|
+
export const CLI_VERSION = "2.0.39";
|
|
16
|
+
export const API_CONTRACT_REVISION = "sha256:1d637a77a49d5a821ef55f88bd9107427aede63f9652335b5d1a6a870a7e92a0";
|
|
17
17
|
const CART_SESSION_DEFAULT_DIR = ".itpay-v3";
|
|
18
18
|
const CART_SESSION_FILENAME = "cart.json";
|
|
19
19
|
const OPERATION_JOURNAL_FILENAME = "operations.json";
|
|
@@ -27,7 +27,7 @@ export function cliDistribution(env = process.env) {
|
|
|
27
27
|
export class BackendOverrideError extends Error {
|
|
28
28
|
code = "backend_override_forbidden";
|
|
29
29
|
constructor() {
|
|
30
|
-
super(`ITPAY_BACKEND_URL only supports ${DEFAULT_BASE_URL} or ${
|
|
30
|
+
super(`ITPAY_BACKEND_URL only supports ${DEFAULT_BASE_URL} or ${SANDBOX_BASE_URL}`);
|
|
31
31
|
this.name = "BackendOverrideError";
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -35,23 +35,23 @@ export function resolveBackendURL(env = process.env) {
|
|
|
35
35
|
const requested = env.ITPAY_BACKEND_URL?.trim();
|
|
36
36
|
if (!requested || requested === DEFAULT_BASE_URL || requested === `${DEFAULT_BASE_URL}/`)
|
|
37
37
|
return DEFAULT_BASE_URL;
|
|
38
|
-
if (requested ===
|
|
39
|
-
return
|
|
38
|
+
if (requested === SANDBOX_BASE_URL || requested === `${SANDBOX_BASE_URL}/`)
|
|
39
|
+
return SANDBOX_BASE_URL;
|
|
40
40
|
throw new BackendOverrideError();
|
|
41
41
|
}
|
|
42
42
|
export function qualifyBackendCommand(command, env = process.env) {
|
|
43
43
|
const requested = env.ITPAY_BACKEND_URL?.trim();
|
|
44
|
-
if (requested !==
|
|
44
|
+
if (requested !== SANDBOX_BASE_URL && requested !== `${SANDBOX_BASE_URL}/`)
|
|
45
45
|
return command;
|
|
46
|
-
if (!command.startsWith("itpay ") || command.startsWith(`ITPAY_BACKEND_URL=${
|
|
46
|
+
if (!command.startsWith("itpay ") || command.startsWith(`ITPAY_BACKEND_URL=${SANDBOX_BASE_URL} `))
|
|
47
47
|
return command;
|
|
48
|
-
return `ITPAY_BACKEND_URL=${
|
|
48
|
+
return `ITPAY_BACKEND_URL=${SANDBOX_BASE_URL} ${command}`;
|
|
49
49
|
}
|
|
50
50
|
function stateFilename(filename, baseURL) {
|
|
51
|
-
if (baseURL !==
|
|
51
|
+
if (baseURL !== SANDBOX_BASE_URL)
|
|
52
52
|
return filename;
|
|
53
53
|
const dot = filename.lastIndexOf(".");
|
|
54
|
-
return dot < 0 ? `${filename}.
|
|
54
|
+
return dot < 0 ? `${filename}.sandbox` : `${filename.slice(0, dot)}.sandbox${filename.slice(dot)}`;
|
|
55
55
|
}
|
|
56
56
|
function stateDir(env) {
|
|
57
57
|
return resolve(env.HOME || homedir(), CART_SESSION_DEFAULT_DIR);
|
|
@@ -74,7 +74,7 @@ export function loadConfig(env = process.env) {
|
|
|
74
74
|
const ideImageDirOverride = env.ITPAY_IDE_IMAGE_DIR_OVERRIDE;
|
|
75
75
|
return {
|
|
76
76
|
baseURL,
|
|
77
|
-
environment: baseURL ===
|
|
77
|
+
environment: baseURL === SANDBOX_BASE_URL ? "development" : "production",
|
|
78
78
|
...(agentType ? { agentType } : {}),
|
|
79
79
|
checkoutCurrency,
|
|
80
80
|
idempotencyKey,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"identity_model": {
|
|
14
14
|
"local_key": "One owner-only Ed25519 private key for the local installation.",
|
|
15
|
-
"backend_registration": "One registration per official Backend: app.itpay.ai by default and
|
|
15
|
+
"backend_registration": "One registration per official Backend: app.itpay.ai by default and sandbox.itpay.ai only with the exact test override.",
|
|
16
16
|
"agent_instance": "One instance per agent_type under each Backend registration; same-type windows and chats reuse it.",
|
|
17
17
|
"presentation": "Host and target route output only and never identify the Agent or provide business input."
|
|
18
18
|
},
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"Use the real runtime type and keep it stable across every command in the flow.",
|
|
51
51
|
"Keep the same CLI/Node launcher and Host-approved permission context for the whole flow.",
|
|
52
52
|
"Treat a new window, chat, task, or process of the same runtime as the same Agent Type, not a new identity.",
|
|
53
|
-
"Expect production traffic to use https://app.itpay.ai. Use https://
|
|
53
|
+
"Expect production traffic to use https://app.itpay.ai. Use https://sandbox.itpay.ai only for an explicit test and keep the complete returned Backend-prefixed command for that entire flow.",
|
|
54
54
|
"After automatic recovery fails, stop and report the exact code, selected official Backend, Agent Type, and command family without exposing private keys or tokens."
|
|
55
55
|
],
|
|
56
56
|
"forbidden": [
|
|
57
57
|
"Do not delete ~/.itpay-v3, rotate the key, switch Agent Type, or repeatedly retry to obtain fresh quota.",
|
|
58
58
|
"Do not use device recover for session expiry, revocation, quota recovery, or an unconfirmed Backend failure.",
|
|
59
|
-
"Do not redirect the CLI to
|
|
59
|
+
"Do not redirect the CLI to dev, local, an IP, or any custom Backend; only the exact official sandbox.itpay.ai test override is allowed.",
|
|
60
60
|
"Do not use --target as identity or service input."
|
|
61
61
|
],
|
|
62
62
|
"next_docs": [
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"intent": "list supported Agent Types",
|
|
15
15
|
"command": "itpay install --json",
|
|
16
|
-
"success_signal": "status is install_targets and exactly
|
|
16
|
+
"success_signal": "status is install_targets and exactly nine supported Agent Type definitions are returned"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"intent": "read setup for the real runtime",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"Start with install, identify the current real runtime from result.agent_types, run itpay install <agent_type> --json yourself, and then execute each returned next.command unchanged until the Skill is loaded.",
|
|
36
36
|
"After setup, tell the human only that ItPay is ready; never ask them to run setup commands or explain technical setup steps.",
|
|
37
37
|
"Use the CLI distribution already provided by the current npm package, Skill, or plugin; update only through that distribution's own instructions.",
|
|
38
|
-
"Production defaults to https://app.itpay.ai. Testing may set ITPAY_BACKEND_URL to the exact official URL https://
|
|
38
|
+
"Production defaults to https://app.itpay.ai. Testing may set ITPAY_BACKEND_URL to the exact official URL https://sandbox.itpay.ai; no other Backend is allowed.",
|
|
39
39
|
"If backend_contract_incompatible includes result.required_cli_version, stop all ItPay business commands and use only the exact distribution-specific update recovery returned by the CLI; never replace its version with latest.",
|
|
40
40
|
"After upgrading, require itpay --version to equal result.required_cli_version before running readyz again; never change Agent Type or Device identity to recover compatibility.",
|
|
41
|
-
"Use one exact type: codex-desktop, codex-cli, claude-code-desktop, claude-code-cli, workbuddy, zcode, kimi-code, or openclaw.",
|
|
41
|
+
"Use one exact type: codex-desktop, codex-cli, claude-code-desktop, claude-code-cli, workbuddy, zcode, doubao-work, kimi-code, or openclaw.",
|
|
42
42
|
"For compatibility, a global --agent-type codex declaration is normalized immediately to codex-desktop; all registration, output, and returned commands use codex-desktop. Never generate the alias, and do not use codex as an install target.",
|
|
43
|
-
"One local private key is reused, while Device registrations and quota lineage remain separate for app.itpay.ai and
|
|
43
|
+
"One local private key is reused, while Device registrations and quota lineage remain separate for app.itpay.ai and sandbox.itpay.ai.",
|
|
44
44
|
"Within each official Backend registration, each Agent Type has one Agent Instance; all windows and chats of the same type reuse it.",
|
|
45
45
|
"Agent Type identifies the runtime. Host and target only select a presentation destination; load render-hosts only when a handoff cannot be shown.",
|
|
46
46
|
"Keep the exact Agent Type in every next or recovery command; do not fall back to a type previously used by another runtime.",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
],
|
|
49
49
|
"forbidden": [
|
|
50
50
|
"Do not use terminal, claude-code, or plain-chat as Agent Types. Do not generate codex as an Agent Type; it is accepted only as a legacy global declaration and becomes codex-desktop before any request.",
|
|
51
|
-
"Do not set or suggest any Backend except the default https://app.itpay.ai or the exact test override https://
|
|
51
|
+
"Do not set or suggest any Backend except the default https://app.itpay.ai or the exact test override https://sandbox.itpay.ai.",
|
|
52
52
|
"Do not claim that install writes host configuration or registers a device; it only prints instructions.",
|
|
53
53
|
"Do not create a new identity for a different window, task, chat, or process of the same Agent Type."
|
|
54
54
|
],
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"claude code",
|
|
72
72
|
"workbuddy",
|
|
73
73
|
"zcode",
|
|
74
|
+
"doubao work",
|
|
74
75
|
"kimi code",
|
|
75
76
|
"openclaw"
|
|
76
77
|
]
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"required_state": {
|
|
13
13
|
"needs": [
|
|
14
14
|
"the real supported Agent Type",
|
|
15
|
-
"one official Backend: production https://app.itpay.ai by default, or explicit test https://
|
|
15
|
+
"one official Backend: production https://app.itpay.ai by default, or explicit test https://sandbox.itpay.ai"
|
|
16
16
|
],
|
|
17
17
|
"must_not_need": [
|
|
18
18
|
"Admin access",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"Treat result as current facts, instruction as how to use those facts, next as the preferred executable action, and recovery as exceptional paths.",
|
|
39
39
|
"Run one state-changing command at a time. Treat next.command as the preferred continuation: execute it unchanged after filling required user data only when the current result has not already satisfied the user's goal.",
|
|
40
40
|
"Keep the same explicit Agent Type through next and recovery commands; same-type windows reuse one Backend Agent Instance.",
|
|
41
|
-
"When testing
|
|
41
|
+
"When testing sandbox, execute every returned command unchanged so its ITPAY_BACKEND_URL=https://sandbox.itpay.ai prefix is preserved.",
|
|
42
42
|
"Use --target only for a Host presentation destination. Put capability business values in --input key=value exactly as required by the schema.",
|
|
43
43
|
"Start a separate Service Execution for each independent service intent; quota remains shared according to Backend identity policy.",
|
|
44
44
|
"Ask the user for required email or contact values and explain their purpose; never invent them.",
|
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
"default_host": "plain-chat",
|
|
41
41
|
"responsibility": "open handoff.url immediately in the ZCode built-in browser and stop; only show the same clickable URL when the built-in browser is unavailable"
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
"agent_type": "doubao-work",
|
|
45
|
+
"default_host": "plain-chat",
|
|
46
|
+
"responsibility": "show handoff.url as the preferred same-phone checkout or authorization link and handoff.qr_image_url as the labeled save-or-scan fallback; state the amount for Checkout and stop"
|
|
47
|
+
},
|
|
43
48
|
{
|
|
44
49
|
"agent_type": "kimi-code",
|
|
45
50
|
"default_host": "terminal",
|
|
@@ -70,6 +75,7 @@
|
|
|
70
75
|
"A local QR path is not visible until a desktop Agent attaches or renders that file on the human-facing surface; WorkBuddy never receives a local QR path.",
|
|
71
76
|
"For workbuddy with plain-chat, execute handoff.agent_action exactly once; it calls present_files with handoff.url as the only files element and opens the rendered Card Link in the right-side browser.",
|
|
72
77
|
"For zcode with plain-chat, open handoff.url in the built-in browser. Do not only paste text, download or rebuild a QR, or invent a private browser-tool payload; use the same clickable URL only as fallback.",
|
|
78
|
+
"For doubao-work with plain-chat, show two labeled official links: handoff.url for direct same-phone opening and handoff.qr_image_url for saving or scanning on another device; do not parse credentials, download or rebuild the QR, or create an alternative resource.",
|
|
73
79
|
"If the WorkBuddy action fails, send the original handoff.url, report that it did not auto-open, and stop without creating another payment resource.",
|
|
74
80
|
"Do not claim the handoff was shown until both a usable payment image or QR and the Checkout URL are visible.",
|
|
75
81
|
"IM Hosts that require a target must receive --target before Checkout creation. OpenClaw has no default Host; Kimi Code uses terminal.",
|
|
@@ -99,6 +105,7 @@
|
|
|
99
105
|
"desktop",
|
|
100
106
|
"workbuddy",
|
|
101
107
|
"zcode",
|
|
108
|
+
"doubao work",
|
|
102
109
|
"kimi code",
|
|
103
110
|
"openclaw",
|
|
104
111
|
"telegram"
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
| `claude-code-cli` | `terminal` | 在用户可见终端输出二维码和官方链接,不声称已在桌面对话展示。 |
|
|
17
17
|
| `workbuddy` | `plain-chat` | 返回完整渲染的 HTML Card Link 和可原样执行的 `present_files` action;立即打开 Card Link,不返回或检查本地图片路径。 |
|
|
18
18
|
| `zcode` | `plain-chat` | 返回完整渲染的官方 URL;立即用 ZCode 内置浏览器打开,不只粘贴文字链接,也不返回或重建二维码图片。 |
|
|
19
|
+
| `doubao-work` | `plain-chat` | 同时返回手机直达收银台链接和官方二维码图片链接;在豆包工作对话中明确标注两者,说明金额后停止等待。 |
|
|
19
20
|
| `kimi-code` | `terminal` | 使用标准 CLI 引导,在用户可见终端渲染二维码和付款链接。 |
|
|
20
21
|
| `openclaw` | 无;必须显式传入 | `--host telegram` 使用 OpenClaw 原生 `message` action;其他入口返回标准 HTTPS 二维码和付款链接。 |
|
|
21
22
|
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
- OpenClaw 的 IM Host 必须提供 `--target`。缺失时在任何 Checkout 创建前返回 `target_required`。
|
|
35
36
|
- `kimi-code` 是 CLI 型 Agent,复用 `terminal` Host 和现有 CLI 展示,不增加 Kimi 专属交易协议。
|
|
36
37
|
- `zcode` 使用 `plain-chat` Host 和官方 URL-only handoff。Agent 必须自行在 ZCode 内置浏览器打开 URL;只有内置浏览器确实不可用时才向用户展示同一个可点击链接。
|
|
38
|
+
- `doubao-work` 使用 `plain-chat` Host。它虽运行在云电脑中,仍走 Local Device Authority;不得改走 MCP 或创建第二套身份。Checkout 和 Vault 授权必须同时展示 `handoff.url` 与 `handoff.qr_image_url`。
|
|
37
39
|
- session 失效时 CLI 只续期并重试原请求一次;再次失败立即返回。revoked v2 Device 不自动换身份。
|
|
38
40
|
- 同一 Device 首次登记新的 Agent Type 时,CLI 只使用本地已登记且 Backend 仍接受的既有 Agent Instance 完成签名登记;被撤销的 Instance 会被跳过且不会恢复。若没有任何既有 Instance 可用,CLI 必须停止,不得重新登记 Device、旋转私钥或借用其他 Backend。
|
|
39
41
|
|
|
@@ -79,6 +81,7 @@ URL 内 credential 不得被提取、单独输出、记录或重建。
|
|
|
79
81
|
| `claude-code-cli / terminal` | `url`;非 JSON 输出另外渲染终端二维码 |
|
|
80
82
|
| `workbuddy / plain-chat` | `url, agent_action`(`present_files(files=[url])`,打开完整渲染的 HTML Card Link) |
|
|
81
83
|
| `zcode / plain-chat` | `url`(立即用 ZCode 内置浏览器打开;不返回图片或平台私有 action) |
|
|
84
|
+
| `doubao-work / plain-chat` | `url, qr_image_url`(`url` 是本机直接打开的首选入口;`qr_image_url` 是保存或由另一台设备扫码的备用入口) |
|
|
82
85
|
| `kimi-code / terminal` | `url`;非 JSON 输出另外渲染终端二维码 |
|
|
83
86
|
| `openclaw / telegram` | `url, qr_image_url, agent_action` |
|
|
84
87
|
| `openclaw / other` | `url, qr_image_url` |
|
|
@@ -87,6 +90,8 @@ WorkBuddy instruction 必须要求 Agent 原样执行一次 `handoff.agent_actio
|
|
|
87
90
|
|
|
88
91
|
ZCode instruction 必须明确要求 Agent 立即用内置浏览器打开 `handoff.url`,确认已发起打开后说明金额并停止。不得只把 URL 当作文字粘贴给用户,也不得下载、解析或重建二维码。只有内置浏览器明确不可用时,才把同一个 `handoff.url` 作为可点击链接展示。CLI 不猜测或输出 ZCode 私有工具调用 JSON。
|
|
89
92
|
|
|
93
|
+
Doubao Work instruction 必须要求 Agent 在当前对话中展示两个有标签的官方入口:优先展示“手机直接打开收银台”对应的 `handoff.url`,再展示“二维码图片(保存或用另一台设备扫码)”对应的 `handoff.qr_image_url`。说明金额后停止等待;不得解析 URL 中的 credential、下载或重建二维码、调用 `pay`,也不得创建替代 Checkout。
|
|
94
|
+
|
|
90
95
|
OpenClaw Telegram 的 `handoff.agent_action` 是可原样执行的原生 `message` tool action。`presentation` 只包含标准 `blocks.buttons`:`📱 手机点这儿支付` 使用扁平 `url`,`📋 已授权给我读` 使用扁平 `value=itp:grant_confirmed:<checkout_id>`;二维码单独使用 action 的 `media`。CLI `instruction` 必须要求 Agent 原样执行该 action,不得改写 Presentation、换用其他消息工具或声称普通文本回复等同于已发送按钮。收到授权 callback 后立即执行 `next.command` 查询同一 Checkout,再只跟随后端返回的同一 Execution grant 流程;callback 只携带 Checkout ID,不携带 display token,也不证明付款或 grant 已生效。OpenClaw `target` 使用原生 chat target(如 `5559456744` 或 `-1001234567890:topic:42`),不添加 `telegram:` 前缀。
|
|
91
96
|
|
|
92
97
|
### Purchased-content authorization
|
|
@@ -94,7 +99,7 @@ OpenClaw Telegram 的 `handoff.agent_action` 是可原样执行的原生 `messag
|
|
|
94
99
|
`vault access` 使用相同字段集合,但不包含金额、Checkout ID、付款状态或付款
|
|
95
100
|
查询命令。桌面 handoff 的 Markdown 标题和链接必须明确为“授权查看已购
|
|
96
101
|
内容”;Terminal 显示授权二维码;WorkBuddy 用 `present_files` 打开完整
|
|
97
|
-
`handoff.url`;ZCode 用内置浏览器打开完整 `handoff.url`;OpenClaw 使用返回的图片/原生 action。
|
|
102
|
+
`handoff.url`;ZCode 用内置浏览器打开完整 `handoff.url`;Doubao Work 同时展示授权链接和官方二维码图片链接;OpenClaw 使用返回的图片/原生 action。
|
|
98
103
|
|
|
99
104
|
授权 handoff 展示后 `next=null`。用户明确表示已完成时,Agent只重新执行
|
|
100
105
|
产生授权要求的原始 `vault list`、`orders` 或 `vault read`,不得再次执行
|
|
@@ -169,6 +169,7 @@ itpay buy \
|
|
|
169
169
|
| `claude-code-cli` | `terminal` | `url` | 在用户可见终端展示;不能声称桌面对话已收到图片。 |
|
|
170
170
|
| `workbuddy` | `plain-chat` | `url,agent_action` | 原样执行一次 `present_files(files=[url])`,在右侧打开完整渲染的 HTML Card Link,然后停止。 |
|
|
171
171
|
| `zcode` | `plain-chat` | `url` | 立即用 ZCode 内置浏览器打开 URL;只有浏览器不可用时才展示同一个可点击链接。 |
|
|
172
|
+
| `doubao-work` | `plain-chat` | `url,qr_image_url` | 展示“手机直接打开收银台”和“二维码图片(保存或用另一台设备扫码)”两个有标签的官方入口,说明金额后停止。 |
|
|
172
173
|
| `kimi-code` | `terminal` | `url` | 使用标准 CLI 非 JSON 终端二维码和链接。 |
|
|
173
174
|
| `openclaw` | 必须显式 | Telegram 返回 `url,qr_image_url,agent_action`;其他入口返回 `url,qr_image_url` | Telegram 执行原生 `message` action;其他入口直接展示图片和链接。 |
|
|
174
175
|
|
|
@@ -40,7 +40,7 @@ itpay catalog list [--json]
|
|
|
40
40
|
|
|
41
41
|
## 异常处理
|
|
42
42
|
|
|
43
|
-
输出不得包含 snapshot、manifest 原文、
|
|
43
|
+
输出不得包含 snapshot、manifest 原文、Arazzo workflow 或 Provider secret。服务为空时返回 `catalog_empty`,要求稍后重试,不猜服务 ID。
|
|
44
44
|
|
|
45
45
|
## Agent Type / Host
|
|
46
46
|
|
|
@@ -77,6 +77,7 @@ token 缺失或不匹配时使用本机句柄恢复。只有请求的 Checkout
|
|
|
77
77
|
| `claude-code-cli` | `url`;普通文本模式渲染终端二维码。 |
|
|
78
78
|
| `workbuddy` | 返回 `url,agent_action`;原样执行一次 `present_files(files=[url])` 打开完整渲染的 HTML Card Link,不生成本地文件。 |
|
|
79
79
|
| `zcode` | 返回 `url`;立即用 ZCode 内置浏览器打开,不只粘贴文字链接,也不生成或重建二维码文件。 |
|
|
80
|
+
| `doubao-work` | 返回 `url,qr_image_url`;展示手机直达收银台链接和官方二维码图片链接,说明金额后停止。 |
|
|
80
81
|
| `kimi-code` | `url`;普通文本模式渲染标准终端二维码。 |
|
|
81
82
|
| `openclaw` | Telegram 为 `url,qr_image_url,agent_action`;instruction 强制原样执行 action。`📋 已授权给我读` callback 触发同一 Checkout 查询,再由 Backend 决定是否进入 grant 读取;其他显式 Host 为 `url,qr_image_url`。 |
|
|
82
83
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
itpay --agent-type <agent_type> device recover --confirm-backend-reset --json
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
命令只作用于当前官方 Backend 的 Device registration,并保留本地 Ed25519 私钥、Cart 和业务资源。默认是 `https://app.itpay.ai`;显式测试可使用准确的 `ITPAY_BACKEND_URL=https://
|
|
15
|
+
命令只作用于当前官方 Backend 的 Device registration,并保留本地 Ed25519 私钥、Cart 和业务资源。默认是 `https://app.itpay.ai`;显式测试可使用准确的 `ITPAY_BACKEND_URL=https://sandbox.itpay.ai`。该命令不访问 Backend、不自动创建新身份;返回的只读 `services list` 会保留同一 Backend,是重新登记入口。
|
|
16
16
|
|
|
17
17
|
同一台电脑上的多个 Local Agent Type 共享本地 Device key,但各自使用独立 Agent
|
|
18
18
|
Instance。CLI 只在原子更新 Device state 时使用短期本地锁;释放和 stale recovery
|
|
@@ -18,10 +18,10 @@ itpay install [target] [--json]
|
|
|
18
18
|
|
|
19
19
|
| 参数 | 必填 | 说明 |
|
|
20
20
|
| --- | --- | --- |
|
|
21
|
-
| `target` | 否 |
|
|
21
|
+
| `target` | 否 | 九种正式 Agent Type 之一;省略或传 `list` 时列出全部。Host 名称不是合法 target。 |
|
|
22
22
|
| `--json` | 否 | 返回标准命令 envelope;推荐 Agent 使用。 |
|
|
23
23
|
|
|
24
|
-
正式 target:`codex-desktop`、`codex-cli`、`claude-code-desktop`、`claude-code-cli`、`workbuddy`、`zcode`、`kimi-code`、`openclaw`。
|
|
24
|
+
正式 target:`codex-desktop`、`codex-cli`、`claude-code-desktop`、`claude-code-cli`、`workbuddy`、`zcode`、`doubao-work`、`kimi-code`、`openclaw`。
|
|
25
25
|
|
|
26
26
|
## 指定 Agent Type 输出
|
|
27
27
|
|
|
@@ -77,7 +77,7 @@ OpenClaw 额外明确没有默认入口:
|
|
|
77
77
|
|
|
78
78
|
## 列表输出
|
|
79
79
|
|
|
80
|
-
省略 target 或传 `list`
|
|
80
|
+
省略 target 或传 `list` 时返回九组运行时定义,不重复每种类型的完整 instruction:
|
|
81
81
|
|
|
82
82
|
```json
|
|
83
83
|
{
|
|
@@ -90,6 +90,7 @@ OpenClaw 额外明确没有默认入口:
|
|
|
90
90
|
{ "agent_type": "claude-code-cli", "default_host": "terminal" },
|
|
91
91
|
{ "agent_type": "workbuddy", "default_host": "plain-chat" },
|
|
92
92
|
{ "agent_type": "zcode", "default_host": "plain-chat" },
|
|
93
|
+
{ "agent_type": "doubao-work", "default_host": "plain-chat" },
|
|
93
94
|
{ "agent_type": "kimi-code", "default_host": "terminal" },
|
|
94
95
|
{
|
|
95
96
|
"agent_type": "openclaw",
|
|
@@ -122,6 +123,7 @@ OpenClaw 额外明确没有默认入口:
|
|
|
122
123
|
| `claude-code-cli` | `terminal` | 只在用户可见终端展示付款交接。 |
|
|
123
124
|
| `workbuddy` | `plain-chat` | 会持久化 `~/.itpay-v3` 的 Bash 调用先设 Shell 工具参数 `dangerouslyDisableSandbox=true`;拒绝权限时停止。Checkout 原样执行返回的 `present_files` action,打开渲染后的 Card Link。 |
|
|
124
125
|
| `zcode` | `plain-chat` | Checkout 或授权返回后立即用 ZCode 内置浏览器打开 `handoff.url`;只有浏览器不可用时才展示同一个可点击链接。 |
|
|
126
|
+
| `doubao-work` | `plain-chat` | Checkout 或授权时同时展示 `handoff.url` 和 `handoff.qr_image_url` 两个有标签的官方入口;优先让手机直接打开链接,二维码供保存或另一台设备扫码。 |
|
|
125
127
|
| `kimi-code` | `terminal` | 使用标准 CLI 流程和终端展示,不增加 Kimi 专属命令。 |
|
|
126
128
|
| `openclaw` | 无 | 必须显式提供当前入口;Telegram 使用原生 action,其他入口展示标准二维码和链接。 |
|
|
127
129
|
|
|
@@ -140,7 +142,7 @@ OpenClaw 额外明确没有默认入口:
|
|
|
140
142
|
"code": "unsupported_agent_type",
|
|
141
143
|
"message": "unsupported install target: codex"
|
|
142
144
|
},
|
|
143
|
-
"instruction": "target 只接受:codex-desktop, codex-cli, claude-code-desktop, claude-code-cli, workbuddy, zcode, kimi-code, openclaw。",
|
|
145
|
+
"instruction": "target 只接受:codex-desktop, codex-cli, claude-code-desktop, claude-code-cli, workbuddy, zcode, doubao-work, kimi-code, openclaw。",
|
|
144
146
|
"next": null,
|
|
145
147
|
"recovery": [
|
|
146
148
|
{
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## 范围与意义
|
|
6
6
|
|
|
7
|
-
检查当前官方 Backend 是否可用。默认使用生产环境 `https://app.itpay.ai`;仅测试时可通过 `ITPAY_BACKEND_URL=https://
|
|
7
|
+
检查当前官方 Backend 是否可用。默认使用生产环境 `https://app.itpay.ai`;仅测试时可通过 `ITPAY_BACKEND_URL=https://sandbox.itpay.ai` 选择官方沙箱环境。它只调用 `/v1/readyz` 做 liveness 诊断,不执行平台兼容性 gate、不登记设备、不创建业务资源;需要服务端合同的命令仍会在各自入口严格检查 compatibility。
|
|
8
8
|
|
|
9
|
-
**上游:** CLI 安装;Backend 只能是官方 `https://app.itpay.ai` 或 `https://
|
|
9
|
+
**上游:** CLI 安装;Backend 只能是官方 `https://app.itpay.ai` 或 `https://sandbox.itpay.ai`,其他 override 在网络或本地状态写入前被拒绝。
|
|
10
10
|
**下游:** 完整 `itpay` Skill;由 Agent 根据用户意图选择新服务、已购内容、订单或退款入口。
|
|
11
11
|
|
|
12
12
|
## 语法与参数
|
|
@@ -31,14 +31,14 @@ itpay readyz [--json]
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
沙箱环境返回同一 envelope,但明确标记环境并在每个后续命令中保留 sandbox Backend:
|
|
35
35
|
|
|
36
36
|
```json
|
|
37
37
|
{
|
|
38
38
|
"status": "ready",
|
|
39
|
-
"result": { "backend": "available", "backend_url": "https://
|
|
40
|
-
"instruction": "ItPay
|
|
41
|
-
"next": { "command": "ITPAY_BACKEND_URL=https://
|
|
39
|
+
"result": { "backend": "available", "backend_url": "https://sandbox.itpay.ai", "environment": "development" },
|
|
40
|
+
"instruction": "ItPay sandbox 可用。先完整读取内置 Skill,再根据用户意图选择新服务、已购内容、订单或退款入口;后续必须执行返回的完整命令并保持同一 sandbox Backend。",
|
|
41
|
+
"next": { "command": "ITPAY_BACKEND_URL=https://sandbox.itpay.ai itpay skill show itpay --json", "reason": "加载完整操作与安全规则" },
|
|
42
42
|
"recovery": []
|
|
43
43
|
}
|
|
44
44
|
```
|
|
@@ -54,9 +54,9 @@ itpay readyz [--json]
|
|
|
54
54
|
"status": "error",
|
|
55
55
|
"error": {
|
|
56
56
|
"code": "backend_override_forbidden",
|
|
57
|
-
"message": "ITPAY_BACKEND_URL only supports https://app.itpay.ai or https://
|
|
57
|
+
"message": "ITPAY_BACKEND_URL only supports https://app.itpay.ai or https://sandbox.itpay.ai"
|
|
58
58
|
},
|
|
59
|
-
"instruction": "移除 ITPAY_BACKEND_URL 使用正式环境,或准确设置为 https://
|
|
59
|
+
"instruction": "移除 ITPAY_BACKEND_URL 使用正式环境,或准确设置为 https://sandbox.itpay.ai。",
|
|
60
60
|
"next": null,
|
|
61
61
|
"recovery": []
|
|
62
62
|
}
|
|
@@ -84,6 +84,7 @@ itpay services checkout <service_execution_id> --resume
|
|
|
84
84
|
| `claude-code-cli` | `handoff={url}`;普通文本模式在用户可见终端渲染二维码。 |
|
|
85
85
|
| `workbuddy` | `handoff={url,agent_action}`;原样执行一次 `present_files(files=[url])` 打开完整渲染的 HTML Card Link,然后停止;不得检查或生成本地文件。 |
|
|
86
86
|
| `zcode` | `handoff={url}`;立即用 ZCode 内置浏览器打开,然后停止;只有浏览器不可用时才展示同一个可点击链接。 |
|
|
87
|
+
| `doubao-work` | `handoff={url,qr_image_url}`;在当前对话中展示手机直达收银台链接和官方二维码图片链接,说明金额后停止。 |
|
|
87
88
|
| `kimi-code` | `handoff={url}`;复用标准 CLI 终端展示。 |
|
|
88
89
|
| `openclaw` | 必须显式传 Host;Telegram 还必须传 OpenClaw 原生 Target,并返回必须原样执行的 `message` action;其他入口返回标准 `url,qr_image_url`。 |
|
|
89
90
|
|
|
@@ -99,6 +100,12 @@ ZCode 的准确 instruction 语义必须完整包含:
|
|
|
99
100
|
Backend 尚未确认付款。立即用 ZCode 内置浏览器打开 handoff.url,让用户完成付款;确认已发起打开后说明金额,然后停止等待。不要只粘贴文字链接,不要下载、解析或重建二维码,不要创建新 Checkout、Payment Intent 或 Execution。只有内置浏览器明确不可用时,才展示同一个可点击 handoff.url。只有用户明确表示已付款或要求查询状态时,才执行 next.command;用户的话不是付款成功证明。
|
|
100
101
|
```
|
|
101
102
|
|
|
103
|
+
Doubao Work 的准确 instruction 语义必须完整包含:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Backend 尚未确认付款。在当前豆包工作对话中展示两个有标签的官方入口:将 handoff.url 标为“手机直接打开收银台”,将 handoff.qr_image_url 标为“二维码图片(保存或用另一台设备扫码)”。说明金额后停止等待。不要解析或单独输出 URL credential,不要下载或重建二维码,不要调用 pay,不要创建新 Checkout、Payment Intent 或 Execution。只有用户明确表示已付款或要求查询状态时,才执行 next.command;用户的话不是付款成功证明。
|
|
107
|
+
```
|
|
108
|
+
|
|
102
109
|
`--locale` 默认 `zh-CN`,可显式使用 `--locale en`。语言只影响 Card 渲染,不改变 Checkout、付款或恢复状态。
|
|
103
110
|
|
|
104
111
|
OpenClaw 的 Host/Target 校验必须发生在读取 execution 后、创建 Checkout 前;校验失败不能调用 Checkout 创建接口。Telegram `agent_action.arguments.presentation` 只使用 `blocks.buttons`,其中 `📱 手机点这儿支付` 使用扁平 `url`,`📋 已授权给我读` 使用 `value=itp:grant_confirmed:<checkout_id>`。准确 instruction 必须要求 Agent 立即用原生 `message` tool 原样执行 `handoff.agent_action`,不得改写 Presentation、换工具或用普通回复冒充按钮已发送。收到该 callback 表示用户声明已在收银台授权读取;Agent 立即执行 `next.command` 查询同一 Checkout,再只按 Backend 返回的 `next.command` 进入同一 Execution grant 流程。callback 不包含 display token,也不证明付款或 grant active;Backend 未返回 `grant_active` 前不得读取结果。
|
|
@@ -59,7 +59,7 @@ itpay services get <service_execution_id> [--json]
|
|
|
59
59
|
|
|
60
60
|
## 异常处理
|
|
61
61
|
|
|
62
|
-
默认不返回原始 events、Provider metadata、内部 bindings、
|
|
62
|
+
默认不返回原始 events、Provider metadata、内部 bindings、Arazzo workflow、capability schema、candidate hash、client context 或完整 payload。需要完整但仍经服务端脱敏的事件时才运行 `services events`。
|
|
63
63
|
|
|
64
64
|
execution 不存在或不属于当前身份时保留不透明 `not_found`,只恢复到 `itpay services list --json`;不得通过错误差异探测其他账号。
|
|
65
65
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `itpay services`
|
|
2
2
|
|
|
3
|
-
> **Product boundary:** `itpay` is the single public CLI entry point, and `$itpay` is its user-facing Skill invocation.
|
|
3
|
+
> **Product boundary:** `itpay` is the single public CLI entry point, and `$itpay` is its user-facing Skill invocation. Seller-published workflows enter the same Buyer execution, Checkout, delivery, and refund state machine as ItPay services.
|
|
4
4
|
|
|
5
5
|
## 命令范围
|
|
6
6
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
## 子命令
|
|
23
23
|
|
|
24
24
|
- [`start`](start.md)
|
|
25
|
+
- [`run`](run.md)
|
|
25
26
|
- [`invoke`](invoke.md)
|
|
26
27
|
- [`action`](action.md)
|
|
27
28
|
- [`quote`](quote.md)
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
itpay services --help
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
输出十一个子命令及一句选择规则:运行已发布服务使用 `run`,正常推进使用 `next`,深度诊断才使用 `get/events`。未知子命令返回参数错误和本 help,不创建 Execution。
|
|
44
45
|
|
|
45
46
|
## Agent Type / Host
|
|
46
47
|
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
读取一笔 Service Execution 的当前状态,并只返回一个首选下一步。若交付模式允许 Agent 直接读取,本命令同时返回完整 safe result。
|
|
8
8
|
|
|
9
9
|
**上游:** `services start`、`invoke`、`action`、`checkout`,或一次中断恢复。
|
|
10
|
-
**下游:** 一个可执行命令、需要用户完成的候选选择或授权,或
|
|
10
|
+
**下游:** 一个可执行命令、需要用户完成的候选选择或授权,或 Arazzo workflow 真正到达终态。
|
|
11
11
|
|
|
12
|
-
本命令不返回原始 Backend DTO、capability 列表、内部 result ID/hash、
|
|
12
|
+
本命令不返回原始 Backend DTO、capability 列表、内部 result ID/hash、Arazzo workflow、binding 或重复 guidance。
|
|
13
13
|
|
|
14
14
|
Backend 会根据当前 capability 选择 `current_delivery`;完整 `delivery_bindings` 仅是历史记录。CLI 不按数组位置猜测当前交付,同一 Execution 后续产生的新交付会取代旧交付成为默认结果。
|
|
15
15
|
|
|
@@ -28,7 +28,7 @@ itpay services next <service_execution_id> [--json]
|
|
|
28
28
|
|
|
29
29
|
## 候选选择
|
|
30
30
|
|
|
31
|
-
免费或付费候选已经产生、
|
|
31
|
+
免费或付费候选已经产生、Arazzo workflow 允许继续选择时,恢复输出必须包含当前 Result Set 的安全候选:
|
|
32
32
|
|
|
33
33
|
```json
|
|
34
34
|
{
|
|
@@ -76,7 +76,7 @@ itpay services next <service_execution_id> [--json]
|
|
|
76
76
|
}
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
只有
|
|
79
|
+
只有 Arazzo workflow 允许继续选择时才返回上述 `next`。若结果本身就是最终交付,instruction 要求用普通语言解释可公开字段并停止,且 `next: null`。文本输出可以保留 Agent 执行所需的 Execution 与 `delivery_mode`,但 Agent 不向用户暴露这些内部词、Result Item ID、Invocation ID 或 Hash。
|
|
80
80
|
|
|
81
81
|
## Vault 交付
|
|
82
82
|
|
|
@@ -91,7 +91,7 @@ itpay services next <service_execution_id> [--json]
|
|
|
91
91
|
"delivery_mode": "vault_artifact",
|
|
92
92
|
"grant_status": "none"
|
|
93
93
|
},
|
|
94
|
-
"instruction": "这是当前
|
|
94
|
+
"instruction": "这是当前 Arazzo step 对应的交付;请用户在订单页面授权,未授权前不要读取或猜测内容。",
|
|
95
95
|
"next": {
|
|
96
96
|
"command": "itpay services read-result <id> --json",
|
|
97
97
|
"reason": "仅在用户确认授权后执行"
|
|
@@ -141,7 +141,7 @@ itpay services next <service_execution_id> [--json]
|
|
|
141
141
|
"grant_status": "active",
|
|
142
142
|
"grant_expires_at": "<RFC3339 time>"
|
|
143
143
|
},
|
|
144
|
-
"instruction": "这是当前
|
|
144
|
+
"instruction": "这是当前 Arazzo step 对应的交付;用户授权有效,立即读取并遵守字段范围与到期时间。",
|
|
145
145
|
"next": {
|
|
146
146
|
"command": "itpay services read-result <id> --json",
|
|
147
147
|
"reason": "读取当前有效 grant 的结果"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
本命令是多 Execution 合并付款的高级入口。普通单 Execution 流程应使用 `services checkout`,不要把 `services quote` 当作 Checkout 失败后的替代路径。
|
|
10
10
|
|
|
11
|
-
**上游:** 用户明确要求合并多个独立 Execution,且每个 Execution 的
|
|
11
|
+
**上游:** 用户明确要求合并多个独立 Execution,且每个 Execution 的 Arazzo workflow 当前都允许 `prepare_quote`。
|
|
12
12
|
|
|
13
13
|
**下游:** `cart add --quote`。多个独立 Execution 的 Quote 可以加入同一 Cart。
|
|
14
14
|
|
|
@@ -57,7 +57,7 @@ itpay services quote <service_execution_id> --capability <capability_id>
|
|
|
57
57
|
- `capability_input_invalid`:缺少 required input;不创建 Quote、Cart 或 Checkout。
|
|
58
58
|
- `delivery_email_required`:先说明邮箱用于交付 claim link,再询问用户;禁止代填。
|
|
59
59
|
- 候选未确认、来自其他 Execution、Quote 已存在冲突:Backend 拒绝且不改变 Execution。
|
|
60
|
-
- `service_quote_not_allowed`:当前
|
|
60
|
+
- `service_quote_not_allowed`:当前 Arazzo workflow 不允许从当前 Execution 状态购买该 capability;不得换 capability、新建 Execution 或尝试其他购买命令,只回到同一 Execution 的 `services next`。
|
|
61
61
|
- Backend 不支持当前交易合同时返回 `backend_contract_incompatible`,必须停止,不能改用 `services checkout`、`cart`、`buy` 或 `pay` 绕过。
|
|
62
62
|
|
|
63
63
|
## Agent Type / Host
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# `itpay services run`
|
|
2
|
+
|
|
3
|
+
## 范围与意义
|
|
4
|
+
|
|
5
|
+
运行 Catalog 中已发布的通用 Buyer workflow。CLI 只提交服务声明要求的输入,并复用现有 Service Execution、Checkout、交付和退款命令;它不解释或执行 Seller 提供的任意命令文本。
|
|
6
|
+
|
|
7
|
+
没有提供输入时,本命令创建一次 Execution,返回已发布的 JSON input schema,并要求 Agent 继续同一 Execution。已有 Execution 必须通过 `--execution` 恢复,不能创建替代 Execution。
|
|
8
|
+
|
|
9
|
+
## 语法与参数
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
itpay services run <service_id>
|
|
13
|
+
[--input-json <file>]
|
|
14
|
+
[--execution <service_execution_id>]
|
|
15
|
+
[--timeout <seconds>]
|
|
16
|
+
[--host <host>]
|
|
17
|
+
[--target <target>]
|
|
18
|
+
[--json]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| 参数 | 说明 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `service_id` | Catalog 返回的服务 ID。恢复时必须与 Execution 所属服务一致。 |
|
|
24
|
+
| `--input-json` | UTF-8 JSON 文件;顶层必须是 object,并符合服务发布的 input schema。 |
|
|
25
|
+
| `--execution` | 恢复同一 Execution。不得用它切换服务或绕过原状态。 |
|
|
26
|
+
| `--timeout` | 本次等待 workflow 状态变化的秒数,默认 120,范围 0–600;超时只返回当前状态。 |
|
|
27
|
+
| `--host` / `--target` | Host 展示上下文,不是业务输入或 Buyer 身份。 |
|
|
28
|
+
| `--json` | 输出稳定 JSON 信封。 |
|
|
29
|
+
|
|
30
|
+
## 缺少输入
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"status": "input_required",
|
|
35
|
+
"result": {
|
|
36
|
+
"service_execution_id": "<execution_id>",
|
|
37
|
+
"service_id": "<service_id>",
|
|
38
|
+
"input_schema": { "type": "object", "required": ["<field>"] }
|
|
39
|
+
},
|
|
40
|
+
"instruction": "根据服务声明填写输入,然后继续同一服务执行。",
|
|
41
|
+
"next": {
|
|
42
|
+
"command": "itpay services run <service_id> --execution <execution_id> --input-json <file> --json",
|
|
43
|
+
"reason": "提交买家输入"
|
|
44
|
+
},
|
|
45
|
+
"recovery": []
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Agent 必须展示 schema 所需信息并等待用户提供真实输入;不得猜值,也不得为补输入创建新 Execution。
|
|
50
|
+
|
|
51
|
+
## 执行与付款
|
|
52
|
+
|
|
53
|
+
提供输入后,CLI 使用稳定 idempotency key 向同一 Execution 提交一次。`queued` 或 `running` 只轮询该 Execution。进入付款步骤时,CLI 调用现有 `services checkout`,返回其标准 `human_checkout_required` 输出和 Host handoff;不会实现第二套付款逻辑。
|
|
54
|
+
|
|
55
|
+
付款完成后即使 CLI 已退出,Backend 仍继续该 workflow。再次运行:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
itpay services run <service_id> --execution <execution_id> --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
只恢复当前状态。交付、Vault 授权和退款继续使用 `services next`、`services read-result`、`vault` 与 `refund` 的既有合同。
|
|
62
|
+
|
|
63
|
+
## 终态和异常
|
|
64
|
+
|
|
65
|
+
- 成功、付款、交付、授权、退款锁等状态使用既有命令的标准信封,不额外包装 Seller 专用格式。
|
|
66
|
+
- 既有 Checkout、身份、兼容性和网络错误保持原错误码、instruction 与 recovery;`services run` 不得覆盖可执行的邮箱、登录、升级或状态恢复指令。
|
|
67
|
+
- 如果创建 Execution 后未收到完整响应,返回 `workflow_start_outcome_unknown`,只允许先执行 `itpay services list --json` 查找刚创建的 Execution;不得直接重跑 `services run` 创建替代 Execution。
|
|
68
|
+
- `recovery_required` 或 `failed` 返回当前 workflow step,`next: null`,并明确禁止重建 Execution 或重放结果未知的 Provider 请求。
|
|
69
|
+
- service 不匹配、输入文件不是 JSON object、timeout 越界或 Backend 错误返回 `workflow_run_failed`。
|
|
70
|
+
- `--timeout` 到期不是失败,只返回同一 Execution 当前可恢复状态。
|
|
71
|
+
|
|
72
|
+
## Agent Type / Host
|
|
73
|
+
|
|
74
|
+
所有 Local Agent Type 共享同一状态机和 JSON 事实。Host 只改变付款链接、二维码或附件的展示方式,不改变身份、价格、workflow 或交付权限。
|
|
@@ -44,7 +44,7 @@ itpay --agent-type <agent_type> services start <service_id>
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Start API 只提供免费额度上限,不提供当前剩余额度,因此本命令不得虚构 `remaining`。不得输出全部 capability DTO、contract version、
|
|
47
|
+
Start API 只提供免费额度上限,不提供当前剩余额度,因此本命令不得虚构 `remaining`。不得输出全部 capability DTO、contract version、Arazzo workflow、buyer/device ID 或重复 guidance。若服务不存在,recovery 为 `catalog list`。设备 session 由 CLI 自动登记或刷新;401 `agent_device_session_required` 仅续期并重试一次,仍失败时返回错误,不循环。
|
|
48
48
|
|
|
49
49
|
## Agent Type / Host
|
|
50
50
|
|
|
@@ -27,7 +27,8 @@ itpay vault access [--artifact <artifact_ref>] [--host <host>] [--target <target
|
|
|
27
27
|
"handoff": {
|
|
28
28
|
"url": "https://app.itpay.ai/vault/access/...",
|
|
29
29
|
"qr_local_path": "<desktop-optional-local-path>",
|
|
30
|
-
"markdown": "<desktop-optional-host-ready-markdown>"
|
|
30
|
+
"markdown": "<desktop-optional-host-ready-markdown>",
|
|
31
|
+
"qr_image_url": "<chat-host-optional-absolute-https-png>"
|
|
31
32
|
},
|
|
32
33
|
"instruction": "说明这是当前智能体的只读授权,实际展示 handoff,然后停止;用户完成后重新运行最初的读取命令。",
|
|
33
34
|
"next": null,
|
|
@@ -53,6 +54,7 @@ Agent不得提取、单独输出、记录或重建其中的 credential;但不
|
|
|
53
54
|
| `claude-code-cli / terminal` | `url`;文本模式同时渲染终端二维码 |
|
|
54
55
|
| `workbuddy / plain-chat` | `url, agent_action` |
|
|
55
56
|
| `zcode / plain-chat` | `url`;立即用内置浏览器打开,浏览器不可用时才展示可点击链接 |
|
|
57
|
+
| `doubao-work / plain-chat` | `url, qr_image_url`;展示“直接打开授权页”和“授权二维码图片(保存或用另一台设备扫码)”两个有标签的官方入口 |
|
|
56
58
|
| `kimi-code / terminal` | `url`;文本模式同时渲染终端二维码 |
|
|
57
59
|
| `openclaw / telegram` | `url, qr_image_url, agent_action` |
|
|
58
60
|
| `openclaw / other` | `url, qr_image_url` |
|
|
@@ -61,3 +63,5 @@ Agent不得提取、单独输出、记录或重建其中的 credential;但不
|
|
|
61
63
|
未显示并发送同一个 URL;不得创建替代请求。
|
|
62
64
|
|
|
63
65
|
ZCode 不接收图片路径或二维码 URL。instruction 必须要求 Agent立即用内置浏览器打开完整 `handoff.url`,然后停止等待;不得只粘贴文字链接或重建二维码。仅当内置浏览器明确不可用时才展示同一个可点击链接。
|
|
66
|
+
|
|
67
|
+
Doubao Work 的两个字段都是必需项。若兼容 Backend 未直接返回二维码 URL,CLI 必须从同一官方授权入口派生 Backend 的对应二维码端点;无法安全派生时命令必须明确失败,不得返回缺字段的 handoff。instruction 必须要求 Agent 同时展示完整 `handoff.url` 与 `handoff.qr_image_url`,清楚区分直接打开与跨设备扫码用途,然后停止等待。不得解析 credential、下载或重建二维码,也不得重复执行 `vault access` 检查状态。
|
|
@@ -37,7 +37,7 @@ CLI 输出是给 Agent 执行的协议,不是后端 DTO 的调试转储。默
|
|
|
37
37
|
- `recovery`:成功时通常为空;失败或中断时最多两个动作。
|
|
38
38
|
- 一旦命令声明 `--agent-type` 或 `ITPAY_AGENT_TYPE`,所有 ItPay `next.command` 和 `recovery.command` 都保留同一类型。
|
|
39
39
|
- 相同事实不得同时出现在顶层、`agent_guidance`、`next_actions` 等多个位置。
|
|
40
|
-
- 默认隐藏 buyer、device、contract version、
|
|
40
|
+
- 默认隐藏 buyer、device、contract version、Arazzo workflow、quote lock、内部 event ID 等实现细节。
|
|
41
41
|
- token、付款 URL 和本地二维码路径只在确实需要交给用户时返回,并不得写入日志型命令。
|
|
42
42
|
|
|
43
43
|
## 默认文本输出
|
|
@@ -78,6 +78,7 @@ Commander 自动提供的 `itpay help [command]` 与 `itpay <group> help [subcom
|
|
|
78
78
|
### 通用服务执行
|
|
79
79
|
|
|
80
80
|
- [`itpay services`](commands/services/index.md)
|
|
81
|
+
- [`itpay services run`](commands/services/run.md)
|
|
81
82
|
- [`itpay services start`](commands/services/start.md)
|
|
82
83
|
- [`itpay services invoke`](commands/services/invoke.md)
|
|
83
84
|
- [`itpay services action`](commands/services/action.md)
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
13
13
|
| ChatGPT + Codex | `itpay-plugin-chatgpt` | ChatGPT MCP;本地 Codex CLI | OpenAI app-plus-skills plugin、MCP config、Skill、离线 CLI | blocked:Buyer Vault 候选尚未完成外部发布 | 2026-08-10 automated CI;ChatGPT/Codex 真机待验收 | pre-Vault `2b1e8a9c8030` | 当前 MCP 合同、OAuth refresh/revoke、OpenAI 审核;本地 CLI bundle pin |
|
|
14
14
|
| WorkBuddy | `itpay-skill-workbuddy` | 本地 CLI;显式 MCP | SkillHub/local Skill 包、单文件 CLI、MCP OAuth | blocked:Buyer Vault 候选尚未同步 SkillHub | 2026-08-10 automated CI;WorkBuddy 真机待验收 | pre-Vault `584ebf3f8c46` | 权限模式、窄浏览器、OAuth 回跳/refresh、SkillHub 状态 |
|
|
15
|
+
| 豆包工作 | `itpay-ai/cli` | 云电脑内的本地 CLI | 官方 npm CLI;`doubao-work` Agent Type | candidate:CLI 合同与自动化测试完成后待豆包工作真机验收 | 待本轮 automated CI 与真机验收 | 发布前 CLI tag | 云电脑安装/持久化、本机直达链接、二维码备用链接 |
|
|
15
16
|
| OpenClaw / ClawHub | `itpay-skill-openclaw` | host-dependent CLI | ClawHub Skill、单文件 CLI | blocked:Buyer Vault 候选尚未同步 ClawHub | 2026-08-10 automated CI;OpenClaw 真机待验收 | pre-Vault `af2aa79d85c8` | 公开目录/审核状态、host renderer、更新/回滚 |
|
|
16
17
|
| Kimi Work / Kimi Code | `itpay-plugin-kimi-work` | Work MCP;Code host-dependent CLI | Kimi plugin + Skill、离线 CLI | blocked:Buyer Vault 候选尚未发布;公开 release 仍为 `v2.0.17` | 2026-08-10 automated CI;两个 surface 真机待验收 | `v2.0.17` / `b8d40fe9cffd` | 两个 surface 真机、MCP Token persistence、市场状态 |
|
|
17
18
|
| Hermes Agent / Skills Hub | `itpay-skill-hermes` | host-dependent CLI | GitHub Skill tap、单文件 CLI | blocked:Buyer Vault 候选尚未同步 Skills Hub | 2026-08-10 automated CI;Hermes 真机待验收 | pre-Vault `1189f25103fd` | Skills Hub/trusted 状态、更新/回滚、可选 MCP 真机 |
|
|
@@ -29,7 +30,7 @@ the named platform has real acceptance and its distribution surface is updated.
|
|
|
29
30
|
| --- | --- | --- |
|
|
30
31
|
| Claude / Claude Code | planned | 确认分发面和仓库,完成 manifest、CLI/MCP 路由、OAuth/Device 真机验收。 |
|
|
31
32
|
| Gemini CLI | planned | 确认当前 Extension 规则,完成仓库、manifest、bundle 和真机验收。 |
|
|
32
|
-
|
|
|
33
|
+
| 扣子/火山/其他 | unconfirmed | 明确具体产品面和官方第三方发布入口,不能相互代替。 |
|
|
33
34
|
|
|
34
35
|
不要创建空仓库占位,也不要根据旧建议名单宣称支持。
|
|
35
36
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itpay/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.39",
|
|
4
4
|
"description": "The ItPay CLI for services, orders, and human-authorized purchased content.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"codex",
|
|
32
32
|
"openclaw",
|
|
33
33
|
"zcode",
|
|
34
|
+
"doubao-work",
|
|
35
|
+
"doubao",
|
|
34
36
|
"trae"
|
|
35
37
|
],
|
|
36
38
|
"license": "MIT",
|