tauri-agent-tools 0.7.1 → 0.9.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 (82) hide show
  1. package/.agents/skills/tauri-agent-tools/SKILL.md +59 -14
  2. package/.agents/skills/tauri-bridge-setup/SKILL.md +10 -4
  3. package/.agents/skills/tauri-debug-quickstart/SKILL.md +10 -6
  4. package/AGENTS.md +13 -3
  5. package/README.md +33 -5
  6. package/dist/bridge/client.d.ts +21 -0
  7. package/dist/bridge/client.js +38 -2
  8. package/dist/bridge/client.js.map +1 -1
  9. package/dist/bridge/tokenDiscovery.js +5 -2
  10. package/dist/bridge/tokenDiscovery.js.map +1 -1
  11. package/dist/cli.js +5 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/bundle.d.ts +2 -0
  14. package/dist/commands/bundle.js +212 -0
  15. package/dist/commands/bundle.js.map +1 -0
  16. package/dist/commands/capabilitiesAudit.js +14 -1
  17. package/dist/commands/capabilitiesAudit.js.map +1 -1
  18. package/dist/commands/capture.d.ts +11 -0
  19. package/dist/commands/capture.js +161 -156
  20. package/dist/commands/capture.js.map +1 -1
  21. package/dist/commands/check.js +2 -2
  22. package/dist/commands/check.js.map +1 -1
  23. package/dist/commands/consoleMonitor.js +3 -3
  24. package/dist/commands/consoleMonitor.js.map +1 -1
  25. package/dist/commands/dom.js +2 -2
  26. package/dist/commands/dom.js.map +1 -1
  27. package/dist/commands/health.js +19 -1
  28. package/dist/commands/health.js.map +1 -1
  29. package/dist/commands/interact/click.js +2 -2
  30. package/dist/commands/interact/click.js.map +1 -1
  31. package/dist/commands/interact/scroll.js +3 -3
  32. package/dist/commands/interact/scroll.js.map +1 -1
  33. package/dist/commands/ipcMonitor.js +41 -7
  34. package/dist/commands/ipcMonitor.js.map +1 -1
  35. package/dist/commands/logs.d.ts +30 -0
  36. package/dist/commands/logs.js +279 -0
  37. package/dist/commands/logs.js.map +1 -0
  38. package/dist/commands/mutations.js +3 -3
  39. package/dist/commands/mutations.js.map +1 -1
  40. package/dist/commands/probe.js +49 -9
  41. package/dist/commands/probe.js.map +1 -1
  42. package/dist/commands/processTree.js +116 -4
  43. package/dist/commands/processTree.js.map +1 -1
  44. package/dist/commands/rustLogs.js +3 -3
  45. package/dist/commands/rustLogs.js.map +1 -1
  46. package/dist/commands/screenshot.js +2 -2
  47. package/dist/commands/screenshot.js.map +1 -1
  48. package/dist/commands/shared.d.ts +37 -0
  49. package/dist/commands/shared.js +62 -3
  50. package/dist/commands/shared.js.map +1 -1
  51. package/dist/commands/sidecarReplay.js +46 -1
  52. package/dist/commands/sidecarReplay.js.map +1 -1
  53. package/dist/commands/sidecarTap.js +23 -8
  54. package/dist/commands/sidecarTap.js.map +1 -1
  55. package/dist/commands/snapshot.js +2 -2
  56. package/dist/commands/snapshot.js.map +1 -1
  57. package/dist/commands/storeInspect.js +2 -2
  58. package/dist/commands/storeInspect.js.map +1 -1
  59. package/dist/commands/wait.js +3 -3
  60. package/dist/commands/wait.js.map +1 -1
  61. package/dist/commands/webviewAttach.js +17 -1
  62. package/dist/commands/webviewAttach.js.map +1 -1
  63. package/dist/platform/macos.js +35 -15
  64. package/dist/platform/macos.js.map +1 -1
  65. package/dist/schemas/bridge.d.ts +14 -0
  66. package/dist/schemas/bridge.js +3 -0
  67. package/dist/schemas/bridge.js.map +1 -1
  68. package/dist/util/logMerge.d.ts +42 -0
  69. package/dist/util/logMerge.js +133 -0
  70. package/dist/util/logMerge.js.map +1 -0
  71. package/dist/util/mergeByTimestamp.d.ts +18 -0
  72. package/dist/util/mergeByTimestamp.js +30 -0
  73. package/dist/util/mergeByTimestamp.js.map +1 -0
  74. package/dist/util/psTree.d.ts +28 -0
  75. package/dist/util/psTree.js +76 -0
  76. package/dist/util/psTree.js.map +1 -0
  77. package/dist/util/redactText.d.ts +23 -0
  78. package/dist/util/redactText.js +377 -0
  79. package/dist/util/redactText.js.map +1 -0
  80. package/examples/tauri-bridge/src/dev_bridge.rs +199 -12
  81. package/package.json +3 -2
  82. package/rust-bridge/README.md +2 -2
