@itpay/cli 0.1.1 → 0.1.4
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 +9 -6
- package/bin/itp +135 -30
- package/docs/agent/buyer/cart-checkout.json +9 -5
- package/docs/agent/buyer/catalog-search.json +1 -0
- package/docs/agent/buyer/human-claim-ui.json +3 -1
- package/docs/agent/buyer/product-recommendation.json +1 -0
- package/docs/agent/buyer/quickstart.json +2 -0
- package/docs/agent/buyer/vault-agent-read.json +6 -3
- package/package.json +1 -1
- package/skills/itpay-buyer/SKILL.md +24 -5
package/README.md
CHANGED
|
@@ -34,16 +34,18 @@ openclaw
|
|
|
34
34
|
Default API endpoint:
|
|
35
35
|
|
|
36
36
|
```text
|
|
37
|
-
|
|
37
|
+
https://dev.api.itpay.ai
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Override it for
|
|
40
|
+
Override it for local development, staging, or production:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
export ITPAY_API_BASE=
|
|
44
|
-
export
|
|
43
|
+
export ITPAY_API_BASE=http://127.0.0.1:18080
|
|
44
|
+
export ITPAY_CORE_API_BASE=http://127.0.0.1:18080
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
Production release will switch the package default to `https://api.itpay.ai`.
|
|
48
|
+
|
|
47
49
|
## Repository Layout
|
|
48
50
|
|
|
49
51
|
```text
|
|
@@ -184,10 +186,11 @@ node ./bin/itp --version
|
|
|
184
186
|
|
|
185
187
|
## Basic User Flow
|
|
186
188
|
|
|
187
|
-
|
|
189
|
+
The default endpoint is the AWS dev backend. Set API endpoint only when testing
|
|
190
|
+
local or another environment:
|
|
188
191
|
|
|
189
192
|
```bash
|
|
190
|
-
export ITPAY_API_BASE=
|
|
193
|
+
export ITPAY_API_BASE=http://127.0.0.1:18080
|
|
191
194
|
```
|
|
192
195
|
|
|
193
196
|
For the current buyer commerce flow, search the catalog, create a cart/checkout,
|
package/bin/itp
CHANGED
|
@@ -8,8 +8,8 @@ import { execFileSync } from "node:child_process";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import QRCode from "qrcode";
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.1.
|
|
12
|
-
const DEFAULT_API_BASE = process.env.ITPAY_API_BASE || process.env.ITPAY_CORE_BASE_URL || "
|
|
11
|
+
const VERSION = "0.1.4";
|
|
12
|
+
const DEFAULT_API_BASE = process.env.ITPAY_API_BASE || process.env.ITPAY_CORE_API_BASE || process.env.ITPAY_CORE_BASE_URL || "https://dev.api.itpay.ai";
|
|
13
13
|
const CONFIG_DIR = path.join(os.homedir(), ".itp");
|
|
14
14
|
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
15
15
|
const STATE_PATH = path.join(CONFIG_DIR, "state.json");
|
|
@@ -198,9 +198,9 @@ async function main() {
|
|
|
198
198
|
"buyer catalog search --query 企业工商 --category business_data_api --provider itpay_enterprise_data --json",
|
|
199
199
|
"buyer catalog get --variant var_pubg_couple_skin_cny20 --json",
|
|
200
200
|
"buyer cart create --variant var_pubg_couple_skin_cny20 --json",
|
|
201
|
-
"buyer cart create --
|
|
201
|
+
"buyer cart create --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=京东 --json",
|
|
202
202
|
"buyer cart show <cart_id> --json",
|
|
203
|
-
"buyer cart add <cart_id> --variant var_itpay_enterprise_fuzzy_search_cny01 --quantity 1 --json",
|
|
203
|
+
"buyer cart add <cart_id> --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=美团 --quantity 1 --json",
|
|
204
204
|
"buyer cart remove <cart_id> --line <cart_line_item_id> --json",
|
|
205
205
|
"buyer shelf manifest --json",
|
|
206
206
|
"buyer shelf snapshot --version <catalog_version> --json",
|
|
@@ -715,11 +715,12 @@ async function buyer(command, rest, flags) {
|
|
|
715
715
|
const checkoutID = flags.checkout || flags.checkout_id || positional(rest, 1) || readState().last_core_checkout_id;
|
|
716
716
|
if (!checkoutID) throw new Error("checkout_id is required");
|
|
717
717
|
const checkout = await getBuyerCheckout(checkoutID, flags);
|
|
718
|
-
await maybeClaimBuyerSessionForCheckout(checkout, flags);
|
|
718
|
+
const claimedSession = await maybeClaimBuyerSessionForCheckout(checkout, flags);
|
|
719
719
|
output(buyerRunOutput({
|
|
720
720
|
status: checkout.delivery_status || checkout.status,
|
|
721
721
|
checkout,
|
|
722
722
|
delivery: checkout.delivery,
|
|
723
|
+
buyer_session: buyerSessionClaimStatus(claimedSession),
|
|
723
724
|
agent_next_actions: deliveryAwareAgentNextActions(checkout),
|
|
724
725
|
optional_agent_read_grant: optionalAgentReadGrantHint(checkout.checkout_id, checkout)
|
|
725
726
|
}));
|
|
@@ -759,15 +760,21 @@ async function buyer(command, rest, flags) {
|
|
|
759
760
|
}
|
|
760
761
|
}));
|
|
761
762
|
return;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const claimedSession = await maybeClaimBuyerSessionForCheckout(checkout, flags);
|
|
766
|
+
if (checkout.payment_intent_id) {
|
|
767
|
+
const intent = await getBuyerPaymentIntent(checkout.payment_intent_id, flags);
|
|
768
|
+
await renderItPayPaymentAction(intent, flags);
|
|
769
|
+
output(buyerRunOutput({
|
|
770
|
+
status: intent.status === "verified" ? "payment_verified" : "waiting_user_payment",
|
|
771
|
+
checkout,
|
|
772
|
+
payment_intent: intent,
|
|
773
|
+
buyer_session: buyerSessionClaimStatus(claimedSession),
|
|
774
|
+
agent_next_actions: intent.agent_next_actions || checkout.agent_next_actions || ["wait_payment"]
|
|
775
|
+
}));
|
|
776
|
+
return;
|
|
762
777
|
}
|
|
763
|
-
}
|
|
764
|
-
await maybeClaimBuyerSessionForCheckout(checkout, flags);
|
|
765
|
-
if (checkout.payment_intent_id) {
|
|
766
|
-
const intent = await getBuyerPaymentIntent(checkout.payment_intent_id, flags);
|
|
767
|
-
await renderItPayPaymentAction(intent, flags);
|
|
768
|
-
output(buyerRunOutput({ status: intent.status === "verified" ? "payment_verified" : "waiting_user_payment", checkout, payment_intent: intent, agent_next_actions: intent.agent_next_actions || checkout.agent_next_actions || ["wait_payment"] }));
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
778
|
if (checkout.agent_next_actions?.includes("create_payment_intent") || checkout.next_required_action === "create_payment_intent") {
|
|
772
779
|
const intent = await createBuyerPaymentIntent(checkout.checkout_id, flags);
|
|
773
780
|
await renderItPayPaymentAction(intent, flags);
|
|
@@ -778,6 +785,7 @@ async function buyer(command, rest, flags) {
|
|
|
778
785
|
status: checkout.delivery_status || checkout.status,
|
|
779
786
|
checkout,
|
|
780
787
|
delivery: checkout.delivery,
|
|
788
|
+
buyer_session: buyerSessionClaimStatus(claimedSession),
|
|
781
789
|
agent_next_actions: deliveryAwareAgentNextActions(checkout),
|
|
782
790
|
optional_agent_read_grant: optionalAgentReadGrantHint(checkout.checkout_id, checkout)
|
|
783
791
|
}));
|
|
@@ -838,10 +846,12 @@ async function buyer(command, rest, flags) {
|
|
|
838
846
|
if (subcommand === "grants") {
|
|
839
847
|
const action = rest[1] && !String(rest[1]).startsWith("--") ? rest[1] : "list";
|
|
840
848
|
if (action === "list") {
|
|
849
|
+
const claimedSession = await ensureBuyerSessionForVaultAccess(flags);
|
|
841
850
|
const grants = await listBuyerAgentReadGrants(flags);
|
|
842
851
|
output(buyerRunOutput({
|
|
843
852
|
status: "agent_read_grants",
|
|
844
853
|
...grants,
|
|
854
|
+
buyer_session: buyerSessionClaimStatus(claimedSession),
|
|
845
855
|
agent_next_actions: grants.agent_readable_grants?.length ? ["read_agent_grant_view"] : ["wait_for_human_agent_read_grant"]
|
|
846
856
|
}));
|
|
847
857
|
return;
|
|
@@ -849,6 +859,7 @@ async function buyer(command, rest, flags) {
|
|
|
849
859
|
if (action === "read" || action === "show") {
|
|
850
860
|
const grantID = flags.grant || flags.grant_id || flags.agent_read_grant_id || positional(rest, 2);
|
|
851
861
|
if (!grantID) throw new Error("agent_read_grant_id is required");
|
|
862
|
+
await ensureBuyerSessionForVaultAccess(flags);
|
|
852
863
|
const view = await readBuyerAgentReadGrant(grantID, flags);
|
|
853
864
|
output(buyerRunOutput({
|
|
854
865
|
status: "agent_read_grant_view",
|
|
@@ -859,6 +870,7 @@ async function buyer(command, rest, flags) {
|
|
|
859
870
|
}
|
|
860
871
|
}
|
|
861
872
|
if (subcommand === "read") {
|
|
873
|
+
await ensureBuyerSessionForVaultAccess(flags);
|
|
862
874
|
const view = await readBuyerVaultArtifactGrant(flags);
|
|
863
875
|
output(buyerRunOutput({
|
|
864
876
|
status: "agent_read_grant_view",
|
|
@@ -1317,6 +1329,20 @@ async function maybeClaimBuyerSessionFromAuthAction(action, flags = {}) {
|
|
|
1317
1329
|
}
|
|
1318
1330
|
}
|
|
1319
1331
|
|
|
1332
|
+
function buyerSessionClaimStatus(claimed = null) {
|
|
1333
|
+
const config = readConfig();
|
|
1334
|
+
const hasSession = Boolean(readSessionToken());
|
|
1335
|
+
if (!claimed && !hasSession) return undefined;
|
|
1336
|
+
return {
|
|
1337
|
+
status: "buyer_session_saved",
|
|
1338
|
+
session_stored: true,
|
|
1339
|
+
buyer_account_id: claimed?.buyer_account_id || config.account_id || null,
|
|
1340
|
+
agent_device_id: claimed?.agent_device_id || config.device_id || null,
|
|
1341
|
+
token_included: false,
|
|
1342
|
+
agent_next_actions: ["reuse_buyer_session", "list_agent_read_grants"]
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1320
1346
|
async function maybeClaimBuyerSessionForCheckout(checkout, flags = {}) {
|
|
1321
1347
|
if (!checkout?.checkout_id) return null;
|
|
1322
1348
|
if (readSessionToken()) return null;
|
|
@@ -1325,19 +1351,76 @@ async function maybeClaimBuyerSessionForCheckout(checkout, flags = {}) {
|
|
|
1325
1351
|
return await maybeClaimBuyerSessionFromAuthAction(action, flags);
|
|
1326
1352
|
}
|
|
1327
1353
|
|
|
1354
|
+
async function ensureBuyerSessionForVaultAccess(flags = {}) {
|
|
1355
|
+
if (readSessionToken()) return null;
|
|
1356
|
+
const checkoutID =
|
|
1357
|
+
flags.checkout ||
|
|
1358
|
+
flags.checkout_id ||
|
|
1359
|
+
readState().last_core_checkout_id ||
|
|
1360
|
+
readState().last_core_auth_checkout_id;
|
|
1361
|
+
if (checkoutID) {
|
|
1362
|
+
try {
|
|
1363
|
+
const checkout = await getBuyerCheckout(checkoutID, flags);
|
|
1364
|
+
rememberCoreAuthAction(checkout.checkout_id || checkoutID, checkout.human_action);
|
|
1365
|
+
const claimed = await maybeClaimBuyerSessionForCheckout(checkout, { ...flags, quiet: true });
|
|
1366
|
+
if (claimed || readSessionToken()) return claimed;
|
|
1367
|
+
} catch {
|
|
1368
|
+
// Continue with the locally remembered auth action below.
|
|
1369
|
+
}
|
|
1370
|
+
const action = readCoreAuthAction(checkoutID);
|
|
1371
|
+
const claimed = await maybeClaimBuyerSessionFromAuthAction(action, { ...flags, quiet: true });
|
|
1372
|
+
if (claimed || readSessionToken()) return claimed;
|
|
1373
|
+
}
|
|
1374
|
+
const state = readState();
|
|
1375
|
+
const entries = Object.entries(state.core_auth_actions || {});
|
|
1376
|
+
for (const [, action] of entries.reverse()) {
|
|
1377
|
+
const claimed = await maybeClaimBuyerSessionFromAuthAction(action, { ...flags, quiet: true });
|
|
1378
|
+
if (claimed || readSessionToken()) return claimed;
|
|
1379
|
+
}
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1328
1383
|
function parseBuyerAuthActionURL(action) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1384
|
+
if (!action || typeof action !== "object") return {};
|
|
1385
|
+
let authSessionID = String(action.auth_session_id || "").trim();
|
|
1386
|
+
if (!authSessionID && String(action.id || "").startsWith("auth_")) {
|
|
1387
|
+
authSessionID = String(action.id).trim();
|
|
1388
|
+
}
|
|
1389
|
+
let displayToken = "";
|
|
1390
|
+
let sourceURL = "";
|
|
1391
|
+
for (const rawURL of buyerAuthActionCandidateURLs(action)) {
|
|
1392
|
+
try {
|
|
1393
|
+
const parsed = new URL(rawURL);
|
|
1394
|
+
const token = parsed.searchParams.get("display_token") || "";
|
|
1395
|
+
if (token && !displayToken) displayToken = token;
|
|
1396
|
+
const match = parsed.pathname.match(/(?:^|\/)(?:v1\/buyer\/auth-sessions|auth)\/([^/?#]+)(?:\/|$)/);
|
|
1397
|
+
if (match && !authSessionID) authSessionID = decodeURIComponent(match[1]);
|
|
1398
|
+
if (!sourceURL && (match || token)) sourceURL = rawURL;
|
|
1399
|
+
if (authSessionID && displayToken) break;
|
|
1400
|
+
} catch {
|
|
1401
|
+
// Ignore non-URL display entries.
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
return { authSessionID, displayToken, sourceURL };
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
function buyerAuthActionCandidateURLs(action) {
|
|
1408
|
+
const urls = [];
|
|
1409
|
+
for (const key of ["url", "web_url", "auth_url", "oauth_start_url", "mobile_wallet_url"]) {
|
|
1410
|
+
if (action?.[key]) urls.push(String(action[key]));
|
|
1340
1411
|
}
|
|
1412
|
+
const presentationDisplay = action?.presentation?.display;
|
|
1413
|
+
if (Array.isArray(presentationDisplay)) {
|
|
1414
|
+
for (const entry of presentationDisplay) {
|
|
1415
|
+
if (entry?.url) urls.push(String(entry.url));
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
if (Array.isArray(action?.display)) {
|
|
1419
|
+
for (const entry of action.display) {
|
|
1420
|
+
if (entry?.url) urls.push(String(entry.url));
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
return urls;
|
|
1341
1424
|
}
|
|
1342
1425
|
|
|
1343
1426
|
function rememberCoreAuthAction(checkoutID, action) {
|
|
@@ -1351,9 +1434,9 @@ function rememberCoreAuthAction(checkoutID, action) {
|
|
|
1351
1434
|
next[checkoutID] = {
|
|
1352
1435
|
kind: "auth_qr",
|
|
1353
1436
|
id: action.id || action.auth_session_id || parsed.authSessionID,
|
|
1354
|
-
auth_session_id:
|
|
1355
|
-
url: action.url,
|
|
1356
|
-
web_url: action.web_url || action.url,
|
|
1437
|
+
auth_session_id: parsed.authSessionID,
|
|
1438
|
+
url: action.url || parsed.sourceURL,
|
|
1439
|
+
web_url: action.web_url || action.url || parsed.sourceURL,
|
|
1357
1440
|
expires_at: action.expires_at || null,
|
|
1358
1441
|
saved_at: new Date().toISOString()
|
|
1359
1442
|
};
|
|
@@ -1487,7 +1570,7 @@ function isBuyerDeliveryComplete(result) {
|
|
|
1487
1570
|
}
|
|
1488
1571
|
|
|
1489
1572
|
function buyerRunOutput(value = {}) {
|
|
1490
|
-
return stripInternalBuyerFields({
|
|
1573
|
+
return normalizeBuyerMoneyFields(stripInternalBuyerFields({
|
|
1491
1574
|
schema_version: "itp.buyer.v1",
|
|
1492
1575
|
docs: value.docs || buyerDocsFor(value),
|
|
1493
1576
|
...value,
|
|
@@ -1496,7 +1579,29 @@ function buyerRunOutput(value = {}) {
|
|
|
1496
1579
|
claim_token_included: false,
|
|
1497
1580
|
provider_raw_payload_included: false
|
|
1498
1581
|
}
|
|
1499
|
-
});
|
|
1582
|
+
}));
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
function normalizeBuyerMoneyFields(value) {
|
|
1586
|
+
if (Array.isArray(value)) return value.map((item) => normalizeBuyerMoneyFields(item));
|
|
1587
|
+
if (!value || typeof value !== "object") return value;
|
|
1588
|
+
const next = {};
|
|
1589
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1590
|
+
next[key] = normalizeBuyerMoneyFields(item);
|
|
1591
|
+
}
|
|
1592
|
+
if (
|
|
1593
|
+
typeof next.amount === "number" &&
|
|
1594
|
+
Number.isFinite(next.amount) &&
|
|
1595
|
+
typeof next.currency === "string" &&
|
|
1596
|
+
next.currency.trim()
|
|
1597
|
+
) {
|
|
1598
|
+
const currency = next.currency.trim().toUpperCase();
|
|
1599
|
+
next.amount_minor = Number.isInteger(next.amount) ? next.amount : Math.round(next.amount);
|
|
1600
|
+
next.amount_major = Number((next.amount_minor / 100).toFixed(2));
|
|
1601
|
+
next.display_amount = `${currency} ${(next.amount_minor / 100).toFixed(2)}`;
|
|
1602
|
+
next.amount_unit = "minor";
|
|
1603
|
+
}
|
|
1604
|
+
return next;
|
|
1500
1605
|
}
|
|
1501
1606
|
|
|
1502
1607
|
function buyerDocsFor(value = {}) {
|
|
@@ -3602,7 +3707,7 @@ function coreURL(pathname, flags = {}) {
|
|
|
3602
3707
|
}
|
|
3603
3708
|
|
|
3604
3709
|
function coreApiBase(flags = {}) {
|
|
3605
|
-
const base = flags.api_base || flags.core_api_base || process.env.ITPAY_API_BASE || process.env.ITPAY_CORE_API_BASE || process.env.ITPAY_CORE_BASE_URL || "
|
|
3710
|
+
const base = flags.api_base || flags.core_api_base || process.env.ITPAY_API_BASE || process.env.ITPAY_CORE_API_BASE || process.env.ITPAY_CORE_BASE_URL || "https://dev.api.itpay.ai";
|
|
3606
3711
|
return String(base).replace(/\/$/, "");
|
|
3607
3712
|
}
|
|
3608
3713
|
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"intent": "add one more selected UCP Variant.id to an existing cart before checkout",
|
|
56
|
-
"command": "itp buyer cart add <cart_id> --variant <variant_id> --quantity 1 --json",
|
|
57
|
-
"success_signal": "response.cart.cart_id is unchanged
|
|
56
|
+
"command": "itp buyer cart add <cart_id> --variant <variant_id> --input key=value --quantity 1 --json",
|
|
57
|
+
"success_signal": "response.cart.cart_id is unchanged; response.cart.line_items either includes a new line for different input/settings or increments quantity for an identical line"
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
"intent": "remove one line from an existing cart before checkout",
|
|
@@ -77,12 +77,15 @@
|
|
|
77
77
|
"Before cart creation, inspect product metadata input_schema_json and collect every required input field. Do not wait until after payment to ask for required query inputs.",
|
|
78
78
|
"Enterprise fuzzy search requires input.company_name. This can be a keyword, brand, short name, or partial company name supplied by the user, such as 京东.",
|
|
79
79
|
"Enterprise precise lookup requires input.company_name_or_credit_no. This must be a complete China mainland registered company name or unified social credit code. If the user only provides a brand/short name, resolve the exact name first or use fuzzy search before precise lookup.",
|
|
80
|
-
"Use --input key=value for service-specific inputs. For multiple lines, prefer separate cart add commands
|
|
80
|
+
"Use --input key=value for service-specific inputs. For multiple query lines, prefer separate cart add commands so each line locks its own input.",
|
|
81
|
+
"Cart line identity includes variant, offer, price, provider product, and normalized input. Only a completely identical line should merge by increasing quantity.",
|
|
82
|
+
"If the same variant has a different company_name, company_name_or_credit_no, page number, setting, or any other input value, it must remain a separate cart line.",
|
|
81
83
|
"Before checkout create, confirm buyer email is available for secure delivery. If it is missing, ask the human for the email before checkout; do not guess or use a placeholder.",
|
|
82
84
|
"Use cart_id as the checkout handoff.",
|
|
83
|
-
"Use buyer cart show whenever you need current cart contents. Do not rely on chat memory for cart state.",
|
|
85
|
+
"Use buyer cart show before changing an existing cart and whenever you need current cart contents. Do not rely on chat memory for cart state.",
|
|
84
86
|
"Use buyer cart add/remove before checkout when the user changes their mind. After checkout is created, treat the cart as locked.",
|
|
85
87
|
"Do not override cart line_items during checkout.",
|
|
88
|
+
"Cart, checkout, and catalog JSON money fields use minor units. For CNY, amount=10 or expected_amount=10 means CNY 0.10. Tell humans the display_amount or converted major-unit amount, never interpret amount as yuan.",
|
|
86
89
|
"If the user asks for several compatible products, add them to one cart and create one checkout. Do not split into separate checkouts unless ItPay rejects the cart or says split checkout is required.",
|
|
87
90
|
"If the same cart is retried, expect the same checkout unless contact/client reference changes.",
|
|
88
91
|
"The backend revalidates catalog, price, and delivery requirements.",
|
|
@@ -91,7 +94,8 @@
|
|
|
91
94
|
"Do not tell the user auth_qr is a completed payment or payment proof.",
|
|
92
95
|
"For first purchase, show the ItPay auth entry as one human orchestration entry; after provider OAuth callback the same checkout exposes payment.",
|
|
93
96
|
"After showing auth_qr, poll checkout or run buyer checkout resume until identity_status becomes identity_resolved and payment_intent_id appears.",
|
|
94
|
-
"When auth completes, CLI should claim and store the buyer session so a repeat purchase by the same agent/device can skip auth."
|
|
97
|
+
"When auth completes, CLI should claim and store the buyer session so a repeat purchase by the same agent/device can skip auth.",
|
|
98
|
+
"If checkout status/resume returns buyer_session.status=buyer_session_saved, the agent is now bound to that buyer account on this device. Continue with payment, delivery polling, or buyer vault commands; do not ask the human for a buyer session token."
|
|
95
99
|
],
|
|
96
100
|
"forbidden": [
|
|
97
101
|
"Use the UCP cart and buyer checkout commands for external-agent tests.",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"Use stable categories: business_data_api, business_verification_api, identity_verification_api, phone_verification_api, risk_compliance_api, location_weather_api, finance_data_api.",
|
|
48
48
|
"Use safe facets such as --use-case, --input-facet, --output-facet, --sensitivity-level, --delivery-mode, and --provider.",
|
|
49
49
|
"Use product and variant metadata to explain options in user language.",
|
|
50
|
+
"Money values from catalog JSON use minor units. For CNY, amount=10 means CNY 0.10, not CNY 10. Prefer display_amount when present, or divide amount/amount_minor by 100 before telling the user.",
|
|
50
51
|
"For products with requires_human_input=true, do not ask for identity numbers or phone numbers in chat; rely on ItPay human authorization/input.",
|
|
51
52
|
"Do not create checkout until the user intent maps to one selected variant or the user confirms a cart."
|
|
52
53
|
],
|
|
@@ -30,12 +30,14 @@
|
|
|
30
30
|
"The claim link is short-lived and single-use.",
|
|
31
31
|
"The agent may explain that ItPay intentionally separates agent operations from raw secret access.",
|
|
32
32
|
"If the human wants the agent to analyze or use the delivered result, ask them to click 'Give to Agent / 一键给 Agent' in the ItPay page and confirm with Passkey.",
|
|
33
|
-
"After the human grants access, the agent should discover the grant with `itp buyer vault grants list
|
|
33
|
+
"After the human grants access, the agent should discover the grant with `itp buyer vault grants list --checkout <checkout_id> --json`; do not ask the human to paste the grant id. The CLI restores the buyer agent session from the checkout auth handoff when possible.",
|
|
34
|
+
"If `buyer vault grants list` returns buyer_session.status=buyer_session_saved, the agent should proceed with the returned grant list; the saved session is intentionally not printed.",
|
|
34
35
|
"If the human later wants the agent to install or use something, wait for an explicit human-granted install/capability flow."
|
|
35
36
|
],
|
|
36
37
|
"forbidden": [
|
|
37
38
|
"Do not ask the human to paste the claim link or key into chat.",
|
|
38
39
|
"Do not fetch the claim page with CLI, curl, browser automation, or an agent tool.",
|
|
40
|
+
"Do not ask the human for auth session IDs, display tokens, buyer session tokens, or portal tokens.",
|
|
39
41
|
"Do not store raw content in local run files."
|
|
40
42
|
],
|
|
41
43
|
"next_docs": [
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"agent_rules": [
|
|
30
30
|
"Map user intent to the variant description and price.",
|
|
31
|
+
"Catalog JSON money fields use minor units. For CNY, amount=10 means CNY 0.10 and amount=50 means CNY 0.50. Use display_amount when present, or divide by 100 before explaining price to the user.",
|
|
31
32
|
"For API products, explain what the API checks or returns, quota unit, sensitivity level, required human input, and whether Passkey/WebAuthn reveal is required.",
|
|
32
33
|
"If metadata says agent_may_view_raw_result=false, tell the user secure delivery/reveal is human-first and do not request the raw result.",
|
|
33
34
|
"For enterprise fuzzy search, tell the user the required input is a company keyword/short name/brand. The user can say something broad like 京东; the service is designed to return candidates.",
|
|
@@ -39,10 +39,12 @@
|
|
|
39
39
|
"Use --json for every ItPay command.",
|
|
40
40
|
"Search and explain options before buying unless the user already named a variant.",
|
|
41
41
|
"Add the selected UCP Variant.id to cart; do not bypass cart for CORE-028 flows.",
|
|
42
|
+
"When explaining prices, remember ItPay JSON money fields use minor units. For CNY, amount=10 means CNY 0.10. Prefer display_amount when present.",
|
|
42
43
|
"Before checkout, make sure a buyer delivery email is available. If no email is known from the current buyer context, ask the human for it before creating checkout.",
|
|
43
44
|
"Do not invent, guess, or use a placeholder email. Secure delivery and account/order access depend on the buyer email.",
|
|
44
45
|
"For first purchase, show auth_qr as the ItPay first-purchase entry: the human first approves provider login/registration/profile sharing, then ItPay should continue the same checkout to payment.",
|
|
45
46
|
"After showing auth_qr, keep running/resuming the same checkout unless the human explicitly asks you to pause. Do not stop merely because a QR was displayed.",
|
|
47
|
+
"When a buyer command returns buyer_session.status=buyer_session_saved, the CLI has stored the buyer account session for this agent device. You may continue with checkout/payment or `buyer vault` commands without asking the human for a token.",
|
|
46
48
|
"Use high-level itp buy when possible; it is designed to show the first-purchase entry, wait/resume, continue to payment, wait for verification, and poll delivery.",
|
|
47
49
|
"Show the returned payment QR exactly as provided.",
|
|
48
50
|
"Payment truth comes only from payment_intent.verified.",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"A checkout/order has delivered a vault artifact and the human granted agent-readable access."
|
|
11
11
|
],
|
|
12
12
|
"required_state": {
|
|
13
|
-
"needs": ["authenticated buyer account session", "current agent device binding", "order_id or checkout_id or vault_artifact_id"],
|
|
13
|
+
"needs": ["checkout_id or authenticated buyer account session", "current agent device binding", "order_id or checkout_id or vault_artifact_id"],
|
|
14
14
|
"must_not_need": ["human portal token", "claim token", "passkey credential", "raw protected payload", "grant id copied by the human"]
|
|
15
15
|
},
|
|
16
16
|
"commands": [
|
|
@@ -37,14 +37,17 @@
|
|
|
37
37
|
],
|
|
38
38
|
"agent_rules": [
|
|
39
39
|
"Only read through `buyer vault` commands after the human has explicitly approved the agent grant in the ItPay portal.",
|
|
40
|
+
"Prefer `itp buyer vault grants list --checkout <checkout_id> --json`; the CLI can automatically restore the buyer agent session from the checkout auth handoff when possible.",
|
|
41
|
+
"If the response includes buyer_session.status=buyer_session_saved, continue directly to `buyer vault grants read <agent_read_grant_id> --json`; do not ask the human for session tokens, auth IDs, or grant IDs.",
|
|
40
42
|
"Do not ask the human to copy or paste `agent_read_grant_id`; discover it with `buyer vault grants list`.",
|
|
41
43
|
"If no grant is returned, tell the human to open their ItPay account portal, reveal with Passkey, choose fields, and confirm one-key agent authorization.",
|
|
42
44
|
"Use only fields returned in the grant view. Do not infer that unreturned fields are accessible.",
|
|
43
|
-
"If the command returns 401 or buyer_session_invalid
|
|
45
|
+
"If the command still returns 401 or buyer_session_invalid after using `--checkout`, run `itp buyer checkout status <checkout_id> --json`, then retry `itp buyer vault grants list --checkout <checkout_id> --json`. Ask the human to reauthorize only if the checkout/auth handoff has expired."
|
|
44
46
|
],
|
|
45
47
|
"forbidden": [
|
|
48
|
+
"Do not open, click through, scrape, or automate the human web UI yourself.",
|
|
46
49
|
"Do not open, scrape, or screenshot the human portal to obtain protected content.",
|
|
47
|
-
"Do not request passkey credentials, portal tokens, claim links, claim tokens, storage refs, provider AppCode, provider keys, or raw payloads.",
|
|
50
|
+
"Do not request passkey credentials, portal tokens, claim links, claim tokens, auth session IDs, display tokens, session tokens, storage refs, provider AppCode, provider keys, or raw payloads.",
|
|
48
51
|
"Do not use another agent's grant id. Grants are scoped to the exact buyer account session and agent device.",
|
|
49
52
|
"Do not cache selected fields beyond the task context unless the user explicitly asks you to create a local artifact."
|
|
50
53
|
],
|
package/package.json
CHANGED
|
@@ -67,7 +67,7 @@ itp buyer catalog get --variant <variant_id> --json
|
|
|
67
67
|
itp buyer cart create --variant <variant_id> --json
|
|
68
68
|
itp buyer cart create --variants <variant_id_1>,<variant_id_2> --quantities 1,1 --json
|
|
69
69
|
itp buyer cart show <cart_id> --json
|
|
70
|
-
itp buyer cart add <cart_id> --variant <variant_id> --quantity 1 --json
|
|
70
|
+
itp buyer cart add <cart_id> --variant <variant_id> --input key=value --quantity 1 --json
|
|
71
71
|
itp buyer cart remove <cart_id> --line <cart_line_item_id> --json
|
|
72
72
|
itp buyer checkout create --cart <cart_id> --email <buyer_email> --phone <buyer_phone> --json
|
|
73
73
|
itp buyer checkout resume <checkout_id> --json
|
|
@@ -82,10 +82,18 @@ Enterprise data products require query input at cart time:
|
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
itp buyer cart create --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=京东 --json
|
|
85
|
+
itp buyer cart show <cart_id> --json
|
|
86
|
+
itp buyer cart add <cart_id> --variant var_itpay_enterprise_fuzzy_search_cny01 --input company_name=美团 --json
|
|
85
87
|
itp buyer cart create --variant var_itpay_enterprise_precise_lookup_cny05 --input company_name_or_credit_no=北京京东世纪贸易有限公司 --json
|
|
86
88
|
itp buy var_itpay_enterprise_fuzzy_search_cny01 --sandbox --email <buyer_email> --input company_name=京东 --json
|
|
87
89
|
```
|
|
88
90
|
|
|
91
|
+
For cart edits, always read the server cart first with `buyer cart show`.
|
|
92
|
+
Cart line identity includes the variant, offer, price, provider product, and
|
|
93
|
+
normalized input. A fully identical line increments quantity; a different
|
|
94
|
+
company name, exact name, page number, setting, or other input must stay as a
|
|
95
|
+
separate line.
|
|
96
|
+
|
|
89
97
|
Use fuzzy search when the user gives a short name, brand, keyword, or uncertain
|
|
90
98
|
entity. Use precise lookup only after you have the exact China mainland
|
|
91
99
|
registered company name or unified social credit code. If the user says
|
|
@@ -97,9 +105,11 @@ registered name or run fuzzy search first.
|
|
|
97
105
|
1. Use `--json` for every ItPay command.
|
|
98
106
|
2. Do not invent service IDs, variant IDs, checkout IDs, payment URLs, QR URLs,
|
|
99
107
|
payment intent IDs, delivery IDs, or claim links.
|
|
100
|
-
3. When the user asks for several compatible services,
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
3. When the user asks for several compatible services, use one cart and one
|
|
109
|
+
checkout. Prefer `buyer cart create` for the first line, then `buyer cart
|
|
110
|
+
show` and `buyer cart add` for each additional query line so each service
|
|
111
|
+
input is locked to the correct cart line. Split only when ItPay rejects the
|
|
112
|
+
cart or explicitly says split checkout is required.
|
|
103
113
|
4. Before checkout, make sure a buyer delivery email is available. If the CLI
|
|
104
114
|
has no known buyer email, ask the human for the email; do not invent one,
|
|
105
115
|
do not use placeholders, and do not proceed to checkout without it. The
|
|
@@ -126,8 +136,13 @@ registered name or run fuzzy search first.
|
|
|
126
136
|
`delivery_claimable`, `check_email`, and `claim_link_sent`, but must not
|
|
127
137
|
fetch or reveal protected content.
|
|
128
138
|
11. If the human uses Passkey to authorize agent-readable vault access, do not
|
|
129
|
-
ask them to paste content, portal text, claim links,
|
|
139
|
+
ask them to paste content, portal text, claim links, session tokens, auth
|
|
140
|
+
session IDs, display tokens, or grant IDs. Run
|
|
130
141
|
`itp buyer vault grants list ...` and then `itp buyer vault read ...`.
|
|
142
|
+
The CLI automatically restores the buyer agent session from the checkout
|
|
143
|
+
auth handoff when possible. If the JSON includes
|
|
144
|
+
`buyer_session.status=buyer_session_saved`, continue with the returned
|
|
145
|
+
grants; the session token is intentionally stored locally and not printed.
|
|
131
146
|
Use only the fields returned by that command.
|
|
132
147
|
12. If the user asks you to analyze, compare, summarize, install, or otherwise
|
|
133
148
|
use a delivered result, you may ask them to open the ItPay claim/account
|
|
@@ -140,6 +155,10 @@ registered name or run fuzzy search first.
|
|
|
140
155
|
broad keyword. For enterprise precise lookup, `company_name_or_credit_no`
|
|
141
156
|
must be exact; otherwise warn the user that the query may waste the paid
|
|
142
157
|
lookup.
|
|
158
|
+
15. Do not operate ItPay by opening the human web UI yourself. Use the CLI for
|
|
159
|
+
catalog, cart, checkout, payment wait, delivery status, grant discovery,
|
|
160
|
+
and vault reads. Browser/UI pages are for the human to scan, pay, claim,
|
|
161
|
+
reveal, and approve.
|
|
143
162
|
|
|
144
163
|
## Docs Directory
|
|
145
164
|
|