tauri-agent-tools 0.2.1 → 0.3.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.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: tauri-agent-tools
3
3
  description: CLI for inspecting Tauri desktop apps — DOM queries, screenshots, IPC/console monitoring, storage, and page state
4
- version: 0.2.0
5
- tags: [tauri, desktop, debugging, screenshot, dom, inspection]
4
+ version: 0.3.0
5
+ tags: [tauri, desktop, debugging, screenshot, dom, inspection, diff, mutations, snapshot]
6
6
  ---
7
7
 
8
8
  # tauri-agent-tools
@@ -32,10 +32,10 @@ npm install -g tauri-agent-tools
32
32
  Some commands require the Rust dev bridge running inside the Tauri app. Others work standalone.
33
33
 
34
34
  **Bridge required** (needs running Tauri app with bridge):
35
- `screenshot --selector`, `dom`, `eval`, `wait --selector`, `wait --eval`, `ipc-monitor`, `console-monitor`, `storage`, `page-state`
35
+ `screenshot --selector`, `dom`, `eval`, `wait --selector`, `wait --eval`, `ipc-monitor`, `console-monitor`, `storage`, `page-state`, `mutations`, `snapshot`
36
36
 
37
37
  **Standalone** (no bridge needed):
38
- `screenshot --title` (full window only), `wait --title`, `list-windows`, `info`
38
+ `screenshot --title` (full window only), `wait --title`, `list-windows`, `info`, `diff`
39
39
 
40
40
  The bridge auto-discovers via token files in `/tmp/tauri-dev-bridge-*.token`. No manual port/token configuration needed.
41
41
 
@@ -80,12 +80,46 @@ tauri-agent-tools storage --type local --json
80
80
  tauri-agent-tools console-monitor --level error --duration 5000 --json
