@ytspar/sweetlink 1.13.0 → 1.15.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 (100) hide show
  1. package/README.md +294 -40
  2. package/claude-skills/screenshot/SKILL.md +141 -20
  3. package/dist/cli/outputSchemas.d.ts +16 -0
  4. package/dist/cli/outputSchemas.d.ts.map +1 -1
  5. package/dist/cli/outputSchemas.js +33 -0
  6. package/dist/cli/outputSchemas.js.map +1 -1
  7. package/dist/cli/sweetlink-dev.js +0 -0
  8. package/dist/cli/sweetlink.js +639 -11
  9. package/dist/cli/sweetlink.js.map +1 -1
  10. package/dist/daemon/browser.d.ts +58 -0
  11. package/dist/daemon/browser.d.ts.map +1 -0
  12. package/dist/daemon/browser.js +172 -0
  13. package/dist/daemon/browser.js.map +1 -0
  14. package/dist/daemon/client.d.ts +34 -0
  15. package/dist/daemon/client.d.ts.map +1 -0
  16. package/dist/daemon/client.js +139 -0
  17. package/dist/daemon/client.js.map +1 -0
  18. package/dist/daemon/cursor.d.ts +15 -0
  19. package/dist/daemon/cursor.d.ts.map +1 -0
  20. package/dist/daemon/cursor.js +76 -0
  21. package/dist/daemon/cursor.js.map +1 -0
  22. package/dist/daemon/demo.d.ts +68 -0
  23. package/dist/daemon/demo.d.ts.map +1 -0
  24. package/dist/daemon/demo.js +247 -0
  25. package/dist/daemon/demo.js.map +1 -0
  26. package/dist/daemon/devices.d.ts +39 -0
  27. package/dist/daemon/devices.d.ts.map +1 -0
  28. package/dist/daemon/devices.js +101 -0
  29. package/dist/daemon/devices.js.map +1 -0
  30. package/dist/daemon/diff.d.ts +20 -0
  31. package/dist/daemon/diff.d.ts.map +1 -0
  32. package/dist/daemon/diff.js +181 -0
  33. package/dist/daemon/diff.js.map +1 -0
  34. package/dist/daemon/errorPatterns.d.ts +17 -0
  35. package/dist/daemon/errorPatterns.d.ts.map +1 -0
  36. package/dist/daemon/errorPatterns.js +81 -0
  37. package/dist/daemon/errorPatterns.js.map +1 -0
  38. package/dist/daemon/evidence.d.ts +29 -0
  39. package/dist/daemon/evidence.d.ts.map +1 -0
  40. package/dist/daemon/evidence.js +131 -0
  41. package/dist/daemon/evidence.js.map +1 -0
  42. package/dist/daemon/index.d.ts +10 -0
  43. package/dist/daemon/index.d.ts.map +1 -0
  44. package/dist/daemon/index.js +102 -0
  45. package/dist/daemon/index.js.map +1 -0
  46. package/dist/daemon/listeners.d.ts +55 -0
  47. package/dist/daemon/listeners.d.ts.map +1 -0
  48. package/dist/daemon/listeners.js +129 -0
  49. package/dist/daemon/listeners.js.map +1 -0
  50. package/dist/daemon/recording.d.ts +54 -0
  51. package/dist/daemon/recording.d.ts.map +1 -0
  52. package/dist/daemon/recording.js +216 -0
  53. package/dist/daemon/recording.js.map +1 -0
  54. package/dist/daemon/refs.d.ts +70 -0
  55. package/dist/daemon/refs.d.ts.map +1 -0
  56. package/dist/daemon/refs.js +185 -0
  57. package/dist/daemon/refs.js.map +1 -0
  58. package/dist/daemon/ringBuffer.d.ts +26 -0
  59. package/dist/daemon/ringBuffer.d.ts.map +1 -0
  60. package/dist/daemon/ringBuffer.js +54 -0
  61. package/dist/daemon/ringBuffer.js.map +1 -0
  62. package/dist/daemon/server.d.ts +23 -0
  63. package/dist/daemon/server.d.ts.map +1 -0
  64. package/dist/daemon/server.js +585 -0
  65. package/dist/daemon/server.js.map +1 -0
  66. package/dist/daemon/session.d.ts +47 -0
  67. package/dist/daemon/session.d.ts.map +1 -0
  68. package/dist/daemon/session.js +8 -0
  69. package/dist/daemon/session.js.map +1 -0
  70. package/dist/daemon/stateFile.d.ts +56 -0
  71. package/dist/daemon/stateFile.d.ts.map +1 -0
  72. package/dist/daemon/stateFile.js +178 -0
  73. package/dist/daemon/stateFile.js.map +1 -0
  74. package/dist/daemon/summary.d.ts +28 -0
  75. package/dist/daemon/summary.d.ts.map +1 -0
  76. package/dist/daemon/summary.js +152 -0
  77. package/dist/daemon/summary.js.map +1 -0
  78. package/dist/daemon/types.d.ts +72 -0
  79. package/dist/daemon/types.d.ts.map +1 -0
  80. package/dist/daemon/types.js +28 -0
  81. package/dist/daemon/types.js.map +1 -0
  82. package/dist/daemon/viewer.d.ts +24 -0
  83. package/dist/daemon/viewer.d.ts.map +1 -0
  84. package/dist/daemon/viewer.js +567 -0
  85. package/dist/daemon/viewer.js.map +1 -0
  86. package/dist/daemon/visualDiff.d.ts +34 -0
  87. package/dist/daemon/visualDiff.d.ts.map +1 -0
  88. package/dist/daemon/visualDiff.js +80 -0
  89. package/dist/daemon/visualDiff.js.map +1 -0
  90. package/dist/server/index.d.ts.map +1 -1
  91. package/dist/server/index.js +173 -0
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/types.d.ts +19 -1
  94. package/dist/types.d.ts.map +1 -1
  95. package/dist/types.js.map +1 -1
  96. package/dist/vite.d.ts +12 -0
  97. package/dist/vite.d.ts.map +1 -1
  98. package/dist/vite.js +13 -0
  99. package/dist/vite.js.map +1 -1
  100. package/package.json +20 -12
