agent-miniprogram 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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +128 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +386 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/close.d.ts +3 -0
  7. package/dist/commands/close.js +6 -0
  8. package/dist/commands/close.js.map +1 -0
  9. package/dist/commands/connect.d.ts +4 -0
  10. package/dist/commands/connect.js +8 -0
  11. package/dist/commands/connect.js.map +1 -0
  12. package/dist/commands/data.d.ts +3 -0
  13. package/dist/commands/data.js +6 -0
  14. package/dist/commands/data.js.map +1 -0
  15. package/dist/commands/eval.d.ts +3 -0
  16. package/dist/commands/eval.js +6 -0
  17. package/dist/commands/eval.js.map +1 -0
  18. package/dist/commands/input.d.ts +3 -0
  19. package/dist/commands/input.js +6 -0
  20. package/dist/commands/input.js.map +1 -0
  21. package/dist/commands/launch.d.ts +4 -0
  22. package/dist/commands/launch.js +7 -0
  23. package/dist/commands/launch.js.map +1 -0
  24. package/dist/commands/mock.d.ts +3 -0
  25. package/dist/commands/mock.js +13 -0
  26. package/dist/commands/mock.js.map +1 -0
  27. package/dist/commands/navigate.d.ts +7 -0
  28. package/dist/commands/navigate.js +10 -0
  29. package/dist/commands/navigate.js.map +1 -0
  30. package/dist/commands/screenshot.d.ts +4 -0
  31. package/dist/commands/screenshot.js +6 -0
  32. package/dist/commands/screenshot.js.map +1 -0
  33. package/dist/commands/scroll.d.ts +5 -0
  34. package/dist/commands/scroll.js +6 -0
  35. package/dist/commands/scroll.js.map +1 -0
  36. package/dist/commands/snapshot.d.ts +4 -0
  37. package/dist/commands/snapshot.js +6 -0
  38. package/dist/commands/snapshot.js.map +1 -0
  39. package/dist/commands/tap.d.ts +3 -0
  40. package/dist/commands/tap.js +6 -0
  41. package/dist/commands/tap.js.map +1 -0
  42. package/dist/commands/wait.d.ts +5 -0
  43. package/dist/commands/wait.js +20 -0
  44. package/dist/commands/wait.js.map +1 -0
  45. package/dist/daemon/client.d.ts +6 -0
  46. package/dist/daemon/client.js +55 -0
  47. package/dist/daemon/client.js.map +1 -0
  48. package/dist/daemon/server.d.ts +1 -0
  49. package/dist/daemon/server.js +369 -0
  50. package/dist/daemon/server.js.map +1 -0
  51. package/dist/daemon/session.d.ts +14 -0
  52. package/dist/daemon/session.js +65 -0
  53. package/dist/daemon/session.js.map +1 -0
  54. package/dist/replay/player.d.ts +3 -0
  55. package/dist/replay/player.js +41 -0
  56. package/dist/replay/player.js.map +1 -0
  57. package/dist/replay/recorder.d.ts +15 -0
  58. package/dist/replay/recorder.js +39 -0
  59. package/dist/replay/recorder.js.map +1 -0
  60. package/dist/snapshot/builder.d.ts +16 -0
  61. package/dist/snapshot/builder.js +371 -0
  62. package/dist/snapshot/builder.js.map +1 -0
  63. package/dist/snapshot/refs.d.ts +17 -0
  64. package/dist/snapshot/refs.js +68 -0
  65. package/dist/snapshot/refs.js.map +1 -0
  66. package/package.json +44 -0
  67. package/skills/agent-miniprogram/SKILL.md +163 -0
