@vforsh/argus 0.5.1 → 0.5.3

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 (37) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/argus.js +232 -51
  3. package/dist/cli/register/recordCommands.d.ts.map +1 -1
  4. package/dist/cli/register/recordCommands.js +6 -3
  5. package/dist/cli/register/recordCommands.js.map +1 -1
  6. package/dist/cli/register/snapshotCommands.js +1 -1
  7. package/dist/cli/register/snapshotCommands.js.map +1 -1
  8. package/dist/cli/register/traceCommands.d.ts.map +1 -1
  9. package/dist/cli/register/traceCommands.js +6 -3
  10. package/dist/cli/register/traceCommands.js.map +1 -1
  11. package/dist/commands/domKeydown.d.ts.map +1 -1
  12. package/dist/commands/domKeydown.js +7 -2
  13. package/dist/commands/domKeydown.js.map +1 -1
  14. package/dist/commands/page.js +2 -2
  15. package/dist/commands/page.js.map +1 -1
  16. package/dist/commands/record.d.ts.map +1 -1
  17. package/dist/commands/record.js +3 -2
  18. package/dist/commands/record.js.map +1 -1
  19. package/dist/commands/screenshot.d.ts.map +1 -1
  20. package/dist/commands/screenshot.js +2 -1
  21. package/dist/commands/screenshot.js.map +1 -1
  22. package/dist/commands/trace.d.ts.map +1 -1
  23. package/dist/commands/trace.js +3 -2
  24. package/dist/commands/trace.js.map +1 -1
  25. package/dist/eval/evalClient.d.ts +9 -1
  26. package/dist/eval/evalClient.d.ts.map +1 -1
  27. package/dist/eval/evalClient.js +31 -8
  28. package/dist/eval/evalClient.js.map +1 -1
  29. package/dist/skill/argus/SKILL.md +6 -0
  30. package/dist/skill/argus/reference/CAPTURE.md +6 -0
  31. package/dist/skill/argus/reference/EVAL.md +2 -0
  32. package/dist/skill/argus/reference/INSPECT.md +6 -0
  33. package/dist/utils/paths.d.ts +12 -0
  34. package/dist/utils/paths.d.ts.map +1 -1
  35. package/dist/utils/paths.js +15 -0
  36. package/dist/utils/paths.js.map +1 -1
  37. package/package.json +1 -1
