@itpay/cli 2.1.33 → 2.1.40

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 (75) hide show
  1. package/dist/src/client/backend.js +5 -0
  2. package/dist/src/commands/aftercare.js +12 -0
  3. package/dist/src/commands/buy.js +12 -56
  4. package/dist/src/commands/cart.js +2 -0
  5. package/dist/src/commands/catalog.js +24 -9
  6. package/dist/src/commands/checkout_handoff.js +11 -99
  7. package/dist/src/commands/guidance.js +1 -184
  8. package/dist/src/commands/install.js +2 -1
  9. package/dist/src/commands/order.js +20 -2
  10. package/dist/src/commands/rail_catalog.js +1 -261
  11. package/dist/src/commands/readyz.js +2 -2
  12. package/dist/src/commands/refund.js +10 -54
  13. package/dist/src/commands/services/actions.js +133 -0
  14. package/dist/src/commands/services/commerce.js +197 -0
  15. package/dist/src/commands/services/lifecycle.js +418 -0
  16. package/dist/src/commands/services/results.js +130 -0
  17. package/dist/src/commands/services.js +14 -2584
  18. package/dist/src/commands/skill.js +3 -0
  19. package/dist/src/main.js +82 -31
  20. package/dist/src/render/checkout_handoff.js +101 -0
  21. package/dist/src/render/checkout_plan.js +47 -0
  22. package/dist/src/services/adapter.js +1 -0
  23. package/dist/src/services/presentation.js +198 -0
  24. package/dist/src/services/rail/actions.js +51 -0
  25. package/dist/src/services/rail/adapter.js +27 -0
  26. package/dist/src/services/rail/aftercare.js +45 -0
  27. package/dist/src/services/rail/catalog.js +261 -0
  28. package/dist/src/services/rail/checkout.js +19 -0
  29. package/dist/src/services/rail/fulfillment.js +76 -0
  30. package/dist/src/services/rail/guide.js +110 -0
  31. package/dist/src/services/rail/invocation.js +54 -0
  32. package/dist/src/services/rail/page.js +76 -0
  33. package/dist/src/services/rail/pagination.js +6 -0
  34. package/dist/src/services/rail/query.js +71 -0
  35. package/dist/src/services/rail/readers.js +107 -0
  36. package/dist/src/services/rail/reading.js +125 -0
  37. package/dist/src/services/rail/recovery.js +51 -0
  38. package/dist/src/services/rail/results.js +378 -0
  39. package/dist/src/services/rail/review.js +268 -0
  40. package/dist/src/services/rail/saved.js +49 -0
  41. package/dist/src/services/rail/wait.js +11 -0
  42. package/dist/src/services/registry.js +31 -0
  43. package/dist/src/services/schema.js +21 -0
  44. package/dist/src/services/shared/envelope.js +184 -0
  45. package/dist/src/services/shared/input.js +39 -0
  46. package/dist/src/services/shared/pagination.js +28 -0
  47. package/dist/src/services/shared/platform.js +365 -0
  48. package/dist/src/services/shared/refund.js +40 -0
  49. package/dist/src/services/shared/workflow.js +28 -0
  50. package/dist/src/state/account_auth.js +25 -10
  51. package/dist/src/state/config.js +2 -2
  52. package/dist/src/state/device_authority.js +5 -3
  53. package/docs/agent/buyer/cart-checkout.json +2 -1
  54. package/docs/agent/buyer/catalog-list.json +6 -4
  55. package/docs/agent/buyer/identity-and-sessions.json +3 -2
  56. package/docs/agent/buyer/install-and-setup.json +8 -3
  57. package/docs/agent/buyer/orders-refunds.json +14 -5
  58. package/docs/agent/buyer/payment-flow.json +2 -1
  59. package/docs/agent/buyer/quickstart.json +3 -2
  60. package/docs/agent/buyer/rail-booking.json +41 -27
  61. package/docs/agent/buyer/render-hosts.json +1 -1
  62. package/docs/agent/buyer/service-feedback.json +2 -2
  63. package/docs/cli-reference/commands/aftercare.md +15 -0
  64. package/docs/cli-reference/commands/cart/add.md +4 -0
  65. package/docs/cli-reference/commands/cart/next.md +4 -0
  66. package/docs/cli-reference/commands/readyz.md +2 -50
  67. package/docs/cli-reference/commands/services/checkout.md +4 -0
  68. package/docs/cli-reference/commands/services/next.md +8 -35
  69. package/docs/cli-reference/commands/services/quote.md +1 -1
  70. package/docs/cli-reference/commands/services/run.md +8 -12
  71. package/docs/cli-reference/commands/services/start.md +3 -1
  72. package/docs/cli-reference/conventions.md +1 -1
  73. package/docs/cli-reference/index.md +2 -0
  74. package/package.json +4 -3
  75. package/skills/itpay/SKILL.md +53 -19
