@itpay/cli 2.0.13 → 2.0.15
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 +15 -7
- package/dist/src/commands/docs.js +1 -0
- package/dist/src/commands/guidance.js +8 -12
- package/dist/src/commands/install.js +2 -2
- package/dist/src/commands/readyz.js +7 -3
- package/dist/src/commands/skill.js +10 -10
- package/dist/src/main.js +22 -18
- package/dist/src/state/config.js +41 -6
- package/docs/agent/buyer/cart-checkout.json +16 -3
- package/docs/agent/buyer/catalog-list.json +1 -0
- package/docs/agent/buyer/identity-and-sessions.json +34 -13
- package/docs/agent/buyer/install-and-setup.json +25 -8
- package/docs/agent/buyer/orders-refunds.json +13 -2
- package/docs/agent/buyer/payment-flow.json +17 -3
- package/docs/agent/buyer/quickstart.json +49 -13
- package/docs/agent/buyer/render-hosts.json +14 -2
- package/docs/cli-reference/agent-types.md +2 -0
- package/docs/cli-reference/commands/buy.md +2 -0
- package/docs/cli-reference/commands/cart/add.md +2 -0
- package/docs/cli-reference/commands/cart/clear.md +2 -0
- package/docs/cli-reference/commands/cart/index.md +2 -0
- package/docs/cli-reference/commands/cart/next.md +2 -0
- package/docs/cli-reference/commands/cart/remove.md +3 -1
- package/docs/cli-reference/commands/cart/show.md +2 -0
- package/docs/cli-reference/commands/catalog/index.md +2 -0
- package/docs/cli-reference/commands/catalog/list.md +2 -0
- package/docs/cli-reference/commands/checkout.md +2 -0
- package/docs/cli-reference/commands/device.md +3 -1
- package/docs/cli-reference/commands/docs/index.md +2 -0
- package/docs/cli-reference/commands/docs/list.md +2 -0
- package/docs/cli-reference/commands/docs/search.md +2 -0
- package/docs/cli-reference/commands/docs/show.md +2 -0
- package/docs/cli-reference/commands/install.md +4 -2
- package/docs/cli-reference/commands/next.md +2 -0
- package/docs/cli-reference/commands/order.md +2 -0
- package/docs/cli-reference/commands/orders.md +2 -0
- package/docs/cli-reference/commands/pay.md +2 -0
- package/docs/cli-reference/commands/readyz.md +40 -11
- package/docs/cli-reference/commands/refund/cancel.md +2 -0
- package/docs/cli-reference/commands/refund/create.md +2 -0
- package/docs/cli-reference/commands/refund/get.md +2 -0
- package/docs/cli-reference/commands/refund/index.md +2 -0
- package/docs/cli-reference/commands/refund/list.md +2 -0
- package/docs/cli-reference/commands/refund/watch.md +2 -0
- package/docs/cli-reference/commands/services/action.md +2 -0
- package/docs/cli-reference/commands/services/checkout.md +2 -0
- package/docs/cli-reference/commands/services/events.md +2 -0
- package/docs/cli-reference/commands/services/get.md +2 -0
- package/docs/cli-reference/commands/services/index.md +2 -0
- package/docs/cli-reference/commands/services/invoke.md +2 -0
- package/docs/cli-reference/commands/services/list.md +2 -0
- package/docs/cli-reference/commands/services/next.md +2 -0
- package/docs/cli-reference/commands/services/quote.md +2 -0
- package/docs/cli-reference/commands/services/read-result.md +2 -0
- package/docs/cli-reference/commands/services/start.md +2 -0
- package/docs/cli-reference/commands/skill.md +5 -3
- package/docs/cli-reference/conventions.md +2 -0
- package/docs/cli-reference/index.md +3 -1
- package/docs/skill-bundle-rollout/01-mcp-authentication.md +256 -0
- package/docs/skill-bundle-rollout/02-platform-bundle-repositories.md +282 -0
- package/docs/skill-bundle-rollout/03-platform-publishing.md +270 -0
- package/docs/skill-bundle-rollout/README.md +98 -0
- package/package.json +6 -3
- package/skills/{itpay-buyer → itpay}/SKILL.md +39 -17
package/README.md
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
# ItPay CLI
|
|
2
2
|
|
|
3
|
-
The official V3 CLI
|
|
3
|
+
The official V3 CLI and the single ItPay entry point for Agent-driven commerce.
|
|
4
|
+
|
|
5
|
+
## One Entry Point, Two Actions
|
|
6
|
+
|
|
7
|
+
`itpay` is the only public CLI entry point, and `$itpay` is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are `buy` and `sell`: Buyer workflows are available now, while Seller workflows will use the same entry point and are not implemented yet. Do not create separate Buyer or Seller product entry points.
|
|
4
8
|
|
|
5
9
|
```bash
|
|
6
10
|
npm install -g @itpay/cli
|
|
7
11
|
itpay readyz --json
|
|
8
|
-
itpay skill show itpay
|
|
12
|
+
itpay skill show itpay --json
|
|
9
13
|
itpay install --json
|
|
10
14
|
itpay --agent-type codex-desktop readyz --json
|
|
11
15
|
# follow next.command: typed skill show, then catalog list
|
|
12
16
|
```
|
|
13
17
|
|
|
14
|
-
The
|
|
18
|
+
The CLI defaults to the production Backend `https://app.itpay.ai`. Explicit tests may set `ITPAY_BACKEND_URL=https://dev.itpay.ai`; every other Backend URL is rejected before network or local state access.
|
|
15
19
|
|
|
16
20
|
## Output Contract
|
|
17
21
|
|
|
@@ -42,11 +46,11 @@ Normative per-command contracts: [CLI Command Reference](docs/cli-reference/inde
|
|
|
42
46
|
|
|
43
47
|
`--agent-type` identifies the stable runtime and registered Agent instance. Every returned ItPay command preserves it. Different windows or chats of the same type reuse one Agent Instance; they are not separate identities. `--host` only selects the human presentation surface, and `--target` only routes output to a Host destination. Use `itpay install <agent_type> --json` for the exact responsibility.
|
|
44
48
|
|
|
45
|
-
The local installation keeps one Ed25519 private key
|
|
49
|
+
The local installation keeps one Ed25519 private key and a separate registration for each official Backend, with one Agent Instance per Agent Type under each registration. A rejected session is renewed and the same request is retried once; revoked v2 registrations are never silently replaced.
|
|
46
50
|
|
|
47
51
|
## Command Families
|
|
48
52
|
|
|
49
|
-
- `readyz
|
|
53
|
+
- `readyz`: selected official Backend liveness; `catalog list`: compatibility-gated discovery.
|
|
50
54
|
- `services start/invoke/action/checkout/next`: generic Service Execution flow.
|
|
51
55
|
- `cart add/show/remove/clear/next`, `buy`: canonical Cart and ordinary Checkout flow.
|
|
52
56
|
- `checkout`: authoritative payment and fulfillment recovery.
|
|
@@ -71,12 +75,12 @@ itpay --agent-type <agent_type> services checkout <service_execution_id> --resum
|
|
|
71
75
|
itpay checkout --id <checkout_id> --token <display_token> --json
|
|
72
76
|
```
|
|
73
77
|
|
|
74
|
-
The local `~/.itpay-v3` directory stores one owner-only signing key, Backend-scoped Device registrations and Agent instances, idempotency operations, and recovery handles. Backend state remains authoritative. Do not delete or rotate this identity to recover quota.
|
|
78
|
+
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`; dev uses `cart.dev.json` / `operations.dev.json`. Backend state remains authoritative. Do not delete or rotate this identity to recover quota.
|
|
75
79
|
|
|
76
80
|
## Environment
|
|
77
81
|
|
|
78
|
-
- `ITPAY_BACKEND_URL`: deliberate API override.
|
|
79
82
|
- `ITPAY_AGENT_TYPE`: stable alternative to global `--agent-type`.
|
|
83
|
+
- `ITPAY_BACKEND_URL`: optional test override; only the exact official URL `https://dev.itpay.ai` is accepted. Unset it for production.
|
|
80
84
|
- `ITPAY_BEARER_TOKEN`: account-scoped Buyer session for account-only commands such as `orders`.
|
|
81
85
|
- `ITPAY_CART_SESSION_PATH`: local recovery-state path override.
|
|
82
86
|
- `ITPAY_CURRENCY`: ordinary Cart currency, default `CNY`.
|
|
@@ -91,10 +95,14 @@ Provider credentials, Buyer identity, payment provider choice, amount, refund po
|
|
|
91
95
|
```bash
|
|
92
96
|
npm run lint
|
|
93
97
|
npm test
|
|
98
|
+
npm run test:coverage
|
|
94
99
|
npm run test:package
|
|
95
100
|
npm run pack:dry-run
|
|
96
101
|
```
|
|
97
102
|
|
|
103
|
+
`npm install` configures the repository's pre-commit hook. Every commit must pass
|
|
104
|
+
`npm run lint` and `npm test`; do not bypass the hook for pull-request changes.
|
|
105
|
+
|
|
98
106
|
Source boundaries:
|
|
99
107
|
|
|
100
108
|
- `src/main.ts`: parser and error-envelope wiring.
|
|
@@ -92,6 +92,7 @@ function findDocsDir() {
|
|
|
92
92
|
function parseDoc(raw, file) {
|
|
93
93
|
const value = JSON.parse(raw);
|
|
94
94
|
if (typeof value.schema_version !== "string" ||
|
|
95
|
+
typeof value.product_scope !== "string" ||
|
|
95
96
|
typeof value.topic !== "string" ||
|
|
96
97
|
typeof value.title !== "string" ||
|
|
97
98
|
typeof value.purpose !== "string") {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HttpError } from "../client/http.js";
|
|
2
2
|
import { resolveOutput } from "../render/sink.js";
|
|
3
3
|
import { declaredAgentType, qualifyItPayCommand } from "../state/agent_type.js";
|
|
4
|
+
import { qualifyBackendCommand } from "../state/config.js";
|
|
4
5
|
export function isTerminalServiceExecutionStatus(status) {
|
|
5
6
|
return status === "failed" || status === "refunded" || status === "cancelled";
|
|
6
7
|
}
|
|
@@ -84,7 +85,7 @@ export function printAgentGuidance(guidance, output) {
|
|
|
84
85
|
out("next actions:\n");
|
|
85
86
|
for (const action of guidance.next_actions) {
|
|
86
87
|
out(` - ${action.label}\n`);
|
|
87
|
-
out(` ${qualifyItPayCommand(action.command, agentType)}\n`);
|
|
88
|
+
out(` ${qualifyBackendCommand(qualifyItPayCommand(action.command, agentType))}\n`);
|
|
88
89
|
if (action.requires_human)
|
|
89
90
|
out(" requires human confirmation\n");
|
|
90
91
|
if (action.reason)
|
|
@@ -95,17 +96,17 @@ export function printAgentGuidance(guidance, output) {
|
|
|
95
96
|
out("recovery:\n");
|
|
96
97
|
for (const action of guidance.recovery) {
|
|
97
98
|
out(` - ${action.label}\n`);
|
|
98
|
-
out(` ${qualifyItPayCommand(action.command, agentType)}\n`);
|
|
99
|
+
out(` ${qualifyBackendCommand(qualifyItPayCommand(action.command, agentType))}\n`);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
function qualifyEnvelope(value, agentType) {
|
|
103
104
|
return {
|
|
104
105
|
...value,
|
|
105
|
-
next: value.next ? { ...value.next, command: qualifyItPayCommand(value.next.command, agentType) } : null,
|
|
106
|
+
next: value.next ? { ...value.next, command: qualifyBackendCommand(qualifyItPayCommand(value.next.command, agentType)) } : null,
|
|
106
107
|
recovery: value.recovery.map((action) => ({
|
|
107
108
|
...action,
|
|
108
|
-
command: qualifyItPayCommand(action.command, agentType),
|
|
109
|
+
command: qualifyBackendCommand(qualifyItPayCommand(action.command, agentType)),
|
|
109
110
|
})),
|
|
110
111
|
};
|
|
111
112
|
}
|
|
@@ -257,8 +258,8 @@ export function errorRecoveryActions(error) {
|
|
|
257
258
|
return [
|
|
258
259
|
{
|
|
259
260
|
id: "read_agent_session_rules",
|
|
260
|
-
label: "Read identity and session recovery rules",
|
|
261
|
-
command: "itpay skill show itpay
|
|
261
|
+
label: "Read ItPay identity and session recovery rules",
|
|
262
|
+
command: "itpay skill show itpay --json",
|
|
262
263
|
reason: "The CLI already attempted one automatic session renewal; do not rotate identity or loop retries.",
|
|
263
264
|
},
|
|
264
265
|
];
|
|
@@ -304,14 +305,9 @@ export function errorRecoveryActions(error) {
|
|
|
304
305
|
return [
|
|
305
306
|
{
|
|
306
307
|
id: "retry_after_backend_recovers",
|
|
307
|
-
label: "Retry after the
|
|
308
|
+
label: "Retry after the selected official Backend is reachable",
|
|
308
309
|
command: "itpay readyz",
|
|
309
310
|
},
|
|
310
|
-
{
|
|
311
|
-
id: "check_backend_url",
|
|
312
|
-
label: "Check the configured backend URL",
|
|
313
|
-
command: "echo $ITPAY_BACKEND_URL",
|
|
314
|
-
},
|
|
315
311
|
];
|
|
316
312
|
}
|
|
317
313
|
return [];
|
|
@@ -48,9 +48,9 @@ export function runInstall(target, options = {}) {
|
|
|
48
48
|
instruction: INSTRUCTIONS[normalized],
|
|
49
49
|
next: {
|
|
50
50
|
command: `itpay --agent-type ${normalized} readyz --json`,
|
|
51
|
-
reason: "
|
|
51
|
+
reason: "验证当前官方 ItPay API 的可用性",
|
|
52
52
|
},
|
|
53
|
-
recovery: [{ command: "itpay docs show install-and-setup", reason: "
|
|
53
|
+
recovery: [{ command: "itpay docs show install-and-setup", reason: "查看官方 Backend 和首次使用说明" }],
|
|
54
54
|
}, options);
|
|
55
55
|
}
|
|
56
56
|
function isInstallAgentType(value) {
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
import { writeCommandEnvelope } from "./guidance.js";
|
|
3
3
|
export async function runReadyz(backend, options = {}) {
|
|
4
4
|
const response = await backend.readyz();
|
|
5
|
+
const backendURL = options.backendURL ?? "https://app.itpay.ai";
|
|
6
|
+
const environment = options.environment ?? "production";
|
|
5
7
|
writeCommandEnvelope({
|
|
6
8
|
status: response.status,
|
|
7
|
-
result: { backend: "available", ...(options.agentType ? { agent_type: options.agentType } : {}) },
|
|
8
|
-
instruction:
|
|
9
|
-
|
|
9
|
+
result: { backend: "available", backend_url: backendURL, environment, ...(options.agentType ? { agent_type: options.agentType } : {}) },
|
|
10
|
+
instruction: environment === "development"
|
|
11
|
+
? "ItPay dev 可用;后续必须执行返回的完整命令,并继续使用同一个 dev Backend。先完整读取内置 ItPay Skill,再进入当前已支持的 buy 流程。"
|
|
12
|
+
: "ItPay 可用;先完整读取内置 ItPay Skill,再进入当前已支持的 buy 流程。sell 将来也使用同一入口,但当前尚未实现。",
|
|
13
|
+
next: { command: "itpay skill show itpay --json", reason: "加载完整操作与安全规则" },
|
|
10
14
|
recovery: [],
|
|
11
15
|
}, options);
|
|
12
16
|
}
|
|
@@ -4,24 +4,24 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { declaredAgentType } from "../state/agent_type.js";
|
|
5
5
|
import { CommandContractError, writeCommandEnvelope } from "./guidance.js";
|
|
6
6
|
const commandDir = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const
|
|
7
|
+
const ITPAY_SKILL = "itpay";
|
|
8
8
|
export function runSkillShow(name, options = {}) {
|
|
9
9
|
const normalized = name.trim().toLowerCase();
|
|
10
|
-
if (normalized !==
|
|
11
|
-
throw new CommandContractError("skill_not_found", `skill not found: ${name}`, `当前 CLI 只内置 ${
|
|
10
|
+
if (normalized !== ITPAY_SKILL) {
|
|
11
|
+
throw new CommandContractError("skill_not_found", `skill not found: ${name}`, `当前 CLI 只内置 ${ITPAY_SKILL};不要猜测 Skill 名称。`, [{ command: `itpay skill show ${ITPAY_SKILL} --json`, reason: "读取完整 ItPay Skill" }]);
|
|
12
12
|
}
|
|
13
13
|
let content;
|
|
14
14
|
try {
|
|
15
15
|
content = readFileSync(findSkillPath(), "utf8");
|
|
16
16
|
}
|
|
17
17
|
catch {
|
|
18
|
-
throw new Error("packaged skill is unavailable: itpay
|
|
18
|
+
throw new Error("packaged skill is unavailable: itpay");
|
|
19
19
|
}
|
|
20
20
|
validateSkill(content);
|
|
21
21
|
const agentType = options.agentType ?? declaredAgentType();
|
|
22
22
|
const envelope = {
|
|
23
23
|
status: "shown",
|
|
24
|
-
result: { skill:
|
|
24
|
+
result: { skill: ITPAY_SKILL, content },
|
|
25
25
|
instruction: agentType
|
|
26
26
|
? agentType === "workbuddy"
|
|
27
27
|
? "完整读取并遵守 Skill;保持 workbuddy 和同一 Node/CLI launcher。运行会持久化 ~/.itpay-v3 的 ItPay Bash 命令前,把 Shell 工具参数 dangerouslyDisableSandbox 设为 true;用户拒绝权限时停止,不要切换 Node、删除 identity 或处理 lock。"
|
|
@@ -40,16 +40,16 @@ export function runSkillShow(name, options = {}) {
|
|
|
40
40
|
}
|
|
41
41
|
function findSkillPath() {
|
|
42
42
|
if (process.env.ITPAY_CLI_SKILLS_DIR) {
|
|
43
|
-
return resolve(process.env.ITPAY_CLI_SKILLS_DIR,
|
|
43
|
+
return resolve(process.env.ITPAY_CLI_SKILLS_DIR, ITPAY_SKILL, "SKILL.md");
|
|
44
44
|
}
|
|
45
|
-
const packagePath = resolve(commandDir, "..", "..", "..", "skills",
|
|
45
|
+
const packagePath = resolve(commandDir, "..", "..", "..", "skills", ITPAY_SKILL, "SKILL.md");
|
|
46
46
|
if (existsSync(packagePath))
|
|
47
47
|
return packagePath;
|
|
48
|
-
return resolve(commandDir, "..", "..", "skills",
|
|
48
|
+
return resolve(commandDir, "..", "..", "skills", ITPAY_SKILL, "SKILL.md");
|
|
49
49
|
}
|
|
50
50
|
function validateSkill(content) {
|
|
51
51
|
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
52
|
-
if (!frontmatter || !/^name:\s*itpay
|
|
53
|
-
throw new Error("invalid packaged skill: itpay
|
|
52
|
+
if (!frontmatter || !/^name:\s*itpay\s*$/m.test(frontmatter) || !/^description:\s*(?:>|\S)/m.test(frontmatter)) {
|
|
53
|
+
throw new Error("invalid packaged skill: itpay");
|
|
54
54
|
}
|
|
55
55
|
}
|
package/dist/src/main.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// services/backend/internal/httpapi/handlers/*.go. Commands only
|
|
3
3
|
// orchestrate; HTTP and rendering live in src/client and src/render.
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { CLI_VERSION, loadConfig, cartSessionPath, newBackendClient } from "./state/config.js";
|
|
5
|
+
import { BackendOverrideError, CLI_VERSION, loadConfig, cartSessionPath, newBackendClient } from "./state/config.js";
|
|
6
6
|
import { DeviceAuthority, DeviceAuthorizationError, DeviceStateError } from "./state/device_authority.js";
|
|
7
7
|
import { CartSession } from "./state/cart_session.js";
|
|
8
8
|
import { defaultHostForAgentType, normalizeHost, validateContext } from "./state/client_context.js";
|
|
@@ -26,7 +26,7 @@ import { collectOption, parseKeyValueList, runServicesAction, runServicesCheckou
|
|
|
26
26
|
const program = new Command();
|
|
27
27
|
program
|
|
28
28
|
.name("itpay")
|
|
29
|
-
.description("V3 ItPay CLI —
|
|
29
|
+
.description("V3 ItPay CLI — one entry point for buy workflows and future sell workflows")
|
|
30
30
|
.option("--agent-type <type>", "agent runtime type used for device enrollment and client-specific guidance")
|
|
31
31
|
.version(CLI_VERSION);
|
|
32
32
|
function withHost(value) {
|
|
@@ -83,6 +83,7 @@ function resolveCheckoutPresentationArgs(input) {
|
|
|
83
83
|
}
|
|
84
84
|
function reportCLIError(error, contract) {
|
|
85
85
|
const commandError = error instanceof CommandContractError ? error : undefined;
|
|
86
|
+
const backendOverrideError = error instanceof BackendOverrideError ? error : undefined;
|
|
86
87
|
const deviceError = error instanceof DeviceAuthorizationError ? error : undefined;
|
|
87
88
|
const stateError = error instanceof DeviceStateError ? error : undefined;
|
|
88
89
|
const httpRecovery = errorRecoveryActions(error).map((action) => ({
|
|
@@ -106,11 +107,11 @@ function reportCLIError(error, contract) {
|
|
|
106
107
|
const providerContractMismatch = error instanceof HttpError && error.code === "provider_contract_mismatch";
|
|
107
108
|
const capabilityInputInvalid = error instanceof HttpError && error.code === "capability_input_invalid";
|
|
108
109
|
const deviceRecovery = deviceError ? [{
|
|
109
|
-
command: "itpay skill show itpay
|
|
110
|
-
reason: "
|
|
110
|
+
command: "itpay skill show itpay --json",
|
|
111
|
+
reason: "读取 ItPay 身份边界;该错误需要用户或运营恢复 Backend 登记,不能通过换类型或删除本地身份绕过",
|
|
111
112
|
}] : [];
|
|
112
113
|
const stateRecovery = stateError ? [{
|
|
113
|
-
command: "itpay skill show itpay
|
|
114
|
+
command: "itpay skill show itpay --json",
|
|
114
115
|
reason: "读取 Device 状态边界;修复当前 Host 的持久写权限后重试原命令",
|
|
115
116
|
}] : [];
|
|
116
117
|
const authorizationInstruction = stateError
|
|
@@ -122,11 +123,11 @@ function reportCLIError(error, contract) {
|
|
|
122
123
|
: deviceError
|
|
123
124
|
? "Device 身份验证失败;停止重试,不要切换 Agent Type、删除状态或旋转私钥。"
|
|
124
125
|
: undefined;
|
|
125
|
-
if (contract || commandError) {
|
|
126
|
+
if (contract || commandError || backendOverrideError) {
|
|
126
127
|
writeCommandEnvelope({
|
|
127
128
|
status: "error",
|
|
128
129
|
error: {
|
|
129
|
-
code: incompatible ? "backend_contract_incompatible" : commandError?.code ?? (error instanceof HttpError ? error.code : stateError?.code ?? deviceError?.code ?? contract?.code ?? "command_failed"),
|
|
130
|
+
code: incompatible ? "backend_contract_incompatible" : backendOverrideError?.code ?? commandError?.code ?? (error instanceof HttpError ? error.code : stateError?.code ?? deviceError?.code ?? contract?.code ?? "command_failed"),
|
|
130
131
|
message: error instanceof Error ? error.message : String(error),
|
|
131
132
|
},
|
|
132
133
|
...(requiredCLIVersion ? {
|
|
@@ -164,7 +165,9 @@ function reportCLIError(error, contract) {
|
|
|
164
165
|
? "Provider 拒绝了本次请求,但未声明这是输入错误;向用户逐字报告 error.message 和 result.quota 并停止。不要修改输入、不要重试、不要创建新 Execution。"
|
|
165
166
|
: capabilityInputInvalid
|
|
166
167
|
? "输入未通过本地校验,上游尚未被调用且用户额度未变化。向用户逐字报告 error.message 并停止,不要原样重试或运行其他恢复命令。用户提供修正后的输入后,继续使用当前未结束的 Execution。"
|
|
167
|
-
:
|
|
168
|
+
: backendOverrideError
|
|
169
|
+
? "移除 ITPAY_BACKEND_URL 使用正式环境,或准确设置为 https://dev.itpay.ai。"
|
|
170
|
+
: commandError?.instruction ?? authorizationInstruction ?? contract?.instruction ?? "检查命令参数后重试。",
|
|
168
171
|
next: null,
|
|
169
172
|
recovery: incompatible
|
|
170
173
|
? requiredCLIVersion
|
|
@@ -172,9 +175,9 @@ function reportCLIError(error, contract) {
|
|
|
172
175
|
: []
|
|
173
176
|
: backendInternal || providerConnectionUnavailable || providerTemporary || providerInputRejected || providerContractMismatch || providerRejected || capabilityInputInvalid
|
|
174
177
|
? []
|
|
175
|
-
: commandError?.recovery ?? (stateError ? stateRecovery : deviceError ? deviceRecovery : identityRecovery ? httpRecovery : contract?.recovery ?? []),
|
|
178
|
+
: backendOverrideError ? [] : commandError?.recovery ?? (stateError ? stateRecovery : deviceError ? deviceRecovery : identityRecovery ? httpRecovery : contract?.recovery ?? []),
|
|
176
179
|
}, {
|
|
177
|
-
...(contract?.jsonOutput !== undefined ? { jsonOutput: contract.jsonOutput } : {}),
|
|
180
|
+
...(contract?.jsonOutput !== undefined ? { jsonOutput: contract.jsonOutput } : backendOverrideError ? { jsonOutput: process.argv.includes("--json") } : {}),
|
|
178
181
|
output: (text) => { process.stderr.write(text); },
|
|
179
182
|
});
|
|
180
183
|
process.exitCode = 1;
|
|
@@ -209,33 +212,34 @@ program
|
|
|
209
212
|
const config = loadConfig();
|
|
210
213
|
const backend = newBackendClient(config);
|
|
211
214
|
try {
|
|
212
|
-
await
|
|
213
|
-
|
|
215
|
+
await runReadyz(backend, {
|
|
216
|
+
jsonOutput: Boolean(options.json), backendURL: config.baseURL, environment: config.environment,
|
|
217
|
+
...(config.agentType ? { agentType: config.agentType } : {}),
|
|
218
|
+
});
|
|
214
219
|
}
|
|
215
220
|
catch (error) {
|
|
216
221
|
reportCLIError(error, {
|
|
217
222
|
jsonOutput: Boolean(options.json),
|
|
218
223
|
code: "backend_unavailable",
|
|
219
|
-
instruction:
|
|
224
|
+
instruction: `当前官方 Backend ${config.baseURL} 不可用;恢复前不要继续下单,也不要切换环境。`,
|
|
220
225
|
recovery: [
|
|
221
|
-
{ command: "
|
|
222
|
-
{ command: "itpay readyz", reason: "重试可用性检查" },
|
|
226
|
+
{ command: "itpay readyz", reason: "重试当前官方 Backend 的可用性检查" },
|
|
223
227
|
],
|
|
224
228
|
});
|
|
225
229
|
}
|
|
226
230
|
});
|
|
227
231
|
// --- device ---------------------------------------------------------------
|
|
228
|
-
const deviceCmd = program.command("device").description("Recover
|
|
232
|
+
const deviceCmd = program.command("device").description("Recover the current official Backend registration after an operator-confirmed reset");
|
|
229
233
|
deviceCmd
|
|
230
234
|
.command("recover")
|
|
231
|
-
.description("Forget only the
|
|
235
|
+
.description("Forget only the current official Backend registration while preserving the local private key")
|
|
232
236
|
.option("--confirm-backend-reset", "confirm that an operator reset the selected Backend registration database")
|
|
233
237
|
.option("--json", "output JSON instead of terminal text")
|
|
234
238
|
.action(async (options) => {
|
|
235
239
|
const config = loadConfig();
|
|
236
240
|
try {
|
|
237
241
|
if (!config.agentType) {
|
|
238
|
-
throw new CommandContractError("agent_type_required",
|
|
242
|
+
throw new CommandContractError("agent_type_required", `agent type is required for ${config.baseURL} Device recovery`, "如实声明当前 Agent Type;恢复后必须用同一类型重新登记。", [{ command: "itpay install --json", reason: "选择当前真实 Agent Type" }]);
|
|
239
243
|
}
|
|
240
244
|
if (!options.confirmBackendReset) {
|
|
241
245
|
throw new CommandContractError("backend_reset_confirmation_required", "--confirm-backend-reset is required", "仅在运营已确认当前 Backend 的 Device 登记数据库被重建或清空后执行;普通 session 失效或 revoked 不得使用。", [{ command: "itpay docs show identity-and-sessions --json", reason: "检查适用边界" }]);
|
package/dist/src/state/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// CLI configuration loader.
|
|
1
|
+
// CLI configuration loader. Production defaults to app.itpay.ai; the only
|
|
2
|
+
// allowed override is the official dev Backend. Checkout
|
|
2
3
|
// display-token persistence belongs to the cart session file, protected with
|
|
3
4
|
// owner-only permissions. Provider secrets are explicitly out of scope here.
|
|
4
5
|
import { homedir } from "node:os";
|
|
@@ -10,21 +11,54 @@ import { declaredAgentType } from "./agent_type.js";
|
|
|
10
11
|
import { DeviceAuthority } from "./device_authority.js";
|
|
11
12
|
import { OperationJournal } from "./operation_journal.js";
|
|
12
13
|
export const DEFAULT_BASE_URL = "https://app.itpay.ai";
|
|
13
|
-
export const
|
|
14
|
+
export const DEV_BASE_URL = "https://dev.itpay.ai";
|
|
15
|
+
export const CLI_VERSION = "2.0.15";
|
|
14
16
|
export const API_CONTRACT_REVISION = "sha256:7f4c40b082292bf823631bcd37d452f4a8537153e30636d5eb3a2b24a77ce602";
|
|
15
17
|
const CART_SESSION_DEFAULT_DIR = ".itpay-v3";
|
|
16
18
|
const CART_SESSION_FILENAME = "cart.json";
|
|
17
19
|
const OPERATION_JOURNAL_FILENAME = "operations.json";
|
|
20
|
+
export class BackendOverrideError extends Error {
|
|
21
|
+
code = "backend_override_forbidden";
|
|
22
|
+
constructor() {
|
|
23
|
+
super(`ITPAY_BACKEND_URL only supports ${DEFAULT_BASE_URL} or ${DEV_BASE_URL}`);
|
|
24
|
+
this.name = "BackendOverrideError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function resolveBackendURL(env = process.env) {
|
|
28
|
+
const requested = env.ITPAY_BACKEND_URL?.trim();
|
|
29
|
+
if (!requested || requested === DEFAULT_BASE_URL || requested === `${DEFAULT_BASE_URL}/`)
|
|
30
|
+
return DEFAULT_BASE_URL;
|
|
31
|
+
if (requested === DEV_BASE_URL || requested === `${DEV_BASE_URL}/`)
|
|
32
|
+
return DEV_BASE_URL;
|
|
33
|
+
throw new BackendOverrideError();
|
|
34
|
+
}
|
|
35
|
+
export function qualifyBackendCommand(command, env = process.env) {
|
|
36
|
+
const requested = env.ITPAY_BACKEND_URL?.trim();
|
|
37
|
+
if (requested !== DEV_BASE_URL && requested !== `${DEV_BASE_URL}/`)
|
|
38
|
+
return command;
|
|
39
|
+
if (!command.startsWith("itpay ") || command.startsWith(`ITPAY_BACKEND_URL=${DEV_BASE_URL} `))
|
|
40
|
+
return command;
|
|
41
|
+
return `ITPAY_BACKEND_URL=${DEV_BASE_URL} ${command}`;
|
|
42
|
+
}
|
|
43
|
+
function stateFilename(filename, baseURL) {
|
|
44
|
+
if (baseURL !== DEV_BASE_URL)
|
|
45
|
+
return filename;
|
|
46
|
+
const dot = filename.lastIndexOf(".");
|
|
47
|
+
return dot < 0 ? `${filename}.dev` : `${filename.slice(0, dot)}.dev${filename.slice(dot)}`;
|
|
48
|
+
}
|
|
49
|
+
function stateDir(env) {
|
|
50
|
+
return resolve(env.HOME || homedir(), CART_SESSION_DEFAULT_DIR);
|
|
51
|
+
}
|
|
18
52
|
export function cartSessionPath(env = process.env) {
|
|
19
53
|
if (env.ITPAY_CART_SESSION_PATH) {
|
|
20
54
|
return resolve(env.ITPAY_CART_SESSION_PATH);
|
|
21
55
|
}
|
|
22
|
-
const dir =
|
|
56
|
+
const dir = stateDir(env);
|
|
23
57
|
mkdirSync(dir, { recursive: true });
|
|
24
|
-
return resolve(dir, CART_SESSION_FILENAME);
|
|
58
|
+
return resolve(dir, stateFilename(CART_SESSION_FILENAME, resolveBackendURL(env)));
|
|
25
59
|
}
|
|
26
60
|
export function loadConfig(env = process.env) {
|
|
27
|
-
const baseURL = env
|
|
61
|
+
const baseURL = resolveBackendURL(env);
|
|
28
62
|
const bearerToken = env.ITPAY_BEARER_TOKEN || undefined;
|
|
29
63
|
const agentType = declaredAgentType(env);
|
|
30
64
|
const checkoutCurrency = env.ITPAY_CURRENCY || "CNY";
|
|
@@ -33,10 +67,11 @@ export function loadConfig(env = process.env) {
|
|
|
33
67
|
const ideImageDirOverride = env.ITPAY_IDE_IMAGE_DIR_OVERRIDE;
|
|
34
68
|
return {
|
|
35
69
|
baseURL,
|
|
70
|
+
environment: baseURL === DEV_BASE_URL ? "development" : "production",
|
|
36
71
|
...(agentType ? { agentType } : {}),
|
|
37
72
|
checkoutCurrency,
|
|
38
73
|
idempotencyKey,
|
|
39
|
-
...(!env.ITPAY_IDEMPOTENCY_KEY ? { operationJournal: new OperationJournal(resolve(
|
|
74
|
+
...(!env.ITPAY_IDEMPOTENCY_KEY ? { operationJournal: new OperationJournal(resolve(stateDir(env), stateFilename(OPERATION_JOURNAL_FILENAME, baseURL))) } : {}),
|
|
40
75
|
ideImageAttach,
|
|
41
76
|
...(ideImageDirOverride ? { ideImageDirOverride } : {}),
|
|
42
77
|
...(bearerToken ? { bearerToken } : {}),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "itp.agent_doc.v1",
|
|
3
3
|
"role": "buyer",
|
|
4
|
+
"product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
|
|
4
5
|
"topic": "cart-checkout",
|
|
5
6
|
"title": "Canonical Cart And Checkout Routing",
|
|
6
7
|
"purpose": "Use the canonical server Cart and route service-backed lines through Service Execution without hardcoded service logic.",
|
|
@@ -43,8 +44,20 @@
|
|
|
43
44
|
"Do not treat QR display as payment verification."
|
|
44
45
|
],
|
|
45
46
|
"next_docs": [
|
|
46
|
-
{
|
|
47
|
-
|
|
47
|
+
{
|
|
48
|
+
"condition": "Checkout handoff is ready",
|
|
49
|
+
"topic": "payment-flow"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"condition": "Host rendering needs clarification",
|
|
53
|
+
"topic": "render-hosts"
|
|
54
|
+
}
|
|
48
55
|
],
|
|
49
|
-
"search_terms": [
|
|
56
|
+
"search_terms": [
|
|
57
|
+
"cart",
|
|
58
|
+
"checkout",
|
|
59
|
+
"service execution",
|
|
60
|
+
"resume",
|
|
61
|
+
"contact"
|
|
62
|
+
]
|
|
50
63
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "itp.agent_doc.v1",
|
|
3
3
|
"role": "buyer",
|
|
4
|
+
"product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
|
|
4
5
|
"topic": "catalog-list",
|
|
5
6
|
"title": "Browse ItPay V3 Service Catalog",
|
|
6
7
|
"purpose": "Teach the agent how to browse and display available catalog services to the buyer.",
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "itp.agent_doc.v1",
|
|
3
3
|
"role": "buyer",
|
|
4
|
+
"product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
|
|
4
5
|
"topic": "identity-and-sessions",
|
|
5
6
|
"title": "Device Identity And Session Recovery",
|
|
6
|
-
"purpose": "Explain stable local identity, Backend-scoped registrations, Agent Type instances, and bounded automatic session recovery.",
|
|
7
|
+
"purpose": "Explain stable local identity, official Backend-scoped registrations, Agent Type instances, and bounded automatic session recovery.",
|
|
7
8
|
"when_to_use": [
|
|
8
9
|
"A different Agent window or runtime starts using an existing CLI installation.",
|
|
9
10
|
"The CLI reports device_state_unwritable, or the Backend reports agent_identity_required, agent_device_session_required, or agent_device_revoked.",
|
|
10
|
-
"
|
|
11
|
+
"An operator confirms that the currently selected official Backend registration database was reset."
|
|
11
12
|
],
|
|
12
13
|
"identity_model": {
|
|
13
14
|
"local_key": "One owner-only Ed25519 private key for the local installation.",
|
|
14
|
-
"backend_registration": "One
|
|
15
|
+
"backend_registration": "One registration per official Backend: app.itpay.ai by default and dev.itpay.ai only with the exact test override.",
|
|
15
16
|
"agent_instance": "One instance per agent_type under each Backend registration; same-type windows and chats reuse it.",
|
|
16
17
|
"presentation": "Host and target route output only and never identify the Agent or provide business input."
|
|
17
18
|
},
|
|
@@ -29,36 +30,56 @@
|
|
|
29
30
|
"commands": [
|
|
30
31
|
{
|
|
31
32
|
"intent": "reload the complete rules",
|
|
32
|
-
"command": "itpay --agent-type <agent_type> skill show itpay
|
|
33
|
+
"command": "itpay --agent-type <agent_type> skill show itpay --json",
|
|
33
34
|
"success_signal": "the full Skill is returned and next keeps the same Agent Type"
|
|
34
35
|
},
|
|
35
36
|
{
|
|
36
|
-
"intent": "confirm the selected Backend is available",
|
|
37
|
+
"intent": "confirm the selected official Backend is available",
|
|
37
38
|
"command": "itpay --agent-type <agent_type> readyz --json",
|
|
38
39
|
"success_signal": "Backend is available and onboarding returns to the Skill"
|
|
39
40
|
},
|
|
40
41
|
{
|
|
41
|
-
"intent": "recover after an operator-confirmed reset of the selected Backend registration database",
|
|
42
|
+
"intent": "recover after an operator-confirmed reset of the selected official Backend registration database",
|
|
42
43
|
"command": "itpay --agent-type <agent_type> device recover --confirm-backend-reset --json",
|
|
43
|
-
"success_signal": "only the selected Backend registration is removed
|
|
44
|
+
"success_signal": "only the selected Backend registration is removed and the private key and other Backend registration remain"
|
|
44
45
|
}
|
|
45
46
|
],
|
|
46
47
|
"agent_rules": [
|
|
47
48
|
"Use the real runtime type and keep it stable across every command in the flow.",
|
|
48
49
|
"Keep the same CLI/Node launcher and Host-approved permission context for the whole flow.",
|
|
49
50
|
"Treat a new window, chat, task, or process of the same runtime as the same Agent Type, not a new identity.",
|
|
50
|
-
"Expect
|
|
51
|
-
"After automatic recovery fails, stop and report the exact code, Backend
|
|
51
|
+
"Expect production traffic to use https://app.itpay.ai. Use https://dev.itpay.ai only for an explicit test and keep the complete returned Backend-prefixed command for that entire flow.",
|
|
52
|
+
"After automatic recovery fails, stop and report the exact code, selected official Backend, Agent Type, and command family without exposing private keys or tokens."
|
|
52
53
|
],
|
|
53
54
|
"forbidden": [
|
|
54
55
|
"Do not delete ~/.itpay-v3, rotate the key, switch Agent Type, or repeatedly retry to obtain fresh quota.",
|
|
55
56
|
"Do not use device recover for session expiry, revocation, quota recovery, or an unconfirmed Backend failure.",
|
|
56
|
-
"Do not
|
|
57
|
+
"Do not redirect the CLI to test, local, an IP, or any custom Backend; only the exact official dev.itpay.ai test override is allowed.",
|
|
57
58
|
"Do not use --target as identity or service input."
|
|
58
59
|
],
|
|
59
60
|
"next_docs": [
|
|
60
|
-
{
|
|
61
|
-
|
|
61
|
+
{
|
|
62
|
+
"condition": "Identity is healthy",
|
|
63
|
+
"topic": "quickstart"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"condition": "Need setup details",
|
|
67
|
+
"topic": "install-and-setup"
|
|
68
|
+
}
|
|
62
69
|
],
|
|
63
|
-
"search_terms": [
|
|
70
|
+
"search_terms": [
|
|
71
|
+
"identity",
|
|
72
|
+
"device",
|
|
73
|
+
"session",
|
|
74
|
+
"login",
|
|
75
|
+
"authentication",
|
|
76
|
+
"agent type",
|
|
77
|
+
"backend",
|
|
78
|
+
"revoked",
|
|
79
|
+
"recover",
|
|
80
|
+
"unwritable",
|
|
81
|
+
"lock",
|
|
82
|
+
"window",
|
|
83
|
+
"chat"
|
|
84
|
+
]
|
|
64
85
|
}
|