jdbuyskill 0.1.0
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 +183 -0
- package/SKILL.md +97 -0
- package/agents/openai.yaml +4 -0
- package/bin/jdbuyskill.mjs +103 -0
- package/package.json +30 -0
- package/references/examples.md +59 -0
- package/references/harness-protocol.md +155 -0
- package/references/task-schema.md +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# jdbuyskill
|
|
2
|
+
|
|
3
|
+
A Codex skill for running JD.com product monitoring and checkout tasks through a visible browser harness.
|
|
4
|
+
|
|
5
|
+
This skill is designed for agent-operated browser sessions: Codex performs scheduled checks and page actions step by step, while the user manually handles login, CAPTCHA, SMS verification, risk-control prompts, address blockers, and payment.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
- Parses JD product monitoring or checkout requests into a structured task object.
|
|
10
|
+
- Runs stock checks in a visible browser or local Chrome CDP session.
|
|
11
|
+
- Supports aligned polling intervals such as every 5 or 10 minutes.
|
|
12
|
+
- Supports three purchase strategies:
|
|
13
|
+
- `notify_only`: notify when the product appears available.
|
|
14
|
+
- `dry_run`: enter checkout and stop before final submit.
|
|
15
|
+
- `submit_order`: click final submit once, then stop before payment.
|
|
16
|
+
- Uses a strict state-machine protocol for browser actions and status reporting.
|
|
17
|
+
|
|
18
|
+
## Safety Boundaries
|
|
19
|
+
|
|
20
|
+
This skill does not support:
|
|
21
|
+
|
|
22
|
+
- CAPTCHA solving
|
|
23
|
+
- login, SMS, or risk-control bypass
|
|
24
|
+
- bot evasion or stealth browser patches
|
|
25
|
+
- request-header spoofing
|
|
26
|
+
- JD internal API automation
|
|
27
|
+
- unattended background purchasing
|
|
28
|
+
- automatic payment
|
|
29
|
+
|
|
30
|
+
Protected steps must be handled manually by the user in the visible browser.
|
|
31
|
+
|
|
32
|
+
## Install From npm
|
|
33
|
+
|
|
34
|
+
Install globally:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g jdbuyskill
|
|
38
|
+
jdbuyskill install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or run without a global install:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx jdbuyskill install
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then restart Codex so it can discover the skill.
|
|
48
|
+
|
|
49
|
+
By default, the installer copies the skill to:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
$CODEX_HOME/skills/jdbuyskill
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If `CODEX_HOME` is unset, it installs to:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
~/.codex/skills/jdbuyskill
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Use a custom skills directory:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
jdbuyskill install --dest /path/to/skills
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Replace an existing installed copy:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
jdbuyskill install --force
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Install From GitHub
|
|
74
|
+
|
|
75
|
+
Clone the repository and symlink it into your Codex skills directory:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/<owner>/<repo>.git
|
|
79
|
+
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
|
|
80
|
+
ln -sfn "$(pwd)/<repo>" "${CODEX_HOME:-$HOME/.codex}/skills/jdbuyskill"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or copy it:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
|
|
87
|
+
cp -R /path/to/jdbuyskill "${CODEX_HOME:-$HOME/.codex}/skills/jdbuyskill"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Restart Codex after installing.
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
Invoke the skill in Codex:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
Use $jdbuyskill to monitor https://item.jd.com/100012043978.html every 10 minutes and notify me when it is available.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Dry-run checkout:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
Use $jdbuyskill to check this JD item with quantity 2 and go to checkout, but do not submit the order.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Submit once, then stop before payment:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
Use $jdbuyskill to submit the order once if this JD item is available. I will pay manually.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Local Chrome CDP Mode
|
|
113
|
+
|
|
114
|
+
For CDP mode, start Chrome with:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
|
118
|
+
--remote-debugging-port=9222 \
|
|
119
|
+
--user-data-dir=/tmp/jdbuy-chrome-profile
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If that path does not exist on your machine, start Chrome with equivalent `--remote-debugging-port=9222` and `--user-data-dir` flags.
|
|
123
|
+
|
|
124
|
+
## Project Structure
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
jdbuyskill/
|
|
128
|
+
SKILL.md
|
|
129
|
+
agents/
|
|
130
|
+
openai.yaml
|
|
131
|
+
references/
|
|
132
|
+
task-schema.md
|
|
133
|
+
harness-protocol.md
|
|
134
|
+
examples.md
|
|
135
|
+
bin/
|
|
136
|
+
jdbuyskill.mjs
|
|
137
|
+
package.json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Publish to npm
|
|
141
|
+
|
|
142
|
+
Before publishing, update `package.json` if needed:
|
|
143
|
+
|
|
144
|
+
- Change `name` if `jdbuyskill` is already taken.
|
|
145
|
+
- Change `version` for each release.
|
|
146
|
+
- Set an appropriate license if you want others to reuse the package.
|
|
147
|
+
|
|
148
|
+
Publish:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npm login
|
|
152
|
+
npm whoami
|
|
153
|
+
npm publish --access public
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Preview published files:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm pack --dry-run
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
If your local npm cache has permission issues, use a temporary cache:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm --cache /tmp/npm-cache-jdbuyskill pack --dry-run
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Publish to GitHub
|
|
169
|
+
|
|
170
|
+
Initialize and push:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
git init
|
|
174
|
+
git add .
|
|
175
|
+
git commit -m "Add jdbuyskill"
|
|
176
|
+
git branch -M main
|
|
177
|
+
git remote add origin https://github.com/<owner>/<repo>.git
|
|
178
|
+
git push -u origin main
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
The npm package currently uses `UNLICENSED` in `package.json`. Add a `LICENSE` file and update `package.json` before publishing if you want to distribute it under an open-source license such as MIT.
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jdbuyskill
|
|
3
|
+
description: Use when a user asks Codex to run a JD.com product monitoring, availability check, cart, or checkout task in a visible browser with a product URL, quantity, purchase strategy, local CDP browser, or aligned polling interval. Do not use for CAPTCHA solving, risk-control bypass, bot evasion, stealth automation, internal API automation, or payment verification.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# JD Buy Harness Runbook
|
|
7
|
+
|
|
8
|
+
Operate JD.com purchase tasks as a visible-browser harness. Codex performs each check and browser action itself under the protocol; do not generate a long-running automation program, cron job, daemon, or request-level bot.
|
|
9
|
+
|
|
10
|
+
## Required References
|
|
11
|
+
|
|
12
|
+
Read these before acting:
|
|
13
|
+
|
|
14
|
+
1. `references/task-schema.md` for task parsing and validation.
|
|
15
|
+
2. `references/harness-protocol.md` for allowed states, transitions, page signals, and evidence rules.
|
|
16
|
+
3. `references/examples.md` when the user request is ambiguous or you need parsing examples.
|
|
17
|
+
|
|
18
|
+
## Operating Rules
|
|
19
|
+
|
|
20
|
+
- Keep exactly one current protocol state from `references/harness-protocol.md`.
|
|
21
|
+
- Report every state transition with the format in `Status Format`.
|
|
22
|
+
- Run the first stock check immediately; only repeat checks at aligned wall-clock boundaries.
|
|
23
|
+
- Default to `dry_run` unless the user explicitly requests `submit_order`.
|
|
24
|
+
- Pause for manual login, CAPTCHA, SMS, risk-control, address blockers, and payment prompts.
|
|
25
|
+
- Stop before payment. For `submit_order`, click final submit at most once, then stop.
|
|
26
|
+
- Do not continue from an unexpected page by guessing. Capture evidence and ask the user.
|
|
27
|
+
|
|
28
|
+
## Refuse Or Narrow
|
|
29
|
+
|
|
30
|
+
Refuse only the unsafe part when possible. Offer a compliant alternative such as `notify_only`, `dry_run`, screenshots, HTML snapshots, slower aligned checks, or pausing for manual intervention.
|
|
31
|
+
|
|
32
|
+
Reject requests to:
|
|
33
|
+
|
|
34
|
+
- bypass CAPTCHA, login, SMS, risk control, bot detection, or payment confirmation
|
|
35
|
+
- spoof headers, patch browser stealth signals, or use internal JD APIs
|
|
36
|
+
- run unattended background purchasing or automatic payment
|
|
37
|
+
- disable manual intervention for protected steps
|
|
38
|
+
|
|
39
|
+
## Task Setup
|
|
40
|
+
|
|
41
|
+
Build an in-memory task object before opening the browser:
|
|
42
|
+
|
|
43
|
+
- `product_url`: JD product detail URL.
|
|
44
|
+
- `quantity`: purchase quantity, default `1`.
|
|
45
|
+
- `purchase_strategy`: `notify_only`, `dry_run`, or `submit_order`; default `dry_run`.
|
|
46
|
+
- `poll_aligned_minutes`: default `5`.
|
|
47
|
+
- `max_attempts`: default `0`, meaning no fixed cap while the session remains active.
|
|
48
|
+
- `browser.mode`: `cdp` or `visible`; prefer `cdp` only when a local endpoint is available.
|
|
49
|
+
|
|
50
|
+
If any required or safety-relevant field is ambiguous, show the interpreted task object and ask for confirmation before continuing.
|
|
51
|
+
|
|
52
|
+
For CDP mode, ask the user to start Chrome when no endpoint is available:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
|
56
|
+
--remote-debugging-port=9222 \
|
|
57
|
+
--user-data-dir=/tmp/jdbuy-chrome-profile
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Connect to `http://127.0.0.1:9222` with the available browser-control tool. If connection fails, stop and ask the user to restart Chrome with the command above.
|
|
61
|
+
|
|
62
|
+
## Execution Loop
|
|
63
|
+
|
|
64
|
+
Run exactly this high-level loop:
|
|
65
|
+
|
|
66
|
+
1. Open the product URL.
|
|
67
|
+
2. Run one immediate stock check.··
|
|
68
|
+
3. If unavailable, wait until the next aligned wall-clock boundary.
|
|
69
|
+
4. Repeat checks only on aligned boundaries.
|
|
70
|
+
5. If available, apply `purchase_strategy`.
|
|
71
|
+
6. If manual login, CAPTCHA, SMS, or risk prompt appears, pause and ask the user to handle it.
|
|
72
|
+
7. If `dry_run`, stop before final order submission.
|
|
73
|
+
8. If `submit_order`, click submit order once, then stop for manual payment.
|
|
74
|
+
|
|
75
|
+
## Status Format
|
|
76
|
+
|
|
77
|
+
At every state transition, report one short block:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
state: <STATE>
|
|
81
|
+
page: <current URL or page label>
|
|
82
|
+
signal: <visible button/text/challenge/checkout marker>
|
|
83
|
+
next: <next action or next scheduled check time>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Stop Conditions
|
|
87
|
+
|
|
88
|
+
Stop immediately when:
|
|
89
|
+
|
|
90
|
+
- the protocol reaches `STOPPED`
|
|
91
|
+
- the page requires phone-only purchase
|
|
92
|
+
- browser control or CDP connection is unavailable
|
|
93
|
+
- the user must handle login, CAPTCHA, SMS, risk control, address selection, or payment
|
|
94
|
+
- the task violates the safety boundary
|
|
95
|
+
- evidence is insufficient to classify the page state
|
|
96
|
+
|
|
97
|
+
When stopped, summarize the last state, last observed signal, and what user action is needed next.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const packageRoot = resolve(__dirname, "..");
|
|
10
|
+
const skillName = "jdbuyskill";
|
|
11
|
+
|
|
12
|
+
function usage() {
|
|
13
|
+
console.log(`Usage:
|
|
14
|
+
jdbuyskill install [--dest <skills-dir>] [--force]
|
|
15
|
+
jdbuyskill --help
|
|
16
|
+
|
|
17
|
+
Installs ${skillName} into:
|
|
18
|
+
$CODEX_HOME/skills/${skillName}
|
|
19
|
+
or, when CODEX_HOME is unset:
|
|
20
|
+
~/.codex/skills/${skillName}
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--dest <dir> Install into a custom skills directory.
|
|
24
|
+
--force Replace an existing installed copy.
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function defaultSkillsDir() {
|
|
29
|
+
const codexHome = process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
30
|
+
return join(codexHome, "skills");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseArgs(argv) {
|
|
34
|
+
const args = [...argv];
|
|
35
|
+
const command = args[0] && !args[0].startsWith("-") ? args.shift() : "install";
|
|
36
|
+
const options = {
|
|
37
|
+
command,
|
|
38
|
+
dest: defaultSkillsDir(),
|
|
39
|
+
force: false
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
if (arg === "--help" || arg === "-h") {
|
|
45
|
+
options.command = "help";
|
|
46
|
+
} else if (arg === "--force") {
|
|
47
|
+
options.force = true;
|
|
48
|
+
} else if (arg === "--dest") {
|
|
49
|
+
const value = args[i + 1];
|
|
50
|
+
if (!value || value.startsWith("-")) {
|
|
51
|
+
throw new Error("--dest requires a directory path");
|
|
52
|
+
}
|
|
53
|
+
options.dest = resolve(value);
|
|
54
|
+
i += 1;
|
|
55
|
+
} else {
|
|
56
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return options;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function copySkill(destDir, force) {
|
|
64
|
+
const installDir = join(destDir, skillName);
|
|
65
|
+
const entries = ["SKILL.md", "agents", "references"];
|
|
66
|
+
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
const source = join(packageRoot, entry);
|
|
69
|
+
if (!existsSync(source)) {
|
|
70
|
+
throw new Error(`Package is missing required skill file: ${entry}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (existsSync(installDir)) {
|
|
75
|
+
if (!force) {
|
|
76
|
+
throw new Error(`${installDir} already exists. Re-run with --force to replace it.`);
|
|
77
|
+
}
|
|
78
|
+
rmSync(installDir, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
mkdirSync(installDir, { recursive: true });
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
cpSync(join(packageRoot, entry), join(installDir, entry), { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(`Installed ${skillName} to ${installDir}`);
|
|
87
|
+
console.log("Restart Codex to pick up the skill.");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const options = parseArgs(process.argv.slice(2));
|
|
92
|
+
if (options.command === "help") {
|
|
93
|
+
usage();
|
|
94
|
+
} else if (options.command === "install") {
|
|
95
|
+
copySkill(options.dest, options.force);
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`Unknown command: ${options.command}`);
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`jdbuyskill: ${error.message}`);
|
|
101
|
+
console.error("Run `jdbuyskill --help` for usage.");
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jdbuyskill",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Codex skill for visible-browser JD.com product monitoring and checkout harness tasks.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jdbuyskill": "bin/jdbuyskill.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"SKILL.md",
|
|
11
|
+
"agents/",
|
|
12
|
+
"references/",
|
|
13
|
+
"bin/jdbuyskill.mjs"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"install-skill": "node bin/jdbuyskill.mjs install",
|
|
17
|
+
"pack:dry": "npm pack --dry-run"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"codex",
|
|
21
|
+
"skill",
|
|
22
|
+
"jd",
|
|
23
|
+
"browser",
|
|
24
|
+
"harness"
|
|
25
|
+
],
|
|
26
|
+
"license": "UNLICENSED",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# JD Buy Harness Examples
|
|
2
|
+
|
|
3
|
+
Use these examples to parse user requests into task objects. They are examples only; still validate the live request against `task-schema.md`.
|
|
4
|
+
|
|
5
|
+
## Notify Only
|
|
6
|
+
|
|
7
|
+
User: "Monitor this JD item every 10 minutes and tell me when it is available: https://item.jd.com/100012043978.html"
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"product_url": "https://item.jd.com/100012043978.html",
|
|
12
|
+
"quantity": 1,
|
|
13
|
+
"purchase_strategy": "notify_only",
|
|
14
|
+
"poll_aligned_minutes": 10,
|
|
15
|
+
"max_attempts": 0,
|
|
16
|
+
"browser": {
|
|
17
|
+
"mode": "cdp",
|
|
18
|
+
"cdp_endpoint": "http://127.0.0.1:9222"
|
|
19
|
+
},
|
|
20
|
+
"manual_intervention": {
|
|
21
|
+
"login": true,
|
|
22
|
+
"captcha": true,
|
|
23
|
+
"sms": true,
|
|
24
|
+
"risk_control": true,
|
|
25
|
+
"address": true,
|
|
26
|
+
"payment": true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Dry Run Checkout
|
|
32
|
+
|
|
33
|
+
User: "Use visible Chrome to check this item now, quantity 2, and go as far as checkout but don't submit."
|
|
34
|
+
|
|
35
|
+
Set `purchase_strategy` to `dry_run` and `quantity` to `2`. If the URL is missing, ask for it before opening the browser.
|
|
36
|
+
|
|
37
|
+
## Submit Once
|
|
38
|
+
|
|
39
|
+
User: "If this JD item is available, submit the order once. I will pay manually."
|
|
40
|
+
|
|
41
|
+
Set `purchase_strategy` to `submit_order` only if the user provided a valid JD product URL or confirms the parsed URL. Stop immediately after one final submit click.
|
|
42
|
+
|
|
43
|
+
## Ambiguous Automatic Request
|
|
44
|
+
|
|
45
|
+
User: "Automatically buy this when it drops."
|
|
46
|
+
|
|
47
|
+
Ask whether they mean:
|
|
48
|
+
|
|
49
|
+
- `notify_only`: notify on availability
|
|
50
|
+
- `dry_run`: reach checkout and stop before submit
|
|
51
|
+
- `submit_order`: submit once, then stop before payment
|
|
52
|
+
|
|
53
|
+
Do not create unattended background automation.
|
|
54
|
+
|
|
55
|
+
## Unsafe Request
|
|
56
|
+
|
|
57
|
+
User: "Bypass CAPTCHA and use headers so JD thinks this is a normal browser."
|
|
58
|
+
|
|
59
|
+
Refuse the bypass/header-spoofing portion. Offer visible-browser monitoring with manual CAPTCHA handling, slower aligned checks, screenshots, or `notify_only`.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# JD Buy Harness Protocol
|
|
2
|
+
|
|
3
|
+
The agent must operate the task as a strict state machine. At any time, the task is in exactly one state.
|
|
4
|
+
|
|
5
|
+
## States
|
|
6
|
+
|
|
7
|
+
1. `TASK_PARSED`
|
|
8
|
+
2. `BROWSER_READY`
|
|
9
|
+
3. `PRODUCT_OPENED`
|
|
10
|
+
4. `CHECKING_STOCK`
|
|
11
|
+
5. `WAITING_FOR_BOUNDARY`
|
|
12
|
+
6. `MANUAL_INTERVENTION`
|
|
13
|
+
7. `AVAILABLE_FOUND`
|
|
14
|
+
8. `CHECKOUT_STARTED`
|
|
15
|
+
9. `DRY_RUN_STOP`
|
|
16
|
+
10. `ORDER_SUBMITTED`
|
|
17
|
+
11. `STOPPED`
|
|
18
|
+
|
|
19
|
+
## Allowed Transitions
|
|
20
|
+
|
|
21
|
+
- `TASK_PARSED -> BROWSER_READY`
|
|
22
|
+
- `BROWSER_READY -> PRODUCT_OPENED`
|
|
23
|
+
- `PRODUCT_OPENED -> CHECKING_STOCK`
|
|
24
|
+
- `CHECKING_STOCK -> AVAILABLE_FOUND`
|
|
25
|
+
- `CHECKING_STOCK -> WAITING_FOR_BOUNDARY`
|
|
26
|
+
- `CHECKING_STOCK -> MANUAL_INTERVENTION`
|
|
27
|
+
- `WAITING_FOR_BOUNDARY -> PRODUCT_OPENED`
|
|
28
|
+
- `MANUAL_INTERVENTION -> PRODUCT_OPENED`
|
|
29
|
+
- `AVAILABLE_FOUND -> STOPPED` for `notify_only`
|
|
30
|
+
- `AVAILABLE_FOUND -> CHECKOUT_STARTED` for `dry_run` or `submit_order`
|
|
31
|
+
- `CHECKOUT_STARTED -> DRY_RUN_STOP` for `dry_run`
|
|
32
|
+
- `CHECKOUT_STARTED -> ORDER_SUBMITTED` for `submit_order`
|
|
33
|
+
- `DRY_RUN_STOP -> STOPPED`
|
|
34
|
+
- `ORDER_SUBMITTED -> STOPPED`
|
|
35
|
+
|
|
36
|
+
Any other transition is a protocol violation.
|
|
37
|
+
|
|
38
|
+
## State Duties
|
|
39
|
+
|
|
40
|
+
| State | Duties | Exit condition |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `TASK_PARSED` | Validate the task object and safety boundary. | Browser tool or CDP endpoint is ready. |
|
|
43
|
+
| `BROWSER_READY` | Confirm visible browser control works. | Product URL can be opened. |
|
|
44
|
+
| `PRODUCT_OPENED` | Load or reload the product page at an allowed check time. | Primary product area is inspectable. |
|
|
45
|
+
| `CHECKING_STOCK` | Classify availability from visible primary controls. | Available, unavailable, or intervention signal is observed. |
|
|
46
|
+
| `WAITING_FOR_BOUNDARY` | Wait without refreshing or clicking. | Next aligned wall-clock boundary arrives. |
|
|
47
|
+
| `MANUAL_INTERVENTION` | Ask the user to handle a protected prompt. | User confirms the browser is ready to continue. |
|
|
48
|
+
| `AVAILABLE_FOUND` | Report evidence and apply strategy. | Stop for notify-only or enter checkout. |
|
|
49
|
+
| `CHECKOUT_STARTED` | Confirm checkout page marker and strategy stop point. | Stop before submit or submit once. |
|
|
50
|
+
| `DRY_RUN_STOP` | Report that final submit was not clicked. | Stop. |
|
|
51
|
+
| `ORDER_SUBMITTED` | Report that final submit was clicked once. | Stop for manual payment. |
|
|
52
|
+
| `STOPPED` | No further page actions. | None. |
|
|
53
|
+
|
|
54
|
+
## Stock Signals
|
|
55
|
+
|
|
56
|
+
Treat the product as available when the primary product area shows a visible, enabled purchase button:
|
|
57
|
+
|
|
58
|
+
- `立即购买`
|
|
59
|
+
- `加入购物车`
|
|
60
|
+
|
|
61
|
+
Treat the product as unavailable when the primary product area shows:
|
|
62
|
+
|
|
63
|
+
- `无货`
|
|
64
|
+
- `暂无货`
|
|
65
|
+
- `到货通知`
|
|
66
|
+
- `商品已售完`
|
|
67
|
+
- disabled purchase controls
|
|
68
|
+
|
|
69
|
+
If both available and unavailable words appear, prefer the visible enabled primary purchase button over page-wide text. Page-wide text may include unrelated recommendations.
|
|
70
|
+
|
|
71
|
+
If the page says `前往手机购买`, `手机购买`, or `仅支持手机`, stop or ask the user whether to switch to manual phone purchase. Do not claim desktop checkout is possible.
|
|
72
|
+
|
|
73
|
+
Do not treat recommendation cards, ads, search results, or page-wide text outside the primary product area as product availability.
|
|
74
|
+
|
|
75
|
+
## Boundary Timing
|
|
76
|
+
|
|
77
|
+
Run the first check immediately.
|
|
78
|
+
|
|
79
|
+
For subsequent checks, compute the next wall-clock boundary:
|
|
80
|
+
|
|
81
|
+
- `poll_aligned_minutes = 5`: `00/05/10/15/...`
|
|
82
|
+
- `poll_aligned_minutes = 10`: `00/10/20/30/...`
|
|
83
|
+
|
|
84
|
+
When waiting:
|
|
85
|
+
|
|
86
|
+
1. Report the next check time.
|
|
87
|
+
2. Do not refresh or click during the wait.
|
|
88
|
+
3. Resume only at the boundary unless the user interrupts.
|
|
89
|
+
|
|
90
|
+
If `max_attempts > 0`, count each `CHECKING_STOCK` entry as one attempt. Stop after the final unavailable check and summarize the last evidence.
|
|
91
|
+
|
|
92
|
+
## Checkout Rules
|
|
93
|
+
|
|
94
|
+
Before checkout:
|
|
95
|
+
|
|
96
|
+
- Confirm current state is `AVAILABLE_FOUND`.
|
|
97
|
+
- Set quantity if the visible page supports it.
|
|
98
|
+
- Prefer `立即购买` over `加入购物车`.
|
|
99
|
+
|
|
100
|
+
After clicking checkout:
|
|
101
|
+
|
|
102
|
+
- Confirm a checkout marker such as `提交订单`, `收货地址`, or `填写并核对订单信息`.
|
|
103
|
+
- Use JD's current default address. Do not force address selection unless the user explicitly requests it.
|
|
104
|
+
- For `dry_run`, stop before clicking final submit.
|
|
105
|
+
- For `submit_order`, click final submit once, then stop for manual payment.
|
|
106
|
+
|
|
107
|
+
If quantity cannot be set visibly, report the observed quantity control state and ask the user whether to continue with the current quantity.
|
|
108
|
+
|
|
109
|
+
## Manual Intervention
|
|
110
|
+
|
|
111
|
+
Enter `MANUAL_INTERVENTION` when observing:
|
|
112
|
+
|
|
113
|
+
- login prompt
|
|
114
|
+
- CAPTCHA
|
|
115
|
+
- SMS verification
|
|
116
|
+
- security/risk prompt
|
|
117
|
+
- address selection blocker
|
|
118
|
+
- payment prompt
|
|
119
|
+
- unknown checkout blocker
|
|
120
|
+
|
|
121
|
+
Ask the user to handle it in the visible browser, then continue only after the user confirms.
|
|
122
|
+
|
|
123
|
+
## Browser And Page Failures
|
|
124
|
+
|
|
125
|
+
Stop and report evidence when:
|
|
126
|
+
|
|
127
|
+
- browser control disconnects or the CDP endpoint is unavailable
|
|
128
|
+
- the product page fails to load after a normal retry
|
|
129
|
+
- the page is not a JD product page after navigation
|
|
130
|
+
- the visible page language or layout prevents identifying the primary product controls
|
|
131
|
+
- the checkout page lacks a clear checkout marker after a click
|
|
132
|
+
|
|
133
|
+
Do not compensate by using JD internal APIs, direct HTTP requests, header spoofing, or stealth browser patches.
|
|
134
|
+
|
|
135
|
+
## Evidence
|
|
136
|
+
|
|
137
|
+
When a page state is unexpected, capture or request:
|
|
138
|
+
|
|
139
|
+
- screenshot
|
|
140
|
+
- current URL
|
|
141
|
+
- visible text around the relevant control
|
|
142
|
+
- if available, page HTML or accessibility tree snippet
|
|
143
|
+
|
|
144
|
+
Do not continue by guessing.
|
|
145
|
+
|
|
146
|
+
## Status Report Contract
|
|
147
|
+
|
|
148
|
+
Every transition report must include:
|
|
149
|
+
|
|
150
|
+
- state
|
|
151
|
+
- current URL or page label
|
|
152
|
+
- observed signal
|
|
153
|
+
- next action or scheduled check time
|
|
154
|
+
|
|
155
|
+
Keep the report factual. Do not claim purchase success after `ORDER_SUBMITTED`; payment and final merchant confirmation are outside this harness.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# JD Buy Harness Task Schema
|
|
2
|
+
|
|
3
|
+
Use this schema as the in-memory task object for the agent-run harness. It is not a Python application config.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"product_url": "https://item.jd.com/100012043978.html",
|
|
8
|
+
"quantity": 1,
|
|
9
|
+
"purchase_strategy": "dry_run",
|
|
10
|
+
"poll_aligned_minutes": 5,
|
|
11
|
+
"max_attempts": 0,
|
|
12
|
+
"browser": {
|
|
13
|
+
"mode": "cdp",
|
|
14
|
+
"cdp_endpoint": "http://127.0.0.1:9222"
|
|
15
|
+
},
|
|
16
|
+
"manual_intervention": {
|
|
17
|
+
"login": true,
|
|
18
|
+
"captcha": true,
|
|
19
|
+
"sms": true,
|
|
20
|
+
"risk_control": true,
|
|
21
|
+
"address": true,
|
|
22
|
+
"payment": true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Defaults
|
|
28
|
+
|
|
29
|
+
Use these defaults when the user does not specify a value:
|
|
30
|
+
|
|
31
|
+
| Field | Default |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `quantity` | `1` |
|
|
34
|
+
| `purchase_strategy` | `dry_run` |
|
|
35
|
+
| `poll_aligned_minutes` | `5` |
|
|
36
|
+
| `max_attempts` | `0` |
|
|
37
|
+
| `browser.mode` | `cdp` when a local endpoint is available, otherwise `visible` |
|
|
38
|
+
| `browser.cdp_endpoint` | `http://127.0.0.1:9222` |
|
|
39
|
+
| `manual_intervention.*` | `true` |
|
|
40
|
+
|
|
41
|
+
## Field Rules
|
|
42
|
+
|
|
43
|
+
- `product_url`: required `item.jd.com` or `re.jd.com` URL.
|
|
44
|
+
- `quantity`: integer, at least `1`.
|
|
45
|
+
- `purchase_strategy`: one of `notify_only`, `dry_run`, or `submit_order`.
|
|
46
|
+
- `poll_aligned_minutes`: integer that divides 60; commonly `5` or `10`.
|
|
47
|
+
- `max_attempts`: integer at least `0`; `0` means no fixed cap while the agent session remains active.
|
|
48
|
+
- `browser.mode`: `cdp` for a user-started Chrome endpoint, or `visible` for another available visible browser tool.
|
|
49
|
+
- `manual_intervention`: all entries must remain `true`; do not automate login, CAPTCHA, SMS, risk control, address blockers, or payment.
|
|
50
|
+
|
|
51
|
+
## Purchase Strategies
|
|
52
|
+
|
|
53
|
+
| Strategy | Allowed behavior | Stop point |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `notify_only` | Monitor and notify when the product appears available. | Stop at `AVAILABLE_FOUND`. |
|
|
56
|
+
| `dry_run` | Start checkout to verify the path. | Stop before clicking final submit order. |
|
|
57
|
+
| `submit_order` | Click final submit order once. | Stop immediately after submit; payment remains manual. |
|
|
58
|
+
|
|
59
|
+
## Validation Rules
|
|
60
|
+
|
|
61
|
+
Reject the task before browser actions when:
|
|
62
|
+
|
|
63
|
+
- `product_url` is missing or is not a JD product URL.
|
|
64
|
+
- `quantity < 1` or quantity is not an integer.
|
|
65
|
+
- `purchase_strategy` is outside `notify_only`, `dry_run`, or `submit_order`.
|
|
66
|
+
- `poll_aligned_minutes` does not divide 60.
|
|
67
|
+
- `max_attempts < 0`.
|
|
68
|
+
- the user asks to disable manual intervention for login, CAPTCHA, SMS, risk control, address blockers, or payment.
|
|
69
|
+
- the user requests bypass, stealth, header spoofing, internal API automation, unattended background purchase, or automatic payment.
|
|
70
|
+
|
|
71
|
+
## Ambiguity Handling
|
|
72
|
+
|
|
73
|
+
Ask for confirmation before acting when:
|
|
74
|
+
|
|
75
|
+
- the URL is a JD search, campaign, or cart page rather than an item page.
|
|
76
|
+
- the user says "buy" but does not specify whether final submit is allowed.
|
|
77
|
+
- the user asks for "automatic" behavior that could mean either aligned agent checks or unattended code automation.
|
|
78
|
+
- the requested polling interval is expressed informally and cannot be converted to a divisor of 60.
|
|
79
|
+
- the browser mode is requested but the corresponding tool or CDP endpoint is unavailable.
|
|
80
|
+
|
|
81
|
+
When asking, show the parsed task object and state which fields need confirmation.
|