@@ -0,0 +1,130 @@
1
+ import { serviceAdapter } from "../../services/registry.js";
2
+ import { CommandContractError, writeCommandEnvelope, plainValueLines } from "../../services/shared/envelope.js";
3
+ import { grantedResultEnvelope, servicesNextPlainResult } from "../../services/shared/platform.js";
4
+ import { runServicesNext } from "./lifecycle.js";
5
+ export async function runServicesPage(backend, serviceExecutionID, resultItemID, options = {}) {
6
+ const offset = options.offset ?? 0;
7
+ const limit = options.limit ?? 20;
8
+ if (!Number.isInteger(offset) || offset < 0) {
9
+ throw new CommandContractError("offset_invalid", "--offset must be a non-negative integer", "offset 必须是非负整数;本次未读取服务端分页。", [{ command: `itpay services page ${serviceExecutionID} ${resultItemID} --json`, reason: "从第一页重新读取" }]);
10
+ }
11
+ if (!Number.isInteger(limit) || limit < 1 || limit > 20) {
12
+ throw new CommandContractError("limit_invalid", "--limit must be an integer from 1 to 20", "limit 必须是 1 到 20 的整数;本次未读取服务端分页。", [{ command: `itpay services page ${serviceExecutionID} ${resultItemID} --offset ${offset} --json`, reason: "用默认页大小重试" }]);
13
+ }
14
+ const response = await backend.getServiceExecutionResultItemPage(serviceExecutionID, resultItemID, offset, limit, limit === 1 ? undefined : "summary");
15
+ const execution = response.service_id && response.service_contract_version_id
16
+ ? { service_id: response.service_id, service_contract_version_id: response.service_contract_version_id, ...(response.public_binding ? { public_binding: response.public_binding } : {}) }
17
+ : (await backend.getServiceExecution(serviceExecutionID)).execution;
18
+ const adapter = serviceAdapter(execution);
19
+ if (adapter.renderPage(response, serviceExecutionID, resultItemID, offset, limit, options))
20
+ return;
21
+ const envelope = { status: !adapter.supported ? "presentation_contract_unavailable" : "result_page", result: { service_execution_id: serviceExecutionID, page: response.page }, instruction: !adapter.supported ? "当前锁定合同不受支持;保留已有结果并停止,使用兼容CLI读取同一执行。" : "这是同一已保存结果的分页;直接读取事实,不重查。", next: null, recovery: [] };
22
+ writeCommandEnvelope(envelope, { ...options, plainResult: plainValueLines(envelope.result) });
23
+ }
24
+ export async function runServicesList(backend, options = {}) {
25
+ const limit = options.limit ?? 10;
26
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
27
+ throw new CommandContractError("limit_invalid", "--limit must be an integer from 1 to 100", "使用 1 到 100 的整数 limit;本次未读取服务端列表。", [{ command: "itpay services list --limit 10 --json", reason: "使用默认上限重试" }]);
28
+ }
29
+ const response = await backend.listServiceExecutions(limit);
30
+ const executions = response.executions.map(({ execution }) => ({
31
+ service_execution_id: execution.service_execution_id,
32
+ service_id: execution.service_id,
33
+ status: execution.status,
34
+ phase: execution.phase,
35
+ updated_at: execution.updated_at,
36
+ reader: { command: `itpay services next ${execution.service_execution_id} --json`, reason: "读取这笔已有服务" },
37
+ }));
38
+ const latest = executions[0];
39
+ const envelope = {
40
+ status: latest ? "listed" : "no_executions",
41
+ result: { executions },
42
+ instruction: executions.length === 1
43
+ ? "只有一条可恢复记录;继续读取同一笔服务。"
44
+ : latest
45
+ ? "按原任务中已明确的执行ID读取对应reader;只有无法确定属于哪一笔任务时才询问用户。"
46
+ : "当前设备没有可恢复的 Service Execution;先读取已发布目录,不要猜测 ID。",
47
+ next: executions.length === 1
48
+ ? { command: `itpay services next ${latest.service_execution_id} --json`, reason: "继续唯一可恢复的服务" }
49
+ : latest
50
+ ? null
51
+ : { command: "itpay catalog list --json", reason: "选择已发布服务" },
52
+ recovery: [],
53
+ };
54
+ writeCommandEnvelope(envelope, {
55
+ ...(options.jsonOutput !== undefined ? { jsonOutput: options.jsonOutput } : {}),
56
+ ...(options.output ? { output: options.output } : {}),
57
+ });
58
+ }
59
+ export async function runServicesReadResult(backend, serviceExecutionID, options = {}) {
60
+ const model = await backend.getServiceExecution(serviceExecutionID);
61
+ const outcome = await serviceAdapter(model.execution).readResult(backend, model, serviceExecutionID, options);
62
+ if (outcome === "handled")
63
+ return;
64
+ if (outcome === "state") {
65
+ await runServicesNext(backend, serviceExecutionID, options);
66
+ return;
67
+ }
68
+ const response = await backend.getGrantedServiceResult(serviceExecutionID);
69
+ let orderID;
70
+ try {
71
+ const model = await backend.getServiceExecution(serviceExecutionID);
72
+ orderID = (model.current_delivery ?? model.delivery_bindings.at(-1))?.order_id;
73
+ }
74
+ catch {
75
+ // Feedback context is optional and must never block an authorized result.
76
+ }
77
+ const envelope = grantedResultEnvelope(response, orderID);
78
+ writeCommandEnvelope(envelope, {
79
+ ...(options.jsonOutput !== undefined ? { jsonOutput: options.jsonOutput } : {}),
80
+ ...(options.output ? { output: options.output } : {}),
81
+ plainResult: servicesNextPlainResult(envelope.result),
82
+ });
83
+ }
84
+ export async function runServicesEvents(backend, serviceExecutionID, options = {}) {
85
+ const afterSequence = options.afterSequence ?? 0;
86
+ const limit = options.limit ?? 50;
87
+ if (!serviceExecutionID.trim()) {
88
+ throw new CommandContractError("service_execution_id_required", "service execution id is required", "使用 services list 返回的 execution ID;不要猜测。", [{ command: "itpay services list --json", reason: "列出当前身份可见执行" }]);
89
+ }
90
+ if (!Number.isSafeInteger(afterSequence) || afterSequence < 0) {
91
+ throw new CommandContractError("events_parameter_invalid", "after_sequence must be a non-negative integer", "--after-sequence 必须是非负整数;本次未读取事件。", [{ command: `itpay services events ${serviceExecutionID} --help`, reason: "查看诊断参数" }]);
92
+ }
93
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) {
94
+ throw new CommandContractError("events_parameter_invalid", "limit must be an integer between 1 and 100", "--limit 必须是 1 到 100 的整数;本次未读取事件。", [{ command: `itpay services events ${serviceExecutionID} --help`, reason: "查看诊断参数" }]);
95
+ }
96
+ const response = await backend.listServiceExecutionEvents(serviceExecutionID, afterSequence, limit);
97
+ const events = response.events.map((event) => ({
98
+ sequence: event.sequence,
99
+ type: event.type,
100
+ status: event.status,
101
+ phase: event.phase,
102
+ ...(event.capability_id ? { capability_id: event.capability_id } : {}),
103
+ occurred_at: event.occurred_at,
104
+ }));
105
+ writeCommandEnvelope({
106
+ status: "listed",
107
+ result: {
108
+ service_execution_id: serviceExecutionID,
109
+ after_sequence: afterSequence,
110
+ returned_count: events.length,
111
+ events,
112
+ },
113
+ instruction: "这是已保存的诊断事件;事件不代表业务结果,也不授权重放业务步骤。已读完所需诊断时停止;实际任务沿先前返回的当前动作继续。",
114
+ next: null,
115
+ recovery: events.length === limit && events.length > 0
116
+ ? [{
117
+ command: `itpay services events ${serviceExecutionID} --after-sequence ${events.at(-1).sequence} --limit ${limit} --json`,
118
+ reason: "继续读取下一页诊断事件",
119
+ }]
120
+ : [],
121
+ }, {
122
+ ...(options.jsonOutput !== undefined ? { jsonOutput: options.jsonOutput } : {}),
123
+ ...(options.output ? { output: options.output } : {}),
124
+ plainResult: [
125
+ `service_execution_id: ${serviceExecutionID}`,
126
+ `returned_count: ${events.length}`,
127
+ ...events.map((event) => `${event.sequence} ${event.occurred_at} ${event.type} ${event.status}/${event.phase}`),
128
+ ],
129
+ });
130
+ }