@vforsh/argus 0.1.10 → 0.1.11

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 (64) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/argus.js +1032 -1120
  3. package/dist/cdp/sendCdpCommand.d.ts +11 -0
  4. package/dist/cdp/sendCdpCommand.d.ts.map +1 -0
  5. package/dist/cdp/sendCdpCommand.js +103 -0
  6. package/dist/cdp/sendCdpCommand.js.map +1 -0
  7. package/dist/cli/program.js +1 -1
  8. package/dist/cli/program.js.map +1 -1
  9. package/dist/commands/chrome.d.ts.map +1 -1
  10. package/dist/commands/chrome.js +1 -99
  11. package/dist/commands/chrome.js.map +1 -1
  12. package/dist/commands/chromeStart.d.ts.map +1 -1
  13. package/dist/commands/chromeStart.js +14 -44
  14. package/dist/commands/chromeStart.js.map +1 -1
  15. package/dist/commands/list.d.ts.map +1 -1
  16. package/dist/commands/list.js +3 -5
  17. package/dist/commands/list.js.map +1 -1
  18. package/dist/commands/logs.d.ts.map +1 -1
  19. package/dist/commands/logs.js +10 -57
  20. package/dist/commands/logs.js.map +1 -1
  21. package/dist/commands/net.d.ts.map +1 -1
  22. package/dist/commands/net.js +8 -22
  23. package/dist/commands/net.js.map +1 -1
  24. package/dist/commands/netTail.d.ts.map +1 -1
  25. package/dist/commands/netTail.js +11 -25
  26. package/dist/commands/netTail.js.map +1 -1
  27. package/dist/commands/page.d.ts.map +1 -1
  28. package/dist/commands/page.js +1 -99
  29. package/dist/commands/page.js.map +1 -1
  30. package/dist/commands/start.d.ts.map +1 -1
  31. package/dist/commands/start.js +6 -46
  32. package/dist/commands/start.js.map +1 -1
  33. package/dist/commands/startShared.d.ts +32 -0
  34. package/dist/commands/startShared.d.ts.map +1 -0
  35. package/dist/commands/startShared.js +74 -0
  36. package/dist/commands/startShared.js.map +1 -0
  37. package/dist/commands/tail.d.ts.map +1 -1
  38. package/dist/commands/tail.js +8 -43
  39. package/dist/commands/tail.js.map +1 -1
  40. package/dist/commands/trace.d.ts.map +1 -1
  41. package/dist/commands/trace.js +7 -9
  42. package/dist/commands/trace.js.map +1 -1
  43. package/dist/commands/watcherStart.d.ts.map +1 -1
  44. package/dist/commands/watcherStart.js +10 -51
  45. package/dist/commands/watcherStart.js.map +1 -1
  46. package/dist/eval/evalClient.js +5 -14
  47. package/dist/eval/evalClient.js.map +1 -1
  48. package/dist/httpClient.d.ts +1 -12
  49. package/dist/httpClient.d.ts.map +1 -1
  50. package/dist/httpClient.js +1 -84
  51. package/dist/httpClient.js.map +1 -1
  52. package/dist/runtime-code/strings.js +9 -1
  53. package/dist/runtime-code/strings.js.map +1 -1
  54. package/dist/watchers/queryParams.d.ts +34 -0
  55. package/dist/watchers/queryParams.d.ts.map +1 -0
  56. package/dist/watchers/queryParams.js +80 -0
  57. package/dist/watchers/queryParams.js.map +1 -0
  58. package/dist/watchers/requestWatcher.d.ts +3 -0
  59. package/dist/watchers/requestWatcher.d.ts.map +1 -1
  60. package/dist/watchers/requestWatcher.js +15 -9
  61. package/dist/watchers/requestWatcher.js.map +1 -1
  62. package/dist/watchers/resolveWatcher.js +2 -3
  63. package/dist/watchers/resolveWatcher.js.map +1 -1
  64. package/package.json +1 -1
