1688-cli 0.1.41 → 0.1.42

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.
Files changed (83) hide show
  1. package/AGENTS.md +112 -318
  2. package/ARCHITECTURE.md +106 -0
  3. package/README.md +100 -10
  4. package/dist/cli.js +98 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/cart-list.js +2 -1
  7. package/dist/commands/cart-list.js.map +1 -1
  8. package/dist/commands/compare.js +107 -0
  9. package/dist/commands/compare.js.map +1 -0
  10. package/dist/commands/doctor.js +19 -5
  11. package/dist/commands/doctor.js.map +1 -1
  12. package/dist/commands/offer.js +7 -5
  13. package/dist/commands/offer.js.map +1 -1
  14. package/dist/commands/order-list.js +4 -2
  15. package/dist/commands/order-list.js.map +1 -1
  16. package/dist/commands/order-logistics.js +4 -2
  17. package/dist/commands/order-logistics.js.map +1 -1
  18. package/dist/commands/research.js +142 -0
  19. package/dist/commands/research.js.map +1 -0
  20. package/dist/commands/search.js +59 -18
  21. package/dist/commands/search.js.map +1 -1
  22. package/dist/commands/seller-messages.js +7 -4
  23. package/dist/commands/seller-messages.js.map +1 -1
  24. package/dist/commands/sourcing-utils.js +438 -0
  25. package/dist/commands/sourcing-utils.js.map +1 -0
  26. package/dist/commands/supplier-inspect.js +559 -0
  27. package/dist/commands/supplier-inspect.js.map +1 -0
  28. package/dist/commands/supplier-search.js +522 -0
  29. package/dist/commands/supplier-search.js.map +1 -0
  30. package/dist/daemon/protocol.js +2 -1
  31. package/dist/daemon/protocol.js.map +1 -1
  32. package/dist/session/dispatch.js +2 -0
  33. package/dist/session/dispatch.js.map +1 -1
  34. package/dist/session/im-ws.js +8 -5
  35. package/dist/session/im-ws.js.map +1 -1
  36. package/dist/session/paths.js +17 -4
  37. package/dist/session/paths.js.map +1 -1
  38. package/dist/session/search-mtop.js +53 -0
  39. package/dist/session/search-mtop.js.map +1 -1
  40. package/dist/session/supplier-search.js +403 -0
  41. package/dist/session/supplier-search.js.map +1 -0
  42. package/dist/util/encoding.js +8 -0
  43. package/dist/util/encoding.js.map +1 -0
  44. package/dist/util/temp.js +6 -0
  45. package/dist/util/temp.js.map +1 -0
  46. package/docs/AGENT_MAPS_PLAN.md +171 -0
  47. package/docs/AGENT_WORKING_PRINCIPLES.md +143 -0
  48. package/docs/COMMANDS.md +199 -0
  49. package/docs/FEATURES.md +45 -0
  50. package/docs/JSON_CONTRACTS.md +390 -0
  51. package/docs/QUALITY_SCORE.md +60 -0
  52. package/docs/README.md +35 -0
  53. package/docs/RELIABILITY.md +61 -0
  54. package/docs/SAFETY.md +100 -0
  55. package/docs/WORKFLOW.md +82 -0
  56. package/docs/exec-plans/README.md +9 -0
  57. package/docs/exec-plans/active/README.md +4 -0
  58. package/docs/exec-plans/completed/2026-05-28-sourcing-research-v1.md +125 -0
  59. package/docs/exec-plans/completed/2026-05-31-supplier-inspect-v1.md +113 -0
  60. package/docs/exec-plans/completed/2026-06-04-supplier-search-v1.md +81 -0
  61. package/docs/exec-plans/completed/2026-06-07-windows-cli-compatibility.md +138 -0
  62. package/docs/exec-plans/completed/README.md +4 -0
  63. package/docs/exec-plans/tech-debt-tracker.md +5 -0
  64. package/docs/generated/command-index.md +54 -0
  65. package/docs/generated/json-shapes.md +111 -0
  66. package/docs/generated/module-map.md +13 -0
  67. package/docs/generated/test-index.md +34 -0
  68. package/docs/playbooks/add-command.md +15 -0
  69. package/docs/playbooks/add-mtop-capture.md +13 -0
  70. package/docs/playbooks/change-json-output.md +11 -0
  71. package/docs/playbooks/debug-risk-control.md +12 -0
  72. package/docs/playbooks/update-cli-release.md +11 -0
  73. package/docs/specs/checkout-and-orders.md +30 -0
  74. package/docs/specs/seller-im.md +28 -0
  75. package/docs/specs/sourcing-research.md +186 -0
  76. package/docs/specs/supplier-inspect.md +144 -0
  77. package/docs/specs/supplier-search.md +179 -0
  78. package/docs/specs/windows-cli-compatibility.md +123 -0
  79. package/package.json +12 -2
  80. package/scripts/check_agent_map.mjs +86 -0
  81. package/scripts/fix_bin_mode.mjs +18 -0
  82. package/scripts/generate_agent_context.mjs +253 -0
  83. package/scripts/postinstall.mjs +12 -4
