tauri-agent-tools 0.5.1 → 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.
Files changed (65) hide show
  1. package/.agents/skills/tauri-agent-tools/SKILL.md +105 -12
  2. package/.agents/skills/tauri-bridge-setup/SKILL.md +42 -6
  3. package/AGENTS.md +9 -7
  4. package/README.md +51 -11
  5. package/dist/bridge/client.d.ts +5 -2
  6. package/dist/bridge/client.js +38 -3
  7. package/dist/bridge/client.js.map +1 -1
  8. package/dist/cli.js +22 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/capture.d.ts +3 -0
  11. package/dist/commands/capture.js +218 -0
  12. package/dist/commands/capture.js.map +1 -0
  13. package/dist/commands/check.d.ts +5 -0
  14. package/dist/commands/check.js +174 -0
  15. package/dist/commands/check.js.map +1 -0
  16. package/dist/commands/eval.js +16 -3
  17. package/dist/commands/eval.js.map +1 -1
  18. package/dist/commands/interact/click.d.ts +6 -0
  19. package/dist/commands/interact/click.js +102 -0
  20. package/dist/commands/interact/click.js.map +1 -0
  21. package/dist/commands/interact/focus.d.ts +3 -0
  22. package/dist/commands/interact/focus.js +40 -0
  23. package/dist/commands/interact/focus.js.map +1 -0
  24. package/dist/commands/interact/navigate.d.ts +3 -0
  25. package/dist/commands/interact/navigate.js +49 -0
  26. package/dist/commands/interact/navigate.js.map +1 -0
  27. package/dist/commands/interact/scroll.d.ts +11 -0
  28. package/dist/commands/interact/scroll.js +110 -0
  29. package/dist/commands/interact/scroll.js.map +1 -0
  30. package/dist/commands/interact/select.d.ts +3 -0
  31. package/dist/commands/interact/select.js +59 -0
  32. package/dist/commands/interact/select.js.map +1 -0
  33. package/dist/commands/interact/shared.d.ts +23 -0
  34. package/dist/commands/interact/shared.js +62 -0
  35. package/dist/commands/interact/shared.js.map +1 -0
  36. package/dist/commands/interact/type.d.ts +6 -0
  37. package/dist/commands/interact/type.js +59 -0
  38. package/dist/commands/interact/type.js.map +1 -0
  39. package/dist/commands/invoke.d.ts +3 -0
  40. package/dist/commands/invoke.js +53 -0
  41. package/dist/commands/invoke.js.map +1 -0
  42. package/dist/commands/probe.d.ts +2 -0
  43. package/dist/commands/probe.js +117 -0
  44. package/dist/commands/probe.js.map +1 -0
  45. package/dist/commands/shared.d.ts +10 -4
  46. package/dist/commands/shared.js +23 -3
  47. package/dist/commands/shared.js.map +1 -1
  48. package/dist/commands/storeInspect.d.ts +13 -0
  49. package/dist/commands/storeInspect.js +156 -0
  50. package/dist/commands/storeInspect.js.map +1 -0
  51. package/dist/schemas/bridge.d.ts +34 -0
  52. package/dist/schemas/bridge.js +13 -0
  53. package/dist/schemas/bridge.js.map +1 -1
  54. package/dist/schemas/commands.d.ts +126 -0
  55. package/dist/schemas/commands.js +28 -0
  56. package/dist/schemas/commands.js.map +1 -1
  57. package/dist/schemas/index.d.ts +3 -2
  58. package/dist/schemas/index.js +3 -2
  59. package/dist/schemas/index.js.map +1 -1
  60. package/dist/schemas/interact.d.ts +118 -0
  61. package/dist/schemas/interact.js +31 -0
  62. package/dist/schemas/interact.js.map +1 -0
  63. package/examples/tauri-bridge/src/dev_bridge.rs +88 -2
  64. package/package.json +1 -1
  65. package/rust-bridge/README.md +7 -5
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ // === Interaction Results ===
3
+ export const InteractionResultSchema = z.object({
4
+ success: z.boolean(),
5
+ selector: z.string().optional(),
6
+ tagName: z.string().optional(),
7
+ error: z.string().optional(),
8
+ });
9
+ export const ClickResultSchema = InteractionResultSchema.extend({
10
+ text: z.string().optional(),
11
+ });
12
+ export const TypeResultSchema = InteractionResultSchema.extend({
13
+ value: z.string().optional(),
14
+ });
15
+ export const ScrollResultSchema = z.object({
16
+ success: z.boolean(),
17
+ scrollX: z.number().optional(),
18
+ scrollY: z.number().optional(),
19
+ error: z.string().optional(),
20
+ });
21
+ export const SelectResultSchema = InteractionResultSchema.extend({
22
+ value: z.string().optional(),
23
+ checked: z.boolean().optional(),
24
+ });
25
+ export const InvokeResultSchema = z.object({
26
+ success: z.boolean(),
27
+ command: z.string(),
28
+ result: z.unknown().optional(),
29
+ error: z.string().optional(),
30
+ });
31
+ //# sourceMappingURL=interact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interact.js","sourceRoot":"","sources":["../../src/schemas/interact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8BAA8B;AAE9B,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAC9D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAC7D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAC/D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC"}
@@ -15,6 +15,8 @@ use tracing_subscriber::util::SubscriberInitExt;
15
15
  struct EvalRequest {
16
16
  js: String,
17
17
  token: String,
18
+ #[serde(default)]
19
+ window: Option<String>,
18
20
  }
