@itpay/cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -246
- package/bin/itp +24 -57
- package/docs/agent/buyer/cart-checkout.json +1 -1
- package/package.json +1 -4
- package/e2e-local.sh +0 -134
- package/skills/voltagent/SKILL.md +0 -603
- package/smoke.sh +0 -426
package/smoke.sh
DELETED
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env sh
|
|
2
|
-
set -eu
|
|
3
|
-
|
|
4
|
-
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
5
|
-
TMP_HOME=$(mktemp -d "${TMPDIR:-/tmp}/voltagent-itp-home.XXXXXX")
|
|
6
|
-
TMP_PREFIX=$(mktemp -d "${TMPDIR:-/tmp}/voltagent-itp-prefix.XXXXXX")
|
|
7
|
-
MOCK_SERVER_PID=""
|
|
8
|
-
|
|
9
|
-
cleanup() {
|
|
10
|
-
if [ -n "$MOCK_SERVER_PID" ]; then
|
|
11
|
-
kill "$MOCK_SERVER_PID" >/dev/null 2>&1 || true
|
|
12
|
-
fi
|
|
13
|
-
rm -rf "$TMP_HOME" "$TMP_PREFIX"
|
|
14
|
-
}
|
|
15
|
-
trap cleanup EXIT INT TERM
|
|
16
|
-
|
|
17
|
-
mkdir -p "$TMP_HOME/.itp"
|
|
18
|
-
cat >"$TMP_HOME/.itp/credentials.json" <<'JSON'
|
|
19
|
-
{
|
|
20
|
-
"grant_gr_test": {
|
|
21
|
-
"key": "sk-test",
|
|
22
|
-
"grant_id": "gr_test",
|
|
23
|
-
"target": "codex",
|
|
24
|
-
"credential_store": "file",
|
|
25
|
-
"credential_warning": "native credential store unavailable",
|
|
26
|
-
"base_url": "http://localhost:3000",
|
|
27
|
-
"openai_base_url": "http://localhost:3000/openai/v1",
|
|
28
|
-
"anthropic_base_url": "http://localhost:3000/anthropic/v1",
|
|
29
|
-
"gemini_base_url": "http://localhost:3000/gemini/v1beta",
|
|
30
|
-
"models": ["gpt-5.5"],
|
|
31
|
-
"install_profiles": ["claude-code", "codex", "openclaw"]
|
|
32
|
-
},
|
|
33
|
-
"grant_gr_missing_key": {
|
|
34
|
-
"grant_id": "gr_missing_key",
|
|
35
|
-
"target": "codex",
|
|
36
|
-
"credential_store": "macos-keychain",
|
|
37
|
-
"credential_ref": "voltagent:gr_missing_key",
|
|
38
|
-
"base_url": "http://localhost:3000",
|
|
39
|
-
"openai_base_url": "http://localhost:3000/openai/v1",
|
|
40
|
-
"anthropic_base_url": "http://localhost:3000/anthropic/v1",
|
|
41
|
-
"gemini_base_url": "http://localhost:3000/gemini/v1beta",
|
|
42
|
-
"models": ["gpt-5.5"],
|
|
43
|
-
"install_profiles": ["claude-code", "codex", "openclaw"]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
JSON
|
|
47
|
-
chmod 644 "$TMP_HOME/.itp/credentials.json"
|
|
48
|
-
|
|
49
|
-
node --check "$ROOT/bin/itp"
|
|
50
|
-
ITP_PREFIX="$TMP_PREFIX" "$ROOT/install.sh" >/dev/null
|
|
51
|
-
SKILL_PATH=$(HOME="$TMP_HOME" "$ROOT/bin/itp" skill path --role buyer)
|
|
52
|
-
test -f "$SKILL_PATH"
|
|
53
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" skill show --role buyer | grep -q "ItPay Buyer Agent Skill"
|
|
54
|
-
SKILL_JSON=$(HOME="$TMP_HOME" "$ROOT/bin/itp" skill show --role buyer --json)
|
|
55
|
-
printf '%s' "$SKILL_JSON" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.skill !== "itpay-buyer" || json.role !== "buyer" || !json.path || !json.content.includes("Non-Negotiable Rules")) process.exit(1);})'
|
|
56
|
-
LEGACY_SKILL_JSON=$(HOME="$TMP_HOME" "$ROOT/bin/itp" skill show --role voltagent --json)
|
|
57
|
-
printf '%s' "$LEGACY_SKILL_JSON" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.skill !== "voltagent" || !json.content.includes("VoltaGent / ITPay Agent Runbook")) process.exit(1);})'
|
|
58
|
-
INSTALLED_SKILL_PATH=$(HOME="$TMP_HOME" "$TMP_PREFIX/bin/itp" skill path --role buyer)
|
|
59
|
-
test -f "$INSTALLED_SKILL_PATH"
|
|
60
|
-
HOME="$TMP_HOME" "$TMP_PREFIX/bin/itp" skill show --role buyer | grep -q "ItPay Buyer Agent Skill"
|
|
61
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" --help >/dev/null
|
|
62
|
-
HELP=$(HOME="$TMP_HOME" "$ROOT/bin/itp" --help)
|
|
63
|
-
printf '%s' "$HELP" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (!json.commands.includes("keys rotate --grant <grant_id>") || !json.commands.includes("checkout create --plan credit-300 --method alipay --idempotency-key <uuid>") || !json.commands.includes("checkout list --limit 20") || !json.commands.includes("setup --credits 100 --method alipay") || !json.commands.includes("setup --credits 100 --target codex --method alipay --install-runtime") || !json.commands.includes("status --json") || !json.commands.includes("resume --json") || !json.commands.includes("skill show")) process.exit(1);})'
|
|
64
|
-
printf '%s' "$HELP" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); for (const command of ["buy var_pubg_couple_skin_cny20 --sandbox --email buyer@example.com --phone +8613800000000 --json","buyer cart create --variant var_pubg_couple_skin_cny20 --json","buyer checkout create --cart <cart_id> --method alipay --email buyer@example.com --phone +8613800000000 --json","buyer payment wait <payment_intent_id> --json","buyer payment refresh-qr <payment_intent_id> --reason order-not-found --json","buyer deliveries list --checkout <checkout_id> --json","buyer vault grants list --checkout <checkout_id> --json","buyer vault grants read <agent_read_grant_id> --json","buyer vault read --order <order_id> --artifact <vault_artifact_id> --json","docs show quickstart --role buyer --json","ops sandbox worker run-once --json"]) { if (!json.commands.includes(command)) process.exit(1); }})'
|
|
65
|
-
DOCS_LIST=$(HOME="$TMP_HOME" "$ROOT/bin/itp" docs list --role buyer --json)
|
|
66
|
-
printf '%s' "$DOCS_LIST" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.schema_version !== "itp.agent_doc_index.v1" || !json.topics.some((topic)=>topic.topic==="cart-checkout")) process.exit(1);})'
|
|
67
|
-
DOCS_SHOW=$(HOME="$TMP_HOME" "$ROOT/bin/itp" docs show quickstart --role buyer --json)
|
|
68
|
-
printf '%s' "$DOCS_SHOW" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.topic !== "quickstart" || !Array.isArray(json.next_docs) || !json.next_docs.length) process.exit(1);})'
|
|
69
|
-
DOCS_SEARCH=$(HOME="$TMP_HOME" "$ROOT/bin/itp" docs search "付款 等待" --role buyer --json)
|
|
70
|
-
printf '%s' "$DOCS_SEARCH" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (!json.matches.some((match)=>match.topic==="payment-wait")) process.exit(1);})'
|
|
71
|
-
BUYER_AUTH_STATUS=$(HOME="$TMP_HOME" "$ROOT/bin/itp" buyer auth status --json)
|
|
72
|
-
printf '%s' "$BUYER_AUTH_STATUS" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.schema_version !== "itp.buyer.v1" || json.auth_required_for_discovery !== false) process.exit(1); if (data.toLowerCase().includes("ops-token") || data.toLowerCase().includes("sandbox_ops_token")) process.exit(1);})'
|
|
73
|
-
SNAPSHOT_VERSION_TRAP=$(HOME="$TMP_HOME" "$ROOT/bin/itp" buyer shelf snapshot --version dummy --json 2>/dev/null || true)
|
|
74
|
-
if printf '%s' "$SNAPSHOT_VERSION_TRAP" | grep -q '"version"'; then
|
|
75
|
-
echo "buyer shelf snapshot --version was intercepted by top-level version handler" >&2
|
|
76
|
-
exit 1
|
|
77
|
-
fi
|
|
78
|
-
CHECKOUT_STATUS_TRAP=$(HOME="$TMP_HOME" "$ROOT/bin/itp" buyer checkout status --json 2>&1 >/dev/null || true)
|
|
79
|
-
printf '%s' "$CHECKOUT_STATUS_TRAP" | grep -q "checkout_id is required"
|
|
80
|
-
MOCK_LOG="$TMP_HOME/mock-core-requests.jsonl"
|
|
81
|
-
MOCK_PORT_FILE="$TMP_HOME/mock-core-port"
|
|
82
|
-
cat >"$TMP_HOME/mock-core.mjs" <<'JS'
|
|
83
|
-
import fs from "node:fs";
|
|
84
|
-
import http from "node:http";
|
|
85
|
-
|
|
86
|
-
const logFile = process.env.MOCK_LOG;
|
|
87
|
-
const portFile = process.env.MOCK_PORT_FILE;
|
|
88
|
-
|
|
89
|
-
function writeJSON(res, status, payload) {
|
|
90
|
-
res.writeHead(status, {"Content-Type": "application/json"});
|
|
91
|
-
res.end(JSON.stringify(payload));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function readBody(req) {
|
|
95
|
-
return new Promise((resolve) => {
|
|
96
|
-
let data = "";
|
|
97
|
-
req.on("data", (chunk) => {
|
|
98
|
-
data += chunk;
|
|
99
|
-
});
|
|
100
|
-
req.on("end", () => {
|
|
101
|
-
if (!data) return resolve({});
|
|
102
|
-
try {
|
|
103
|
-
resolve(JSON.parse(data));
|
|
104
|
-
} catch {
|
|
105
|
-
resolve({raw: data});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const product = {
|
|
112
|
-
operation: "get_product",
|
|
113
|
-
product: {
|
|
114
|
-
id: "cat_pubg_sandbox_topup",
|
|
115
|
-
title: "PUBG Mobile Sandbox Top-Up",
|
|
116
|
-
description: "Sandbox service for ItPay end-to-end buyer testing.",
|
|
117
|
-
selected: {variant_id: "var_pubg_couple_skin_cny20", catalog_version: "catv_pubg_sandbox_20260609"},
|
|
118
|
-
metadata: {
|
|
119
|
-
"ai.itpay.catalog_version": "catv_pubg_sandbox_20260609",
|
|
120
|
-
"ai.itpay.required_profile_fields": ["email", "phone"]
|
|
121
|
-
},
|
|
122
|
-
variants: [{
|
|
123
|
-
id: "var_pubg_couple_skin_cny20",
|
|
124
|
-
title: "Couple Skin Pack",
|
|
125
|
-
description: "Low-cost couple skin sandbox pack.",
|
|
126
|
-
price: {amount: 2000, currency: "CNY"},
|
|
127
|
-
availability: {status: "available", available: true},
|
|
128
|
-
metadata: {
|
|
129
|
-
"ai.itpay.offer_id": "offer_pubg_couple_skin_cny20",
|
|
130
|
-
"ai.itpay.catalog_version": "catv_pubg_sandbox_20260609",
|
|
131
|
-
"ai.itpay.required_profile_fields": ["email", "phone"]
|
|
132
|
-
}
|
|
133
|
-
}, {
|
|
134
|
-
id: "var_pubg_deluxe_skin_cny40",
|
|
135
|
-
title: "Deluxe Skin Pack",
|
|
136
|
-
description: "Higher-value deluxe sandbox pack.",
|
|
137
|
-
price: {amount: 4000, currency: "CNY"},
|
|
138
|
-
availability: {status: "available", available: true},
|
|
139
|
-
metadata: {
|
|
140
|
-
"ai.itpay.offer_id": "offer_pubg_deluxe_skin_cny40",
|
|
141
|
-
"ai.itpay.catalog_version": "catv_pubg_sandbox_20260609",
|
|
142
|
-
"ai.itpay.required_profile_fields": ["email", "phone"]
|
|
143
|
-
}
|
|
144
|
-
}]
|
|
145
|
-
},
|
|
146
|
-
messages: []
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const cart = {
|
|
150
|
-
operation: "create_cart",
|
|
151
|
-
id: "cart_mock_pubg",
|
|
152
|
-
cart_id: "cart_mock_pubg",
|
|
153
|
-
status: "active",
|
|
154
|
-
currency: "CNY",
|
|
155
|
-
amount: 2000,
|
|
156
|
-
line_items: [{
|
|
157
|
-
id: "cli_mock_line",
|
|
158
|
-
item: {
|
|
159
|
-
id: "var_pubg_couple_skin_cny20",
|
|
160
|
-
title: "Couple Skin Pack",
|
|
161
|
-
catalog_item_id: "cat_pubg_sandbox_topup",
|
|
162
|
-
catalog_variant_id: "var_pubg_couple_skin_cny20",
|
|
163
|
-
offer_id: "offer_pubg_couple_skin_cny20",
|
|
164
|
-
catalog_version: "catv_pubg_sandbox_20260609",
|
|
165
|
-
price: {amount: 2000, currency: "CNY"}
|
|
166
|
-
},
|
|
167
|
-
quantity: 1,
|
|
168
|
-
amount: 2000,
|
|
169
|
-
currency: "CNY"
|
|
170
|
-
}],
|
|
171
|
-
checkout_handoff: {cart_id: "cart_mock_pubg", checkout_path: "/api/ucp/v1/checkouts"},
|
|
172
|
-
agent_next_actions: ["create_checkout_from_cart"],
|
|
173
|
-
sensitive_redacted: true
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
const catalogSearch = {
|
|
177
|
-
operation: "search_catalog",
|
|
178
|
-
query: "企业工商信息 查询",
|
|
179
|
-
products: [{
|
|
180
|
-
id: "cat_itpay_enterprise_precise_lookup",
|
|
181
|
-
title: "ItPay 自营企业工商数据精准查询",
|
|
182
|
-
description: "按完整企业名称或统一社会信用代码查询中国大陆企业工商登记资料。",
|
|
183
|
-
categories: ["business_data_api", "company_lookup"],
|
|
184
|
-
price_range: {min: {amount: 50, currency: "CNY"}, max: {amount: 50, currency: "CNY"}},
|
|
185
|
-
variants: [{
|
|
186
|
-
id: "var_itpay_enterprise_precise_lookup_cny05",
|
|
187
|
-
title: "ItPay 自营企业工商数据精准查询 单次查询",
|
|
188
|
-
price: {amount: 50, currency: "CNY"},
|
|
189
|
-
availability: {status: "available", available: true},
|
|
190
|
-
metadata: {
|
|
191
|
-
"ai.itpay.offer_id": "offer_itpay_enterprise_precise_lookup_cny05",
|
|
192
|
-
"ai.itpay.catalog_version": "catv_itpay_enterprise_data_001",
|
|
193
|
-
"ai.itpay.sensitivity_level": "business_sensitive",
|
|
194
|
-
"ai.itpay.delivery_mode": "managed_capability",
|
|
195
|
-
"ai.itpay.agent_may_view_raw_result": "false"
|
|
196
|
-
}
|
|
197
|
-
}],
|
|
198
|
-
metadata: {
|
|
199
|
-
"ai.itpay.taxonomy.category": "business_data_api",
|
|
200
|
-
"ai.itpay.provider": "itpay_enterprise_data",
|
|
201
|
-
"ai.itpay.provider_product_id": "81api_company_base_info",
|
|
202
|
-
"ai.itpay.sensitivity_level": "business_sensitive",
|
|
203
|
-
"ai.itpay.delivery_mode": "managed_capability"
|
|
204
|
-
}
|
|
205
|
-
}],
|
|
206
|
-
messages: [],
|
|
207
|
-
pagination: {limit: 10}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const checkout = {
|
|
211
|
-
checkout_id: "chk_mock_pubg",
|
|
212
|
-
cart_id: "cart_mock_pubg",
|
|
213
|
-
status: "requires_payment",
|
|
214
|
-
catalog_item_id: "cat_pubg_sandbox_topup",
|
|
215
|
-
catalog_variant_id: "var_pubg_couple_skin_cny20",
|
|
216
|
-
offer_id: "offer_pubg_couple_skin_cny20",
|
|
217
|
-
amount: 2000,
|
|
218
|
-
currency: "CNY",
|
|
219
|
-
delivery: {status: "not_ready", sensitive_content_redacted: true},
|
|
220
|
-
agent_next_actions: ["create_payment_intent"]
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
const intent = {
|
|
224
|
-
payment_intent_id: "pi_mock_pubg",
|
|
225
|
-
payment_attempt_id: "pa_mock_pubg",
|
|
226
|
-
checkout_id: "chk_mock_pubg",
|
|
227
|
-
status: "waiting_user_payment",
|
|
228
|
-
amount: 2000,
|
|
229
|
-
currency: "CNY",
|
|
230
|
-
human_action: {
|
|
231
|
-
kind: "payment_qr",
|
|
232
|
-
qr_png_url: "http://127.0.0.1/mock-qr.png",
|
|
233
|
-
qr_image_url: "http://127.0.0.1/mock-qr.svg",
|
|
234
|
-
mobile_wallet_url: "http://127.0.0.1/mock-mobile-wallet",
|
|
235
|
-
url: "http://127.0.0.1/mock-pay"
|
|
236
|
-
},
|
|
237
|
-
qr_png_url: "http://127.0.0.1/mock-qr.png",
|
|
238
|
-
qr_image_url: "http://127.0.0.1/mock-qr.svg",
|
|
239
|
-
mobile_wallet_url: "http://127.0.0.1/mock-mobile-wallet",
|
|
240
|
-
agent_wait: {
|
|
241
|
-
recommended: "long_poll",
|
|
242
|
-
wait_url: "/v1/payment-intents/pi_mock_pubg/events/wait",
|
|
243
|
-
cursor: "0",
|
|
244
|
-
timeout_seconds: 25
|
|
245
|
-
},
|
|
246
|
-
agent_next_actions: ["wait_payment"]
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const server = http.createServer(async (req, res) => {
|
|
250
|
-
const url = new URL(req.url, "http://127.0.0.1");
|
|
251
|
-
const body = await readBody(req);
|
|
252
|
-
fs.appendFileSync(logFile, JSON.stringify({method: req.method, path: url.pathname, body}) + "\n");
|
|
253
|
-
if (req.method === "POST" && url.pathname === "/api/ucp/v1/catalog/search") return writeJSON(res, 200, catalogSearch);
|
|
254
|
-
if (req.method === "POST" && url.pathname === "/api/ucp/v1/catalog/product") return writeJSON(res, 200, product);
|
|
255
|
-
if (req.method === "POST" && url.pathname === "/api/ucp/v1/carts") return writeJSON(res, 201, cart);
|
|
256
|
-
if (req.method === "GET" && url.pathname === "/api/ucp/v1/carts/cart_mock_pubg") return writeJSON(res, 200, cart);
|
|
257
|
-
if (req.method === "POST" && url.pathname === "/api/ucp/v1/checkouts") return writeJSON(res, 202, checkout);
|
|
258
|
-
if (req.method === "POST" && url.pathname === "/v1/checkouts/chk_mock_pubg/payment-intents") return writeJSON(res, 202, intent);
|
|
259
|
-
if (req.method === "POST" && url.pathname === "/v1/buyer/accounts/ba_mock_0376/portal-login-links") {
|
|
260
|
-
if (req.headers.authorization !== "Bearer sess_mock_0376") return writeJSON(res, 401, {error: "missing buyer session"});
|
|
261
|
-
return writeJSON(res, 201, {
|
|
262
|
-
login_link_id: "apl_mock_0376",
|
|
263
|
-
buyer_account_id: "ba_mock_0376",
|
|
264
|
-
login_url: "https://itpay.ai/v1/account-portal/login/apl_mock_0376?token=human-only",
|
|
265
|
-
expires_at: "2026-06-11T16:00:00Z",
|
|
266
|
-
one_time: true,
|
|
267
|
-
sensitive_redacted: true,
|
|
268
|
-
agent_next_actions: ["show_login_link_to_human_only"]
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
if (req.method === "GET" && url.pathname === "/v1/buyer/accounts/ba_mock_0376/auth/status") {
|
|
272
|
-
if (req.headers.authorization !== "Bearer sess_mock_0376") return writeJSON(res, 401, {error: "missing buyer session"});
|
|
273
|
-
return writeJSON(res, 200, {
|
|
274
|
-
buyer_account_id: "ba_mock_0376",
|
|
275
|
-
account_status: "active",
|
|
276
|
-
sensitive_redacted: true
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
if (req.method === "GET" && url.pathname === "/v1/vault/agent-read-grants") {
|
|
280
|
-
if (req.headers.authorization !== "Bearer sess_mock_0376") return writeJSON(res, 401, {error: "missing buyer session"});
|
|
281
|
-
return writeJSON(res, 200, {
|
|
282
|
-
agent_readable_grants: [{
|
|
283
|
-
agent_read_grant_id: "arg_mock_038c",
|
|
284
|
-
buyer_account_id: "ba_mock_0376",
|
|
285
|
-
agent_device_id: "ad_mock_0376",
|
|
286
|
-
checkout_id: url.searchParams.get("checkout_id") || "chk_mock_pubg",
|
|
287
|
-
vault_artifact_id: "vault_mock_038c",
|
|
288
|
-
order_id: "ord_mock_038c",
|
|
289
|
-
order_line_item_id: "cli_mock_line",
|
|
290
|
-
entitlement_id: "ent_mock_038c",
|
|
291
|
-
scope: "selected_fields",
|
|
292
|
-
fields: ["result.data.name"],
|
|
293
|
-
status: "active",
|
|
294
|
-
expires_at: "2026-06-11T16:00:00Z",
|
|
295
|
-
read_url: "/v1/vault/agent-read-grants/arg_mock_038c/view",
|
|
296
|
-
agent_next_actions: ["read_agent_grant_view"],
|
|
297
|
-
sensitive_redacted: true
|
|
298
|
-
}],
|
|
299
|
-
buyer_account_id: "ba_mock_0376",
|
|
300
|
-
agent_device_id: "ad_mock_0376",
|
|
301
|
-
count: 1,
|
|
302
|
-
sensitive_redacted: true,
|
|
303
|
-
agent_next_actions: ["read_agent_grant_view"]
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
if (req.method === "GET" && url.pathname === "/v1/vault/agent-read-grants/arg_mock_038c/view") {
|
|
307
|
-
if (req.headers.authorization !== "Bearer sess_mock_0376") return writeJSON(res, 401, {error: "missing buyer session"});
|
|
308
|
-
return writeJSON(res, 200, {
|
|
309
|
-
agent_read_grant_id: "arg_mock_038c",
|
|
310
|
-
buyer_account_id: "ba_mock_0376",
|
|
311
|
-
agent_device_id: "ad_mock_0376",
|
|
312
|
-
vault_artifact_id: "vault_mock_038c",
|
|
313
|
-
order_id: "ord_mock_038c",
|
|
314
|
-
order_line_item_id: "cli_mock_line",
|
|
315
|
-
entitlement_id: "ent_mock_038c",
|
|
316
|
-
scope: "selected_fields",
|
|
317
|
-
fields: ["result.data.name"],
|
|
318
|
-
status: "active",
|
|
319
|
-
expires_at: "2026-06-11T16:00:00Z",
|
|
320
|
-
selected_fields: {"result.data.name": "北京赢在未来科技有限公司"},
|
|
321
|
-
sensitive_redacted: false
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
return writeJSON(res, 404, {error: "not found", path: url.pathname});
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
server.listen(0, "127.0.0.1", () => {
|
|
328
|
-
fs.writeFileSync(portFile, String(server.address().port));
|
|
329
|
-
});
|
|
330
|
-
JS
|
|
331
|
-
MOCK_LOG="$MOCK_LOG" MOCK_PORT_FILE="$MOCK_PORT_FILE" node "$TMP_HOME/mock-core.mjs" &
|
|
332
|
-
MOCK_SERVER_PID=$!
|
|
333
|
-
i=0
|
|
334
|
-
while [ ! -s "$MOCK_PORT_FILE" ] && [ "$i" -lt 50 ]; do
|
|
335
|
-
i=$((i + 1))
|
|
336
|
-
sleep 0.1
|
|
337
|
-
done
|
|
338
|
-
if [ ! -s "$MOCK_PORT_FILE" ]; then
|
|
339
|
-
echo "mock core server did not start" >&2
|
|
340
|
-
exit 1
|
|
341
|
-
fi
|
|
342
|
-
MOCK_PORT=$(cat "$MOCK_PORT_FILE")
|
|
343
|
-
SEARCH_OUTPUT=$(HOME="$TMP_HOME" ITPAY_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer catalog search --query "企业工商信息 查询" --category business_data_api --provider itpay_enterprise_data --service-type ai_api --delivery-mode managed_capability --sensitivity-level business_sensitive --use-case company_lookup --input-facet company_name --requires-webauthn-reveal true --json)
|
|
344
|
-
printf '%s' "$SEARCH_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "catalog_search_results" || !json.products.some((product)=>product.id==="cat_itpay_enterprise_precise_lookup")) process.exit(1);})'
|
|
345
|
-
BUY_OUTPUT=$(HOME="$TMP_HOME" ITPAY_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buy var_pubg_couple_skin_cny20 --sandbox --email buyer@example.com --phone +8613800000000 --no-wait --json)
|
|
346
|
-
printf '%s' "$BUY_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "waiting_user_payment" || json.cart.cart_id !== "cart_mock_pubg" || json.checkout.checkout_id !== "chk_mock_pubg" || json.payment_intent.payment_intent_id !== "pi_mock_pubg") process.exit(1); if (json.payment_intent.human_action.preferred_qr_url !== "http://127.0.0.1/mock-qr.png") process.exit(1); if (json.payment_intent.human_action.agent_display_hint.primary !== "qr_png_url") process.exit(1); if (json.payment_intent.human_action.mobile_wallet_url !== "http://127.0.0.1/mock-mobile-wallet") process.exit(1); if (!json.docs.some((doc)=>doc.topic==="payment-wait")) process.exit(1); if (JSON.stringify(json).includes("issue_payment_proof")) process.exit(1);})'
|
|
347
|
-
MULTI_CART_OUTPUT=$(HOME="$TMP_HOME" ITPAY_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer cart create --variants var_pubg_couple_skin_cny20,var_pubg_deluxe_skin_cny40 --quantities 1,2 --json)
|
|
348
|
-
printf '%s' "$MULTI_CART_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "cart_created" || json.cart.cart_id !== "cart_mock_pubg") process.exit(1);})'
|
|
349
|
-
node - <<'JS' "$TMP_HOME/.itp/config.json" "$TMP_HOME/.itp/credentials.json"
|
|
350
|
-
const fs = require("fs");
|
|
351
|
-
const [configPath, credentialsPath] = process.argv.slice(2);
|
|
352
|
-
fs.writeFileSync(configPath, JSON.stringify({account_id: "ba_mock_0376", device_id: "ad_mock_0376"}, null, 2), {mode: 0o600});
|
|
353
|
-
const credentials = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));
|
|
354
|
-
credentials.session_token = "sess_mock_0376";
|
|
355
|
-
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {mode: 0o600});
|
|
356
|
-
JS
|
|
357
|
-
PORTAL_LINK_OUTPUT=$(HOME="$TMP_HOME" ITPAY_CORE_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" account login-link --json)
|
|
358
|
-
printf '%s' "$PORTAL_LINK_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "account_portal_login_link_created" || json.portal_login_link.one_time !== true) process.exit(1); if (!json.login_url.includes("/v1/account-portal/login/")) process.exit(1); if (json.next.safe_for_agent !== false || json.next.requires_human !== true || json.next.agent_must_not_open !== true) process.exit(1);})'
|
|
359
|
-
BUYER_AUTH_WITH_SESSION=$(HOME="$TMP_HOME" ITPAY_CORE_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer auth status --json)
|
|
360
|
-
printf '%s' "$BUYER_AUTH_WITH_SESSION" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "authenticated_buyer_session" || json.authenticated !== true || json.buyer_account_id !== "ba_mock_0376" || json.agent_device_id !== "ad_mock_0376") process.exit(1);})'
|
|
361
|
-
GRANTS_LIST_OUTPUT=$(HOME="$TMP_HOME" ITPAY_CORE_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer vault grants list --checkout chk_mock_pubg --json)
|
|
362
|
-
printf '%s' "$GRANTS_LIST_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "agent_read_grants" || !Array.isArray(json.agent_readable_grants) || json.agent_readable_grants[0].agent_read_grant_id !== "arg_mock_038c") process.exit(1); if (!json.docs.some((doc)=>doc.topic==="vault-agent-read")) process.exit(1); if (data.includes("北京赢在未来") || data.includes("storage_ref")) process.exit(1);})'
|
|
363
|
-
GRANT_READ_OUTPUT=$(HOME="$TMP_HOME" ITPAY_CORE_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer vault grants read arg_mock_038c --json)
|
|
364
|
-
printf '%s' "$GRANT_READ_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "agent_read_grant_view" || json.grant.selected_fields["result.data.name"] !== "北京赢在未来科技有限公司") process.exit(1); if (data.includes("storage_ref")) process.exit(1);})'
|
|
365
|
-
VAULT_READ_OUTPUT=$(HOME="$TMP_HOME" ITPAY_CORE_API_BASE="http://127.0.0.1:$MOCK_PORT" "$ROOT/bin/itp" buyer vault read --order ord_mock_038c --artifact vault_mock_038c --json)
|
|
366
|
-
printf '%s' "$VAULT_READ_OUTPUT" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.status !== "agent_read_grant_view" || json.grant.discovered_grant.agent_read_grant_id !== "arg_mock_038c" || json.grant.selected_fields["result.data.name"] !== "北京赢在未来科技有限公司") process.exit(1);})'
|
|
367
|
-
node - <<'JS' "$TMP_HOME/.itp/credentials.json"
|
|
368
|
-
const fs = require("fs");
|
|
369
|
-
const credentialsPath = process.argv[2];
|
|
370
|
-
const credentials = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));
|
|
371
|
-
delete credentials.session_token;
|
|
372
|
-
delete credentials.session_token_store;
|
|
373
|
-
delete credentials.session_token_ref;
|
|
374
|
-
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {mode: 0o600});
|
|
375
|
-
JS
|
|
376
|
-
node -e 'const fs=require("fs"); const rows=fs.readFileSync(process.argv[1],"utf8").trim().split(/\n/).map(JSON.parse); const has=(m,p)=>rows.some(r=>r.method===m&&r.path===p); if(!has("POST","/api/ucp/v1/catalog/product")||!has("POST","/api/ucp/v1/carts")||!has("POST","/api/ucp/v1/checkouts")||!has("POST","/v1/checkouts/chk_mock_pubg/payment-intents")) process.exit(1); if(has("POST","/v1/checkouts")) process.exit(1);' "$MOCK_LOG"
|
|
377
|
-
node -e 'const fs=require("fs"); const rows=fs.readFileSync(process.argv[1],"utf8").trim().split(/\n/).map(JSON.parse); const multi=rows.find(r=>r.method==="POST"&&r.path==="/api/ucp/v1/carts"&&Array.isArray(r.body.line_items)&&r.body.line_items.length===2); if(!multi) process.exit(1); if(multi.body.line_items[0].item.id!=="var_pubg_couple_skin_cny20"||multi.body.line_items[0].quantity!==1||multi.body.line_items[1].item.id!=="var_pubg_deluxe_skin_cny40"||multi.body.line_items[1].quantity!==2) process.exit(1);' "$MOCK_LOG"
|
|
378
|
-
node -e 'const fs=require("fs"); const rows=fs.readFileSync(process.argv[1],"utf8").trim().split(/\n/).map(JSON.parse); const search=rows.find(r=>r.method==="POST"&&r.path==="/api/ucp/v1/catalog/search"); if(!search) process.exit(1); const f=search.body.filters||{}; if(!Array.isArray(f.categories)||f.categories[0]!=="business_data_api") process.exit(1); if(f["ai.itpay.provider"]!=="itpay_enterprise_data"||f["ai.itpay.service_type"]!=="ai_api"||f["ai.itpay.delivery_mode"]!=="managed_capability"||f["ai.itpay.sensitivity_level"]!=="business_sensitive") process.exit(1); if(!Array.isArray(f["ai.itpay.taxonomy.use_cases"])||f["ai.itpay.taxonomy.use_cases"][0]!=="company_lookup") process.exit(1); if(!Array.isArray(f["ai.itpay.taxonomy.input_facets"])||f["ai.itpay.taxonomy.input_facets"][0]!=="company_name") process.exit(1); if(f["ai.itpay.requires_webauthn_reveal"]!==true) process.exit(1);' "$MOCK_LOG"
|
|
379
|
-
kill "$MOCK_SERVER_PID" >/dev/null 2>&1 || true
|
|
380
|
-
MOCK_SERVER_PID=""
|
|
381
|
-
AGENT_STATUS=$(HOME="$TMP_HOME" "$ROOT/bin/itp" status --json)
|
|
382
|
-
printf '%s' "$AGENT_STATUS" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.schema_version !== "itp.agent.v1" || json.status !== "unauthenticated" || json.secrets.raw_key_included !== false) process.exit(1);})'
|
|
383
|
-
AUTH_STATUS=$(HOME="$TMP_HOME" "$ROOT/bin/itp" auth status --json)
|
|
384
|
-
printf '%s' "$AUTH_STATUS" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.authenticated !== false) process.exit(1);})'
|
|
385
|
-
BALANCE_NO_SESSION=$(HOME="$TMP_HOME" "$ROOT/bin/itp" balance --json 2>/dev/null || true)
|
|
386
|
-
if [ -n "$BALANCE_NO_SESSION" ]; then
|
|
387
|
-
echo "balance accepted without session" >&2
|
|
388
|
-
exit 1
|
|
389
|
-
fi
|
|
390
|
-
PLANS_ALIAS=$(HOME="$TMP_HOME" "$ROOT/bin/itp" plans --json)
|
|
391
|
-
printf '%s' "$PLANS_ALIAS" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (!Array.isArray(json.plans)) process.exit(1);})'
|
|
392
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" install codex --grant gr_test --dry-run --json >/dev/null
|
|
393
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" install claude-code --grant gr_test --dry-run --json >/dev/null
|
|
394
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" install openclaw --grant gr_test --dry-run --json >/dev/null
|
|
395
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" install codex --grant gr_test --offline --no-test --json >/dev/null
|
|
396
|
-
HOME="$TMP_HOME" "$ROOT/bin/itp" doctor --target codex --json >/dev/null
|
|
397
|
-
DOCTOR=$(HOME="$TMP_HOME" "$ROOT/bin/itp" doctor --target codex --grant gr_test --offline --json)
|
|
398
|
-
printf '%s' "$DOCTOR" | node -e 'let data="";process.stdin.on("data",c=>data+=c);process.stdin.on("end",()=>{const json=JSON.parse(data); if (json.grant_credential_store !== "file" || !json.warning) process.exit(1);})'
|
|
399
|
-
TOKEN=$(HOME="$TMP_HOME" "$ROOT/bin/itp" token issue --grant gr_test --stdout)
|
|
400
|
-
|
|
401
|
-
if [ "$TOKEN" != "sk-test" ]; then
|
|
402
|
-
echo "unexpected token output" >&2
|
|
403
|
-
exit 1
|
|
404
|
-
fi
|
|
405
|
-
|
|
406
|
-
if HOME="$TMP_HOME" "$ROOT/bin/itp" install codex --grant gr_missing_key --dry-run --json >/dev/null 2>&1; then
|
|
407
|
-
echo "install accepted missing grant credential key" >&2
|
|
408
|
-
exit 1
|
|
409
|
-
fi
|
|
410
|
-
|
|
411
|
-
if HOME="$TMP_HOME" "$ROOT/bin/itp" account set-password --json >/dev/null 2>&1; then
|
|
412
|
-
echo "set-password accepted without --password-stdin" >&2
|
|
413
|
-
exit 1
|
|
414
|
-
fi
|
|
415
|
-
|
|
416
|
-
if printf '' | HOME="$TMP_HOME" "$ROOT/bin/itp" auth login --username smoke --password-stdin --json >/dev/null 2>&1; then
|
|
417
|
-
echo "auth login accepted empty stdin password" >&2
|
|
418
|
-
exit 1
|
|
419
|
-
fi
|
|
420
|
-
|
|
421
|
-
if HOME="$TMP_HOME" "$ROOT/bin/itp" auth login --username smoke --password badsecret --json >/dev/null 2>&1; then
|
|
422
|
-
echo "auth login accepted --password" >&2
|
|
423
|
-
exit 1
|
|
424
|
-
fi
|
|
425
|
-
|
|
426
|
-
echo "itp smoke ok"
|