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.
- package/.agents/skills/tauri-agent-tools/SKILL.md +59 -14
- package/.agents/skills/tauri-bridge-setup/SKILL.md +10 -4
- package/.agents/skills/tauri-debug-quickstart/SKILL.md +10 -6
- package/AGENTS.md +13 -3
- package/README.md +33 -5
- package/dist/bridge/client.d.ts +21 -0
- package/dist/bridge/client.js +38 -2
- package/dist/bridge/client.js.map +1 -1
- package/dist/bridge/tokenDiscovery.js +5 -2
- package/dist/bridge/tokenDiscovery.js.map +1 -1
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/bundle.d.ts +2 -0
- package/dist/commands/bundle.js +212 -0
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/capabilitiesAudit.js +14 -1
- package/dist/commands/capabilitiesAudit.js.map +1 -1
- package/dist/commands/capture.d.ts +11 -0
- package/dist/commands/capture.js +161 -156
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/check.js +2 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/consoleMonitor.js +3 -3
- package/dist/commands/consoleMonitor.js.map +1 -1
- package/dist/commands/dom.js +2 -2
- package/dist/commands/dom.js.map +1 -1
- package/dist/commands/health.js +19 -1
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/interact/click.js +2 -2
- package/dist/commands/interact/click.js.map +1 -1
- package/dist/commands/interact/scroll.js +3 -3
- package/dist/commands/interact/scroll.js.map +1 -1
- package/dist/commands/ipcMonitor.js +41 -7
- package/dist/commands/ipcMonitor.js.map +1 -1
- package/dist/commands/logs.d.ts +30 -0
- package/dist/commands/logs.js +279 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/mutations.js +3 -3
- package/dist/commands/mutations.js.map +1 -1
- package/dist/commands/probe.js +49 -9
- package/dist/commands/probe.js.map +1 -1
- package/dist/commands/processTree.js +116 -4
- package/dist/commands/processTree.js.map +1 -1
- package/dist/commands/rustLogs.js +3 -3
- package/dist/commands/rustLogs.js.map +1 -1
- package/dist/commands/screenshot.js +2 -2
- package/dist/commands/screenshot.js.map +1 -1
- package/dist/commands/shared.d.ts +37 -0
- package/dist/commands/shared.js +62 -3
- package/dist/commands/shared.js.map +1 -1
- package/dist/commands/sidecarReplay.js +46 -1
- package/dist/commands/sidecarReplay.js.map +1 -1
- package/dist/commands/sidecarTap.js +23 -8
- package/dist/commands/sidecarTap.js.map +1 -1
- package/dist/commands/snapshot.js +2 -2
- package/dist/commands/snapshot.js.map +1 -1
- package/dist/commands/storeInspect.js +2 -2
- package/dist/commands/storeInspect.js.map +1 -1
- package/dist/commands/wait.js +3 -3
- package/dist/commands/wait.js.map +1 -1
- package/dist/commands/webviewAttach.js +17 -1
- package/dist/commands/webviewAttach.js.map +1 -1
- package/dist/platform/macos.js +35 -15
- package/dist/platform/macos.js.map +1 -1
- package/dist/schemas/bridge.d.ts +14 -0
- package/dist/schemas/bridge.js +3 -0
- package/dist/schemas/bridge.js.map +1 -1
- package/dist/util/logMerge.d.ts +42 -0
- package/dist/util/logMerge.js +133 -0
- package/dist/util/logMerge.js.map +1 -0
- package/dist/util/mergeByTimestamp.d.ts +18 -0
- package/dist/util/mergeByTimestamp.js +30 -0
- package/dist/util/mergeByTimestamp.js.map +1 -0
- package/dist/util/psTree.d.ts +28 -0
- package/dist/util/psTree.js +76 -0
- package/dist/util/psTree.js.map +1 -0
- package/dist/util/redactText.d.ts +23 -0
- package/dist/util/redactText.js +377 -0
- package/dist/util/redactText.js.map +1 -0
- package/examples/tauri-bridge/src/dev_bridge.rs +199 -12
- package/package.json +3 -2
- 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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,
|
|
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;
|
package/dist/commands/capture.js
CHANGED
|
@@ -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',
|
|
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)',
|
|
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
|
|
63
|
-
|
|
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
|