@itpay/cli 2.1.61 → 2.1.63

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");
@@ -3741,7 +3741,7 @@ __name(safeParseJson, "safeParseJson");
3741
3741
 
3742
3742
  // src/state/hub_credentials.ts
3743
3743
  import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
3744
- import { chmodSync as chmodSync2, existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
3744
+ import { chmodSync as chmodSync2, existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
3745
3745
  import { dirname as dirname2, resolve } from "node:path";
3746
3746
 
3747
3747
  // src/state/file_lock.ts
@@ -3963,12 +3963,7 @@ function importHubKeyUnlocked(apiKey, baseURL, env = process.env) {
3963
3963
  api_key: apiKey,
3964
3964
  created_at: (/* @__PURE__ */ new Date()).toISOString()
3965
3965
  };
3966
- mkdirSync2(dirname2(path2), { recursive: true, mode: 448 });
3967
- const tmp = `${path2}.${randomUUID2()}.tmp`;
3968
- writeFileSync2(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", mode: 384 });
3969
- chmodSync2(tmp, 384);
3970
- renameSync(tmp, path2);
3971
- chmodSync2(path2, 384);
3966
+ saveHubProfileUnlocked(file.profiles["default"], env);
3972
3967
  return { key_prefix: apiKey.slice(0, 14) };
3973
3968
  }
3974
3969
  __name(importHubKeyUnlocked, "importHubKeyUnlocked");
@@ -4011,21 +4006,61 @@ function storeHubSessionUnlocked(accessToken, refreshToken, expiresIn, subject,
4011
4006
  token_url: hubOAuthConfig(env).tokenURL,
4012
4007
  created_at: (/* @__PURE__ */ new Date()).toISOString()
4013
4008
  };
4014
- mkdirSync2(dirname2(path2), { recursive: true, mode: 448 });
4015
- const tmp = `${path2}.${randomUUID2()}.tmp`;
4016
- writeFileSync2(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", mode: 384 });
4017
- chmodSync2(tmp, 384);
4018
- renameSync(tmp, path2);
4019
- chmodSync2(path2, 384);
4009
+ saveHubProfileUnlocked(file.profiles["default"], env);
4020
4010
  }
4021
4011
  __name(storeHubSessionUnlocked, "storeHubSessionUnlocked");
4012
+ function saveHubProfileUnlocked(profile, env) {
4013
+ const path2 = hubCredentialsPath(env);
4014
+ const tmp = `${path2}.${randomUUID2()}.tmp`;
4015
+ try {
4016
+ const file = existsSync(path2) ? JSON.parse(readFileSync2(path2, "utf8")) : { schema_version: "itpay.hub_credentials.v1", profiles: {} };
4017
+ file.profiles.default = profile;
4018
+ mkdirSync2(dirname2(path2), { recursive: true, mode: 448 });
4019
+ writeFileSync2(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", flag: "wx", mode: 384 });
4020
+ chmodSync2(tmp, 384);
4021
+ renameSync(tmp, path2);
4022
+ } catch {
4023
+ throw new Error("credential_persistence_failed: could not save the original connection; stop and check private storage before retrying");
4024
+ } finally {
4025
+ try {
4026
+ unlinkSync2(tmp);
4027
+ } catch {
4028
+ }
4029
+ }
4030
+ }
4031
+ __name(saveHubProfileUnlocked, "saveHubProfileUnlocked");
4032
+ async function probeHubIdentity(resource, accessToken) {
4033
+ let response;
4034
+ try {
4035
+ response = await fetch(`${resource}/v1/me`, {
4036
+ headers: { Authorization: `Bearer ${accessToken}`, "X-ItPay-OAuth-Resource": resource },
4037
+ signal: AbortSignal.timeout(1e4)
4038
+ });
4039
+ } catch {
4040
+ throw new Error("connection_verification_pending: identity check unavailable; preserve the original connection and references, do not reconnect");
4041
+ }
4042
+ if (!response.ok) {
4043
+ if (response.status === 401 || response.status === 403) throw new Error("authorization_required: original connection identity rejected");
4044
+ throw new Error("connection_verification_pending: identity check unavailable; preserve the original connection and references, do not reconnect");
4045
+ }
4046
+ try {
4047
+ const identity = await response.json();
4048
+ if (!identity || typeof identity !== "object" || Array.isArray(identity)) throw new Error();
4049
+ const me = identity;
4050
+ if (typeof me.buyer_id !== "string" || !me.buyer_id || typeof me.consumer_id !== "string" || !me.consumer_id) throw new Error();
4051
+ return { buyer_id: me.buyer_id, consumer_id: me.consumer_id };
4052
+ } catch {
4053
+ throw new Error("connection_verification_pending: identity response invalid; preserve the original connection and references, do not reconnect");
4054
+ }
4055
+ }
4056
+ __name(probeHubIdentity, "probeHubIdentity");
4022
4057
  function storedHubToken(env = process.env) {
4023
4058
  const path2 = hubCredentialsPath(env);
4024
4059
  if (!existsSync(path2)) return void 0;
4025
4060
  try {
4026
4061
  const file = JSON.parse(readFileSync2(path2, "utf8"));
4027
4062
  const p = file.profiles["default"];
4028
- if (!p?.access_token) return void 0;
4063
+ if (!p?.access_token || p.identity_verification_pending) return void 0;
4029
4064
  if (p.expires_at && Date.parse(p.expires_at) <= Date.now()) return void 0;
4030
4065
  return p.access_token;
4031
4066
  } catch {
@@ -4043,31 +4078,68 @@ async function connectedHubToken(env = process.env, rejectedToken) {
4043
4078
  return withAsyncFileLock(`${hubCredentialsPath(env)}.refresh.lock`, async () => {
4044
4079
  const p = storedHubProfile(env);
4045
4080
  if (!p?.access_token || !p.subject) throw new Error("authorization_required: reconnect ItPay");
4046
- const refreshAt = p.refresh_after ? Date.parse(p.refresh_after) : Date.parse(p.expires_at ?? "") - 3e4;
4047
- if (p.access_token !== rejectedToken && refreshAt > Date.now()) return p.access_token;
4048
4081
  const cfg = hubOAuthConfig(env);
4049
- if (!p.refresh_token || p.base_url !== cfg.resource || p.token_url !== cfg.tokenURL || p.client_id !== cfg.clientID) {
4082
+ if (p.base_url !== cfg.resource || p.token_url !== cfg.tokenURL || p.client_id !== cfg.clientID || !p.consumer_id) {
4050
4083
  throw new Error("authorization_required: connection configuration changed");
4051
4084
  }
4052
- const response = await fetch(p.token_url, {
4053
- method: "POST",
4054
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
4055
- body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: p.refresh_token, client_id: p.client_id, resource: cfg.resource }),
4056
- signal: AbortSignal.timeout(1e4)
4057
- });
4058
- if (!response.ok) throw new Error("authorization_required: connection refresh rejected");
4059
- const token = await response.json();
4060
- if (!token.access_token || token.token_type?.toLowerCase() !== "bearer" || !Number.isFinite(token.expires_in) || token.expires_in <= 0) {
4061
- throw new Error("authorization_required: invalid refresh response");
4062
- }
4063
- const who = await fetch(`${cfg.resource}/v1/me`, { headers: { Authorization: `Bearer ${token.access_token}` }, signal: AbortSignal.timeout(1e4) });
4064
- if (!who.ok) throw new Error("authorization_required: refreshed identity rejected");
4065
- const identity = await who.json();
4066
- if (identity.buyer_id !== p.subject || identity.consumer_id && identity.consumer_id !== p.consumer_id) {
4085
+ const refreshAt = p.refresh_after ? Date.parse(p.refresh_after) : Date.parse(p.expires_at ?? "") - 3e4;
4086
+ if (!p.identity_verification_pending && p.access_token !== rejectedToken && refreshAt > Date.now()) return p.access_token;
4087
+ let candidate = p;
4088
+ if (!p.identity_verification_pending || !(Date.parse(p.expires_at ?? "") > Date.now())) {
4089
+ if (!p.refresh_token) throw new Error("authorization_required: reconnect the original ItPay connection");
4090
+ let response;
4091
+ try {
4092
+ response = await fetch(p.token_url, {
4093
+ method: "POST",
4094
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
4095
+ body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: p.refresh_token, client_id: p.client_id, resource: cfg.resource }),
4096
+ signal: AbortSignal.timeout(1e4)
4097
+ });
4098
+ } catch {
4099
+ throw new Error("connection_verification_pending: refresh outcome unknown; preserve the original connection and references, do not repeat authorization or business requests");
4100
+ }
4101
+ if (!response.ok) {
4102
+ let rejected = response.status === 401 || response.status === 403;
4103
+ if (response.status === 400) {
4104
+ try {
4105
+ const problem = await response.json();
4106
+ rejected = ["invalid_grant", "invalid_client", "unauthorized_client"].includes(problem?.error ?? "");
4107
+ } catch {
4108
+ }
4109
+ }
4110
+ if (rejected) throw new Error("authorization_required: connection refresh rejected");
4111
+ throw new Error("connection_verification_pending: refresh unavailable; preserve the original connection and references");
4112
+ }
4113
+ let token;
4114
+ try {
4115
+ token = await response.json();
4116
+ } catch {
4117
+ throw new Error("connection_verification_pending: invalid refresh response; preserve the original connection and references");
4118
+ }
4119
+ if (!token || typeof token.access_token !== "string" || !token.access_token || typeof token.token_type !== "string" || token.token_type.toLowerCase() !== "bearer" || typeof token.expires_in !== "number" || !Number.isFinite(token.expires_in) || token.expires_in <= 0 || (!Number.isFinite(Date.now() + token.expires_in * 1e3) || Date.now() + token.expires_in * 1e3 > 864e13) || token.refresh_token !== void 0 && (typeof token.refresh_token !== "string" || !token.refresh_token)) {
4120
+ throw new Error("connection_verification_pending: invalid refresh response; preserve the original connection and references");
4121
+ }
4122
+ const now = Date.now();
4123
+ candidate = {
4124
+ ...p,
4125
+ access_token: token.access_token,
4126
+ refresh_token: token.refresh_token ?? p.refresh_token,
4127
+ expires_at: new Date(now + token.expires_in * 1e3).toISOString(),
4128
+ refresh_after: new Date(now + token.expires_in * 1e3 - Math.min(3e4, Math.max(100, token.expires_in * 100))).toISOString(),
4129
+ identity_verification_pending: true
4130
+ };
4131
+ saveHubProfileUnlocked(candidate, env);
4132
+ }
4133
+ const identity = await probeHubIdentity(cfg.resource, candidate.access_token);
4134
+ if (identity.buyer_id !== p.subject || identity.consumer_id !== p.consumer_id) {
4067
4135
  throw new Error("authorization_required: refreshed identity changed");
4068
4136
  }
4069
- storeHubSessionUnlocked(token.access_token, token.refresh_token ?? p.refresh_token, token.expires_in, p.subject, cfg.resource, env, p.consumer_id);
4070
- return token.access_token;
4137
+ if (!(Date.parse(candidate.expires_at ?? "") > Date.now())) {
4138
+ throw new Error("connection_verification_pending: token expired during identity check; preserve the original connection and references");
4139
+ }
4140
+ delete candidate.identity_verification_pending;
4141
+ saveHubProfileUnlocked(candidate, env);
4142
+ return candidate.access_token;
4071
4143
  });
4072
4144
  }
4073
4145
  __name(connectedHubToken, "connectedHubToken");
@@ -4095,13 +4167,14 @@ function loadHubConfig(env = process.env) {
4095
4167
  }
4096
4168
  __name(loadHubConfig, "loadHubConfig");
4097
4169
  function toSdkConfig(cfg) {
4170
+ const base = { baseUrl: cfg.baseURL, resource: cfg.baseURL.replace(/\/+$/, "") };
4098
4171
  if (cfg.bearerToken) {
4099
- return { baseUrl: cfg.baseURL, token: cfg.bearerToken };
4172
+ return { ...base, token: cfg.bearerToken };
4100
4173
  }
4101
4174
  if (cfg.apiKey) {
4102
- return { baseUrl: cfg.baseURL, token: cfg.apiKey, apiKeyHeader: "X-ItPay-Key" };
4175
+ return { ...base, token: cfg.apiKey, apiKeyHeader: "X-ItPay-Key" };
4103
4176
  }
4104
- return { baseUrl: cfg.baseURL };
4177
+ return base;
4105
4178
  }
4106
4179
  __name(toSdkConfig, "toSdkConfig");
4107
4180
  var HubClient2 = class {
@@ -4167,14 +4240,14 @@ var HubClient2 = class {
4167
4240
  let token;
4168
4241
  if (this.cfg.sessionEnv) {
4169
4242
  token = await connectedHubToken(this.cfg.sessionEnv);
4170
- this.sdk = new HubClient({ baseUrl: this.cfg.baseURL, token });
4243
+ this.sdk = new HubClient(toSdkConfig({ ...this.cfg, bearerToken: token }));
4171
4244
  }
4172
4245
  try {
4173
4246
  return await fn();
4174
4247
  } catch (err) {
4175
4248
  if (!(err instanceof HubApiError) || err.status !== 401 || err.envelope.error.code !== "unauthenticated" || !this.cfg.sessionEnv || !token) throw err;
4176
4249
  const refreshed = await connectedHubToken(this.cfg.sessionEnv, token);
4177
- this.sdk = new HubClient({ baseUrl: this.cfg.baseURL, token: refreshed });
4250
+ this.sdk = new HubClient(toSdkConfig({ ...this.cfg, bearerToken: refreshed }));
4178
4251
  return await fn();
4179
4252
  }
4180
4253
  } catch (err) {
@@ -5588,7 +5661,7 @@ function writeCommandEnvelope(value, options = {}) {
5588
5661
  }
5589
5662
  return { ...action, command: [...assignments, qualifyItPayCommand(action.command, declaredAgentType())].join(" ") };
5590
5663
  }, "qualify");
5591
- value = { ...value, next: value.next ? qualify(value.next) : null, recovery: value.recovery.map(qualify).filter((action) => action !== null) };
5664
+ value = { ...value, instruction: value.instruction + " " + routingInstruction(value), next: value.next ? qualify(value.next) : null, recovery: value.recovery.map(qualify).filter((action) => action !== null) };
5592
5665
  const out = options.output ?? ((text2) => {
5593
5666
  process.stdout.write(text2);
5594
5667
  });
@@ -5603,6 +5676,21 @@ function writeCommandEnvelope(value, options = {}) {
5603
5676
  for (const action of value.recovery) out("recovery: " + action.command + "\n when: " + action.reason + "\n");
5604
5677
  }
5605
5678
  __name(writeCommandEnvelope, "writeCommandEnvelope");
5679
+ function hubFailureInstruction(error, fallback) {
5680
+ if (!(error instanceof HttpError)) return fallback;
5681
+ 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";
5682
+ 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";
5683
+ 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";
5684
+ 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";
5685
+ return fallback;
5686
+ }
5687
+ __name(hubFailureInstruction, "hubFailureInstruction");
5688
+ function routingInstruction(value) {
5689
+ const result = value.result && typeof value.result === "object" ? value.result : {};
5690
+ 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 ?? "");
5691
+ 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";
5692
+ }
5693
+ __name(routingInstruction, "routingInstruction");
5606
5694
 
5607
5695
  // src/commands/hub.ts
5608
5696
  function hub() {
@@ -5792,7 +5880,7 @@ var HubTaskRequestError = class extends Error {
5792
5880
  super(error instanceof Error ? error.message : "original Hub request did not return a receipt");
5793
5881
  this.requestID = task.request_id;
5794
5882
  this.references = { request_id: task.request_id, ...task.run_id ? { run_id: task.run_id } : {}, ...task.intent_id ? { intent_id: task.intent_id } : {} };
5795
- this.code = error instanceof HttpError ? error.code : ["authorization_required", "idempotency_conflict", "invalid_state"].find((code) => this.message.startsWith(code + ":")) ?? "hub_request_unknown";
5883
+ this.code = error instanceof HttpError ? error.code : ["authorization_required", "connection_verification_pending", "credential_persistence_failed", "idempotency_conflict", "invalid_state"].find((code) => this.message.startsWith(code + ":")) ?? "hub_request_unknown";
5796
5884
  }
5797
5885
  };
5798
5886
  async function dispatchOriginalTask(client, store, task, options) {
@@ -5832,11 +5920,11 @@ async function dispatchOriginalTask(client, store, task, options) {
5832
5920
  }
5833
5921
  __name(dispatchOriginalTask, "dispatchOriginalTask");
5834
5922
  function renderRun(rec, jsonOutput, note) {
5835
- const charged = rec.actual_charge ? atomsToYuan(rec.actual_charge.amount_atoms) : "\xA50.000000";
5923
+ const charged = rec.actual_charge ? atomsToYuan(rec.actual_charge.amount_atoms) : "\u8D39\u7528\u56DE\u6267\u672A\u63D0\u4F9B";
5836
5924
  writeCommandEnvelope({
5837
5925
  status: rec.execution_state === "succeeded" ? "executed" : rec.execution_state,
5838
- 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 } : {} },
5839
- 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`,
5926
+ 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 } : {} },
5927
+ 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`,
5840
5928
  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" },
5841
5929
  recovery: []
5842
5930
  }, {
@@ -5880,7 +5968,7 @@ async function runHubWallet(options) {
5880
5968
  writeCommandEnvelope({
5881
5969
  status: "ok",
5882
5970
  result: { available: bal.available, held: bal.held },
5883
- instruction: `\u53EF\u7528 ${atomsToYuan(bal.available.amount_atoms)}\uFF0C\u5728\u9014 ${atomsToYuan(bal.held.amount_atoms)}\u3002`,
5971
+ 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`,
5884
5972
  next: null,
5885
5973
  recovery: []
5886
5974
  }, {
@@ -5891,7 +5979,7 @@ async function runHubWallet(options) {
5891
5979
  __name(runHubWallet, "runHubWallet");
5892
5980
  async function runHubUsage(options) {
5893
5981
  const usage = await hub().usage();
5894
- 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: [] }, {
5982
+ 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: [] }, {
5895
5983
  jsonOutput: Boolean(options.jsonOutput),
5896
5984
  plainResult: [`gross ${atomsToYuan(usage.gross_atoms)} refunded ${atomsToYuan(usage.refunded_atoms)} net ${atomsToYuan(usage.net_atoms)} held ${atomsToYuan(usage.held_atoms)}`]
5897
5985
  });
@@ -6162,12 +6250,15 @@ async function runHubConnect(options) {
6162
6250
  plainResult: ["\u6253\u5F00\u6D4F\u89C8\u5668\u5B8C\u6210\u6388\u6743\uFF1A", ` ${authorizeURL}`]
6163
6251
  });
6164
6252
  const tokens = await done;
6165
- const meResponse = await fetch(`${cfg.resource}/v1/me`, {
6166
- headers: { Authorization: `Bearer ${tokens.accessToken}` },
6167
- signal: AbortSignal.timeout(1e4)
6168
- });
6169
- if (!meResponse.ok) throw new Error("authorization_required: could not verify connected identity");
6170
- const me = await meResponse.json();
6253
+ let me;
6254
+ try {
6255
+ me = await probeHubIdentity(cfg.resource, tokens.accessToken);
6256
+ } catch (error) {
6257
+ if (error instanceof Error && error.message.startsWith("connection_verification_pending:")) {
6258
+ throw new Error("connection_not_saved: identity verification unavailable; this connection was not saved and the existing connection was not replaced");
6259
+ }
6260
+ throw error;
6261
+ }
6171
6262
  if (!me.buyer_id || (!me.consumer_id || me.consumer_id !== `oauth:${cfg.clientID}` && !me.consumer_id.startsWith(`oauth:${cfg.clientID}:`))) throw new Error("authorization_required: OAuth consumer mismatch");
6172
6263
  const subject = me.buyer_id;
6173
6264
  storeHubSession(tokens.accessToken, tokens.refreshToken, tokens.expiresIn, subject, cfg.resource, process.env, me.consumer_id);
@@ -6191,12 +6282,12 @@ __name(runHubConnect, "runHubConnect");
6191
6282
 
6192
6283
  // src/commands/api_commands.ts
6193
6284
  function reportCLIError(error, contract) {
6194
- 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";
6285
+ const code = error instanceof HubTaskRequestError ? error.code : error instanceof HttpError ? error.code : error instanceof Error && ["authorization_required", "connection_not_saved", "connection_verification_pending", "credential_persistence_failed"].some((code2) => error.message.startsWith(code2 + ":")) ? error.message.split(":", 1)[0] : contract?.code ?? "command_failed";
6195
6286
  const auth = code === "authorization_required" || code === "unauthenticated";
6196
6287
  const taskID = error instanceof HubTaskRequestError ? error.requestID : void 0;
6197
6288
  const references = error instanceof HubTaskRequestError ? error.references : void 0;
6198
6289
  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;
6199
- 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" : 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") });
6290
+ writeCommandEnvelope({ status: "error", error: { code, message: error instanceof Error ? error.message : String(error) }, ...references ? { result: references } : {}, instruction: code === "connection_not_saved" ? "\u672C\u6B21\u8FDE\u63A5\u6821\u9A8C\u6682\u672A\u5B8C\u6210\uFF0C\u5C1A\u672A\u4FDD\u5B58\uFF1B\u539F\u6709\u8FDE\u63A5\u672A\u66FF\u6362\u3002\u670D\u52A1\u6062\u590D\u540E\u6309\u539F\u914D\u7F6E\u6B63\u5E38 connect\uFF0C\u4FDD\u7559\u539F\u8EAB\u4EFD\u548C\u4EFB\u52A1\uFF0C\u4E0D\u91CD\u53D1\u4E1A\u52A1\u3002" : code === "connection_verification_pending" ? "\u539F\u8FDE\u63A5\u6821\u9A8C\u6682\u672A\u5B8C\u6210\uFF1B\u4FDD\u7559\u539F\u8EAB\u4EFD\u548C\u5F15\u7528\uFF0C\u4E0D\u91CD\u65B0\u6388\u6743\u3001\u4E0D\u91CD\u53D1\u4E1A\u52A1\u3002\u7A0D\u540E\u53EA\u8BFB\u6838\u5BF9\u539F\u4EFB\u52A1\u3002" : code === "credential_persistence_failed" ? "\u539F\u8FDE\u63A5\u672A\u80FD\u5B89\u5168\u843D\u76D8\uFF1B\u505C\u6B62\u91CD\u8BD5\u5E76\u6838\u5BF9\u79C1\u6709\u5B58\u50A8\uFF0C\u4E0D\u6E05\u72B6\u6001\u6216\u6362\u8EAB\u4EFD\u3002" : 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 || code === "connection_not_saved" ? { command: qualifyItPayCommand(`itpay api connect${contract?.jsonOutput ? " --json" : ""}`, declaredAgentType()), reason: code === "connection_not_saved" ? "\u672C\u6B21\u8FDE\u63A5\u672A\u4FDD\u5B58\uFF1B\u6309\u539F\u914D\u7F6E\u5B8C\u6210\u6B63\u5E38\u8FDE\u63A5" : "\u6B63\u5E38\u6388\u6743\u540E\u7EE7\u7EED\u539F\u4EFB\u52A1" } : ["idempotency_conflict", "invalid_state", "forbidden", "publication_changed", "credential_revalidation_required", "credential_persistence_failed"].includes(code) ? null : recover, recovery: auth && recover ? [recover] : contract?.recovery ?? [] }, { jsonOutput: contract?.jsonOutput ?? process.argv.includes("--json") });
6200
6291
  process.exitCode = 1;
6201
6292
  }
6202
6293
  __name(reportCLIError, "reportCLIError");
@@ -6233,7 +6324,7 @@ function registerAPICommands(program3) {
6233
6324
  try {
6234
6325
  await runHubInspect(operationID2, { jsonOutput: Boolean(options.json) });
6235
6326
  } catch (error) {
6236
- reportCLIError(error, { jsonOutput: Boolean(options.json), code: "hub_inspect_failed", instruction: "operation_id \u53EF\u80FD\u672A\u77E5\u6216\u672A\u53D1\u5E03\u3002", recovery: [] });
6327
+ 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: [] });
6237
6328
  }
6238
6329
  });
6239
6330
  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) => {
@@ -6662,7 +6753,7 @@ __name(streamSSE, "streamSSE");
6662
6753
 
6663
6754
  // src/state/device_key.ts
6664
6755
  import { createHash as createHash5, createPrivateKey, createPublicKey, generateKeyPairSync, randomUUID as randomUUID6 } from "node:crypto";
6665
- import { constants, closeSync, fstatSync, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
6756
+ import { constants, closeSync, fstatSync, linkSync, lstatSync as lstatSync2, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
6666
6757
  import { dirname as dirname4 } from "node:path";
6667
6758
  function invalid(code) {
6668
6759
  return Object.assign(new Error(code), { code });
@@ -6714,7 +6805,7 @@ function createDeviceKey(path2, existingIdentity) {
6714
6805
  return canonical;
6715
6806
  } finally {
6716
6807
  try {
6717
- unlinkSync2(temp);
6808
+ unlinkSync3(temp);
6718
6809
  } catch (error) {
6719
6810
  throw Object.assign(error instanceof Error ? error : new Error("Key temporary cleanup failed"), { deviceStateOperation: "cleanup_private_key_temporary", canonicalKeyPublished: canonicalPublished });
6720
6811
  }
@@ -6724,7 +6815,7 @@ __name(createDeviceKey, "createDeviceKey");
6724
6815
 
6725
6816
  // src/state/device_session_cache.ts
6726
6817
  import { createHash as createHash6, randomUUID as randomUUID7 } from "node:crypto";
6727
- import { constants as constants2, closeSync as closeSync2, fstatSync as fstatSync2, linkSync as linkSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync6, openSync as openSync2, readFileSync as readFileSync9, renameSync as renameSync4, readdirSync as readdirSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
6818
+ import { constants as constants2, closeSync as closeSync2, fstatSync as fstatSync2, linkSync as linkSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync6, openSync as openSync2, readFileSync as readFileSync9, renameSync as renameSync4, readdirSync as readdirSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "node:fs";
6728
6819
  import { join as join3 } from "node:path";
6729
6820
  function invalid2(code) {
6730
6821
  return Object.assign(new Error(code), { code });
@@ -6767,7 +6858,7 @@ function writeComplete(path2, text2, createOnly) {
6767
6858
  return true;
6768
6859
  } finally {
6769
6860
  try {
6770
- unlinkSync3(temp);
6861
+ unlinkSync4(temp);
6771
6862
  } catch (error) {
6772
6863
  if (error.code !== "ENOENT") throw error;
6773
6864
  }
@@ -7331,7 +7422,7 @@ __name(checkAuthorizationBudget, "checkAuthorizationBudget");
7331
7422
 
7332
7423
  // src/state/operation_journal.ts
7333
7424
  import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
7334
- import { chmodSync as chmodSync4, existsSync as existsSync4, linkSync as linkSync3, mkdirSync as mkdirSync7, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "node:fs";
7425
+ import { chmodSync as chmodSync4, existsSync as existsSync4, linkSync as linkSync3, mkdirSync as mkdirSync7, readFileSync as readFileSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "node:fs";
7335
7426
  import { basename, resolve as resolve4 } from "node:path";
7336
7427
  var OperationJournal = class {
7337
7428
  constructor(legacyPath) {
@@ -7371,7 +7462,7 @@ var OperationJournal = class {
7371
7462
  }
7372
7463
  } finally {
7373
7464
  try {
7374
- unlinkSync4(temporaryPath);
7465
+ unlinkSync5(temporaryPath);
7375
7466
  } catch (error) {
7376
7467
  if (error.code !== "ENOENT") throw error;
7377
7468
  }
@@ -12164,7 +12255,7 @@ __name(railAftercareOrder, "railAftercareOrder");
12164
12255
 
12165
12256
  // src/state/task_journal.ts
12166
12257
  import { randomUUID as randomUUID10, createHash as createHash10 } from "node:crypto";
12167
- import { existsSync as existsSync5, linkSync as linkSync4, lstatSync as lstatSync5, mkdirSync as mkdirSync9, readFileSync as readFileSync12, readdirSync as readdirSync4, unlinkSync as unlinkSync5, writeFileSync as writeFileSync8 } from "node:fs";
12258
+ import { existsSync as existsSync5, linkSync as linkSync4, lstatSync as lstatSync5, mkdirSync as mkdirSync9, readFileSync as readFileSync12, readdirSync as readdirSync4, unlinkSync as unlinkSync6, writeFileSync as writeFileSync8 } from "node:fs";
12168
12259
  import { join as join4 } from "node:path";
12169
12260
  var PAUSED_STAGES = /* @__PURE__ */ new Set(["login_required", "rate_limited", "quota_paused", "auth_pending", "awaiting_input"]);
12170
12261
  var TERMINAL_STAGES = /* @__PURE__ */ new Set(["completed", "delivered", "issued", "failed", "cancelled", "refunded"]);
@@ -12287,7 +12378,7 @@ var TaskJournal = class {
12287
12378
  linkSync4(temp, target2);
12288
12379
  } finally {
12289
12380
  try {
12290
- unlinkSync5(temp);
12381
+ unlinkSync6(temp);
12291
12382
  } catch (e) {
12292
12383
  if (!object2(e) || e.code !== "ENOENT") throw e;
12293
12384
  }
@@ -16703,8 +16794,8 @@ __name(installDefinition, "installDefinition");
16703
16794
  import { createHash as createHash12 } from "node:crypto";
16704
16795
 
16705
16796
  // src/state/skill_identity.generated.ts
16706
- var CANONICAL_SKILL_SHA256 = "dcbce8347f9ed4a95b89bbd680bbfb2c5308f1081e1af1554f413b950eb902dc";
16707
- var CANONICAL_API_SKILL_SHA256 = "70af9cc2363b1c60174e4159e296b64c183c833a20930e8612c265bb69c238e6";
16797
+ var CANONICAL_SKILL_SHA256 = "4a38087a41ed4b9b6e879726b93bdef99ca67fccd2a0f9837123d5b334b046c0";
16798
+ var CANONICAL_API_SKILL_SHA256 = "dffec781d5053bbdb93ec555ad2b1b4a7cad55c2281a3c9c19597a4a9418bde6";
16708
16799
 
16709
16800
  // src/commands/skill.ts
16710
16801
  import { existsSync as existsSync9, readFileSync as readFileSync16 } from "node:fs";
@@ -16778,7 +16869,7 @@ ${CODEX_WAIT_GUIDANCE}
16778
16869
  const envelope = {
16779
16870
  status: "shown",
16780
16871
  result: { skill: ITPAY_SKILL, content },
16781
- 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",
16872
+ 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",
16782
16873
  next: agentType ? null : { command: "itpay install --json", reason: "\u9009\u62E9\u771F\u5B9E\u4E14\u7A33\u5B9A\u7684 Agent Type" },
16783
16874
  recovery: []
16784
16875
  };
@@ -16842,7 +16933,7 @@ function showAPISkill(options) {
16842
16933
  writeCommandEnvelope2({
16843
16934
  status: "shown",
16844
16935
  result: { skill: "itpay-api", content },
16845
- 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",
16936
+ 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",
16846
16937
  next: null,
16847
16938
  recovery: []
16848
16939
  }, {
@@ -16916,7 +17007,7 @@ async function runSetup(backend, config, skillPath, options = {}) {
16916
17007
  reason: "\u7531\u672C\u4EBA\u5B8C\u6210\u5B98\u65B9\u8D26\u53F7\u6388\u6743\uFF0C\u4E0D\u81EA\u52A8\u767B\u5F55"
16917
17008
  } } : {}
16918
17009
  },
16919
- 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",
17010
+ 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",
16920
17011
  next: null,
16921
17012
  recovery: []
16922
17013
  }, { ...options, ...config.agentType ? { agentType: config.agentType } : {} });
@@ -17262,7 +17353,7 @@ async function runCatalogList(backend, options = {}) {
17262
17353
  writeCommandEnvelope2({
17263
17354
  status: empty ? "catalog_empty" : "listed",
17264
17355
  result: { catalog_version: manifest.version, services: services2 },
17265
- 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",
17356
+ 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",
17266
17357
  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,
17267
17358
  recovery: []
17268
17359
  }, {
@@ -19105,19 +19196,28 @@ __name(resumeEnvelope, "resumeEnvelope");
19105
19196
 
19106
19197
  // src/main.ts
19107
19198
  var program2 = new Command();
19108
- 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", `
19199
+ 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", `
19109
19200
  Agent quick start:
19110
19201
  1. Use one official package in the host's permitted persistent npm location.
19111
19202
  2. Run: itpay setup --agent-type <actual_type> --json
19112
- 3. Read and enable the returned same-package Skill before business commands.
19203
+ 3. Read the same-package Services or API Skill for the requested outcome.
19204
+ Keep the existing launcher, actual Agent Type and state directory across sessions.
19205
+ Setup checks Services device/account status, not API Hub authorization.
19113
19206
 
19114
19207
  Common human intents:
19115
- New service or query catalog list
19208
+ API or structured data skill show itpay-api --json \u2192 api discover
19209
+ Service handling/delivery skill show itpay --json \u2192 catalog list
19116
19210
  Previously purchased item vault list
19117
19211
  Purchase history orders
19118
19212
  Delivery or refund problem resume the known Order or Refund
19119
19213
  Review a completed service feedback submit
19120
19214
 
19215
+ New tasks: prefer the official pinned CLI only when this host permits and can
19216
+ execute it; otherwise use the corresponding hosted Services or Hub MCP. A cloud
19217
+ host is not required to install software. Route by deliverable, not "query".
19218
+ Accepted, payment-pending or unknown tasks keep their original identity, entry
19219
+ and request/run/order; never switch entries to resubmit.
19220
+
19121
19221
  The Agent runs commands. Ask the human only to choose, authorize, pay, provide
19122
19222
  required contact details, or confirm a refund. Never expose commands or internal IDs.
19123
19223
  `);
@@ -19523,8 +19623,8 @@ program2.command("next").description("Show the next recommended agent action fro
19523
19623
  });
19524
19624
  }
19525
19625
  });
19526
- var catalogCmd = program2.command("catalog").description("Browse V3 service catalog");
19527
- catalogCmd.command("list").description("List all available services from the published catalog manifest").option("--json", "output JSON instead of terminal text").action(async (options) => {
19626
+ var catalogCmd = program2.command("catalog").description("Browse the Services catalog (API data uses api discover)");
19627
+ 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) => {
19528
19628
  const backend = newBackendClient(loadConfig());
19529
19629
  try {
19530
19630
  await requirePlatformCompatibility(backend);
@@ -1,4 +1,4 @@
1
- const CLI_VERSION = "2.1.61";
1
+ const CLI_VERSION = "2.1.63";
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.61",
3
+ "version": "2.1.63",
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": "928231fd3c11229cd9116a36fcbf3ff1eef6402f"
151
+ "gitHead": "176112cd3f6ee08a740ae35b9a921d9340d03f10"
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,9 @@ 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
13
 
14
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.
15
15