81
81
  ```
82
82
 
83
+ ### Capture a full debug snapshot
84
+
85
+ ```bash
86
+ # Screenshot + DOM + page state + storage in one call
87
+ tauri-agent-tools snapshot -o /tmp/debug --json
88
+ ```
89
+
90
+ ### Compare screenshots
91
+
92
+ ```bash
93
+ # Pixel-level comparison
94
+ tauri-agent-tools diff /tmp/before.png /tmp/after.png --json
95
+
96
+ # Fail CI if more than 1% of pixels differ
97
+ tauri-agent-tools diff /tmp/expected.png /tmp/actual.png --threshold 1
98
+ ```
99
+
100
+ ### Watch DOM mutations
101
+
102
+ ```bash
103
+ # Observe child additions/removals for 10 seconds
104
+ tauri-agent-tools mutations "#todo-list" --duration 10000 --json
105
+
106
+ # Also track attribute changes
107
+ tauri-agent-tools mutations ".sidebar" --attributes --duration 5000
108
+ ```
109
+
110
+ ### Find elements by text
111
+
112
+ ```bash
113
+ # Search for elements containing text
114
+ tauri-agent-tools dom --text "Settings" --first --json
115
+ ```
116
+
83
117
  ## Command Reference
84
118
 
85
119
  | Command | Key Flags | Bridge? | Description |
86
120
  |---------|-----------|---------|-------------|
87
121
  | `screenshot` | `--selector <css>`, `--title <regex>`, `-o <path>`, `--max-width <n>` | selector: yes, title: no | Capture window or DOM element screenshot |
88
- | `dom` | `[selector]`, `--depth <n>`, `--styles`, `--mode accessibility`, `--json` | yes | Query DOM structure |
122
+ | `dom` | `[selector]`, `--depth <n>`, `--styles`, `--text <pattern>`, `--mode accessibility`, `--json` | yes | Query DOM structure or find elements by text |
89
123
  | `eval` | `<js-expression>` | yes | Evaluate JavaScript in webview |
90
124
  | `wait` | `--selector <css>`, `--eval <js>`, `--title <regex>`, `--timeout <ms>` | selector/eval: yes | Wait for a condition |
91
125
  | `list-windows` | `--tauri`, `--json` | no | List visible windows |
@@ -94,11 +128,14 @@ tauri-agent-tools console-monitor --level error --duration 5000 --json
94
128
  | `console-monitor` | `--level <lvl>`, `--filter <regex>`, `--duration <ms>`, `--json` | yes | Monitor console output |
95
129
  | `storage` | `--type <local\|session\|cookies\|all>`, `--key <name>`, `--json` | yes | Inspect browser storage |
96
130
  | `page-state` | `--json` | yes | URL, title, viewport, scroll, document size |
131
+ | `diff` | `<image1> <image2>`, `-o <path>`, `--threshold <pct>`, `--json` | no | Compare two screenshots with difference metrics |
132
+ | `mutations` | `<selector>`, `--attributes`, `--duration <ms>`, `--json` | yes | Watch DOM mutations on a CSS selector |
133
+ | `snapshot` | `-o <prefix>`, `-s <css>`, `--dom-depth <n>`, `--eval <js>`, `--json` | yes | Capture screenshot + DOM + page state + storage in one shot |
97
134
 
98
135
  ## Important Notes
99
136
 
100
137
  - **All read-only.** No commands modify app state, inject input, or write to storage.
101
138
  - **Use `--json`** for structured, parseable output in automation.
102
- - **Always use `--duration`** with `ipc-monitor` and `console-monitor` — without it, they run indefinitely.
139
+ - **Always use `--duration`** with `ipc-monitor`, `console-monitor`, and `mutations` — without it, they run indefinitely.
103
140
  - **`screenshot --selector`** requires both the bridge AND platform screenshot tools (`imagemagick`).
104
141
  - **One bridge at a time.** Auto-discovery picks the first token file found. If multiple Tauri apps run simultaneously, use `--port` and `--token` explicitly.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: tauri-bridge-setup
3
3
  description: How to add the tauri-agent-tools Rust dev bridge to a Tauri application
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  tags: [tauri, rust, bridge, setup, integration]
6
6
  ---
7
7
 
package/AGENTS.md CHANGED
@@ -8,7 +8,7 @@ This package includes two [Agent Skills](https://agentskills.io):
8
8
 
9
9
  | Skill | Path | Purpose |
10
10
  |-------|------|---------|
11
- | `tauri-agent-tools` | `.agents/skills/tauri-agent-tools/SKILL.md` | Using the 11 CLI commands to inspect Tauri apps |
11
+ | `tauri-agent-tools` | `.agents/skills/tauri-agent-tools/SKILL.md` | Using the 14 CLI commands to inspect Tauri apps |
12
12
  | `tauri-bridge-setup` | `.agents/skills/tauri-bridge-setup/SKILL.md` | Adding the Rust dev bridge to a Tauri project |
13
13
 
14
14
  ## Quick Reference
@@ -21,10 +21,13 @@ This package includes two [Agent Skills](https://agentskills.io):
21
21
  `list-windows`, `info`, `screenshot --title`, `wait --title`
22
22
 
23
23
  **Bridge-required commands** (Tauri app must have dev bridge running):
24
- `dom`, `eval`, `screenshot --selector`, `wait --selector/--eval`, `ipc-monitor`, `console-monitor`, `storage`, `page-state`
24
+ `dom`, `eval`, `screenshot --selector`, `wait --selector/--eval`, `ipc-monitor`, `console-monitor`, `storage`, `page-state`, `mutations`, `snapshot`
25
+
26
+ **Local-only commands** (no bridge needed):
27
+ `diff`
25
28
 
26
29
  **Bridge auto-discovery:** The CLI finds the running bridge via token files in `/tmp/tauri-dev-bridge-*.token`. No manual configuration needed.
27
30
 
28
31
  **Structured output:** Use `--json` on any command for machine-readable output.
29
32
 
30
- **Monitors:** Always pass `--duration <ms>` to `ipc-monitor` and `console-monitor` to avoid indefinite execution.
33
+ **Monitors:** Always pass `--duration <ms>` to `ipc-monitor`, `console-monitor`, and `mutations` to avoid indefinite execution.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Agent-driven inspection toolkit for Tauri desktop apps**
6
6
 
7
- 11 read-only commands to screenshot, inspect, and monitor Tauri apps from the CLI.
7
+ 14 read-only commands to screenshot, inspect, and monitor Tauri apps from the CLI.
8
8
 
9
9
  [![CI](https://github.com/cesarandreslopez/tauri-agent-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/cesarandreslopez/tauri-agent-tools/actions/workflows/ci.yml)
10
10
  [![npm version](https://img.shields.io/npm/v/tauri-agent-tools.svg)](https://www.npmjs.com/package/tauri-agent-tools)
@@ -107,6 +107,7 @@ Query DOM structure from the Tauri app.
107
107
  | `--depth <number>` | Max child depth (default: 3) |
108
108
  | `--tree` | Compact tree view (default) |
109
109
  | `--styles` | Include computed styles |
110
+ | `--text <pattern>` | Find elements containing this text (case-insensitive) |
110
111
  | `--count` | Just output match count |
111
112
  | `--first` | Only return first match |
112
113
  | `--json` | Full structured JSON output |
@@ -189,6 +190,43 @@ Query webview page state: URL, title, viewport, scroll position, document size,
189
190
  |--------|-------------|
190
191
  | `--json` | Output as JSON |
191
192
 
193
+ ### `diff`
194
+
195
+ Compare two screenshots and output difference metrics.
196
+
197
+ | Option | Description |
198
+ |--------|-------------|
199
+ | `<image1>` | First image path |
200
+ | `<image2>` | Second image path |
201
+ | `-o, --output <path>` | Diff image output path |
202
+ | `--threshold <percent>` | Fail (exit code 1) if difference exceeds this percentage |
203
+ | `--json` | Output structured JSON |
204
+
205
+ ### `mutations`
206
+
207
+ Watch DOM mutations on a CSS selector (read-only). Patches a `MutationObserver` into the webview, polls for changes, and cleans up on exit.
208
+
209
+ | Option | Description |
210
+ |--------|-------------|
211
+ | `<selector>` | CSS selector of the element to observe |
212
+ | `--attributes` | Also watch attribute changes |
213
+ | `--interval <ms>` | Poll interval in milliseconds (default: 500) |
214
+ | `--duration <ms>` | Auto-stop after N milliseconds |
215
+ | `--json` | Output one JSON object per line |
216
+
217
+ ### `snapshot`
218
+
219
+ Capture screenshot + DOM tree + page state + storage in one shot. Writes multiple files with a shared prefix.
220
+
221
+ | Option | Description |
222
+ |--------|-------------|
223
+ | `-o, --output <prefix>` | Output path prefix (e.g. `/tmp/debug`) |
224
+ | `-s, --selector <css>` | CSS selector to screenshot (full window if omitted) |
225
+ | `-t, --title <regex>` | Window title to match (default: auto-discover) |
226
+ | `--dom-depth <number>` | DOM tree depth (default: 3) |
227
+ | `--eval <js>` | Additional JS to eval and save |
228
+ | `--json` | Output structured manifest |
229
+
192
230
  ## How It Works
193
231
 
194
232
  ```