package/README.md CHANGED
@@ -24,6 +24,12 @@ Sweetlink enables Claude AI agents to autonomously debug, test, and iterate on w
24
24
  - **🎯 Token Efficient** - ~1000 tokens/screenshot vs ~5000 for MCP tools
25
25
  - **📝 LLM-Optimized Output** - Summary format with deduplication for context efficiency
26
26
  - **🚀 Zero Setup** - Works immediately with any web app
27
+ - **🖥️ Persistent Daemon** - Playwright daemon stays alive between commands (~150ms screenshots)
28
+ - **🏷️ @Ref System** - Accessibility tree refs for click/fill without CSS selectors
29
+ - **📊 Ring Buffers** - Always-on console/network/dialog capture (50K entries)
30
+ - **🎬 Session Recording** - Record actions with screenshots, generate interactive viewer
31
+ - **🔍 Snapshot Diffing** - Text diff of accessibility tree after actions
32
+ - **📱 Device Emulation** - Named presets (iPhone 14, Pixel 7, iPad Pro) for batch screenshots
27
33
 
28
34
  ## Screenshot Button
29
35
 
@@ -86,22 +92,30 @@ That's it! The plugin automatically:
86
92
  - Detects Vite's port and configures everything
87
93
  - DevBar connects automatically
88
94
 
89
- ### For Next.js
95
+ ### For Next.js (Recommended)
90
96
 
91
- Use the `instrumentation.ts` hook to start the server once on startup:
97
+ Wrap your Next.js config - zero configuration needed:
92
98
 
93
- ```typescript
94
- // src/instrumentation.ts (or instrumentation.ts at root)
95
- export async function register() {
96
- if (process.env.NEXT_RUNTIME === 'nodejs') {
97
- if (process.env.NODE_ENV === 'development') {
98
- import('@ytspar/sweetlink/auto');
99
- }
100
- }
101
- }
99
+ ```javascript
100
+ // next.config.mjs
101
+ import { withSweetlink } from '@ytspar/sweetlink/next';
102
+
103
+ const nextConfig = { /* your config */ };
104
+ export default withSweetlink(nextConfig);
102
105
  ```
103
106
 
104
- This runs once when the Next.js server starts and auto-configures the WebSocket port based on the app port (3000 → 9223).
107
+ That's it! The plugin automatically:
108
+ - Detects the port from `--port` argv (e.g., `next dev --port 3002`)
109
+ - Falls back to `process.env.PORT`, then `3000`
110
+ - Starts the WebSocket server on `appPort + 6223`
111
+ - No-ops in production
112
+
113
+ Works with other wrappers too:
114
+
115
+ ```javascript
116
+ // With Sentry, MDX, etc.
117
+ export default withSentryConfig(withSweetlink(withMDX(nextConfig)), sentryOptions);
118
+ ```
105
119
 
106
120
  ### For Any Node.js App (Express, Remix, etc.)
107
121
 
@@ -167,7 +181,7 @@ pnpm sweetlink query --selector "h1"
167
181
  ### Screenshots
168
182
 
169
183
  ```bash
170
- # Full page screenshot
184
+ # Full page screenshot (html2canvas, fast)
171
185
  pnpm sweetlink screenshot
172
186
 
173
187
  # Element screenshot
@@ -176,8 +190,23 @@ pnpm sweetlink screenshot --selector ".company-card"
176
190
  # Full page with custom output
177
191
  pnpm sweetlink screenshot --full-page --output page.png
178
192
 
