@itpay/cli 2.1.60 → 2.1.62

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.
@@ -1,6 +1,6 @@
1
1
  Third-party packages reachable from the ItPay Buyer runtime.
2
2
 
3
- ===== @itpay/hub-client@0.1.0-integration.34f4fc639af5 (UNLICENSED) =====
3
+ ===== @itpay/hub-client@0.1.0-integration.b575cbbd6435 (UNLICENSED) =====
4
4
  --- LICENSE ---
5
5
  UNLICENSED
6
6
 
package/dist/src/main.js CHANGED
@@ -3134,7 +3134,7 @@ var HubClient = class {
3134
3134
  const controller = new AbortController();
3135
3135
  let timer;
3136
3136
  const aborted = new Promise((_, reject) => {
3137
- controller.signal.addEventListener("abort", () => reject(new HubApiError(0, { error: { code: opts.signal?.aborted ? "request_cancelled" : "request_timeout", message: method === "POST" && path2 !== "/v1/discover" ? "Request outcome is unknown; read the original request/run before exact-key recovery. No automatic write retry." : "Read budget exhausted; keep the original reference and read it later.", details: { stage, method, path: path2 } } })), { once: true });
3137
+ controller.signal.addEventListener("abort", () => reject(new HubApiError(0, { error: { code: opts.signal?.aborted ? "request_cancelled" : "request_timeout", message: method === "POST" && path2 !== "/v1/discover" ? "Request outcome is unknown; read the original request/run before exact-key recovery. No automatic write retry." : `Hub ${stage} read timed out after ${timeoutMs} ms; no spending-budget conclusion. Keep the original reference and read it later.`, details: { stage, method, path: path2 } } })), { once: true });
3138
3138
  timer = setTimeout(() => controller.abort(), timeoutMs);
3139
3139
  });
3140
3140
  const cancel = /* @__PURE__ */ __name(() => controller.abort(), "cancel");
@@ -3841,7 +3841,8 @@ __name(withAsyncFileLock, "withAsyncFileLock");
3841
3841
  import { createHash, randomBytes } from "node:crypto";
3842
3842
  import { createServer } from "node:http";
3843
3843
  function hubOAuthConfig(env = process.env) {
3844
- const issuer = (env.ITPAY_HUB_OAUTH_ISSUER ?? "http://localhost:24444").replace(/\/+$/, "");
3844
+ const devHub = (env.ITPAY_HUB_URL ?? "").replace(/\/+$/, "") === "https://market-v4-dev.itpay.ai";
3845
+ const issuer = (env.ITPAY_HUB_OAUTH_ISSUER ?? (devHub ? "https://auth-v4-dev.itpay.ai" : "http://localhost:24444")).replace(/\/+$/, "");
3845
3846
  return {
3846
3847
  authorizeURL: `${issuer}/oauth2/auth`,
3847
3848
  tokenURL: `${issuer}/oauth2/token`,
@@ -5568,6 +5569,26 @@ __name(renderPaymentHandoff, "renderPaymentHandoff");
5568
5569
 
5569
5570
  // src/commands/hub_guidance.ts
5570
5571
  function writeCommandEnvelope(value, options = {}) {
5572
+ const qualify = /* @__PURE__ */ __name((action) => {
5573
+ if (!action.command.startsWith("itpay ")) return action;
5574
+ const assignments = [];
5575
+ for (const name of ["ITPAY_HUB_URL", "ITPAY_HUB_OAUTH_ISSUER", "ITPAY_HUB_OAUTH_CLIENT", "ITPAY_HUB_OAUTH_SCOPE", "ITPAY_STATE_DIR"]) {
5576
+ const raw = process.env[name];
5577
+ if (!raw) continue;
5578
+ if (name === "ITPAY_HUB_URL" || name === "ITPAY_HUB_OAUTH_ISSUER") {
5579
+ try {
5580
+ const u = new URL(raw);
5581
+ if (!["http:", "https:"].includes(u.protocol) || u.username || u.password || u.search || u.hash) return null;
5582
+ } catch {
5583
+ return null;
5584
+ }
5585
+ }
5586
+ const quoted = "'" + raw.replaceAll("'", `'"'"'`) + "'";
5587
+ assignments.push(name + "=" + quoted);
5588
+ }
5589
+ return { ...action, command: [...assignments, qualifyItPayCommand(action.command, declaredAgentType())].join(" ") };
5590
+ }, "qualify");
5591
+ value = { ...value, instruction: value.instruction + " " + routingInstruction(value), next: value.next ? qualify(value.next) : null, recovery: value.recovery.map(qualify).filter((action) => action !== null) };
5571
5592
  const out = options.output ?? ((text2) => {
5572
5593
  process.stdout.write(text2);
5573
5594
  });
@@ -5582,6 +5603,21 @@ function writeCommandEnvelope(value, options = {}) {
5582
5603
  for (const action of value.recovery) out("recovery: " + action.command + "\n when: " + action.reason + "\n");
5583
5604
  }
5584
5605
  __name(writeCommandEnvelope, "writeCommandEnvelope");
5606
+ function hubFailureInstruction(error, fallback) {
5607
+ if (!(error instanceof HttpError)) return fallback;
5608
+ if ((error.code === "request_timeout" || error.code === "request_cancelled") && error.message.includes("outcome is unknown")) return "\u63D0\u4EA4\u7ED3\u679C\u672A\u77E5\uFF1B\u4FDD\u7559\u539F\u8EAB\u4EFD\u3001\u5165\u53E3\u3001\u5E42\u7B49\u952E\u53CA\u8BF7\u6C42\u5F15\u7528\uFF0C\u5148\u8BFB\u53D6\u539F\u4EFB\u52A1\uFF0C\u4E0D\u6362\u8DEF\u91CD\u53D1\u6216\u91CD\u65B0\u4ED8\u6B3E\u3002";
5609
+ if (error.code === "request_timeout" || error.code === "request_cancelled") return "Hub \u8BFB\u53D6\u8D85\u65F6\u6216\u5DF2\u53D6\u6D88\uFF0C\u672A\u53D6\u5F97\u5F53\u524D\u4E8B\u5B9E\uFF1B\u8FD9\u4E0D\u8868\u793A\u64CD\u4F5C\u672A\u53D1\u5E03\u6216\u6D88\u8D39\u9884\u7B97\u4E0D\u8DB3\u3002\u4FDD\u7559\u539F\u8EAB\u4EFD\u3001\u6761\u4EF6\u53CA\u5DF2\u6709\u8BF7\u6C42\u5F15\u7528\uFF0C\u7A0D\u540E\u8BFB\u53D6\uFF1B\u4E0D\u6362\u8DEF\u91CD\u53D1\u3002";
5610
+ if (error.status === 404) return "\u8BE5\u64CD\u4F5C\u6216\u539F\u5F15\u7528\u5F53\u524D\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u89C1\uFF1B\u6838\u5BF9\u539F\u7F16\u53F7\u53CA\u53EF\u89C1\u53D1\u5E03\uFF0C\u4E0D\u731C\u66FF\u4EE3\u64CD\u4F5C\u3002";
5611
+ if (error.status === 403) return "\u5F53\u524D\u51ED\u636E\u6743\u9650\u6216\u6388\u6743\u8303\u56F4\u4E0D\u8DB3\uFF1B\u6838\u5BF9\u5B9E\u9645\u62D2\u7EDD\u539F\u56E0\u53CA\u5B98\u65B9\u6388\u6743\uFF0C\u4FDD\u7559\u539F\u8EAB\u4EFD\u548C\u8BF7\u6C42\uFF0C\u4E0D\u6362\u5165\u53E3\u7ED5\u8FC7\u3002";
5612
+ return fallback;
5613
+ }
5614
+ __name(hubFailureInstruction, "hubFailureInstruction");
5615
+ function routingInstruction(value) {
5616
+ const result = value.result && typeof value.result === "object" ? value.result : {};
5617
+ const original = ["request_id", "run_id", "intent_id", "order_id", "topup_id"].some((key) => typeof result[key] === "string" && result[key] !== "") || ["unknown", "unavailable"].includes(value.status) || ["hub_request_unknown", "request_timeout", "request_cancelled"].includes(value.error?.code ?? "");
5618
+ return original ? "\u7EE7\u7EED\u539F\u8EAB\u4EFD\u3001\u5165\u53E3\u548C\u5DF2\u6709\u8BF7\u6C42\u5F15\u7528\uFF0C\u4E0D\u6362\u8DEF\u91CD\u53D1\u3002" : "\u5F53\u524D\u4E3A API Hub\uFF1B\u529E\u7406\u3001\u4EA4\u4ED8\u4E0E\u552E\u540E\u4F7F\u7528 Services\uFF0C\u7A7A\u7ED3\u679C\u53EA\u9650\u5F53\u524D\u76EE\u5F55\u53CA\u6761\u4EF6\u3002";
5619
+ }
5620
+ __name(routingInstruction, "routingInstruction");
5585
5621
 
5586
5622
  // src/commands/hub.ts
5587
5623
  function hub() {
@@ -5650,7 +5686,9 @@ async function runHubInspect(operationID2, options) {
5650
5686
  input_schema: desc.input_schema ?? null
5651
5687
  },
5652
5688
  instruction: desc.status !== "published" ? "\u8BE5\u64CD\u4F5C\u5F53\u524D\u4E0D\u53EF\u8FD0\u884C\uFF1B\u4E0D\u8981\u53D1\u8D77 run\u3002" : "\u4F7F\u7528 current_publication_id \u7ED1\u5B9A\u8FD0\u884C\uFF1B\u5E26 effect_class=external_write/purchase \u7684\u64CD\u4F5C\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002",
5653
- next: desc.status === "published" ? { command: `itpay api run ${desc.operation_id} --publication ${desc.current_publication_id} --input '<JSON>'${options.jsonOutput ? " --json" : ""}`, reason: "\u53D1\u5E03\u7ED1\u5B9A\u8FD0\u884C" } : null,
5689
+ // Actual user input is still required; help is executable without calling
5690
+ // the supplier, while a placeholder is not a runnable action.
5691
+ next: desc.status === "published" ? { command: "itpay api run --help", reason: "\u6309 input_schema \u548C\u7528\u6237\u9700\u6C42\u51C6\u5907\u771F\u5B9E\u8F93\u5165\uFF1B\u6B64\u5E2E\u52A9\u547D\u4EE4\u4E0D\u6267\u884C API" } : null,
5654
5692
  recovery: []
5655
5693
  }, {
5656
5694
  jsonOutput: Boolean(options.jsonOutput),
@@ -5746,48 +5784,74 @@ async function runHubRun(operationID2, options) {
5746
5784
  throw new Error(`idempotency_conflict: request ${task.request_id} already exists with different input/publication/credential selection \u2014 use a new --request-id or "itpay api resume ${task.request_id}"`);
5747
5785
  }
5748
5786
  if (!created && task.run_id) {
5749
- const rec2 = await waitForRun(client, task.run_id, options.waitSeconds ?? 0);
5750
- store.update(task.request_id, { status: rec2.execution_state === "succeeded" ? "succeeded" : rec2.execution_state === "failed" ? "failed" : "dispatched" });
5751
- renderRun(rec2, options.jsonOutput, "replayed");
5787
+ const rec = await waitForRun(client, task.run_id, options.waitSeconds ?? 0);
5788
+ store.update(task.request_id, { status: rec.execution_state === "succeeded" ? "succeeded" : rec.execution_state === "failed" ? "failed" : "dispatched" });
5789
+ renderRun(rec, options.jsonOutput, "replayed");
5752
5790
  return;
5753
5791
  }
5754
5792
  if (!created && task.intent_id) {
5755
5793
  await renderBlockedTask(task, null, options.jsonOutput);
5756
5794
  return;
5757
5795
  }
5758
- const body = {
5759
- expected_publication_id: task.publication_id,
5760
- input: task.input,
5761
- ...task.credential_id ? { credential_id: task.credential_id } : {},
5762
- ...task.source_credentials ? { source_credentials: task.source_credentials } : {}
5763
- };
5764
- if (options.maxCharge) {
5765
- body.max_charge = { currency: "CNY", scale: 6, amount_atoms: options.maxCharge };
5766
- }
5767
- store.update(task.request_id, { status: "dispatched" });
5768
- const admission = await client.run(operationID2, body, store.idempotencyKey(task.request_id));
5769
- if (!isRunReceipt(admission)) {
5770
- store.update(task.request_id, { status: "blocked", intent_id: admission.intent_id, blocking_reason: admission.blocking_reason });
5771
- await renderBlockedTask(task, admission, options.jsonOutput);
5772
- return;
5796
+ await dispatchOriginalTask(client, store, task, options);
5797
+ }
5798
+ __name(runHubRun, "runHubRun");
5799
+ var HubTaskRequestError = class extends Error {
5800
+ static {
5801
+ __name(this, "HubTaskRequestError");
5773
5802
  }
5774
- let rec = admission;
5775
- store.update(task.request_id, { run_id: rec.run_id });
5776
- if (options.waitSeconds) {
5777
- rec = await waitForRun(client, rec.run_id, options.waitSeconds);
5803
+ requestID;
5804
+ references;
5805
+ code;
5806
+ constructor(error, task) {
5807
+ super(error instanceof Error ? error.message : "original Hub request did not return a receipt");
5808
+ this.requestID = task.request_id;
5809
+ this.references = { request_id: task.request_id, ...task.run_id ? { run_id: task.run_id } : {}, ...task.intent_id ? { intent_id: task.intent_id } : {} };
5810
+ this.code = error instanceof HttpError ? error.code : ["authorization_required", "idempotency_conflict", "invalid_state"].find((code) => this.message.startsWith(code + ":")) ?? "hub_request_unknown";
5811
+ }
5812
+ };
5813
+ async function dispatchOriginalTask(client, store, task, options) {
5814
+ try {
5815
+ const selections = { ...task.credential_id ? { credential_id: task.credential_id } : {}, ...task.source_credentials ? { source_credentials: task.source_credentials } : {} };
5816
+ if (task.input_digest !== digestTask(task.operation_id, task.publication_id, task.input, task.max_charge_atoms, selections)) {
5817
+ throw new Error("idempotency_conflict: stored request facts do not match the original digest; preserve this task for review");
5818
+ }
5819
+ const body = {
5820
+ expected_publication_id: task.publication_id,
5821
+ input: task.input,
5822
+ ...task.credential_id ? { credential_id: task.credential_id } : {},
5823
+ ...task.source_credentials ? { source_credentials: task.source_credentials } : {}
5824
+ };
5825
+ if (task.max_charge_atoms) {
5826
+ body.max_charge = { currency: "CNY", scale: 6, amount_atoms: task.max_charge_atoms };
5827
+ }
5828
+ store.update(task.request_id, { status: "dispatched" });
5829
+ const admission = await client.run(task.operation_id, body, store.idempotencyKey(task.request_id));
5830
+ if (!isRunReceipt(admission)) {
5831
+ store.update(task.request_id, { status: "blocked", intent_id: admission.intent_id, blocking_reason: admission.blocking_reason });
5832
+ await renderBlockedTask(task, admission, options.jsonOutput);
5833
+ return;
5834
+ }
5835
+ let rec = admission;
5836
+ store.update(task.request_id, { run_id: rec.run_id });
5837
+ if (options.waitSeconds) {
5838
+ rec = await waitForRun(client, rec.run_id, options.waitSeconds);
5839
+ }
5840
+ store.update(task.request_id, {
5841
+ status: rec.execution_state === "succeeded" ? "succeeded" : rec.execution_state === "failed" ? "failed" : "dispatched"
5842
+ });
5843
+ renderRun(rec, options.jsonOutput);
5844
+ } catch (error) {
5845
+ throw new HubTaskRequestError(error, store.get(task.request_id) ?? task);
5778
5846
  }
5779
- store.update(task.request_id, {
5780
- status: rec.execution_state === "succeeded" ? "succeeded" : rec.execution_state === "failed" ? "failed" : "dispatched"
5781
- });
5782
- renderRun(rec, options.jsonOutput);
5783
5847
  }
5784
- __name(runHubRun, "runHubRun");
5848
+ __name(dispatchOriginalTask, "dispatchOriginalTask");
5785
5849
  function renderRun(rec, jsonOutput, note) {
5786
- const charged = rec.actual_charge ? atomsToYuan(rec.actual_charge.amount_atoms) : "\xA50.000000";
5850
+ const charged = rec.actual_charge ? atomsToYuan(rec.actual_charge.amount_atoms) : "\u8D39\u7528\u56DE\u6267\u672A\u63D0\u4F9B";
5787
5851
  writeCommandEnvelope({
5788
5852
  status: rec.execution_state === "succeeded" ? "executed" : rec.execution_state,
5789
- result: { run_id: rec.run_id, execution_state: rec.execution_state, settlement_state: rec.settlement_state, actual_charge: rec.actual_charge ?? null, result: rec.result ?? null, error: rec.error ?? null, ...note ? { note } : {} },
5790
- instruction: rec.execution_state === "succeeded" ? `\u8FD0\u884C\u5B8C\u6210\uFF0C\u5DF2\u6309\u4EF7\u683C\u5361\u7ED3\u7B97 ${charged}\u3002` : `\u8FD0\u884C\u672A\u5B8C\u6210\uFF08${rec.error?.code ?? rec.execution_state}\uFF09\uFF1B\u7528 itpay api run-status ${rec.run_id} \u67E5\u8BE2\u539F\u4EFB\u52A1\uFF0C\u4E0D\u91CD\u590D\u53D1\u8D77\u3002`,
5853
+ result: { run_id: rec.run_id, execution_state: rec.execution_state, settlement_state: rec.settlement_state, ...rec.delivery_state ? { delivery_state: rec.delivery_state } : {}, actual_charge: rec.actual_charge ?? null, result: rec.result ?? null, error: rec.error ?? null, ...note ? { note } : {} },
5854
+ instruction: rec.execution_state === "succeeded" ? `\u6267\u884C\u72B6\u6001\u4E3A succeeded\uFF1B\u4EA4\u4ED8\u72B6\u6001 ${rec.delivery_state ?? "\u672A\u63D0\u4F9B"}\uFF0C\u7ED3\u7B97\u72B6\u6001 ${rec.settlement_state ?? "\u672A\u63D0\u4F9B"}\uFF0C\u5B9E\u9645\u8D39\u7528\u56DE\u6267 ${charged}\u3002\u4EC5\u636E\u5B9E\u9645 result \u548C\u4EA4\u4ED8\u4E8B\u5B9E\u56DE\u7B54\uFF0C\u7A7A\u503C\u4E0D\u4EE3\u8868\u67E5\u8BE2\u6210\u529F\u4E14\u96F6\u6761\u3002` : `\u6267\u884C\u72B6\u6001 ${rec.execution_state}\uFF08${rec.error?.code ?? "\u65E0\u9519\u8BEF\u4EE3\u7801"}\uFF09\uFF0C\u7ED3\u7B97\u72B6\u6001 ${rec.settlement_state ?? "\u672A\u63D0\u4F9B"}\uFF0C\u5B9E\u9645\u8D39\u7528\u56DE\u6267 ${charged}\uFF1B\u7528 itpay api run-status ${rec.run_id} \u67E5\u8BE2\u539F\u4EFB\u52A1\uFF0C\u4E0D\u91CD\u590D\u53D1\u8D77\u3002`,
5791
5855
  next: ["succeeded", "failed"].includes(rec.execution_state) ? null : { command: `itpay api run-status ${rec.run_id}`, reason: "\u67E5\u8BE2\u539F run \u72B6\u6001\uFF0C\u4E0D\u65B0\u5EFA\u8BF7\u6C42" },
5792
5856
  recovery: []
5793
5857
  }, {
@@ -5831,7 +5895,7 @@ async function runHubWallet(options) {
5831
5895
  writeCommandEnvelope({
5832
5896
  status: "ok",
5833
5897
  result: { available: bal.available, held: bal.held },
5834
- instruction: `\u53EF\u7528 ${atomsToYuan(bal.available.amount_atoms)}\uFF0C\u5728\u9014 ${atomsToYuan(bal.held.amount_atoms)}\u3002`,
5898
+ instruction: `\u5F53\u524D\u8D26\u6237\u94B1\u5305\uFF1A\u53EF\u7528 ${atomsToYuan(bal.available.amount_atoms)}\uFF0C\u5728\u9014 ${atomsToYuan(bal.held.amount_atoms)}\uFF1B\u4E0D\u4EE3\u8868\u672C Consumer \u7684\u6388\u6743\u6D88\u8D39\u4E0A\u9650\u3002`,
5835
5899
  next: null,
5836
5900
  recovery: []
5837
5901
  }, {
@@ -5842,7 +5906,7 @@ async function runHubWallet(options) {
5842
5906
  __name(runHubWallet, "runHubWallet");
5843
5907
  async function runHubUsage(options) {
5844
5908
  const usage = await hub().usage();
5845
- writeCommandEnvelope({ status: "ok", result: usage, instruction: "\u5F53\u524D Consumer \u7684\u7528\u91CF\u4E0E\u8D39\u7528\u56DE\u6267\uFF1B\u8BFB\u53D6\u4E0D\u4F1A\u518D\u6B21\u6267\u884C\u6216\u6263\u8D39\u3002", next: null, recovery: [] }, {
5909
+ writeCommandEnvelope({ status: "ok", result: usage, instruction: "\u5F53\u524D\u8FDE\u63A5\u51ED\u636E\uFF08API Key \u6216 Consumer\uFF09\u8303\u56F4\u7684\u7528\u91CF\u4E0E\u8D39\u7528\u56DE\u6267\uFF1Bruns \u5305\u542B\u5931\u8D25\u8C03\u7528\uFF0C\u4E0D\u80FD\u5F53\u4F5C\u6210\u529F\u4EA4\u4ED8\u6B21\u6570\u3002\u94B1\u5305\u4F59\u989D\u5C5E\u4E8E\u8D26\u6237\u53E3\u5F84\uFF1B\u8BFB\u53D6\u4E0D\u4F1A\u518D\u6B21\u6267\u884C\u6216\u6263\u8D39\u3002", next: null, recovery: [] }, {
5846
5910
  jsonOutput: Boolean(options.jsonOutput),
5847
5911
  plainResult: [`gross ${atomsToYuan(usage.gross_atoms)} refunded ${atomsToYuan(usage.refunded_atoms)} net ${atomsToYuan(usage.net_atoms)} held ${atomsToYuan(usage.held_atoms)}`]
5848
5912
  });
@@ -6013,25 +6077,33 @@ async function runHubResume(requestID, options) {
6013
6077
  if (!task) {
6014
6078
  throw new Error(`not_found: unknown task ${requestID} \u2014 check "itpay api tasks"`);
6015
6079
  }
6016
- if (task.run_id) {
6017
- const rec = await waitForRun(client, task.run_id, options.waitSeconds ?? 0);
6018
- store.update(requestID, { status: rec.execution_state === "succeeded" ? "succeeded" : rec.execution_state === "failed" ? "failed" : "dispatched" });
6019
- renderRun(rec, options.jsonOutput);
6020
- return;
6021
- }
6022
- if (task.intent_id) {
6023
- const res = await client.continueIntent(task.intent_id, `cli-continue-${requestID}`);
6024
- if (res.run) {
6025
- store.update(requestID, { run_id: res.run.run_id, status: res.run.execution_state === "succeeded" ? "succeeded" : "dispatched" });
6026
- renderRun(res.run, options.jsonOutput);
6027
- } else {
6028
- const state = res.blocking_reason ?? res.state ?? res.status ?? "blocked";
6029
- store.update(requestID, { blocking_reason: state });
6030
- await renderBlockedTask(task, { ...res, intent_id: task.intent_id, blocking_reason: state }, options.jsonOutput);
6080
+ try {
6081
+ if (task.run_id) {
6082
+ const rec = await waitForRun(client, task.run_id, options.waitSeconds ?? 0);
6083
+ store.update(requestID, { status: rec.execution_state === "succeeded" ? "succeeded" : rec.execution_state === "failed" ? "failed" : "dispatched" });
6084
+ renderRun(rec, options.jsonOutput);
6085
+ return;
6031
6086
  }
6032
- return;
6087
+ if (task.intent_id) {
6088
+ const res = await client.continueIntent(task.intent_id, `cli-continue-${requestID}`);
6089
+ if (res.run) {
6090
+ store.update(requestID, { run_id: res.run.run_id, status: res.run.execution_state === "succeeded" ? "succeeded" : "dispatched" });
6091
+ renderRun(res.run, options.jsonOutput);
6092
+ } else {
6093
+ const state = res.blocking_reason ?? res.state ?? res.status ?? "blocked";
6094
+ store.update(requestID, { blocking_reason: state });
6095
+ await renderBlockedTask(task, { ...res, intent_id: task.intent_id, blocking_reason: state }, options.jsonOutput);
6096
+ }
6097
+ return;
6098
+ }
6099
+ if (!["pending", "dispatched", "unknown"].includes(task.status)) {
6100
+ throw new HubTaskRequestError(new Error("invalid_state: original task has no authoritative run or intent; preserve it for review"), task);
6101
+ }
6102
+ await dispatchOriginalTask(client, store, task, options);
6103
+ } catch (error) {
6104
+ if (error instanceof HubTaskRequestError) throw error;
6105
+ throw new HubTaskRequestError(error, store.get(requestID) ?? task);
6033
6106
  }
6034
- throw new Error(`invalid_state: task ${requestID} has no run or intent \u2014 it never reached the server`);
6035
6107
  }
6036
6108
  __name(runHubResume, "runHubResume");
6037
6109
  async function runHubTasks(options) {
@@ -6134,7 +6206,12 @@ __name(runHubConnect, "runHubConnect");
6134
6206
 
6135
6207
  // src/commands/api_commands.ts
6136
6208
  function reportCLIError(error, contract) {
6137
- writeCommandEnvelope({ status: "error", error: { code: error instanceof HttpError ? error.code : contract?.code ?? "command_failed", message: error instanceof Error ? error.message : String(error) }, instruction: contract?.instruction ?? "Check the command and the current Hub connection; resume known tasks before retrying writes.", next: null, recovery: contract?.recovery ?? [] }, { jsonOutput: contract?.jsonOutput ?? process.argv.includes("--json") });
6209
+ const code = error instanceof HubTaskRequestError ? error.code : error instanceof HttpError ? error.code : error instanceof Error && error.message.startsWith("authorization_required:") ? "authorization_required" : contract?.code ?? "command_failed";
6210
+ const auth = code === "authorization_required" || code === "unauthenticated";
6211
+ const taskID = error instanceof HubTaskRequestError ? error.requestID : void 0;
6212
+ const references = error instanceof HubTaskRequestError ? error.references : void 0;
6213
+ const recover = taskID ? { command: qualifyItPayCommand(references?.run_id ? `itpay api run-status ${references.run_id}${contract?.jsonOutput ? " --json" : ""}` : `itpay api resume ${taskID}${contract?.jsonOutput ? " --json" : ""}`, declaredAgentType()), reason: "\u8BFB\u53D6\u6216\u6062\u590D\u540C\u4E00\u539F\u4EFB\u52A1\uFF0C\u4E0D\u521B\u5EFA\u66FF\u4EE3\u8BF7\u6C42" } : null;
6214
+ writeCommandEnvelope({ status: "error", error: { code, message: error instanceof Error ? error.message : String(error) }, ...references ? { result: references } : {}, instruction: auth ? "\u5148\u5B8C\u6210 ItPay API \u6B63\u5E38\u8FDE\u63A5\uFF1B\u4FDD\u7559\u539F\u8EAB\u4EFD\u548C\u4EFB\u52A1\uFF0C\u4E0D\u8981\u521B\u5EFA\u66FF\u4EE3\u8BF7\u6C42\u3002" : ["idempotency_conflict", "invalid_state"].includes(code) ? "\u539F\u4EFB\u52A1\u8BB0\u5F55\u4E0D\u4E00\u81F4\uFF1B\u4FDD\u7559\u8BB0\u5F55\u6838\u5BF9\uFF0C\u4E0D\u80FD\u4FEE\u6539\u51BB\u7ED3\u53C2\u6570\u7EE7\u7EED\u53D1\u9001\u3002" : taskID ? "\u539F\u8BF7\u6C42\u5C1A\u672A\u53D6\u5F97\u53EF\u7528\u56DE\u6267\uFF1B\u8FD9\u4E0D\u4EE3\u8868\u672A\u5230\u8FBE\u670D\u52A1\u5668\u3002\u4FDD\u7559\u539F\u8BF7\u6C42\u6062\u590D\uFF0C\u4E0D\u91CD\u65B0\u8C03\u7528\u6216\u5145\u503C\u3002" : hubFailureInstruction(error, contract?.instruction ?? "Check the command and current Hub connection; preserve original tasks."), next: auth ? { command: qualifyItPayCommand(`itpay api connect${contract?.jsonOutput ? " --json" : ""}`, declaredAgentType()), reason: "\u6B63\u5E38\u6388\u6743\u540E\u7EE7\u7EED\u539F\u4EFB\u52A1" } : ["idempotency_conflict", "invalid_state", "forbidden", "publication_changed", "credential_revalidation_required"].includes(code) ? null : recover, recovery: auth && recover ? [recover] : contract?.recovery ?? [] }, { jsonOutput: contract?.jsonOutput ?? process.argv.includes("--json") });
6138
6215
  process.exitCode = 1;
6139
6216
  }
6140
6217
  __name(reportCLIError, "reportCLIError");
@@ -6171,7 +6248,7 @@ function registerAPICommands(program3) {
6171
6248
  try {
6172
6249
  await runHubInspect(operationID2, { jsonOutput: Boolean(options.json) });
6173
6250
  } catch (error) {
6174
- reportCLIError(error, { jsonOutput: Boolean(options.json), code: "hub_inspect_failed", instruction: "operation_id \u53EF\u80FD\u672A\u77E5\u6216\u672A\u53D1\u5E03\u3002", recovery: [] });
6251
+ reportCLIError(error, { jsonOutput: Boolean(options.json), code: "hub_inspect_failed", instruction: "\u672A\u53D6\u5F97\u64CD\u4F5C\u5408\u540C\uFF1B\u4FDD\u7559\u5F53\u524D\u6761\u4EF6\uFF0C\u6309\u5B9E\u9645\u9519\u8BEF\u6838\u5BF9 Hub \u8FDE\u63A5\uFF0C\u4E0D\u63A8\u6D4B\u53D1\u5E03\u72B6\u6001\u3002", recovery: [] });
6175
6252
  }
6176
6253
  });
6177
6254
  hubCmd.command("run").description("Execute a metered operation (idempotent, prepaid)").argument("<operation_id>").requiredOption("--publication <id>", "expected publication id from inspect").requiredOption("--input <json>", "JSON object, @file path, or - for stdin").option("--credential-id <id>", "stored BYOK credential reference").option("--source-credentials <json>", "Native source credential references JSON or @file").option("--max-charge <atoms>", "max charge in atoms (scale 6)").option("--request-id <id>", "stable logical request id \u2014 replays resume the same request").option("--wait <seconds>", "poll run status until terminal", "0").option("--json", "output JSON").action(async (operationID2, options) => {
@@ -12880,7 +12957,7 @@ function railInvocationProjection(response, requestedCapability, input, itemCoun
12880
12957
  __name(railInvocationProjection, "railInvocationProjection");
12881
12958
 
12882
12959
  // src/services/rail/recovery.ts
12883
- var RAIL_LOCATION_EVIDENCE_REASONS = /* @__PURE__ */ new Set(["endpoint_kind_conflict", "place_identity_uncertain", "endpoint_adcode_name_conflict", "endpoint_poi_name_conflict", "endpoint_station_name_code_conflict", "location_evidence_required", "coordinate_name_mismatch", "area_scope_too_broad", "address_required", "administrative_area_unresolved", "station_location_evidence_required", "coordinate_identity_unverified"]);
12960
+ var RAIL_LOCATION_EVIDENCE_REASONS = /* @__PURE__ */ new Set(["station_jurisdiction_evidence_required", "endpoint_kind_conflict", "place_identity_uncertain", "endpoint_adcode_name_conflict", "endpoint_poi_name_conflict", "endpoint_station_name_code_conflict", "location_evidence_required", "coordinate_name_mismatch", "area_scope_too_broad", "address_required", "administrative_area_unresolved", "station_location_evidence_required", "coordinate_identity_unverified"]);
12884
12961
  var RAIL_QUOTE_FAILURE_GUIDANCE = {
12885
12962
  quote_source_unavailable: "\u5B9E\u65F6\u8F66\u7968\u6570\u636E\u6682\u4E0D\u53EF\u7528\uFF1B\u4FDD\u7559\u539F\u9009\u62E9\uFF0C\u7A0D\u540E\u6309\u7528\u6237\u610F\u613F\u91CD\u65B0\u6838\u9A8C\uFF0C\u4E0D\u521B\u5EFA\u66FF\u4EE3\u8BA2\u5355\u3002",
12886
12963
  quote_train_changed: "\u6240\u9009\u8F66\u6B21\u7684\u65F6\u523B\u6216\u8FD0\u884C\u4FE1\u606F\u5DF2\u53D8\u5316\uFF1B\u5411\u7528\u6237\u8BF4\u660E\u5E76\u5F81\u8BE2\u662F\u5426\u91CD\u65B0\u67E5\u7968\u3002",
@@ -13000,6 +13077,9 @@ function railWorkflowEnvelope(model) {
13000
13077
  const affected = model.workflow?.failure?.endpoint ?? model.workflow?.dependency?.endpoint;
13001
13078
  const query = model.workflow?.query_input ?? {};
13002
13079
  const endpoints = query.endpoints && typeof query.endpoints === "object" ? query.endpoints : {};
13080
+ if (code === "station_jurisdiction_evidence_required") {
13081
+ return { status: "system_evidence_required", result: { service_execution_id: id, reason: code, failed_step: model.workflow?.failure?.step_id, failure: model.workflow?.failure, query, ...affected === "origin" || affected === "destination" ? { affected_endpoint: affected, original_place: endpoints[affected]?.text ?? query[affected] } : {} }, instruction: "\u5730\u56FE\u5730\u70B9\u672A\u80FD\u56DE\u5339\u539F\u94C1\u8DEF\u7AD9\u8EAB\u4EFD\uFF0C\u9700\u670D\u52A1\u7EF4\u62A4\u65B9\u6838\u5BF9\u5730\u56FE\u4E0E\u94C1\u8DEF\u76EE\u5F55\u4E8B\u5B9E\u3002\u4FDD\u7559\u5B8C\u6574\u539F\u9700\u6C42\u53CA\u5DF2\u89E3\u6790\u53E6\u4E00\u7AEF\uFF1B\u4E0D\u8981\u6C42\u7528\u6237\u6539\u5730\u5740\uFF0C\u4E0D\u6362kind\u3001\u7AD9\u3001\u65E5\u671F\u6216\u731C\u5750\u6807\u3002\u5F53\u524D\u65E0\u53EF\u6267\u884C\u6062\u590D\uFF0C\u505C\u6B62\uFF1B\u4E0D\u91CD\u65B0\u67E5\u7968\u6216\u521B\u5EFA\u8D2D\u4E70\u3002", next: null, recovery: [] };
13082
+ }
13003
13083
  const stationPair = [endpoints.origin, endpoints.destination].every((endpoint) => endpoint?.kind === "station" && typeof endpoint.text === "string" && endpoint.text.trim() && typeof endpoint.station_code === "string" && /^[A-Z]{3}$/.test(endpoint.station_code));
13004
13084
  if (code === "station_location_evidence_required") {
13005
13085
  const exactInput = stationPair && typeof query.travel_date === "string" ? { origin: endpoints.origin.text, destination: endpoints.destination.text, travel_date: query.travel_date } : void 0;
@@ -16638,8 +16718,8 @@ __name(installDefinition, "installDefinition");
16638
16718
  import { createHash as createHash12 } from "node:crypto";
16639
16719
 
16640
16720
  // src/state/skill_identity.generated.ts
16641
- var CANONICAL_SKILL_SHA256 = "dcbce8347f9ed4a95b89bbd680bbfb2c5308f1081e1af1554f413b950eb902dc";
16642
- var CANONICAL_API_SKILL_SHA256 = "a00535a771acc0d3bd325316380d0a58d2291a013c792c5edccae65694647b45";
16721
+ var CANONICAL_SKILL_SHA256 = "4a38087a41ed4b9b6e879726b93bdef99ca67fccd2a0f9837123d5b334b046c0";
16722
+ var CANONICAL_API_SKILL_SHA256 = "dffec781d5053bbdb93ec555ad2b1b4a7cad55c2281a3c9c19597a4a9418bde6";
16643
16723
 
16644
16724
  // src/commands/skill.ts
16645
16725
  import { existsSync as existsSync9, readFileSync as readFileSync16 } from "node:fs";
@@ -16713,7 +16793,7 @@ ${CODEX_WAIT_GUIDANCE}
16713
16793
  const envelope = {
16714
16794
  status: "shown",
16715
16795
  result: { skill: ITPAY_SKILL, content },
16716
- instruction: agentType ? agentType === "workbuddy" ? "\u5B8C\u6574\u8BFB\u53D6\u539F\u6587\u5E76\u6309\u5BBF\u4E3B\u6280\u80FD\u65B9\u5F0F\u4FDD\u5B58\u542F\u7528\uFF1B\u6309\u7528\u6237\u610F\u56FE\u9009\u62E9\u7B2C\u4E00\u6761\u4E1A\u52A1\u547D\u4EE4\u3002\u4FDD\u6301 workbuddy\u3001\u540C\u4E00\u5165\u53E3\u548C Backend\uFF1B\u53EA\u6709\u5B9E\u9645\u6301\u4E45\u5316\u64CD\u4F5C\u88AB\u62D2\u65F6\u624D\u6CBF\u5BBF\u4E3B\u6B63\u5F0F\u6D41\u7A0B\u7533\u8BF7\u6240\u9700\u6743\u9650\uFF0C\u62D2\u7EDD\u540E\u62A5\u544A\u53D7\u963B\u64CD\u4F5C\uFF0C\u4E0D\u5220\u9664 identity\u3002" : `\u5B8C\u6574\u8BFB\u53D6\u539F\u6587\u5E76\u6309\u5BBF\u4E3B\u6280\u80FD\u65B9\u5F0F\u4FDD\u5B58\u542F\u7528\uFF1B\u628A\u81EA\u5DF1\u89C6\u4E3A\u670D\u52A1\u7528\u6237\u7684\u4EE3\u7406\uFF0C\u5148\u7406\u89E3\u7528\u6237\u610F\u56FE\u548C\u89E3\u91CA\u7528\u6237\u6743\u76CA\uFF0C\u518D\u9009\u62E9\u8D2D\u4E70\u3001\u5DF2\u8D2D\u5185\u5BB9\u3001\u8BA2\u5355\u6216\u9000\u6B3E\u5BF9\u5E94\u7684\u7B2C\u4E00\u6761\u547D\u4EE4\u3002\u5F53\u524D Agent Type \u662F ${agentType}\uFF0C\u540E\u7EED\u547D\u4EE4\u4FDD\u6301\u4E0D\u53D8\u3002` : "\u5B8C\u6574\u8BFB\u53D6\u5E76\u9075\u5B88 Skill\uFF1B\u5148\u5982\u5B9E\u9009\u62E9\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u5BF9\u5E94\u7684 Agent Type\u3002",
16796
+ instruction: agentType ? agentType === "workbuddy" ? "\u5B8C\u6574\u8BFB\u53D6 Services \u539F\u6587\u5E76\u6309\u5BBF\u4E3B\u6280\u80FD\u65B9\u5F0F\u542F\u7528\uFF1BAPI/\u6570\u636E\u4EFB\u52A1\u6539\u8BFB itpay-api\uFF0C\u4E0D\u56E0 Services \u76EE\u5F55\u672A\u5217\u51FA\u5C31\u5224\u65E0\u80FD\u529B\u3002\u6309\u7528\u6237\u4EA4\u4ED8\u7269\u9009\u62E9\u7B2C\u4E00\u6761\u547D\u4EE4\u3002\u4FDD\u6301 workbuddy\u3001\u540C\u4E00\u5165\u53E3\u548C Backend\uFF1B\u53EA\u6709\u5B9E\u9645\u6301\u4E45\u5316\u64CD\u4F5C\u88AB\u62D2\u65F6\u624D\u6CBF\u5BBF\u4E3B\u6B63\u5F0F\u6D41\u7A0B\u7533\u8BF7\u6240\u9700\u6743\u9650\uFF0C\u62D2\u7EDD\u540E\u62A5\u544A\u53D7\u963B\u64CD\u4F5C\uFF0C\u4E0D\u5220\u9664 identity\u3002" : `\u5B8C\u6574\u8BFB\u53D6\u539F\u6587\u5E76\u6309\u5BBF\u4E3B\u6280\u80FD\u65B9\u5F0F\u4FDD\u5B58\u542F\u7528\uFF1B\u628A\u81EA\u5DF1\u89C6\u4E3A\u670D\u52A1\u7528\u6237\u7684\u4EE3\u7406\uFF0C\u5148\u7406\u89E3\u7528\u6237\u610F\u56FE\u548C\u89E3\u91CA\u7528\u6237\u6743\u76CA\uFF0C\u518D\u9009\u62E9\u8D2D\u4E70\u3001\u5DF2\u8D2D\u5185\u5BB9\u3001\u8BA2\u5355\u6216\u9000\u6B3E\u5BF9\u5E94\u7684\u7B2C\u4E00\u6761\u547D\u4EE4\u3002\u5F53\u524D Agent Type \u662F ${agentType}\uFF0C\u540E\u7EED\u547D\u4EE4\u4FDD\u6301\u4E0D\u53D8\u3002` : "\u5B8C\u6574\u8BFB\u53D6\u5E76\u9075\u5B88 Skill\uFF1B\u5148\u5982\u5B9E\u9009\u62E9\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u5BF9\u5E94\u7684 Agent Type\u3002",
16717
16797
  next: agentType ? null : { command: "itpay install --json", reason: "\u9009\u62E9\u771F\u5B9E\u4E14\u7A33\u5B9A\u7684 Agent Type" },
16718
16798
  recovery: []
16719
16799
  };
@@ -16777,7 +16857,7 @@ function showAPISkill(options) {
16777
16857
  writeCommandEnvelope2({
16778
16858
  status: "shown",
16779
16859
  result: { skill: "itpay-api", content },
16780
- instruction: "\u5B8C\u6574\u8BFB\u53D6 API Skill\uFF0C\u6309\u7528\u6237\u4EFB\u52A1\u4F7F\u7528 itpay api --help\uFF1B\u9700\u8981\u8BA4\u8BC1\u65F6\u7531\u672C\u4EBA\u5B8C\u6210 api connect\uFF0C\u5DF2\u6709\u4EFB\u52A1\u6CBF\u539F\u5F15\u7528\u6062\u590D\u3002\u4FDD\u6301\u771F\u5B9E\u5BBF\u4E3B\u3001Hub \u7AEF\u70B9\u548C\u72B6\u6001\u76EE\u5F55\u3002",
16860
+ instruction: "\u5B8C\u6574\u8BFB\u53D6 API Skill\uFF1BAPI/\u6570\u636E\u4EFB\u52A1\u76F4\u63A5\u6309 itpay api --help\u3001discover\u3001inspect \u7EE7\u7EED\uFF0C\u4E0D\u5148\u67E5 Services \u76EE\u5F55\uFF1B\u9700\u8981\u8BA4\u8BC1\u65F6\u7531\u672C\u4EBA\u5B8C\u6210 api connect\uFF0C\u5DF2\u6709\u4EFB\u52A1\u6CBF\u539F\u5F15\u7528\u6062\u590D\u3002\u4FDD\u6301\u771F\u5B9E\u5BBF\u4E3B\u3001Hub \u7AEF\u70B9\u548C\u72B6\u6001\u76EE\u5F55\u3002",
16781
16861
  next: null,
16782
16862
  recovery: []
16783
16863
  }, {
@@ -16851,7 +16931,7 @@ async function runSetup(backend, config, skillPath, options = {}) {
16851
16931
  reason: "\u7531\u672C\u4EBA\u5B8C\u6210\u5B98\u65B9\u8D26\u53F7\u6388\u6743\uFF0C\u4E0D\u81EA\u52A8\u767B\u5F55"
16852
16932
  } } : {}
16853
16933
  },
16854
- instruction: account.status === "authenticated" ? "\u8BBE\u5907\u5DF2\u51C6\u5907\u597D\uFF0C\u5DF2\u6709\u8D26\u53F7\u6388\u6743\u53EF\u7EE7\u7EED\u4F7F\u7528\u3002\u8BFB\u53D6\u5E76\u542F\u7528\u4E0B\u65B9 Skill \u540E\uFF0C\u6309\u7528\u6237\u9700\u6C42\u5F00\u59CB\u3002" : "\u8BBE\u5907\u5DF2\u51C6\u5907\u597D\u3002\u8BFB\u53D6\u5E76\u542F\u7528\u4E0B\u65B9 Skill \u540E\u5373\u53EF\u5F00\u59CB\uFF1B\u9700\u8981\u8D26\u53F7\u7684\u529F\u80FD\u4F1A\u518D\u8BF7\u7528\u6237\u6388\u6743\u3002",
16934
+ instruction: (account.status === "authenticated" ? "\u8BBE\u5907\u5DF2\u51C6\u5907\u597D\uFF0CServices \u8D26\u53F7\u5DF2\u6388\u6743\uFF1B\u672C\u6B21\u672A\u6838\u9A8C Hub API \u6388\u6743\u3002" : "\u8BBE\u5907\u5DF2\u51C6\u5907\u597D\uFF1BServices \u9700\u8981\u8D26\u53F7\u7684\u529F\u80FD\u518D\u8BF7\u672C\u4EBA\u6388\u6743\uFF0C\u672C\u6B21\u672A\u6838\u9A8C Hub API \u6388\u6743\u3002") + " \u6309\u4EA4\u4ED8\u7269\u9009\u62E9\u540C\u5305 Skill\uFF1AAPI/\u7ED3\u6784\u5316\u6570\u636E\u8BFB itpay skill show itpay-api --json\uFF0C\u518D api discover\uFF1B\u529E\u7406\u3001\u4EA4\u4ED8\u548C\u552E\u540E\u8BFB itpay skill show itpay --json\u3002skill_path \u662F Services \u539F\u8DEF\u5F84\uFF0C\u4E0D\u8981\u6C42 API \u5148\u8BFB\u94C1\u8DEF\u8BF4\u660E\u3002\u4FDD\u7559\u539F launcher\u3001\u771F\u5B9E\u5BBF\u4E3B\u548C\u72B6\u6001\u76EE\u5F55\uFF0C\u65B0\u4F1A\u8BDD\u4E0D\u521B\u5EFA\u65B0\u8EAB\u4EFD\uFF1B\u6B63\u5E38\u4EFB\u52A1\u4E0D\u91CD\u590D setup\u3002\u65B0\u4EFB\u52A1\u4EC5\u5728\u5BBF\u4E3B\u83B7\u51C6\u4E14\u80FD\u6267\u884C CLI \u65F6\u4F18\u5148 CLI\uFF0C\u5426\u5219\u4F7F\u7528\u5BF9\u5E94\u6258\u7BA1 MCP\uFF1B\u4E0D\u8981\u6C42\u4E91\u5BBF\u4E3B\u8BD5\u88C5\u3002\u5DF2\u53D7\u7406\u3001\u5F85\u4ED8\u6B3E\u6216\u672A\u77E5\u7ED3\u679C\u53EA\u6CBF\u539F\u8EAB\u4EFD\u3001\u5165\u53E3\u548C\u4E1A\u52A1\u5F15\u7528\u6062\u590D\uFF0C\u4E0D\u6362\u8DEF\u91CD\u53D1\u3002",
16855
16935
  next: null,
16856
16936
  recovery: []
16857
16937
  }, { ...options, ...config.agentType ? { agentType: config.agentType } : {} });
@@ -17197,7 +17277,7 @@ async function runCatalogList(backend, options = {}) {
17197
17277
  writeCommandEnvelope2({
17198
17278
  status: empty ? "catalog_empty" : "listed",
17199
17279
  result: { catalog_version: manifest.version, services: services2 },
17200
- instruction: empty ? "\u5F53\u524D\u6CA1\u6709\u5DF2\u53D1\u5E03\u670D\u52A1\uFF1B\u672C\u6B21\u76EE\u5F55\u8BFB\u53D6\u7ED3\u675F\uFF0C\u4E0D\u731C\u6D4B\u670D\u52A1\u6216\u81EA\u52A8\u91CD\u8BD5\u3002" : options.locale === "en" ? "Explain the service, its operations and pricing; start only the declared operation matching the human request." : "\u5411\u7528\u6237\u89E3\u91CA\u4E3B\u670D\u52A1\u3001\u8F85\u52A9\u6B65\u9AA4\u548C\u4EF7\u683C\uFF1B\u5F97\u5230\u7528\u6237\u610F\u56FE\u540E\u518D\u542F\u52A8\u5BF9\u5E94 service_id\u3002",
17280
+ instruction: empty ? "\u5F53\u524D Services \u76EE\u5F55\u6CA1\u6709\u5DF2\u53D1\u5E03\u670D\u52A1\uFF0C\u4E0D\u4EE3\u8868 API Hub \u6CA1\u6709\u5339\u914D\u9879\uFF1BAPI/\u6570\u636E\u4EFB\u52A1\u4F7F\u7528 itpay api discover\u3002\u672C\u6B21\u8BFB\u53D6\u7ED3\u675F\uFF0C\u4E0D\u731C\u6D4B\u670D\u52A1\u6216\u81EA\u52A8\u91CD\u8BD5\u3002" : options.locale === "en" ? "This is the Services catalog, not the API Hub catalog. API/data tasks use itpay api discover. Explain the service, operations and pricing; start only a matching declared operation." : "\u5411\u7528\u6237\u89E3\u91CA\u4E3B\u670D\u52A1\u3001\u8F85\u52A9\u6B65\u9AA4\u548C\u4EF7\u683C\uFF1B\u8FD9\u662F Services \u76EE\u5F55\uFF0C\u4E0D\u542B API Hub \u76EE\u5F55\u3002API/\u7ED3\u6784\u5316\u6570\u636E\u7528 itpay api discover\uFF0C\u4E0D\u80FD\u56E0\u8FD9\u91CC\u672A\u5217\u51FA\u5C31\u5224\u5B9A ItPay \u65E0\u6B64\u80FD\u529B\u3002\u529E\u7406\u3001\u4EA4\u4ED8\u548C\u552E\u540E\u6309\u5339\u914D\u7684 service_id\u3001\u64CD\u4F5C\u53CA\u4EF7\u683C\u7EE7\u7EED\u3002",
17201
17281
  next: services2.length === 1 && firstServiceID ? { command: `itpay services start ${firstServiceID}${jsonFlag}`, reason: "\u4EC5\u5F53\u5F53\u524D\u670D\u52A1\u7B26\u5408\u7528\u6237\u8BF7\u6C42\u65F6\u8BFB\u53D6\u8F93\u5165\u5408\u540C\uFF1B\u4E0D\u8868\u793A\u8D2D\u4E70\u540C\u610F" } : null,
17202
17282
  recovery: []
17203
17283
  }, {
@@ -19040,19 +19120,28 @@ __name(resumeEnvelope, "resumeEnvelope");
19040
19120
 
19041
19121
  // src/main.ts
19042
19122
  var program2 = new Command();
19043
- program2.name("itpay").description("V3 ItPay CLI \u2014 buy services, review orders, and read human-authorized purchased content").option("--agent-type <type>", "agent runtime type used for device enrollment and client-specific guidance").version(CLI_VERSION2).addHelpText("after", `
19123
+ program2.name("itpay").description("ItPay CLI \u2014 Services, API Hub, orders, and human-authorized content").option("--agent-type <type>", "agent runtime type used for device enrollment and client-specific guidance").version(CLI_VERSION2).addHelpText("after", `
19044
19124
  Agent quick start:
19045
19125
  1. Use one official package in the host's permitted persistent npm location.
19046
19126
  2. Run: itpay setup --agent-type <actual_type> --json
19047
- 3. Read and enable the returned same-package Skill before business commands.
19127
+ 3. Read the same-package Services or API Skill for the requested outcome.
19128
+ Keep the existing launcher, actual Agent Type and state directory across sessions.
19129
+ Setup checks Services device/account status, not API Hub authorization.
19048
19130
 
19049
19131
  Common human intents:
19050
- New service or query catalog list
19132
+ API or structured data skill show itpay-api --json \u2192 api discover
19133
+ Service handling/delivery skill show itpay --json \u2192 catalog list
19051
19134
  Previously purchased item vault list
19052
19135
  Purchase history orders
19053
19136
  Delivery or refund problem resume the known Order or Refund
19054
19137
  Review a completed service feedback submit
19055
19138
 
19139
+ New tasks: prefer the official pinned CLI only when this host permits and can
19140
+ execute it; otherwise use the corresponding hosted Services or Hub MCP. A cloud
19141
+ host is not required to install software. Route by deliverable, not "query".
19142
+ Accepted, payment-pending or unknown tasks keep their original identity, entry
19143
+ and request/run/order; never switch entries to resubmit.
19144
+
19056
19145
  The Agent runs commands. Ask the human only to choose, authorize, pay, provide
19057
19146
  required contact details, or confirm a refund. Never expose commands or internal IDs.
19058
19147
  `);
@@ -19458,8 +19547,8 @@ program2.command("next").description("Show the next recommended agent action fro
19458
19547
  });
19459
19548
  }
19460
19549
  });
19461
- var catalogCmd = program2.command("catalog").description("Browse V3 service catalog");
19462
- catalogCmd.command("list").description("List all available services from the published catalog manifest").option("--json", "output JSON instead of terminal text").action(async (options) => {
19550
+ var catalogCmd = program2.command("catalog").description("Browse the Services catalog (API data uses api discover)");
19551
+ catalogCmd.command("list").description("List published Services; this is not the API Hub catalog").option("--json", "output JSON instead of terminal text").action(async (options) => {
19463
19552
  const backend = newBackendClient(loadConfig());
19464
19553
  try {
19465
19554
  await requirePlatformCompatibility(backend);
@@ -1,4 +1,4 @@
1
- const CLI_VERSION = "2.1.60";
1
+ const CLI_VERSION = "2.1.62";
2
2
  const API_CONTRACT_REVISION = "sha256:f20af3780a0e12a79a6ca9507ba65167a4018338495af66d87931e55619b618a";
3
3
  export {
4
4
  API_CONTRACT_REVISION,
@@ -34,9 +34,9 @@
34
34
  "current_flow": [
35
35
  "Use the authorized channel/Backend and host-permitted tool prefix/cache/state directories. Use real dot or muse in those hosts, never codex spoofing. Retain one launcher and its Backend, Agent Type and ITPAY_STATE_DIR for every next/recovery command. Do not change HOME.",
36
36
  "Declare the actual host type via ITPAY_AGENT_TYPE or the global --agent-type option, then run itpay setup --json once after installation/upgrade. Preserve that real declaration, launcher/PATH, Backend and any custom private ITPAY_STATE_DIR for all later commands. Exported values can be inherited by child processes; a new shell may need them again. A one-time setup flag is not persistent configuration. setup_ready means device preparation; login_required is a separate valid account status.",
37
- "Read itpay skill show itpay --json and enable that exact package Skill via the host mechanism. Record the actual path and limitation if the host cannot enable it.",
37
+ "Choose by deliverable: API/data/developer tasks read itpay skill show itpay-api --json; service handling, reports, delivery and aftercare read itpay skill show itpay --json. Enable only the needed same-package Skill via the host mechanism; API tasks do not require Services tutorials. Record the actual path and limitation if the host cannot enable it.",
38
38
  "Do not repeat setup, installation or login for ordinary tasks. A nonzero install is not ready; keep the actual error and follow its current recovery.",
39
- "ITPAY_STATE_DIR selects the private state directory; choose an allowed directory before first enrollment and preserve it. If an existing identity lacks its key or becomes inaccessible, recover access; never rotate identity to regain quota.",
39
+ "ITPAY_STATE_DIR selects the private state directory; reuse the existing allowed directory across new chats. Only before a genuinely separate, authorized first enrollment choose another allowed directory and preserve it. If an existing identity lacks its key or becomes inaccessible, recover access; never rotate identity to regain quota.",
40
40
  "Check install prefix, npm cache, state and receipt writes independently. A writable directory is not proof of persistence across sessions. setup reports Skill readability separately from writing, host discovery and version; do not reinstall during normal tasks.",
41
41
  "When login_required, the returned account_action is optional: use it only for a user-requested login or an account-required feature; do not auto-login or bind for free queries. Missing host declaration is technical input the Agent restores from actual context, not an unknown server authorization or a reason to ask the human to guess a type."
42
42
  ]
@@ -8,6 +8,8 @@ itpay setup --agent-type <actual_type> --json
8
8
 
9
9
  Run once after installation or upgrade. Unsupported/missing type and unavailable same-package Skill fail before network access. This command reads authoritative device/account status using existing authentication; it does not install, launch login or run business commands.
10
10
 
11
- `setup_ready` returns `cli_version`, `backend_url`, `agent_type`, `device_status: ready`, `account_status: authenticated|login_required`, absolute `skill_path` and package-bound `skill_version`. `next` is null. Read the original Skill and enable it using the host mechanism before business; setup does not claim either happened. Repeated setup preserves identity and existing authorization. Account unknown, missing endpoint or incompatible Backend fails with nonzero exit and the actual reason.
11
+ `setup_ready` returns `cli_version`, `backend_url`, `agent_type`, `device_status: ready`, `account_status: authenticated|login_required`, absolute `skill_path` and package-bound `skill_version`. `next` is null. `skill_path` remains the Services path for compatibility. Select by deliverable: API/data/developer tasks read `itpay skill show itpay-api --json`; service handling, delivery and aftercare read `itpay skill show itpay --json`. Services account status does not verify Hub authorization. Read the needed original Skill and enable it using the host mechanism before business; setup does not claim either happened. Repeated setup preserves identity and existing authorization. Account unknown, missing endpoint or incompatible Backend fails with nonzero exit and the actual reason.
12
12
 
13
13
  For testing set `ITPAY_BACKEND_URL=https://dev.itpay.ai` on every invocation; production defaults to app.itpay.ai. Do not switch environments to hide failure. `install`, `readyz` and `auth status` remain diagnostic/compatibility commands, not a required initialization chain.
14
+
15
+ Reuse the existing launcher and permitted state directory across chats; a new chat is not a new identity. A genuinely separate identity requires explicit authorization. New tasks prefer the permitted, available official CLI; otherwise use the corresponding hosted MCP. Do not require cloud hosts to attempt installation. Accepted, payment-pending and unknown tasks preserve their original entry and references.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itpay/cli",
3
- "version": "2.1.60",
3
+ "version": "2.1.62",
4
4
  "description": "The ItPay CLI for services, orders, and human-authorized purchased content.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -110,7 +110,7 @@
110
110
  "node": ">=18"
111
111
  },
112
112
  "devDependencies": {
113
- "@itpay/hub-client": "file:dependencies/itpay-hub-client-0.1.0-integration.34f4fc639af5.tgz",
113
+ "@itpay/hub-client": "file:dependencies/itpay-hub-client-0.1.0-integration.b575cbbd6435.tgz",
114
114
  "@modelcontextprotocol/sdk": "^1.29.0",
115
115
  "@types/node": "^22.7.5",
116
116
  "@types/qrcode": "^1.5.5",
@@ -148,5 +148,5 @@
148
148
  "services",
149
149
  "api"
150
150
  ],
151
- "gitHead": "9eb053fdeeb9edecba3310f915096e96fee3b96e"
151
+ "gitHead": "3a37b928152232141542065996bb2c76e748e21e"
152
152
  }
@@ -7,7 +7,7 @@ description: Find or buy ItPay services, plan or book railway travel, read purch
7
7
 
8
8
  展示本人登录、办理或付款入口时,只使用工具返回的官方 HTML 卡、由同一 HTML 截图的官方图片和原官方链接。图片失败或宿主不能展示图片时,给出原链接、用途、当前状态、本人需做的动作及原任务 next;不得自行编码、重画、裁剪二维码,也不得换单或重建授权。
9
9
 
10
- For a new task, prefer the official pinned ItPay CLI when execution is permitted and available in the current host. Install only through the host-permitted official installation path when authorized. Services tasks use the Services Skill; API tasks use the independent API Skill and `itpay api`. CLI calls HTTP APIs directly, never MCP transport. Without permitted CLI capability, use the corresponding ItPay-hosted user Services MCP or Hub MCP and only its actually available tools; ordinary users do not self-host another MCP. Platform-required workflows and explicit connection tests follow the actual available capability. Entry selection never authorizes a permission bypass: preserve the original identity, entry, request/run and current grant after acceptance or an unknown result. Continue across entries only when the owner explicitly supports recovery under the same actual authority; CLI errors never license a substitute transaction or raw HTTP workaround.
10
+ For a new task, prefer the official pinned ItPay CLI when execution is permitted and available in the current host. This does not require a cloud host to try installing software. Route by the requested deliverable, not by the word "query": API calls, structured data (including company fields), and developer tasks use the API Skill and `itpay api discover`; service handling, purchased reports, delivery and aftercare use the Services Skill and its declared service contract. Install only through the host-permitted official installation path when authorized. Services tasks use the Services Skill; API tasks use the independent API Skill and `itpay api`. CLI calls HTTP APIs directly, never MCP transport. Without permitted CLI capability, use the corresponding ItPay-hosted user Services MCP or Hub MCP and only its actually available tools; ordinary users do not self-host another MCP. Platform-required workflows and explicit connection tests follow the actual available capability. Entry selection never authorizes a permission bypass: preserve the original identity, entry, request/run and current grant after acceptance, while waiting for payment/fulfillment/aftercare, or after an unknown result. Continue across entries only when the owner explicitly supports recovery under the same actual authority; CLI errors never license a substitute transaction or raw HTTP workaround.
11
11
 
12
12
  Use the installed `itpay` entry yourself. Understand the human’s complete goal and constraints; preserve the actual Agent Type, Backend and device identity. Installation preparation belongs to `install-and-setup`; after setup, ordinary tasks need no repeated installation, readyz or login checks.
13
13
 
@@ -15,13 +15,13 @@ If this Skill is supplied with `references/itpay-cli-invocation.md`, read it onc
15
15
 
16
16
  ## Runtime and state
17
17
 
18
- Use real `dot` or `muse` in those hosts; never impersonate codex-desktop. Keep the same permitted launcher/PATH, Backend, actual `ITPAY_AGENT_TYPE` (or explicit global `--agent-type`) and private `ITPAY_STATE_DIR` through every command and returned continuation, including auth login/status. Exported values can be inherited; a separate shell may need the same declarations again. A setup-only flag does not persist them. Missing declarations are technical input for the Agent to restore from its real host context, never a reason to guess another host or reset identity. npm prefix/cache, receipt and state must all use host-permitted paths; do not change HOME, clear identity or rotate keys to recover quota. Current write access does not prove cross-session persistence. Skill readability, writing, host discovery and version are separate facts; normal tasks need no reinstall. Cloud execution and user-visible presentation are separate; unknown visibility remains unknown.
18
+ Use real `dot` or `muse` in those hosts; never impersonate codex-desktop. A new chat is not a new identity: reuse the existing permitted state directory. Choose a separate directory only for a genuinely separate, explicitly authorized identity. Keep the same permitted launcher/PATH, Backend, actual `ITPAY_AGENT_TYPE` (or explicit global `--agent-type`) and private `ITPAY_STATE_DIR` through every command and returned continuation, including auth login/status. Exported values can be inherited; a separate shell may need the same declarations again. A setup-only flag does not persist them. Missing declarations are technical input for the Agent to restore from its real host context, never a reason to guess another host or reset identity. npm prefix/cache, receipt and state must all use host-permitted paths; do not change HOME, clear identity or rotate keys to recover quota. Current write access does not prove cross-session persistence. Skill readability, writing, host discovery and version are separate facts; normal tasks need no reinstall. Cloud execution and user-visible presentation are separate; unknown visibility remains unknown.
19
19
 
20
20
  ## One current flow
21
21
 
22
22
  Understand → query → read complete results → select under delegation → obtain only missing genuine consent → prepare one official page → show it immediately → read the original order.
23
23
 
24
- For railway travel, read `itpay docs show rail-booking` once before the first query. That guide owns endpoint understanding, reliable route knowledge versus targeted lookup, the pre-query 2–4 line brief and Exact/Smart choice. Preserve full administrative/place names, dates, party size, station locks and deadlines. For other new services, use `itpay catalog list --json` and the selected published operation/template. For an existing execution, use its current reader; do not start another query.
24
+ For railway travel, read `itpay docs show rail-booking` once before the first query. That guide owns endpoint understanding, reliable route knowledge versus targeted lookup, the pre-query 2–4 line brief and Exact/Smart choice. Preserve full administrative/place names, dates, party size, station locks and deadlines. For other service handling or delivery tasks, use `itpay catalog list --json` and the selected published operation/template. This catalog covers Services only: absence here does not prove an API/data capability is unavailable. API tasks use the independent API Skill and `itpay api discover`. For an existing execution, use its current reader; do not start another query.
25
25
 
26
26
  For purchased content use `itpay vault list --json` (optionally `--query`); for orders use `itpay orders --json` or the returned order reader. Clarify only genuine ambiguity between a new request and an earlier purchase. Explicit multi-service Carts have their separate `cart-checkout` guide; they are not the normal service purchase route.
27
27
 
@@ -7,9 +7,11 @@ description: Discover and invoke ItPay API Hub operations, read usage and wallet
7
7
 
8
8
  展示本人登录、办理或付款入口时,只使用工具返回的官方 HTML 卡、由同一 HTML 截图的官方图片和原官方链接。图片失败或宿主不能展示图片时,给出原链接、用途、当前状态、本人需做的动作及原任务 next;不得自行编码、重画、裁剪二维码,也不得换单或重建授权。
9
9
 
10
- For a new task, prefer the official pinned ItPay CLI when execution is permitted and available in the current host. Install only through the host-permitted official installation path when authorized. Services tasks use the Services Skill; API tasks use the independent API Skill and `itpay api`. CLI calls HTTP APIs directly, never MCP transport. Without permitted CLI capability, use the corresponding ItPay-hosted user Services MCP or Hub MCP and only its actually available tools; ordinary users do not self-host another MCP. Platform-required workflows and explicit connection tests follow the actual available capability. Entry selection never authorizes a permission bypass: preserve the original identity, entry, request/run and current grant after acceptance or an unknown result. Continue across entries only when the owner explicitly supports recovery under the same actual authority; CLI errors never license a substitute transaction or raw HTTP workaround.
10
+ For a new task, prefer the official pinned ItPay CLI when execution is permitted and available in the current host. This does not require a cloud host to try installing software. Route by the requested deliverable, not by the word "query": API calls, structured data (including company fields), and developer tasks use the API Skill and `itpay api discover`; service handling, purchased reports, delivery and aftercare use the Services Skill and its declared service contract. Install only through the host-permitted official installation path when authorized. Services tasks use the Services Skill; API tasks use the independent API Skill and `itpay api`. CLI calls HTTP APIs directly, never MCP transport. Without permitted CLI capability, use the corresponding ItPay-hosted user Services MCP or Hub MCP and only its actually available tools; ordinary users do not self-host another MCP. Platform-required workflows and explicit connection tests follow the actual available capability. Entry selection never authorizes a permission bypass: preserve the original identity, entry, request/run and current grant after acceptance, while waiting for payment/fulfillment/aftercare, or after an unknown result. Continue across entries only when the owner explicitly supports recovery under the same actual authority; CLI errors never license a substitute transaction or raw HTTP workaround.
11
11
 
12
- Use this Skill for API tasks; Services/railway instructions are not prerequisites. Use the installed pinned launcher and `itpay api --help`; `hub` is its compatibility alias. Keep the actual host/Agent Type, ITPAY_HUB_URL and permitted ITPAY_STATE_DIR across every command/session. Never switch accounts, spoof a host or clear identity to recover quota.
12
+ A new chat is not a new identity: keep the existing permitted state directory and launcher; isolate a different identity only when explicitly authorized. Use this Skill for API tasks; Services/railway instructions are not prerequisites. Use the installed pinned launcher and `itpay api --help`; `hub` is its compatibility alias. Keep the actual host/Agent Type, ITPAY_HUB_URL and permitted ITPAY_STATE_DIR across every command/session. Never switch accounts, spoof a host or clear identity to recover quota.
13
+
14
+ For an explicitly authorized **v4 dev API** task, select `ITPAY_HUB_URL=https://market-v4-dev.itpay.ai` before the first API command and preserve it with the permitted state directory. Its OAuth issuer is `https://auth-v4-dev.itpay.ai`; the CLI selects that issuer for this exact dev Hub unless explicitly configured otherwise. CLI resource is the Hub root, not the hosted MCP `/mcp` URL. For example, after the user selects v4 dev: `ITPAY_HUB_URL=https://market-v4-dev.itpay.ai itpay api connect --json`. Never select or switch dev merely because a request failed, and never infer the API identity from Services configuration. Local defaults and other explicit Hub/issuer configurations remain separate.
13
15
 
14
16
  Connect with the existing `itpay api connect` browser OAuth flow when authentication is required. The human enters verification privately. Existing credentials and task files belong to their endpoint/resource; sharing an ItPay account does not merge OAuth grants, API budgets, Services devices or data ACLs. Never request tokens or codes in chat. Use `api doctor` only for an actual connection problem, not before every task.
15
17