19
21
 
20
22
  #[derive(Deserialize)]
@@ -41,6 +43,32 @@ struct LogResponse {
41
43
  entries: Vec<LogEntry>,
42
44
  }
43
45
 
46
+ #[derive(Deserialize)]
47
+ struct DescribeRequest {
48
+ token: String,
49
+ }
50
+
51
+ #[derive(Serialize, Default)]
52
+ struct DescribeResponse {
53
+ #[serde(skip_serializing_if = "Option::is_none")]
54
+ app: Option<String>,
55
+ #[serde(skip_serializing_if = "Option::is_none")]
56
+ pid: Option<u32>,
57
+ #[serde(skip_serializing_if = "Option::is_none")]
58
+ windows: Option<Vec<String>>,
59
+ capabilities: Vec<String>,
60
+ #[serde(skip_serializing_if = "Option::is_none")]
61
+ surfaces: Option<HashMap<String, String>>,
62
+ #[serde(skip_serializing_if = "Option::is_none")]
63
+ exports: Option<HashMap<String, String>>,
64
+ }
65
+
66
+ #[derive(Serialize)]
67
+ struct VersionResponse {
68
+ version: String,
69
+ endpoints: Vec<String>,
70
+ }
71
+
44
72
  #[derive(Serialize)]
45
73
  struct TokenFile {
46
74
  port: u16,
@@ -295,7 +323,24 @@ pub fn start_bridge(app: &AppHandle) -> Result<(u16, Arc<LogBuffer>), String> {
295
323
  let is_post = request.method().as_str() == "POST";
296
324
  let url = request.url().to_string();
297
325
 
298
- if !is_post || (url != "/eval" && url != "/logs") {
326
+ // Handle GET /version (no auth needed)
327
+ if url == "/version" && request.method().as_str() == "GET" {
328
+ let resp = VersionResponse {
329
+ version: "0.6.0".to_string(),
330
+ endpoints: vec![
331
+ "/eval".to_string(),
332
+ "/logs".to_string(),
333
+ "/describe".to_string(),
334
+ "/version".to_string(),
335
+ ],
336
+ };
337
+ let json = serde_json::to_string(&resp).unwrap();
338
+ let header = Header::from_bytes("Content-Type", "application/json").unwrap();
339
+ let _ = request.respond(Response::from_string(json).with_header(header));
340
+ continue;
341
+ }
342
+
343
+ if !is_post || (url != "/eval" && url != "/logs" && url != "/describe") {
299
344
  let _ = request.respond(Response::from_string("Not found").with_status_code(404));
300
345
  continue;
301
346
  }
@@ -333,6 +378,46 @@ pub fn start_bridge(app: &AppHandle) -> Result<(u16, Arc<LogBuffer>), String> {
333
378
  continue;
334
379
  }
335
380
 
381
+ // Handle /describe endpoint
382
+ if url == "/describe" {
383
+ let desc_req: DescribeRequest = match serde_json::from_str(&body) {
384
+ Ok(r) => r,
385
+ Err(_) => {
386
+ let _ = request
387
+ .respond(Response::from_string("Invalid JSON").with_status_code(400));
388
+ continue;
389
+ }
390
+ };
391
+
392
+ if desc_req.token != expected_token {
393
+ let _ = request
394
+ .respond(Response::from_string("Unauthorized").with_status_code(401));
395
+ continue;
396
+ }
397
+
398
+ let windows: Vec<String> = app_handle
399
+ .webview_windows()
400
+ .keys()
401
+ .cloned()
402
+ .collect();
403
+
404
+ let resp = DescribeResponse {
405
+ pid: Some(std::process::id()),
406
+ windows: Some(windows),
407
+ capabilities: vec![
408
+ "eval".to_string(),
409
+ "logs".to_string(),
410
+ "describe".to_string(),
411
+ ],
412
+ ..Default::default()
413
+ };
414
+
415
+ let json = serde_json::to_string(&resp).unwrap();
416
+ let header = Header::from_bytes("Content-Type", "application/json").unwrap();
417
+ let _ = request.respond(Response::from_string(json).with_header(header));
418
+ continue;
419
+ }
420
+
336
421
  // Handle /eval endpoint
337
422
  let eval_req: EvalRequest = match serde_json::from_str(&body) {
338
423
  Ok(r) => r,
@@ -353,7 +438,8 @@ pub fn start_bridge(app: &AppHandle) -> Result<(u16, Arc<LogBuffer>), String> {
353
438
  // Evaluate JS in webview via callback pattern
354
439
  let request_id = uuid::Uuid::new_v4().to_string();
355
440
 
356
- if let Some(window) = app_handle.get_webview_window("main") {
441
+ let window_label = eval_req.window.as_deref().unwrap_or("main");
442
+ if let Some(window) = app_handle.get_webview_window(window_label) {
357
443
  // Build JS that evaluates the expression, then calls back into Rust
358
444
  // via __TAURI__.core.invoke() to deliver the result.
359
445
  let callback_js = format!(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-agent-tools",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Agent-driven inspection toolkit for Tauri desktop apps",
5
5
  "type": "module",
6
6
  "bin": {
@@ -82,19 +82,21 @@ tauri-agent-tools eval "document.title"
82
82
  1. Bridge starts an HTTP server on a random localhost port
83
83
  2. A token file with `{ port, token, pid }` is written to `/tmp/`
84
84
  3. `tauri-agent-tools` discovers the token file and authenticates via the token
85
- 4. Requests are `POST /eval { js, token }` (JS evaluation) or `POST /logs { token }` (Rust log retrieval)
86
- 5. For `/eval`, the bridge injects JS into the webview
85
+ 4. The bridge exposes four endpoints: `POST /eval` (JS evaluation), `POST /logs` (Rust log retrieval), `POST /describe` (bridge metadata), and `GET /version` (unauthenticated health check)
86
+ 5. `/eval` accepts an optional `window` field to target specific webview windows (defaults to `"main"`)
87
87
  6. The injected JS evaluates the expression, then calls back into Rust via `window.__TAURI__.core.invoke("__dev_bridge_result", { id, value })` to deliver the result
88
88
  7. The HTTP handler thread waits for the result (up to 5 seconds) and returns it as JSON
89
- 8. For `/logs`, the bridge drains its ring buffer of captured `tracing` events and returns them as JSON
90
- 9. The token file is cleaned up when the app exits
89
+ 8. `/logs` drains the ring buffer of captured `tracing` events and returns them as JSON
90
+ 9. `/describe` returns PID, window labels, and capabilities
91
+ 10. The token file is cleaned up when the app exits
91
92
 
92
93
  ## Security
93
94
 
94
95
  - **Localhost only** — the bridge binds to `127.0.0.1`
95
96
  - **Token authenticated** — every request requires a random 32-char token
96
97
  - **Development only** — wrapped in `cfg!(debug_assertions)`, stripped in release builds
97
- - **Read-only** — `tauri-agent-tools` only reads DOM state, never injects input
98
+ - **Inspection is read-only** — inspection commands only read DOM state
99
+ - **Interaction is debug-only** — interaction commands use eval-based DOM dispatch, sandboxed to the webview
98
100
 
99
101
  ## Agent-Assisted Setup
100
102