@itpay/cli 0.2.16 → 2.0.0-rc.1

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.
Files changed (69) hide show
  1. package/README.md +148 -447
  2. package/bin/itp +1 -150
  3. package/dist/src/client/backend.js +154 -0
  4. package/dist/src/client/http.js +76 -0
  5. package/dist/src/client/types.js +4 -0
  6. package/dist/src/commands/buy.js +351 -0
  7. package/dist/src/commands/cart.js +264 -0
  8. package/dist/src/commands/catalog.js +26 -0
  9. package/dist/src/commands/checkout.js +106 -0
  10. package/dist/src/commands/docs.js +61 -0
  11. package/dist/src/commands/guidance.js +422 -0
  12. package/dist/src/commands/install.js +95 -0
  13. package/dist/src/commands/order.js +78 -0
  14. package/dist/src/commands/orders.js +22 -0
  15. package/dist/src/commands/pay.js +26 -0
  16. package/dist/src/commands/readyz.js +8 -0
  17. package/dist/src/commands/refund.js +20 -0
  18. package/dist/src/commands/services.js +317 -0
  19. package/dist/src/main.js +606 -0
  20. package/dist/src/render/feishu.js +201 -0
  21. package/dist/src/render/ide.js +321 -0
  22. package/dist/src/render/index.js +57 -0
  23. package/dist/src/render/interaction.js +49 -0
  24. package/dist/src/render/markdown.js +83 -0
  25. package/dist/src/render/output.js +42 -0
  26. package/dist/src/render/plain_chat.js +60 -0
  27. package/dist/src/render/plan.js +31 -0
  28. package/dist/src/render/qr.js +32 -0
  29. package/dist/src/render/sink.js +6 -0
  30. package/dist/src/render/status.js +37 -0
  31. package/dist/src/render/telegram.js +172 -0
  32. package/dist/src/render/terminal.js +148 -0
  33. package/dist/src/render/terminal_image.js +19 -0
  34. package/dist/src/state/cart_session.js +151 -0
  35. package/dist/src/state/client_context.js +73 -0
  36. package/dist/src/state/config.js +82 -0
  37. package/dist/src/state/device_authority.js +217 -0
  38. package/dist/src/state/operation_journal.js +80 -0
  39. package/docs/agent/buyer/cart-checkout.json +56 -94
  40. package/docs/agent/buyer/catalog-list.json +47 -0
  41. package/docs/agent/buyer/install-and-setup.json +82 -0
  42. package/docs/agent/buyer/orders-refunds.json +76 -0
  43. package/docs/agent/buyer/payment-flow.json +77 -0
  44. package/docs/agent/buyer/quickstart.json +143 -75
  45. package/docs/agent/buyer/render-hosts.json +79 -0
  46. package/package.json +32 -13
  47. package/skills/itpay-buyer/SKILL.md +107 -238
  48. package/docs/agent/buyer/account-portal.json +0 -81
  49. package/docs/agent/buyer/catalog-search.json +0 -106
  50. package/docs/agent/buyer/human-claim-ui.json +0 -77
  51. package/docs/agent/buyer/payment-qr.json +0 -97
  52. package/docs/agent/buyer/payment-wait.json +0 -84
  53. package/docs/agent/buyer/product-recommendation.json +0 -80
  54. package/docs/agent/buyer/qr-refresh.json +0 -67
  55. package/docs/agent/buyer/recovery.json +0 -85
  56. package/docs/agent/buyer/safety-policy.json +0 -70
  57. package/docs/agent/buyer/secure-delivery.json +0 -90
  58. package/docs/agent/buyer/vault-agent-read.json +0 -95
  59. package/install.ps1 +0 -65
  60. package/install.sh +0 -66
  61. package/lib/account-status.js +0 -157
  62. package/lib/buyer.js +0 -2332
  63. package/lib/client-context.js +0 -126
  64. package/lib/docs.js +0 -200
  65. package/lib/env.js +0 -723
  66. package/lib/http.js +0 -151
  67. package/lib/ops.js +0 -135
  68. package/lib/render-human.js +0 -718
  69. package/lib/runtime.js +0 -1456