package/dist/argus.js CHANGED
@@ -2131,7 +2131,7 @@ var {
2131
2131
  // dist/cli/program.js
2132
2132
  function createProgram() {
2133
2133
  const program2 = new Command;
2134
- program2.name("argus").description("Argus CLI for local watcher servers").version("0.1.0").configureOutput({
2134
+ program2.name("argus").description("Argus CLI for local watcher servers").version("0.1.11").configureOutput({
2135
2135
  outputError: (str, write) => write(str)
2136
2136
  }).showSuggestionAfterError(true).exitOverride((error) => {
2137
2137
  if (error.code === "commander.helpDisplayed" || error.code === "commander.version") {
@@ -2606,38 +2606,7 @@ var getOriginHost = (origin) => {
2606
2606
  };
2607
2607
  var isTrackingCookieName = (name) => TRACKING_COOKIE_PATTERNS.some((pattern) => pattern.test(name));
2608
2608
  var normalizeCookieDomain = (domain) => domain.trim().toLowerCase().replace(/^\./, "");
2609
- // dist/registry.js
2610
- var loadRegistry = async () => {
2611
- const { registry: registry2, warnings } = await readRegistry();
2612
- for (const warning of warnings) {
2613
- console.error(warning);
2614
- }
2615
- return registry2;
2616
- };
2617
- var pruneRegistry = async (ttlMs = DEFAULT_TTL_MS) => {
2618
- return updateRegistry((registry2) => {
2619
- const { registry: pruned } = pruneStaleWatchers(registry2, Date.now(), ttlMs);
2620
- return pruned;
2621
- });
2622
- };
2623
- var removeWatcherAndPersist = async (id) => {
2624
- return updateRegistry((registry2) => removeWatcherEntry(registry2, id));
2625
- };
2626
- var removeWatchersAndPersist = async (ids) => {
2627
- if (ids.length === 0) {
2628
- const { registry: registry2 } = await readRegistry();
2629
- return registry2;
2630
- }
2631
- return updateRegistry((registry2) => {
2632
- let next = registry2;
2633
- for (const id of ids) {
2634
- next = removeWatcherEntry(next, id);
2635
- }
2636
- return next;
2637
- });
2638
- };
2639
-
2640
- // dist/httpClient.js
2609
+ // ../argus-core/dist/http/fetch.js
2641
2610
  var fetchJson = async (url, options = {}) => {
2642
2611
  const controller = new AbortController;
2643
2612
  const timeoutMs = options.timeoutMs ?? 5000;
@@ -2667,24 +2636,6 @@ var fetchJson = async (url, options = {}) => {
2667
2636
  clearTimeout(timer);
2668
2637
  }
2669
2638
  };
2670
- var isAbortError = (error) => {
2671
- if (!error || typeof error !== "object" || !("name" in error)) {
2672
- return false;
2673
- }
2674
- return error.name === "AbortError";
2675
- };
2676
- var extractErrorMessage = async (response) => {
2677
- try {
2678
- const body = await response.json();
2679
- if (body && typeof body === "object" && "error" in body) {
2680
- const error = body.error;
2681
- if (error && typeof error === "object" && "message" in error) {
2682
- return error.message;
2683
- }
2684
- }
2685
- } catch {}
2686
- return null;
2687
- };
2688
2639
  var fetchText = async (url, options = {}) => {
2689
2640
  const controller = new AbortController;
2690
2641
  const timeoutMs = options.timeoutMs ?? 5000;
@@ -2710,50 +2661,53 @@ var fetchText = async (url, options = {}) => {
2710
2661
  clearTimeout(timer);
2711
2662
  }
2712
2663
  };
2713
-
2714
- // dist/cli/parse.js
2715
- var formatError = (error) => {
2716
- if (!error) {
2717
- return "unknown error";
2718
- }
2719
- if (error instanceof Error) {
2720
- return error.message;
2664
+ var isAbortError = (error) => {
2665
+ if (!error || typeof error !== "object" || !("name" in error)) {
2666
+ return false;
2721
2667
  }
2722
- return String(error);
2668
+ return error.name === "AbortError";
2723
2669
  };
2724
- var parseNumber = (value) => {
2725
- if (!value) {
2726
- return;
2727
- }
2728
- const parsed = Number(value);
2729
- if (!Number.isFinite(parsed)) {
2730
- return;
2731
- }
2732
- return parsed;
2670
+ var extractErrorMessage = async (response) => {
2671
+ try {
2672
+ const body = await response.json();
2673
+ if (body && typeof body === "object" && "error" in body) {
2674
+ const error = body.error;
2675
+ if (error && typeof error === "object" && "message" in error) {
2676
+ return error.message;
2677
+ }
2678
+ }
2679
+ } catch {}
2680
+ return null;
2733
2681
  };
2734
- var parsePositiveInt = (value, options) => {
2735
- if (value === undefined) {
2736
- return;
2737
- }
2738
- const parsed = Number(value);
2739
- if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
2740
- return;
2741
- }
2742
- const min = options?.allowZero ? 0 : 1;
2743
- if (parsed < min) {
2744
- return;
2682
+ // dist/registry.js
2683
+ var loadRegistry = async () => {
2684
+ const { registry: registry2, warnings } = await readRegistry();
2685
+ for (const warning of warnings) {
2686
+ console.error(warning);
2745
2687
  }
2746
- return parsed;
2688
+ return registry2;
2747
2689
  };
2748
- var normalizeQueryValue = (value) => {
2749
- if (value == null) {
2750
- return;
2751
- }
2752
- const trimmed = value.trim();
2753
- if (!trimmed) {
2754
- return;
2690
+ var pruneRegistry = async (ttlMs = DEFAULT_TTL_MS) => {
2691
+ return updateRegistry((registry2) => {
2692
+ const { registry: pruned } = pruneStaleWatchers(registry2, Date.now(), ttlMs);
2693
+ return pruned;
2694
+ });
2695
+ };
2696
+ var removeWatcherAndPersist = async (id) => {
2697
+ return updateRegistry((registry2) => removeWatcherEntry(registry2, id));
2698
+ };
2699
+ var removeWatchersAndPersist = async (ids) => {
2700
+ if (ids.length === 0) {
2701
+ const { registry: registry2 } = await readRegistry();
2702
+ return registry2;
2755
2703
  }
2756
- return trimmed;
2704
+ return updateRegistry((registry2) => {
2705
+ let next = registry2;
2706
+ for (const id of ids) {
2707
+ next = removeWatcherEntry(next, id);
2708
+ }
2709
+ return next;
2710
+ });
2757
2711
  };
2758
2712
 
2759
2713
  // dist/output/format.js
@@ -2847,151 +2801,49 @@ var createOutput = (options) => {
2847
2801
  writeWarn
2848
2802
  };
2849
2803
  };
2850
-
2851
- // dist/commands/chrome.js
2852
- import { execFile } from "node:child_process";
2853
-
2854
- // dist/cdp/resolveCdpEndpoint.js
2855
- var parsePort = (value) => {
2856
- const parsed = Number.parseInt(value, 10);
2857
- if (!Number.isFinite(parsed) || parsed < 1 || parsed > 65535) {
2858
- return null;
2859
- }
2860
- return parsed;
2861
- };
2862
- var parseCdpOption = (value) => {
2863
- const trimmed = value.trim();
2864
- if (!trimmed) {
2865
- return { error: "Invalid --cdp value: empty host:port." };
2866
- }
2867
- const separator = trimmed.lastIndexOf(":");
2868
- if (separator <= 0 || separator === trimmed.length - 1) {
2869
- return { error: `Invalid --cdp value "${value}": expected <host:port>.` };
2870
- }
2871
- const host = trimmed.slice(0, separator);
2872
- const portValue = trimmed.slice(separator + 1);
2873
- const port = parsePort(portValue);
2874
- if (port == null) {
2875
- return { error: `Invalid --cdp port: ${portValue}. Must be an integer 1-65535.` };
2876
- }
2877
- return { host, port };
2878
- };
2879
- var resolveCdpEndpoint = async (options) => {
2880
- if (options.cdp && options.id) {
2881
- return { ok: false, error: "Cannot combine --cdp with --id.", exitCode: 2 };
2882
- }
2883
- if (options.cdp) {
2884
- const parsed = parseCdpOption(options.cdp);
2885
- if ("error" in parsed) {
2886
- return { ok: false, error: parsed.error, exitCode: 2 };
2887
- }
2888
- return { ok: true, host: parsed.host, port: parsed.port };
2804
+ // dist/cli/parse.js
2805
+ var formatError = (error) => {
2806
+ if (!error) {
2807
+ return "unknown error";
2889
2808
  }
2890
- if (options.id != null) {
2891
- let registry2;
2892
- try {
2893
- registry2 = await pruneRegistry();
2894
- } catch (error) {
2895
- return { ok: false, error: `Failed to load registry: ${error instanceof Error ? error.message : error}`, exitCode: 1 };
2896
- }
2897
- const watcher = registry2.watchers[options.id];
2898
- if (!watcher) {
2899
- return { ok: false, error: `Watcher not found: ${options.id}`, exitCode: 2 };
2900
- }
2901
- if (!watcher.chrome) {
2902
- return { ok: false, error: `Watcher "${options.id}" has no chrome connection configured.`, exitCode: 2 };
2903
- }
2904
- return { ok: true, host: watcher.chrome.host, port: watcher.chrome.port };
2809
+ if (error instanceof Error) {
2810
+ return error.message;
2905
2811
  }
2906
- return { ok: true, host: "127.0.0.1", port: 9222 };
2812
+ return String(error);
2907
2813
  };
2908
-
2909
- // dist/cdp/selectTarget.js
2910
- var normalizeFilter = (value) => {
2814
+ var parseNumber = (value) => {
2911
2815
  if (!value) {
2912
- return null;
2816
+ return;
2913
2817
  }
2914
- const trimmed = value.trim();
2915
- return trimmed ? trimmed.toLowerCase() : null;
2916
- };
2917
- var filterTargets = (targets, filters) => {
2918
- const title = normalizeFilter(filters.title);
2919
- const url = normalizeFilter(filters.url);
2920
- const match = normalizeFilter(filters.match);
2921
- if (!title && !url && !match) {
2922
- return targets;
2818
+ const parsed = Number(value);
2819
+ if (!Number.isFinite(parsed)) {
2820
+ return;
2923
2821
  }
2924
- return targets.filter((target) => {
2925
- const targetTitle = (target.title ?? "").toLowerCase();
2926
- const targetUrl = (target.url ?? "").toLowerCase();
2927
- const combined = `${targetTitle} ${targetUrl}`.trim();
2928
- if (title && !targetTitle.includes(title)) {
2929
- return false;
2930
- }
2931
- if (url && !targetUrl.includes(url)) {
2932
- return false;
2933
- }
2934
- if (match && !combined.includes(match)) {
2935
- return false;
2936
- }
2937
- return true;
2938
- });
2822
+ return parsed;
2939
2823
  };
2940
- var selectTargetFromCandidates = async (candidates, output, options) => {
2941
- if (candidates.length === 0) {
2942
- return { ok: false, error: options.messages.empty, exitCode: 2 };
2943
- }
2944
- if (candidates.length === 1) {
2945
- return { ok: true, target: candidates[0] };
2946
- }
2947
- if (!options.interactive) {
2948
- writeCandidateList(candidates, output);
2949
- return { ok: false, error: options.messages.ambiguous, exitCode: 2 };
2950
- }
2951
- writeCandidateList(candidates, output, true);
2952
- output.writeHuman("Select target by number or id:");
2953
- const selection = await readLineOnce();
2954
- if (!selection) {
2955
- return { ok: false, error: "No selection provided.", exitCode: 2 };
2824
+ var parsePositiveInt = (value, options) => {
2825
+ if (value === undefined) {
2826
+ return;
2956
2827
  }
2957
- const numeric = Number.parseInt(selection, 10);
2958
- if (Number.isFinite(numeric) && numeric >= 1 && numeric <= candidates.length) {
2959
- return { ok: true, target: candidates[numeric - 1] };
2828
+ const parsed = Number(value);
2829
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
2830
+ return;
2960
2831
  }
2961
- const byId = candidates.find((candidate) => candidate.id === selection);
2962
- if (byId) {
2963
- return { ok: true, target: byId };
2832
+ const min = options?.allowZero ? 0 : 1;
2833
+ if (parsed < min) {
2834
+ return;
2964
2835
  }
2965
- return { ok: false, error: "Invalid selection.", exitCode: 2 };
2836
+ return parsed;
2966
2837
  };
2967
- var writeCandidateList = (candidates, output, numbered = false) => {
2968
- for (const [index, target] of candidates.entries()) {
2969
- const indexLabel = numbered ? `[${index + 1}] ` : "";
2970
- const title = target.title ? ` ${target.title}` : "";
2971
- const targetUrl = target.url ? ` ${target.url}` : "";
2972
- output.writeHuman(`${indexLabel}${target.id} ${target.type}${title}${targetUrl}`);
2838
+ var normalizeQueryValue = (value) => {
2839
+ if (value == null) {
2840
+ return;
2973
2841
  }
2974
- };
2975
- var readLineOnce = async () => {
2976
- return await new Promise((resolve) => {
2977
- const onData = (data) => {
2978
- cleanup();
2979
- resolve(data.toString("utf8").trim());
2980
- };
2981
- const onError = () => {
2982
- cleanup();
2983
- resolve("");
2984
- };
2985
- const cleanup = () => {
2986
- process.stdin.off("data", onData);
2987
- process.stdin.off("error", onError);
2988
- process.stdin.pause();
2989
- };
2990
- process.stdin.setEncoding("utf8");
2991
- process.stdin.once("data", onData);
2992
- process.stdin.once("error", onError);
2993
- process.stdin.resume();
2994
- });
2842
+ const trimmed = value.trim();
2843
+ if (!trimmed) {
2844
+ return;
2845
+ }
2846
+ return trimmed;
2995
2847
  };
2996
2848
 
2997
2849
  // dist/watchers/resolveWatcher.js
@@ -3032,22 +2884,139 @@ var resolveWatcher = async (input) => {
3032
2884
  return { ok: false, error: "Watcher id required.", exitCode: 2, candidates: watchers };
3033
2885
  };
3034
2886
  var checkWatcherStatus = async (watcher) => {
3035
- const url = `http://${watcher.host}:${watcher.port}/status`;
3036
2887
  try {
3037
- const status = await fetchJson(url, { timeoutMs: 1500 });
2888
+ const status = await fetchWatcherJson(watcher, { path: "/status", timeoutMs: 1500 });
3038
2889
  return { ok: true, status };
3039
2890
  } catch (error) {
3040
2891
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
3041
2892
  }
3042
2893
  };
3043
2894
 
2895
+ // dist/watchers/requestWatcher.js
2896
+ var buildWatcherUrl = (watcher, path4, query) => {
2897
+ const qs = query?.toString();
2898
+ return `http://${watcher.host}:${watcher.port}${path4}${qs ? `?${qs}` : ""}`;
2899
+ };
2900
+ var formatWatcherTransportError = (watcher, error) => `${watcher.id}: failed to reach watcher (${formatError(error)})`;
2901
+ async function fetchWatcherJson(watcher, input) {
2902
+ return fetchJson(buildWatcherUrl(watcher, input.path, input.query), {
2903
+ method: input.method,
2904
+ body: input.body,
2905
+ timeoutMs: input.timeoutMs,
2906
+ returnErrorResponse: input.returnErrorResponse
2907
+ });
2908
+ }
2909
+ async function requestWatcherJson(input) {
2910
+ const resolved = await resolveWatcher({ id: input.id });
2911
+ if (!resolved.ok) {
2912
+ return {
2913
+ ok: false,
2914
+ exitCode: resolved.exitCode,
2915
+ message: resolved.error,
2916
+ candidates: resolved.candidates
2917
+ };
2918
+ }
2919
+ const { watcher } = resolved;
2920
+ try {
2921
+ const data = await fetchWatcherJson(watcher, input);
2922
+ return { ok: true, watcher, data };
2923
+ } catch (error) {
2924
+ return {
2925
+ ok: false,
2926
+ watcher,
2927
+ exitCode: 1,
2928
+ message: formatWatcherTransportError(watcher, error)
2929
+ };
2930
+ }
2931
+ }
2932
+ async function resolveWatcherOrExit(input, output) {
2933
+ const resolved = await resolveWatcher(input);
2934
+ if (!resolved.ok) {
2935
+ writeResolveError(resolved, output);
2936
+ return null;
2937
+ }
2938
+ return { watcher: resolved.watcher };
2939
+ }
2940
+ function writeRequestError(result, output) {
2941
+ output.writeWarn(result.message);
2942
+ if (result.candidates && result.candidates.length > 0) {
2943
+ for (const watcher of result.candidates) {
2944
+ output.writeWarn(formatWatcherLine(watcher));
2945
+ }
2946
+ output.writeWarn("Hint: run `argus list` to see all watchers.");
2947
+ }
2948
+ process.exitCode = result.exitCode;
2949
+ }
2950
+ function writeResolveError(resolved, output) {
2951
+ output.writeWarn(resolved.error);
2952
+ if (resolved.candidates && resolved.candidates.length > 0) {
2953
+ for (const watcher of resolved.candidates) {
2954
+ output.writeWarn(formatWatcherLine(watcher));
2955
+ }
2956
+ output.writeWarn("Hint: run `argus list` to see all watchers.");
2957
+ }
2958
+ process.exitCode = resolved.exitCode;
2959
+ }
2960
+
3044
2961
  // dist/commands/chrome.js
3045
- var normalizeUrl = (url) => {
3046
- if (url.startsWith("http://") || url.startsWith("https://")) {
3047
- return url;
2962
+ import { execFile } from "node:child_process";
2963
+
2964
+ // dist/cdp/resolveCdpEndpoint.js
2965
+ var parsePort = (value) => {
2966
+ const parsed = Number.parseInt(value, 10);
2967
+ if (!Number.isFinite(parsed) || parsed < 1 || parsed > 65535) {
2968
+ return null;
3048
2969
  }
3049
- return `http://${url}`;
2970
+ return parsed;
2971
+ };
2972
+ var parseCdpOption = (value) => {
2973
+ const trimmed = value.trim();
2974
+ if (!trimmed) {
2975
+ return { error: "Invalid --cdp value: empty host:port." };
2976
+ }
2977
+ const separator = trimmed.lastIndexOf(":");
2978
+ if (separator <= 0 || separator === trimmed.length - 1) {
2979
+ return { error: `Invalid --cdp value "${value}": expected <host:port>.` };
2980
+ }
2981
+ const host = trimmed.slice(0, separator);
2982
+ const portValue = trimmed.slice(separator + 1);
2983
+ const port = parsePort(portValue);
2984
+ if (port == null) {
2985
+ return { error: `Invalid --cdp port: ${portValue}. Must be an integer 1-65535.` };
2986
+ }
2987
+ return { host, port };
3050
2988
  };
2989
+ var resolveCdpEndpoint = async (options) => {
2990
+ if (options.cdp && options.id) {
2991
+ return { ok: false, error: "Cannot combine --cdp with --id.", exitCode: 2 };
2992
+ }
2993
+ if (options.cdp) {
2994
+ const parsed = parseCdpOption(options.cdp);
2995
+ if ("error" in parsed) {
2996
+ return { ok: false, error: parsed.error, exitCode: 2 };
2997
+ }
2998
+ return { ok: true, host: parsed.host, port: parsed.port };
2999
+ }
3000
+ if (options.id != null) {
3001
+ let registry2;
3002
+ try {
3003
+ registry2 = await pruneRegistry();
3004
+ } catch (error) {
3005
+ return { ok: false, error: `Failed to load registry: ${error instanceof Error ? error.message : error}`, exitCode: 1 };
3006
+ }
3007
+ const watcher = registry2.watchers[options.id];
3008
+ if (!watcher) {
3009
+ return { ok: false, error: `Watcher not found: ${options.id}`, exitCode: 2 };
3010
+ }
3011
+ if (!watcher.chrome) {
3012
+ return { ok: false, error: `Watcher "${options.id}" has no chrome connection configured.`, exitCode: 2 };
3013
+ }
3014
+ return { ok: true, host: watcher.chrome.host, port: watcher.chrome.port };
3015
+ }
3016
+ return { ok: true, host: "127.0.0.1", port: 9222 };
3017
+ };
3018
+
3019
+ // dist/cdp/sendCdpCommand.js
3051
3020
  var getWebSocketCtor = () => {
3052
3021
  const ctor = globalThis.WebSocket;
3053
3022
  return ctor ?? null;
@@ -3100,9 +3069,9 @@ var sendCdpCommand = async (wsUrl, payload, timeoutMs = 5000) => {
3100
3069
  } catch {}
3101
3070
  if (error) {
3102
3071
  reject(error);
3103
- } else {
3104
- resolve();
3072
+ return;
3105
3073
  }
3074
+ resolve();
3106
3075
  };
3107
3076
  const onOpen = () => {
3108
3077
  try {
@@ -3142,6 +3111,102 @@ var sendCdpCommand = async (wsUrl, payload, timeoutMs = 5000) => {
3142
3111
  ws.addEventListener("close", onClose);
3143
3112
  });
3144
3113
  };
3114
+
3115
+ // dist/cdp/selectTarget.js
3116
+ var normalizeFilter = (value) => {
3117
+ if (!value) {
3118
+ return null;
3119
+ }
3120
+ const trimmed = value.trim();
3121
+ return trimmed ? trimmed.toLowerCase() : null;
3122
+ };
3123
+ var filterTargets = (targets, filters) => {
3124
+ const title = normalizeFilter(filters.title);
3125
+ const url = normalizeFilter(filters.url);
3126
+ const match = normalizeFilter(filters.match);
3127
+ if (!title && !url && !match) {
3128
+ return targets;
3129
+ }
3130
+ return targets.filter((target) => {
3131
+ const targetTitle = (target.title ?? "").toLowerCase();
3132
+ const targetUrl = (target.url ?? "").toLowerCase();
3133
+ const combined = `${targetTitle} ${targetUrl}`.trim();
3134
+ if (title && !targetTitle.includes(title)) {
3135
+ return false;
3136
+ }
3137
+ if (url && !targetUrl.includes(url)) {
3138
+ return false;
3139
+ }
3140
+ if (match && !combined.includes(match)) {
3141
+ return false;
3142
+ }
3143
+ return true;
3144
+ });
3145
+ };
3146
+ var selectTargetFromCandidates = async (candidates, output, options) => {
3147
+ if (candidates.length === 0) {
3148
+ return { ok: false, error: options.messages.empty, exitCode: 2 };
3149
+ }
3150
+ if (candidates.length === 1) {
3151
+ return { ok: true, target: candidates[0] };
3152
+ }
3153
+ if (!options.interactive) {
3154
+ writeCandidateList(candidates, output);
3155
+ return { ok: false, error: options.messages.ambiguous, exitCode: 2 };
3156
+ }
3157
+ writeCandidateList(candidates, output, true);
3158
+ output.writeHuman("Select target by number or id:");
3159
+ const selection = await readLineOnce();
3160
+ if (!selection) {
3161
+ return { ok: false, error: "No selection provided.", exitCode: 2 };
3162
+ }
3163
+ const numeric = Number.parseInt(selection, 10);
3164
+ if (Number.isFinite(numeric) && numeric >= 1 && numeric <= candidates.length) {
3165
+ return { ok: true, target: candidates[numeric - 1] };
3166
+ }
3167
+ const byId = candidates.find((candidate) => candidate.id === selection);
3168
+ if (byId) {
3169
+ return { ok: true, target: byId };
3170
+ }
3171
+ return { ok: false, error: "Invalid selection.", exitCode: 2 };
3172
+ };
3173
+ var writeCandidateList = (candidates, output, numbered = false) => {
3174
+ for (const [index, target] of candidates.entries()) {
3175
+ const indexLabel = numbered ? `[${index + 1}] ` : "";
3176
+ const title = target.title ? ` ${target.title}` : "";
3177
+ const targetUrl = target.url ? ` ${target.url}` : "";
3178
+ output.writeHuman(`${indexLabel}${target.id} ${target.type}${title}${targetUrl}`);
3179
+ }
3180
+ };
3181
+ var readLineOnce = async () => {
3182
+ return await new Promise((resolve) => {
3183
+ const onData = (data) => {
3184
+ cleanup();
3185
+ resolve(data.toString("utf8").trim());
3186
+ };
3187
+ const onError = () => {
3188
+ cleanup();
3189
+ resolve("");
3190
+ };
3191
+ const cleanup = () => {
3192
+ process.stdin.off("data", onData);
3193
+ process.stdin.off("error", onError);
3194
+ process.stdin.pause();
3195
+ };
3196
+ process.stdin.setEncoding("utf8");
3197
+ process.stdin.once("data", onData);
3198
+ process.stdin.once("error", onError);
3199
+ process.stdin.resume();
3200
+ });
3201
+ };
3202
+
3203
+ // dist/commands/chrome.js
3204
+ var normalizeUrl = (url) => {
3205
+ if (url.startsWith("http://") || url.startsWith("https://")) {
3206
+ return url;
3207
+ }
3208
+ return `http://${url}`;
3209
+ };
3145
3210
  var runChromeVersion = async (options) => {
3146
3211
  const output = createOutput(options);
3147
3212
  const endpoint = await resolveCdpEndpoint(options);
@@ -3590,12 +3655,11 @@ var listWatchers = async (options, output) => {
3590
3655
  return [];
3591
3656
  const results = [];
3592
3657
  for (const watcher of watchers) {
3593
- const url = `http://${watcher.host}:${watcher.port}/status`;
3594
3658
  try {
3595
- const status = await fetchJson(url, { timeoutMs: 2000 });
3659
+ const status = await fetchWatcherJson(watcher, { path: "/status", timeoutMs: 2000 });
3596
3660
  results.push({ watcher, status });
3597
3661
  } catch (error) {
3598
- output.writeWarn(`${watcher.id}: failed to reach watcher (${formatError(error)})`);
3662
+ output.writeWarn(formatWatcherTransportError(watcher, error));
3599
3663
  results.push({ watcher });
3600
3664
  }
3601
3665
  }
@@ -3604,11 +3668,6 @@ var listWatchers = async (options, output) => {
3604
3668
 
3605
3669
  // dist/commands/start.js
3606
3670
  import { rmSync as rmSync2 } from "node:fs";
3607
- import fs7 from "node:fs/promises";
3608
-
3609
- // ../argus-watcher/dist/index.js
3610
- import os3 from "node:os";
3611
- import path7 from "node:path";
3612
3671
 
3613
3672
  // ../../node_modules/.bun/emittery@1.2.0/node_modules/emittery/maps.js
3614
3673
  var anyMap = new WeakMap;
@@ -4056,6 +4115,72 @@ Object.defineProperty(Emittery, "listenerRemoved", {
4056
4115
  configurable: false
4057
4116
  });
4058
4117
 
4118
+ // ../argus-watcher/dist/registry/registry.js
4119
+ var resolveUniqueWatcherId = async (id) => {
4120
+ const { registry: registry2 } = await readRegistry();
4121
+ const staleIds = [];
4122
+ const isIdAvailable = (candidate) => {
4123
+ const existing = registry2.watchers[candidate];
4124
+ if (!existing) {
4125
+ return true;
4126
+ }
4127
+ if (existing.pid == null || !isProcessAlive(existing.pid)) {
4128
+ staleIds.push(candidate);
4129
+ return true;
4130
+ }
4131
+ return false;
4132
+ };
4133
+ let resolvedId = id;
4134
+ if (!isIdAvailable(id)) {
4135
+ let suffix = 2;
4136
+ while (!isIdAvailable(`${id}-${suffix}`)) {
4137
+ suffix++;
4138
+ }
4139
+ resolvedId = `${id}-${suffix}`;
4140
+ }
4141
+ if (staleIds.length > 0) {
4142
+ await updateRegistry((reg) => {
4143
+ let next = reg;
4144
+ for (const staleId of staleIds) {
4145
+ next = removeWatcherEntry(next, staleId);
4146
+ }
4147
+ return next;
4148
+ });
4149
+ }
4150
+ return resolvedId;
4151
+ };
4152
+ var isProcessAlive = (pid) => {
4153
+ try {
4154
+ process.kill(pid, 0);
4155
+ return true;
4156
+ } catch {
4157
+ return false;
4158
+ }
4159
+ };
4160
+ var announceWatcher = async (watcher) => {
4161
+ await updateRegistry((registry2) => setWatcherEntry(registry2, watcher));
4162
+ };
4163
+ var updateWatcherHeartbeat = async (watcher) => {
4164
+ await announceWatcher(watcher);
4165
+ };
4166
+ var removeWatcher = async (id) => {
4167
+ await updateRegistry((registry2) => removeWatcherEntry(registry2, id));
4168
+ };
4169
+ var startRegistryHeartbeat = (getWatcher, intervalMs = 15000) => {
4170
+ const timer = setInterval(() => {
4171
+ const watcher = getWatcher();
4172
+ watcher.updatedAt = Date.now();
4173
+ updateWatcherHeartbeat(watcher);
4174
+ }, intervalMs);
4175
+ return {
4176
+ stop: () => clearInterval(timer)
4177
+ };
4178
+ };
4179
+
4180
+ // ../argus-watcher/dist/startWatcherRuntime.js
4181
+ import os3 from "node:os";
4182
+ import path7 from "node:path";
4183
+
4059
4184
  // ../argus-watcher/dist/buffer/LogBuffer.js
4060
4185
  class LogBuffer {
4061
4186
  maxSize;
@@ -5156,6 +5281,33 @@ var handle14 = async (req, res, _url, ctx) => {
5156
5281
  }
5157
5282
  };
5158
5283
 
5284
+ // ../argus-watcher/dist/http/routes/domSelectorRoute.js
5285
+ var readDomSelectorPayload = async (req, res) => {
5286
+ const payload = await readJsonBody(req, res);
5287
+ if (!payload) {
5288
+ return null;
5289
+ }
5290
+ if (!payload.selector || typeof payload.selector !== "string") {
5291
+ respondInvalidBody(res, "selector is required");
5292
+ return null;
5293
+ }
5294
+ const all = payload.all ?? false;
5295
+ if (typeof all !== "boolean") {
5296
+ respondInvalidBody(res, "all must be a boolean");
5297
+ return null;
5298
+ }
5299
+ return { payload, all };
5300
+ };
5301
+ var respondMultipleMatches = (res, matches, action) => {
5302
+ respondJson(res, {
5303
+ ok: false,
5304
+ error: {
5305
+ message: `Selector matched ${matches} elements; pass all=true to ${action} all matches`,
5306
+ code: "multiple_matches"
5307
+ }
5308
+ }, 400);
5309
+ };
5310
+
5159
5311
  // ../argus-watcher/dist/cdp/text-filter.js
5160
5312
  var filterNodesByText = async (session, nodeIds, text) => {
5161
5313
  const pattern = parseTextPattern(text);
@@ -5592,17 +5744,11 @@ var fillResolvedNodes = async (session, nodeIds, value) => {
5592
5744
  };
5593
5745
  // ../argus-watcher/dist/http/routes/postDomTree.js
5594
5746
  var handle15 = async (req, res, _url, ctx) => {
5595
- const payload = await readJsonBody(req, res);
5596
- if (!payload) {
5747
+ const parsed = await readDomSelectorPayload(req, res);
5748
+ if (!parsed) {
5597
5749
  return;
5598
5750
  }
5599
- if (!payload.selector || typeof payload.selector !== "string") {
5600
- return respondInvalidBody(res, "selector is required");
5601
- }
5602
- const all = payload.all ?? false;
5603
- if (typeof all !== "boolean") {
5604
- return respondInvalidBody(res, "all must be a boolean");
5605
- }
5751
+ const { payload, all } = parsed;
5606
5752
  emitRequest(ctx, res, "dom/tree");
5607
5753
  try {
5608
5754
  const response = await fetchDomSubtreeBySelector(ctx.cdpSession, {
@@ -5613,13 +5759,7 @@ var handle15 = async (req, res, _url, ctx) => {
5613
5759
  text: payload.text
5614
5760
  });
5615
5761
  if (!all && response.matches > 1) {
5616
- return respondJson(res, {
5617
- ok: false,
5618
- error: {
5619
- message: `Selector matched ${response.matches} elements; pass all=true to return all matches`,
5620
- code: "multiple_matches"
5621
- }
5622
- }, 400);
5762
+ return respondMultipleMatches(res, response.matches, "return");
5623
5763
  }
5624
5764
  respondJson(res, response);
5625
5765
  } catch (error) {
@@ -5629,17 +5769,11 @@ var handle15 = async (req, res, _url, ctx) => {
5629
5769
 
5630
5770
  // ../argus-watcher/dist/http/routes/postDomInfo.js
5631
5771
  var handle16 = async (req, res, _url, ctx) => {
5632
- const payload = await readJsonBody(req, res);
5633
- if (!payload) {
5772
+ const parsed = await readDomSelectorPayload(req, res);
5773
+ if (!parsed) {
5634
5774
  return;
5635
5775
  }
5636
- if (!payload.selector || typeof payload.selector !== "string") {
5637
- return respondInvalidBody(res, "selector is required");
5638
- }
5639
- const all = payload.all ?? false;
5640
- if (typeof all !== "boolean") {
5641
- return respondInvalidBody(res, "all must be a boolean");
5642
- }
5776
+ const { payload, all } = parsed;
5643
5777
  emitRequest(ctx, res, "dom/info");
5644
5778
  try {
5645
5779
  const response = await fetchDomInfoBySelector(ctx.cdpSession, {
@@ -5649,13 +5783,7 @@ var handle16 = async (req, res, _url, ctx) => {
5649
5783
  text: payload.text
5650
5784
  });
5651
5785
  if (!all && response.matches > 1) {
5652
- return respondJson(res, {
5653
- ok: false,
5654
- error: {
5655
- message: `Selector matched ${response.matches} elements; pass all=true to return all matches`,
5656
- code: "multiple_matches"
5657
- }
5658
- }, 400);
5786
+ return respondMultipleMatches(res, response.matches, "return");
5659
5787
  }
5660
5788
  respondJson(res, response);
5661
5789
  } catch (error) {
@@ -5854,28 +5982,16 @@ var createNotInteractableError = (message) => {
5854
5982
 
5855
5983
  // ../argus-watcher/dist/http/routes/postDomHover.js
5856
5984
  var handle17 = async (req, res, _url, ctx) => {
5857
- const payload = await readJsonBody(req, res);
5858
- if (!payload) {
5985
+ const parsed = await readDomSelectorPayload(req, res);
5986
+ if (!parsed) {
5859
5987
  return;
5860
5988
  }
5861
- if (!payload.selector || typeof payload.selector !== "string") {
5862
- return respondInvalidBody(res, "selector is required");
5863
- }
5864
- const all = payload.all ?? false;
5865
- if (typeof all !== "boolean") {
5866
- return respondInvalidBody(res, "all must be a boolean");
5867
- }
5989
+ const { payload, all } = parsed;
5868
5990
  emitRequest(ctx, res, "dom/hover");
5869
5991
  try {
5870
5992
  const { allNodeIds, nodeIds } = await resolveDomSelectorMatches(ctx.cdpSession, payload.selector, all, payload.text);
5871
5993
  if (!all && allNodeIds.length > 1) {
5872
- return respondJson(res, {
5873
- ok: false,
5874
- error: {
5875
- message: `Selector matched ${allNodeIds.length} elements; pass all=true to hover all matches`,
5876
- code: "multiple_matches"
5877
- }
5878
- }, 400);
5994
+ return respondMultipleMatches(res, allNodeIds.length, "hover");
5879
5995
  }
5880
5996
  if (allNodeIds.length === 0) {
5881
5997
  const response2 = { ok: true, matches: 0, hovered: 0 };
@@ -5938,13 +6054,7 @@ var handle18 = async (req, res, _url, ctx) => {
5938
6054
  nodeIds = result.nodeIds;
5939
6055
  }
5940
6056
  if (!all && allNodeIds.length > 1) {
5941
- return respondJson(res, {
5942
- ok: false,
5943
- error: {
5944
- message: `Selector matched ${allNodeIds.length} elements; pass all=true to click all matches`,
5945
- code: "multiple_matches"
5946
- }
5947
- }, 400);
6057
+ return respondMultipleMatches(res, allNodeIds.length, "click");
5948
6058
  }
5949
6059
  if (allNodeIds.length === 0) {
5950
6060
  const response2 = { ok: true, matches: 0, clicked: 0 };
@@ -6210,17 +6320,11 @@ var selectDomAddNodeIds = (allNodeIds, options) => {
6210
6320
 
6211
6321
  // ../argus-watcher/dist/http/routes/postDomRemove.js
6212
6322
  var handle21 = async (req, res, _url, ctx) => {
6213
- const payload = await readJsonBody(req, res);
6214
- if (!payload) {
6323
+ const parsed = await readDomSelectorPayload(req, res);
6324
+ if (!parsed) {
6215
6325
  return;
6216
6326
  }
6217
- if (!payload.selector || typeof payload.selector !== "string") {
6218
- return respondInvalidBody(res, "selector is required");
6219
- }
6220
- const all = payload.all ?? false;
6221
- if (typeof all !== "boolean") {
6222
- return respondInvalidBody(res, "all must be a boolean");
6223
- }
6327
+ const { payload, all } = parsed;
6224
6328
  emitRequest(ctx, res, "dom/remove");
6225
6329
  try {
6226
6330
  const { allNodeIds, removedCount } = await removeElements(ctx.cdpSession, {
@@ -6229,13 +6333,7 @@ var handle21 = async (req, res, _url, ctx) => {
6229
6333
  text: payload.text
6230
6334
  });
6231
6335
  if (!all && allNodeIds.length > 1) {
6232
- return respondJson(res, {
6233
- ok: false,
6234
- error: {
6235
- message: `Selector matched ${allNodeIds.length} elements; pass all=true to remove all matches`,
6236
- code: "multiple_matches"
6237
- }
6238
- }, 400);
6336
+ return respondMultipleMatches(res, allNodeIds.length, "remove");
6239
6337
  }
6240
6338
  const response = { ok: true, matches: allNodeIds.length, removed: removedCount };
6241
6339
  respondJson(res, response);
@@ -6341,28 +6439,16 @@ var handle23 = async (req, res, _url, ctx) => {
6341
6439
 
6342
6440
  // ../argus-watcher/dist/http/routes/postDomFocus.js
6343
6441
  var handle24 = async (req, res, _url, ctx) => {
6344
- const payload = await readJsonBody(req, res);
6345
- if (!payload) {
6442
+ const parsed = await readDomSelectorPayload(req, res);
6443
+ if (!parsed) {
6346
6444
  return;
6347
6445
  }
6348
- if (!payload.selector || typeof payload.selector !== "string") {
6349
- return respondInvalidBody(res, "selector is required");
6350
- }
6351
- const all = payload.all ?? false;
6352
- if (typeof all !== "boolean") {
6353
- return respondInvalidBody(res, "all must be a boolean");
6354
- }
6446
+ const { payload, all } = parsed;
6355
6447
  emitRequest(ctx, res, "dom/focus");
6356
6448
  try {
6357
6449
  const { allNodeIds, nodeIds } = await resolveDomSelectorMatches(ctx.cdpSession, payload.selector, all, payload.text);
6358
6450
  if (!all && allNodeIds.length > 1) {
6359
- return respondJson(res, {
6360
- ok: false,
6361
- error: {
6362
- message: `Selector matched ${allNodeIds.length} elements; pass all=true to focus all matches`,
6363
- code: "multiple_matches"
6364
- }
6365
- }, 400);
6451
+ return respondMultipleMatches(res, allNodeIds.length, "focus");
6366
6452
  }
6367
6453
  if (allNodeIds.length === 0) {
6368
6454
  const response2 = { ok: true, matches: 0, focused: 0 };
@@ -6765,7 +6851,7 @@ var handle33 = async (req, res, _url, ctx) => {
6765
6851
  }
6766
6852
  emitRequest(ctx, res, "reload");
6767
6853
  try {
6768
- await ctx.cdpSession.sendAndWait("Page.reload", {
6854
+ await ctx.pageCdpSession.sendAndWait("Page.reload", {
6769
6855
  ignoreCache: payload.ignoreCache ?? false
6770
6856
  });
6771
6857
  const response = { ok: true };
@@ -6920,68 +7006,6 @@ var startHttpServer = async (options) => {
6920
7006
  };
6921
7007
  };
6922
7008
 
6923
- // ../argus-watcher/dist/registry/registry.js
6924
- var resolveUniqueWatcherId = async (id) => {
6925
- const { registry: registry2 } = await readRegistry();
6926
- const staleIds = [];
6927
- const isIdAvailable = (candidate) => {
6928
- const existing = registry2.watchers[candidate];
6929
- if (!existing) {
6930
- return true;
6931
- }
6932
- if (existing.pid == null || !isProcessAlive(existing.pid)) {
6933
- staleIds.push(candidate);
6934
- return true;
6935
- }
6936
- return false;
6937
- };
6938
- let resolvedId = id;
6939
- if (!isIdAvailable(id)) {
6940
- let suffix = 2;
6941
- while (!isIdAvailable(`${id}-${suffix}`)) {
6942
- suffix++;
6943
- }
6944
- resolvedId = `${id}-${suffix}`;
6945
- }
6946
- if (staleIds.length > 0) {
6947
- await updateRegistry((reg) => {
6948
- let next = reg;
6949
- for (const staleId of staleIds) {
6950
- next = removeWatcherEntry(next, staleId);
6951
- }
6952
- return next;
6953
- });
6954
- }
6955
- return resolvedId;
6956
- };
6957
- var isProcessAlive = (pid) => {
6958
- try {
6959
- process.kill(pid, 0);
6960
- return true;
6961
- } catch {
6962
- return false;
6963
- }
6964
- };
6965
- var announceWatcher = async (watcher) => {
6966
- await updateRegistry((registry2) => setWatcherEntry(registry2, watcher));
6967
- };
6968
- var updateWatcherHeartbeat = async (watcher) => {
6969
- await announceWatcher(watcher);
6970
- };
6971
- var removeWatcher = async (id) => {
6972
- await updateRegistry((registry2) => removeWatcherEntry(registry2, id));
6973
- };
6974
- var startRegistryHeartbeat = (getWatcher, intervalMs = 15000) => {
6975
- const timer = setInterval(() => {
6976
- const watcher = getWatcher();
6977
- watcher.updatedAt = Date.now();
6978
- updateWatcherHeartbeat(watcher);
6979
- }, intervalMs);
6980
- return {
6981
- stop: () => clearInterval(timer)
6982
- };
6983
- };
6984
-
6985
7009
  // ../argus-watcher/dist/fileLogs/WatcherFileLogger.js
6986
7010
  import fs3 from "node:fs";
6987
7011
  import fsPromises from "node:fs/promises";
@@ -10031,6 +10055,8 @@ class SessionManager {
10031
10055
  var createEmptyFrameState = () => ({
10032
10056
  topFrameId: null,
10033
10057
  requestedFrameId: null,
10058
+ requestedFrameHint: null,
10059
+ requestedFrameDetached: false,
10034
10060
  activeFrameId: null,
10035
10061
  activeAttachedAt: null,
10036
10062
  frames: new Map,
@@ -10129,13 +10155,114 @@ var parseExecutionContext = (params) => {
10129
10155
  isDefault: record.context.auxData?.isDefault === true
10130
10156
  };
10131
10157
  };
10132
- var resolveRequestedFrameId = (state, requestedFrameId) => {
10158
+ var createRequestedFrameHint = (frame) => {
10159
+ if (!frame) {
10160
+ return null;
10161
+ }
10162
+ return {
10163
+ url: frame.url || null,
10164
+ title: frame.title?.trim() || null
10165
+ };
10166
+ };
10167
+ var resolveRequestedFrameId = (state, requestedFrameId, requestedFrameHint) => {
10133
10168
  if (!requestedFrameId) {
10134
10169
  return null;
10135
10170
  }
10136
- return state.frames.has(requestedFrameId) ? requestedFrameId : null;
10171
+ if (state.frames.has(requestedFrameId)) {
10172
+ return requestedFrameId;
10173
+ }
10174
+ if (!requestedFrameHint) {
10175
+ return null;
10176
+ }
10177
+ const urlMatch = requestedFrameHint.url == null ? null : findSingleMatchingFrameId(state, (frame) => frame.url === requestedFrameHint.url);
10178
+ if (urlMatch) {
10179
+ return urlMatch;
10180
+ }
10181
+ if (requestedFrameHint.url != null || !requestedFrameHint.title) {
10182
+ return null;
10183
+ }
10184
+ return findSingleMatchingFrameId(state, (frame) => frame.title?.trim() === requestedFrameHint.title);
10185
+ };
10186
+ var resolveRequestedTarget = (state) => {
10187
+ if (state.requestedFrameId == null) {
10188
+ return { kind: "page" };
10189
+ }
10190
+ const nextFrameId = resolveRequestedFrameId(state, state.requestedFrameId, state.requestedFrameHint);
10191
+ if (nextFrameId) {
10192
+ return { kind: "frame", frameId: nextFrameId };
10193
+ }
10194
+ return state.requestedFrameDetached ? { kind: "page" } : { kind: "pending" };
10195
+ };
10196
+ var findSingleMatchingFrameId = (state, predicate) => {
10197
+ let matchId = null;
10198
+ for (const frame of state.frames.values()) {
10199
+ if (!predicate(frame)) {
10200
+ continue;
10201
+ }
10202
+ if (matchId) {
10203
+ return null;
10204
+ }
10205
+ matchId = frame.frameId;
10206
+ }
10207
+ return matchId;
10137
10208
  };
10138
10209
 
10210
+ // ../argus-watcher/dist/sources/extension-delegating-session.js
10211
+ var createDelegatingSession = (options) => {
10212
+ const subscriptions = new Set;
10213
+ const rebindSubscriptions = () => {
10214
+ for (const subscription of subscriptions) {
10215
+ subscription.unbind();
10216
+ const currentSession = options.getCurrentSession();
10217
+ if (!currentSession) {
10218
+ continue;
10219
+ }
10220
+ subscription.off = currentSession.handle.onEvent(subscription.method, subscription.handler);
10221
+ }
10222
+ };
10223
+ const disposeSubscriptions = () => {
10224
+ for (const subscription of subscriptions) {
10225
+ subscription.unbind();
10226
+ }
10227
+ subscriptions.clear();
10228
+ };
10229
+ const controller = {
10230
+ rebind: rebindSubscriptions,
10231
+ dispose: disposeSubscriptions
10232
+ };
10233
+ const session = {
10234
+ isAttached: () => options.getCurrentSession()?.handle.isAttached() ?? false,
10235
+ sendAndWait: async (method, params, commandOptions) => {
10236
+ const currentSession = options.requireCurrentSession();
10237
+ const targetContext = options.getTargetContext();
10238
+ const nextParams = options.mapParams ? options.mapParams(method, params) : params;
10239
+ const nextOptions = targetContext.kind === "frame" && targetContext.sessionId ? { ...commandOptions ?? {}, sessionId: targetContext.sessionId } : commandOptions;
10240
+ return currentSession.handle.sendAndWait(method, nextParams, nextOptions);
10241
+ },
10242
+ onEvent: (method, handler) => {
10243
+ const subscription = createDelegatingEventSubscription(method, handler);
10244
+ subscriptions.add(subscription);
10245
+ controller.rebind();
10246
+ return () => {
10247
+ subscription.unbind();
10248
+ subscriptions.delete(subscription);
10249
+ };
10250
+ },
10251
+ getTargetContext: options.getTargetContext
10252
+ };
10253
+ controller.rebind();
10254
+ return { session, controller };
10255
+ };
10256
+ var createDelegatingEventSubscription = (method, handler) => ({
10257
+ method,
10258
+ handler,
10259
+ off: null,
10260
+ unbind() {
10261
+ this.off?.();
10262
+ this.off = null;
10263
+ }
10264
+ });
10265
+
10139
10266
  // ../argus-watcher/dist/sources/extension-log-events.js
10140
10267
  var toConsoleEvent2 = (params, session, config) => {
10141
10268
  const record = params;
@@ -10235,6 +10362,103 @@ var applyStripPrefixes = (file, prefixes) => {
10235
10362
  return file;
10236
10363
  };
10237
10364
 
10365
+ // ../argus-watcher/dist/sources/extension-session-events.js
10366
+ var registerExtensionSessionEventHandlers = ({ session, events, ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2, getOrCreateFrameState, reconcileTargetSelection, removeFrame, refreshFrameTitle, emitTargetChanged, setCurrentSession }) => {
10367
+ session.handle.onEvent("Runtime.executionContextCreated", (params, meta) => {
10368
+ const context = parseExecutionContext(params);
10369
+ if (!context?.isDefault || !context.frameId) {
10370
+ return;
10371
+ }
10372
+ const state = getOrCreateFrameState(session.tabId);
10373
+ state.executionContexts.set(context.frameId, context.id);
10374
+ const frame = state.frames.get(context.frameId);
10375
+ if (frame) {
10376
+ frame.sessionId = meta.sessionId ?? null;
10377
+ }
10378
+ refreshFrameTitle(session, context.frameId, context.id);
10379
+ reconcileTargetSelection(session);
10380
+ });
10381
+ session.handle.onEvent("Runtime.executionContextsCleared", () => {
10382
+ const state = getOrCreateFrameState(session.tabId);
10383
+ state.executionContexts.clear();
10384
+ state.pendingTitleLoads.clear();
10385
+ });
10386
+ session.handle.onEvent("Runtime.executionContextDestroyed", (params) => {
10387
+ const record = params;
10388
+ if (record.executionContextId == null) {
10389
+ return;
10390
+ }
10391
+ const state = getOrCreateFrameState(session.tabId);
10392
+ for (const [frameId, contextId] of state.executionContexts.entries()) {
10393
+ if (contextId === record.executionContextId) {
10394
+ state.executionContexts.delete(frameId);
10395
+ state.pendingTitleLoads.delete(frameId);
10396
+ }
10397
+ }
10398
+ });
10399
+ session.handle.onEvent("Page.frameNavigated", (params, meta) => {
10400
+ const frame = parseFrame(params);
10401
+ if (!frame) {
10402
+ return;
10403
+ }
10404
+ const state = getOrCreateFrameState(session.tabId);
10405
+ state.frames.set(frame.frameId, frame);
10406
+ frame.sessionId = meta.sessionId ?? null;
10407
+ if (!frame.parentFrameId) {
10408
+ if (!meta.sessionId) {
10409
+ state.topFrameId = frame.frameId;
10410
+ session.url = frame.url;
10411
+ } else if (state.topFrameId == null) {
10412
+ state.topFrameId = frame.parentFrameId;
10413
+ }
10414
+ } else if (state.executionContexts.has(frame.frameId)) {
10415
+ refreshFrameTitle(session, frame.frameId);
10416
+ }
10417
+ setCurrentSession(session);
10418
+ if (!frame.parentFrameId && !meta.sessionId) {
10419
+ events.onPageNavigation?.({ url: frame.url, title: session.title ?? null });
10420
+ }
10421
+ if (reconcileTargetSelection(session)) {
10422
+ return;
10423
+ }
10424
+ if (!frame.parentFrameId && state.activeFrameId == null || state.activeFrameId === frame.frameId) {
10425
+ emitTargetChanged(session);
10426
+ }
10427
+ });
10428
+ session.handle.onEvent("Page.frameAttached", (params, meta) => {
10429
+ const record = params;
10430
+ if (!record.frameId) {
10431
+ return;
10432
+ }
10433
+ const state = getOrCreateFrameState(session.tabId);
10434
+ state.frames.set(record.frameId, {
10435
+ frameId: record.frameId,
10436
+ parentFrameId: record.parentFrameId ?? state.topFrameId ?? null,
10437
+ url: "",
10438
+ title: null,
10439
+ sessionId: meta.sessionId ?? null
10440
+ });
10441
+ reconcileTargetSelection(session);
10442
+ });
10443
+ session.handle.onEvent("Page.frameDetached", (params) => {
10444
+ const record = params;
10445
+ if (!record.frameId) {
10446
+ return;
10447
+ }
10448
+ removeFrame(session.tabId, record.frameId);
10449
+ reconcileTargetSelection(session);
10450
+ });
10451
+ session.handle.onEvent("Page.domContentEventFired", () => {
10452
+ events.onPageLoad?.();
10453
+ });
10454
+ session.handle.onEvent("Runtime.consoleAPICalled", (params) => {
10455
+ events.onLog(toConsoleEvent2(params, session, { ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2 }));
10456
+ });
10457
+ session.handle.onEvent("Runtime.exceptionThrown", (params) => {
10458
+ events.onLog(toExceptionEvent2(params, session, { ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2 }));
10459
+ });
10460
+ };
10461
+
10238
10462
  // ../argus-watcher/dist/sources/extension-source.js
10239
10463
  var createExtensionSource = (options) => {
10240
10464
  const { events, ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2, watcherId, watcherHost, watcherPort } = options;
@@ -10277,13 +10501,16 @@ var createExtensionSource = (options) => {
10277
10501
  onTargetSelected: (tabId, frameId) => {
10278
10502
  const session = currentSession;
10279
10503
  if (!session || session.tabId !== tabId) {
10280
- getOrCreateFrameState(tabId).requestedFrameId = frameId;
10504
+ const state = getOrCreateFrameState(tabId);
10505
+ setRequestedTargetSelection(state, frameId);
10281
10506
  return;
10282
10507
  }
10283
10508
  requestTargetSelection(session, frameId);
10284
10509
  }
10285
10510
  });
10286
- const proxySession = createDelegatingSession({
10511
+ const { session: proxySession, controller: proxyController } = createDelegatingSession({
10512
+ getCurrentSession: () => currentSession,
10513
+ requireCurrentSession: getCurrentExtensionSession,
10287
10514
  getTargetContext: () => getCurrentTargetContext() ?? { kind: "page" },
10288
10515
  mapParams: (method, params) => {
10289
10516
  const targetContext = getCurrentTargetContext();
@@ -10299,9 +10526,13 @@ var createExtensionSource = (options) => {
10299
10526
  };
10300
10527
  }
10301
10528
  });
10302
- const pageSession = createDelegatingSession({
10529
+ delegatingSessions.add(proxyController);
10530
+ const { session: pageSession, controller: pageController } = createDelegatingSession({
10531
+ getCurrentSession: () => currentSession,
10532
+ requireCurrentSession: getCurrentExtensionSession,
10303
10533
  getTargetContext: () => ({ kind: "page" })
10304
10534
  });
10535
+ delegatingSessions.add(pageController);
10305
10536
  messaging.start();
10306
10537
  sendHostInfo();
10307
10538
  messaging.onDisconnect(() => {
@@ -10336,7 +10567,8 @@ var createExtensionSource = (options) => {
10336
10567
  const target = parseExtensionTargetId(targetId);
10337
10568
  const session = currentSession;
10338
10569
  if (!session || session.tabId !== target.tabId) {
10339
- getOrCreateFrameState(target.tabId).requestedFrameId = target.frameId;
10570
+ const state = getOrCreateFrameState(target.tabId);
10571
+ setRequestedTargetSelection(state, target.frameId);
10340
10572
  sessionManager.attachTab(target.tabId);
10341
10573
  return;
10342
10574
  }
@@ -10378,10 +10610,24 @@ var createExtensionSource = (options) => {
10378
10610
  for (const controller of delegatingSessions) {
10379
10611
  controller.dispose();
10380
10612
  }
10613
+ delegatingSessions.clear();
10381
10614
  }
10382
10615
  async function bootstrapAttachedSession(session) {
10383
10616
  try {
10384
- registerSessionEventHandlers(session);
10617
+ registerExtensionSessionEventHandlers({
10618
+ session,
10619
+ events,
10620
+ ignoreMatcher,
10621
+ stripUrlPrefixes: stripUrlPrefixes2,
10622
+ getOrCreateFrameState,
10623
+ reconcileTargetSelection,
10624
+ removeFrame,
10625
+ refreshFrameTitle,
10626
+ emitTargetChanged,
10627
+ setCurrentSession: (nextSession) => {
10628
+ currentSession = nextSession;
10629
+ }
10630
+ });
10385
10631
  await enableBootstrapDomains(session);
10386
10632
  await refreshFrameTree(session);
10387
10633
  if (currentSession?.tabId !== session.tabId) {
@@ -10404,101 +10650,6 @@ var createExtensionSource = (options) => {
10404
10650
  await session.handle.sendAndWait("Runtime.enable");
10405
10651
  await session.handle.sendAndWait("Page.enable");
10406
10652
  }
10407
- function registerSessionEventHandlers(session) {
10408
- session.handle.onEvent("Runtime.executionContextCreated", (params, meta) => {
10409
- const context = parseExecutionContext(params);
10410
- if (!context?.isDefault || !context.frameId) {
10411
- return;
10412
- }
10413
- const state = getOrCreateFrameState(session.tabId);
10414
- state.executionContexts.set(context.frameId, context.id);
10415
- const frame = state.frames.get(context.frameId);
10416
- if (frame) {
10417
- frame.sessionId = meta.sessionId ?? null;
10418
- }
10419
- refreshFrameTitle(session, context.frameId, context.id);
10420
- reconcileTargetSelection(session);
10421
- });
10422
- session.handle.onEvent("Runtime.executionContextsCleared", () => {
10423
- const state = getOrCreateFrameState(session.tabId);
10424
- state.executionContexts.clear();
10425
- state.pendingTitleLoads.clear();
10426
- });
10427
- session.handle.onEvent("Runtime.executionContextDestroyed", (params) => {
10428
- const record = params;
10429
- if (record.executionContextId == null) {
10430
- return;
10431
- }
10432
- const state = getOrCreateFrameState(session.tabId);
10433
- for (const [frameId, contextId] of state.executionContexts.entries()) {
10434
- if (contextId === record.executionContextId) {
10435
- state.executionContexts.delete(frameId);
10436
- state.pendingTitleLoads.delete(frameId);
10437
- }
10438
- }
10439
- });
10440
- session.handle.onEvent("Page.frameNavigated", (params, meta) => {
10441
- const frame = parseFrame(params);
10442
- if (!frame) {
10443
- return;
10444
- }
10445
- const state = getOrCreateFrameState(session.tabId);
10446
- state.frames.set(frame.frameId, frame);
10447
- frame.sessionId = meta.sessionId ?? null;
10448
- if (!frame.parentFrameId) {
10449
- if (!meta.sessionId) {
10450
- state.topFrameId = frame.frameId;
10451
- session.url = frame.url;
10452
- } else if (state.topFrameId == null) {
10453
- state.topFrameId = frame.parentFrameId;
10454
- }
10455
- } else if (state.executionContexts.has(frame.frameId)) {
10456
- refreshFrameTitle(session, frame.frameId);
10457
- }
10458
- currentSession = session;
10459
- if (!frame.parentFrameId && !meta.sessionId) {
10460
- events.onPageNavigation?.({ url: frame.url, title: session.title ?? null });
10461
- }
10462
- if (reconcileTargetSelection(session)) {
10463
- return;
10464
- }
10465
- if (!frame.parentFrameId && state.activeFrameId == null || state.activeFrameId === frame.frameId) {
10466
- emitTargetChanged(session);
10467
- }
10468
- });
10469
- session.handle.onEvent("Page.frameAttached", (params, meta) => {
10470
- const record = params;
10471
- if (!record.frameId) {
10472
- return;
10473
- }
10474
- const state = getOrCreateFrameState(session.tabId);
10475
- state.frames.set(record.frameId, {
10476
- frameId: record.frameId,
10477
- parentFrameId: record.parentFrameId ?? state.topFrameId ?? null,
10478
- url: "",
10479
- title: null,
10480
- sessionId: meta.sessionId ?? null
10481
- });
10482
- reconcileTargetSelection(session);
10483
- });
10484
- session.handle.onEvent("Page.frameDetached", (params) => {
10485
- const record = params;
10486
- if (!record.frameId) {
10487
- return;
10488
- }
10489
- removeFrame(session.tabId, record.frameId);
10490
- reconcileTargetSelection(session);
10491
- });
10492
- session.handle.onEvent("Page.domContentEventFired", () => {
10493
- events.onPageLoad?.();
10494
- });
10495
- session.handle.onEvent("Runtime.consoleAPICalled", (params) => {
10496
- events.onLog(toConsoleEvent2(params, session, { ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2 }));
10497
- });
10498
- session.handle.onEvent("Runtime.exceptionThrown", (params) => {
10499
- events.onLog(toExceptionEvent2(params, session, { ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2 }));
10500
- });
10501
- }
10502
10653
  function getCurrentTargetContext() {
10503
10654
  const session = currentSession;
10504
10655
  if (!session) {
@@ -10585,30 +10736,47 @@ var createExtensionSource = (options) => {
10585
10736
  }
10586
10737
  function requestTargetSelection(session, frameId) {
10587
10738
  const state = getOrCreateFrameState(session.tabId);
10588
- state.requestedFrameId = frameId;
10739
+ setRequestedTargetSelection(state, frameId);
10589
10740
  reconcileTargetSelection(session);
10590
10741
  }
10742
+ function setRequestedTargetSelection(state, frameId) {
10743
+ const frame = frameId ? state.frames.get(frameId) : null;
10744
+ state.requestedFrameId = frameId;
10745
+ state.requestedFrameHint = createRequestedFrameHint(frame);
10746
+ state.requestedFrameDetached = false;
10747
+ }
10591
10748
  function reconcileTargetSelection(session) {
10592
10749
  const state = getOrCreateFrameState(session.tabId);
10593
- const nextActiveFrameId = resolveRequestedFrameId(state, state.requestedFrameId);
10594
- if (state.requestedFrameId == null) {
10595
- if (state.activeFrameId == null) {
10596
- if (state.activeAttachedAt == null) {
10597
- state.activeAttachedAt = Date.now();
10598
- emitTargetChanged(session);
10599
- return true;
10600
- }
10601
- return false;
10602
- }
10603
- state.activeFrameId = null;
10604
- state.activeAttachedAt = Date.now();
10605
- emitTargetChanged(session);
10606
- return true;
10750
+ const resolution = resolveRequestedTarget(state);
10751
+ if (resolution.kind === "page") {
10752
+ state.requestedFrameDetached = false;
10753
+ return activatePageTarget(session, state);
10754
+ }
10755
+ if (resolution.kind === "pending") {
10756
+ return false;
10607
10757
  }
10608
- if (nextActiveFrameId == null || state.activeFrameId === nextActiveFrameId) {
10758
+ state.requestedFrameDetached = false;
10759
+ if (state.activeFrameId === resolution.frameId) {
10609
10760
  return false;
10610
10761
  }
10611
- state.activeFrameId = nextActiveFrameId;
10762
+ return activateFrameTarget(session, state, resolution.frameId);
10763
+ }
10764
+ function activatePageTarget(session, state) {
10765
+ if (state.activeFrameId == null) {
10766
+ if (state.activeAttachedAt == null) {
10767
+ state.activeAttachedAt = Date.now();
10768
+ emitTargetChanged(session);
10769
+ return true;
10770
+ }
10771
+ return false;
10772
+ }
10773
+ state.activeFrameId = null;
10774
+ state.activeAttachedAt = Date.now();
10775
+ emitTargetChanged(session);
10776
+ return true;
10777
+ }
10778
+ function activateFrameTarget(session, state, frameId) {
10779
+ state.activeFrameId = frameId;
10612
10780
  state.activeAttachedAt = Date.now();
10613
10781
  emitTargetChanged(session);
10614
10782
  return true;
@@ -10625,8 +10793,10 @@ var createExtensionSource = (options) => {
10625
10793
  for (const childId of childIds) {
10626
10794
  removeFrame(tabId, childId);
10627
10795
  }
10628
- if (state.requestedFrameId === frameId) {
10629
- state.requestedFrameId = null;
10796
+ if (state.activeFrameId === frameId) {
10797
+ state.requestedFrameDetached = state.requestedFrameId === frameId;
10798
+ state.activeFrameId = null;
10799
+ state.activeAttachedAt = null;
10630
10800
  }
10631
10801
  state.frames.delete(frameId);
10632
10802
  state.executionContexts.delete(frameId);
@@ -10666,53 +10836,6 @@ var createExtensionSource = (options) => {
10666
10836
  state.pendingTitleLoads.delete(frameId);
10667
10837
  }
10668
10838
  }
10669
- function createDelegatingSession(config) {
10670
- const subscriptions = new Set;
10671
- const rebindSubscriptions = () => {
10672
- for (const subscription of subscriptions) {
10673
- subscription.unbind();
10674
- if (!currentSession) {
10675
- continue;
10676
- }
10677
- subscription.off = currentSession.handle.onEvent(subscription.method, subscription.handler);
10678
- }
10679
- };
10680
- const disposeSubscriptions = () => {
10681
- for (const subscription of subscriptions) {
10682
- subscription.unbind();
10683
- }
10684
- subscriptions.clear();
10685
- };
10686
- const controller = {
10687
- rebind: rebindSubscriptions,
10688
- dispose: () => {
10689
- disposeSubscriptions();
10690
- delegatingSessions.delete(controller);
10691
- }
10692
- };
10693
- delegatingSessions.add(controller);
10694
- controller.rebind();
10695
- return {
10696
- isAttached: () => currentSession?.handle.isAttached() ?? false,
10697
- sendAndWait: async (method, params, options2) => {
10698
- const session = getCurrentExtensionSession();
10699
- const targetContext = config.getTargetContext();
10700
- const nextParams = config.mapParams ? config.mapParams(method, params) : params;
10701
- const nextOptions = targetContext.kind === "frame" && targetContext.sessionId ? { ...options2 ?? {}, sessionId: targetContext.sessionId } : options2;
10702
- return session.handle.sendAndWait(method, nextParams, nextOptions);
10703
- },
10704
- onEvent: (method, handler) => {
10705
- const subscription = createDelegatingEventSubscription(method, handler);
10706
- subscriptions.add(subscription);
10707
- controller.rebind();
10708
- return () => {
10709
- subscription.unbind();
10710
- subscriptions.delete(subscription);
10711
- };
10712
- },
10713
- getTargetContext: config.getTargetContext
10714
- };
10715
- }
10716
10839
  };
10717
10840
  var tabToTarget = (tab) => ({
10718
10841
  id: formatPageTargetId(tab.tabId),
@@ -10722,72 +10845,16 @@ var tabToTarget = (tab) => ({
10722
10845
  faviconUrl: tab.faviconUrl,
10723
10846
  attached: tab.attached
10724
10847
  });
10725
- var createDelegatingEventSubscription = (method, handler) => ({
10726
- method,
10727
- handler,
10728
- off: null,
10729
- unbind() {
10730
- this.off?.();
10731
- this.off = null;
10732
- }
10733
- });
10734
10848
 
10735
- // ../argus-watcher/dist/index.js
10736
- var startWatcher = async (options) => {
10737
- if (!options.id) {
10738
- throw new Error("Watcher id is required");
10739
- }
10740
- const watcherId = await resolveUniqueWatcherId(options.id);
10741
- const sourceMode = options.source ?? "cdp";
10742
- const host = options.host ?? "127.0.0.1";
10743
- const port = options.port ?? 0;
10744
- const chrome = options.chrome ?? { host: "127.0.0.1", port: 9222 };
10745
- const bufferSize = options.bufferSize ?? 50000;
10746
- const netBufferSize = options.bufferSize ?? 50000;
10747
- const startedAt = Date.now();
10748
- const ignoreMatcher = buildIgnoreMatcher(options.ignoreList);
10749
- const stripUrlPrefixes2 = options.location?.stripUrlPrefixes;
10750
- const artifactsBaseDir = resolveArtifactsBaseDir(options.artifacts?.base, watcherId);
10751
- const logsEnabled = options.artifacts?.logs?.enabled === true;
10752
- const logsDir = path7.join(artifactsBaseDir, "logs");
10753
- const includeTimestamps = options.artifacts?.logs?.includeTimestamps ?? false;
10754
- const maxFiles = resolveMaxFiles(options.artifacts?.logs?.maxFiles);
10755
- const netEnabled = options.net?.enabled === true;
10756
- const pageConsoleLogging = options.pageConsoleLogging ?? "minimal";
10757
- const events = new Emittery;
10758
- const buffer = new LogBuffer(bufferSize);
10759
- const netBuffer = netEnabled ? new NetBuffer(netBufferSize) : null;
10849
+ // ../argus-watcher/dist/startWatcherRuntime.js
10850
+ var createWatcherHandle = async (options, watcherId) => {
10851
+ const setup = normalizeWatcherSetup(options, watcherId);
10852
+ const { sourceMode, host, port, chrome, artifactsBaseDir, pageConsoleLogging, ignoreMatcher, stripUrlPrefixes: stripUrlPrefixes2, events, buffer, netBuffer, record, fileLogger, sessionHandle, emulationController, throttleController } = setup;
10760
10853
  let closing = false;
10761
10854
  let readyForShutdown = false;
10762
10855
  let shutdownRequested = false;
10763
10856
  let closeOnce = null;
10764
10857
  let cdpStatus = { attached: false, target: null };
10765
- const fileLogger = logsEnabled ? new WatcherFileLogger({
10766
- watcherId,
10767
- startedAt,
10768
- logsDir,
10769
- chrome: sourceMode === "cdp" ? chrome : undefined,
10770
- match: options.match,
10771
- maxFiles,
10772
- includeTimestamps,
10773
- buildFilename: options.artifacts?.logs?.buildFilename
10774
- }) : null;
10775
- const record = {
10776
- id: watcherId,
10777
- host,
10778
- port,
10779
- pid: process.pid,
10780
- cwd: process.cwd(),
10781
- startedAt,
10782
- updatedAt: Date.now(),
10783
- match: sourceMode === "cdp" ? options.match : undefined,
10784
- chrome: sourceMode === "cdp" ? chrome : undefined,
10785
- includeTimestamps,
10786
- source: sourceMode
10787
- };
10788
- const sessionHandle = createCdpSessionHandle();
10789
- const emulationController = createEmulationController();
10790
- const throttleController = createThrottleController();
10791
10858
  const logToPageConsole = (message) => {
10792
10859
  if (pageConsoleLogging === "none") {
10793
10860
  return;
@@ -10996,6 +11063,7 @@ var startWatcher = async (options) => {
10996
11063
  netBuffer,
10997
11064
  getWatcher: () => record,
10998
11065
  getCdpStatus: () => cdpStatus,
11066
+ pageCdpSession: sourceHandle.pageSession ?? sourceHandle.session,
10999
11067
  cdpSession: sourceHandle.session,
11000
11068
  traceRecorder,
11001
11069
  screenshotter,
@@ -11058,6 +11126,71 @@ var startWatcher = async (options) => {
11058
11126
  }
11059
11127
  };
11060
11128
  };
11129
+ var normalizeWatcherSetup = (options, watcherId) => {
11130
+ const sourceMode = options.source ?? "cdp";
11131
+ const host = options.host ?? "127.0.0.1";
11132
+ const port = options.port ?? 0;
11133
+ const chrome = options.chrome ?? { host: "127.0.0.1", port: 9222 };
11134
+ const bufferSize = options.bufferSize ?? 50000;
11135
+ const startedAt = Date.now();
11136
+ const ignoreMatcher = buildIgnoreMatcher(options.ignoreList);
11137
+ const stripUrlPrefixes2 = options.location?.stripUrlPrefixes;
11138
+ const artifactsBaseDir = resolveArtifactsBaseDir(options.artifacts?.base, watcherId);
11139
+ const logsEnabled = options.artifacts?.logs?.enabled === true;
11140
+ const logsDir = path7.join(artifactsBaseDir, "logs");
11141
+ const includeTimestamps = options.artifacts?.logs?.includeTimestamps ?? false;
11142
+ const maxFiles = resolveMaxFiles(options.artifacts?.logs?.maxFiles);
11143
+ const netEnabled = options.net?.enabled === true;
11144
+ const pageConsoleLogging = options.pageConsoleLogging ?? "minimal";
11145
+ const events = new Emittery;
11146
+ const buffer = new LogBuffer(bufferSize);
11147
+ const netBuffer = netEnabled ? new NetBuffer(bufferSize) : null;
11148
+ const fileLogger = logsEnabled ? new WatcherFileLogger({
11149
+ watcherId,
11150
+ startedAt,
11151
+ logsDir,
11152
+ chrome: sourceMode === "cdp" ? chrome : undefined,
11153
+ match: options.match,
11154
+ maxFiles,
11155
+ includeTimestamps,
11156
+ buildFilename: options.artifacts?.logs?.buildFilename
11157
+ }) : null;
11158
+ const record = {
11159
+ id: watcherId,
11160
+ host,
11161
+ port,
11162
+ pid: process.pid,
11163
+ cwd: process.cwd(),
11164
+ startedAt,
11165
+ updatedAt: Date.now(),
11166
+ match: sourceMode === "cdp" ? options.match : undefined,
11167
+ chrome: sourceMode === "cdp" ? chrome : undefined,
11168
+ includeTimestamps,
11169
+ source: sourceMode
11170
+ };
11171
+ return {
11172
+ sourceMode,
11173
+ host,
11174
+ port,
11175
+ chrome,
11176
+ watcherId,
11177
+ startedAt,
11178
+ artifactsBaseDir,
11179
+ includeTimestamps,
11180
+ netEnabled,
11181
+ pageConsoleLogging,
11182
+ ignoreMatcher,
11183
+ stripUrlPrefixes: stripUrlPrefixes2,
11184
+ events,
11185
+ buffer,
11186
+ netBuffer,
11187
+ record,
11188
+ fileLogger,
11189
+ sessionHandle: createCdpSessionHandle(),
11190
+ emulationController: createEmulationController(),
11191
+ throttleController: createThrottleController()
11192
+ };
11193
+ };
11061
11194
  var resolveArtifactsBaseDir = (base, watcherId) => {
11062
11195
  if (base !== undefined && base !== null) {
11063
11196
  if (typeof base !== "string" || base.trim() === "") {
@@ -11098,11 +11231,20 @@ var formatError4 = (error) => {
11098
11231
  return String(error);
11099
11232
  };
11100
11233
 
11234
+ // ../argus-watcher/dist/index.js
11235
+ var startWatcher = async (options) => {
11236
+ if (!options.id) {
11237
+ throw new Error("Watcher id is required");
11238
+ }
11239
+ const watcherId = await resolveUniqueWatcherId(options.id);
11240
+ return createWatcherHandle(options, watcherId);
11241
+ };
11242
+
11101
11243
  // dist/commands/chromeStart.js
11102
11244
  import { spawn } from "node:child_process";
11103
11245
  import { copyFileSync, cpSync, existsSync as existsSync2, mkdtempSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
11104
- import { homedir, tmpdir } from "node:os";
11105
- import path8 from "node:path";
11246
+ import { homedir as homedir2, tmpdir } from "node:os";
11247
+ import path9 from "node:path";
11106
11248
 
11107
11249
  // dist/utils/chromeBin.js
11108
11250
  import { existsSync } from "node:fs";
@@ -11185,6 +11327,80 @@ var getCdpPort = async () => {
11185
11327
  return getEphemeralPort();
11186
11328
  };
11187
11329
 
11330
+ // dist/commands/startShared.js
11331
+ import fs7 from "node:fs/promises";
11332
+
11333
+ // dist/utils/paths.js
11334
+ import { homedir } from "node:os";
11335
+ import path8 from "node:path";
11336
+ var resolvePath = (input) => {
11337
+ const expanded = input.startsWith("~/") || input === "~" ? path8.join(homedir(), input.slice(1)) : input;
11338
+ return path8.resolve(expanded);
11339
+ };
11340
+
11341
+ // dist/commands/startShared.js
11342
+ var resolveInjectScript = async (inject, output) => {
11343
+ if (!inject) {
11344
+ return;
11345
+ }
11346
+ const resolvedPath = resolvePath(inject.file);
11347
+ let script;
11348
+ try {
11349
+ script = await fs7.readFile(resolvedPath, "utf8");
11350
+ } catch (error) {
11351
+ output.writeWarn(`Failed to read inject script at ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}. Skipping injection.`);
11352
+ return;
11353
+ }
11354
+ if (script.trim() === "") {
11355
+ output.writeWarn(`Inject script at ${resolvedPath} is empty. Skipping injection.`);
11356
+ return;
11357
+ }
11358
+ return { script, exposeArgus: inject.exposeArgus };
11359
+ };
11360
+ var normalizeHttpUrl2 = (value) => {
11361
+ if (!value) {
11362
+ return null;
11363
+ }
11364
+ if (value.startsWith("http://") || value.startsWith("https://")) {
11365
+ return value;
11366
+ }
11367
+ return `http://${value}`;
11368
+ };
11369
+ var buildWatcherMatch = (options) => {
11370
+ const match = {};
11371
+ const url = options.url?.trim();
11372
+ if (url) {
11373
+ match.url = url;
11374
+ }
11375
+ const type = options.type?.trim();
11376
+ if (type) {
11377
+ match.type = type;
11378
+ }
11379
+ const origin = options.origin?.trim();
11380
+ if (origin) {
11381
+ match.origin = origin;
11382
+ }
11383
+ const targetId = options.target?.trim();
11384
+ if (targetId) {
11385
+ match.targetId = targetId;
11386
+ }
11387
+ const parent = options.parent?.trim();
11388
+ if (parent) {
11389
+ match.parent = parent;
11390
+ }
11391
+ return Object.keys(match).length > 0 ? match : undefined;
11392
+ };
11393
+ var registerTerminationHandlers = (terminate) => {
11394
+ const handleTermination = () => {
11395
+ terminate().then(() => process.exit(0));
11396
+ };
11397
+ process.on("SIGINT", handleTermination);
11398
+ process.on("SIGTERM", handleTermination);
11399
+ };
11400
+ var waitForever = async () => {
11401
+ await new Promise(() => {});
11402
+ };
11403
+
11188
11404
  // dist/commands/chromeStart.js
11189
11405
  var delay2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
11190
11406
  var resolveChromeUserDataDir = () => {
@@ -11197,13 +11413,13 @@ var resolveChromeUserDataDir = () => {
11197
11413
  const platform = process.platform;
11198
11414
  if (platform === "darwin") {
11199
11415
  const candidates = [
11200
- path8.join(homedir(), "Library/Application Support/Google/Chrome"),
11201
- path8.join(homedir(), "Library/Application Support/Chromium")
11416
+ path9.join(homedir2(), "Library/Application Support/Google/Chrome"),
11417
+ path9.join(homedir2(), "Library/Application Support/Chromium")
11202
11418
  ];
11203
11419
  return candidates.find((candidate) => existsSync2(candidate)) ?? null;
11204
11420
  }
11205
11421
  if (platform === "linux") {
11206
- const candidates = [path8.join(homedir(), ".config/google-chrome"), path8.join(homedir(), ".config/chromium")];
11422
+ const candidates = [path9.join(homedir2(), ".config/google-chrome"), path9.join(homedir2(), ".config/chromium")];
11207
11423
  return candidates.find((candidate) => existsSync2(candidate)) ?? null;
11208
11424
  }
11209
11425
  if (platform === "win32") {
@@ -11211,21 +11427,21 @@ var resolveChromeUserDataDir = () => {
11211
11427
  if (!base) {
11212
11428
  return null;
11213
11429
  }
11214
- const candidates = [path8.join(base, "Google/Chrome/User Data"), path8.join(base, "Chromium/User Data")];
11430
+ const candidates = [path9.join(base, "Google/Chrome/User Data"), path9.join(base, "Chromium/User Data")];
11215
11431
  return candidates.find((candidate) => existsSync2(candidate)) ?? null;
11216
11432
  }
11217
11433
  return null;
11218
11434
  };
11219
11435
  var copyDefaultProfile = (sourceDir) => {
11220
- const destRoot = mkdtempSync(path8.join(tmpdir(), "argus-chrome-profile-"));
11436
+ const destRoot = mkdtempSync(path9.join(tmpdir(), "argus-chrome-profile-"));
11221
11437
  mkdirSync(destRoot, { recursive: true });
11222
11438
  const entries = ["Default", "Local State", "First Run", "Last Version"];
11223
11439
  for (const entry of entries) {
11224
- const source = path8.join(sourceDir, entry);
11440
+ const source = path9.join(sourceDir, entry);
11225
11441
  if (!existsSync2(source)) {
11226
11442
  continue;
11227
11443
  }
11228
- const dest = path8.join(destRoot, entry);
11444
+ const dest = path9.join(destRoot, entry);
11229
11445
  if (entry === "Default") {
11230
11446
  cpSync(source, dest, { recursive: true });
11231
11447
  } else {
@@ -11246,8 +11462,8 @@ var stripExtensionsFromPrefs = (prefsPath) => {
11246
11462
  } catch {}
11247
11463
  };
11248
11464
  var copyDefaultProfileLite = (sourceDir) => {
11249
- const destRoot = mkdtempSync(path8.join(tmpdir(), "argus-chrome-profile-lite-"));
11250
- const defaultDir = path8.join(destRoot, "Default");
11465
+ const destRoot = mkdtempSync(path9.join(tmpdir(), "argus-chrome-profile-lite-"));
11466
+ const defaultDir = path9.join(destRoot, "Default");
11251
11467
  mkdirSync(defaultDir, { recursive: true });
11252
11468
  const copyIfExists = (source, dest) => {
11253
11469
  if (!existsSync2(source)) {
@@ -11255,20 +11471,20 @@ var copyDefaultProfileLite = (sourceDir) => {
11255
11471
  }
11256
11472
  copyFileSync(source, dest);
11257
11473
  };
11258
- copyIfExists(path8.join(sourceDir, "Local State"), path8.join(destRoot, "Local State"));
11259
- copyIfExists(path8.join(sourceDir, "Default", "Cookies"), path8.join(defaultDir, "Cookies"));
11260
- copyIfExists(path8.join(sourceDir, "Default", "Cookies-journal"), path8.join(defaultDir, "Cookies-journal"));
11261
- copyIfExists(path8.join(sourceDir, "Default", "Login Data"), path8.join(defaultDir, "Login Data"));
11262
- copyIfExists(path8.join(sourceDir, "Default", "Login Data-journal"), path8.join(defaultDir, "Login Data-journal"));
11263
- copyIfExists(path8.join(sourceDir, "Default", "Preferences"), path8.join(defaultDir, "Preferences"));
11264
- copyIfExists(path8.join(sourceDir, "Default", "Secure Preferences"), path8.join(defaultDir, "Secure Preferences"));
11265
- stripExtensionsFromPrefs(path8.join(defaultDir, "Preferences"));
11266
- stripExtensionsFromPrefs(path8.join(defaultDir, "Secure Preferences"));
11474
+ copyIfExists(path9.join(sourceDir, "Local State"), path9.join(destRoot, "Local State"));
11475
+ copyIfExists(path9.join(sourceDir, "Default", "Cookies"), path9.join(defaultDir, "Cookies"));
11476
+ copyIfExists(path9.join(sourceDir, "Default", "Cookies-journal"), path9.join(defaultDir, "Cookies-journal"));
11477
+ copyIfExists(path9.join(sourceDir, "Default", "Login Data"), path9.join(defaultDir, "Login Data"));
11478
+ copyIfExists(path9.join(sourceDir, "Default", "Login Data-journal"), path9.join(defaultDir, "Login Data-journal"));
11479
+ copyIfExists(path9.join(sourceDir, "Default", "Preferences"), path9.join(defaultDir, "Preferences"));
11480
+ copyIfExists(path9.join(sourceDir, "Default", "Secure Preferences"), path9.join(defaultDir, "Secure Preferences"));
11481
+ stripExtensionsFromPrefs(path9.join(defaultDir, "Preferences"));
11482
+ stripExtensionsFromPrefs(path9.join(defaultDir, "Secure Preferences"));
11267
11483
  return destRoot;
11268
11484
  };
11269
11485
  var copyDefaultProfileMedium = (sourceDir) => {
11270
11486
  const destRoot = copyDefaultProfileLite(sourceDir);
11271
- const defaultDir = path8.join(destRoot, "Default");
11487
+ const defaultDir = path9.join(destRoot, "Default");
11272
11488
  const copyPathIfExists = (source, dest) => {
11273
11489
  if (!existsSync2(source)) {
11274
11490
  return;
@@ -11280,9 +11496,9 @@ var copyDefaultProfileMedium = (sourceDir) => {
11280
11496
  }
11281
11497
  copyFileSync(source, dest);
11282
11498
  };
11283
- copyPathIfExists(path8.join(sourceDir, "Default", "History"), path8.join(defaultDir, "History"));
11284
- copyPathIfExists(path8.join(sourceDir, "Default", "Local Storage"), path8.join(defaultDir, "Local Storage"));
11285
- copyPathIfExists(path8.join(sourceDir, "Default", "IndexedDB"), path8.join(defaultDir, "IndexedDB"));
11499
+ copyPathIfExists(path9.join(sourceDir, "Default", "History"), path9.join(defaultDir, "History"));
11500
+ copyPathIfExists(path9.join(sourceDir, "Default", "Local Storage"), path9.join(defaultDir, "Local Storage"));
11501
+ copyPathIfExists(path9.join(sourceDir, "Default", "IndexedDB"), path9.join(defaultDir, "IndexedDB"));
11286
11502
  return destRoot;
11287
11503
  };
11288
11504
  var waitForCdpReady = async (host, port, chrome) => {
@@ -11306,35 +11522,11 @@ var waitForCdpReady = async (host, port, chrome) => {
11306
11522
  }
11307
11523
  return { ready: false, error: lastError ?? "Timed out waiting for CDP." };
11308
11524
  };
11309
- var sendBrowserClose = (wsUrl, timeoutMs = 3000) => new Promise((resolve2) => {
11310
- const ws = new WebSocket(wsUrl);
11311
- const timer = setTimeout(() => {
11312
- try {
11313
- ws.close();
11314
- } catch {}
11315
- resolve2();
11316
- }, timeoutMs);
11317
- ws.addEventListener("open", () => {
11318
- try {
11319
- ws.send(JSON.stringify({ id: 1, method: "Browser.close" }));
11320
- } catch {}
11321
- });
11322
- ws.addEventListener("message", () => {
11323
- clearTimeout(timer);
11324
- try {
11325
- ws.close();
11326
- } catch {}
11327
- resolve2();
11328
- });
11329
- ws.addEventListener("error", () => {
11330
- clearTimeout(timer);
11331
- resolve2();
11332
- });
11333
- ws.addEventListener("close", () => {
11334
- clearTimeout(timer);
11335
- resolve2();
11336
- });
11337
- });
11525
+ var sendBrowserClose = async (wsUrl, timeoutMs = 3000) => {
11526
+ try {
11527
+ await sendCdpCommand(wsUrl, { id: 1, method: "Browser.close" }, timeoutMs);
11528
+ } catch {}
11529
+ };
11338
11530
  var normalizeProfile = (profile) => {
11339
11531
  if (!profile) {
11340
11532
  return "default-lite";
@@ -11375,7 +11567,7 @@ var launchChrome = async (options) => {
11375
11567
  const cdpPort = await getCdpPort();
11376
11568
  const cdpHost = "127.0.0.1";
11377
11569
  if (!userDataDir) {
11378
- userDataDir = mkdtempSync(path8.join(tmpdir(), "argus-chrome-"));
11570
+ userDataDir = mkdtempSync(path9.join(tmpdir(), "argus-chrome-"));
11379
11571
  }
11380
11572
  const cleanupDir = () => {
11381
11573
  if (userDataDir) {
@@ -11475,12 +11667,9 @@ var runChromeStart = async (options) => {
11475
11667
  process.exitCode = 2;
11476
11668
  return;
11477
11669
  }
11478
- startupUrl = watcher.match.url;
11479
- if (!startupUrl.startsWith("http://") && !startupUrl.startsWith("https://")) {
11480
- startupUrl = `http://${startupUrl}`;
11481
- }
11670
+ startupUrl = normalizeHttpUrl2(watcher.match.url);
11482
11671
  } else if (options.url) {
11483
- startupUrl = options.url;
11672
+ startupUrl = normalizeHttpUrl2(options.url);
11484
11673
  }
11485
11674
  let result;
11486
11675
  try {
@@ -11495,12 +11684,7 @@ var runChromeStart = async (options) => {
11495
11684
  process.exitCode = 1;
11496
11685
  return;
11497
11686
  }
11498
- process.on("SIGINT", () => {
11499
- result.closeGracefully().then(() => process.exit(0));
11500
- });
11501
- process.on("SIGTERM", () => {
11502
- result.closeGracefully().then(() => process.exit(0));
11503
- });
11687
+ registerTerminationHandlers(() => result.closeGracefully());
11504
11688
  result.chrome.on("exit", () => {
11505
11689
  if (result.userDataDir) {
11506
11690
  try {
@@ -11527,36 +11711,10 @@ var runChromeStart = async (options) => {
11527
11711
  output.writeHuman(` url=${info.startupUrl}`);
11528
11712
  }
11529
11713
  }
11530
- await new Promise(() => {});
11531
- };
11532
-
11533
- // dist/utils/paths.js
11534
- import { homedir as homedir2 } from "node:os";
11535
- import path9 from "node:path";
11536
- var resolvePath = (input) => {
11537
- const expanded = input.startsWith("~/") || input === "~" ? path9.join(homedir2(), input.slice(1)) : input;
11538
- return path9.resolve(expanded);
11714
+ await waitForever();
11539
11715
  };
11540
11716
 
11541
11717
  // dist/commands/start.js
11542
- var resolveInjectScript = async (inject, output) => {
11543
- if (!inject) {
11544
- return null;
11545
- }
11546
- const resolvedPath = resolvePath(inject.file);
11547
- let script;
11548
- try {
11549
- script = await fs7.readFile(resolvedPath, "utf8");
11550
- } catch (error) {
11551
- output.writeWarn(`Failed to read inject script at ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}. Skipping injection.`);
11552
- return null;
11553
- }
11554
- if (script.trim() === "") {
11555
- output.writeWarn(`Inject script at ${resolvedPath} is empty. Skipping injection.`);
11556
- return null;
11557
- }
11558
- return { script, exposeArgus: inject.exposeArgus };
11559
- };
11560
11718
  var runStart = async (options) => {
11561
11719
  const output = createOutput(options);
11562
11720
  if (!options.id || options.id.trim() === "") {
@@ -11565,13 +11723,7 @@ var runStart = async (options) => {
11565
11723
  return;
11566
11724
  }
11567
11725
  const watcherId = options.id.trim();
11568
- let chromeUrl = null;
11569
- if (options.url) {
11570
- chromeUrl = options.url;
11571
- if (!chromeUrl.startsWith("http://") && !chromeUrl.startsWith("https://")) {
11572
- chromeUrl = `http://${chromeUrl}`;
11573
- }
11574
- }
11726
+ const chromeUrl = normalizeHttpUrl2(options.url);
11575
11727
  const hasTargeting = options.url?.trim() || options.target?.trim() || options.origin?.trim() || options.type?.trim();
11576
11728
  if (!hasTargeting) {
11577
11729
  output.writeWarn("At least one targeting option is required: --url, --target, --origin, or --type.");
@@ -11600,17 +11752,7 @@ var runStart = async (options) => {
11600
11752
  if (!options.json) {
11601
11753
  output.writeHuman("Attaching watcher...");
11602
11754
  }
11603
- const match = {};
11604
- if (options.url?.trim())
11605
- match.url = options.url.trim();
11606
- if (options.type?.trim())
11607
- match.type = options.type.trim();
11608
- if (options.origin?.trim())
11609
- match.origin = options.origin.trim();
11610
- if (options.target?.trim())
11611
- match.targetId = options.target.trim();
11612
- if (options.parent?.trim())
11613
- match.parent = options.parent.trim();
11755
+ const match = buildWatcherMatch(options);
11614
11756
  let artifactsBaseDir;
11615
11757
  if (options.artifacts != null) {
11616
11758
  const trimmed = options.artifacts.trim();
@@ -11628,7 +11770,7 @@ var runStart = async (options) => {
11628
11770
  handle38 = await startWatcher({
11629
11771
  id: watcherId,
11630
11772
  source: "cdp",
11631
- match: Object.keys(match).length > 0 ? match : undefined,
11773
+ match,
11632
11774
  chrome: { host: chrome.cdpHost, port: chrome.cdpPort },
11633
11775
  host: "127.0.0.1",
11634
11776
  port: 0,
@@ -11650,12 +11792,7 @@ var runStart = async (options) => {
11650
11792
  } catch {}
11651
11793
  await chrome.closeGracefully();
11652
11794
  };
11653
- process.on("SIGINT", () => {
11654
- shutdown().then(() => process.exit(0));
11655
- });
11656
- process.on("SIGTERM", () => {
11657
- shutdown().then(() => process.exit(0));
11658
- });
11795
+ registerTerminationHandlers(shutdown);
11659
11796
  chrome.chrome.on("exit", () => {
11660
11797
  if (chrome.userDataDir) {
11661
11798
  try {
@@ -11708,7 +11845,7 @@ Stopping...`);
11708
11845
  }
11709
11846
  });
11710
11847
  }
11711
- await new Promise(() => {});
11848
+ await waitForever();
11712
11849
  };
11713
11850
 
11714
11851
  // dist/commands/doctor.js
@@ -11837,66 +11974,6 @@ var formatStatus = (status) => {
11837
11974
  return "WARN";
11838
11975
  };
11839
11976
 
11840
- // dist/watchers/requestWatcher.js
11841
- async function requestWatcherJson(input) {
11842
- const resolved = await resolveWatcher({ id: input.id });
11843
- if (!resolved.ok) {
11844
- return {
11845
- ok: false,
11846
- exitCode: resolved.exitCode,
11847
- message: resolved.error,
11848
- candidates: resolved.candidates
11849
- };
11850
- }
11851
- const { watcher } = resolved;
11852
- const qs = input.query?.toString();
11853
- const url = `http://${watcher.host}:${watcher.port}${input.path}${qs ? `?${qs}` : ""}`;
11854
- try {
11855
- const data = await fetchJson(url, {
11856
- method: input.method,
11857
- body: input.body,
11858
- timeoutMs: input.timeoutMs,
11859
- returnErrorResponse: input.returnErrorResponse
11860
- });
11861
- return { ok: true, watcher, data };
11862
- } catch (error) {
11863
- return {
11864
- ok: false,
11865
- watcher,
11866
- exitCode: 1,
11867
- message: `${watcher.id}: failed to reach watcher (${formatError(error)})`
11868
- };
11869
- }
11870
- }
11871
- async function resolveWatcherOrExit(input, output) {
11872
- const resolved = await resolveWatcher(input);
11873
- if (!resolved.ok) {
11874
- writeResolveError(resolved, output);
11875
- return null;
11876
- }
11877
- return { watcher: resolved.watcher };
11878
- }
11879
- function writeRequestError(result, output) {
11880
- output.writeWarn(result.message);
11881
- if (result.candidates && result.candidates.length > 0) {
11882
- for (const watcher of result.candidates) {
11883
- output.writeWarn(formatWatcherLine(watcher));
11884
- }
11885
- output.writeWarn("Hint: run `argus list` to see all watchers.");
11886
- }
11887
- process.exitCode = result.exitCode;
11888
- }
11889
- function writeResolveError(resolved, output) {
11890
- output.writeWarn(resolved.error);
11891
- if (resolved.candidates && resolved.candidates.length > 0) {
11892
- for (const watcher of resolved.candidates) {
11893
- output.writeWarn(formatWatcherLine(watcher));
11894
- }
11895
- output.writeWarn("Hint: run `argus list` to see all watchers.");
11896
- }
11897
- process.exitCode = resolved.exitCode;
11898
- }
11899
-
11900
11977
  // dist/commands/reload.js
11901
11978
  var runReload = async (id, options) => {
11902
11979
  const output = createOutput(options);
@@ -12397,30 +12474,11 @@ Examples:
12397
12474
 
12398
12475
  // dist/commands/watcherStart.js
12399
12476
  import crypto2 from "node:crypto";
12400
- import fs9 from "node:fs/promises";
12401
12477
  var isValidPort = (port) => Number.isFinite(port) && port >= 1 && port <= 65535;
12402
12478
  var parsePort2 = (value) => {
12403
12479
  const port = typeof value === "string" ? parseInt(value, 10) : value;
12404
12480
  return isValidPort(port) ? port : null;
12405
12481
  };
12406
- var resolveInjectScript2 = async (inject, output) => {
12407
- if (!inject) {
12408
- return null;
12409
- }
12410
- const resolvedPath = resolvePath(inject.file);
12411
- let script;
12412
- try {
12413
- script = await fs9.readFile(resolvedPath, "utf8");
12414
- } catch (error) {
12415
- output.writeWarn(`Failed to read inject script at ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}. Skipping injection.`);
12416
- return null;
12417
- }
12418
- if (script.trim() === "") {
12419
- output.writeWarn(`Inject script at ${resolvedPath} is empty. Skipping injection.`);
12420
- return null;
12421
- }
12422
- return { script, exposeArgus: inject.exposeArgus };
12423
- };
12424
12482
  var runWatcherStart = async (options) => {
12425
12483
  const output = createOutput(options);
12426
12484
  const sourceMode = options.source ?? "cdp";
@@ -12471,7 +12529,6 @@ var runWatcherStart = async (options) => {
12471
12529
  }
12472
12530
  }
12473
12531
  const watcherId = options.id?.trim() || generateWatcherId();
12474
- const matchUrl = options.url?.trim();
12475
12532
  let artifactsBaseDir;
12476
12533
  if (options.artifacts != null) {
12477
12534
  const trimmed = options.artifacts.trim();
@@ -12482,29 +12539,14 @@ var runWatcherStart = async (options) => {
12482
12539
  }
12483
12540
  artifactsBaseDir = resolvePath(trimmed);
12484
12541
  }
12485
- const inject = await resolveInjectScript2(options.inject, output);
12486
- const match = {};
12487
- if (matchUrl) {
12488
- match.url = matchUrl;
12489
- }
12490
- if (options.type?.trim()) {
12491
- match.type = options.type.trim();
12492
- }
12493
- if (options.origin?.trim()) {
12494
- match.origin = options.origin.trim();
12495
- }
12496
- if (options.target?.trim()) {
12497
- match.targetId = options.target.trim();
12498
- }
12499
- if (options.parent?.trim()) {
12500
- match.parent = options.parent.trim();
12501
- }
12542
+ const inject = await resolveInjectScript(options.inject, output);
12543
+ const match = sourceMode === "cdp" ? buildWatcherMatch(options) : undefined;
12502
12544
  let handle38;
12503
12545
  try {
12504
12546
  handle38 = await startWatcher({
12505
12547
  id: watcherId,
12506
12548
  source: sourceMode,
12507
- match: sourceMode === "cdp" && Object.keys(match).length > 0 ? match : undefined,
12549
+ match,
12508
12550
  chrome: sourceMode === "cdp" ? { host: chromeHost, port: chromePort } : undefined,
12509
12551
  host: "127.0.0.1",
12510
12552
  port: 0,
@@ -12525,11 +12567,11 @@ var runWatcherStart = async (options) => {
12525
12567
  port: handle38.watcher.port,
12526
12568
  pid: handle38.watcher.pid,
12527
12569
  source: sourceMode,
12528
- matchUrl: match.url,
12529
- matchType: match.type,
12530
- matchOrigin: match.origin,
12531
- matchTarget: match.targetId,
12532
- matchParent: match.parent,
12570
+ matchUrl: match?.url,
12571
+ matchType: match?.type,
12572
+ matchOrigin: match?.origin,
12573
+ matchTarget: match?.targetId,
12574
+ matchParent: match?.parent,
12533
12575
  chromeHost,
12534
12576
  chromePort,
12535
12577
  artifactsBaseDir
@@ -12539,12 +12581,7 @@ var runWatcherStart = async (options) => {
12539
12581
  await handle38.close();
12540
12582
  } catch {}
12541
12583
  };
12542
- process.on("SIGINT", () => {
12543
- cleanup().then(() => process.exit(0));
12544
- });
12545
- process.on("SIGTERM", () => {
12546
- cleanup().then(() => process.exit(0));
12547
- });
12584
+ registerTerminationHandlers(cleanup);
12548
12585
  handle38.events.on("cdpAttached", ({ target }) => {
12549
12586
  const typeInfo = target?.type ? ` (type: ${target.type})` : "";
12550
12587
  output.writeHuman(`[${handle38.watcher.id}] CDP attached: ${target?.title} (${target?.url})${typeInfo}`);
@@ -12582,7 +12619,7 @@ var runWatcherStart = async (options) => {
12582
12619
  output.writeHuman(` artifacts=${result.artifactsBaseDir}`);
12583
12620
  }
12584
12621
  }
12585
- await new Promise(() => {});
12622
+ await waitForever();
12586
12623
  };
12587
12624
  var generateWatcherId = () => crypto2.randomBytes(3).toString("hex");
12588
12625
 
@@ -12918,100 +12955,6 @@ var parseParamsString = (value) => {
12918
12955
  var isHttpUrl = (url) => {
12919
12956
  return url.startsWith("http://") || url.startsWith("https://");
12920
12957
  };
12921
- var getWebSocketCtor2 = () => {
12922
- const ctor = globalThis.WebSocket;
12923
- return ctor ?? null;
12924
- };
12925
- var toMessageText2 = (data) => {
12926
- if (typeof data === "string") {
12927
- return data;
12928
- }
12929
- if (data instanceof ArrayBuffer) {
12930
- return Buffer.from(data).toString("utf8");
12931
- }
12932
- if (Buffer.isBuffer(data)) {
12933
- return data.toString("utf8");
12934
- }
12935
- return null;
12936
- };
12937
- var sendCdpCommand2 = async (wsUrl, payload, timeoutMs = 5000) => {
12938
- const WebSocketConstructor = getWebSocketCtor2();
12939
- if (!WebSocketConstructor) {
12940
- throw new Error("WebSocket unavailable. Node 18+ required.");
12941
- }
12942
- const ws = new WebSocketConstructor(wsUrl);
12943
- const requestId = payload.id;
12944
- await new Promise((resolve2, reject) => {
12945
- let settled = false;
12946
- const timer = setTimeout(() => {
12947
- if (!settled) {
12948
- settled = true;
12949
- try {
12950
- ws.close();
12951
- } catch {}
12952
- reject(new Error(`CDP command timed out after ${timeoutMs}ms`));
12953
- }
12954
- }, timeoutMs);
12955
- const cleanup = () => {
12956
- clearTimeout(timer);
12957
- ws.removeEventListener?.("open", onOpen);
12958
- ws.removeEventListener?.("message", onMessage);
12959
- ws.removeEventListener?.("error", onError);
12960
- ws.removeEventListener?.("close", onClose);
12961
- };
12962
- const finish = (error) => {
12963
- if (settled) {
12964
- return;
12965
- }
12966
- settled = true;
12967
- cleanup();
12968
- try {
12969
- ws.close();
12970
- } catch {}
12971
- if (error) {
12972
- reject(error);
12973
- } else {
12974
- resolve2();
12975
- }
12976
- };
12977
- const onOpen = () => {
12978
- try {
12979
- ws.send(JSON.stringify(payload));
12980
- } catch (error) {
12981
- finish(error instanceof Error ? error : new Error(String(error)));
12982
- }
12983
- };
12984
- const onMessage = (event) => {
12985
- const text = toMessageText2(event.data);
12986
- if (!text) {
12987
- return;
12988
- }
12989
- try {
12990
- const message = JSON.parse(text);
12991
- if (message.id !== requestId) {
12992
- return;
12993
- }
12994
- if (message.error?.message) {
12995
- finish(new Error(message.error.message));
12996
- return;
12997
- }
12998
- finish();
12999
- } catch (error) {
13000
- finish(error instanceof Error ? error : new Error(String(error)));
13001
- }
13002
- };
13003
- const onError = () => {
13004
- finish(new Error("WebSocket error"));
13005
- };
13006
- const onClose = () => {
13007
- finish(new Error("WebSocket closed before response"));
13008
- };
13009
- ws.addEventListener("open", onOpen);
13010
- ws.addEventListener("message", onMessage);
13011
- ws.addEventListener("error", onError);
13012
- ws.addEventListener("close", onClose);
13013
- });
13014
- };
13015
12958
  var runPageReload = async (options) => {
13016
12959
  const output = createOutput(options);
13017
12960
  const hasParamFlag = (options.param?.length ?? 0) > 0;
@@ -13115,7 +13058,7 @@ var reloadTarget = async (target, context) => {
13115
13058
  }
13116
13059
  if (!context.hasParamFlag && !context.hasParamsFlag) {
13117
13060
  try {
13118
- await sendCdpCommand2(target.webSocketDebuggerUrl, { id: 1, method: "Page.reload" });
13061
+ await sendCdpCommand(target.webSocketDebuggerUrl, { id: 1, method: "Page.reload" });
13119
13062
  } catch (error) {
13120
13063
  output.writeWarn(`Failed to reload target ${target.id}: ${error instanceof Error ? error.message : error}`);
13121
13064
  process.exitCode = 1;
@@ -13171,7 +13114,7 @@ var reloadTarget = async (target, context) => {
13171
13114
  }
13172
13115
  const nextUrl = parsedUrl.toString();
13173
13116
  try {
13174
- await sendCdpCommand2(target.webSocketDebuggerUrl, { id: 1, method: "Page.navigate", params: { url: nextUrl } });
13117
+ await sendCdpCommand(target.webSocketDebuggerUrl, { id: 1, method: "Page.navigate", params: { url: nextUrl } });
13175
13118
  } catch (error) {
13176
13119
  output.writeWarn(`Failed to navigate target ${target.id}: ${error instanceof Error ? error.message : error}`);
13177
13120
  process.exitCode = 1;
@@ -13571,10 +13514,8 @@ var parseDurationMs = (value) => {
13571
13514
  return amount * multiplier;
13572
13515
  };
13573
13516
 
13574
- // dist/commands/logs.js
13575
- var runLogs = async (id, options) => {
13576
- const output = createOutput(options);
13577
- const params = new URLSearchParams;
13517
+ // dist/watchers/queryParams.js
13518
+ var appendAfterLimitParams = (params, options) => {
13578
13519
  const after = parseNumber(options.after);
13579
13520
  if (after != null) {
13580
13521
  params.set("after", String(after));
@@ -13583,19 +13524,38 @@ var runLogs = async (id, options) => {
13583
13524
  if (limit != null) {
13584
13525
  params.set("limit", String(limit));
13585
13526
  }
13527
+ };
13528
+ var appendSinceParam = (params, since) => {
13529
+ const resolved = resolveSinceTimestamp(since);
13530
+ if (resolved.error) {
13531
+ return resolved;
13532
+ }
13533
+ if (resolved.sinceTs == null) {
13534
+ return {};
13535
+ }
13536
+ params.set("sinceTs", String(resolved.sinceTs));
13537
+ return {};
13538
+ };
13539
+ var resolveSinceTimestamp = (since) => {
13540
+ if (!since) {
13541
+ return { sinceTs: null };
13542
+ }
13543
+ const duration = parseDurationMs(since);
13544
+ if (!duration) {
13545
+ return { sinceTs: null, error: `Invalid --since value: ${since}` };
13546
+ }
13547
+ return { sinceTs: Date.now() - duration };
13548
+ };
13549
+ var appendLogFilterParams = (params, options) => {
13586
13550
  if (options.levels) {
13587
13551
  params.set("levels", options.levels);
13588
13552
  }
13589
- const normalizedMatch = normalizeMatch(options.match);
13553
+ const normalizedMatch = normalizeMatchPatterns2(options.match);
13590
13554
  if (normalizedMatch.error) {
13591
- output.writeWarn(normalizedMatch.error);
13592
- process.exitCode = 2;
13593
- return;
13555
+ return normalizedMatch;
13594
13556
  }
13595
- if (normalizedMatch.match) {
13596
- for (const pattern of normalizedMatch.match) {
13597
- params.append("match", pattern);
13598
- }
13557
+ for (const pattern of normalizedMatch.patterns) {
13558
+ params.append("match", pattern);
13599
13559
  }
13600
13560
  const matchCase = resolveMatchCase2(options);
13601
13561
  if (matchCase) {
@@ -13605,14 +13565,50 @@ var runLogs = async (id, options) => {
13605
13565
  if (source) {
13606
13566
  params.set("source", source);
13607
13567
  }
13608
- if (options.since) {
13609
- const duration = parseDurationMs(options.since);
13610
- if (!duration) {
13611
- output.writeWarn(`Invalid --since value: ${options.since}`);
13612
- process.exitCode = 2;
13613
- return;
13614
- }
13615
- params.set("sinceTs", String(Date.now() - duration));
13568
+ return {};
13569
+ };
13570
+ var appendNetFilterParams = (params, options) => {
13571
+ const grep = normalizeQueryValue(options.grep);
13572
+ if (grep) {
13573
+ params.set("grep", grep);
13574
+ }
13575
+ };
13576
+ var normalizeMatchPatterns2 = (match) => {
13577
+ if (!match || match.length === 0) {
13578
+ return { patterns: [] };
13579
+ }
13580
+ const patterns = match.map((value) => value.trim());
13581
+ if (patterns.some((value) => value.length === 0)) {
13582
+ return { patterns: [], error: "Invalid --match value: empty pattern." };
13583
+ }
13584
+ return { patterns };
13585
+ };
13586
+ var resolveMatchCase2 = (options) => {
13587
+ if (options.caseSensitive) {
13588
+ return "sensitive";
13589
+ }
13590
+ if (options.ignoreCase) {
13591
+ return "insensitive";
13592
+ }
13593
+ return;
13594
+ };
13595
+
13596
+ // dist/commands/logs.js
13597
+ var runLogs = async (id, options) => {
13598
+ const output = createOutput(options);
13599
+ const params = new URLSearchParams;
13600
+ appendAfterLimitParams(params, options);
13601
+ const filters = appendLogFilterParams(params, options);
13602
+ if (filters.error) {
13603
+ output.writeWarn(filters.error);
13604
+ process.exitCode = 2;
13605
+ return;
13606
+ }
13607
+ const since = appendSinceParam(params, options.since);
13608
+ if (since.error) {
13609
+ output.writeWarn(since.error);
13610
+ process.exitCode = 2;
13611
+ return;
13616
13612
  }
13617
13613
  const result = await requestWatcherJson({
13618
13614
  id,
@@ -13639,26 +13635,6 @@ var runLogs = async (id, options) => {
13639
13635
  }));
13640
13636
  }
13641
13637
  };
13642
- var normalizeMatch = (match) => {
13643
- if (!match || match.length === 0) {
13644
- return {};
13645
- }
13646
- const normalized = match.map((value) => value.trim());
13647
- const invalid = normalized.find((value) => value.length === 0);
13648
- if (invalid != null) {
13649
- return { error: "Invalid --match value: empty pattern." };
13650
- }
13651
- return { match: normalized };
13652
- };
13653
- var resolveMatchCase2 = (options) => {
13654
- if (options.caseSensitive) {
13655
- return "sensitive";
13656
- }
13657
- if (options.ignoreCase) {
13658
- return "insensitive";
13659
- }
13660
- return;
13661
- };
13662
13638
 
13663
13639
  // dist/commands/tail.js
13664
13640
  var runTail = async (id, options) => {
@@ -13683,34 +13659,18 @@ var runTail = async (id, options) => {
13683
13659
  if (limit != null) {
13684
13660
  params.set("limit", String(limit));
13685
13661
  }
13686
- if (options.levels) {
13687
- params.set("levels", options.levels);
13688
- }
13689
- const normalizedMatch = normalizeMatch2(options.match);
13690
- if (normalizedMatch.error) {
13691
- output.writeWarn(normalizedMatch.error);
13662
+ const filters = appendLogFilterParams(params, options);
13663
+ if (filters.error) {
13664
+ output.writeWarn(filters.error);
13692
13665
  process.exitCode = 2;
13693
13666
  return;
13694
13667
  }
13695
- if (normalizedMatch.match) {
13696
- for (const pattern of normalizedMatch.match) {
13697
- params.append("match", pattern);
13698
- }
13699
- }
13700
- const matchCase = resolveMatchCase3(options);
13701
- if (matchCase) {
13702
- params.set("matchCase", matchCase);
13703
- }
13704
- const source = normalizeQueryValue(options.source);
13705
- if (source) {
13706
- params.set("source", source);
13707
- }
13708
- const url = `http://${watcher.host}:${watcher.port}/tail?${params.toString()}`;
13668
+ const url = buildWatcherUrl(watcher, "/tail", params);
13709
13669
  let response;
13710
13670
  try {
13711
13671
  response = await fetchJson(url, { timeoutMs: timeoutMs + 5000 });
13712
13672
  } catch (error) {
13713
- output.writeWarn(`${watcher.id}: failed to reach watcher (${formatError(error)})`);
13673
+ output.writeWarn(formatWatcherTransportError(watcher, error));
13714
13674
  process.exitCode = 1;
13715
13675
  return;
13716
13676
  }
@@ -13733,26 +13693,6 @@ var runTail = async (id, options) => {
13733
13693
  after = response.nextAfter;
13734
13694
  }
13735
13695
  };
13736
- var normalizeMatch2 = (match) => {
13737
- if (!match || match.length === 0) {
13738
- return {};
13739
- }
13740
- const normalized = match.map((value) => value.trim());
13741
- const invalid = normalized.find((value) => value.length === 0);
13742
- if (invalid != null) {
13743
- return { error: "Invalid --match value: empty pattern." };
13744
- }
13745
- return { match: normalized };
13746
- };
13747
- var resolveMatchCase3 = (options) => {
13748
- if (options.caseSensitive) {
13749
- return "sensitive";
13750
- }
13751
- if (options.ignoreCase) {
13752
- return "insensitive";
13753
- }
13754
- return;
13755
- };
13756
13696
 
13757
13697
  // dist/cli/register/registerLogs.js
13758
13698
  function registerLogs(program2) {
@@ -13802,26 +13742,13 @@ Examples:
13802
13742
  var runNet = async (id, options) => {
13803
13743
  const output = createOutput(options);
13804
13744
  const params = new URLSearchParams;
13805
- const after = parseNumber(options.after);
13806
- if (after != null) {
13807
- params.set("after", String(after));
13808
- }
13809
- const limit = parseNumber(options.limit);
13810
- if (limit != null) {
13811
- params.set("limit", String(limit));
13812
- }
13813
- if (options.since) {
13814
- const duration = parseDurationMs(options.since);
13815
- if (!duration) {
13816
- output.writeWarn(`Invalid --since value: ${options.since}`);
13817
- process.exitCode = 2;
13818
- return;
13819
- }
13820
- params.set("sinceTs", String(Date.now() - duration));
13821
- }
13822
- const grep = normalizeQueryValue(options.grep);
13823
- if (grep) {
13824
- params.set("grep", grep);
13745
+ appendAfterLimitParams(params, options);
13746
+ appendNetFilterParams(params, options);
13747
+ const since = appendSinceParam(params, options.since);
13748
+ if (since.error) {
13749
+ output.writeWarn(since.error);
13750
+ process.exitCode = 2;
13751
+ return;
13825
13752
  }
13826
13753
  const result = await requestWatcherJson({
13827
13754
  id,
@@ -13852,14 +13779,12 @@ var runNetTail = async (id, options) => {
13852
13779
  let after = parseNumber(options.after) ?? 0;
13853
13780
  const timeoutMs = parseNumber(options.timeout) ?? 25000;
13854
13781
  const limit = parseNumber(options.limit);
13855
- const sinceTsResult = resolveSinceTs(options.since);
13856
- if (sinceTsResult.error) {
13857
- output.writeWarn(sinceTsResult.error);
13782
+ const since = resolveSinceTimestamp(options.since);
13783
+ if (since.error) {
13784
+ output.writeWarn(since.error);
13858
13785
  process.exitCode = 2;
13859
13786
  return;
13860
13787
  }
13861
- const sinceTs = sinceTsResult.value;
13862
- const grep = normalizeQueryValue(options.grep);
13863
13788
  let running = true;
13864
13789
  const stop = () => {
13865
13790
  running = false;
@@ -13873,18 +13798,16 @@ var runNetTail = async (id, options) => {
13873
13798
  if (limit != null) {
13874
13799
  params.set("limit", String(limit));
13875
13800
  }
13876
- if (sinceTs != null) {
13877
- params.set("sinceTs", String(sinceTs));
13878
- }
13879
- if (grep) {
13880
- params.set("grep", grep);
13801
+ if (since.sinceTs != null) {
13802
+ params.set("sinceTs", String(since.sinceTs));
13881
13803
  }
13882
- const url = `http://${watcher.host}:${watcher.port}/net/tail?${params.toString()}`;
13804
+ appendNetFilterParams(params, options);
13805
+ const url = buildWatcherUrl(watcher, "/net/tail", params);
13883
13806
  let response;
13884
13807
  try {
13885
13808
  response = await fetchJson(url, { timeoutMs: timeoutMs + 5000 });
13886
13809
  } catch (error) {
13887
- output.writeWarn(`${watcher.id}: failed to reach watcher (${formatError(error)})`);
13810
+ output.writeWarn(formatWatcherTransportError(watcher, error));
13888
13811
  process.exitCode = 1;
13889
13812
  return;
13890
13813
  }
@@ -13900,16 +13823,6 @@ var runNetTail = async (id, options) => {
13900
13823
  after = response.nextAfter;
13901
13824
  }
13902
13825
  };
13903
- var resolveSinceTs = (value) => {
13904
- if (!value) {
13905
- return { value: null };
13906
- }
13907
- const duration = parseDurationMs(value);
13908
- if (!duration) {
13909
- return { value: null, error: `Invalid --since value: ${value}` };
13910
- }
13911
- return { value: Date.now() - duration };
13912
- };
13913
13826
 
13914
13827
  // dist/cli/register/registerNet.js
13915
13828
  function registerNet(program2) {
@@ -14122,7 +14035,6 @@ var addCookieScopeOptions = (command, forOriginDescription) => command.option("-
14122
14035
 
14123
14036
  // dist/eval/evalClient.js
14124
14037
  var evalOnce = async (input) => {
14125
- const url = `http://${input.watcher.host}:${input.watcher.port}/eval`;
14126
14038
  const body = {
14127
14039
  expression: input.expression,
14128
14040
  awaitPromise: input.awaitPromise,
@@ -14132,7 +14044,8 @@ var evalOnce = async (input) => {
14132
14044
  };
14133
14045
  let response;
14134
14046
  try {
14135
- response = await fetchJson(url, {
14047
+ response = await fetchWatcherJson(input.watcher, {
14048
+ path: "/eval",
14136
14049
  method: "POST",
14137
14050
  body,
14138
14051
  timeoutMs: input.timeoutMs ? input.timeoutMs + 5000 : 1e4
@@ -14141,7 +14054,7 @@ var evalOnce = async (input) => {
14141
14054
  return {
14142
14055
  ok: false,
14143
14056
  kind: "transport",
14144
- error: `${input.watcher.id}: failed to reach watcher (${formatError5(error)})`
14057
+ error: formatWatcherTransportError(input.watcher, error)
14145
14058
  };
14146
14059
  }
14147
14060
  if (response.exception && input.failOnException) {
@@ -14178,19 +14091,10 @@ var evalWithRetries = async (input) => {
14178
14091
  return {
14179
14092
  ok: false,
14180
14093
  kind: "transport",
14181
- error: `${input.watcher.id}: failed to reach watcher (unknown error)`,
14094
+ error: formatWatcherTransportError(input.watcher, "unknown error"),
14182
14095
  attempt
14183
14096
  };
14184
14097
  };
14185
- var formatError5 = (error) => {
14186
- if (!error) {
14187
- return "unknown error";
14188
- }
14189
- if (error instanceof Error) {
14190
- return error.message;
14191
- }
14192
- return String(error);
14193
- };
14194
14098
 
14195
14099
  // dist/commands/evalShared.js
14196
14100
  import { readFile } from "node:fs/promises";
@@ -14630,7 +14534,7 @@ var parseTotalTimeout = (value) => {
14630
14534
  };
14631
14535
 
14632
14536
  // dist/commands/iframeHelper.js
14633
- import * as fs10 from "node:fs/promises";
14537
+ import * as fs9 from "node:fs/promises";
14634
14538
  var runIframeHelper = async (options) => {
14635
14539
  const script = generateIframeHelperScript({
14636
14540
  log: options.log ?? true,
@@ -14638,7 +14542,7 @@ var runIframeHelper = async (options) => {
14638
14542
  namespace: options.namespace ?? "argus"
14639
14543
  });
14640
14544
  if (options.out) {
14641
- await fs10.writeFile(options.out, script, "utf-8");
14545
+ await fs9.writeFile(options.out, script, "utf-8");
14642
14546
  console.error(`Written to ${options.out}`);
14643
14547
  } else {
14644
14548
  process.stdout.write(script);
@@ -15405,7 +15309,7 @@ var runDomRemove = async (id, options) => {
15405
15309
  };
15406
15310
 
15407
15311
  // dist/commands/domSetFile.js
15408
- import fs11 from "node:fs";
15312
+ import fs10 from "node:fs";
15409
15313
  var runDomSetFile = async (id, options) => {
15410
15314
  const output = createOutput(options);
15411
15315
  if (!options.selector || options.selector.trim() === "") {
@@ -15421,7 +15325,7 @@ var runDomSetFile = async (id, options) => {
15421
15325
  const files = [];
15422
15326
  for (const f of options.file) {
15423
15327
  const absolute = resolvePath(f);
15424
- if (!fs11.existsSync(absolute)) {
15328
+ if (!fs10.existsSync(absolute)) {
15425
15329
  output.writeWarn(`File not found: ${absolute}`);
15426
15330
  process.exitCode = 2;
15427
15331
  return;
@@ -16918,9 +16822,9 @@ var runTraceStop = async (id, options) => {
16918
16822
  output.writeHuman(`Trace saved: ${stop.outFile} (${stop.eventCount} events, ${formatDurationMs(stop.durationMs)})`);
16919
16823
  };
16920
16824
  var runTraceStartInternal = async (watcher, options, output) => {
16921
- const url = `http://${watcher.host}:${watcher.port}/trace/start`;
16922
16825
  try {
16923
- const response = await fetchJson(url, {
16826
+ const response = await fetchWatcherJson(watcher, {
16827
+ path: "/trace/start",
16924
16828
  method: "POST",
16925
16829
  body: {
16926
16830
  outFile: options.out,
@@ -16931,22 +16835,22 @@ var runTraceStartInternal = async (watcher, options, output) => {
16931
16835
  });
16932
16836
  return response;
16933
16837
  } catch (error) {
16934
- output.writeWarn(`${watcher.id}: failed to reach watcher (${formatError(error)})`);
16838
+ output.writeWarn(formatWatcherTransportError(watcher, error));
16935
16839
  process.exitCode = 1;
16936
16840
  return null;
16937
16841
  }
16938
16842
  };
16939
16843
  var runTraceStopInternal = async (watcher, options, output) => {
16940
- const url = `http://${watcher.host}:${watcher.port}/trace/stop`;
16941
16844
  try {
16942
- const response = await fetchJson(url, {
16845
+ const response = await fetchWatcherJson(watcher, {
16846
+ path: "/trace/stop",
16943
16847
  method: "POST",
16944
16848
  body: { traceId: options.traceId, outFile: options.outFile },
16945
16849
  timeoutMs: 20000
16946
16850
  });
16947
16851
  return response;
16948
16852
  } catch (error) {
16949
- output.writeWarn(`${watcher.id}: failed to reach watcher (${formatError(error)})`);
16853
+ output.writeWarn(formatWatcherTransportError(watcher, error));
16950
16854
  process.exitCode = 1;
16951
16855
  return null;
16952
16856
  }
@@ -16995,7 +16899,7 @@ function resolveActionOptions(options, command) {
16995
16899
  }
16996
16900
 
16997
16901
  // dist/commands/configInit.js
16998
- import fs12 from "node:fs/promises";
16902
+ import fs11 from "node:fs/promises";
16999
16903
  import path11 from "node:path";
17000
16904
  import { fileURLToPath, pathToFileURL } from "node:url";
17001
16905
  var DEFAULT_CONFIG_PATH = ".argus/config.json";
@@ -17029,7 +16933,7 @@ var resolveConfigPath = (cwd, targetPath) => {
17029
16933
  var ensureParentDir2 = async (filePath) => {
17030
16934
  const dir = path11.dirname(filePath);
17031
16935
  try {
17032
- await fs12.mkdir(dir, { recursive: true });
16936
+ await fs11.mkdir(dir, { recursive: true });
17033
16937
  return true;
17034
16938
  } catch (error) {
17035
16939
  console.error(`Failed to create config directory ${dir}: ${error instanceof Error ? error.message : String(error)}`);
@@ -17039,7 +16943,7 @@ var ensureParentDir2 = async (filePath) => {
17039
16943
  };
17040
16944
  var writeConfigFile = async (filePath, contents, force) => {
17041
16945
  try {
17042
- await fs12.writeFile(filePath, contents, { encoding: "utf8", flag: force ? "w" : "wx" });
16946
+ await fs11.writeFile(filePath, contents, { encoding: "utf8", flag: force ? "w" : "wx" });
17043
16947
  return true;
17044
16948
  } catch (error) {
17045
16949
  if (error.code === "EEXIST") {
@@ -17054,7 +16958,7 @@ var writeConfigFile = async (filePath, contents, force) => {
17054
16958
  };
17055
16959
  var ensureSchemaFile = async (schemaPath) => {
17056
16960
  try {
17057
- const stats = await fs12.stat(schemaPath);
16961
+ const stats = await fs11.stat(schemaPath);
17058
16962
  if (!stats.isFile()) {
17059
16963
  console.error(`Schema path is not a file: ${schemaPath}`);
17060
16964
  process.exitCode = 2;
@@ -17107,11 +17011,11 @@ Examples:
17107
17011
  }
17108
17012
 
17109
17013
  // dist/commands/extension/setup.js
17110
- import fs14 from "node:fs";
17014
+ import fs13 from "node:fs";
17111
17015
  import { execSync as execSync2 } from "node:child_process";
17112
17016
 
17113
17017
  // dist/commands/extension/nativeHost.js
17114
- import fs13 from "node:fs";
17018
+ import fs12 from "node:fs";
17115
17019
  import path12 from "node:path";
17116
17020
  import os4 from "node:os";
17117
17021
  import { execSync } from "node:child_process";
@@ -17145,7 +17049,7 @@ var findArgusExecutable = () => {
17145
17049
  try {
17146
17050
  const npmGlobalPrefix = execSync("npm config get prefix", { encoding: "utf8" }).trim();
17147
17051
  const globalBinPath = path12.join(npmGlobalPrefix, "bin", "argus");
17148
- if (fs13.existsSync(globalBinPath)) {
17052
+ if (fs12.existsSync(globalBinPath)) {
17149
17053
  return globalBinPath;
17150
17054
  }
17151
17055
  } catch {}
@@ -17158,7 +17062,7 @@ var findArgusExecutable = () => {
17158
17062
  throw new Error("Could not find argus executable. Please install argus globally (npm install -g @vforsh/argus) or ensure it is in your PATH.");
17159
17063
  };
17160
17064
  var findNodePath = () => {
17161
- return fs13.realpathSync(process.execPath);
17065
+ return fs12.realpathSync(process.execPath);
17162
17066
  };
17163
17067
  var createManifest = (extensionId, executablePath) => {
17164
17068
  return {
@@ -17176,12 +17080,12 @@ var createWrapperScript = (platform, executablePath) => {
17176
17080
  const script = `#!/bin/bash
17177
17081
  exec "${nodePath}" "${executablePath}" watcher native-host
17178
17082
  `;
17179
- fs13.writeFileSync(wrapperPath, script, { mode: 493 });
17083
+ fs12.writeFileSync(wrapperPath, script, { mode: 493 });
17180
17084
  return wrapperPath;
17181
17085
  };
17182
17086
  var readManifest = (manifestPath) => {
17183
17087
  try {
17184
- const content = fs13.readFileSync(manifestPath, "utf8");
17088
+ const content = fs12.readFileSync(manifestPath, "utf8");
17185
17089
  return JSON.parse(content);
17186
17090
  } catch {
17187
17091
  return null;
@@ -17189,7 +17093,7 @@ var readManifest = (manifestPath) => {
17189
17093
  };
17190
17094
  var isWrapperExecutable = (wrapperPath) => {
17191
17095
  try {
17192
- fs13.accessSync(wrapperPath, fs13.constants.X_OK);
17096
+ fs12.accessSync(wrapperPath, fs12.constants.X_OK);
17193
17097
  return true;
17194
17098
  } catch {
17195
17099
  return false;
@@ -17222,7 +17126,7 @@ var runExtensionSetup = async (options) => {
17222
17126
  const manifestDir = getManifestDir(platform);
17223
17127
  const manifestPath = getManifestPath(platform);
17224
17128
  const wrapperPath = getWrapperPath(platform);
17225
- fs14.mkdirSync(manifestDir, { recursive: true });
17129
+ fs13.mkdirSync(manifestDir, { recursive: true });
17226
17130
  let executablePath;
17227
17131
  try {
17228
17132
  executablePath = findArgusExecutable();
@@ -17237,7 +17141,7 @@ var runExtensionSetup = async (options) => {
17237
17141
  }
17238
17142
  createWrapperScript(platform, executablePath);
17239
17143
  const manifest = createManifest(extensionId, wrapperPath);
17240
- fs14.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
17144
+ fs13.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
17241
17145
  if (platform === "win32") {
17242
17146
  const regKey = `HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\${HOST_NAME}`;
17243
17147
  try {
@@ -17278,7 +17182,7 @@ var runExtensionSetup = async (options) => {
17278
17182
  };
17279
17183
 
17280
17184
  // dist/commands/extension/remove.js
17281
- import fs15 from "node:fs";
17185
+ import fs14 from "node:fs";
17282
17186
  import { execSync as execSync3 } from "node:child_process";
17283
17187
  var runExtensionRemove = async (options) => {
17284
17188
  const output = createOutput(options);
@@ -17298,12 +17202,12 @@ var runExtensionRemove = async (options) => {
17298
17202
  const wrapperPath = getWrapperPath(platform);
17299
17203
  let manifestRemoved = false;
17300
17204
  let wrapperRemoved = false;
17301
- if (fs15.existsSync(manifestPath)) {
17302
- fs15.unlinkSync(manifestPath);
17205
+ if (fs14.existsSync(manifestPath)) {
17206
+ fs14.unlinkSync(manifestPath);
17303
17207
  manifestRemoved = true;
17304
17208
  }
17305
- if (fs15.existsSync(wrapperPath)) {
17306
- fs15.unlinkSync(wrapperPath);
17209
+ if (fs14.existsSync(wrapperPath)) {
17210
+ fs14.unlinkSync(wrapperPath);
17307
17211
  wrapperRemoved = true;
17308
17212
  }
17309
17213
  if (platform === "win32") {
@@ -17342,7 +17246,7 @@ var runExtensionRemove = async (options) => {
17342
17246
  };
17343
17247
 
17344
17248
  // dist/commands/extension/status.js
17345
- import fs16 from "node:fs";
17249
+ import fs15 from "node:fs";
17346
17250
  var runExtensionStatus = async (options) => {
17347
17251
  const output = createOutput(options);
17348
17252
  let platform;
@@ -17359,8 +17263,8 @@ var runExtensionStatus = async (options) => {
17359
17263
  }
17360
17264
  const manifestPath = getManifestPath(platform);
17361
17265
  const wrapperPath = getWrapperPath(platform);
17362
- const manifestExists = fs16.existsSync(manifestPath);
17363
- const wrapperExists = fs16.existsSync(wrapperPath);
17266
+ const manifestExists = fs15.existsSync(manifestPath);
17267
+ const wrapperExists = fs15.existsSync(wrapperPath);
17364
17268
  const wrapperExecutable = wrapperExists && isWrapperExecutable(wrapperPath);
17365
17269
  let manifest = null;
17366
17270
  let manifestValid = false;
@@ -17420,7 +17324,7 @@ var runExtensionStatus = async (options) => {
17420
17324
  };
17421
17325
 
17422
17326
  // dist/commands/extension/info.js
17423
- import fs17 from "node:fs";
17327
+ import fs16 from "node:fs";
17424
17328
  var runExtensionInfo = async (options) => {
17425
17329
  const output = createOutput(options);
17426
17330
  let platform;
@@ -17437,8 +17341,8 @@ var runExtensionInfo = async (options) => {
17437
17341
  }
17438
17342
  const manifestPath = getManifestPath(platform);
17439
17343
  const wrapperPath = getWrapperPath(platform);
17440
- const manifestExists = fs17.existsSync(manifestPath);
17441
- const wrapperExists = fs17.existsSync(wrapperPath);
17344
+ const manifestExists = fs16.existsSync(manifestPath);
17345
+ const wrapperExists = fs16.existsSync(wrapperPath);
17442
17346
  let extensionId = null;
17443
17347
  let argusPath = null;
17444
17348
  if (manifestExists) {
@@ -27757,7 +27661,7 @@ function hr2(a2, t, e) {
27757
27661
  }
27758
27662
  return t;
27759
27663
  }
27760
- var fs18 = hr2;
27664
+ var fs17 = hr2;
27761
27665
  function cr2(a2, t) {
27762
27666
  return t === false ? false : a2.charAt(t) === "/" && a2.charAt(t + 1) === "/" ? ls(a2, t) : t;
27763
27667
  }
@@ -27765,7 +27669,7 @@ var ds = cr2;
27765
27669
  function lr2(a2, t) {
27766
27670
  let e = null, s = t;
27767
27671
  for (;s !== e; )
27768
- e = s, s = cs(a2, s), s = ps(a2, s), s = ds(a2, s), s = fs18(a2, s);
27672
+ e = s, s = cs(a2, s), s = ps(a2, s), s = ds(a2, s), s = fs17(a2, s);
27769
27673
  return s;
27770
27674
  }
27771
27675
  var ms = lr2;
@@ -29765,13 +29669,13 @@ function kc({ node: e, parent: t }) {
29765
29669
  let r = /^[fx]?(?:describe|it|test)$/u;
29766
29670
  return t.type === "TaggedTemplateExpression" && t.quasi === e && t.tag.type === "MemberExpression" && t.tag.property.type === "Identifier" && t.tag.property.name === "each" && (t.tag.object.type === "Identifier" && r.test(t.tag.object.name) || t.tag.object.type === "MemberExpression" && t.tag.object.property.type === "Identifier" && (t.tag.object.property.name === "only" || t.tag.object.property.name === "skip") && t.tag.object.object.type === "Identifier" && r.test(t.tag.object.object.name));
29767
29671
  }
29768
- var fs19 = [(e, t) => e.type === "ObjectExpression" && t === "properties", (e, t) => e.type === "CallExpression" && e.callee.type === "Identifier" && e.callee.name === "Component" && t === "arguments", (e, t) => e.type === "Decorator" && t === "expression"];
29672
+ var fs18 = [(e, t) => e.type === "ObjectExpression" && t === "properties", (e, t) => e.type === "CallExpression" && e.callee.type === "Identifier" && e.callee.name === "Component" && t === "arguments", (e, t) => e.type === "Decorator" && t === "expression"];
29769
29673
  function oo2(e) {
29770
29674
  let t = (n) => n.type === "TemplateLiteral", r = (n, s) => Oe3(n) && !n.computed && n.key.type === "Identifier" && n.key.name === "styles" && s === "value";
29771
- return e.match(t, (n, s) => q3(n) && s === "elements", r, ...fs19) || e.match(t, r, ...fs19);
29675
+ return e.match(t, (n, s) => q3(n) && s === "elements", r, ...fs18) || e.match(t, r, ...fs18);
29772
29676
  }
29773
29677
  function ys2(e) {
29774
- return e.match((t) => t.type === "TemplateLiteral", (t, r) => Oe3(t) && !t.computed && t.key.type === "Identifier" && t.key.name === "template" && r === "value", ...fs19);
29678
+ return e.match((t) => t.type === "TemplateLiteral", (t, r) => Oe3(t) && !t.computed && t.key.type === "Identifier" && t.key.name === "template" && r === "value", ...fs18);
29775
29679
  }
29776
29680
  function Ds2(e, t) {
29777
29681
  return T3(e, x2.Block | x2.Leading, ({ value: r }) => r === ` ${t} `);
@@ -33678,7 +33582,7 @@ var ft4 = w4((gx, Mi3) => {
33678
33582
  ct4.default = ct4;
33679
33583
  });
33680
33584
  var fe3 = w4((wx, zi3) => {
33681
- var Bi3 = Me4(), Ui3 = ft4(), Fc2 = ut4(), { isClean: Fi3, my: $i3 } = Ht4(), fs20, Wi3, Gi3, ps3;
33585
+ var Bi3 = Me4(), Ui3 = ft4(), Fc2 = ut4(), { isClean: Fi3, my: $i3 } = Ht4(), fs19, Wi3, Gi3, ps3;
33682
33586
  function Yi3(t) {
33683
33587
  return t.map((e) => (e.nodes && (e.nodes = Yi3(e.nodes)), delete e.source, e));
33684
33588
  }
@@ -33777,7 +33681,7 @@ var fe3 = w4((wx, zi3) => {
33777
33681
  } else if (e.selector || e.selectors)
33778
33682
  e = [new ps3(e)];
33779
33683
  else if (e.name)
33780
- e = [new fs20(e)];
33684
+ e = [new fs19(e)];
33781
33685
  else if (e.text)
33782
33686
  e = [new Bi3(e)];
33783
33687
  else
@@ -33879,7 +33783,7 @@ var fe3 = w4((wx, zi3) => {
33879
33783
  ps3 = t;
33880
33784
  };
33881
33785
  z3.registerAtRule = (t) => {
33882
- fs20 = t;
33786
+ fs19 = t;
33883
33787
  };
33884
33788
  z3.registerRoot = (t) => {
33885
33789
  Gi3 = t;
@@ -33887,7 +33791,7 @@ var fe3 = w4((wx, zi3) => {
33887
33791
  zi3.exports = z3;
33888
33792
  z3.default = z3;
33889
33793
  z3.rebuild = (t) => {
33890
- t.type === "atrule" ? Object.setPrototypeOf(t, fs20.prototype) : t.type === "rule" ? Object.setPrototypeOf(t, ps3.prototype) : t.type === "decl" ? Object.setPrototypeOf(t, Ui3.prototype) : t.type === "comment" ? Object.setPrototypeOf(t, Bi3.prototype) : t.type === "root" && Object.setPrototypeOf(t, Gi3.prototype), t[$i3] = true, t.nodes && t.nodes.forEach((e) => {
33794
+ t.type === "atrule" ? Object.setPrototypeOf(t, fs19.prototype) : t.type === "rule" ? Object.setPrototypeOf(t, ps3.prototype) : t.type === "decl" ? Object.setPrototypeOf(t, Ui3.prototype) : t.type === "comment" ? Object.setPrototypeOf(t, Bi3.prototype) : t.type === "root" && Object.setPrototypeOf(t, Gi3.prototype), t[$i3] = true, t.nodes && t.nodes.forEach((e) => {
33891
33795
  z3.rebuild(e);
33892
33796
  });
33893
33797
  };
@@ -38851,7 +38755,7 @@ var readQuotedLiteral = (source, startIndex, startLineNumber, quote) => {
38851
38755
  return { value: null, nextIndex: index, lineNumber, startLineNumber };
38852
38756
  };
38853
38757
  var classifyCodeString = (value, includeAll) => {
38854
- if (/[\u0000-\u001f]/.test(value)) {
38758
+ if (hasControlChars(value)) {
38855
38759
  return null;
38856
38760
  }
38857
38761
  const kind = detectInterestingKind(value);
@@ -38875,6 +38779,14 @@ var detectInterestingKind = (value) => {
38875
38779
  }
38876
38780
  return null;
38877
38781
  };
38782
+ var hasControlChars = (value) => {
38783
+ for (let index = 0;index < value.length; index += 1) {
38784
+ if (value.charCodeAt(index) < 32) {
38785
+ return true;
38786
+ }
38787
+ }
38788
+ return false;
38789
+ };
38878
38790
  var rankCodeStrings = (matches) => matches.map((match) => ({
38879
38791
  ...match,
38880
38792
  score: scoreCodeString(match)