@@ -0,0 +1,212 @@
1
+ import { Command } from 'commander';
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdir, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { addBridgeOptions } from './shared.js';
6
+ import { exec } from '../util/exec.js';
7
+ import { redactDir } from '../util/redactText.js';
8
+ export function registerBundle(program) {
9
+ const cmd = new Command('bundle')
10
+ .description('Collect a shareable incident bundle: merged logs, deep process tree, app paths, forensics ' +
11
+ '(and optionally a UI capture) into one redacted directory + .tar.gz. Best-effort — degrades cleanly.')
12
+ .option('--config <path>', 'Path to tauri.conf.json (or its directory). Auto-detected if omitted.')
13
+ .option('--identifier <id>', 'Bundle identifier override')
14
+ .option('-o, --out <dir>', 'Output directory (default: ./bundle-<timestamp>)')
15
+ .option('--since <duration>', 'How far back to pull from app log files (forensics phase, default: 10m)')
16
+ .option('--with-capture', 'Also capture a UI snapshot (screenshot + DOM); needs a live bridge')
17
+ .option('--no-archive', 'Skip the final .tar.gz (leave the directory only)')
18
+ .option('--json', 'Print the summary as JSON in addition to writing it to disk');
19
+ addBridgeOptions(cmd);
20
+ cmd.action(async (opts) => {
21
+ const outDir = opts.out ?? `./bundle-${timestampSlug()}`;
22
+ await mkdir(outDir, { recursive: true });
23
+ const outcomes = [];
24
+ // ── Merged logs (bridge-optional + on-disk files) ───────────────────────
25
+ {
26
+ const args = ['logs', '--json'];
27
+ if (opts.config)
28
+ args.push('--config', opts.config);
29
+ if (opts.identifier)
30
+ args.push('--identifier', opts.identifier);
31
+ forwardBridge(args, opts);
32
+ outcomes.push(await runCapturingStdout(args, join(outDir, 'logs.ndjson')));
33
+ }
34
+ // ── Deep OS process tree ────────────────────────────────────────────────
35
+ {
36
+ const args = ['process-tree', '--deep', '--json'];
37
+ forwardBridge(args, opts);
38
+ outcomes.push(await runCapturingStdout(args, join(outDir, 'process-tree.json')));
39
+ }
40
+ // ── App paths ───────────────────────────────────────────────────────────
41
+ {
42
+ const args = ['app-paths', '--platform', 'all', '--exists', '--json'];
43
+ if (opts.config)
44
+ args.push('--config', opts.config);
45
+ if (opts.identifier)
46
+ args.push('--identifier', opts.identifier);
47
+ outcomes.push(await runCapturingStdout(args, join(outDir, 'app-paths.json')));
48
+ }
49
+ // ── Forensics bundle (bridge-free; works on a dead app) ─────────────────
50
+ {
51
+ const args = ['forensics', '-o', join(outDir, 'forensics')];
52
+ if (opts.config)
53
+ args.push('--config', opts.config);
54
+ if (opts.identifier)
55
+ args.push('--identifier', opts.identifier);
56
+ if (opts.since)
57
+ args.push('--since', opts.since);
58
+ outcomes.push(await runToDir('forensics', args));
59
+ }
60
+ // ── Optional UI capture (needs a live bridge + screenshot tools) ────────
61
+ if (opts.withCapture) {
62
+ const args = ['capture', '-o', join(outDir, 'capture'), '--json'];
63
+ forwardBridge(args, opts);
64
+ outcomes.push(await runToDir('capture', args));
65
+ }
66
+ // ── Redact obvious secrets across all collected text files ──────────────
67
+ const redacted = await redactDir(outDir);
68
+ outcomes.push({
69
+ phase: 'redact',
70
+ ok: redacted.failures.length === 0,
71
+ detail: `redacted ${redacted.redactions} value(s), ${redacted.warnings.length} warning(s), ${redacted.failures.length} failure(s)`,
72
+ });
73
+ // ── Summary ─────────────────────────────────────────────────────────────
74
+ const summary = {
75
+ outDir,
76
+ createdPhases: outcomes,
77
+ ok: outcomes.filter((o) => o.ok).length,
78
+ total: outcomes.length,
79
+ };
80
+ await writeFile(join(outDir, 'summary.json'), JSON.stringify(summary, null, 2));
81
+ await writeFile(join(outDir, 'summary.md'), renderSummary(outDir, outcomes));
82
+ // ── Archive ─────────────────────────────────────────────────────────────
83
+ let archivePath = null;
84
+ if (opts.archive !== false) {
85
+ archivePath = `${outDir.replace(/\/+$/, '')}.tar.gz`;
86
+ try {
87
+ await exec('tar', ['-czf', archivePath, '-C', dirnameOf(outDir), basenameOf(outDir)]);
88
+ outcomes.push({ phase: 'archive', ok: true, detail: `→ ${archivePath}` });
89
+ }
90
+ catch (e) {
91
+ archivePath = null;
92
+ outcomes.push({
93
+ phase: 'archive',
94
+ ok: false,
95
+ detail: e instanceof Error ? e.message : String(e),
96
+ });
97
+ }
98
+ }
99
+ if (opts.json) {
100
+ console.log(JSON.stringify({ ...summary, archive: archivePath }, null, 2));
101
+ }
102
+ else {
103
+ console.log(`✓ Incident bundle written to ${outDir}`);
104
+ console.log(` ${summary.ok}/${summary.total} phases succeeded`);
105
+ if (archivePath)
106
+ console.log(` Archive: ${archivePath}`);
107
+ console.log(` Open ${join(outDir, 'summary.md')} first.`);
108
+ }
109
+ });
110
+ program.addCommand(cmd);
111
+ }
112
+ function forwardBridge(args, opts) {
113
+ if (opts.port !== undefined)
114
+ args.push('--port', String(opts.port));
115
+ if (opts.token !== undefined)
116
+ args.push('--token', opts.token);
117
+ if (opts.pid !== undefined)
118
+ args.push('--pid', String(opts.pid));
119
+ if (opts.windowLabel !== undefined)
120
+ args.push('--window-label', opts.windowLabel);
121
+ }
122
+ function timestampSlug() {
123
+ return new Date().toISOString().replace(/[:.]/g, '-');
124
+ }
125
+ function dirnameOf(p) {
126
+ const norm = p.replace(/\/+$/, '');
127
+ const idx = norm.lastIndexOf('/');
128
+ return idx <= 0 ? '.' : norm.slice(0, idx);
129
+ }
130
+ function basenameOf(p) {
131
+ const norm = p.replace(/\/+$/, '');
132
+ const idx = norm.lastIndexOf('/');
133
+ return idx < 0 ? norm : norm.slice(idx + 1);
134
+ }
135
+ /** Spawn this same CLI binary, capturing stdout into `outFile`. */
136
+ function runCapturingStdout(args, outFile) {
137
+ return new Promise((resolve) => {
138
+ const cliPath = process.argv[1];
139
+ if (!cliPath) {
140
+ resolve({ phase: args[0] ?? 'phase', ok: false, detail: 'could not locate CLI binary' });
141
+ return;
142
+ }
143
+ const child = spawn(process.execPath, [cliPath, ...args], { stdio: ['ignore', 'pipe', 'pipe'] });
144
+ let stdout = '';
145
+ let stderr = '';
146
+ child.stdout.setEncoding('utf-8');
147
+ child.stdout.on('data', (c) => (stdout += c));
148
+ child.stderr.setEncoding('utf-8');
149
+ child.stderr.on('data', (c) => (stderr += c));
150
+ child.on('error', (err) => resolve({ phase: args[0] ?? 'phase', ok: false, detail: err.message }));
151
+ child.on('close', async (code) => {
152
+ try {
153
+ await writeFile(outFile, stdout);
154
+ }
155
+ catch {
156
+ /* ignore write failure */
157
+ }
158
+ resolve({
159
+ phase: args[0] ?? 'phase',
160
+ ok: code === 0,
161
+ detail: code === 0 ? `→ ${outFile}` : `exit ${code}${stderr ? ': ' + stderr.trim().slice(0, 200) : ''}`,
162
+ });
163
+ });
164
+ });
165
+ }
166
+ /** Spawn this CLI binary for a command that writes its own output directory. */
167
+ function runToDir(phase, args) {
168
+ return new Promise((resolve) => {
169
+ const cliPath = process.argv[1];
170
+ if (!cliPath) {
171
+ resolve({ phase, ok: false, detail: 'could not locate CLI binary' });
172
+ return;
173
+ }
174
+ const child = spawn(process.execPath, [cliPath, ...args], { stdio: ['ignore', 'ignore', 'pipe'] });
175
+ let stderr = '';
176
+ child.stderr.setEncoding('utf-8');
177
+ child.stderr.on('data', (c) => (stderr += c));
178
+ child.on('error', (err) => resolve({ phase, ok: false, detail: err.message }));
179
+ child.on('close', (code) => resolve({
180
+ phase,
181
+ ok: code === 0,
182
+ detail: code === 0 ? 'ok' : `exit ${code}${stderr ? ': ' + stderr.trim().slice(0, 200) : ''}`,
183
+ }));
184
+ });
185
+ }
186
+ function renderSummary(outDir, outcomes) {
187
+ const rows = outcomes.map((o) => `- ${o.ok ? '✓' : '✗'} **${o.phase}** — ${o.detail}`).join('\n');
188
+ return `# Incident bundle
189
+
190
+ - **Output:** \`${outDir}\`
191
+
192
+ ## Contents
193
+
194
+ - \`logs.ndjson\` — merged, timestamp-ordered logs (bridge ring buffer + on-disk log files)
195
+ - \`process-tree.json\` — full OS process descendant tree (sidecars + grandchildren)
196
+ - \`app-paths.json\` — resolved per-platform data/log/cache/config dirs (with existence)
197
+ - \`forensics/\` — post-mortem bundle (app-log tail, panic markers, OS-log tail, app-data listing)
198
+ - \`capture/\` — UI snapshot (only when \`--with-capture\` and a bridge were available)
199
+
200
+ ## Phases
201
+
202
+ ${rows}
203
+
204
+ ## Notes
205
+
206
+ Secrets (\`token\`, \`api_key\`, \`password\`, JWTs, AWS keys, …) and PII (emails, IPs,
207
+ phone numbers, home paths) were redacted from text artifacts on write. Images are
208
+ not redacted and are flagged as warnings in the redact phase.
209
+ Re-run any individual command directly for live/interactive inspection.
210
+ `;
211
+ }
212
+ //# sourceMappingURL=bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/commands/bundle.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import { addBridgeOptions, resolveBridge } from './shared.js';
2
+ import { addBridgeOptions, resolveBridge, endpointAvailable, endpointUnavailableNote, } from './shared.js';
3
3
  const OVERBROAD_PERMISSIONS = new Set([
4
4
  'fs:allow-all',
5
5
  'fs:default',
@@ -17,6 +17,19 @@ export function registerCapabilitiesAudit(program) {
17
17
  addBridgeOptions(sub);
18
18
  sub.action(async (opts) => {
19
19
  const bridge = await resolveBridge(opts);
20
+ // Graceful degradation: older bridges (pre-v0.7) have no /capabilities
21
+ // endpoint. Point the user at the bridge-free static auditor instead.
22
+ if (!(await endpointAvailable(bridge, '/capabilities', opts))) {
23
+ const note = endpointUnavailableNote('/capabilities', (await bridge.version())?.version) +
24
+ ' For a bridge-free audit, run `tauri-agent-tools config inspect`.';
25
+ if (opts.json) {
26
+ console.log(JSON.stringify({ endpoint: '/capabilities', available: false, note }, null, 2));
27
+ }
28
+ else {
29
+ console.error(`note: ${note}`);
30
+ }
31
+ return;
32
+ }
20
33
  const caps = await bridge.capabilities();
21
34
  const findings = audit(caps);
22
35
  const out = {
@@ -1 +1 @@
1
- {"version":3,"file":"capabilitiesAudit.js","sourceRoot":"","sources":["../../src/commands/capabilitiesAudit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capabilitiesAudit.js","sourceRoot":"","sources":["../../src/commands/capabilitiesAudit.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,14 @@
1
1
  import { Command } from 'commander';
2
2
  import type { PlatformAdapter } from '../types.js';
3
+ import type { CaptureManifest } from '../schemas/commands.js';
4
+ import type { BridgeClient } from '../bridge/client.js';
5
+ export interface CaptureToDirOptions {
6
+ output: string;
7
+ selector?: string;
8
+ title?: string;
9
+ domDepth: number;
10
+ eval?: string;
11
+ logsDuration: number;
12
+ }
13
+ export declare function captureToDir(bridge: BridgeClient, adapter: PlatformAdapter, opts: CaptureToDirOptions): Promise<CaptureManifest>;
3
14
  export declare function registerCapture(program: Command, getAdapter: () => PlatformAdapter | Promise<PlatformAdapter>): void;
@@ -1,7 +1,7 @@
1
1
  import { writeFile, mkdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { Command } from 'commander';
4
- import { addBridgeOptions, resolveBridge } from './shared.js';
4
+ import { addBridgeOptions, resolveBridge, parseIntArg } from './shared.js';
5
5
  import { buildSerializerScript } from './dom.js';
6
6
  import { computeCropRect, cropImage } from '../util/image.js';
7
7
  import { DomNodeSchema } from '../schemas/dom.js';
@@ -45,174 +45,179 @@ async function resolveWindowId(adapter, bridge, title) {
45
45
  throw new Error('Could not get window title. Use --title.');
46
46
  return adapter.findWindow(docTitle);
47
47
  }
48
+ export async function captureToDir(bridge, adapter, opts) {
49
+ const outDir = opts.output;
50
+ const format = 'png';
51
+ const files = {};
52
+ // 1. Create output directory
53
+ await mkdir(outDir, { recursive: true });
54
+ // 2. Inject console error capture
55
+ try {
56
+ await bridge.eval(INJECT_CONSOLE_ERROR_SCRIPT);
57
+ }
58
+ catch {
59
+ // Non-fatal — continue without error capture
60
+ }
61
+ // 3. Get page state — save to page-state.json
62
+ let capturedUrl;
63
+ let capturedTitle;
64
+ let capturedViewport;
65
+ try {
66
+ const raw = await bridge.eval(PAGE_STATE_SCRIPT);
67
+ const parsed = PageStateSchema.parse(JSON.parse(String(raw)));
68
+ capturedUrl = parsed.url;
69
+ capturedTitle = parsed.title;
70
+ capturedViewport = parsed.viewport;
71
+ const path = join(outDir, 'page-state.json');
72
+ await writeFile(path, JSON.stringify(parsed, null, 2));
73
+ files['page-state.json'] = path;
74
+ }
75
+ catch (err) {
76
+ files['page-state.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
77
+ }
78
+ // 4. Screenshot — save to screenshot.png
79
+ try {
80
+ const windowId = await resolveWindowId(adapter, bridge, opts.title);
81
+ let buffer;
82
+ if (opts.selector) {
83
+ const elementRect = await bridge.getElementRect(opts.selector);
84
+ if (!elementRect)
85
+ throw new Error(`Element not found: ${opts.selector}`);
86
+ const viewport = await bridge.getViewportSize();
87
+ const windowGeom = await adapter.getWindowGeometry(windowId);
88
+ buffer = await adapter.captureWindow(windowId, format);
89
+ const cropRect = computeCropRect(elementRect, viewport, {
90
+ width: windowGeom.width,
91
+ height: windowGeom.height,
92
+ });
93
+ buffer = await cropImage(buffer, cropRect, format);
94
+ }
95
+ else {
96
+ buffer = await adapter.captureWindow(windowId, format);
97
+ }
98
+ const path = join(outDir, 'screenshot.png');
99
+ await writeFile(path, buffer);
100
+ files['screenshot.png'] = path;
101
+ }
102
+ catch (err) {
103
+ files['screenshot.png'] = `error: ${err instanceof Error ? err.message : String(err)}`;
104
+ }
105
+ // 5. DOM tree — save to dom.json
106
+ try {
107
+ const raw = await bridge.eval(buildSerializerScript('body', opts.domDepth, false));
108
+ const parsed = DomNodeSchema.parse(JSON.parse(String(raw)));
109
+ const path = join(outDir, 'dom.json');
110
+ await writeFile(path, JSON.stringify(parsed, null, 2));
111
+ files['dom.json'] = path;
112
+ }
113
+ catch (err) {
114
+ files['dom.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
115
+ }
116
+ // 6. Storage — save to storage.json
117
+ try {
118
+ const raw = await bridge.eval(STORAGE_SCRIPT);
119
+ const parsed = SnapshotStorageResultSchema.parse(JSON.parse(String(raw)));
120
+ const path = join(outDir, 'storage.json');
121
+ await writeFile(path, JSON.stringify(parsed, null, 2));
122
+ files['storage.json'] = path;
123
+ }
124
+ catch (err) {
125
+ files['storage.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
126
+ }
127
+ // 7. Wait for logs-duration, drain console errors — save to console-errors.json
128
+ try {
129
+ await new Promise((resolve) => setTimeout(resolve, opts.logsDuration));
130
+ const raw = await bridge.eval(DRAIN_CONSOLE_ERRORS_SCRIPT);
131
+ const errors = JSON.parse(String(raw));
132
+ const path = join(outDir, 'console-errors.json');
133
+ await writeFile(path, JSON.stringify(errors, null, 2));
134
+ files['console-errors.json'] = path;
135
+ }
136
+ catch (err) {
137
+ files['console-errors.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
138
+ }
139
+ // 8. Fetch rust logs — save to rust-logs.json
140
+ try {
141
+ const logs = await bridge.fetchLogs();
142
+ const path = join(outDir, 'rust-logs.json');
143
+ await writeFile(path, JSON.stringify(logs, null, 2));
144
+ files['rust-logs.json'] = path;
145
+ }
146
+ catch (err) {
147
+ files['rust-logs.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
148
+ }
149
+ // 9. Optional custom eval — save to eval.json
150
+ if (opts.eval) {
151
+ try {
152
+ const raw = await bridge.eval(opts.eval);
153
+ const parsed = typeof raw === 'string'
154
+ ? (() => { try {
155
+ return JSON.parse(raw);
156
+ }
157
+ catch {
158
+ return raw;
159
+ } })()
160
+ : raw;
161
+ const path = join(outDir, 'eval.json');
162
+ await writeFile(path, JSON.stringify(parsed, null, 2));
163
+ files['eval.json'] = path;
164
+ }
165
+ catch (err) {
166
+ files['eval.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
167
+ }
168
+ }
169
+ // 10. Write manifest.json
170
+ const errorCount = Object.values(files).filter(v => v.startsWith('error: ')).length;
171
+ const manifest = {
172
+ timestamp: new Date().toISOString(),
173
+ url: capturedUrl,
174
+ title: capturedTitle,
175
+ viewport: capturedViewport,
176
+ errorCount,
177
+ files,
178
+ };
179
+ const manifestPath = join(outDir, 'manifest.json');
180
+ await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
181
+ return manifest;
182
+ }
48
183
  export function registerCapture(program, getAdapter) {
49
184
  const cmd = new Command('capture')
50
185
  .description('Capture enhanced snapshot with manifest directory (screenshot, DOM, state, logs, errors)')
51
186
  .requiredOption('-o, --output <dir>', 'Output directory path')
52
187
  .option('-s, --selector <css>', 'CSS selector to screenshot (full window if omitted)')
53
188
  .option('-t, --title <regex>', 'Window title to match (default: auto-discover)')
54
- .option('--dom-depth <number>', 'DOM tree depth', parseInt, 3)
189
+ .option('--dom-depth <number>', 'DOM tree depth', parseIntArg, 3)
55
190
  .option('--eval <js>', 'Additional JS to eval and save')
56
- .option('--logs-duration <ms>', 'Duration to wait for console errors (ms)', parseInt, 3000)
191
+ .option('--logs-duration <ms>', 'Duration to wait for console errors (ms)', parseIntArg, 3000)
57
192
  .option('--json', 'Output structured manifest');
58
193
  addBridgeOptions(cmd);
59
194
  cmd.action(async (opts) => {
60
195
  const bridge = await resolveBridge(opts);
61
196
  const adapter = await getAdapter();
62
- const outDir = opts.output;
63
- const format = 'png';
64
- const files = {};
65
- // 1. Create output directory
66
- await mkdir(outDir, { recursive: true });
67
- // 2. Inject console error capture
68
- try {
69
- await bridge.eval(INJECT_CONSOLE_ERROR_SCRIPT);
70
- }
71
- catch {
72
- // Non-fatal — continue without error capture
73
- }
74
- // 3. Get page state — save to page-state.json
75
- let capturedUrl;
76
- let capturedTitle;
77
- let capturedViewport;
78
- try {
79
- const raw = await bridge.eval(PAGE_STATE_SCRIPT);
80
- const parsed = PageStateSchema.parse(JSON.parse(String(raw)));
81
- capturedUrl = parsed.url;
82
- capturedTitle = parsed.title;
83
- capturedViewport = parsed.viewport;
84
- const path = join(outDir, 'page-state.json');
85
- await writeFile(path, JSON.stringify(parsed, null, 2));
86
- files['page-state.json'] = path;
87
- }
88
- catch (err) {
89
- files['page-state.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
90
- }
91
- // 4. Screenshot — save to screenshot.png
92
- try {
93
- const windowId = await resolveWindowId(adapter, bridge, opts.title);
94
- let buffer;
95
- if (opts.selector) {
96
- const elementRect = await bridge.getElementRect(opts.selector);
97
- if (!elementRect)
98
- throw new Error(`Element not found: ${opts.selector}`);
99
- const viewport = await bridge.getViewportSize();
100
- const windowGeom = await adapter.getWindowGeometry(windowId);
101
- buffer = await adapter.captureWindow(windowId, format);
102
- const cropRect = computeCropRect(elementRect, viewport, {
103
- width: windowGeom.width,
104
- height: windowGeom.height,
105
- });
106
- buffer = await cropImage(buffer, cropRect, format);
107
- }
108
- else {
109
- buffer = await adapter.captureWindow(windowId, format);
110
- }
111
- const path = join(outDir, 'screenshot.png');
112
- await writeFile(path, buffer);
113
- files['screenshot.png'] = path;
114
- }
115
- catch (err) {
116
- files['screenshot.png'] = `error: ${err instanceof Error ? err.message : String(err)}`;
117
- }
118
- // 5. DOM tree — save to dom.json
119
- try {
120
- const raw = await bridge.eval(buildSerializerScript('body', opts.domDepth, false));
121
- const parsed = DomNodeSchema.parse(JSON.parse(String(raw)));
122
- const path = join(outDir, 'dom.json');
123
- await writeFile(path, JSON.stringify(parsed, null, 2));
124
- files['dom.json'] = path;
125
- }
126
- catch (err) {
127
- files['dom.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
128
- }
129
- // 6. Storage — save to storage.json
130
- try {
131
- const raw = await bridge.eval(STORAGE_SCRIPT);
132
- const parsed = SnapshotStorageResultSchema.parse(JSON.parse(String(raw)));
133
- const path = join(outDir, 'storage.json');
134
- await writeFile(path, JSON.stringify(parsed, null, 2));
135
- files['storage.json'] = path;
136
- }
137
- catch (err) {
138
- files['storage.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
139
- }
140
- // 7. Wait for logs-duration, drain console errors — save to console-errors.json
141
- try {
142
- await new Promise((resolve) => setTimeout(resolve, opts.logsDuration));
143
- const raw = await bridge.eval(DRAIN_CONSOLE_ERRORS_SCRIPT);
144
- const errors = JSON.parse(String(raw));
145
- const path = join(outDir, 'console-errors.json');
146
- await writeFile(path, JSON.stringify(errors, null, 2));
147
- files['console-errors.json'] = path;
148
- }
149
- catch (err) {
150
- files['console-errors.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
151
- }
152
- // 8. Fetch rust logs — save to rust-logs.json
153
- try {
154
- const logs = await bridge.fetchLogs();
155
- const path = join(outDir, 'rust-logs.json');
156
- await writeFile(path, JSON.stringify(logs, null, 2));
157
- files['rust-logs.json'] = path;
158
- }
159
- catch (err) {
160
- files['rust-logs.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
161
- }
162
- // 9. Optional custom eval — save to eval.json
163
- if (opts.eval) {
164
- try {
165
- const raw = await bridge.eval(opts.eval);
166
- const parsed = typeof raw === 'string'
167
- ? (() => { try {
168
- return JSON.parse(raw);
169
- }
170
- catch {
171
- return raw;
172
- } })()
173
- : raw;
174
- const path = join(outDir, 'eval.json');
175
- await writeFile(path, JSON.stringify(parsed, null, 2));
176
- files['eval.json'] = path;
177
- }
178
- catch (err) {
179
- files['eval.json'] = `error: ${err instanceof Error ? err.message : String(err)}`;
180
- }
181
- }
182
- // 10. Write manifest.json
183
- const errorCount = Object.values(files).filter(v => v.startsWith('error: ')).length;
184
- const manifest = {
185
- timestamp: new Date().toISOString(),
186
- url: capturedUrl,
187
- title: capturedTitle,
188
- viewport: capturedViewport,
189
- errorCount,
190
- files,
191
- };
192
- const manifestPath = join(outDir, 'manifest.json');
193
- await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
194
- // 11. Output
195
- if (opts.json) {
196
- console.log(JSON.stringify(manifest, null, 2));
197
- }
198
- else {
199
- console.log(`Capture: ${outDir}`);
200
- console.log(`Time: ${manifest.timestamp}`);
201
- if (capturedUrl)
202
- console.log(`URL: ${capturedUrl}`);
203
- if (capturedTitle)
204
- console.log(`Title: ${capturedTitle}`);
205
- console.log('');
206
- for (const [key, value] of Object.entries(files)) {
207
- const isError = value.startsWith('error: ');
208
- const status = isError ? 'FAIL' : ' OK';
209
- console.log(`[${status}] ${key}: ${value}`);
210
- }
211
- if (errorCount > 0) {
212
- console.log(`\n${errorCount} artifact(s) failed.`);
213
- }
214
- }
197
+ const manifest = await captureToDir(bridge, adapter, opts);
198
+ printCaptureManifest(opts.output, manifest, opts.json);
215
199
  });
216
200
  program.addCommand(cmd);
217
201
  }
202
+ function printCaptureManifest(outDir, manifest, json) {
203
+ if (json) {
204
+ console.log(JSON.stringify(manifest, null, 2));
205
+ return;
206
+ }
207
+ console.log(`Capture: ${outDir}`);
208
+ console.log(`Time: ${manifest.timestamp}`);
209
+ if (manifest.url)
210
+ console.log(`URL: ${manifest.url}`);
211
+ if (manifest.title)
212
+ console.log(`Title: ${manifest.title}`);
213
+ console.log('');
214
+ for (const [key, value] of Object.entries(manifest.files)) {
215
+ const isError = value.startsWith('error: ');
216
+ const status = isError ? 'FAIL' : ' OK';
217
+ console.log(`[${status}] ${key}: ${value}`);
218
+ }
219
+ if ((manifest.errorCount ?? 0) > 0) {
220
+ console.log(`\n${manifest.errorCount} artifact(s) failed.`);
221
+ }
222
+ }
218
223
  //# sourceMappingURL=capture.js.map