179
- # Force CDP method (requires Chrome debugging)
180
- pnpm sweetlink screenshot --force-cdp
193
+ # Navigate to URL before capturing
194
+ pnpm sweetlink screenshot --url http://localhost:3000/about
195
+
196
+ # Custom viewport dimensions
197
+ pnpm sweetlink screenshot --force-cdp --width 375 --height 667
198
+ pnpm sweetlink screenshot --force-cdp --viewport mobile
199
+
200
+ # Pixel-perfect via daemon (see Persistent Daemon section)
201
+ pnpm sweetlink screenshot --hifi
202
+ pnpm sweetlink screenshot --responsive
203
+
204
+ # Skip server readiness check
205
+ pnpm sweetlink screenshot --no-wait
206
+
207
+ # Force specific method
208
+ pnpm sweetlink screenshot --force-cdp # Playwright/CDP
209
+ pnpm sweetlink screenshot --force-ws # WebSocket/html2canvas
181
210
  ```
182
211
 
183
212
  ### DOM Queries
@@ -292,14 +321,206 @@ pnpm sweetlink click --selector ".tab" --index 2
292
321
 
293
322
  **Debugging:** Use `DEBUG=1 pnpm sweetlink click ...` to see generated JavaScript.
294
323
 
295
- ### Network Requests (CDP Required)
324
+ ### Network Requests
296
325
 
297
326
  ```bash
298
- # Get all network requests
327
+ # Get all network requests (via WebSocket bridge)
299
328
  pnpm sweetlink network
300
329
 
301
330
  # Filter by URL
302
331
  pnpm sweetlink network --filter "/api/"
