@ytspar/sweetlink 1.26.6 → 1.27.0-canary.48cfa86

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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Batch screenshot manifest parsing.
3
+ *
4
+ * Lives outside the CLI entry point so the validation is directly importable and
5
+ * testable — the CLI module is a top-level IIFE and cannot be imported for a
6
+ * unit test without running it.
7
+ */
8
+ /** One frame in a `--batch` manifest. `url` and `output` are required. */
9
+ export interface BatchScreenshotItem {
10
+ url: string;
11
+ output: string;
12
+ selector?: string;
13
+ fullPage?: boolean;
14
+ viewport?: string;
15
+ hideDevbar?: boolean;
16
+ }
17
+ export interface BatchScreenshotResult {
18
+ url: string;
19
+ output: string;
20
+ ok: boolean;
21
+ width?: number;
22
+ height?: number;
23
+ error?: string;
24
+ }
25
+ /**
26
+ * Parse and validate a batch manifest.
27
+ *
28
+ * Every field is checked up front rather than per frame, so a malformed manifest
29
+ * fails before the first browser is touched instead of halfway through a sweep.
30
+ * `output` in particular is required: defaulting it would make every frame write
31
+ * to the same path, and a directory of identical frames reads downstream as "the
32
+ * capture tool duplicated my frames" rather than "my manifest was malformed".
33
+ */
34
+ export declare function parseBatchManifest(raw: string): BatchScreenshotItem[];
35
+ //# sourceMappingURL=batchManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batchManifest.d.ts","sourceRoot":"","sources":["../src/batchManifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA4BrE"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Batch screenshot manifest parsing.
3
+ *
4
+ * Lives outside the CLI entry point so the validation is directly importable and
5
+ * testable — the CLI module is a top-level IIFE and cannot be imported for a
6
+ * unit test without running it.
7
+ */
8
+ /**
9
+ * Parse and validate a batch manifest.
10
+ *
11
+ * Every field is checked up front rather than per frame, so a malformed manifest
12
+ * fails before the first browser is touched instead of halfway through a sweep.
13
+ * `output` in particular is required: defaulting it would make every frame write
14
+ * to the same path, and a directory of identical frames reads downstream as "the
15
+ * capture tool duplicated my frames" rather than "my manifest was malformed".
16
+ */
17
+ export function parseBatchManifest(raw) {
18
+ let parsed;
19
+ try {
20
+ parsed = JSON.parse(raw);
21
+ }
22
+ catch (error) {
23
+ throw new Error(`batch manifest is not valid JSON: ${error instanceof Error ? error.message : error}`);
24
+ }
25
+ if (!Array.isArray(parsed)) {
26
+ throw new Error('batch manifest must be a JSON array of { url, output } items');
27
+ }
28
+ if (parsed.length === 0) {
29
+ throw new Error('batch manifest is empty — nothing to capture');
30
+ }
31
+ return parsed.map((item, i) => {
32
+ if (typeof item !== 'object' || item === null) {
33
+ throw new Error(`batch item ${i} is not an object`);
34
+ }
35
+ const { url, output } = item;
36
+ if (typeof url !== 'string' || url.length === 0) {
37
+ throw new Error(`batch item ${i} is missing a "url"`);
38
+ }
39
+ if (typeof output !== 'string' || output.length === 0) {
40
+ throw new Error(`batch item ${i} (${url}) is missing an "output" path`);
41
+ }
42
+ return item;
43
+ });
44
+ }
45
+ //# sourceMappingURL=batchManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batchManifest.js","sourceRoot":"","sources":["../src/batchManifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqBH;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,qCAAqC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CACtF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAA+B,CAAC;QACxD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,KAAK,GAAG,+BAA+B,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,IAA2B,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/cdp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAA6B,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAqB/E;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAOlD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CActD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BtE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,oBAAoB,EAAE,YAAY,GAAG,MAAM,CAAC;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2H7D;AAKD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCjE;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CACpF,KAAK,CAAC;IACJ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CACH,CAmDA"}
1
+ {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAA6B,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAsB/E;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAOlD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CActD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BtE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,oBAAoB,EAAE,YAAY,GAAG,MAAM,CAAC;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2H7D;AAKD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCjE;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CACpF,KAAK,CAAC;IACJ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CACH,CAmDA"}
package/dist/cdp.js CHANGED
@@ -6,12 +6,13 @@
6
6
  */
7
7
  import * as fs from 'fs';
8
8
  import { HIDE_DEVBAR_CSS, HIDE_DEVBAR_STYLE_ID, HOVER_TRANSITION_DELAY_MS, SELECTOR_TIMEOUT_MS, } from './screenshotConstants.js';
9
+ import { defaultDevUrl } from './urlUtils.js';
9
10
  import { parseViewport } from './viewportUtils.js';
10
11
  // ============================================================================
11
12
  // Constants
12
13
  // ============================================================================
13
14
  const CDP_URL = process.env.CHROME_CDP_URL || 'http://127.0.0.1:9222';
14
- const DEFAULT_DEV_URL = process.env.SWEETLINK_DEV_URL || 'http://localhost:3000';
15
+ const DEFAULT_DEV_URL = defaultDevUrl();
15
16
  /** Timeouts */
16
17
  const NETWORK_IDLE_TIMEOUT_MS = 10000;
17
18
  const NETWORK_IDLE_TIME_MS = 500;
package/dist/cdp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,uBAAuB,CAAC;AACtE,MAAM,eAAe,GAAG,aAAa,EAAE,CAAC;AAExC,eAAe;AACf,MAAM,uBAAuB,GAAG,KAAK,CAAC;AACtC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,gCAAgC,GAAG,IAAI,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,eAAe,CAAC,CAAC;QACxD,OAAO,QAAQ,CAAC,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC;YACtC,UAAU,EAAE,OAAO;YACnB,eAAe,EAAE,IAAI;SACtB,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;QAC5F,MAAM,IAAI,KAAK,CACb,0BAA0B,YAAY,sIAAsI,CAC7K,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgB;IACrD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7E,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAO,EAAE,EAAE;QACnC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACpB,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,uDAAuD;IACvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CACT,sBAAsB,OAAO,IAAI,OAAO,8BAA8B,eAAe,KAAK,CAC3F,CAAC;QAEF,yCAAyC;QACzC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QAED,MAAM,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,OAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAQtC;IACC,MAAM,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE7C,oBAAoB;QACpB,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEjD,MAAM,IAAI,CAAC,WAAW,CAAC;YACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,iBAAiB,EAAE,CAAC;YACpB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC;QAEH,8DAA8D;QAC9D,IAAI,OAAO,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,kBAAkB,CAAC;oBAC5B,OAAO,EAAE,uBAAuB;oBAChC,QAAQ,EAAE,oBAAoB;iBAC/B,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;QAED,MAAM,iBAAiB,GAInB;YACF,IAAI,EAAE,KAAK;YACX,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK;SACpC,CAAC;QAEF,wDAAwD;QACxD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAE/E,6BAA6B;gBAC7B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;wBACnC,mCAAmC;wBACnC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC,CAAC;oBACrE,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACX,OAAO,CAAC,IAAI,CAAC,wCAAwC,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC;oBAC/E,CAAC;gBACH,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAE/C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC5D,CAAC;gBAED,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;gBAChD,IAAI,WAAW,EAAE,CAAC;oBAChB,iBAAiB,CAAC,IAAI,GAAG;wBACvB,CAAC,EAAE,WAAW,CAAC,CAAC;wBAChB,CAAC,EAAE,WAAW,CAAC,CAAC;wBAChB,KAAK,EAAE,WAAW,CAAC,KAAK;wBACxB,MAAM,EAAE,WAAW,CAAC,MAAM;qBAC3B,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CACb,2BAA2B,OAAO,CAAC,QAAQ,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAClG,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,YAAY,GAAG,KAAK,CAAC;QACzB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;gBACf,IAAI,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC;oBAAE,OAAO,KAAK,CAAC;gBACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC9C,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC;gBACnB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;gBACxB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;gBACjC,OAAO,IAAI,CAAC;YACd,CAAC,EACD,oBAAoB,EACpB,eAAe,CAChB,CAAC;QACJ,CAAC;QAED,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,sBAAsB;YACtB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YAC5D,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;gBAAS,CAAC;YACT,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC9B,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;gBAC7C,CAAC,EAAE,oBAAoB,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,uCAAuC;QACvC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;QAED,iBAAiB;QACjB,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI;YACvC,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE;YAChF,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAE1F,OAAO;YACL,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;YACnC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;SACtC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,6CAA6C;IAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,+CAA+C;IAC/C,IAAI,IAAI,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,kCAAkC,mBAAmB,aAAa,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE7C,2CAA2C;QAC3C,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAc,EAAE,EAAE;YACpD,mDAAmD;YACnD,OAAO,QAAQ,CAAC,yBAAyB,MAAM,GAAG,CAAC,EAAE,CAAC;QACxD,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAA6B;IAU1E,MAAM,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE7C,MAAM,QAAQ,GAOT,EAAE,CAAC;QAER,sBAAsB;QACtB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAoB,EAAE,EAAE;YAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAE1B,2BAA2B;YAC3B,IAAI,OAAO,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG;gBACH,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;gBACxB,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE;gBACpC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,QAAsB,EAAE,EAAE;YAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC;YAE3B,wBAAwB;YACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAEjE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACnC,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC7C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,iCAAiC;QACjC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC,CAAC;QAEtF,OAAO,QAAQ,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC"}
@@ -7,9 +7,9 @@
7
7
  */
8
8
  import * as childProcess from 'child_process';
9
9
  import * as fs from 'fs';
10
- import * as https from 'https';
11
10
  import * as path from 'path';
12
11
  import { WebSocket } from 'ws';
12
+ import { parseBatchManifest, } from '../batchManifest.js';
13
13
  import { detectCDP, getNetworkRequestsViaCDP } from '../cdp.js';
14
14
  import { DaemonRequestError, daemonRequest, ensureDaemon, getDaemonStatus, stopDaemon, } from '../daemon/client.js';
15
15
  import { uploadEvidence } from '../daemon/evidence.js';
@@ -19,7 +19,7 @@ import { screenshotViaPlaywright } from '../playwright.js';
19
19
  import { getCardHeaderPreset, getNavigationPreset, measureViaPlaywright } from '../ruler.js';
20
20
  import { findServerInfoFile } from '../server/discovery.js';
21
21
  import { DEFAULT_WS_PORT, MAX_PORT_RETRIES, parseLocalDevelopmentUrl, parsePortNumber, resolveSweetlinkWsPortForAppPort, } from '../types.js';
22
- import { isLocalHost, SCREENSHOT_DIR, selectClientForTargetUrl, urlsEquivalent } from '../urlUtils.js';
22
+ import { defaultDevUrl, SCREENSHOT_DIR, selectClientForTargetUrl, urlsEquivalent, } from '../urlUtils.js';
23
23
  import { generateClickCode } from './clickCode.js';
24
24
  import { emitJson, printOutputSchema } from './outputSchemas.js';
25
25
  const COMMON_APP_PORTS = [3000, 3001, 4000, 5173, 5174, 8000, 8080];
@@ -368,55 +368,23 @@ async function checkSweetlinkAlive(wsUrl) {
368
368
  * @param timeout Maximum time to wait in ms
369
369
  * @returns true if server is ready, throws if timeout
370
370
  */
371
- /**
372
- * HEAD a local HTTPS URL via node:https with TLS verification relaxed, resolving
373
- * its status code. Only used for local hosts (`isLocalHost`): their self-signed
374
- * certs (Portless `*.localhost` on :443, mkcert) otherwise reject the health
375
- * check before the server is ever reached, so a portless dev server looks "not
376
- * ready" even though it is serving. `fetch` has no ergonomic per-request cert
377
- * bypass, hence node:https here.
378
- */
379
- function headStatusInsecureLocal(target, timeoutMs) {
380
- return new Promise((resolve, reject) => {
381
- const req = https.request(target, { method: 'HEAD', rejectUnauthorized: false }, (res) => {
382
- res.resume(); // drain so the socket can close
383
- resolve(res.statusCode ?? 0);
384
- });
385
- req.setTimeout(timeoutMs, () => req.destroy(new Error('timeout')));
386
- req.on('error', reject);
387
- req.end();
388
- });
389
- }
390
371
  async function waitForServer(url, timeout = SERVER_READY_TIMEOUT) {
391
372
  const startTime = Date.now();
392
373
  let lastError = null;
393
374
  // Parse URL to get just the origin for health check
394
375
  const parsedUrl = new URL(url);
395
376
  const healthCheckUrl = `${parsedUrl.protocol}//${parsedUrl.host}`;
396
- // Local HTTPS dev servers (Portless `*.localhost`, mkcert) serve self-signed
397
- // certs that fetch's TLS layer rejects; probe those via node:https with
398
- // verification relaxed. Everything else keeps the plain fetch health check.
399
- const relaxTls = parsedUrl.protocol === 'https:' && isLocalHost(parsedUrl.hostname);
400
377
  console.log(`[Sweetlink] Waiting for server at ${healthCheckUrl}...`);
401
378
  while (Date.now() - startTime < timeout) {
402
379
  try {
403
- let ok;
404
- if (relaxTls) {
405
- const status = await headStatusInsecureLocal(healthCheckUrl, 2000);
406
- // Any 2xx/3xx means the server answered (a redirect or 304 still proves it's up).
407
- ok = status >= 200 && status < 400;
408
- }
409
- else {
410
- const controller = new AbortController();
411
- const timeoutId = setTimeout(() => controller.abort(), 2000);
412
- const response = await fetch(healthCheckUrl, {
413
- method: 'HEAD',
414
- signal: controller.signal,
415
- });
416
- clearTimeout(timeoutId);
417
- ok = response.ok || response.status === 304;
418
- }
419
- if (ok) {
380
+ const controller = new AbortController();
381
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
382
+ const response = await fetch(healthCheckUrl, {
383
+ method: 'HEAD',
384
+ signal: controller.signal,
385
+ });
386
+ clearTimeout(timeoutId);
387
+ if (response.ok || response.status === 304) {
420
388
  console.log(`[Sweetlink] Server ready (${Date.now() - startTime}ms)`);
421
389
  return true;
422
390
  }
@@ -630,13 +598,65 @@ async function takePlaywrightScreenshot(options, method) {
630
598
  ...(options.hideDevbar ? { devbarHidden: true } : {}),
631
599
  };
632
600
  }
601
+ /**
602
+ * Screenshot when no browser client is connected, preferring the persistent daemon.
603
+ *
604
+ * `takePlaywrightScreenshot` cold-launches a browser per invocation (~2s). That is
605
+ * fine for a one-off, but the automated callers — visual-evidence gallery frames,
606
+ * batch capture runs — take dozens of shots in a row and pay it every single time.
607
+ * They never pass `--hifi`, so they never reached the persistent daemon that exists
608
+ * for exactly this case and serves repeat shots in ~150ms.
609
+ *
610
+ * Worse, the daemon was unreachable precisely where it helps most: the routes those
611
+ * captures target render without devbar, so there is never a connected browser
612
+ * client and the WebSocket path always escalates here.
613
+ *
614
+ * So make the warm path the default rather than an opt-in flag, and fall back to a
615
+ * standalone launch whenever the daemon can't serve the request. The returned
616
+ * `method` names the engine that actually served the frame, so a silent regression
617
+ * back to per-frame launches is visible in the log rather than invisible.
618
+ */
619
+ async function takeScreenshotPreferDaemon(options, targetUrl, fallbackMethod) {
620
+ // --hover is a standalone-Playwright capability; the daemon screenshot request
621
+ // has no hover support, so don't route those through it.
622
+ if (!options.hover) {
623
+ try {
624
+ const daemonState = await ensureDaemon(findProjectRoot(), targetUrl);
625
+ const resp = await daemonRequest(daemonState, 'screenshot', {
626
+ selector: options.selector,
627
+ fullPage: options.fullPage,
628
+ viewport: options.viewport,
629
+ hideDevbar: options.hideDevbar,
630
+ url: options.url || targetUrl,
631
+ });
632
+ const data = resp.data;
633
+ const outputPath = options.output || getDefaultScreenshotPath();
634
+ ensureDir(outputPath);
635
+ fs.writeFileSync(outputPath, Buffer.from(data.screenshot, 'base64'));
636
+ const method = 'Daemon (auto-escalation)';
637
+ reportScreenshotSuccess(outputPath, data.width, data.height, method, options.selector);
638
+ return {
639
+ path: getRelativePath(outputPath),
640
+ width: data.width,
641
+ height: data.height,
642
+ method,
643
+ selector: options.selector,
644
+ ...(options.hideDevbar ? { devbarHidden: true } : {}),
645
+ };
646
+ }
647
+ catch (error) {
648
+ console.warn(`[Sweetlink] Daemon unavailable (${error instanceof Error ? error.message : error}) — falling back to a standalone browser`);
649
+ }
650
+ }
651
+ return await takePlaywrightScreenshot(options, fallbackMethod);
652
+ }
633
653
  async function screenshot(options) {
634
654
  // Convert --width/--height to viewport format if provided
635
655
  if (options.width && !options.viewport) {
636
656
  const height = options.height || Math.round(options.width * 1.5); // Default aspect ratio
637
657
  options.viewport = `${options.width}x${height}`;
638
658
  }
639
- const targetUrl = options.url || 'http://localhost:3000';
659
+ const targetUrl = options.url || defaultDevUrl();
640
660
  // Auto-wait for server if --wait flag is set or if URL is provided
641
661
  // This eliminates the need for external sleep workarounds
642
662
  if (options.wait !== false) {
@@ -734,7 +754,11 @@ async function screenshot(options) {
734
754
  // This prevents launching a headless browser only to discover the dev server is dead.
735
755
  const serverAlive = await checkSweetlinkAlive();
736
756
  if (!serverAlive && !options.forceCDP) {
737
- console.warn('[Sweetlink] Sweetlink server not responding will use Playwright standalone');
757
+ // Not necessarily a fault: pages rendered without devbar (isolated component
758
+ // render routes, production builds) never host a Sweetlink server. Say what
759
+ // happens next rather than implying a standalone launch is the only option —
760
+ // the escalation path prefers the persistent daemon.
761
+ console.warn('[Sweetlink] No Sweetlink server on the page — capturing via browser automation');
738
762
  }
739
763
  // Check if CDP is available (unless force WS is specified)
740
764
  // Hover requires CDP/Playwright
@@ -774,9 +798,10 @@ async function screenshot(options) {
774
798
  console.error('[Sweetlink] Could not navigate browser to', options.url);
775
799
  process.exit(1);
776
800
  }
777
- // Auto-escalate to Playwright (opens browser, navigates, screenshots)
778
- console.log('[Sweetlink] No browser for navigation escalating to Playwright');
779
- return await takePlaywrightScreenshot(playwrightOpts, 'Playwright (auto-escalation)');
801
+ // Auto-escalate (opens browser, navigates, screenshots), preferring the
802
+ // persistent daemon so a batch of frames doesn't relaunch a browser each time.
803
+ console.log('[Sweetlink] No browser for navigation — escalating');
804
+ return await takeScreenshotPreferDaemon(playwrightOpts, targetUrl, 'Playwright (auto-escalation)');
780
805
  }
781
806
  }
782
807
  console.log('[Sweetlink] Using WebSocket for screenshot');
@@ -796,9 +821,9 @@ async function screenshot(options) {
796
821
  // Auto-escalate to Playwright when no browser client is connected
797
822
  // This happens after dev server restart when browser page hasn't been refreshed
798
823
  if (response.error?.includes('No browser client connected')) {
799
- console.log('[Sweetlink] No browser client - auto-escalating to Playwright');
824
+ console.log('[Sweetlink] No browser client - auto-escalating');
800
825
  try {
801
- return await takePlaywrightScreenshot(playwrightOpts, 'Playwright (auto-escalation)');
826
+ return await takeScreenshotPreferDaemon(playwrightOpts, targetUrl, 'Playwright (auto-escalation)');
802
827
  }
803
828
  catch (playwrightError) {
804
829
  console.error('[Sweetlink] Playwright fallback also failed:', playwrightError instanceof Error ? playwrightError.message : playwrightError);
@@ -844,6 +869,90 @@ async function screenshot(options) {
844
869
  process.exit(1);
845
870
  }
846
871
  }
872
+ /**
873
+ * Capture many frames in one process against one browser.
874
+ *
875
+ * Even with the daemon serving frames, driving a batch as N separate CLI
876
+ * invocations pays Node startup and module load per frame — which dominates once
877
+ * the browser launch is gone. Callers that already know their whole frame list
878
+ * (visual-evidence capture plans, gallery sweeps) can hand it over once and get
879
+ * a single process, a single daemon handshake, and a single server-ready wait.
880
+ *
881
+ * One frame failing does not abort the batch: a capture plan is more useful with
882
+ * 25 of 26 frames plus a named failure than with nothing, and the caller decides
883
+ * whether a partial set is acceptable.
884
+ */
885
+ async function screenshotBatch(options) {
886
+ const { items, defaults } = options;
887
+ const firstUrl = items[0].url;
888
+ if (options.wait !== false) {
889
+ try {
890
+ await waitForServer(firstUrl, options.waitTimeout || SERVER_READY_TIMEOUT);
891
+ }
892
+ catch (error) {
893
+ console.error('[Sweetlink] Server not available:', error instanceof Error ? error.message : error);
894
+ process.exit(1);
895
+ }
896
+ }
897
+ const resolve = (item) => ({
898
+ selector: item.selector ?? defaults.selector,
899
+ fullPage: item.fullPage ?? defaults.fullPage,
900
+ viewport: item.viewport ?? defaults.viewport,
901
+ hideDevbar: item.hideDevbar ?? defaults.hideDevbar,
902
+ });
903
+ // One handshake for the whole batch. If the daemon can't start we still run
904
+ // every frame in this process — slower per frame, but the caller keeps the
905
+ // single-invocation win instead of the batch failing outright.
906
+ let daemonState = null;
907
+ try {
908
+ daemonState = await ensureDaemon(findProjectRoot(), firstUrl);
909
+ }
910
+ catch (error) {
911
+ console.warn(`[Sweetlink] Daemon unavailable (${error instanceof Error ? error.message : error}) — running the batch against standalone browsers`);
912
+ }
913
+ const engine = daemonState ? 'Daemon (batch)' : 'Playwright (batch fallback)';
914
+ const captured = [];
915
+ for (const [index, item] of items.entries()) {
916
+ const shared = resolve(item);
917
+ try {
918
+ if (daemonState) {
919
+ const resp = await daemonRequest(daemonState, 'screenshot', {
920
+ ...shared,
921
+ url: item.url,
922
+ });
923
+ const data = resp.data;
924
+ ensureDir(item.output);
925
+ fs.writeFileSync(item.output, Buffer.from(data.screenshot, 'base64'));
926
+ captured.push({
927
+ url: item.url,
928
+ output: getRelativePath(item.output),
929
+ ok: true,
930
+ width: data.width,
931
+ height: data.height,
932
+ });
933
+ }
934
+ else {
935
+ const result = await takePlaywrightScreenshot({ ...shared, output: item.output, url: item.url }, 'Playwright (batch fallback)');
936
+ captured.push({
937
+ url: item.url,
938
+ output: result.path,
939
+ ok: true,
940
+ width: result.width,
941
+ height: result.height,
942
+ });
943
+ }
944
+ console.log(`[Sweetlink] [${index + 1}/${items.length}] ${item.url}`);
945
+ }
946
+ catch (error) {
947
+ const message = error instanceof Error ? error.message : String(error);
948
+ captured.push({ url: item.url, output: item.output, ok: false, error: message });
949
+ console.warn(`[Sweetlink] [${index + 1}/${items.length}] FAILED ${item.url} — ${message}`);
950
+ }
951
+ }
952
+ const failed = captured.filter((c) => !c.ok).length;
953
+ console.log(`[Sweetlink] ✓ Batch complete: ${captured.length - failed}/${captured.length} frames via ${engine}`);
954
+ return { engine, captured, failed };
955
+ }
847
956
  async function queryDOM(options) {
848
957
  // Wait for selector if requested (handles hydration timing)
849
958
  if (options.waitFor) {
@@ -1098,7 +1207,7 @@ async function execViaPlaywright(code) {
1098
1207
  let page;
1099
1208
  if (contexts.length > 0) {
1100
1209
  const pages = contexts[0].pages();
1101
- const devUrl = new URL(process.env.SWEETLINK_DEV_URL || 'http://localhost:3000');
1210
+ const devUrl = new URL(defaultDevUrl());
1102
1211
  const devHost = devUrl.hostname;
1103
1212
  const devPort = devUrl.port || (devUrl.protocol === 'https:' ? '443' : '80');
1104
1213
  page = pages.find((p) => p.url().includes(`${devHost}:${devPort}`) || p.url().includes(`127.0.0.1:${devPort}`));
@@ -1109,7 +1218,7 @@ async function execViaPlaywright(code) {
1109
1218
  if (!page) {
1110
1219
  const context = contexts[0] || (await browser.newContext());
1111
1220
  page = await context.newPage();
1112
- await page.goto(process.env.SWEETLINK_DEV_URL || 'http://localhost:3000', {
1221
+ await page.goto(defaultDevUrl(), {
1113
1222
  waitUntil: 'domcontentloaded',
1114
1223
  });
1115
1224
  }
@@ -1808,8 +1917,16 @@ const COMMAND_HELP = {
1808
1917
  - Auto-launches headless browser if no browser connected
1809
1918
 
1810
1919
  Options:
1811
- --url <url> Navigate browser to URL before capturing (default: http://localhost:3000)
1920
+ --url <url> Navigate browser to URL before capturing
1921
+ (default: $SWEETLINK_DEV_URL, else $PORTLESS_URL, else http://localhost:3000)
1812
1922
  Navigates connected browser via WS; if none connected, opens one via Playwright
1923
+ --batch <path|-> Capture many frames in ONE process from a JSON manifest
1924
+ ('-' reads stdin). Array of { url, output, selector?,
1925
+ fullPage?, viewport?, hideDevbar? }; per-item values win,
1926
+ the other flags here supply defaults. One server wait and
1927
+ one daemon handshake for the whole set — use this instead
1928
+ of a shell loop, which pays Node startup per frame.
1929
+ A failed frame is reported and the batch continues.
1813
1930
  --selector <css-selector> CSS selector of element to screenshot
1814
1931
  --output <path> Output file path (default: screenshot-<timestamp>.png)
1815
1932
  --full-page Capture full scrollable page (default: viewport only)
@@ -2481,7 +2598,7 @@ async function runOneBatchCapture(cap) {
2481
2598
  });
2482
2599
  }
2483
2600
  if (mode === 'screenshot') {
2484
- const targetUrl = cap.url ?? 'http://localhost:3000';
2601
+ const targetUrl = cap.url ?? defaultDevUrl();
2485
2602
  const projRoot = findProjectRoot();
2486
2603
  const state = await ensureDaemon(projRoot, targetUrl);
2487
2604
  const resp = await daemonRequest(state, 'screenshot', {
@@ -2625,7 +2742,7 @@ function printErrorContext(error) {
2625
2742
  * Handle the `wait` command: wait for a server to be ready.
2626
2743
  */
2627
2744
  async function handleWaitCommand() {
2628
- const waitUrl = getArg('--url') || 'http://localhost:3000';
2745
+ const waitUrl = getArg('--url') || defaultDevUrl();
2629
2746
  const waitTimeout = getArg('--timeout')
2630
2747
  ? parseInt(getArg('--timeout'), 10)
2631
2748
  : SERVER_READY_TIMEOUT;
@@ -2644,7 +2761,7 @@ async function handleWaitCommand() {
2644
2761
  * Handle the `status` command: quick non-blocking server health check.
2645
2762
  */
2646
2763
  async function handleStatusCommand() {
2647
- const statusUrl = getArg('--url') || 'http://localhost:3000';
2764
+ const statusUrl = getArg('--url') || defaultDevUrl();
2648
2765
  try {
2649
2766
  const parsedUrl = new URL(statusUrl);
2650
2767
  const healthCheckUrl = `${parsedUrl.protocol}//${parsedUrl.host}`;
@@ -2670,6 +2787,25 @@ async function handleStatusCommand() {
2670
2787
  }
2671
2788
  }
2672
2789
  async function handleScreenshotCmd() {
2790
+ // --batch takes a manifest of frames and captures them all in this one
2791
+ // process. Per-frame flags in the manifest win; the top-level flags below
2792
+ // supply the defaults, so `--hide-devbar --full-page --batch plan.json`
2793
+ // behaves like the same flags repeated on every item.
2794
+ const batchPath = getArg('--batch');
2795
+ if (batchPath) {
2796
+ const raw = batchPath === '-' ? fs.readFileSync(0, 'utf-8') : fs.readFileSync(batchPath, 'utf-8');
2797
+ return screenshotBatch({
2798
+ items: parseBatchManifest(raw),
2799
+ defaults: {
2800
+ fullPage: hasFlag('--full-page'),
2801
+ hideDevbar: hasFlag('--hide-devbar'),
2802
+ viewport: getArg('--viewport'),
2803
+ selector: getArg('--selector'),
2804
+ },
2805
+ wait: !hasFlag('--no-wait'),
2806
+ waitTimeout: getArg('--wait-timeout') ? parseInt(getArg('--wait-timeout'), 10) : undefined,
2807
+ });
2808
+ }
2673
2809
  return screenshot({
2674
2810
  selector: getArg('--selector'),
2675
2811
  output: getArg('--output'),
@@ -2693,7 +2829,7 @@ async function handleScreenshotCmd() {
2693
2829
  }
2694
2830
  async function handleInspectCmd() {
2695
2831
  const projRoot = findProjectRoot();
2696
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
2832
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
2697
2833
  const state = await ensureDaemon(projRoot, targetUrl);
2698
2834
  const actionTranscript = [];
2699
2835
  args.forEach((arg, index) => {
@@ -2781,7 +2917,7 @@ async function handleClickCmd() {
2781
2917
  const clickText = getArg('--text');
2782
2918
  const clickIndex = getArg('--index') ? parseInt(getArg('--index'), 10) : 0;
2783
2919
  const projRoot = findProjectRoot();
2784
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
2920
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
2785
2921
  // Route @e refs to daemon
2786
2922
  if (clickTarget && /^@e\d+$/.test(clickTarget)) {
2787
2923
  const state = await ensureDaemon(projRoot, targetUrl);
@@ -2826,7 +2962,7 @@ async function handleClickCmd() {
2826
2962
  async function handleNetworkCmd() {
2827
2963
  if (hasFlag('--failed')) {
2828
2964
  const projRoot = findProjectRoot();
2829
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
2965
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
2830
2966
  const lastN = getArg('--last') ? parseInt(getArg('--last'), 10) : undefined;
2831
2967
  const state = await ensureDaemon(projRoot, targetUrl);
2832
2968
  const resp = await daemonRequest(state, 'network-read', {
@@ -2896,7 +3032,7 @@ async function handleSetupCmd() {
2896
3032
  }
2897
3033
  async function handleConsoleCmd() {
2898
3034
  const projRoot = findProjectRoot();
2899
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3035
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
2900
3036
  const errorsOnly = hasFlag('--errors');
2901
3037
  const lastN = getArg('--last') ? parseInt(getArg('--last'), 10) : undefined;
2902
3038
  const state = await ensureDaemon(projRoot, targetUrl);
@@ -2912,7 +3048,7 @@ async function handleConsoleCmd() {
2912
3048
  async function handleSessionsCmd() {
2913
3049
  const sub = args[1];
2914
3050
  const projRoot = findProjectRoot();
2915
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3051
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
2916
3052
  const state = await ensureDaemon(projRoot, targetUrl);
2917
3053
  const resp = await daemonRequest(state, 'sessions-list');
2918
3054
  const data = resp.data;
@@ -3047,7 +3183,7 @@ async function handleDemoCmd() {
3047
3183
  return { sections: updated.sections.length, exitCode: lastSection.exitCode };
3048
3184
  }
3049
3185
  if (sub === 'screenshot') {
3050
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3186
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3051
3187
  const caption = getArg('--caption') ?? 'Screenshot';
3052
3188
  const daemonState = await ensureDaemon(projRoot, targetUrl);
3053
3189
  const resp = await daemonRequest(daemonState, 'screenshot', {});
@@ -3059,7 +3195,7 @@ async function handleDemoCmd() {
3059
3195
  return { sections: updated.sections.length };
3060
3196
  }
3061
3197
  if (sub === 'snapshot') {
3062
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3198
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3063
3199
  const daemonState = await ensureDaemon(projRoot, targetUrl);
3064
3200
  const resp = await daemonRequest(daemonState, 'snapshot', { interactive: true });
3065
3201
  const data = resp.data;
@@ -3119,7 +3255,7 @@ async function handleDaemonCmd() {
3119
3255
  // so honour --url for status/stop too — otherwise they look up the
3120
3256
  // un-suffixed `daemon.json` and miss the daemon that `start`
3121
3257
  // wrote with --url.
3122
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3258
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3123
3259
  const appPort = extractPort(targetUrl);
3124
3260
  if (subcommand === 'stop') {
3125
3261
  const stopped = await stopDaemon(projRoot, appPort);
@@ -3160,7 +3296,7 @@ async function handleFillCmd() {
3160
3296
  }
3161
3297
  if (/^@e\d+$/.test(fillTarget)) {
3162
3298
  const projRoot = findProjectRoot();
3163
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3299
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3164
3300
  const state = await ensureDaemon(projRoot, targetUrl);
3165
3301
  await daemonRequest(state, 'fill-ref', { ref: fillTarget, value: fillValue });
3166
3302
  console.log(`[Sweetlink] Filled ${fillTarget} with "${fillValue}"`);
@@ -3171,7 +3307,7 @@ async function handleFillCmd() {
3171
3307
  }
3172
3308
  async function handleSnapshotCmd() {
3173
3309
  const projRoot = findProjectRoot();
3174
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3310
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3175
3311
  const interactive = hasFlag('-i') || hasFlag('--interactive');
3176
3312
  const doDiff = hasFlag('-D') || hasFlag('--diff');
3177
3313
  const doAnnotate = hasFlag('-a') || hasFlag('--annotate');
@@ -3394,9 +3530,7 @@ async function handleSimCmd() {
3394
3530
  console.log(`[Sweetlink] ${recResult.recordingClosed ? '✓' : '⚠'} ${getRelativePath(output)} · ` +
3395
3531
  `${recResult.durationSec.toFixed(1)}s · ${sizeKb}KB · ${recResult.device} · exit=${recResult.exitCode}` +
3396
3532
  tapSuffix +
3397
- (recResult.recordingClosed
3398
- ? ''
3399
- : ' (recording was force-killed; mp4 may be incomplete)'));
3533
+ (recResult.recordingClosed ? '' : ' (recording was force-killed; mp4 may be incomplete)'));
3400
3534
  const result = {
3401
3535
  path: output,
3402
3536
  device: recResult.device,
@@ -3487,7 +3621,7 @@ async function handleTermCmd() {
3487
3621
  }
3488
3622
  async function handleRecordCmd() {
3489
3623
  const projRoot = findProjectRoot();
3490
- const targetUrl = getArg('--url') ?? 'http://localhost:3000';
3624
+ const targetUrl = getArg('--url') ?? defaultDevUrl();
3491
3625
  const subcommand = args[1];
3492
3626
  const state = await ensureDaemon(projRoot, targetUrl);
3493
3627
  if (subcommand === 'start') {
@@ -3505,8 +3639,7 @@ async function handleRecordCmd() {
3505
3639
  params.trace = true;
3506
3640
  const resp = await daemonRequest(state, 'record-start', params);
3507
3641
  const data = resp.data;
3508
- console.log(`[Sweetlink] Recording started: ${data.sessionId}` +
3509
- (data.label ? ` (${data.label})` : ''));
3642
+ console.log(`[Sweetlink] Recording started: ${data.sessionId}${data.label ? ` (${data.label})` : ''}`);
3510
3643
  return data;
3511
3644
  }
3512
3645
  if (subcommand === 'stop') {