package/dist/argus.js CHANGED
@@ -2130,7 +2130,7 @@ var {
2130
2130
  // package.json
2131
2131
  var package_default = {
2132
2132
  name: "@vforsh/argus",
2133
- version: "0.5.1",
2133
+ version: "0.5.3",
2134
2134
  repository: {
2135
2135
  type: "git",
2136
2136
  url: "git+https://github.com/vforsh/argus.git",
@@ -3551,6 +3551,11 @@ var ARGUS_ERROR_CODES = [
3551
3551
  "argus_executable_not_found",
3552
3552
  "body_not_available",
3553
3553
  "cdp_not_attached",
3554
+ "cdp_renderer_unresponsive",
3555
+ "cdp_target_replaced",
3556
+ "cdp_timeout",
3557
+ "chrome_unreachable",
3558
+ "dialog_blocking",
3554
3559
  "dialog_not_prompt",
3555
3560
  "extension_action_failed",
3556
3561
  "extension_frame_not_ready",
@@ -3580,6 +3585,7 @@ var ARGUS_ERROR_CODES = [
3580
3585
  "session_invalid_request",
3581
3586
  "session_request_timeout",
3582
3587
  "session_unknown_command",
3588
+ "target_not_focused",
3583
3589
  "unexpected_matches",
3584
3590
  "unsupported_platform"
3585
3591
  ];
@@ -4451,7 +4457,7 @@ var buildWatcherUrl = (watcher, path4, query2) => {
4451
4457
  const qs = query2?.toString();
4452
4458
  return `http://${watcher.host}:${watcher.port}${path4}${qs ? `?${qs}` : ""}`;
4453
4459
  };
4454
- var formatWatcherTransportError = (watcher, error) => `${watcher.id}: failed to reach watcher (${formatError(error)})`;
4460
+ var formatWatcherTransportError = (watcher, error) => classifyWatcherFailure(error) === "api-rejection" ? `${watcher.id}: watcher rejected the request (${formatError(error)})` : `${watcher.id}: failed to reach watcher (${formatError(error)})`;
4455
4461
  var classifyWatcherFailure = (error) => {
4456
4462
  if (isHttpResponseError(error)) {
4457
4463
  return "api-rejection";
@@ -6104,6 +6110,10 @@ var resolvePath = (input) => {
6104
6110
  const expanded = input.startsWith("~/") || input === "~" ? path4.join(homedir(), input.slice(1)) : input;
6105
6111
  return path4.resolve(expanded);
6106
6112
  };
6113
+ var resolveArtifactOutFile = (out) => {
6114
+ const trimmed = out?.trim();
6115
+ return trimmed ? resolvePath(trimmed) : undefined;
6116
+ };
6107
6117
 
6108
6118
  // dist/commands/startShared.js
6109
6119
  var resolveInjectScript = async (inject, output) => {
@@ -7105,6 +7115,63 @@ var getErrorCode = (error) => {
7105
7115
  var hasErrorCode = (error, code2) => getErrorCode(error) === code2;
7106
7116
  var createNotAttachedError = (message = "No tab attached via extension") => codedError("cdp_not_attached", message);
7107
7117
 
7118
+ // ../argus-watcher/dist/cdp/health.js
7119
+ var CDP_HEALTH_PROBE_TIMEOUT_MS = 2000;
7120
+ var diagnoseCdpHealth = async (probe) => {
7121
+ const id = probe.watcherId ?? "<id>";
7122
+ if (!probe.isAttached()) {
7123
+ return {
7124
+ code: "cdp_not_attached",
7125
+ message: `The watcher is not attached to a target. Check \`argus watcher status ${id}\` and \`argus doctor\`.`
7126
+ };
7127
+ }
7128
+ const transport = await probe.checkTransport?.() ?? { state: "ok" };
7129
+ if (transport.state === "unreachable") {
7130
+ return {
7131
+ code: "chrome_unreachable",
7132
+ message: `Chrome's CDP endpoint did not answer (${transport.detail}). Restart the browser, then \`argus doctor\`.`
7133
+ };
7134
+ }
7135
+ if (transport.state === "target_gone") {
7136
+ probe.onTargetGone?.();
7137
+ return {
7138
+ code: "cdp_target_replaced",
7139
+ message: `The attached page target is gone (${transport.detail}) — a navigation replaced it. ` + `Argus is reattaching; retry the command, or check \`argus watcher status ${id}\`.`
7140
+ };
7141
+ }
7142
+ const dialog2 = probe.getBlockingDialog?.();
7143
+ if (dialog2) {
7144
+ return {
7145
+ code: "dialog_blocking",
7146
+ message: `A ${dialog2.type} dialog is open and blocking the page. ` + `Dismiss it with \`argus dialog accept ${id}\` or \`argus dialog dismiss ${id}\`, then retry.`
7147
+ };
7148
+ }
7149
+ if (!await probe.probeRenderer()) {
7150
+ return {
7151
+ code: "cdp_renderer_unresponsive",
7152
+ message: `The page's renderer did not answer a trivial evaluation within ${CDP_HEALTH_PROBE_TIMEOUT_MS}ms — its main thread is ` + `blocked, or a cross-origin navigation stranded it. A longer timeout will not help: reload with \`argus reload ${id}\`, ` + "or restart Chrome."
7153
+ };
7154
+ }
7155
+ return {
7156
+ code: "cdp_timeout",
7157
+ message: "The watcher, target, and renderer all answered, so the expression itself exceeded its deadline. Pass a longer timeout."
7158
+ };
7159
+ };
7160
+ var toDiagnosedError = (diagnosis, original) => {
7161
+ const detail = original instanceof Error ? original.message : String(original);
7162
+ return codedError(diagnosis.code, `${detail}. ${diagnosis.message}`);
7163
+ };
7164
+ var isCdpTimeoutError = (error) => error instanceof Error && /\b(?:CDP|Bridge|Control) request timed out\b/i.test(error.message);
7165
+ var createSessionRendererProbe = (session2) => async () => {
7166
+ try {
7167
+ const params = { expression: "1", returnByValue: true, silent: true };
7168
+ await session2.sendAndWait("Runtime.evaluate", params, { timeoutMs: CDP_HEALTH_PROBE_TIMEOUT_MS });
7169
+ return true;
7170
+ } catch {
7171
+ return false;
7172
+ }
7173
+ };
7174
+
7108
7175
  // ../argus-watcher/dist/http/httpUtils.js
7109
7176
  var respondJson = (res, body, status2 = 200) => {
7110
7177
  const payload = JSON.stringify(body);
@@ -7133,6 +7200,17 @@ var respondPayloadTooLarge = (res) => {
7133
7200
  var respondError = (res, error) => {
7134
7201
  respondApiError(res, 500, getErrorCode(error), formatError(error));
7135
7202
  };
7203
+ var respondCdpError = async (res, error, diagnose) => {
7204
+ if (!diagnose || !isCdpTimeoutError(error)) {
7205
+ respondError(res, error);
7206
+ return;
7207
+ }
7208
+ try {
7209
+ respondError(res, toDiagnosedError(await diagnose(), error));
7210
+ } catch {
7211
+ respondError(res, error);
7212
+ }
7213
+ };
7136
7214
  var readJsonBody = async (req, res) => {
7137
7215
  const chunks = [];
7138
7216
  let size = 0;
@@ -7274,7 +7352,7 @@ var normalizeTimeout = (value) => {
7274
7352
  // ../argus-watcher/package.json
7275
7353
  var package_default2 = {
7276
7354
  name: "@vforsh/argus-watcher",
7277
- version: "0.5.1",
7355
+ version: "0.5.3",
7278
7356
  repository: {
7279
7357
  type: "git",
7280
7358
  url: "git+https://github.com/vforsh/argus.git",
@@ -7351,7 +7429,7 @@ var defineJsonRoute = (input) => ({
7351
7429
  if (input.handleError?.(res, error)) {
7352
7430
  return;
7353
7431
  }
7354
- respondError(res, error);
7432
+ await respondCdpError(res, error, ctx.diagnoseCdp);
7355
7433
  }
7356
7434
  }
7357
7435
  });
@@ -9470,6 +9548,7 @@ var shouldMaterializeByValue = (record2) => {
9470
9548
  };
9471
9549
 
9472
9550
  // ../argus-watcher/dist/http/routes/postEval.js
9551
+ var DEFAULT_EVAL_CDP_TIMEOUT_MS = 30000;
9473
9552
  var route18 = defineJsonRoute({
9474
9553
  method: "POST",
9475
9554
  path: "/eval",
@@ -9482,7 +9561,7 @@ var route18 = defineJsonRoute({
9482
9561
  replMode: normalizeBoolean(payload.replMode, true),
9483
9562
  returnByValue: normalizeBoolean(payload.returnByValue, true),
9484
9563
  jsonValue: normalizeBoolean(payload.jsonValue, false),
9485
- timeoutMs: normalizeTimeout(payload.timeoutMs),
9564
+ timeoutMs: normalizeTimeout(payload.timeoutMs) ?? DEFAULT_EVAL_CDP_TIMEOUT_MS,
9486
9565
  scenario: normalizeBoolean(payload.scenario, false),
9487
9566
  scenarioServices: {
9488
9567
  buffer: ctx.buffer,
@@ -11071,25 +11150,44 @@ var dispatchKeydown = async (session2, options) => {
11071
11150
  await session2.sendAndWait("DOM.focus", { nodeId });
11072
11151
  focused = true;
11073
11152
  }
11074
- const isPrintable = event.text != null && event.text !== "\r";
11153
+ const carriesText = event.text != null;
11075
11154
  const baseParams = {
11076
11155
  code: event.code,
11077
11156
  key: event.key,
11078
11157
  windowsVirtualKeyCode: event.keyCode,
11079
- nativeVirtualKeyCode: event.keyCode,
11080
11158
  modifiers: event.modifiers
11081
11159
  };
11082
- if (isPrintable) {
11083
- await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "keyDown", text: event.text });
11084
- await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "char", text: event.text });
11085
- await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "keyUp" });
11086
- } else {
11087
- await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "rawKeyDown", text: event.text });
11088
- await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "keyUp" });
11089
- }
11160
+ const keyDownParams = carriesText ? { ...baseParams, type: "keyDown", text: event.text, unmodifiedText: event.text } : { ...baseParams, type: "rawKeyDown" };
11161
+ await session2.sendAndWait("Input.dispatchKeyEvent", keyDownParams);
11162
+ await session2.sendAndWait("Input.dispatchKeyEvent", { ...baseParams, type: "keyUp" });
11090
11163
  return { key: event.key, code: event.code, modifiers: event.modifiers, focused, event };
11091
11164
  };
11092
11165
 
11166
+ // ../argus-watcher/dist/cdp/pageFocus.js
11167
+ var FOCUS_PROBE_TIMEOUT_MS = 3000;
11168
+ var ensurePageInputFocus = async (pageSession, visibility2) => {
11169
+ if (!pageSession.isAttached()) {
11170
+ return { activated: false };
11171
+ }
11172
+ if (await hasPageFocus(pageSession)) {
11173
+ return { activated: false };
11174
+ }
11175
+ try {
11176
+ await visibility2.setLock(pageSession, "shown");
11177
+ } catch (error) {
11178
+ throw notFocusedError(`activating it failed: ${formatError(error)}`);
11179
+ }
11180
+ if (!await hasPageFocus(pageSession)) {
11181
+ throw notFocusedError("activating it did not give it focus");
11182
+ }
11183
+ return { activated: true };
11184
+ };
11185
+ var hasPageFocus = async (pageSession) => {
11186
+ const focused = await tryEvaluateInPage(pageSession, "document.hasFocus()", { timeoutMs: FOCUS_PROBE_TIMEOUT_MS });
11187
+ return focused !== false;
11188
+ };
11189
+ var notFocusedError = (reason) => codedError("target_not_focused", `The page is not focused, so Chrome would drop the keyboard event — ${reason}. ` + "Run `argus page show <id>` and retry, or start the watcher against a visible page.");
11190
+
11093
11191
  // ../argus-watcher/dist/http/routes/postDomKeydown.js
11094
11192
  var route32 = defineJsonRoute({
11095
11193
  method: "POST",
@@ -11097,6 +11195,7 @@ var route32 = defineJsonRoute({
11097
11195
  bodySchema: domKeydownRequestSchema,
11098
11196
  endpoint: "dom/keydown",
11099
11197
  handle: async ({ ctx, body: payload }) => {
11198
+ const activation = await ensurePageInputFocus(ctx.pageCdpSession, ctx.visibilityController);
11100
11199
  const result = await dispatchKeydown(ctx.cdpSession, {
11101
11200
  key: payload.key,
11102
11201
  code: payload.code,
@@ -11109,6 +11208,7 @@ var route32 = defineJsonRoute({
11109
11208
  code: result.code,
11110
11209
  modifiers: result.modifiers,
11111
11210
  focused: result.focused,
11211
+ activated: activation.activated,
11112
11212
  event: result.event
11113
11213
  };
11114
11214
  }
@@ -13468,6 +13568,47 @@ var decodeInlineSourcemap = (value) => {
13468
13568
  }
13469
13569
  };
13470
13570
 
13571
+ // ../argus-watcher/dist/sourcemaps/scriptFetcher.js
13572
+ var createScriptFetcher = () => {
13573
+ const rangeHostileOrigins = new Set;
13574
+ return async (scriptUrl, tailBytes) => {
13575
+ const origin = originOf(scriptUrl);
13576
+ const ranged = tailBytes !== null && tailBytes > 0 && !rangeHostileOrigins.has(origin);
13577
+ const response = await fetch(scriptUrl, ranged ? { headers: { Range: `bytes=-${tailBytes}` } } : undefined);
13578
+ if (response.ok) {
13579
+ return readBody(response);
13580
+ }
13581
+ if (!ranged || !looksLikeRangeRejection(response.status)) {
13582
+ return null;
13583
+ }
13584
+ await discardBody(response);
13585
+ const whole = await fetch(scriptUrl);
13586
+ if (!whole.ok) {
13587
+ await discardBody(whole);
13588
+ return null;
13589
+ }
13590
+ if (!rangeHostileOrigins.has(origin)) {
13591
+ rangeHostileOrigins.add(origin);
13592
+ console.warn(`[Sourcemaps] ${origin} rejected a suffix Range request (HTTP ${response.status}); refetching scripts whole.`);
13593
+ }
13594
+ return readBody(whole);
13595
+ };
13596
+ };
13597
+ var looksLikeRangeRejection = (status2) => status2 === 416 || status2 >= 500;
13598
+ var originOf = (scriptUrl) => {
13599
+ try {
13600
+ return new URL(scriptUrl).origin;
13601
+ } catch {
13602
+ return scriptUrl;
13603
+ }
13604
+ };
13605
+ var readBody = async (response) => ({ text: await response.text(), partial: response.status === 206 });
13606
+ var discardBody = async (response) => {
13607
+ try {
13608
+ await response.body?.cancel();
13609
+ } catch {}
13610
+ };
13611
+
13471
13612
  // ../argus-watcher/dist/sourcemaps/resolveLocation.js
13472
13613
  var resolveSourcemappedLocationWithMap = (traceMap, location) => {
13473
13614
  if (location.line <= 0 || location.column <= 0) {
@@ -13495,6 +13636,7 @@ var createSourcemapResolver = (options = {}) => {
13495
13636
  const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
13496
13637
  const negativeTtlMs = options.negativeTtlMs ?? DEFAULT_NEGATIVE_TTL_MS;
13497
13638
  const tailBytes = options.tailBytes ?? DEFAULT_TAIL_BYTES;
13639
+ const fetchScript = createScriptFetcher();
13498
13640
  const cache = new Map;
13499
13641
  const pending = new Map;
13500
13642
  let generation = 0;
@@ -13536,7 +13678,7 @@ var createSourcemapResolver = (options = {}) => {
13536
13678
  return inFlight;
13537
13679
  }
13538
13680
  const startedAt = generation;
13539
- const promise = loadTraceMap(scriptUrl, tailBytes).catch(() => null).then((traceMap) => {
13681
+ const promise = loadTraceMap(scriptUrl, tailBytes, fetchScript).catch(() => null).then((traceMap) => {
13540
13682
  if (startedAt === generation) {
13541
13683
  writeCache(scriptUrl, traceMap);
13542
13684
  }
@@ -13563,7 +13705,7 @@ var createSourcemapResolver = (options = {}) => {
13563
13705
  };
13564
13706
  return { resolve: resolve2, clear };
13565
13707
  };
13566
- var loadTraceMap = async (scriptUrl, tailBytes) => {
13708
+ var loadTraceMap = async (scriptUrl, tailBytes, fetchScript) => {
13567
13709
  const tail = await fetchScript(scriptUrl, tailBytes);
13568
13710
  if (!tail) {
13569
13711
  return null;
@@ -13585,14 +13727,6 @@ var loadTraceMap = async (scriptUrl, tailBytes) => {
13585
13727
  }
13586
13728
  return new TraceMap(rawMap, reference.url);
13587
13729
  };
13588
- var fetchScript = async (scriptUrl, tailBytes) => {
13589
- const init = tailBytes ? { headers: { Range: `bytes=-${tailBytes}` } } : undefined;
13590
- const response = await fetch(scriptUrl, init);
13591
- if (!response.ok) {
13592
- return null;
13593
- }
13594
- return { text: await response.text(), partial: response.status === 206 };
13595
- };
13596
13730
  var fetchSourcemap = async (mapUrl) => {
13597
13731
  const response = await fetch(mapUrl);
13598
13732
  if (!response.ok) {
@@ -16211,7 +16345,7 @@ var formatArgs = (args) => {
16211
16345
 
16212
16346
  // ../argus-watcher/dist/cdp/watcherTargets.js
16213
16347
  var findTarget = async (chrome, match) => {
16214
- const targets = await fetchTargets(chrome);
16348
+ const targets = await fetchCdpTargets(chrome);
16215
16349
  if (targets.length === 0) {
16216
16350
  throw new Error("No CDP targets available");
16217
16351
  }
@@ -16268,8 +16402,9 @@ var matchesTarget = (target, match, targetById, urlRegex2, titleRegex) => {
16268
16402
  }
16269
16403
  return true;
16270
16404
  };
16271
- var fetchTargets = async (chrome) => {
16272
- const response = await fetch(`http://${chrome.host}:${chrome.port}/json`);
16405
+ var TARGET_LIST_TIMEOUT_MS = 5000;
16406
+ var fetchCdpTargets = async (chrome, timeoutMs = TARGET_LIST_TIMEOUT_MS) => {
16407
+ const response = await fetch(`http://${chrome.host}:${chrome.port}/json`, { signal: AbortSignal.timeout(timeoutMs) });
16273
16408
  if (!response.ok) {
16274
16409
  throw new Error(`Failed to fetch CDP targets (status ${response.status})`);
16275
16410
  }
@@ -16313,6 +16448,12 @@ var startCdpWatcher = (options) => {
16313
16448
  socket.close();
16314
16449
  }
16315
16450
  };
16451
+ const reconnect = () => {
16452
+ if (stopped) {
16453
+ return;
16454
+ }
16455
+ socket?.close();
16456
+ };
16316
16457
  runLoop();
16317
16458
  session2.onEvent("Runtime.consoleAPICalled", (params) => {
16318
16459
  if (!currentTarget) {
@@ -16345,6 +16486,7 @@ var startCdpWatcher = (options) => {
16345
16486
  });
16346
16487
  return {
16347
16488
  stop,
16489
+ reconnect,
16348
16490
  session: session2,
16349
16491
  getTarget: () => currentTarget ? { ...currentTarget } : null
16350
16492
  };
@@ -16534,9 +16676,29 @@ var createCdpSource = (options) => {
16534
16676
  pageUrl: target?.url ?? null
16535
16677
  };
16536
16678
  },
16679
+ healthChecks: {
16680
+ checkTransport: () => checkCdpTransport(chrome, watcher2),
16681
+ onTargetGone: watcher2.reconnect
16682
+ },
16537
16683
  stop: watcher2.stop
16538
16684
  };
16539
16685
  };
16686
+ var checkCdpTransport = async (chrome, watcher2) => {
16687
+ let targets;
16688
+ try {
16689
+ targets = await fetchCdpTargets(chrome, CDP_HEALTH_PROBE_TIMEOUT_MS);
16690
+ } catch (error) {
16691
+ return { state: "unreachable", detail: `${chrome.host}:${chrome.port}: ${formatError(error)}` };
16692
+ }
16693
+ const target = watcher2.getTarget();
16694
+ if (!target) {
16695
+ return { state: "target_gone", detail: "the watcher holds no target" };
16696
+ }
16697
+ if (!targets.some((candidate) => candidate.id === target.id)) {
16698
+ return { state: "target_gone", detail: `Chrome no longer lists target ${target.id} (${target.url})` };
16699
+ }
16700
+ return { state: "ok" };
16701
+ };
16540
16702
 
16541
16703
  // ../argus-watcher/dist/native-messaging/messaging.js
16542
16704
  var createNativeMessaging = () => {
@@ -18231,6 +18393,13 @@ var createWatcherHandle = async (options, watcherId) => {
18231
18393
  };
18232
18394
  }
18233
18395
  });
18396
+ const diagnoseCdp = () => diagnoseCdpHealth({
18397
+ watcherId,
18398
+ isAttached: () => sourceHandle.session.isAttached(),
18399
+ probeRenderer: createSessionRendererProbe(sourceHandle.session),
18400
+ getBlockingDialog: () => dialogTracker.getActive(),
18401
+ ...sourceHandle.healthChecks
18402
+ });
18234
18403
  const dialogSession = getPageSession();
18235
18404
  dialogSession.onEvent("Page.javascriptDialogOpening", (params) => {
18236
18405
  const dialog2 = parseDialogStatus(params);
@@ -18263,6 +18432,7 @@ var createWatcherHandle = async (options, watcherId) => {
18263
18432
  throttleController,
18264
18433
  visibilityController,
18265
18434
  netMockController,
18435
+ diagnoseCdp,
18266
18436
  getNetFilterContext: sourceHandle.getNetFilterContext,
18267
18437
  readBrowserCookies: sourceHandle.readBrowserCookies,
18268
18438
  sourceHandle: sourceMode === "extension" ? sourceHandle : undefined,
@@ -19973,7 +20143,7 @@ var resolveAttachedTarget = async (options, output) => {
19973
20143
  try {
19974
20144
  status2 = await fetchJson(statusUrl, { timeoutMs: 2000 });
19975
20145
  } catch (error) {
19976
- output.writeWarn(`${resolved.watcher.id}: failed to reach watcher (${formatError(error)})`);
20146
+ output.writeWarn(formatWatcherTransportError(resolved.watcher, error));
19977
20147
  process.exitCode = 1;
19978
20148
  return null;
19979
20149
  }
@@ -20898,19 +21068,21 @@ import fs10 from "node:fs/promises";
20898
21068
  import path14 from "node:path";
20899
21069
 
20900
21070
  // dist/eval/evalClient.js
20901
- var DEFAULT_EVAL_REQUEST_TIMEOUT_MS = 1e4;
21071
+ var DEFAULT_EVAL_TIMEOUT_MS = 1e4;
21072
+ var REQUEST_TIMEOUT_GRACE_MS = 8000;
20902
21073
  var MIN_SUGGESTED_TIMEOUT_MS = 60000;
20903
21074
  var evalOnce = async (input) => {
21075
+ const evalTimeoutMs = input.timeoutMs ?? DEFAULT_EVAL_TIMEOUT_MS;
20904
21076
  const body = {
20905
21077
  expression: input.expression,
20906
21078
  args: input.args,
20907
21079
  awaitPromise: input.awaitPromise,
20908
21080
  replMode: input.replMode,
20909
21081
  returnByValue: input.returnByValue,
20910
- timeoutMs: input.timeoutMs,
21082
+ timeoutMs: evalTimeoutMs,
20911
21083
  scenario: input.scenario
20912
21084
  };
20913
- const requestTimeoutMs = input.timeoutMs ? input.timeoutMs + 5000 : DEFAULT_EVAL_REQUEST_TIMEOUT_MS;
21085
+ const requestTimeoutMs = evalTimeoutMs + REQUEST_TIMEOUT_GRACE_MS;
20914
21086
  let response;
20915
21087
  try {
20916
21088
  response = await fetchWatcherJson(input.watcher, {
@@ -20938,11 +21110,11 @@ var evalOnce = async (input) => {
20938
21110
  };
20939
21111
  var formatEvalTransportError = (watcher2, error, timeoutMs) => {
20940
21112
  const baseMessage = formatWatcherTransportError(watcher2, error);
20941
- if (!isTimeoutError(error)) {
21113
+ if (classifyWatcherFailure(error) === "api-rejection" || !isTimeoutError(error)) {
20942
21114
  return baseMessage;
20943
21115
  }
20944
- const suggestedTimeoutMs = Math.max(MIN_SUGGESTED_TIMEOUT_MS, (timeoutMs ?? DEFAULT_EVAL_REQUEST_TIMEOUT_MS) * 2);
20945
- return `${baseMessage}. ` + `Eval may need more time; pass a longer timeout as milliseconds or a duration, for example: ` + `\`argus eval ${watcher2.id} --timeout ${formatSuggestedDuration(suggestedTimeoutMs)} ...\``;
21116
+ const suggestedTimeoutMs = Math.max(MIN_SUGGESTED_TIMEOUT_MS, (timeoutMs ?? DEFAULT_EVAL_TIMEOUT_MS) * 2);
21117
+ return `${baseMessage}. ` + `The watcher did not answer at all, so it may be unresponsive rather than slow: check \`argus watcher status ${watcher2.id}\` ` + `and \`argus doctor\`. If the watcher is healthy, the expression needs more time; pass a longer timeout as milliseconds or a ` + `duration, for example: \`argus eval ${watcher2.id} --timeout ${formatSuggestedDuration(suggestedTimeoutMs)} ...\``;
20946
21118
  };
20947
21119
  var isTimeoutError = (error) => {
20948
21120
  const message = formatError(error);
@@ -48313,9 +48485,12 @@ var runDomKeydown = defineWatcherCommand({
48313
48485
  formatHuman: (response, { options, output }) => {
48314
48486
  if (options.printEvent) {
48315
48487
  output.writeHuman(`Dispatched keydown event: ${JSON.stringify(response.event)}`);
48316
- return;
48488
+ } else {
48489
+ output.writeHuman(`Dispatched keydown: ${response.key} (code=${response.code})`);
48490
+ }
48491
+ if (response.activated) {
48492
+ output.writeHuman("Page was hidden and has been activated (as `argus page show`); release it with `argus page hide`.");
48317
48493
  }
48318
- output.writeHuman(`Dispatched keydown: ${response.key} (code=${response.code})`);
48319
48494
  }
48320
48495
  });
48321
48496
 
@@ -48678,7 +48853,7 @@ var buildScreenshotPlan = (options, output) => {
48678
48853
  path: "/screenshot",
48679
48854
  method: "POST",
48680
48855
  body: {
48681
- outFile: options.out,
48856
+ outFile: resolveArtifactOutFile(options.out),
48682
48857
  selector,
48683
48858
  clip,
48684
48859
  format: "png"
@@ -48800,7 +48975,7 @@ var snapshotCommands = [
48800
48975
  description: "Capture a screenshot to disk on the watcher",
48801
48976
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
48802
48977
  options: [
48803
- { flags: "--out <file>", description: "Output file path (absolute or relative to artifacts directory)" },
48978
+ { flags: "--out <file>", description: "Output file path (absolute, or relative to the current working directory)" },
48804
48979
  { flags: "--selector <selector>", description: "Optional CSS selector for element-only capture" },
48805
48980
  { flags: "--clip <x,y,width,height>", description: "Viewport-relative rectangle crop in CSS pixels" },
48806
48981
  { flags: "--testid <id>", description: `Shorthand for --selector "[data-testid='<id>']"` },
@@ -48915,7 +49090,7 @@ var buildRecordStopPlan = (options, output) => {
48915
49090
  method: "POST",
48916
49091
  body: {
48917
49092
  recordId: normalizeString2(options.recordId),
48918
- outFile: options.out
49093
+ outFile: resolveArtifactOutFile(options.out)
48919
49094
  },
48920
49095
  timeoutMs: RECORD_STOP_TIMEOUT_MS
48921
49096
  };
@@ -48939,7 +49114,7 @@ var buildRecordBody = (options, output) => {
48939
49114
  return null;
48940
49115
  }
48941
49116
  return {
48942
- outFile: options.out,
49117
+ outFile: resolveArtifactOutFile(options.out),
48943
49118
  selector,
48944
49119
  clip,
48945
49120
  fps,
@@ -49064,7 +49239,7 @@ var recordCommands = [
49064
49239
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49065
49240
  options: [
49066
49241
  { flags: "--duration <duration>", description: "Capture for duration (e.g. 3s, 500ms)" },
49067
- { flags: "--out <file>", description: "Output .mp4 or .webm path (absolute or relative to artifacts directory)" },
49242
+ { flags: "--out <file>", description: "Output .mp4 or .webm path (absolute, or relative to the current working directory)" },
49068
49243
  { flags: "--selector <selector>", description: "Optional CSS selector for element-only recording" },
49069
49244
  { flags: "--clip <x,y,width,height>", description: "Viewport-relative rectangle crop in CSS pixels" },
49070
49245
  { flags: "--testid <id>", description: `Shorthand for --selector "[data-testid='<id>']"` },
@@ -49089,7 +49264,7 @@ var recordCommands = [
49089
49264
  description: "Start a silent video recording",
49090
49265
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49091
49266
  options: [
49092
- { flags: "--out <file>", description: "Output .mp4 or .webm path (absolute or relative to artifacts directory)" },
49267
+ { flags: "--out <file>", description: "Output .mp4 or .webm path (absolute, or relative to the current working directory)" },
49093
49268
  { flags: "--selector <selector>", description: "Optional CSS selector for element-only recording" },
49094
49269
  { flags: "--clip <x,y,width,height>", description: "Viewport-relative rectangle crop in CSS pixels" },
49095
49270
  { flags: "--testid <id>", description: `Shorthand for --selector "[data-testid='<id>']"` },
@@ -49110,7 +49285,10 @@ var recordCommands = [
49110
49285
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49111
49286
  options: [
49112
49287
  { flags: "--record-id <id>", description: "Record id returned from start" },
49113
- { flags: "--out <file>", description: "Move the saved recording to this .mp4 or .webm path before returning" },
49288
+ {
49289
+ flags: "--out <file>",
49290
+ description: "Move the saved recording to this .mp4 or .webm path (absolute, or relative to the current working directory)"
49291
+ },
49114
49292
  jsonOption
49115
49293
  ],
49116
49294
  examples: ["argus record stop app", "argus record stop app --out demo.mp4 --json"],
@@ -49193,7 +49371,7 @@ var runTraceStartInternal = async (watcher2, options, output) => {
49193
49371
  path: "/trace/start",
49194
49372
  method: "POST",
49195
49373
  body: {
49196
- outFile: options.out,
49374
+ outFile: resolveArtifactOutFile(options.out),
49197
49375
  categories: options.categories,
49198
49376
  options: options.options
49199
49377
  },
@@ -49211,7 +49389,7 @@ var runTraceStopInternal = async (watcher2, options, output) => {
49211
49389
  const response = await fetchWatcherJson(watcher2, {
49212
49390
  path: "/trace/stop",
49213
49391
  method: "POST",
49214
- body: { traceId: options.traceId, outFile: options.outFile },
49392
+ body: { traceId: options.traceId, outFile: resolveArtifactOutFile(options.outFile) },
49215
49393
  timeoutMs: 20000
49216
49394
  });
49217
49395
  return response;
@@ -49231,7 +49409,7 @@ var traceCommands = [
49231
49409
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49232
49410
  options: [
49233
49411
  { flags: "--duration <duration>", description: "Capture for duration (e.g. 3s, 500ms)" },
49234
- { flags: "--out <file>", description: "Output trace file path (relative to artifacts base directory)" },
49412
+ { flags: "--out <file>", description: "Output trace file path (absolute, or relative to the current working directory)" },
49235
49413
  { flags: "--categories <categories>", description: "Comma-separated tracing categories" },
49236
49414
  { flags: "--options <options>", description: "Tracing options string" },
49237
49415
  jsonOption
@@ -49246,7 +49424,7 @@ var traceCommands = [
49246
49424
  description: "Start Chrome tracing",
49247
49425
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49248
49426
  options: [
49249
- { flags: "--out <file>", description: "Output trace file path (relative to artifacts base directory)" },
49427
+ { flags: "--out <file>", description: "Output trace file path (absolute, or relative to the current working directory)" },
49250
49428
  { flags: "--categories <categories>", description: "Comma-separated tracing categories" },
49251
49429
  { flags: "--options <options>", description: "Tracing options string" },
49252
49430
  jsonOption
@@ -49262,7 +49440,10 @@ var traceCommands = [
49262
49440
  arguments: [{ flags: "[id]", description: "Watcher id to query" }],
49263
49441
  options: [
49264
49442
  { flags: "--trace-id <id>", description: "Trace id returned from start" },
49265
- { flags: "--out <file>", description: "Move the saved trace file to this path before returning" },
49443
+ {
49444
+ flags: "--out <file>",
49445
+ description: "Move the saved trace file to this path (absolute, or relative to the current working directory)"
49446
+ },
49266
49447
  jsonOption
49267
49448
  ],
49268
49449
  examples: ["argus trace stop app", "argus trace stop app --out trace.json --json"],
@@ -51238,7 +51419,7 @@ var resolveAutoIframe = (iframes, allTargets) => {
51238
51419
  };
51239
51420
  var scoreIframeTarget = (target, page) => {
51240
51421
  let score = 0;
51241
- if (originOf(target.url) && originOf(target.url) !== originOf(page?.url)) {
51422
+ if (originOf2(target.url) && originOf2(target.url) !== originOf2(page?.url)) {
51242
51423
  score += 4;
51243
51424
  }
51244
51425
  if (target.title && target.title !== target.url && !target.title.startsWith("http")) {
@@ -51290,7 +51471,7 @@ var statusMatchesTarget = (status2, target) => {
51290
51471
  return Boolean(status2.target.title && status2.target.title === target.title && status2.target.url === target.url);
51291
51472
  };
51292
51473
  var includesIgnoreCase = (value, needle) => value.toLowerCase().includes(needle.toLowerCase());
51293
- var originOf = (url) => {
51474
+ var originOf2 = (url) => {
51294
51475
  if (!url) {
51295
51476
  return null;
51296
51477
  }
@@ -1 +1 @@
1
- {"version":3,"file":"recordCommands.d.ts","sourceRoot":"","sources":["../../../src/cli/register/recordCommands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAKjE,eAAO,MAAM,cAAc,EAAE,SAAS,sBAAsB,EA6D3D,CAAA"}
1
+ {"version":3,"file":"recordCommands.d.ts","sourceRoot":"","sources":["../../../src/cli/register/recordCommands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAKjE,eAAO,MAAM,cAAc,EAAE,SAAS,sBAAsB,EAgE3D,CAAA"}
@@ -8,7 +8,7 @@ export const recordCommands = [
8
8
  arguments: [{ flags: '[id]', description: 'Watcher id to query' }],
9
9
  options: [
10
10
  { flags: '--duration <duration>', description: 'Capture for duration (e.g. 3s, 500ms)' },
11
- { flags: '--out <file>', description: 'Output .mp4 or .webm path (absolute or relative to artifacts directory)' },
11
+ { flags: '--out <file>', description: 'Output .mp4 or .webm path (absolute, or relative to the current working directory)' },
12
12
  { flags: '--selector <selector>', description: 'Optional CSS selector for element-only recording' },
13
13
  { flags: '--clip <x,y,width,height>', description: 'Viewport-relative rectangle crop in CSS pixels' },
14
14
  { flags: '--testid <id>', description: 'Shorthand for --selector "[data-testid=\'<id>\']"' },
@@ -33,7 +33,7 @@ export const recordCommands = [
33
33
  description: 'Start a silent video recording',
34
34
  arguments: [{ flags: '[id]', description: 'Watcher id to query' }],
35
35
  options: [
36
- { flags: '--out <file>', description: 'Output .mp4 or .webm path (absolute or relative to artifacts directory)' },
36
+ { flags: '--out <file>', description: 'Output .mp4 or .webm path (absolute, or relative to the current working directory)' },
37
37
  { flags: '--selector <selector>', description: 'Optional CSS selector for element-only recording' },
38
38
  { flags: '--clip <x,y,width,height>', description: 'Viewport-relative rectangle crop in CSS pixels' },
39
39
  { flags: '--testid <id>', description: 'Shorthand for --selector "[data-testid=\'<id>\']"' },
@@ -54,7 +54,10 @@ export const recordCommands = [
54
54
  arguments: [{ flags: '[id]', description: 'Watcher id to query' }],
55
55
  options: [
56
56
  { flags: '--record-id <id>', description: 'Record id returned from start' },
57
- { flags: '--out <file>', description: 'Move the saved recording to this .mp4 or .webm path before returning' },
57
+ {
58
+ flags: '--out <file>',
59
+ description: 'Move the saved recording to this .mp4 or .webm path (absolute, or relative to the current working directory)',
60
+ },
58
61
  jsonOption,
59
62
  ],
60
63
  examples: ['argus record stop app', 'argus record stop app --out demo.mp4 --json'],
@@ -1 +1 @@
1
- {"version":3,"file":"recordCommands.js","sourceRoot":"","sources":["../../../src/cli/register/recordCommands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recordCommands.js","sourceRoot":"","sources":["../../../src/cli/register/recordCommands.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ export const snapshotCommands = [
8
8
  description: 'Capture a screenshot to disk on the watcher',
9
9
  arguments: [{ flags: '[id]', description: 'Watcher id to query' }],
10
10
  options: [
11
- { flags: '--out <file>', description: 'Output file path (absolute or relative to artifacts directory)' },
11
+ { flags: '--out <file>', description: 'Output file path (absolute, or relative to the current working directory)' },
12
12
  { flags: '--selector <selector>', description: 'Optional CSS selector for element-only capture' },
13
13
  { flags: '--clip <x,y,width,height>', description: 'Viewport-relative rectangle crop in CSS pixels' },
14
14
  { flags: '--testid <id>', description: 'Shorthand for --selector "[data-testid=\'<id>\']"' },