332
+
333
+ # Failed requests only (via daemon ring buffer)
334
+ pnpm sweetlink network --failed
335
+ pnpm sweetlink network --failed --last 10
336
+ ```
337
+
338
+ ### Schema, Outline, Accessibility
339
+
340
+ ```bash
341
+ # Page schema (JSON-LD, meta tags, Open Graph)
342
+ pnpm sweetlink schema
343
+
344
+ # Document outline (heading structure)
345
+ pnpm sweetlink outline
346
+
347
+ # Accessibility audit (axe-core)
348
+ pnpm sweetlink a11y
349
+
350
+ # Web Vitals (FCP, LCP, CLS, INP)
351
+ pnpm sweetlink vitals
352
+ ```
353
+
354
+ ### Server Management
355
+
356
+ ```bash
357
+ # Wait for dev server to be ready (useful in scripts)
358
+ pnpm sweetlink wait --url http://localhost:3000
359
+ pnpm sweetlink wait --url http://localhost:3000 --wait-timeout 60000
360
+
361
+ # Check server health
362
+ pnpm sweetlink status
363
+
364
+ # Clean up Sweetlink processes
365
+ pnpm sweetlink cleanup
366
+ pnpm sweetlink cleanup --force
367
+
368
+ # Target specific app in monorepo (by branch or app name)
369
+ pnpm sweetlink screenshot --app my-app
370
+ ```
371
+
372
+ ### Persistent Daemon (v2)
373
+
374
+ Sweetlink v2 adds a persistent Playwright daemon for high-fidelity operations. The daemon auto-starts on first use and auto-stops after 30min idle.
375
+
376
+ #### Auto-Start with Vite
377
+
378
+ Add `daemon: true` to your Vite plugin config — the daemon starts/stops with your dev server:
379
+
380
+ ```typescript
381
+ // vite.config.ts
382
+ import { sweetlink } from '@ytspar/sweetlink/vite';
383
+
384
+ export default defineConfig({
385
+ plugins: [sweetlink({ daemon: true })]
386
+ // Or with visible browser: sweetlink({ daemon: true, headed: true })
387
+ });
388
+ ```
389
+
390
+ #### Auto-Start with Dev Script
391
+
392
+ Add a `dev` script that starts both your app and the daemon:
393
+
394
+ ```json
395
+ {
396
+ "scripts": {
397
+ "dev": "vite",
398
+ "dev:daemon": "concurrently 'vite' 'sweetlink daemon start --url http://localhost:5173'"
399
+ }
400
+ }
401
+ ```
402
+
403
+ #### Multiple Apps (Monorepo)
404
+
405
+ Each daemon is scoped by app port. Running two apps on different ports creates separate daemons:
406
+
407
+ ```bash
408
+ # Terminal 1: App A on port 3000
409
+ sweetlink daemon start --url http://localhost:3000
410
+ # State: .sweetlink/daemon-3000.json
411
+
412
+ # Terminal 2: App B on port 5173
413
+ sweetlink daemon start --url http://localhost:5173
414
+ # State: .sweetlink/daemon-5173.json
415
+
416
+ # Commands target specific apps via --url
417
+ sweetlink screenshot --hifi --url http://localhost:3000
418
+ sweetlink screenshot --hifi --url http://localhost:5173
419
+ ```
420
+
421
+ #### Manual Lifecycle
422
+
423
+ ```bash
424
+ # Start manually (auto-starts on first --hifi command if not running)
425
+ pnpm sweetlink daemon start --url http://localhost:5173
426
+ pnpm sweetlink daemon start --url http://localhost:5173 --headed # visible browser
427
+
428
+ # Check status
429
+ pnpm sweetlink daemon status
430
+
431
+ # Stop (or wait for 30min idle auto-stop)
432
+ pnpm sweetlink daemon stop
433
+ ```
434
+
435
+ #### CLI Quick Reference
436
+
437
+ ```bash
438
+ # Pixel-perfect screenshot via persistent daemon (~150ms after startup)
439
+ pnpm sweetlink screenshot --hifi
440
+
441
+ # Responsive screenshots at 3 breakpoints (375/768/1280)
442
+ pnpm sweetlink screenshot --responsive
443
+ ```
444
+
445
+ ### Accessibility Snapshots & Refs
446
+
447
+ ```bash
448
+ # List interactive elements with @refs
449
+ pnpm sweetlink snapshot -i
450
+ # @e1 [link] "Home"
451
+ # @e2 [button] "Submit"
452
+ # @e3 [textbox] "Email"
453
+
454
+ # Click/fill by ref (no CSS selector needed)
455
+ pnpm sweetlink click @e2
456
+ pnpm sweetlink fill @e3 "user@example.com"
457
+
458
+ # Diff against previous snapshot
459
+ pnpm sweetlink snapshot -D
460
+
461
+ # Annotated screenshot with red ref labels
462
+ pnpm sweetlink snapshot -a -o annotated.png
463
+ ```
464
+
465
+ ### Console & Network (Ring Buffers)
466
+
467
+ Always-on capture from daemon start — no "start watching" needed.
468
+
469
+ ```bash
470
+ # Console messages (captured since daemon start)
471
+ pnpm sweetlink console
472
+ pnpm sweetlink console --errors
473
+ pnpm sweetlink console --last 20
474
+
475
+ # Failed network requests
476
+ pnpm sweetlink network --failed
477
+ ```
478
+
479
+ ### Session Recording
480
+
481
+ ```bash
482
+ pnpm sweetlink record start
483
+ # ... do actions (click, fill, snapshot) ...
484
+ pnpm sweetlink record stop
485
+ # Generates .sweetlink/<session-id>/viewer.html
486
+ ```
487
+
488
+ ### Demo Documents
489
+
490
+ Build a Markdown tutorial/proof document step-by-step (inspired by [Showboat](https://simonwillison.net/2026/Feb/10/showboat-and-rodney/)):
491
+
492
+ ```bash
493
+ # Start a new demo
494
+ pnpm sweetlink demo init "How to use the search feature"
495
+
496
+ # Add narrative prose
497
+ pnpm sweetlink demo note "First, run the tests to see them pass."
498
+
499
+ # Run a command and capture output inline
500
+ pnpm sweetlink demo exec "pnpm test -- --grep search"
501
+
502
+ # Take a screenshot and embed it
503
+ pnpm sweetlink demo screenshot --url http://localhost:5173 --caption "Search results"
504
+
505
+ # Capture accessibility tree
506
+ pnpm sweetlink demo snapshot --url http://localhost:5173
507
+
508
+ # Remove last section if it's wrong
509
+ pnpm sweetlink demo pop
510
+
511
+ # Re-run all commands to verify outputs haven't changed
512
+ pnpm sweetlink demo verify
513
+
514
+ # Check status
515
+ pnpm sweetlink demo status
516
+ ```
517
+
518
+ Result: a `DEMO.md` with embedded command outputs and screenshots that serves as both documentation and a regression test.
519
+
520
+ ### PR Evidence
521
+
522
+ ```bash
523
+ pnpm sweetlink proof --pr 123
303
524
  ```
304
525
 
305
526
  ## Chrome DevTools Protocol (CDP) Setup
@@ -485,19 +706,53 @@ This 15x token savings enables 10+ autonomous iterations within Claude's budget.
485
706
 
486
707
  ## Comparison with Alternatives
487
708
 
488
- | Feature | Sweetlink | Playwright MCP | Manual Screenshots |
489
- |---------|-----------|----------------|-------------------|
490
- | Setup Time | < 1 min | 5-10 min | N/A |
491
- | Token Cost | ~1,000 | ~5,000 | N/A |
492
- | Auto Reconnect | | | N/A |
493
- | Console Logs | | | |
494
- | Network Requests | ✅ (CDP) | | ❌ |
495
- | DOM Queries | ✅ | ✅ | |
496
- | JS Execution | ✅ | | ❌ |
497
- | Click Elements | ✅ | ✅ | ❌ |
498
- | Element Screenshots | ✅ | | ❌ |
499
- | Full Page Screenshots | ✅ | ✅ | ✅ |
500
- | Autonomous Loops | ✅ (10+) | Limited (2-3) | ❌ |
709
+ ### Screenshot & Interaction
710
+
711
+ | Feature | Sweetlink | Playwright CLI | Chrome DevTools MCP | agent-browser |
712
+ |---------|-----------|----------------|--------------------|--------------|
713
+ | Setup | Vite/Next plugin | npm install | Chrome flag | npm install |
714
+ | Token cost/screenshot | ~1,000 | ~5,000 | ~5,000 | ~3,000 |
715
+ | Fast screenshots (html2canvas) | ✅ | | | ❌ |
716
+ | Pixel-perfect screenshots | ✅ (`--hifi`) | ✅ | | ✅ |
717
+ | Responsive (multi-viewport) | ✅ (`--responsive`) | Manual | ❌ | ❌ |
718
+ | Device emulation (iPhone, Pixel) | ✅ (named presets) | ✅ | ❌ | ✅ |
719
+ | @ref element interaction | ✅ (accessibility tree) | (CSS selectors) | ❌ | ✅ (Stagehand AI) |
720
+ | DOM queries | ✅ | ✅ | ✅ | ❌ |
721
+ | JS execution | ✅ | | | ❌ |
722
+ | Persistent browser sessions | ✅ (daemon) | ❌ (per-run) | ✅ | ✅ |
723
+
724
+ ### Evidence & Reporting
725
+
726
+ | Feature | Sweetlink | ProofShot | Proof | Playwright |
727
+ |---------|-----------|-----------|-------|------------|
728
+ | Video recording (WebM) | ✅ | ✅ | ✅ | ✅ (trace) |
729
+ | Interactive HTML viewer | ✅ (video + overlays) | ✅ | ✅ | ✅ (trace viewer) |
730
+ | Click ripple overlays | ✅ (canvas) | ✅ | ✅ (FFmpeg) | ❌ |
731
+ | Console ring buffer | ✅ (always-on, 50K) | ✅ | ❌ | ❌ |
732
+ | Network ring buffer | ✅ (always-on, 50K) | ❌ | ❌ | ✅ (HAR) |
733
+ | Multi-language error detection | ✅ (10+ languages) | ✅ | ❌ | ❌ |
734
+ | Snapshot diffing (a11y tree) | ✅ | ❌ | ❌ | ❌ |
735
+ | Annotated screenshots | ✅ (@ref labels) | ✅ | ❌ | ❌ |
736
+ | SUMMARY.md report | ✅ | ✅ | ✅ (3 formats) | ❌ |
737
+ | Demo documents (Showboat-style) | ✅ | ❌ | ❌ | ❌ |
738
+ | PR evidence upload | ✅ (`proof --pr`) | ✅ | ❌ | ❌ |
739
+ | Webhook sharing | ✅ (any URL) | ❌ | ❌ | ❌ |
740
+ | Self-contained viewer (offline) | ✅ (base64 video) | ✅ | ✅ | ✅ |
741
+
742
+ ### Developer Experience
743
+
744
+ | Feature | Sweetlink | ProofShot | Chrome DevTools MCP |
745
+ |---------|-----------|-----------|---------------------|
746
+ | Devbar toolbar UI | ✅ | ❌ | ❌ |
747
+ | Record button in browser | ✅ | ❌ | ❌ |
748
+ | Viewer auto-opens on stop | ✅ | ❌ | ❌ |
749
+ | Copy Report to clipboard | ✅ (CLI + viewer) | ❌ | ❌ |
750
+ | Serve viewer on network | ✅ (`report --serve`) | ❌ | ❌ |
751
+ | Multi-instance (monorepo) | ✅ (per-port daemon) | ❌ | ❌ |
752
+ | Vite/Next.js auto-start | ✅ (plugin option) | ❌ | ❌ |
753
+ | Accessibility audit (axe-core) | ✅ | ❌ | ❌ |
754
+ | Web Vitals | ✅ | ❌ | ❌ |
755
+ | Ruler/measurement tool | ✅ | ❌ | ❌ |
501
756
 
502
757
  ## When to Use Alternatives
503
758
 
@@ -506,22 +761,21 @@ This 15x token savings enables 10+ autonomous iterations within Claude's budget.
506
761
  **Use Sweetlink when:**
507
762
  - You're debugging/iterating on a running dev server
508
763
  - You need lightweight, token-efficient screenshots (~1000 tokens vs ~5000)
509
- - You want real-time console log capture
510
- - Your app is already running and you just need to inspect it
764
+ - You want always-on console/network capture without "start watching"
765
+ - You need session recording with interactive video viewer
766
+ - You want demo documents that serve as both tutorials and regression tests
511
767
  - You're doing autonomous UI development loops (10+ iterations)
768
+ - You want a toolbar UI in the browser for visual debugging
512
769
 
513
770
  **Use [Agent Browser](https://github.com/vercel-labs/agent-browser) when:**
514
- - You need full browser automation (navigation, form filling, multi-page flows)
515
- - You're testing production sites or external URLs
516
- - Sweetlink isn't integrated into the target application
771
+ - You're testing production sites or external URLs where Sweetlink isn't installed
517
772
  - You need Stagehand's AI-powered element selection
518
773
  - You're building autonomous agents that interact with arbitrary websites
519
774
 
520
- **Use Playwright MCP when:**
521
- - You need precise, programmatic browser control
522
- - You're running E2E tests with assertions
523
- - You need browser contexts, multiple tabs, or complex scenarios
524
- - You require network interception or request mocking
775
+ **Use Playwright directly when:**
776
+ - You're writing structured E2E test suites with assertions
777
+ - You need network interception, request mocking, or multiple browser contexts
778
+ - You want trace viewer for debugging test failures
525
779
 
526
780
  ### Agent Browser Quick Start
527
781
 
@@ -17,12 +17,17 @@ Sweetlink (`@ytspar/sweetlink`) is a WebSocket-based bridge that enables Claude
17
17
  ### Architecture
18
18
 
19
19
  ```