package/bin/itp CHANGED
@@ -1,152 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { output, outputError, parseFlags, readState, VERSION } from "../lib/env.js";
4
- import { docs, skill } from "../lib/docs.js";
5
- import { ops, admin } from "../lib/ops.js";
6
- import { buyer, buyerBuy } from "../lib/buyer.js";
7
- import { clientContextGate } from "../lib/client-context.js";
8
- import {
9
- accountLoginLink, accountSetPassword, accountShow, agentStatus, authDevice, authLogin, authRegister, authStatus, balance,
10
- checkoutCreate, checkoutList, checkoutOpen, checkoutQR, checkoutRecover, doctor, grantsInstall, grantsList, grantsRevoke,
11
- grantsShow, installRuntime, keys, paymentWait, plansList, plansShow, resume, runs, setup, sync, token, usage
12
- } from "../lib/runtime.js";
13
-
14
- main().catch((error) => {
15
- outputError(error);
16
- process.exit(1);
17
- });
18
-
19
- async function main() {
20
- const args = process.argv.slice(2);
21
- if ((args.length === 1 && args[0] === "--version") || args[0] === "version") {
22
- output({ version: VERSION });
23
- return;
24
- }
25
-
26
- const [group, command, ...rest] = args;
27
- const contextGate = clientContextGate(args);
28
- if (contextGate) {
29
- output(contextGate);
30
- return;
31
- }
32
- const flags = parseFlags(rest);
33
-
34
- if (group === "usage") return usage(parseFlags(args.slice(1)));
35
- if (group === "balance") return balance(parseFlags(args.slice(1)));
36
- if (group === "plans" && (!command || String(command).startsWith("--"))) return plansList(parseFlags(args.slice(1)));
37
- if (group === "setup") return setup(parseFlags(args.slice(1)));
38
- if (group === "buy") {
39
- const buyFlags = parseFlags(command && String(command).startsWith("--") ? args.slice(1) : rest);
40
- if (command && !String(command).startsWith("--")) buyFlags.selection = command;
41
- return buyerBuy(buyFlags);
42
- }
43
- if (group === "buyer") return buyer(command, rest, parseFlags(rest));
44
- if (group === "ops") return ops(command, rest, parseFlags(rest));
45
- if (group === "docs") {
46
- const docsCommand = command && !String(command).startsWith("--") ? command : "list";
47
- const docsFlags = parseFlags(command && String(command).startsWith("--") ? args.slice(1) : rest);
48
- return docs(docsCommand, command && String(command).startsWith("--") ? [] : rest, docsFlags);
49
- }
50
- if (group === "status") return agentStatus(parseFlags(args.slice(1)));
51
- if (group === "resume") return resume(parseFlags(args.slice(1)));
52
- if (group === "runs") {
53
- const runCommand = command && !String(command).startsWith("--") ? command : "current";
54
- const runFlags = parseFlags(command && String(command).startsWith("--") ? args.slice(1) : rest);
55
- if (rest[0] && !String(rest[0]).startsWith("--")) runFlags.run_id = rest[0];
56
- return runs(runCommand, runFlags);
57
- }
58
- if (group === "doctor") return doctor(parseFlags(args.slice(1)));
59
- if (group === "skill") {
60
- const skillCommand = command && !String(command).startsWith("--") ? command : "show";
61
- const skillFlags = parseFlags(command && String(command).startsWith("--") ? args.slice(1) : rest);
62
- return skill(skillCommand, skillFlags);
63
- }
64
- if (group === "keys") return keys(command, parseFlags(rest));
65
- if (group === "token") return token(command, parseFlags(rest));
66
- if (group === "sync") return sync(parseFlags(args.slice(1)));
67
- if (group === "admin") return admin(command, rest, parseFlags(rest));
68
- if (group === "auth" && command === "device") {
69
- const deviceFlags = parseFlags(rest.slice(1));
70
- if (rest[0] === "poll" && rest[1] && !String(rest[1]).startsWith("--")) deviceFlags.auth_id = rest[1];
71
- return authDevice(rest[0], deviceFlags);
72
- }
73
-
74
- switch ([group || "", command || ""].join(" ").trim()) {
75
- case "auth register": return authRegister(flags);
76
- case "auth login": return authLogin(flags);
77
- case "auth status": return authStatus(flags);
78
- case "account show": return accountShow(flags);
79
- case "account login-link": return accountLoginLink(flags);
80
- case "account set-password": return accountSetPassword(flags);
81
- case "plans list": return plansList(flags);
82
- case "plans show": return plansShow(rest[0], flags);
83
- case "checkout create": return checkoutCreate(flags);
84
- case "checkout recover": return checkoutRecover(rest[0] || readState().last_checkout_id, flags);
85
- case "checkout open": return checkoutOpen(flags);
86
- case "checkout qr": return checkoutQR(rest[0] || readState().last_checkout_id, flags);
87
- case "checkout list": return checkoutList(flags);
88
- case "payment wait": return paymentWait(rest[0] || readState().last_checkout_id, flags);
89
- case "balance": return balance(flags);
90
- case "grants list": return grantsList(flags);
91
- case "grants show": return grantsShow(rest[0], flags);
92
- case "grants install": return grantsInstall(rest[0], flags);
93
- case "grants revoke": return grantsRevoke(rest[0], flags);
94
- case "install claude-code":
95
- case "install codex":
96
- case "install openclaw": return installRuntime(command, flags);
97
- case "doctor": return doctor(flags);
98
- default:
99
- output({
100
- version: VERSION,
101
- commands: [
102
- "buy var_pubg_couple_skin_cny20 --email <buyer_email> --phone +8613800000000 --display agent --no-wait-payment --host <client> --json",
103
- "buy var_pubg_couple_skin_cny20 --email <buyer_email> --phone +8613800000000 --no-wait --host <client> --json",
104
- "buyer catalog search --query 企业工商 --category business_data_api --provider itpay_enterprise_data --host <client> --json",
105
- "buyer catalog get --variant var_pubg_couple_skin_cny20 --host <client> --json",
106
- "buyer cart create --variant var_pubg_couple_skin_cny20 --host <client> --json",
107
- "buyer cart create --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=京东 --host <client> --json",
108
- "buyer cart show <cart_id> --host <client> --json",
109
- "buyer cart add <cart_id> --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=美团 --quantity 1 --host <client> --json",
110
- "buyer cart remove <cart_id> --line <cart_line_item_id> --host <client> --json",
111
- "buyer shelf manifest --host <client> --json",
112
- "buyer shelf snapshot --version <catalog_version> --host <client> --json",
113
- "buyer shelf delta --since <catalog_version> --host <client> --json",
114
- "buyer checkout create --cart <cart_id> --method alipay --email <buyer_email> --phone +8613800000000 --host <client> --json",
115
- "buyer checkout status <checkout_id> --host <client> --json",
116
- "buyer checkout resume <checkout_id> --host <client> --json",
117
- "buyer auth status --host <client> --json",
118
- "buyer payment wait <payment_intent_id> --timeout 1 --host <client> --json",
119
- "buyer payment refresh-qr <payment_intent_id> --reason order-not-found --host <client> --json",
120
- "buyer deliveries list --checkout <checkout_id> --host <client> --json",
121
- "buyer deliveries show <delivery_id> --checkout <checkout_id> --host <client> --json",
122
- "buyer refund create --order <order_id> --amount-minor 1000 --currency CNY --reason buyer_requested --host <client> --json",
123
- "buyer refund list --order <order_id> --host <client> --json",
124
- "buyer refund show <refund_id> --host <client> --json",
125
- "buyer refund cancel <refund_id> --reason buyer_changed_mind --host <client> --json",
126
- "buyer vault grants list --checkout <checkout_id> --host <client> --json",
127
- "buyer vault grants read <agent_read_grant_id> --host <client> --json",
128
- "buyer vault read --order <order_id> --artifact <vault_artifact_id> --host <client> --json",
129
- "account login-link --host <client> --json",
130
- "status --host <client> --json",
131
- "status --refresh --host <client> --json",
132
- "docs list --role buyer --json",
133
- "docs show quickstart --role buyer --json",
134
- "docs search <question> --role buyer --json",
135
- "resume --host <client> --json",
136
- "resume --run-id <run_id> --host codex --display none --json",
137
- "runs list|current|show <run_id>|forget <run_id>",
138
- "account login-link",
139
- "skill show",
140
- "skill show --role buyer --json",
141
- "skill path --role buyer",
142
- "admin orders --access-token <root_token> --new-api-user <id>",
143
- "admin payment-events --access-token <root_token> --new-api-user <id>",
144
- "admin outbox --access-token <root_token> --new-api-user <id>",
145
- "admin process-outbox --access-token <root_token> --new-api-user <id>",
146
- "admin recover-order <order_id> --access-token <root_token> --new-api-user <id>",
147
- "install claude-code|codex|openclaw --grant <grant_id> [--offline|--no-test]",
148
- "doctor"
149
- ]
150
- });
151
- }
152
- }
3
+ import "../dist/src/main.js";
@@ -0,0 +1,154 @@
1
+ // V3 endpoint wrappers. One function per route family; one file per domain.
2
+ // Keep parameter shapes aligned with the typed request DTOs in ./types.ts.
3
+ export class BackendClient {
4
+ http;
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ readyz() {
9
+ return this.http.get("/v1/readyz");
10
+ }
11
+ compatibility() {
12
+ return this.http.get("/v1/platform/compatibility");
13
+ }
14
+ // --- Catalog ---
15
+ getCatalogManifest() {
16
+ return this.http.get("/v1/catalog/manifest");
17
+ }
18
+ // --- Cart ---
19
+ createCart(input) {
20
+ return this.http.post("/v1/carts", input);
21
+ }
22
+ getCart(cartID) {
23
+ return this.http.get(`/v1/carts/${encodeURIComponent(cartID)}`);
24
+ }
25
+ addCartItem(cartID, input) {
26
+ return this.http.post(`/v1/carts/${encodeURIComponent(cartID)}/items`, input);
27
+ }
28
+ removeCartItem(cartID, cartItemID) {
29
+ return this.http.delete(`/v1/carts/${encodeURIComponent(cartID)}/items/${encodeURIComponent(cartItemID)}`);
30
+ }
31
+ abandonCart(cartID) {
32
+ return this.http.delete(`/v1/carts/${encodeURIComponent(cartID)}`);
33
+ }
34
+ // --- Checkout ---
35
+ createCheckout(input) {
36
+ return this.http.post("/v1/checkouts", input);
37
+ }
38
+ getCheckoutPresentation(checkoutID, displayToken) {
39
+ const qs = new URLSearchParams({ display_token: displayToken });
40
+ return this.http.get(`/v1/checkouts/${encodeURIComponent(checkoutID)}/presentation?${qs}`);
41
+ }
42
+ // --- Payment intents ---
43
+ createPaymentIntent(checkoutID, input, idempotencyKey) {
44
+ const options = idempotencyKey ? { idempotencyKey } : {};
45
+ return this.http.post(`/v1/checkouts/${encodeURIComponent(checkoutID)}/payment-intents`, input, options);
46
+ }
47
+ // --- SSE streaming ---
48
+ streamCheckoutEvents(checkoutID, displayToken, onEvent, signal) {
49
+ const qs = new URLSearchParams({ display_token: displayToken });
50
+ const url = `${this.http.baseURL}/v1/checkouts/${encodeURIComponent(checkoutID)}/events?${qs}`;
51
+ return streamSSE(url, onEvent, signal);
52
+ }
53
+ // --- Orders ---
54
+ getOrder(orderID) {
55
+ return this.http.get(`/v1/orders/${encodeURIComponent(orderID)}`);
56
+ }
57
+ listAccountOrders(limit, status, bearer) {
58
+ const qs = new URLSearchParams({ limit: String(limit) });
59
+ if (status) {
60
+ qs.set("status", status);
61
+ }
62
+ return this.http.get(`/v1/me/orders?${qs}`, bearer ? { bearer } : {});
63
+ }
64
+ // --- Refund ---
65
+ createRefund(orderID, input, idempotencyKey) {
66
+ const options = idempotencyKey ? { idempotencyKey } : {};
67
+ return this.http.post(`/v1/orders/${encodeURIComponent(orderID)}/refunds`, input, options);
68
+ }
69
+ // --- Service Execution ---
70
+ startServiceExecution(input) {
71
+ return this.http.post("/v1/service-executions", input);
72
+ }
73
+ invokeServiceCapability(serviceExecutionID, capabilityID, input) {
74
+ return this.http.post(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/capabilities/${encodeURIComponent(capabilityID)}/invoke`, input);
75
+ }
76
+ recordServiceExecutionAction(serviceExecutionID, input) {
77
+ return this.http.post(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/actions`, input);
78
+ }
79
+ createServiceExecutionCheckout(serviceExecutionID, input) {
80
+ return this.http.post(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/checkout`, input);
81
+ }
82
+ getServiceExecution(serviceExecutionID) {
83
+ return this.http.get(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}`);
84
+ }
85
+ listServiceExecutions(limit = 50) {
86
+ return this.http.get(`/v1/service-executions?limit=${limit}`);
87
+ }
88
+ listServiceExecutionEvents(serviceExecutionID) {
89
+ return this.http.get(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/events`);
90
+ }
91
+ getGrantedServiceResult(serviceExecutionID) {
92
+ return this.http.get(`/v1/service-executions/${encodeURIComponent(serviceExecutionID)}/granted-result`);
93
+ }
94
+ }
95
+ // --- SSE streaming helper ---
96
+ async function streamSSE(url, onEvent, signal) {
97
+ const response = await fetch(url, {
98
+ headers: { Accept: "text/event-stream" },
99
+ signal,
100
+ });
101
+ if (!response.ok) {
102
+ const text = await response.text();
103
+ let msg = `SSE stream failed: HTTP ${response.status}`;
104
+ try {
105
+ const parsed = JSON.parse(text);
106
+ msg = parsed.message || parsed.code || msg;
107
+ }
108
+ catch { }
109
+ throw new Error(msg);
110
+ }
111
+ if (!response.body) {
112
+ throw new Error("SSE stream: no response body");
113
+ }
114
+ const reader = response.body.getReader();
115
+ const decoder = new TextDecoder();
116
+ let buffer = "";
117
+ try {
118
+ while (true) {
119
+ const { done, value } = await reader.read();
120
+ if (done)
121
+ break;
122
+ buffer += decoder.decode(value, { stream: true });
123
+ const lines = buffer.split("\n");
124
+ buffer = lines.pop() || "";
125
+ let currentEvent = {};
126
+ for (const line of lines) {
127
+ if (line === "") {
128
+ if (currentEvent.type && currentEvent.payload) {
129
+ onEvent(currentEvent);
130
+ }
131
+ currentEvent = {};
132
+ continue;
133
+ }
134
+ if (line.startsWith("event: ")) {
135
+ currentEvent.type = line.slice(7);
136
+ }
137
+ else if (line.startsWith("data: ")) {
138
+ try {
139
+ const data = JSON.parse(line.slice(6));
140
+ currentEvent.type = currentEvent.type || data.event_type;
141
+ currentEvent.aggregateType = data.aggregate_type;
142
+ currentEvent.aggregateId = data.aggregate_id;
143
+ currentEvent.sequence = data.sequence;
144
+ currentEvent.payload = data;
145
+ }
146
+ catch { }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ finally {
152
+ reader.releaseLock();
153
+ }
154
+ }
@@ -0,0 +1,76 @@
1
+ // Thin HTTP client for V3 backend. Keep this file boring on purpose:
2
+ // no retries, no SDK abstractions, no business logic. Higher layers
3
+ // own semantics (e.g. CLI commands, frontend feature hooks).
4
+ export class HttpError extends Error {
5
+ status;
6
+ code;
7
+ payload;
8
+ constructor(status, payload, fallbackMessage) {
9
+ super(payload?.message || fallbackMessage);
10
+ this.status = status;
11
+ this.code = payload?.code || "unknown_error";
12
+ this.payload = payload;
13
+ }
14
+ }
15
+ export class HttpClient {
16
+ baseURL;
17
+ fetchImpl;
18
+ defaultHeaders;
19
+ requestAuthorizer;
20
+ constructor(config) {
21
+ this.baseURL = config.baseURL.replace(/\/$/, "");
22
+ this.fetchImpl = config.fetchImpl ?? globalThis.fetch;
23
+ this.defaultHeaders = {
24
+ "Content-Type": "application/json",
25
+ Accept: "application/json",
26
+ ...(config.defaultHeaders ?? {}),
27
+ };
28
+ this.requestAuthorizer = config.requestAuthorizer;
29
+ }
30
+ async request(path, options = {}) {
31
+ const url = path.startsWith("http") ? path : this.baseURL + path;
32
+ const headers = { ...this.defaultHeaders };
33
+ const method = options.method ?? "GET";
34
+ const body = options.body !== undefined ? JSON.stringify(options.body) : "";
35
+ if (this.requestAuthorizer) {
36
+ Object.assign(headers, await this.requestAuthorizer({ method, path: new URL(url).pathname + new URL(url).search, body }));
37
+ }
38
+ if (options.bearer) {
39
+ headers.Authorization = `Bearer ${options.bearer}`;
40
+ }
41
+ if (options.idempotencyKey) {
42
+ headers["Idempotency-Key"] = options.idempotencyKey;
43
+ }
44
+ const requestInit = {
45
+ method,
46
+ headers,
47
+ ...(options.body !== undefined ? { body } : {}),
48
+ ...(options.signal ? { signal: options.signal } : {}),
49
+ };
50
+ const response = await this.fetchImpl(url, requestInit);
51
+ const text = await response.text();
52
+ const parsed = text.length > 0 ? safeParseJson(text) : undefined;
53
+ if (!response.ok) {
54
+ const errPayload = parsed;
55
+ throw new HttpError(response.status, errPayload, `HTTP ${response.status}`);
56
+ }
57
+ return parsed;
58
+ }
59
+ get(path, options = {}) {
60
+ return this.request(path, { ...options, method: "GET" });
61
+ }
62
+ post(path, body, options = {}) {
63
+ return this.request(path, { ...options, method: "POST", body });
64
+ }
65
+ delete(path, options = {}) {
66
+ return this.request(path, { ...options, method: "DELETE" });
67
+ }
68
+ }
69
+ function safeParseJson(text) {
70
+ try {
71
+ return JSON.parse(text);
72
+ }
73
+ catch {
74
+ return undefined;
75
+ }
76
+ }
@@ -0,0 +1,4 @@
1
+ // V3 API DTO types — keep in sync with services/backend/internal/presenter/*.go
2
+ // Only fields the CLI needs to read. Adding optional fields is fine; removing
3
+ // fields must be coordinated with the backend.
4
+ export {};