@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.
- package/THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/src/main.js +155 -66
- package/dist/src/state/config.js +1 -1
- package/docs/agent/buyer/install-and-setup.json +2 -2
- package/docs/cli-reference/commands/setup.md +3 -1
- package/package.json +3 -3
- package/skills/itpay/SKILL.md +3 -3
- package/skills/itpay-api/SKILL.md +4 -2
package/THIRD-PARTY-NOTICES.txt
CHANGED
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." :
|
|
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
|
|
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
|
-
|
|
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
|
|
5750
|
-
store.update(task.request_id, { status:
|
|
5751
|
-
renderRun(
|
|
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
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
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
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
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(
|
|
5848
|
+
__name(dispatchOriginalTask, "dispatchOriginalTask");
|
|
5785
5849
|
function renderRun(rec, jsonOutput, note) {
|
|
5786
|
-
const charged = rec.actual_charge ? atomsToYuan(rec.actual_charge.amount_atoms) : "\
|
|
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" ? `\
|
|
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
|
|
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
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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 = "
|
|
16642
|
-
var CANONICAL_API_SKILL_SHA256 = "
|
|
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\
|
|
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\
|
|
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\
|
|
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\
|
|
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("
|
|
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
|
|
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
|
-
|
|
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
|
|
19462
|
-
catalogCmd.command("list").description("List
|
|
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);
|
package/dist/src/state/config.js
CHANGED
|
@@ -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
|
-
"
|
|
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;
|
|
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.
|
|
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.
|
|
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": "
|
|
151
|
+
"gitHead": "3a37b928152232141542065996bb2c76e748e21e"
|
|
152
152
|
}
|
package/skills/itpay/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|