20
- CLI (pnpm sweetlink) <--> WebSocket (port 9223) <--> Browser (SweetlinkBridge component)
21
- |
22
- html2canvas (screenshots)
20
+ CLI (pnpm sweetlink)
21
+ |
22
+ ├─ Fast path (WebSocket) ──> Browser (SweetlinkBridge) ──> html2canvas
23
+ | screenshot, logs, exec, query, click, refresh
24
+ |
25
+ └─ HiFi path (HTTP) ──> Daemon (persistent Playwright) ──> Headless Chromium
26
+ screenshot --hifi, --responsive, snapshot, click @ref, fill @ref,
27
+ console, network --failed, record, proof
23
28
  ```
24
29
 
25
- Optionally, if Chrome is launched with `--remote-debugging-port=9222`, Sweetlink uses CDP (Puppeteer) for higher quality screenshots and network inspection.
30
+ The daemon auto-starts on first `--hifi`/`snapshot` command and auto-stops after 30min idle. State file at `.sweetlink/daemon-{port}.json` (scoped per app port for multi-instance support).
26
31
 
27
32
  ### Prerequisites
28
33
 
@@ -122,17 +127,49 @@ Need screenshot or browser interaction?
122
127
  --> Use Agent-Browser (better for sequential multi-step flows)
123
128
  ```
