tauri-agent-tools 0.5.0 → 0.6.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 +105 -12
- package/.agents/skills/tauri-bridge-setup/SKILL.md +42 -6
- package/AGENTS.md +9 -7
- package/README.md +53 -13
- package/dist/bridge/client.d.ts +5 -2
- package/dist/bridge/client.js +38 -3
- package/dist/bridge/client.js.map +1 -1
- package/dist/cli.js +22 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/capture.d.ts +3 -0
- package/dist/commands/capture.js +218 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/check.d.ts +5 -0
- package/dist/commands/check.js +174 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/diff.js +6 -2
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/eval.js +16 -3
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/interact/click.d.ts +6 -0
- package/dist/commands/interact/click.js +102 -0
- package/dist/commands/interact/click.js.map +1 -0
- package/dist/commands/interact/focus.d.ts +3 -0
- package/dist/commands/interact/focus.js +40 -0
- package/dist/commands/interact/focus.js.map +1 -0
- package/dist/commands/interact/navigate.d.ts +3 -0
- package/dist/commands/interact/navigate.js +49 -0
- package/dist/commands/interact/navigate.js.map +1 -0
- package/dist/commands/interact/scroll.d.ts +11 -0
- package/dist/commands/interact/scroll.js +110 -0
- package/dist/commands/interact/scroll.js.map +1 -0
- package/dist/commands/interact/select.d.ts +3 -0
- package/dist/commands/interact/select.js +59 -0
- package/dist/commands/interact/select.js.map +1 -0
- package/dist/commands/interact/shared.d.ts +23 -0
- package/dist/commands/interact/shared.js +62 -0
- package/dist/commands/interact/shared.js.map +1 -0
- package/dist/commands/interact/type.d.ts +6 -0
- package/dist/commands/interact/type.js +59 -0
- package/dist/commands/interact/type.js.map +1 -0
- package/dist/commands/invoke.d.ts +3 -0
- package/dist/commands/invoke.js +53 -0
- package/dist/commands/invoke.js.map +1 -0
- package/dist/commands/probe.d.ts +2 -0
- package/dist/commands/probe.js +117 -0
- package/dist/commands/probe.js.map +1 -0
- package/dist/commands/shared.d.ts +10 -4
- package/dist/commands/shared.js +23 -3
- package/dist/commands/shared.js.map +1 -1
- package/dist/commands/storeInspect.d.ts +13 -0
- package/dist/commands/storeInspect.js +156 -0
- package/dist/commands/storeInspect.js.map +1 -0
- package/dist/platform/detect.js +65 -37
- package/dist/platform/detect.js.map +1 -1
- package/dist/platform/x11.js +3 -1
- package/dist/platform/x11.js.map +1 -1
- package/dist/schemas/bridge.d.ts +34 -0
- package/dist/schemas/bridge.js +13 -0
- package/dist/schemas/bridge.js.map +1 -1
- package/dist/schemas/commands.d.ts +126 -0
- package/dist/schemas/commands.js +28 -0
- package/dist/schemas/commands.js.map +1 -1
- package/dist/schemas/index.d.ts +3 -2
- package/dist/schemas/index.js +3 -2
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/interact.d.ts +118 -0
- package/dist/schemas/interact.js +31 -0
- package/dist/schemas/interact.js.map +1 -0
- package/dist/util/image.js +5 -2
- package/dist/util/image.js.map +1 -1
- package/dist/util/magick.d.ts +21 -0
- package/dist/util/magick.js +46 -0
- package/dist/util/magick.js.map +1 -0
- package/examples/tauri-bridge/src/dev_bridge.rs +88 -2
- package/package.json +1 -1
- package/rust-bridge/README.md +7 -5
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { addBridgeOptions, resolveBridge } from './shared.js';
|
|
5
|
+
import { buildSerializerScript } from './dom.js';
|
|
6
|
+
import { computeCropRect, cropImage } from '../util/image.js';
|
|
7
|
+
import { DomNodeSchema } from '../schemas/dom.js';
|
|
8
|
+
import { PageStateSchema, SnapshotStorageResultSchema } from '../schemas/commands.js';
|
|
9
|
+
const PAGE_STATE_SCRIPT = `(() => {
|
|
10
|
+
return JSON.stringify({
|
|
11
|
+
url: window.location.href,
|
|
12
|
+
title: document.title,
|
|
13
|
+
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
14
|
+
scroll: { x: Math.round(window.scrollX), y: Math.round(window.scrollY) },
|
|
15
|
+
document: { width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight },
|
|
16
|
+
hasTauri: !!(window.__TAURI__)
|
|
17
|
+
});
|
|
18
|
+
})()`;
|
|
19
|
+
const STORAGE_SCRIPT = `(() => {
|
|
20
|
+
var local = Object.keys(localStorage).map(function(k) { return { key: k, value: localStorage.getItem(k) }; });
|
|
21
|
+
var session = Object.keys(sessionStorage).map(function(k) { return { key: k, value: sessionStorage.getItem(k) }; });
|
|
22
|
+
return JSON.stringify({ localStorage: local, sessionStorage: session });
|
|
23
|
+
})()`;
|
|
24
|
+
const INJECT_CONSOLE_ERROR_SCRIPT = `(() => {
|
|
25
|
+
if (!window.__captureErrors) {
|
|
26
|
+
window.__captureErrors = [];
|
|
27
|
+
const orig = console.error.bind(console);
|
|
28
|
+
console.error = function(...args) {
|
|
29
|
+
window.__captureErrors.push({ ts: Date.now(), msg: args.map(String).join(' ') });
|
|
30
|
+
orig(...args);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return 'ok';
|
|
34
|
+
})()`;
|
|
35
|
+
const DRAIN_CONSOLE_ERRORS_SCRIPT = `(() => {
|
|
36
|
+
var errs = window.__captureErrors || [];
|
|
37
|
+
window.__captureErrors = [];
|
|
38
|
+
return JSON.stringify(errs);
|
|
39
|
+
})()`;
|
|
40
|
+
async function resolveWindowId(adapter, bridge, title) {
|
|
41
|
+
if (title)
|
|
42
|
+
return adapter.findWindow(title);
|
|
43
|
+
const docTitle = await bridge.getDocumentTitle();
|
|
44
|
+
if (!docTitle)
|
|
45
|
+
throw new Error('Could not get window title. Use --title.');
|
|
46
|
+
return adapter.findWindow(docTitle);
|
|
47
|
+
}
|
|
48
|
+
export function registerCapture(program, getAdapter) {
|
|
49
|
+
const cmd = new Command('capture')
|
|
50
|
+
.description('Capture enhanced snapshot with manifest directory (screenshot, DOM, state, logs, errors)')
|
|
51
|
+
.requiredOption('-o, --output <dir>', 'Output directory path')
|
|
52
|
+
.option('-s, --selector <css>', 'CSS selector to screenshot (full window if omitted)')
|
|
53
|
+
.option('-t, --title <regex>', 'Window title to match (default: auto-discover)')
|
|
54
|
+
.option('--dom-depth <number>', 'DOM tree depth', parseInt, 3)
|
|
55
|
+
.option('--eval <js>', 'Additional JS to eval and save')
|
|
56
|
+
.option('--logs-duration <ms>', 'Duration to wait for console errors (ms)', parseInt, 3000)
|
|
57
|
+
.option('--json', 'Output structured manifest');
|
|
58
|
+
addBridgeOptions(cmd);
|
|
59
|
+
cmd.action(async (opts) => {
|
|
60
|
+
const bridge = await resolveBridge(opts);
|
|
61
|
+
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
|
+
}
|
|
215
|
+
});
|
|
216
|
+
program.addCommand(cmd);
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare function buildSelectorCheck(selector: string): string;
|
|
3
|
+
export declare function buildEvalCheck(expression: string): string;
|
|
4
|
+
export declare function buildTextCheck(pattern: string): string;
|
|
5
|
+
export declare function registerCheck(program: Command): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { addBridgeOptions, resolveBridge } from './shared.js';
|
|
3
|
+
const ERROR_PATCH_SCRIPT = `(() => {
|
|
4
|
+
if (window.__tauriDevToolsErrorPatched) return 'already_patched';
|
|
5
|
+
window.__tauriDevToolsOriginalConsoleError = console.error;
|
|
6
|
+
window.__tauriDevToolsErrorBuffer = [];
|
|
7
|
+
console.error = function() {
|
|
8
|
+
var args = Array.prototype.slice.call(arguments);
|
|
9
|
+
var message = args.map(function(a) {
|
|
10
|
+
return typeof a === 'object' ? JSON.stringify(a) : String(a);
|
|
11
|
+
}).join(' ');
|
|
12
|
+
window.__tauriDevToolsErrorBuffer.push(message);
|
|
13
|
+
window.__tauriDevToolsOriginalConsoleError.apply(console, arguments);
|
|
14
|
+
};
|
|
15
|
+
window.__tauriDevToolsErrorPatched = true;
|
|
16
|
+
return 'patched';
|
|
17
|
+
})()`;
|
|
18
|
+
const ERROR_DRAIN_SCRIPT = `(() => {
|
|
19
|
+
var buf = window.__tauriDevToolsErrorBuffer || [];
|
|
20
|
+
window.__tauriDevToolsErrorBuffer = [];
|
|
21
|
+
return JSON.stringify(buf);
|
|
22
|
+
})()`;
|
|
23
|
+
const ERROR_CLEANUP_SCRIPT = `(() => {
|
|
24
|
+
if (window.__tauriDevToolsOriginalConsoleError) {
|
|
25
|
+
console.error = window.__tauriDevToolsOriginalConsoleError;
|
|
26
|
+
delete window.__tauriDevToolsOriginalConsoleError;
|
|
27
|
+
delete window.__tauriDevToolsErrorBuffer;
|
|
28
|
+
delete window.__tauriDevToolsErrorPatched;
|
|
29
|
+
}
|
|
30
|
+
return 'cleaned';
|
|
31
|
+
})()`;
|
|
32
|
+
export function buildSelectorCheck(selector) {
|
|
33
|
+
const escaped = selector.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
34
|
+
return `!!document.querySelector('${escaped}')`;
|
|
35
|
+
}
|
|
36
|
+
export function buildEvalCheck(expression) {
|
|
37
|
+
return `!!(${expression})`;
|
|
38
|
+
}
|
|
39
|
+
export function buildTextCheck(pattern) {
|
|
40
|
+
const escaped = pattern.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
41
|
+
return `document.body.textContent.includes('${escaped}')`;
|
|
42
|
+
}
|
|
43
|
+
export function registerCheck(program) {
|
|
44
|
+
const cmd = new Command('check')
|
|
45
|
+
.description('Run structured assertions against the Tauri app and exit nonzero on failure')
|
|
46
|
+
.option('--selector <css>', 'Assert that a CSS selector matches an element')
|
|
47
|
+
.option('--eval <js>', 'Assert that a JavaScript expression is truthy')
|
|
48
|
+
.option('--text <pattern>', 'Assert that body text contains the pattern')
|
|
49
|
+
.option('--no-errors', 'Assert that no console.error calls occurred during --duration')
|
|
50
|
+
.option('--duration <ms>', 'Duration to wait for --no-errors check (ms)', parseInt, 3000)
|
|
51
|
+
.option('--json', 'Output results as JSON');
|
|
52
|
+
addBridgeOptions(cmd);
|
|
53
|
+
cmd.action(async (opts) => {
|
|
54
|
+
const bridge = await resolveBridge(opts);
|
|
55
|
+
const checks = [];
|
|
56
|
+
// Selector check
|
|
57
|
+
if (opts.selector !== undefined) {
|
|
58
|
+
try {
|
|
59
|
+
const js = buildSelectorCheck(opts.selector);
|
|
60
|
+
const result = await bridge.eval(js);
|
|
61
|
+
checks.push({
|
|
62
|
+
type: 'selector',
|
|
63
|
+
passed: result === true || result === 'true',
|
|
64
|
+
selector: opts.selector,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
checks.push({
|
|
69
|
+
type: 'selector',
|
|
70
|
+
passed: false,
|
|
71
|
+
selector: opts.selector,
|
|
72
|
+
error: err instanceof Error ? err.message : String(err),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Eval check
|
|
77
|
+
if (opts.eval !== undefined) {
|
|
78
|
+
try {
|
|
79
|
+
const js = buildEvalCheck(opts.eval);
|
|
80
|
+
const result = await bridge.eval(js);
|
|
81
|
+
checks.push({
|
|
82
|
+
type: 'eval',
|
|
83
|
+
passed: result === true || result === 'true',
|
|
84
|
+
expression: opts.eval,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
checks.push({
|
|
89
|
+
type: 'eval',
|
|
90
|
+
passed: false,
|
|
91
|
+
expression: opts.eval,
|
|
92
|
+
error: err instanceof Error ? err.message : String(err),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Text check
|
|
97
|
+
if (opts.text !== undefined) {
|
|
98
|
+
try {
|
|
99
|
+
const js = buildTextCheck(opts.text);
|
|
100
|
+
const result = await bridge.eval(js);
|
|
101
|
+
checks.push({
|
|
102
|
+
type: 'text',
|
|
103
|
+
passed: result === true || result === 'true',
|
|
104
|
+
pattern: opts.text,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
checks.push({
|
|
109
|
+
type: 'text',
|
|
110
|
+
passed: false,
|
|
111
|
+
pattern: opts.text,
|
|
112
|
+
error: err instanceof Error ? err.message : String(err),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// No-errors check (opts.errors === false when --no-errors is passed)
|
|
117
|
+
if (opts.errors === false) {
|
|
118
|
+
try {
|
|
119
|
+
await bridge.eval(ERROR_PATCH_SCRIPT);
|
|
120
|
+
await new Promise((resolve) => setTimeout(resolve, opts.duration));
|
|
121
|
+
const raw = await bridge.eval(ERROR_DRAIN_SCRIPT);
|
|
122
|
+
await bridge.eval(ERROR_CLEANUP_SCRIPT).catch(() => {
|
|
123
|
+
// Best-effort cleanup
|
|
124
|
+
});
|
|
125
|
+
const errors = JSON.parse(String(raw));
|
|
126
|
+
checks.push({
|
|
127
|
+
type: 'no-errors',
|
|
128
|
+
passed: errors.length === 0,
|
|
129
|
+
errors,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
checks.push({
|
|
134
|
+
type: 'no-errors',
|
|
135
|
+
passed: false,
|
|
136
|
+
errors: [],
|
|
137
|
+
error: err instanceof Error ? err.message : String(err),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const passed = checks.every((c) => c.passed);
|
|
142
|
+
if (opts.json) {
|
|
143
|
+
console.log(JSON.stringify({ passed, checks }));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
for (const check of checks) {
|
|
147
|
+
const status = check.passed ? '[PASS]' : '[FAIL]';
|
|
148
|
+
if (check.type === 'selector') {
|
|
149
|
+
console.log(`${status} selector: ${check.selector ?? ''}`);
|
|
150
|
+
}
|
|
151
|
+
else if (check.type === 'eval') {
|
|
152
|
+
console.log(`${status} eval: ${check.expression ?? ''}`);
|
|
153
|
+
}
|
|
154
|
+
else if (check.type === 'text') {
|
|
155
|
+
console.log(`${status} text: ${check.pattern ?? ''}`);
|
|
156
|
+
}
|
|
157
|
+
else if (check.type === 'no-errors') {
|
|
158
|
+
const detail = !check.passed && check.errors && check.errors.length > 0
|
|
159
|
+
? ` (${check.errors.length} error(s))`
|
|
160
|
+
: '';
|
|
161
|
+
console.log(`${status} no-errors${detail}`);
|
|
162
|
+
}
|
|
163
|
+
if (!check.passed && check.error) {
|
|
164
|
+
console.error(` error: ${check.error}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (!passed) {
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
program.addCommand(cmd);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/diff.js
CHANGED
|
@@ -2,6 +2,7 @@ import { stat } from 'node:fs/promises';
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { exec } from '../util/exec.js';
|
|
5
|
+
import { magickCommand } from '../util/magick.js';
|
|
5
6
|
function formatResult(result) {
|
|
6
7
|
const lines = [
|
|
7
8
|
`Pixels different: ${result.pixelsDifferent}`,
|
|
@@ -34,7 +35,8 @@ export function registerDiff(program) {
|
|
|
34
35
|
// Get image dimensions for total pixel count
|
|
35
36
|
let totalPixels = 0;
|
|
36
37
|
try {
|
|
37
|
-
const
|
|
38
|
+
const identifyCmd = await magickCommand('identify');
|
|
39
|
+
const { stdout } = await exec(identifyCmd.bin, [...identifyCmd.args, '-format', '%w %h', image1]);
|
|
38
40
|
const [w, h] = z.tuple([z.number().int().positive(), z.number().int().positive()]).parse(stdout.toString().trim().split(' ').map(Number));
|
|
39
41
|
totalPixels = w * h;
|
|
40
42
|
}
|
|
@@ -48,7 +50,9 @@ export function registerDiff(program) {
|
|
|
48
50
|
let pixelsDifferent = 0;
|
|
49
51
|
try {
|
|
50
52
|
// compare exits with code 1 when images differ (not an error)
|
|
51
|
-
const
|
|
53
|
+
const compareCmd = await magickCommand('compare');
|
|
54
|
+
const { stderr } = await exec(compareCmd.bin, [
|
|
55
|
+
...compareCmd.args,
|
|
52
56
|
'-metric', 'AE',
|
|
53
57
|
image1,
|
|
54
58
|
image2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/eval.js
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import { Command } from 'commander';
|
|
2
3
|
import { addBridgeOptions, resolveBridge } from './shared.js';
|
|
3
4
|
export function registerEval(program) {
|
|
4
5
|
const cmd = new Command('eval')
|
|
5
6
|
.description('Evaluate a JavaScript expression in the Tauri app')
|
|
6
|
-
.argument('
|
|
7
|
+
.argument('[expression]', 'JavaScript expression to evaluate')
|
|
8
|
+
.option('--file <path>', 'Read JavaScript from a file instead of argument')
|
|
7
9
|
.addHelpText('after', `
|
|
8
10
|
Examples:
|
|
9
11
|
$ tauri-agent-tools eval "document.title"
|
|
10
12
|
$ tauri-agent-tools eval "window.location.href"
|
|
11
|
-
$ tauri-agent-tools eval "document.querySelectorAll('button').length"
|
|
13
|
+
$ tauri-agent-tools eval "document.querySelectorAll('button').length"
|
|
14
|
+
$ tauri-agent-tools eval --file script.js`);
|
|
12
15
|
addBridgeOptions(cmd);
|
|
13
16
|
cmd.action(async (expression, opts) => {
|
|
17
|
+
let js;
|
|
18
|
+
if (opts.file) {
|
|
19
|
+
js = await readFile(opts.file, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
else if (expression) {
|
|
22
|
+
js = expression;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
throw new Error('Provide either an <expression> argument or --file <path>');
|
|
26
|
+
}
|
|
14
27
|
const bridge = await resolveBridge(opts);
|
|
15
|
-
const result = await bridge.eval(
|
|
28
|
+
const result = await bridge.eval(js);
|
|
16
29
|
if (typeof result === 'string') {
|
|
17
30
|
// Try to pretty-print if it's JSON
|
|
18
31
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/commands/eval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/commands/eval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG9D,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;SAC5B,WAAW,CAAC,mDAAmD,CAAC;SAChE,QAAQ,CAAC,cAAc,EAAE,mCAAmC,CAAC;SAC7D,MAAM,CAAC,eAAe,EAAE,iDAAiD,CAAC;SAC1E,WAAW,CAAC,OAAO,EAAE;;;;;4CAKkB,CAAC,CAAC;IAE5C,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAEtB,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAA8B,EAAE,IAAoC,EAAE,EAAE;QACxF,IAAI,EAAU,CAAC;QAEf,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,UAAU,EAAE,CAAC;YACtB,EAAE,GAAG,UAAU,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAErC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,mCAAmC;YACnC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { resolveBridge } from '../shared.js';
|
|
3
|
+
import { addInteractOptions, escapeSelector } from './shared.js';
|
|
4
|
+
import { ClickResultSchema } from '../../schemas/interact.js';
|
|
5
|
+
export function buildClickScript(selector, opts) {
|
|
6
|
+
const escaped = escapeSelector(selector);
|
|
7
|
+
const button = opts.right ? 2 : 0;
|
|
8
|
+
return `(() => {
|
|
9
|
+
var el = document.querySelector('${escaped}');
|
|
10
|
+
if (!el) return JSON.stringify({ success: false, selector: '${escaped}', error: 'Element not found' });
|
|
11
|
+
var r = el.getBoundingClientRect();
|
|
12
|
+
var clientX = r.left + r.width / 2;
|
|
13
|
+
var clientY = r.top + r.height / 2;
|
|
14
|
+
var eventOpts = { bubbles: true, cancelable: true, clientX: clientX, clientY: clientY, button: ${button} };
|
|
15
|
+
el.dispatchEvent(new MouseEvent('mousedown', eventOpts));
|
|
16
|
+
el.dispatchEvent(new MouseEvent('mouseup', eventOpts));
|
|
17
|
+
${opts.right
|
|
18
|
+
? `el.dispatchEvent(new MouseEvent('contextmenu', eventOpts));`
|
|
19
|
+
: opts.double
|
|
20
|
+
? `el.dispatchEvent(new MouseEvent('click', eventOpts));
|
|
21
|
+
el.dispatchEvent(new MouseEvent('dblclick', eventOpts));`
|
|
22
|
+
: `el.dispatchEvent(new MouseEvent('click', eventOpts));`}
|
|
23
|
+
var text = (el.textContent || '').trim().slice(0, 100);
|
|
24
|
+
return JSON.stringify({ success: true, selector: '${escaped}', tagName: el.tagName.toLowerCase(), text: text });
|
|
25
|
+
})()`;
|
|
26
|
+
}
|
|
27
|
+
function buildWaitAndClickScript(selector, opts, waitMs) {
|
|
28
|
+
const escaped = escapeSelector(selector);
|
|
29
|
+
const button = opts.right ? 2 : 0;
|
|
30
|
+
const clickEvents = opts.right
|
|
31
|
+
? `el.dispatchEvent(new MouseEvent('contextmenu', eventOpts));`
|
|
32
|
+
: opts.double
|
|
33
|
+
? `el.dispatchEvent(new MouseEvent('click', eventOpts));
|
|
34
|
+
el.dispatchEvent(new MouseEvent('dblclick', eventOpts));`
|
|
35
|
+
: `el.dispatchEvent(new MouseEvent('click', eventOpts));`;
|
|
36
|
+
return `(() => {
|
|
37
|
+
var deadline = Date.now() + ${waitMs};
|
|
38
|
+
function attempt() {
|
|
39
|
+
var el = document.querySelector('${escaped}');
|
|
40
|
+
if (el) {
|
|
41
|
+
var r = el.getBoundingClientRect();
|
|
42
|
+
var clientX = r.left + r.width / 2;
|
|
43
|
+
var clientY = r.top + r.height / 2;
|
|
44
|
+
var eventOpts = { bubbles: true, cancelable: true, clientX: clientX, clientY: clientY, button: ${button} };
|
|
45
|
+
el.dispatchEvent(new MouseEvent('mousedown', eventOpts));
|
|
46
|
+
el.dispatchEvent(new MouseEvent('mouseup', eventOpts));
|
|
47
|
+
${clickEvents}
|
|
48
|
+
var text = (el.textContent || '').trim().slice(0, 100);
|
|
49
|
+
return JSON.stringify({ success: true, selector: '${escaped}', tagName: el.tagName.toLowerCase(), text: text });
|
|
50
|
+
}
|
|
51
|
+
if (Date.now() >= deadline) {
|
|
52
|
+
return JSON.stringify({ success: false, selector: '${escaped}', error: 'Element not found' });
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return new Promise(function(resolve) {
|
|
57
|
+
function poll() {
|
|
58
|
+
var result = attempt();
|
|
59
|
+
if (result !== null) { resolve(result); return; }
|
|
60
|
+
setTimeout(poll, 100);
|
|
61
|
+
}
|
|
62
|
+
poll();
|
|
63
|
+
});
|
|
64
|
+
})()`;
|
|
65
|
+
}
|
|
66
|
+
export function registerClick(program) {
|
|
67
|
+
const cmd = new Command('click')
|
|
68
|
+
.description('Dispatch mouse click events on a DOM element')
|
|
69
|
+
.argument('<selector>', 'CSS selector of the element to click')
|
|
70
|
+
.option('--double', 'Dispatch a double-click (dblclick) instead of a single click')
|
|
71
|
+
.option('--right', 'Dispatch a right-click (contextmenu) instead of a left click')
|
|
72
|
+
.option('--wait <ms>', 'Wait up to <ms> milliseconds for element to appear', parseInt, 0)
|
|
73
|
+
.addHelpText('after', `
|
|
74
|
+
Examples:
|
|
75
|
+
$ tauri-agent-tools click "button.submit"
|
|
76
|
+
$ tauri-agent-tools click "#menu-toggle" --double
|
|
77
|
+
$ tauri-agent-tools click ".context-target" --right
|
|
78
|
+
$ tauri-agent-tools click ".lazy-item" --wait 3000 --json`);
|
|
79
|
+
addInteractOptions(cmd);
|
|
80
|
+
cmd.action(async (selector, opts) => {
|
|
81
|
+
const bridge = await resolveBridge(opts);
|
|
82
|
+
const clickOpts = { double: !!opts.double, right: !!opts.right };
|
|
83
|
+
const script = opts.wait > 0
|
|
84
|
+
? buildWaitAndClickScript(selector, clickOpts, opts.wait)
|
|
85
|
+
: buildClickScript(selector, clickOpts);
|
|
86
|
+
const raw = await bridge.eval(script);
|
|
87
|
+
const result = ClickResultSchema.parse(JSON.parse(String(raw)));
|
|
88
|
+
if (!result.success) {
|
|
89
|
+
throw new Error(`Click failed: ${result.error} (selector: ${result.selector})`);
|
|
90
|
+
}
|
|
91
|
+
if (opts.json) {
|
|
92
|
+
console.log(JSON.stringify(result, null, 2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const actionLabel = opts.right ? 'right-clicked' : opts.double ? 'double-clicked' : 'clicked';
|
|
96
|
+
const textHint = result.text ? ` "${result.text.slice(0, 40)}"` : '';
|
|
97
|
+
console.log(`${actionLabel} <${result.tagName}${textHint}> (${result.selector})`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
program.addCommand(cmd);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=click.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click.js","sourceRoot":"","sources":["../../../src/commands/interact/click.ts"],"names":[],"mappings":"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"}
|