@@ -253,7 +291,7 @@ This package ships [Agent Skills](https://agentskills.io) so AI coding agents ca
253
291
 
254
292
  | Skill | Description |
255
293
  |-------|-------------|
256
- | `tauri-agent-tools` | Using all 11 CLI commands to inspect Tauri apps |
294
+ | `tauri-agent-tools` | Using all 14 CLI commands to inspect Tauri apps |
257
295
  | `tauri-bridge-setup` | Adding the Rust dev bridge to a Tauri project |
258
296
 
259
297
  <details>
@@ -307,7 +345,7 @@ Full documentation is available at the [docs site](https://cesarandreslopez.gith
307
345
  - [Installation](https://cesarandreslopez.github.io/tauri-agent-tools/getting-started/installation/) — system requirements and setup
308
346
  - [Quick Start](https://cesarandreslopez.github.io/tauri-agent-tools/getting-started/quick-start/) — get running in 5 minutes
309
347
  - [Bridge Setup](https://cesarandreslopez.github.io/tauri-agent-tools/getting-started/bridge-setup/) — integrate the Rust bridge into your Tauri app
310
- - [Command Reference](https://cesarandreslopez.github.io/tauri-agent-tools/commands/) — all 11 commands with examples
348
+ - [Command Reference](https://cesarandreslopez.github.io/tauri-agent-tools/commands/) — all 14 commands with examples
311
349
  - [Platform Support](https://cesarandreslopez.github.io/tauri-agent-tools/platform-support/) — X11, Wayland, macOS details
312
350
  - [Architecture](https://cesarandreslopez.github.io/tauri-agent-tools/architecture/overview/) — how it works under the hood
313
351
 
package/dist/cli.js CHANGED
@@ -17,6 +17,9 @@ import { registerIpcMonitor } from './commands/ipcMonitor.js';
17
17
  import { registerPageState } from './commands/pageState.js';
18
18
  import { registerStorage } from './commands/storage.js';
19
19
  import { registerConsoleMonitor } from './commands/consoleMonitor.js';
20
+ import { registerMutations } from './commands/mutations.js';
21
+ import { registerSnapshot } from './commands/snapshot.js';
22
+ import { registerDiff } from './commands/diff.js';
20
23
  const __dirname = dirname(fileURLToPath(import.meta.url));
21
24
  const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
22
25
  const program = new Command()
@@ -47,6 +50,9 @@ registerIpcMonitor(program);
47
50
  registerPageState(program);
48
51
  registerStorage(program);
49
52
  registerConsoleMonitor(program);
53
+ registerMutations(program);
54
+ registerSnapshot(program, getAdapter);
55
+ registerDiff(program);
50
56
  program.parseAsync().catch((err) => {
51
57
  console.error(err instanceof Error ? err.message : String(err));
52
58
  process.exitCode = 1;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerDiff(program: Command): void;
@@ -0,0 +1,90 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { Command } from 'commander';
3
+ import { exec } from '../util/exec.js';
4
+ function formatResult(result) {
5
+ const lines = [
6
+ `Pixels different: ${result.pixelsDifferent}`,
7
+ `Total pixels: ${result.totalPixels}`,
8
+ `Difference: ${result.percentDifferent.toFixed(3)}%`,
9
+ ];
10
+ if (result.diffImage) {
11
+ lines.push(`Diff image: ${result.diffImage}`);
12
+ }
13
+ return lines.join('\n');
14
+ }
15
+ export function registerDiff(program) {
16
+ const cmd = new Command('diff')
17
+ .description('Compare two screenshots and output difference metrics')
18
+ .argument('<image1>', 'First image path')
19
+ .argument('<image2>', 'Second image path')
20
+ .option('-o, --output <path>', 'Diff image output path')
21
+ .option('--threshold <percent>', 'Fail (exit code 1) if difference exceeds this percentage', parseFloat)
22
+ .option('--json', 'Output structured JSON');
23
+ cmd.action(async (image1, image2, opts) => {
24
+ // Verify files exist
25
+ for (const img of [image1, image2]) {
26
+ try {
27
+ await stat(img);
28
+ }
29
+ catch {
30
+ throw new Error(`File not found: ${img}`);
31
+ }
32
+ }
33
+ // Get image dimensions for total pixel count
34
+ let totalPixels = 0;
35
+ try {
36
+ const { stdout } = await exec('identify', ['-format', '%w %h', image1]);
37
+ const [w, h] = stdout.toString().trim().split(' ').map(Number);
38
+ totalPixels = w * h;
39
+ }
40
+ catch {
41
+ if (opts.threshold !== undefined) {
42
+ throw new Error('Cannot compute percentage: `identify` failed to read image dimensions');
43
+ }
44
+ }
45
+ // Compare images
46
+ const diffOutput = opts.output ?? '/dev/null';
47
+ let pixelsDifferent = 0;
48
+ try {
49
+ // compare exits with code 1 when images differ (not an error)
50
+ const { stderr } = await exec('compare', [
51
+ '-metric', 'AE',
52
+ image1,
53
+ image2,
54
+ diffOutput,
55
+ ]);
56
+ pixelsDifferent = parseInt(stderr.trim(), 10) || 0;
57
+ }
58
+ catch (err) {
59
+ // ImageMagick `compare` exits 1 when images differ — parse stderr
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ const match = msg.match(/(\d+)/);
62
+ if (match) {
63
+ pixelsDifferent = parseInt(match[1], 10);
64
+ }
65
+ else {
66
+ throw err;
67
+ }
68
+ }
69
+ const percentDifferent = totalPixels > 0
70
+ ? (pixelsDifferent / totalPixels) * 100
71
+ : 0;
72
+ const result = {
73
+ pixelsDifferent,
74
+ totalPixels,
75
+ percentDifferent,
76
+ diffImage: opts.output ?? null,
77
+ };
78
+ if (opts.json) {
79
+ console.log(JSON.stringify(result, null, 2));
80
+ }
81
+ else {
82
+ console.log(formatResult(result));
83
+ }
84
+ if (opts.threshold !== undefined && percentDifferent > opts.threshold) {
85
+ process.exitCode = 1;
86
+ }
87
+ });
88
+ program.addCommand(cmd);
89
+ }
90
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
1
  import { Command } from 'commander';
2
+ export declare function buildSerializerScript(selector: string, depth: number, includeStyles: boolean): string;
2
3
  export declare function registerDom(program: Command): void;
@@ -66,7 +66,7 @@ function printTree(node, indent, maxDepth) {
66
66
  }
67
67
  return lines;
68
68
  }
69
- function buildSerializerScript(selector, depth, includeStyles) {
69
+ export function buildSerializerScript(selector, depth, includeStyles) {
70
70
  return `(() => {
71
71
  function serialize(el, d, maxD, styles) {
72
72
  const r = el.getBoundingClientRect();
@@ -123,6 +123,7 @@ export function registerDom(program) {
123
123
  .option('--depth <number>', 'Max child depth', parseInt, 3)
124
124
  .option('--tree', 'Compact tree view (default)')
125
125
  .option('--styles', 'Include computed styles')
126
+ .option('--text <pattern>', 'Find elements containing this text (case-insensitive)')
126
127
  .option('--count', 'Just output match count')
127
128
  .option('--first', 'Only return first match')
128
129
  .option('--json', 'Full structured JSON output');
@@ -130,6 +131,67 @@ export function registerDom(program) {
130
131
  cmd.action(async (selectorArg, opts) => {
131
132
  const selector = opts.selector ?? selectorArg;
132
133
  const bridge = await resolveBridge(opts);
134
+ // Find-by-text mode
135
+ if (opts.text) {
136
+ const escapedText = opts.text.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
137
+ const escapedSelector = selector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
138
+ const textScript = `(() => {
139
+ var root = document.querySelector('${escapedSelector}') || document.body;
140
+ var pattern = '${escapedText}'.toLowerCase();
141
+ var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);
142
+ var seen = new Set();
143
+ var results = [];
144
+ while (walker.nextNode()) {
145
+ var textNode = walker.currentNode;
146
+ if (textNode.textContent && textNode.textContent.toLowerCase().includes(pattern)) {
147
+ var el = textNode.parentElement;
148
+ if (el && !seen.has(el)) {
149
+ seen.add(el);
150
+ var r = el.getBoundingClientRect();
151
+ var node = { tag: el.tagName.toLowerCase(), rect: { width: r.width, height: r.height } };
152
+ if (el.id) node.id = el.id;
153
+ var cls = Array.from(el.classList);
154
+ if (cls.length) node.classes = cls;
155
+ node.text = el.textContent.trim().substring(0, 100);
156
+ results.push(node);
157
+ }
158
+ }
159
+ }
160
+ return JSON.stringify(results);
161
+ })()`;
162
+ const raw = await bridge.eval(textScript);
163
+ const matches = JSON.parse(String(raw));
164
+ if (opts.count) {
165
+ console.log(String(matches.length));
166
+ return;
167
+ }
168
+ if (opts.first) {
169
+ if (matches.length === 0) {
170
+ throw new Error(`No elements found containing "${opts.text}"`);
171
+ }
172
+ if (opts.json) {
173
+ console.log(JSON.stringify(matches[0], null, 2));
174
+ }
175
+ else {
176
+ console.log(formatTreeLine(matches[0], 0));
177
+ }
178
+ return;
179
+ }
180
+ if (opts.json) {
181
+ console.log(JSON.stringify(matches, null, 2));
182
+ }
183
+ else {
184
+ if (matches.length === 0) {
185
+ console.log(`No elements found containing "${opts.text}"`);
186
+ }
187
+ else {
188
+ for (const node of matches) {
189
+ console.log(formatTreeLine(node, 0));
190
+ }
191
+ }
192
+ }
193
+ return;
194
+ }
133
195
  if (opts.mode === 'accessibility') {
134
196
  const tree = await bridge.getAccessibilityTree(selector, opts.depth);
135
197
  if (!tree) {
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/commands/dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAoB9D,SAAS,cAAc,CAAC,IAAc,EAAE,MAAc;IACpD,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;IACzB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACrF,IAAI,IAAI,KAAK,SAAS,GAAG,CAAC;IAC5B,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;YAC/B,CAAC;iBAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;iBAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,IAAI,KAAK,CAAC,MAAM;YAAE,IAAI,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,IAAc,EAAE,MAAc,EAAE,QAAgB;IACrE,MAAM,KAAK,GAAa,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,IAAI,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,IAAa,EAAE,MAAc;IACnD,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC;IACjB,IAAI,IAAI,CAAC,EAAE;QAAE,IAAI,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM;QAAE,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/D,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACrF,IAAI,IAAI,KAAK,SAAS,GAAG,CAAC;IAC5B,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC;YAAE,IAAI,IAAI,WAAW,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,IAAa,EAAE,MAAc,EAAE,QAAgB;IAChE,MAAM,KAAK,GAAa,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,IAAI,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB,EAAE,KAAa,EAAE,aAAsB;IACpF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA0CkC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;;+CAEzB,KAAK,KAAK,aAAa;OAC/D,CAAC;AACR,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC;SAC3B,WAAW,CAAC,wCAAwC,CAAC;SACrD,QAAQ,CAAC,YAAY,EAAE,yBAAyB,EAAE,MAAM,CAAC;SACzD,MAAM,CAAC,sBAAsB,EAAE,uCAAuC,CAAC;SACvE,MAAM,CAAC,eAAe,EAAE,6CAA6C,EAAE,KAAK,CAAC;SAC7E,MAAM,CAAC,kBAAkB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC;SAC1D,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC;SAC/C,MAAM,CAAC,UAAU,EAAE,yBAAyB,CAAC;SAC7C,MAAM,CAAC,SAAS,EAAE,yBAAyB,CAAC;SAC5C,MAAM,CAAC,SAAS,EAAE,yBAAyB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC,CAAC;IAEnD,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAEtB,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,WAAmB,EAAE,IAWtC,EAAE,EAAE;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,WAAW,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;QAEzC,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAoB,CAAC;YACxF,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;YACpD,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAE9C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,8BAA8B,OAAO,WAAW,CAAC;YAC5D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,iEAAiE;YACjE,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEzC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAEjD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/commands/dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { Command } from 'commander';
2
+ export interface MutationEntry {
3
+ type: string;
4
+ target: string;
5
+ timestamp: number;
6
+ added?: Array<{
7
+ tag: string;
8
+ id?: string;
9
+ class?: string;
10
+ }>;
11
+ removed?: Array<{
12
+ tag: string;
13
+ id?: string;
14
+ class?: string;
15
+ }>;
16
+ attribute?: string;
17
+ oldValue?: string | null;
18
+ newValue?: string | null;
19
+ }
20
+ export declare function formatEntry(entry: MutationEntry): string;
21
+ export declare function registerMutations(program: Command): void;
@@ -0,0 +1,144 @@
1
+ import { Command } from 'commander';
2
+ import { addBridgeOptions, resolveBridge } from './shared.js';
3
+ function buildPatchScript(selector, watchAttributes) {
4
+ const escaped = selector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
5
+ return `(() => {
6
+ if (window.__tauriDevToolsMutationPatched) return 'already_patched';
7
+ var target = document.querySelector('${escaped}');
8
+ if (!target) return 'not_found';
9
+ window.__tauriDevToolsMutationLog = [];
10
+ function describeEl(el) {
11
+ if (!el || el.nodeType !== 1) return null;
12
+ var d = { tag: el.tagName.toLowerCase() };
13
+ if (el.id) d.id = el.id;
14
+ var cls = Array.from(el.classList).join(' ');
15
+ if (cls) d.class = cls;
16
+ return d;
17
+ }
18
+ window.__tauriDevToolsMutationObserver = new MutationObserver(function(mutations) {
19
+ for (var i = 0; i < mutations.length; i++) {
20
+ var m = mutations[i];
21
+ var entry = { type: m.type, timestamp: Date.now() };
22
+ var t = m.target;
23
+ entry.target = (t.id ? '#' + t.id : '') || (t.className && typeof t.className === 'string' ? '.' + t.className.split(' ').join('.') : t.tagName ? t.tagName.toLowerCase() : '?');
24
+ if (m.type === 'childList') {
25
+ entry.added = Array.from(m.addedNodes).map(describeEl).filter(Boolean);
26
+ entry.removed = Array.from(m.removedNodes).map(describeEl).filter(Boolean);
27
+ } else if (m.type === 'attributes') {
28
+ entry.attribute = m.attributeName;
29
+ entry.oldValue = m.oldValue;
30
+ entry.newValue = m.target.getAttribute(m.attributeName);
31
+ }
32
+ window.__tauriDevToolsMutationLog.push(entry);
33
+ }
34
+ });
35
+ window.__tauriDevToolsMutationObserver.observe(target, {
36
+ childList: true,
37
+ subtree: true,
38
+ attributes: ${watchAttributes},
39
+ attributeOldValue: ${watchAttributes}
40
+ });
41
+ window.__tauriDevToolsMutationPatched = true;
42
+ return 'patched';
43
+ })()`;
44
+ }
45
+ const DRAIN_SCRIPT = `(() => {
46
+ var log = window.__tauriDevToolsMutationLog || [];
47
+ window.__tauriDevToolsMutationLog = [];
48
+ return JSON.stringify(log);
49
+ })()`;
50
+ const CLEANUP_SCRIPT = `(() => {
51
+ if (window.__tauriDevToolsMutationObserver) {
52
+ window.__tauriDevToolsMutationObserver.disconnect();
53
+ delete window.__tauriDevToolsMutationObserver;
54
+ delete window.__tauriDevToolsMutationLog;
55
+ delete window.__tauriDevToolsMutationPatched;
56
+ }
57
+ return 'cleaned';
58
+ })()`;
59
+ export function formatEntry(entry) {
60
+ const time = new Date(entry.timestamp).toISOString().slice(11, 23);
61
+ if (entry.type === 'childList') {
62
+ const parts = [];
63
+ if (entry.added?.length) {
64
+ parts.push(`+${entry.added.map(n => n.class ? `.${n.class.split(' ').join('.')}` : n.tag).join(', ')}`);
65
+ }
66
+ if (entry.removed?.length) {
67
+ parts.push(`-${entry.removed.map(n => n.class ? `.${n.class.split(' ').join('.')}` : n.tag).join(', ')}`);
68
+ }
69
+ return `[${time}] childList ${entry.target} ${parts.join(' ')}`;
70
+ }
71
+ if (entry.type === 'attributes') {
72
+ return `[${time}] attr ${entry.target} ${entry.attribute}: ${entry.oldValue} → ${entry.newValue}`;
73
+ }
74
+ return `[${time}] ${entry.type} ${entry.target}`;
75
+ }
76
+ async function cleanup(bridge) {
77
+ try {
78
+ await bridge.eval(CLEANUP_SCRIPT);
79
+ }
80
+ catch {
81
+ // Best-effort cleanup
82
+ }
83
+ }
84
+ export function registerMutations(program) {
85
+ const cmd = new Command('mutations')
86
+ .description('Watch DOM mutations on a CSS selector (read-only)')
87
+ .argument('<selector>', 'CSS selector of the element to observe')
88
+ .option('--attributes', 'Also watch attribute changes')
89
+ .option('--interval <ms>', 'Poll interval in milliseconds', parseInt, 500)
90
+ .option('--duration <ms>', 'Auto-stop after N milliseconds', parseInt)
91
+ .option('--json', 'Output one JSON object per line');
92
+ addBridgeOptions(cmd);
93
+ cmd.action(async (selector, opts) => {
94
+ const bridge = await resolveBridge(opts);
95
+ const patchResult = await bridge.eval(buildPatchScript(selector, !!opts.attributes));
96
+ if (patchResult === 'not_found') {
97
+ throw new Error(`Element not found: ${selector}`);
98
+ }
99
+ if (patchResult === 'already_patched') {
100
+ console.error('Warning: mutation observer already active — draining existing log');
101
+ }
102
+ let stopped = false;
103
+ const onSignal = () => {
104
+ stopped = true;
105
+ };
106
+ process.on('SIGINT', onSignal);
107
+ process.on('SIGTERM', onSignal);
108
+ let timer;
109
+ if (opts.duration) {
110
+ timer = setTimeout(() => {
111
+ stopped = true;
112
+ }, opts.duration);
113
+ }
114
+ if (!opts.json) {
115
+ console.error(`Watching mutations on ${selector}... (Ctrl+C to stop)`);
116
+ }
117
+ try {
118
+ while (!stopped) {
119
+ await new Promise((resolve) => setTimeout(resolve, opts.interval));
120
+ if (stopped)
121
+ break;
122
+ const raw = await bridge.eval(DRAIN_SCRIPT);
123
+ const entries = JSON.parse(String(raw));
124
+ for (const entry of entries) {
125
+ if (opts.json) {
126
+ console.log(JSON.stringify(entry));
127
+ }
128
+ else {
129
+ console.log(formatEntry(entry));
130
+ }
131
+ }
132
+ }
133
+ }
134
+ finally {
135
+ if (timer)
136
+ clearTimeout(timer);
137
+ process.off('SIGINT', onSignal);
138
+ process.off('SIGTERM', onSignal);
139
+ await cleanup(bridge);
140
+ }
141
+ });
142
+ program.addCommand(cmd);
143
+ }
144
+ //# sourceMappingURL=mutations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/commands/mutations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ import type { PlatformAdapter } from '../types.js';
3
+ export declare function registerSnapshot(program: Command, getAdapter: () => PlatformAdapter | Promise<PlatformAdapter>): void;
@@ -0,0 +1,131 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { Command } from 'commander';
3
+ import { addBridgeOptions, resolveBridge } from './shared.js';
4
+ import { buildSerializerScript } from './dom.js';
5
+ import { computeCropRect, cropImage } from '../util/image.js';
6
+ const PAGE_STATE_SCRIPT = `(() => {
7
+ return JSON.stringify({
8
+ url: window.location.href,
9
+ title: document.title,
10
+ viewport: { width: window.innerWidth, height: window.innerHeight },
11
+ scroll: { x: Math.round(window.scrollX), y: Math.round(window.scrollY) },
12
+ document: { width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight },
13
+ hasTauri: !!(window.__TAURI__)
14
+ });
15
+ })()`;
16
+ const STORAGE_SCRIPT = `(() => {
17
+ var local = Object.keys(localStorage).map(function(k) { return { key: k, value: localStorage.getItem(k) }; });
18
+ var session = Object.keys(sessionStorage).map(function(k) { return { key: k, value: sessionStorage.getItem(k) }; });
19
+ return JSON.stringify({ localStorage: local, sessionStorage: session });
20
+ })()`;
21
+ async function resolveWindowId(adapter, bridge, title) {
22
+ if (title)
23
+ return adapter.findWindow(title);
24
+ const docTitle = await bridge.getDocumentTitle();
25
+ if (!docTitle)
26
+ throw new Error('Could not get window title. Use --title.');
27
+ return adapter.findWindow(docTitle);
28
+ }
29
+ export function registerSnapshot(program, getAdapter) {
30
+ const cmd = new Command('snapshot')
31
+ .description('Capture screenshot + DOM + page state + storage in one shot')
32
+ .requiredOption('-o, --output <prefix>', 'Output path prefix (e.g. /tmp/debug)')
33
+ .option('-s, --selector <css>', 'CSS selector to screenshot (full window if omitted)')
34
+ .option('-t, --title <regex>', 'Window title to match (default: auto-discover)')
35
+ .option('--dom-depth <number>', 'DOM tree depth', parseInt, 3)
36
+ .option('--eval <js>', 'Additional JS to eval and save')
37
+ .option('--json', 'Output structured manifest');
38
+ addBridgeOptions(cmd);
39
+ cmd.action(async (opts) => {
40
+ const bridge = await resolveBridge(opts);
41
+ const adapter = await getAdapter();
42
+ const prefix = opts.output;
43
+ const format = 'png';
44
+ const files = {};
45
+ // 1. Screenshot
46
+ try {
47
+ const windowId = await resolveWindowId(adapter, bridge, opts.title);
48
+ let buffer;
49
+ if (opts.selector) {
50
+ const elementRect = await bridge.getElementRect(opts.selector);
51
+ if (!elementRect)
52
+ throw new Error(`Element not found: ${opts.selector}`);
53
+ const viewport = await bridge.getViewportSize();
54
+ const windowGeom = await adapter.getWindowGeometry(windowId);
55
+ buffer = await adapter.captureWindow(windowId, format);
56
+ const cropRect = computeCropRect(elementRect, viewport, {
57
+ width: windowGeom.width,
58
+ height: windowGeom.height,
59
+ });
60
+ buffer = await cropImage(buffer, cropRect, format);
61
+ }
62
+ else {
63
+ buffer = await adapter.captureWindow(windowId, format);
64
+ }
65
+ const path = `${prefix}-screenshot.png`;
66
+ await writeFile(path, buffer);
67
+ files.screenshot = path;
68
+ }
69
+ catch (err) {
70
+ files.screenshot = `error: ${err instanceof Error ? err.message : String(err)}`;
71
+ }
72
+ // 2. DOM
73
+ try {
74
+ const raw = await bridge.eval(buildSerializerScript('body', opts.domDepth, false));
75
+ const path = `${prefix}-dom.json`;
76
+ await writeFile(path, JSON.stringify(JSON.parse(String(raw)), null, 2));
77
+ files.dom = path;
78
+ }
79
+ catch (err) {
80
+ files.dom = `error: ${err instanceof Error ? err.message : String(err)}`;
81
+ }
82
+ // 3. Page state
83
+ try {
84
+ const raw = await bridge.eval(PAGE_STATE_SCRIPT);
85
+ const path = `${prefix}-page-state.json`;
86
+ await writeFile(path, JSON.stringify(JSON.parse(String(raw)), null, 2));
87
+ files.pageState = path;
88
+ }
89
+ catch (err) {
90
+ files.pageState = `error: ${err instanceof Error ? err.message : String(err)}`;
91
+ }
92
+ // 4. Storage
93
+ try {
94
+ const raw = await bridge.eval(STORAGE_SCRIPT);
95
+ const path = `${prefix}-storage.json`;
96
+ await writeFile(path, JSON.stringify(JSON.parse(String(raw)), null, 2));
97
+ files.storage = path;
98
+ }
99
+ catch (err) {
100
+ files.storage = `error: ${err instanceof Error ? err.message : String(err)}`;
101
+ }
102
+ // 5. Custom eval (optional)
103
+ if (opts.eval) {
104
+ try {
105
+ const raw = await bridge.eval(opts.eval);
106
+ const path = `${prefix}-eval.json`;
107
+ const parsed = typeof raw === 'string' ? (() => { try {
108
+ return JSON.parse(raw);
109
+ }
110
+ catch {
111
+ return raw;
112
+ } })() : raw;
113
+ await writeFile(path, JSON.stringify(parsed, null, 2));
114
+ files.eval = path;
115
+ }
116
+ catch (err) {
117
+ files.eval = `error: ${err instanceof Error ? err.message : String(err)}`;
118
+ }
119
+ }
120
+ if (opts.json) {
121
+ console.log(JSON.stringify(files, null, 2));
122
+ }
123
+ else {
124
+ for (const [key, path] of Object.entries(files)) {
125
+ console.log(`${key}: ${path}`);
126
+ }
127
+ }
128
+ });
129
+ program.addCommand(cmd);
130
+ }
131
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/commands/snapshot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-agent-tools",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Agent-driven inspection toolkit for Tauri desktop apps",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,6 +48,7 @@
48
48
  "devDependencies": {
49
49
  "@eslint/js": "^9.0.0",
50
50
  "@types/node": "^22.0.0",
51
+ "@vitest/coverage-v8": "^3.2.4",
51
52
  "eslint": "^9.0.0",
52
53
  "typescript": "^5.8.0",
53
54
  "typescript-eslint": "^8.0.0",