124
129
 
130
+ ### Sweetlink v2 Daemon — Persistent Browser (Preferred for Multi-Step)
131
+
132
+ Sweetlink v2 adds a persistent Playwright daemon that keeps a browser alive between commands, solving the statefulness problem. **Use daemon mode for multi-step workflows instead of Agent-Browser.**
133
+
134
+ ```bash
135
+ # Pixel-perfect screenshot via persistent daemon (~150ms)
136
+ pnpm sweetlink screenshot --hifi --url http://localhost:3000 --output .tmp/screenshots/page.png
137
+
138
+ # Responsive screenshots at 3 breakpoints
139
+ pnpm sweetlink screenshot --responsive --url http://localhost:3000
140
+
141
+ # Get interactive element refs
142
+ pnpm sweetlink snapshot -i --url http://localhost:3000
143
+
144
+ # Click/fill by ref (stateful — same browser session!)
145
+ pnpm sweetlink click @e3
146
+ pnpm sweetlink fill @e5 "test@example.com"
147
+
148
+ # Take screenshot after interaction (same browser, state preserved)
149
+ pnpm sweetlink screenshot --hifi --output .tmp/screenshots/after-click.png
150
+
151
+ # Check console errors (ring buffer — captured since daemon start)
152
+ pnpm sweetlink console --errors
153
+
154
+ # Diff accessibility tree after actions
155
+ pnpm sweetlink snapshot -D
156
+
157
+ # Annotated screenshot with ref labels
158
+ pnpm sweetlink snapshot -a -o .tmp/screenshots/annotated.png
159
+
160
+ # Stop daemon when done (or it auto-stops after 30min idle)
161
+ pnpm sweetlink daemon stop
162
+ ```
163
+
125
164
  ### Known Sweetlink Limitations — Use Agent-Browser Instead
126
165
 
127
- These scenarios require multi-step browser state that Sweetlink cannot maintain across commands (each Sweetlink CLI call may open a fresh page):
166
+ With the v2 daemon, most statefulness issues are resolved. These remain:
128
167
 
129
168
  | Scenario | Why Sweetlink fails | Agent-Browser approach |
130
169
  |----------|--------------------|-----------------------|
131
- | **Scroll then screenshot** | `exec` (scroll) and `screenshot` are separate page loads in Playwright fallbackscroll state is lost | `open` -> `scroll down` -> `screenshot` (single session) |
132
- | **Click then screenshot** (when click triggers navigation/animation) | Same statefulness issue click and screenshot may not share the same page | `open` -> `click` -> `screenshot` |
133
- | **Multi-step interactions** (type + submit + wait for result) | Each command is stateless | `open` -> `type` -> `press Enter` -> `screenshot` |
134
- | **Custom viewport dimensions** (not `mobile`/`tablet` presets) | `--viewport` only supports named presets | `agent-browser open --viewport 1600x900` or use Sweetlink `--force-cdp` with preset |
135
- | **Verifying SVG content** (colors, icons, shapes) | html2canvas does not render SVG elements — they appear blank/missing. Fine for layout checks where SVG content doesn't matter, but wrong when the SVGs themselves are what you're verifying (e.g., icon colors, logo accuracy) | Use Sweetlink with `--force-cdp`, or `agent-browser open` -> `screenshot` |
170
+ | **Verifying SVG content** (colors, icons, shapes) | html2canvas (fast path) does not render SVG elementsuse `--hifi` or `--force-cdp` instead | Use Sweetlink with `--hifi`, or `agent-browser open` -> `screenshot` |
171
+ | **Non-dev-server URLs** | Sweetlink requires the app to have the bridge installed | `agent-browser open` any URL |
172
+ | **AI-powered element selection** | Sweetlink uses CSS selectors or @refs | Agent-Browser has Stagehand AI selection |
136
173
 