@@ -0,0 +1,111 @@
1
+ # JSON Shapes
2
+
3
+ _Generated by `scripts/generate_agent_context.mjs`._
4
+
5
+ This is a heuristic index of exported TypeScript interfaces that are likely to matter for agent-facing JSON.
6
+
7
+ | Interface | File | Notable Fields |
8
+ |---|---|---|
9
+ | `CartAddArgs` | `src/commands/cart-add.ts` | `offerId: string;`<br>`skuId: string;`<br>`quantity: number;`<br>`headed?: boolean;` |
10
+ | `CartAddOpts` | `src/commands/cart-add.ts` | `offerId: string;`<br>`sku?: string;`<br>`qty?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
11
+ | `CartAddResult` | `src/commands/cart-add.ts` | `ok: boolean;`<br>`confirmationStatus: 'confirmed';`<br>`added: CartItem;`<br>`/** True when a brand-new cart row was created. False when the SKU was`<br>`isNewRow: boolean;`<br>`/** Actual quantity added by this call. For a new row it equals`<br>`addedQuantity: number;` |
12
+ | `CartItem` | `src/commands/cart-list.ts` | `cartId: string;`<br>`offerId: string;`<br>`skuId: string \| null;`<br>`productTitle: string;`<br>`skuTitle: string \| null;`<br>`unit: string \| null;`<br>`quantity: number;`<br>`unitPrice: number;`<br>`amount: number;`<br>`minQuantity: number \| null;`<br>`maxQuantity: number \| null;`<br>`image: string \| null;`<br>`checked: boolean;`<br>`effective: boolean;` |
13
+ | `CartListArgs` | `src/commands/cart-list.ts` | `headed?: boolean;` |
14
+ | `CartListOpts` | `src/commands/cart-list.ts` | `profile?: string;`<br>`headed?: boolean;` |
15
+ | `CartListResult` | `src/commands/cart-list.ts` | `total: number;`<br>`selectedCount: number;`<br>`items: CartItem[];` |
16
+ | `CartRemoveArgs` | `src/commands/cart-remove.ts` | `cartId: string;`<br>`headed?: boolean;` |
17
+ | `CartRemoveOpts` | `src/commands/cart-remove.ts` | `cartId: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
18
+ | `CartRemoveResult` | `src/commands/cart-remove.ts` | `ok: boolean;`<br>`removed: CartItem;` |
19
+ | `CheckoutConfirmArgs` | `src/commands/checkout-confirm.ts` | `cartIds: string[];`<br>`headed?: boolean;` |
20
+ | `CheckoutConfirmOpts` | `src/commands/checkout-confirm.ts` | `cartIds: string[];`<br>`yes?: boolean;`<br>`agent?: boolean;`<br>`profile?: string;` |
21
+ | `CheckoutConfirmResult` | `src/commands/checkout-confirm.ts` | `ok: boolean;`<br>`placed: boolean;`<br>`finalUrl: string;`<br>`orderId: string \| null;`<br>`message: string;`<br>`preview: CheckoutPrepareResult;` |
22
+ | `CheckoutPrepareArgs` | `src/commands/checkout-prepare.ts` | `cartIds: string[];`<br>`headed?: boolean;` |
23
+ | `CheckoutPrepareOpts` | `src/commands/checkout-prepare.ts` | `cartIds: string[];`<br>`profile?: string;`<br>`headed?: boolean;` |
24
+ | `CheckoutPrepareResult` | `src/commands/checkout-prepare.ts` | `ok: boolean;`<br>`url: string;`<br>`totalAmount: number;`<br>`productAmount: number;`<br>`shippingAmount: number;`<br>`taxAmount: number;`<br>`receiveAddress: {`<br>`fullName: string \| null;`<br>`mobile: string \| null;`<br>`address: string \| null;`<br>`region: string \| null;`<br>`orders: PrepareOrder[];` |
25
+ | `PrepareOrder` | `src/commands/checkout-prepare.ts` | `seller: {`<br>`memberId: string \| null;`<br>`loginId: string \| null;`<br>`companyName: string \| null;`<br>`totalAmount: number;`<br>`productAmount: number;`<br>`shippingAmount: number;`<br>`items: PrepareItem[];` |
26
+ | `CompareOpts` | `src/commands/compare.ts` | `offerIds: string[];`<br>`csv?: boolean;`<br>`output?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
27
+ | `CompareResult` | `src/commands/compare.ts` | `total: number;`<br>`ok: number;`<br>`failed: number;`<br>`items: CompareItem[];` |
28
+ | `DebugLastOpts` | `src/commands/debug.ts` | `failed?: boolean;` |
29
+ | `DebugListOpts` | `src/commands/debug.ts` | `limit?: string;`<br>`failed?: boolean;` |
30
+ | `DebugShowOpts` | `src/commands/debug.ts` | `requestId: string;` |
31
+ | `DoctorOpts` | `src/commands/doctor.ts` | `launch?: boolean;`<br>`live?: boolean;`<br>`profile?: string;` |
32
+ | `FeedbackOpts` | `src/commands/feedback.ts` | `message?: string;`<br>`bug?: boolean;`<br>`open?: boolean;`<br>`submit?: boolean;` |
33
+ | `FeedbackResult` | `src/commands/feedback.ts` | `url: string;`<br>`title: string;`<br>`bodyPreview: string;`<br>`submitted: boolean;` |
34
+ | `ImageSearchArgs` | `src/commands/image-search.ts` | `imagePath: string;`<br>`max: number;`<br>`headed?: boolean;` |
35
+ | `ImageSearchOpts` | `src/commands/image-search.ts` | `imagePath: string;`<br>`max?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
36
+ | `ImageSearchResult` | `src/commands/image-search.ts` | `imageId: string;`<br>`total: number;`<br>`offers: Offer[];` |
37
+ | `InboxArgs` | `src/commands/inbox.ts` | `limit: number;`<br>`unreadOnly: boolean;`<br>`myLoginId: string;`<br>`myMemberId: string;`<br>`headed?: boolean;` |
38
+ | `InboxOpts` | `src/commands/inbox.ts` | `limit?: string;`<br>`unread?: boolean;`<br>`profile?: string;`<br>`headed?: boolean;` |
39
+ | `InboxResult` | `src/commands/inbox.ts` | `myLoginId: string;`<br>`myMemberId: string;`<br>`conversations: Conversation[];`<br>`nextCursor: number \| null;`<br>`truncated: boolean;` |
40
+ | `LoginOpts` | `src/commands/login.ts` | `force?: boolean;`<br>`timeout?: string;`<br>`profile?: string;`<br>`headed?: boolean;`<br>`noDaemon?: boolean;` |
41
+ | `LogoutOpts` | `src/commands/logout.ts` | `yes?: boolean;`<br>`profile?: string;` |
42
+ | `OfferArgs` | `src/commands/offer.ts` | `offerId: string;`<br>`headed?: boolean;` |
43
+ | `OfferOpts` | `src/commands/offer.ts` | `offerId: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
44
+ | `OfferResult` | `src/commands/offer.ts` | `offerId: string;`<br>`title: string;`<br>`url: string;`<br>`priceRange: string \| null;`<br>`priceMin: number \| null;`<br>`priceMax: number \| null;`<br>`/** Display unit ("件" / "个" / "米" ...) */`<br>`unitName: string \| null;`<br>`/** 起订量 — minimum order quantity for a single SKU buy. */`<br>`minOrderQty: number \| null;`<br>`/** 混批起订量 — minimum quantity when mixing SKUs in one order. */`<br>`mixOrderQty: number \| null;`<br>`/** Bulk-discount tiers, e.g. [{minQty: 1, price: 4.16}, {minQty: 100, price: 3.50}]. */`<br>`priceTiers: PriceTier[];` |
45
+ | `PriceTier` | `src/commands/offer.ts` | `minQty: number;`<br>`price: number;` |
46
+ | `ProductAttribute` | `src/commands/offer.ts` | `name: string;`<br>`value: string;` |
47
+ | `SkuOption` | `src/commands/offer.ts` | `prop: string;`<br>`values: { name: string; imageUrl: string \| null }[];` |
48
+ | `SkuPackage` | `src/commands/offer.ts` | `skuId: string;`<br>`spec: string;`<br>`/** cm */`<br>`length: number \| null;`<br>`width: number \| null;`<br>`height: number \| null;`<br>`/** Stated weight (raw value — 1688 sometimes uses grams or kg per offer). */`<br>`weight: number \| null;`<br>`/** Volume (cm³). */`<br>`volume: number \| null;` |
49
+ | `SkuVariant` | `src/commands/offer.ts` | `skuId: string;`<br>`specs: string;`<br>`price: number \| null;`<br>`/** Bulk-tier price when 1688 surfaces a separate multi-piece price. */`<br>`multiPrice: number \| null;`<br>`stock: number \| null;`<br>`saleCount: number;`<br>`/** Best-effort image URL derived from the first option (颜色/款式) match. */`<br>`image: string \| null;` |
50
+ | `OrderGetArgs` | `src/commands/order-get.ts` | `orderId: string;`<br>`maxScanPages: number;`<br>`/** Narrow scan to a specific tradeStatus when known — much faster for`<br>`statusHint?: string;`<br>`headed?: boolean;` |
51
+ | `OrderGetOpts` | `src/commands/order-get.ts` | `orderId: string;`<br>`maxScanPages?: string;`<br>`status?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
52
+ | `Order` | `src/commands/order-list.ts` | `orderId: string;`<br>`status: string;`<br>`statusLabel: string;`<br>`bizType: string \| null; // "cb" / "pc" / ...`<br>`createdAt: string;`<br>`paidAt: string \| null;`<br>`shippedAt: string \| null;`<br>`confirmGoodsTime: string \| null;`<br>`totalAmount: number;`<br>`productAmount: number;`<br>`shipping: number;`<br>`originalAmount: number; // before any promotions`<br>`discountAmount: number; // sum of all promotions applied`<br>`adjustment: number; // seller manual price adjustment (改价)` |
53
+ | `OrderAction` | `src/commands/order-list.ts` | `key: string; // permissionKey, e.g. "canBuyerRefund"`<br>`name: string; // display name, e.g. "申请退款"`<br>`url: string \| null;`<br>`highlight: boolean;` |
54
+ | `OrderItem` | `src/commands/order-list.ts` | `entryId: string;`<br>`productName: string;`<br>`spec: string;`<br>`quantity: number;`<br>`unitPrice: number;`<br>`amount: number;`<br>`image: string \| null;`<br>`productNumber: string \| null;` |
55
+ | `OrderListArgs` | `src/commands/order-list.ts` | `status: string;`<br>`page: number;`<br>`pageSize: number;`<br>`headed?: boolean;` |
56
+ | `OrderListOpts` | `src/commands/order-list.ts` | `status?: string;`<br>`page?: string;`<br>`pageSize?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
57
+ | `OrderListResult` | `src/commands/order-list.ts` | `status: string;`<br>`page: number;`<br>`pageSize: number;`<br>`totalPages: number;`<br>`totalOrders: number;`<br>`orders: Order[];` |
58
+ | `OrderService` | `src/commands/order-list.ts` | `productName: string;`<br>`category: string; // "insurance" / "refund" / ...`<br>`payer: string; // "seller" / "buyer"`<br>`detailLink: string \| null;` |
59
+ | `OrderStep` | `src/commands/order-list.ts` | `status: string;`<br>`name: string;`<br>`paid: number;`<br>`goods: number;`<br>`postage: number;` |
60
+ | `OrderLogisticsArgs` | `src/commands/order-logistics.ts` | `orderId: string;`<br>`maxScanPages: number;`<br>`/** Narrow the scan to one tradeStatus (e.g. "waitbuyerreceive") when known —`<br>`statusHint?: string;`<br>`headed?: boolean;` |
61
+ | `OrderLogisticsOpts` | `src/commands/order-logistics.ts` | `orderId: string;`<br>`maxScanPages?: string;`<br>`status?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
62
+ | `OrderLogisticsResult` | `src/commands/order-logistics.ts` | `orderId: string;`<br>`found: boolean;`<br>`trace: LogisticsTrace[];` |
63
+ | `ResearchOpts` | `src/commands/research.ts` | `keywords: string[];`<br>`maxPerQuery?: string;`<br>`sort?: string;`<br>`priceMin?: string;`<br>`priceMax?: string;`<br>`province?: string;`<br>`city?: string;`<br>`verified?: string;`<br>`minTurnover?: string;`<br>`excludeAds?: boolean;`<br>`enrich?: string;`<br>`jsonl?: boolean;`<br>`csv?: boolean;`<br>`output?: string;` |
64
+ | `ResearchResult` | `src/commands/research.ts` | `queries: string[];`<br>`sort: SearchSort;`<br>`filters: SearchFilterSummary;`<br>`maxPerQuery: number;`<br>`enrichTop: number;`<br>`total: number;`<br>`enrichedCount: number;`<br>`items: ResearchItem[];` |
65
+ | `SearchArgs` | `src/commands/search.ts` | `keyword: string;`<br>`max: number;`<br>`sort?: SearchSort;`<br>`filters?: SearchFilterSummary;`<br>`headed?: boolean;` |
66
+ | `SearchOpts` | `src/commands/search.ts` | `max?: string;`<br>`sort?: string;`<br>`priceMin?: string;`<br>`priceMax?: string;`<br>`province?: string;`<br>`city?: string;`<br>`verified?: string;`<br>`minTurnover?: string;`<br>`excludeAds?: boolean;`<br>`profile?: string;`<br>`headed?: boolean;` |
67
+ | `SearchResult` | `src/commands/search.ts` | `keyword: string;`<br>`sort: SearchSort;`<br>`filters: SearchFilterSummary;`<br>`totalBeforeFilter: number;`<br>`total: number;`<br>`offers: Offer[];` |
68
+ | `SellerChatArgs` | `src/commands/seller-chat.ts` | `/** Display name(s) to find seller in 旺旺 sidebar — try in order */`<br>`searchNames: string[];`<br>`/** Seller loginId (raw, no cnalichn prefix) for order/offer-context URL */`<br>`sellerLoginId?: string;`<br>`/** Order ID — passed in URL to trigger order-scoped conversation */`<br>`orderId?: string;`<br>`/** Offer ID — passed in URL to trigger pre-sale (offer-scoped) conversation */`<br>`offerId?: string;`<br>`myLoginId: string;`<br>`message: string;`<br>`headed?: boolean;` |
69
+ | `SellerChatOpts` | `src/commands/seller-chat.ts` | `target?: string;`<br>`message: string;`<br>`prefix?: boolean;`<br>`/** Skip sending order card link before message (use for follow-up replies) */`<br>`noCard?: boolean;`<br>`profile?: string;`<br>`headed?: boolean;` |
70
+ | `SellerChatResult` | `src/commands/seller-chat.ts` | `ok: boolean;`<br>`sentTo: string;`<br>`message: string;`<br>`sentAt: string;` |
71
+ | `SellerInquireOpts` | `src/commands/seller-inquire.ts` | `offerId: string;`<br>`message: string;`<br>`to?: string; // explicit seller loginId`<br>`profile?: string;`<br>`headed?: boolean;` |
72
+ | `Message` | `src/commands/seller-messages.ts` | `sender: string;`<br>`time: string \| null;`<br>`isMine: boolean;`<br>`content: string;`<br>`read: boolean;`<br>`/** Type of message — auto-detected from DOM. */`<br>`kind: MessageKind;`<br>`/** Populated when kind === 'offerCard' or 'orderCard'. */`<br>`card?: {`<br>`title: string \| null;`<br>`price: string \| null;`<br>`image: string \| null;`<br>`url: string \| null;`<br>`/** Server-side message ID (only present when sourced from WS). Used for` |
73
+ | `SellerMessagesArgs` | `src/commands/seller-messages.ts` | `searchNames: string[];`<br>`sellerLoginId?: string;`<br>`orderId?: string;`<br>`offerId?: string;`<br>`myLoginId: string;`<br>`limit: number;`<br>`headed?: boolean;` |
74
+ | `SellerMessagesOpts` | `src/commands/seller-messages.ts` | `target?: string;`<br>`offer?: string;`<br>`limit?: string;`<br>`since?: string;`<br>`watch?: boolean;`<br>`interval?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
75
+ | `SellerMessagesResult` | `src/commands/seller-messages.ts` | `conversation: string;`<br>`total: number;`<br>`messages: Message[];` |
76
+ | `SimilarArgs` | `src/commands/similar.ts` | `offerId: string;`<br>`max: number;`<br>`headed?: boolean;` |
77
+ | `SimilarOpts` | `src/commands/similar.ts` | `offerId: string;`<br>`max?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
78
+ | `SimilarResult` | `src/commands/similar.ts` | `offerId: string;`<br>`total: number;`<br>`offers: Offer[];` |
79
+ | `OfferDetailSummary` | `src/commands/sourcing-utils.ts` | `offerId: string;`<br>`title: string;`<br>`url: string;`<br>`priceMin: number \| null;`<br>`priceMax: number \| null;`<br>`unitName: string \| null;`<br>`minOrderQty: number \| null;`<br>`mixOrderQty: number \| null;`<br>`priceTiers: PriceTier[];`<br>`saledCount: number \| null;`<br>`categoryId: string \| null;`<br>`supplier: OfferResult['supplier'];`<br>`skuCount: number;`<br>`totalStock: number \| null;` |
80
+ | `SupplierInspectArgs` | `src/commands/supplier-inspect.ts` | `target: string;`<br>`headed?: boolean;` |
81
+ | `SupplierInspectOpts` | `src/commands/supplier-inspect.ts` | `target: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
82
+ | `SupplierInspectResult` | `src/commands/supplier-inspect.ts` | `target: SupplierTarget;`<br>`supplier: {`<br>`name: string \| null;`<br>`loginId: string \| null;`<br>`memberId: string \| null;`<br>`userId: string \| null;`<br>`companyId: string \| null;`<br>`shopUrl: string \| null;`<br>`shopUrls: Record<string, string>;`<br>`identity: string \| null;`<br>`signs: Record<string, boolean>;`<br>`factory: {`<br>`isFactory: boolean;`<br>`superFactory: boolean;` |
83
+ | `SupplierResearchOpts` | `src/commands/supplier-search.ts` | - |
84
+ | `SupplierSearchArgs` | `src/commands/supplier-search.ts` | `keywords: string[];`<br>`maxPerQuery: number;`<br>`enrichTop?: number;`<br>`filters?: SupplierFilters;`<br>`headed?: boolean;` |
85
+ | `SupplierSearchOpts` | `src/commands/supplier-search.ts` | `keywords: string[];`<br>`max?: string;`<br>`enrich?: string;`<br>`factoryOnly?: boolean;`<br>`province?: string;`<br>`city?: string;`<br>`minYears?: string;`<br>`minRepeatRate?: string;`<br>`minResponseRate?: string;`<br>`jsonl?: boolean;`<br>`csv?: boolean;`<br>`output?: string;`<br>`profile?: string;`<br>`headed?: boolean;` |
86
+ | `SupplierSearchResult` | `src/commands/supplier-search.ts` | `queries: string[];`<br>`source: {`<br>`kind: 'company-search';`<br>`endpoint: 'companySearchBusinessService';`<br>`offerAggregation: false;`<br>`filters: SupplierFilters;`<br>`maxPerQuery: number;`<br>`enrichTop: number;`<br>`totalBeforeFilter: number;`<br>`total: number;`<br>`enrichedCount: number;`<br>`items: SupplierSearchItem[];` |
87
+ | `WhoamiArgs` | `src/commands/whoami.ts` | `verify?: boolean;` |
88
+ | `WhoamiOpts` | `src/commands/whoami.ts` | `verify?: boolean;`<br>`profile?: string;` |
89
+ | `WhoamiResult` | `src/commands/whoami.ts` | `loggedIn: boolean;`<br>`memberId?: string;`<br>`nick?: string \| null;`<br>`lastVerifiedAt?: string \| null;` |
90
+ | `FakeShippedOpts` | `src/commands/workflows.ts` | `days?: string;`<br>`limit?: string;`<br>`maxPages?: string;`<br>`maxCheck?: string;`<br>`debug?: boolean;` |
91
+ | `SellerHistoryOpts` | `src/commands/workflows.ts` | `seller: string;`<br>`maxPages?: string;` |
92
+ | `ShippedOpts` | `src/commands/workflows.ts` | `orderId: string;` |
93
+ | `StuckOpts` | `src/commands/workflows.ts` | `days?: string;`<br>`limit?: string;` |
94
+ | `SessionOpts` | `src/session/context.ts` | `headless: boolean;`<br>`profile?: string;` |
95
+ | `DispatchOpts` | `src/session/dispatch.ts` | `headed?: boolean;`<br>`profile?: string;`<br>`noDaemon?: boolean;` |
96
+ | `DecodedMessage` | `src/session/im-cards.ts` | `kind: MessageKind;`<br>`preview: string;`<br>`/** Set when `kind === 'card'`. Semantic name when known, `'unknown'` otherwise. */`<br>`cardTemplate?: CardTemplate;`<br>`/** Raw 6-digit template code (`170002`, `467001`, …). Always present for cards. */`<br>`cardCode?: string;`<br>`/** Populated only when at least one field resolved — keep JSON output compact. */`<br>`extras?: MessageExtras;` |
97
+ | `MessageExtras` | `src/session/im-cards.ts` | `/** Trade order id parsed from card link, if any. */`<br>`orderId?: string;`<br>`/** Offer (product) id parsed from card link, if any. */`<br>`offerId?: string;`<br>`/** Refund / 退货 id, if any. */`<br>`refundId?: string;`<br>`/** Product / order thumbnail URL. */`<br>`imgUrl?: string;`<br>`/** Clickthrough URL embedded in the card. */`<br>`linkUrl?: string;`<br>`/** Display string such as "订单金额:¥4.90" or "¥0.04". */`<br>`amount?: string;` |
98
+ | `RawImMessage` | `src/session/im-cards.ts` | `content?: {`<br>`contentType?: number;`<br>`text?: { content?: string };`<br>`custom?: {`<br>`summary?: string;`<br>`data?: string;`<br>`title?: string;`<br>`extension?: {`<br>`biMsgType?: string;`<br>`dynamic_msg_content?: string;` |
99
+ | `StableLocatorResult` | `src/session/locator.ts` | `strategy: string;`<br>`description: string;` |
100
+ | `ResponseCaptureActionResult` | `src/session/response-capture.ts` | `actionResult: TResult;`<br>`response: T \| null;`<br>`diagnostics: ResponseCaptureDiagnostics;` |
101
+ | `ResponseCaptureEmptyResult` | `src/session/response-capture.ts` | `at: string;`<br>`url: string;` |
102
+ | `SearchOfferCaptureDiagnostics` | `src/session/search-capture.ts` | `startedAt: string;`<br>`endedAt?: string;`<br>`disposed: boolean;`<br>`finalStatus?: SearchOfferCaptureWaitStatus;`<br>`timedOut: boolean;`<br>`seenCount: number;`<br>`matchedCount: number;`<br>`parsedCount: number;`<br>`failureCount: number;`<br>`lastSeenUrl?: string;`<br>`lastMatchedUrl?: string;`<br>`lastParsedUrl?: string;`<br>`lastError?: { name?: string; message: string };`<br>`failures: SearchOfferCaptureFailure[];` |
103
+ | `SearchOfferCaptureFailure` | `src/session/search-capture.ts` | `at: string;`<br>`url: string;`<br>`name?: string;`<br>`message: string;` |
104
+ | `SearchOfferCaptureOptions` | `src/session/search-capture.ts` | `page: Page;`<br>`requireMethod?: string;`<br>`targetPage?: () => number;`<br>`keep?: 'first' \| 'largest';` |
105
+ | `SearchOfferCaptureResult` | `src/session/search-capture.ts` | `actionResult: TResult;`<br>`status: SearchOfferCaptureWaitStatus;`<br>`offers: Offer[];`<br>`diagnostics: SearchOfferCaptureDiagnostics;` |
106
+ | `SearchOfferCaptureWaitOptions` | `src/session/search-capture.ts` | `timeoutMs: number;`<br>`intervalMs?: number;`<br>`isBlocked?: () => boolean \| Promise<boolean>;`<br>`isClosed?: () => boolean;` |
107
+ | `SearchOfferCaptureWaitResult` | `src/session/search-capture.ts` | `status: SearchOfferCaptureWaitStatus;`<br>`offers: Offer[];`<br>`diagnostics: SearchOfferCaptureDiagnostics;` |
108
+ | `Offer` | `src/session/search-mtop.ts` | `offerId: string;`<br>`title: string;`<br>`price: { text: string; min: number \| null; max: number \| null };`<br>`supplier: {`<br>`name: string \| null;`<br>`shopUrl: string \| null;`<br>`years: number \| null;`<br>`location: { province: string \| null; city: string \| null };`<br>`bizType: string \| null;`<br>`verified: { factory: boolean; business: boolean; superFactory: boolean };`<br>`tags: string[];`<br>`serviceTags?: string[];`<br>`productBadges?: string[];`<br>`demand?: {` |
109
+ | `RawOfferItem` | `src/session/search-mtop.ts` | `cellType?: string;`<br>`data?: {`<br>`offerId?: string;`<br>`title?: string;`<br>`priceInfo?: { price?: string };`<br>`offerPicUrl?: string;`<br>`loginId?: string;`<br>`memberId?: string;`<br>`province?: string;`<br>`city?: string;`<br>`bookedCount?: string;`<br>`repurchaseRate?: string;`<br>`repurchaseRateText?: string;`<br>`orderCount?: string \| number;` |
110
+ | `SupplierOfferPreview` | `src/session/supplier-search.ts` | `offerId: string \| null;`<br>`title: string;`<br>`url: string \| null;`<br>`price: { text: string \| null; value: number \| null };`<br>`unit: string \| null;`<br>`image: string \| null;`<br>`bookedCount: number \| null;`<br>`saleQuantity: number \| null;`<br>`quantitySumMonth: number \| null;`<br>`brief: string \| null;` |
111
+ | `SupplierSearchCaptureWaitResult` | `src/session/supplier-search.ts` | `status: SupplierSearchCaptureWaitStatus;`<br>`data: SupplierSearchServiceData \| null;`<br>`diagnostics: SupplierSearchCaptureDiagnostics;` |
@@ -0,0 +1,13 @@
1
+ # Module Map
2
+
3
+ _Generated by `scripts/generate_agent_context.mjs`._
4
+
5
+ | Directory | Source Files | Related Tests | Notes |
6
+ |---|---:|---:|---|
7
+ | `src` | 1 | 0 | - |
8
+ | `src/auth` | 2 | 1 | login/session/cookie helpers |
9
+ | `src/commands` | 29 | 5 | command executors and renderers |
10
+ | `src/daemon` | 5 | 0 | background daemon client/server/protocol |
11
+ | `src/io` | 3 | 10 | output, prompts, and errors |
12
+ | `src/session` | 27 | 11 | browser/session automation helpers |
13
+ | `src/util` | 3 | 0 | shared utilities |
@@ -0,0 +1,34 @@
1
+ # Test Index
2
+
3
+ _Generated by `scripts/generate_agent_context.mjs`._
4
+
5
+ | Test File | Focus | Risk Notes |
6
+ |---|---|---|
7
+ | `tests/artifacts.test.ts` | artifacts | live/session-sensitive, browser/page-state, fixture/parser |
8
+ | `tests/config.test.ts` | config | live/session-sensitive, fixture/parser |
9
+ | `tests/cookies.test.ts` | cookies | live/session-sensitive, browser/page-state |
10
+ | `tests/debug.test.ts` | debug | live/session-sensitive |
11
+ | `tests/doctor-live.test.ts` | doctor-live | live/session-sensitive |
12
+ | `tests/doctor.test.ts` | doctor | live/session-sensitive |
13
+ | `tests/events.test.ts` | events | live/session-sensitive, browser/page-state |
14
+ | `tests/fix-bin-mode.test.ts` | fix-bin-mode | - |
15
+ | `tests/im-cards.test.ts` | im-cards | live/session-sensitive, fixture/parser |
16
+ | `tests/inbox.test.ts` | inbox | live/session-sensitive |
17
+ | `tests/locator.test.ts` | locator | browser/page-state |
18
+ | `tests/mtop.test.ts` | mtop | fixture/parser |
19
+ | `tests/navigation-guard.test.ts` | navigation-guard | live/session-sensitive |
20
+ | `tests/output.test.ts` | output | - |
21
+ | `tests/page-state.test.ts` | page-state | live/session-sensitive, browser/page-state |
22
+ | `tests/paths.test.ts` | paths | - |
23
+ | `tests/profile.test.ts` | profile | live/session-sensitive |
24
+ | `tests/recovery.test.ts` | recovery | browser/page-state |
25
+ | `tests/replay-fixtures.test.ts` | replay-fixtures | browser/page-state, fixture/parser |
26
+ | `tests/response-capture.test.ts` | response-capture | browser/page-state, fixture/parser |
27
+ | `tests/search-capture.test.ts` | search-capture | browser/page-state, fixture/parser |
28
+ | `tests/search-mtop.test.ts` | search-mtop | browser/page-state, fixture/parser |
29
+ | `tests/search-options.test.ts` | search-options | - |
30
+ | `tests/sourcing-utils.test.ts` | sourcing-utils | fixture/parser |
31
+ | `tests/state.test.ts` | state | live/session-sensitive |
32
+ | `tests/supplier-inspect.test.ts` | supplier-inspect | browser/page-state, fixture/parser |
33
+ | `tests/supplier-search.test.ts` | supplier-search | browser/page-state, fixture/parser |
34
+ | `tests/wait.test.ts` | wait | - |
@@ -0,0 +1,15 @@
1
+ # Playbook: Add A Command
2
+
3
+ 1. Add the Commander surface in `src/cli.ts`.
4
+ 2. Create or update the owning module in `src/commands`.
5
+ 3. Keep CLI parsing in `run(opts)` and browser/session work in
6
+ `execute(ctx, args)` when daemon dispatch is needed.
7
+ 4. Wire daemon dispatch in `src/session/dispatch.ts` if the command should run
8
+ through the daemon.
9
+ 5. Use `emit({ human, data })` so JSON/text dual mode stays consistent.
10
+ 6. Add deterministic tests for parsing, output, mtop payload parsing, or helper
11
+ behavior.
12
+ 7. Update `docs/COMMANDS.md` and `docs/JSON_CONTRACTS.md` when behavior or
13
+ output shape changes.
14
+ 8. Run `pnpm agent-context` and the focused verification command.
15
+
@@ -0,0 +1,13 @@
1
+ # Playbook: Add Mtop Capture
2
+
3
+ 1. Probe the browser flow manually only when needed and safe.
4
+ 2. Capture the smallest stable endpoint/method/appId signal.
5
+ 3. Add parsing logic under `src/session` when it is shared, or in the command
6
+ module when it is command-specific.
7
+ 4. Save representative payloads as tests fixtures when they do not contain
8
+ sensitive account data.
9
+ 5. Return structured `CliError` failures for timeout, login redirect,
10
+ risk-control, and parse failure.
11
+ 6. Update `docs/JSON_CONTRACTS.md` if the capture changes agent-facing output.
12
+ 7. Run focused parser/capture tests, then `pnpm agent-context`.
13
+
@@ -0,0 +1,11 @@
1
+ # Playbook: Change JSON Output
2
+
3
+ 1. Identify the stable result interface in `src/commands/*`.
4
+ 2. Prefer additive fields. Do not rename or remove fields unless the user
5
+ approved a breaking change.
6
+ 3. Update human rendering only after preserving machine output.
7
+ 4. Add or update tests for the JSON shape or parser feeding it.
8
+ 5. Update `docs/JSON_CONTRACTS.md`.
9
+ 6. Run `pnpm agent-context`.
10
+ 7. Run `pnpm test` or a focused test plus `pnpm docs-check`.
11
+
@@ -0,0 +1,12 @@
1
+ # Playbook: Debug Risk Control
2
+
3
+ 1. Confirm whether the failure is login redirect, risk-control URL, empty mtop
4
+ capture, network error, or browser closure.
5
+ 2. Check structured exit code behavior. Exit `3` should point to `1688 login`;
6
+ exit `4` should point to rerunning once with `--headed`.
7
+ 3. Use `--headed` only when manual slider solving is expected.
8
+ 4. Inspect `src/session/page-state.ts`, `src/session/recovery.ts`, and the
9
+ relevant command's capture logic.
10
+ 5. Add fixture-backed tests for page-state or parser changes.
11
+ 6. Do not add silent retry loops around risk-control failures.
12
+
@@ -0,0 +1,11 @@
1
+ # Playbook: Update CLI Release Behavior
2
+
3
+ 1. Check `package.json`, `CHANGELOG.md`, `README.md`, and update-notifier
4
+ behavior in `src/cli.ts`.
5
+ 2. Preserve the update protocol in `docs/SAFETY.md`: never run a global install
6
+ command without explicit current-turn user approval.
7
+ 3. If daemon behavior changes after upgrade, document whether
8
+ `1688 daemon reload` is required.
9
+ 4. Run `pnpm build`, `pnpm test`, and `pnpm agent-context`.
10
+ 5. Update docs when install, postinstall, or release packaging behavior changes.
11
+
@@ -0,0 +1,30 @@
1
+ # Checkout And Orders
2
+
3
+ Checkout and order tracking commands operate real buyer state.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ 1688 checkout prepare <cartIds...>
9
+ 1688 checkout confirm <cartIds...>
10
+ 1688 order list [--status <status>]
11
+ 1688 order get <orderId>
12
+ 1688 order logistics <orderId>
13
+ 1688 shipped <orderId>
14
+ 1688 stuck [--days N]
15
+ 1688 fake-shipped [--days N]
16
+ 1688 seller-history <sellerName>
17
+ ```
18
+
19
+ ## Checkout Boundary
20
+
21
+ `checkout prepare` is read-only. `checkout confirm` places a real order and
22
+ must follow the protocol in `docs/SAFETY.md`.
23
+
24
+ ## Agent Requirements
25
+
26
+ - Preserve order IDs, seller identity, totals, line items, services, badges,
27
+ actions, and logistics trace fields.
28
+ - Keep overdue/fake-shipped workflows explainable: include thresholds and the
29
+ evidence used to flag each order.
30
+ - Never hide partial scans; report scan limits and blockers.
@@ -0,0 +1,28 @@
1
+ # Seller IM
2
+
3
+ Seller IM commands cover pre-sale inquiry and post-sale follow-up through
4
+ Wangwang/1688 chat.
5
+
6
+ ## Commands
7
+
8
+ ```bash
9
+ 1688 seller inquire <offerId> <message>
10
+ 1688 seller chat <orderId|loginId> <message>
11
+ 1688 seller messages --offer <offerId>
12
+ 1688 seller messages <orderId|loginId>
13
+ 1688 seller messages ... --watch
14
+ 1688 inbox
15
+ ```
16
+
17
+ ## Safety
18
+
19
+ Sending messages contacts real suppliers. Follow `docs/SAFETY.md` before
20
+ sending agent-authored text.
21
+
22
+ ## Agent Requirements
23
+
24
+ - Preserve line-delimited JSON in watch mode.
25
+ - Deduplicate messages by server-side `messageId` when available.
26
+ - Preserve `kind` and `card` fields so agents can distinguish text, offer
27
+ cards, order cards, images, and auto replies.
28
+ - Keep order/offer scoped conversations attached to the right context.
@@ -0,0 +1,186 @@
1
+ # Sourcing Research
2
+
3
+ This spec defines the first durable sourcing-research layer for `1688-cli`.
4
+ It turns search results into procurement decisions while preserving the CLI's
5
+ buyer-workflow identity: human-paced, logged-in, safe for a real account, and
6
+ agent-friendly JSON.
7
+
8
+ ## Goal
9
+
10
+ Help an agent or buyer answer:
11
+
12
+ - Which offers have demand?
13
+ - Which suppliers look trustworthy?
14
+ - Which offers are cheap enough for the target range?
15
+ - Which offers deserve detail-page enrichment?
16
+ - Which offer IDs should be compared before inquiry/cart/checkout?
17
+
18
+ ## Non-Goals
19
+
20
+ - Do not build a bulk scraping farm.
21
+ - Do not bypass login, risk control, or slider verification.
22
+ - Do not add multi-account orchestration.
23
+ - Do not claim supplier scores, repurchase rate, or service guarantees unless
24
+ the current 1688 payload exposes them reliably.
25
+ - Do not make ordinary `search` slow by fetching every detail page.
26
+
27
+ ## Commands
28
+
29
+ ### `search`
30
+
31
+ Add research-oriented read-only controls to ordinary keyword search:
32
+
33
+ ```bash
34
+ 1688 search <keyword> \
35
+ --sort relevance|best-selling|price-asc|price-desc \
36
+ --price-min 1 \
37
+ --price-max 50 \
38
+ --province 广东 \
39
+ --city 深圳 \
40
+ --verified any|factory|business|super-factory \
41
+ --min-turnover 100 \
42
+ --exclude-ads
43
+ ```
44
+
45
+ `search` remains fast. Filters and local sort apply to the collected result
46
+ set. Remote sort parameters may be added to the search URL when known, but the
47
+ command must still locally normalize output ordering for deterministic agent
48
+ behavior.
49
+
50
+ ### `research`
51
+
52
+ Add a multi-keyword research command:
53
+
54
+ ```bash
55
+ 1688 research <keyword...> \
56
+ --max-per-query 60 \
57
+ --sort best-selling \
58
+ --price-max 50 \
59
+ --verified super-factory \
60
+ --enrich top:10 \
61
+ --jsonl
62
+ ```
63
+
64
+ `research` runs keyword searches one by one, applies the same filters, scores
65
+ offers, deduplicates by `offerId`, and optionally enriches only the top N
66
+ results by calling `offer`.
67
+
68
+ Supported export modes:
69
+
70
+ - default: human table
71
+ - JSON: normal automatic JSON when stdout is piped or `--json` is used
72
+ - `--jsonl`: one research item per line
73
+ - `--csv`: comma-separated table
74
+ - optional `--output <file>`: write export to a file
75
+
76
+ ### `compare`
77
+
78
+ Add a read-only offer comparison command:
79
+
80
+ ```bash
81
+ 1688 compare <offerId...>
82
+ ```
83
+
84
+ It fetches each offer detail, computes comparable fields and a sourcing score,
85
+ and shows price, MOQ, sale count, SKU count, stock, supplier, freight/package
86
+ hints, and detail fetch errors.
87
+
88
+ ### `supplier inspect`
89
+
90
+ Supplier-level inspection now lives in
91
+ [`supplier-inspect.md`](supplier-inspect.md). V1 supports offerId, offer URL,
92
+ `b2b-*` memberId, and factory-card URL. Direct loginId lookup remains out of
93
+ scope because live probing showed it can resolve to the wrong factory.
94
+
95
+ ### `supplier search` / `supplier research`
96
+
97
+ Supplier discovery from 1688's company search is specified separately in
98
+ [`supplier-search.md`](supplier-search.md). These commands must use company
99
+ search payloads and must not build supplier lists by aggregating offer-search
100
+ results.
101
+
102
+ ## Data Model
103
+
104
+ ### Search Item
105
+
106
+ Each `search` offer may include the existing fields plus additive research
107
+ signals:
108
+
109
+ ```ts
110
+ {
111
+ offerId: string,
112
+ title: string,
113
+ price: { text: string, min: number | null, max: number | null },
114
+ supplier: { name: string | null, shopUrl: string | null, years: number | null },
115
+ verified: { factory: boolean, business: boolean, superFactory: boolean },
116
+ tags: string[],
117
+ isP4P: boolean,
118
+ turnover: string | null,
119
+ demand?: {
120
+ orderCountText: string | null,
121
+ orderCount: number | null,
122
+ repurchaseRateText: string | null,
123
+ repurchaseRate: number | null,
124
+ },
125
+ serviceTags?: string[],
126
+ productBadges?: string[],
127
+ }
128
+ ```
129
+
130
+ ### Research Item
131
+
132
+ ```ts
133
+ {
134
+ sourceKeyword: string,
135
+ sourceRank: number,
136
+ globalRank: number,
137
+ offer: Offer,
138
+ demand: {
139
+ turnoverText: string | null,
140
+ orderCount: number | null,
141
+ repurchaseRate: number | null,
142
+ },
143
+ supplier: {
144
+ years: number | null,
145
+ verified: Offer["verified"],
146
+ tags: string[],
147
+ isAd: boolean,
148
+ },
149
+ score: number,
150
+ scoreBreakdown: Array<{ name: string, points: number, reason: string }>,
151
+ enriched?: OfferDetailSummary,
152
+ error?: { code: string, message: string },
153
+ }
154
+ ```
155
+
156
+ ## Sourcing Score V1
157
+
158
+ The score is explainable and bounded to 100.
159
+
160
+ - Price: up to 25 points for a valid low price.
161
+ - Demand: up to 25 points from turnover/order count.
162
+ - Supplier tenure: up to 15 points from shop years.
163
+ - Verification: up to 15 points for super factory, factory, or business
164
+ verification.
165
+ - Service tags: up to 10 points from tags/service badges.
166
+ - Organic result: up to 10 points when the offer is not P4P/ad.
167
+
168
+ The score is a ranking aid, not a truth claim.
169
+
170
+ ## Failure Semantics
171
+
172
+ For `research` and `compare`, distinguish:
173
+
174
+ - run-level failure: login expired, risk control, browser/network failure that
175
+ prevents the command from continuing.
176
+ - item-level failure: one offer detail fails during enrichment or comparison.
177
+
178
+ Item-level failures stay attached to the item and should not fail the whole
179
+ run unless every item fails.
180
+
181
+ ## Verification
182
+
183
+ - Unit tests cover sorting, filters, score calculation, export formatting, and
184
+ enrichment option parsing.
185
+ - `pnpm agent-context` refreshes generated command and JSON-shape indexes.
186
+ - `pnpm agent-verify` is the default gate.
@@ -0,0 +1,144 @@
1
+ # Supplier Inspect
2
+
3
+ This spec defines the first reliable supplier-level inspection command for
4
+ `1688-cli`. It is read-only and aimed at sourcing decisions after a buyer or
5
+ agent has found an offer or supplier `memberId`.
6
+
7
+ ## Goal
8
+
9
+ Help an agent or buyer answer:
10
+
11
+ - Who is the supplier behind this offer?
12
+ - Does the supplier expose factory/trust/service signals?
13
+ - What factory card data is available: location, years, authentication,
14
+ production scope, staff/scale hints, and available offer count?
15
+ - Which fields are observed from 1688 payloads versus unavailable?
16
+
17
+ ## Non-Goals
18
+
19
+ - Do not bypass login, risk control, or slider verification.
20
+ - Do not bulk scrape supplier catalogs.
21
+ - Do not claim loginId lookup is reliable when the current site cannot resolve
22
+ it deterministically.
23
+ - Do not perform write actions such as inquiry, favorite, cart, or checkout.
24
+ - Do not invent scores that are not backed by observed payload fields.
25
+
26
+ ## Probe Findings
27
+
28
+ Live headed probe on 2026-05-31 found these useful sources:
29
+
30
+ - Offer detail page:
31
+ - `window.context.result.global.globalData.model.sellerModel`
32
+ - `mtop.1688.moga.pc.shopcard`
33
+ - Factory card page:
34
+ - `https://sale.1688.com/factory/card.html?memberId=<memberId>`
35
+ - `mtop.com.alibaba.china.factory.card.common.fn.mtop.tpp.faas`
36
+ - Factory card DOM text can expose a visible available-offer count such as
37
+ `共34个商品`.
38
+
39
+ Direct `loginId` factory-card lookup is not reliable. A probe with
40
+ `loginId=<sellerLoginId>` returned a different factory, so V1 must reject
41
+ loginId-only input with a clear error instead of returning possibly wrong data.
42
+
43
+ ## Command
44
+
45
+ ```bash
46
+ 1688 supplier inspect <offerId|memberId|offerUrl|factoryCardUrl>
47
+ ```
48
+
49
+ Supported target forms:
50
+
51
+ - numeric `offerId`
52
+ - `https://detail.1688.com/offer/<offerId>.html`
53
+ - `b2b-*` supplier `memberId`
54
+ - factory-card URL with a `memberId` query parameter
55
+
56
+ Unsupported in V1:
57
+
58
+ - loginId-only input, because live probe showed it can misresolve
59
+
60
+ Options:
61
+
62
+ ```bash
63
+ --profile <name>
64
+ --headed
65
+ ```
66
+
67
+ ## JSON Contract
68
+
69
+ ```ts
70
+ {
71
+ target: {
72
+ input: string,
73
+ type: "offerId" | "memberId",
74
+ offerId: string | null,
75
+ memberId: string | null,
76
+ },
77
+ supplier: {
78
+ name: string | null,
79
+ loginId: string | null,
80
+ memberId: string | null,
81
+ userId: string | null,
82
+ companyId: string | null,
83
+ shopUrl: string | null,
84
+ shopUrls: Record<string, string>,
85
+ identity: string | null,
86
+ signs: Record<string, boolean>,
87
+ },
88
+ factory: {
89
+ isFactory: boolean,
90
+ superFactory: boolean,
91
+ tpYears: number | null,
92
+ medalLevel: string | null,
93
+ thirdPartyAuthProvider: string | null,
94
+ establishedAtText: string | null,
95
+ location: string | null,
96
+ address: string | null,
97
+ coordinates: { latitude: number | null, longitude: number | null },
98
+ productionService: string | null,
99
+ employeeScale: string | null,
100
+ workerCount: string | null,
101
+ profile: string | null,
102
+ tags: string[],
103
+ },
104
+ trust: {
105
+ companyLabel: string | null,
106
+ retentionRate: number | null,
107
+ companyIcons: Array<{ title: string; link: string | null }>,
108
+ shopTags: string[],
109
+ serviceScores: Array<{ key: string; label: string; score: number | null }>,
110
+ },
111
+ offers: {
112
+ availableCount: number | null,
113
+ source: "factory-card-dom" | null,
114
+ },
115
+ sources: {
116
+ offerUrl: string | null,
117
+ factoryCardUrl: string | null,
118
+ shopcardCaptured: boolean,
119
+ factoryCardCaptured: boolean,
120
+ },
121
+ warnings: string[],
122
+ }
123
+ ```
124
+
125
+ All fields are additive and nullable. Missing values mean the current page or
126
+ payload did not expose the signal.
127
+
128
+ ## Failure Semantics
129
+
130
+ - `BAD_INPUT`: target is empty, malformed, or loginId-only.
131
+ - `NOT_LOGGED_IN`: session expired.
132
+ - `RISK_CONTROL`: 1688 risk challenge appeared; retry with `--headed`.
133
+ - `NETWORK_ERROR`: navigation failed.
134
+ - `SUPPLIER_NOT_FOUND`: no supplier identity could be read from a supported
135
+ target.
136
+
137
+ ## Verification
138
+
139
+ - Unit tests cover target normalization and payload assembly helpers.
140
+ - A live smoke test should inspect a known offerId and confirm:
141
+ - supplier identity is present
142
+ - memberId is present
143
+ - factory-card capture succeeds when memberId exists
144
+ - `loginId` direct input fails with `BAD_INPUT`