@@ -0,0 +1,68 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ const STATE_DIR = path.join(os.homedir(), '.agent-miniprogram');
5
+ const REFS_FILE = path.join(STATE_DIR, 'refs.json');
6
+ let registry = new Map();
7
+ let counter = 0;
8
+ function ensureStateDir() {
9
+ if (!fs.existsSync(STATE_DIR)) {
10
+ fs.mkdirSync(STATE_DIR, { recursive: true });
11
+ }
12
+ }
13
+ export function loadRefs() {
14
+ if (!fs.existsSync(REFS_FILE))
15
+ return;
16
+ try {
17
+ const data = JSON.parse(fs.readFileSync(REFS_FILE, 'utf-8'));
18
+ registry = new Map(Object.entries(data.registry || {}));
19
+ counter = data.counter || 0;
20
+ }
21
+ catch {
22
+ registry = new Map();
23
+ counter = 0;
24
+ }
25
+ }
26
+ export function saveRefs() {
27
+ ensureStateDir();
28
+ const obj = {};
29
+ for (const [k, v] of registry)
30
+ obj[k] = v;
31
+ fs.writeFileSync(REFS_FILE, JSON.stringify({ registry: obj, counter }, null, 2));
32
+ }
33
+ export function clearRefs() {
34
+ registry.clear();
35
+ counter = 0;
36
+ saveRefs();
37
+ }
38
+ export function registerRef(selector, tag, text) {
39
+ // Count how many times this selector has already been registered (for $$()[N] resolution)
40
+ let matchIndex = 0;
41
+ for (const [, entry] of registry) {
42
+ if (entry.selector === selector)
43
+ matchIndex++;
44
+ }
45
+ counter++;
46
+ const ref = `@e${counter}`;
47
+ registry.set(ref, { selector, tag, text, matchIndex });
48
+ return ref;
49
+ }
50
+ export function resolveRef(ref) {
51
+ if (!ref?.startsWith('@'))
52
+ return undefined;
53
+ loadRefs();
54
+ return registry.get(ref)?.selector;
55
+ }
56
+ export function resolveRefFull(ref) {
57
+ if (!ref?.startsWith('@'))
58
+ return undefined;
59
+ loadRefs();
60
+ const entry = registry.get(ref);
61
+ if (!entry)
62
+ return undefined;
63
+ return { selector: entry.selector, matchIndex: entry.matchIndex ?? 0 };
64
+ }
65
+ export function getRefInfo(ref) {
66
+ return registry.get(ref);
67
+ }
68
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/snapshot/refs.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "agent-miniprogram",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool for AI-driven WeChat miniprogram automation testing",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "agent-mp": "./dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "skills"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18.0.0"
16
+ },
17
+ "keywords": [
18
+ "wechat",
19
+ "miniprogram",
20
+ "automation",
21
+ "testing",
22
+ "cli",
23
+ "ai",
24
+ "agent"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "start": "tsx src/cli.ts",
29
+ "cli": "tsx src/cli.ts",
30
+ "daemon": "tsx src/daemon/server.ts",
31
+ "test": "vitest run",
32
+ "prepublishOnly": "npm run build && npm test"
33
+ },
34
+ "dependencies": {
35
+ "commander": "^12.0.0",
36
+ "miniprogram-automator": "^0.12.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.0.0",
40
+ "tsx": "^4.7.0",
41
+ "typescript": "^5.4.0",
42
+ "vitest": "^1.4.0"
43
+ }
44
+ }
@@ -0,0 +1,163 @@
1
+ # Agent Miniprogram — Claude Code Skill
2
+
3
+ ## Trigger Conditions
4
+
5
+ Use this skill when asked to:
6
+ - Test, explore, or debug a WeChat miniprogram
7
+ - Automate interactions in the WeChat Developer Tools simulator
8
+ - Verify miniprogram UI behavior or page data
9
+ - Run regression tests on a miniprogram
10
+
11
+ ## Setup
12
+
13
+ The tool requires:
14
+ 1. WeChat Developer Tools installed, with "Security Settings → Enable HTTP Calls" turned on
15
+ 2. The daemon running: `agent-mp daemon`
16
+ - Or if running from source: `npm run daemon`
17
+
18
+ All commands communicate with the daemon via HTTP at `localhost:9430`.
19
+
20
+ ## CLI Reference
21
+
22
+ ```bash
23
+ # Session
24
+ agent-mp launch <project-path> # Launch DevTools + connect
25
+ agent-mp connect [--ws <endpoint>] # Connect to already-running DevTools
26
+ agent-mp status # Show connection status
27
+ agent-mp close # Close connection
28
+
29
+ # Inspection
30
+ agent-mp snapshot # WXML tree with @eN refs (~200-400 tokens)
31
+ agent-mp snapshot --data # Also shows page.data
32
+ agent-mp screenshot [--path <f>] # Save screenshot
33
+ agent-mp data [<dot.path>] # Read page.data
34
+ agent-mp diff snapshot # Diff vs last snapshot
35
+
36
+ # Navigation
37
+ agent-mp navigate <url> # Navigate to page
38
+ agent-mp navigate <url> --type reLaunch|navigateTo|switchTab
39
+ agent-mp back # Navigate back
40
+
41
+ # Interaction (use @eN refs from snapshot)
42
+ agent-mp tap <@ref|selector>
43
+ agent-mp input <@ref|selector> <text>
44
+ agent-mp scroll <@ref|selector> --x <n> --y <n>
45
+ agent-mp long-press <@ref|selector>
46
+ agent-mp swipe <@ref|selector> <up|down|left|right>
47
+
48
+ # Advanced
49
+ agent-mp wait <@ref|ms> # Wait for element or duration
50
+ agent-mp wait --text "some text" # Wait for text to appear
51
+ agent-mp eval "<js code>" # Run JS in AppService
52
+ agent-mp mock <api> '<json>' # Mock wx.* API
53
+
54
+ # Record / Replay
55
+ agent-mp record start
56
+ agent-mp record stop [--output <file.amp>]
57
+ agent-mp replay <file.amp>
58
+ ```
59
+
60
+ All commands support `--json` for structured output.
61
+
62
+ ## Workflow 1: Exploratory Testing
63
+
64
+ ```bash
65
+ # 1. Start session
66
+ agent-mp launch /path/to/miniprogram
67
+
68
+ # 2. Observe current state
69
+ agent-mp snapshot
70
+
71
+ # 3. Interact using refs from snapshot
72
+ agent-mp tap @e5 # tap the login button (ref from snapshot)
73
+ agent-mp snapshot # re-snapshot after action
74
+
75
+ # 4. Fill in forms
76
+ agent-mp input @e3 "13800138000" # phone input
77
+ agent-mp input @e4 "password123" # password input
78
+ agent-mp tap @e7 # tap submit button
79
+
80
+ # 5. Verify result
81
+ agent-mp snapshot --data
82
+
83
+ # 6. Close
84
+ agent-mp close
85
+ ```
86
+
87
+ ## Workflow 2: Debug Workflow
88
+
89
+ ```bash
90
+ agent-mp launch /path/to/miniprogram
91
+ agent-mp navigate /pages/product/detail?id=123
92
+
93
+ # Check page data
94
+ agent-mp data
95
+
96
+ # Execute JS in page context
97
+ agent-mp eval "getCurrentPages()[0].data"
98
+
99
+ # Take screenshot for visual inspection
100
+ agent-mp screenshot --path /tmp/debug.png
101
+
102
+ # Mock an API to test edge case
103
+ agent-mp mock request '{"statusCode":200,"data":{"items":[]}}'
104
+ agent-mp navigate /pages/list/index --type reLaunch
105
+ agent-mp snapshot
106
+ ```
107
+
108
+ ## Workflow 3: Regression Testing (Record & Replay)
109
+
110
+ ```bash
111
+ # Record a user flow
112
+ agent-mp launch /path/to/miniprogram
113
+ agent-mp record start
114
+ agent-mp navigate /pages/index/index
115
+ agent-mp tap @e3
116
+ agent-mp input @e5 "test@example.com"
117
+ agent-mp tap @e7
118
+ agent-mp record stop --output tests/login-flow.amp
119
+
120
+ # Later: replay to verify
121
+ agent-mp launch /path/to/miniprogram
122
+ agent-mp replay tests/login-flow.amp
123
+ agent-mp snapshot --data
124
+ ```
125
+
126
+ ## Snapshot Format
127
+
128
+ The `snapshot` command outputs a compact WXML tree:
129
+
130
+ ```
131
+ Page: /pages/index/index
132
+
133
+ [view @e1]
134
+ [image @e2] src="/img/logo.png"
135
+ [text @e3] "欢迎登录"
136
+ [form @e4]
137
+ [input @e5] placeholder="手机号" (bindinput=onPhoneInput)
138
+ [input @e6] type="password" placeholder="密码" (bindinput=onPasswordInput)
139
+ [button @e7] "登录" (bindtap=onLogin)
140
+ [navigator @e8] → /pages/register/index "注册账号"
141
+ ```
142
+
143
+ Key rules:
144
+ - `@eN` refs are stable within a session — use them instead of selectors
145
+ - **After every navigation, run `snapshot` again** — refs reset on each snapshot call
146
+ - Elements with `(bindtap)` are tappable
147
+ - Elements with `(bindinput)` accept text input
148
+
149
+ ## Best Practices
150
+
151
+ 1. **Always snapshot after navigation** — page content changes, refs reset
152
+ 2. **Prefer refs over selectors** — `@e5` is cleaner than `.form > input:nth-child(2)`
153
+ 3. **Use `--data` to debug state** — `agent-mp snapshot --data` shows both UI and data
154
+ 4. **Use `diff snapshot` for assertions** — run before and after an action to see what changed
155
+ 5. **Use `eval` for complex assertions** — `agent-mp eval "getCurrentPages()[0].data.loginStatus"`
156
+ 6. **Mock network calls for deterministic tests** — `agent-mp mock request '...'`
157
+ 7. **Add `wait` after async operations** — e.g., `agent-mp wait 500` after a form submit
158
+
159
+ ## Error Handling
160
+
161
+ - `Daemon not running` → run `agent-mp daemon` first
162
+ - `Not connected` → run `agent-mp launch <path>` or `agent-mp connect`
163
+ - `Element not found: @e5` → snapshot is stale, run `agent-mp snapshot` again