137
174
  > **Self-updating rule:** When you encounter a NEW Sweetlink failure mode not listed above — i.e., you try Sweetlink, it fails or produces incorrect results for a reason that would apply generally (not a transient network/server issue) — you MUST append a new row to this table before continuing with the Agent-Browser fallback. This keeps the list exhaustive and prevents future sessions from repeating the same mistake.
138
175
 
@@ -159,6 +196,8 @@ All commands use `pnpm sweetlink <command> [options]`.
159
196
  | `--viewport <size>` | Emulate viewport: `mobile`, `tablet` (requires `--force-cdp`) |
160
197
  | `--hover` | Capture hover state (requires `--selector`) |
161
198
  | `--force-cdp` | Force Chrome DevTools Protocol method (higher quality, more tokens) |
199
+ | `--hifi` | Pixel-perfect via persistent Playwright daemon (~150ms after startup) |
200
+ | `--responsive` | Screenshots at 3 breakpoints (375/768/1280px) via daemon |
162
201
 
163
202
  ```bash
164
203
  pnpm sweetlink screenshot --output .tmp/screenshots/full.png
@@ -246,6 +285,88 @@ pnpm sweetlink network # All requests
246
285
  pnpm sweetlink network --filter "/api/" # Filter by URL pattern
247
286
  ```
248
287
 
288
+ ### snapshot — Accessibility tree with @refs (daemon)
289
+
290
+ | Option | Description |
291
+ |--------|-------------|
292
+ | `-i`, `--interactive` | Show only interactive elements with @e refs |
293
+ | `-D`, `--diff` | Diff against previous snapshot |
294
+ | `-a`, `--annotate` | Annotated screenshot with ref labels |
295
+ | `-o <path>` | Output path for annotated screenshot |
296
+
297
+ ```bash
298
+ pnpm sweetlink snapshot -i --url http://localhost:3000
299
+ pnpm sweetlink snapshot -D
300
+ pnpm sweetlink snapshot -a -o .tmp/screenshots/annotated.png
301
+ ```
302
+
303
+ ### click — Click elements (supports @refs)
304
+
305
+ ```bash
306
+ pnpm sweetlink click @e3 # Click by ref (daemon)
307
+ pnpm sweetlink click --selector "button.submit" # Click by CSS selector (WS)
308
+ ```
309
+
310
+ ### fill — Fill inputs by @ref (daemon)
311
+
312
+ ```bash
313
+ pnpm sweetlink fill @e5 "user@example.com"
314
+ ```
315
+
316
+ ### console — Console messages from ring buffer (daemon)
317
+
318
+ | Option | Description |
319
+ |--------|-------------|
320
+ | `--errors` | Show only errors |
321
+ | `--last <n>` | Show only last N entries |
322
+
323
+ ```bash
324
+ pnpm sweetlink console --errors
325
+ pnpm sweetlink console --last 20
326
+ ```
327
+
328
+ ### network --failed — Failed requests from ring buffer (daemon)
329
+
330
+ ```bash
331
+ pnpm sweetlink network --failed
332
+ ```
333
+
334
+ ### record — Session recording (daemon)
335
+
336
+ ```bash
337
+ pnpm sweetlink record start
338
+ pnpm sweetlink record stop # Generates viewer.html
339
+ pnpm sweetlink record status
340
+ ```
341
+
342
+ ### daemon — Daemon lifecycle
343
+
344
+ ```bash
345
+ pnpm sweetlink daemon status
346
+ pnpm sweetlink daemon start --url http://localhost:3000
347
+ pnpm sweetlink daemon start --url http://localhost:3000 --headed # visible browser
348
+ pnpm sweetlink daemon stop
349
+ ```
350
+
351
+ ### proof — Upload session evidence to GitHub PR
352
+
353
+ ```bash
354
+ pnpm sweetlink proof --pr 123
355
+ pnpm sweetlink proof --pr 123 --repo owner/repo
356
+ ```
357
+
358
+ ### Other useful commands
359
+
360
+ ```bash
361
+ pnpm sweetlink wait --url http://localhost:3000 # Wait for server ready
362
+ pnpm sweetlink status # Check server health
363
+ pnpm sweetlink vitals # Get Web Vitals
364
+ pnpm sweetlink a11y # Accessibility audit
365
+ pnpm sweetlink schema # Page schema (meta, OG, JSON-LD)
366
+ pnpm sweetlink outline # Document heading structure
367
+ pnpm sweetlink cleanup --force # Clean up Sweetlink processes
368
+ ```
369
+
249
370
  ## Agent-Browser Commands
250
371
 
251
372
  ### Basic Usage
@@ -336,18 +457,18 @@ pnpm sweetlink screenshot --selector ".fixed-component" --output .tmp/screenshot
336
457
 
337
458
  | Scenario | Tool | Notes |
338
459
  |----------|------|-------|
339
- | Screenshot of dev server page | Sweetlink (`--url`) | Single-command, preferred |
340
- | Screenshot after scrolling | **Agent-Browser** | Sweetlink loses scroll state between commands |
341
- | Check console logs | Sweetlink (`logs`) | |
460
+ | Screenshot of dev server page | Sweetlink (`--url`) | Fast path, preferred |
461
+ | Pixel-perfect screenshot | Sweetlink (`--hifi`) | Persistent daemon, ~150ms |
462
+ | Responsive screenshots | Sweetlink (`--responsive`) | 3 breakpoints via daemon |
463
+ | Click then screenshot same page | Sweetlink daemon (`click @ref` + `screenshot --hifi`) | Daemon preserves state |
464
+ | Multi-step form interactions | Sweetlink daemon (`snapshot -i` + `fill @ref` + `click @ref`) | Refs make this easy |
465
+ | Check console logs | Sweetlink (`console --errors`) | Ring buffer, always-on |
342
466
  | DOM queries | Sweetlink (`query`) | |
343
- | Click then screenshot same page | **Agent-Browser** | Sweetlink can't guarantee state between commands |
344
467
  | Navigate to specific page | Sweetlink (`--url` flag) | |
345
- | Verifying SVG content (icons, colors) | Sweetlink (`--force-cdp`) or **Agent-Browser** | html2canvas can't render SVGs; only matters when SVG content is what you're checking |
346
- | Viewport testing (mobile/tablet) | Sweetlink (`--force-cdp --viewport`) | |
347
- | Custom viewport dimensions | **Agent-Browser** | Sweetlink only supports named presets |
348
- | Non-dev-server URL | Agent-Browser | |
349
- | Complex multi-step form flows | Agent-Browser | |
350
- | Sequential type + submit + wait | Agent-Browser | |
468
+ | Verifying SVG content (icons, colors) | Sweetlink (`--hifi`) | Daemon renders SVGs correctly |
469
+ | Viewport testing (mobile/tablet) | Sweetlink (`--responsive` or `--hifi --viewport`) | |
470
+ | Non-dev-server URL | Agent-Browser | Sweetlink requires bridge |
471
+ | AI-powered element selection | Agent-Browser | Stagehand AI |
351
472
 
352
473
  ## Troubleshooting
353
474
 
@@ -89,6 +89,22 @@ export interface StatusData {
89
89
  running: boolean;
90
90
  statusCode?: number;
91
91
  }
92
+ export interface DaemonStatusData {
93
+ running: boolean;
94
+ pid?: number;
95
+ port?: number;
96
+ url?: string;
97
+ uptime?: number;
98
+ }
99
+ export interface SnapshotData {
100
+ tree: string;
101
+ refs?: Array<{
102
+ ref: string;
103
+ role: string;
104
+ name: string;
105
+ }>;
106
+ diff?: string;
107
+ }
92
108
  export declare const SCHEMAS: Record<string, string>;
93
109
  /**
94
110
  * Write a JSON envelope to stdout. Used in --json mode.
@@ -1 +1 @@
1
- {"version":3,"file":"outputSchemas.d.ts","sourceRoot":"","sources":["../../src/cli/outputSchemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"outputSchemas.d.ts","sourceRoot":"","sources":["../../src/cli/outputSchemas.ts"],"names":[],"mappings":"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"}
@@ -88,6 +88,39 @@ export const SCHEMAS = {
88
88
  url: string;
89
89
  running: boolean;
90
90
  statusCode?: number;
91
+ }`,
92
+ daemon: `interface DaemonStatusData {
93
+ running: boolean;
94
+ pid?: number;
95
+ port?: number;
96
+ url?: string;
97
+ uptime?: number;
98
+ }`,
99
+ snapshot: `interface SnapshotData {
100
+ tree: string;
101
+ refs?: Array<{ ref: string; role: string; name: string }>;
102
+ diff?: string;
103
+ }`,
104
+ console: `interface ConsoleData {
105
+ formatted: string;
106
+ total: number;
107
+ errorCount: number;
108
+ warningCount: number;
109
+ entries: unknown[];
110
+ }`,
111
+ fill: `interface FillData {
112
+ filled: string;
113
+ value: string;
114
+ }`,
115
+ proof: `interface ProofData {
116
+ commentUrl: string;
117
+ }`,
118
+ record: `interface RecordData {
119
+ recording: boolean;
120
+ sessionId?: string;
121
+ duration?: number;
122
+ actionCount?: number;
123
+ manifest?: unknown;
91
124
  }`,
92
125
  };
93
126
  // ============================================================================