@vforsh/argus 0.1.22 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/argus.js +847 -247
  3. package/dist/bin.js +2 -0
  4. package/dist/bin.js.map +1 -1
  5. package/dist/cli/register/evalCommands.d.ts.map +1 -1
  6. package/dist/cli/register/evalCommands.js +1 -0
  7. package/dist/cli/register/evalCommands.js.map +1 -1
  8. package/dist/cli/register/logsCommands.d.ts.map +1 -1
  9. package/dist/cli/register/logsCommands.js +29 -6
  10. package/dist/cli/register/logsCommands.js.map +1 -1
  11. package/dist/commands/eval.d.ts.map +1 -1
  12. package/dist/commands/eval.js +2 -0
  13. package/dist/commands/eval.js.map +1 -1
  14. package/dist/commands/evalBundle.d.ts +2 -1
  15. package/dist/commands/evalBundle.d.ts.map +1 -1
  16. package/dist/commands/evalBundle.js +28 -9
  17. package/dist/commands/evalBundle.js.map +1 -1
  18. package/dist/commands/evalPolling.d.ts +1 -0
  19. package/dist/commands/evalPolling.d.ts.map +1 -1
  20. package/dist/commands/evalPolling.js +1 -0
  21. package/dist/commands/evalPolling.js.map +1 -1
  22. package/dist/commands/evalShared.d.ts +2 -0
  23. package/dist/commands/evalShared.d.ts.map +1 -1
  24. package/dist/commands/evalShared.js +14 -5
  25. package/dist/commands/evalShared.js.map +1 -1
  26. package/dist/commands/evalUntil.d.ts.map +1 -1
  27. package/dist/commands/evalUntil.js +1 -0
  28. package/dist/commands/evalUntil.js.map +1 -1
  29. package/dist/commands/logs.d.ts +13 -0
  30. package/dist/commands/logs.d.ts.map +1 -1
  31. package/dist/commands/logs.js +10 -0
  32. package/dist/commands/logs.js.map +1 -1
  33. package/dist/commands/tail.d.ts +1 -0
  34. package/dist/commands/tail.d.ts.map +1 -1
  35. package/dist/commands/tail.js +25 -18
  36. package/dist/commands/tail.js.map +1 -1
  37. package/dist/eval/evalClient.d.ts +1 -0
  38. package/dist/eval/evalClient.d.ts.map +1 -1
  39. package/dist/eval/evalClient.js +2 -0
  40. package/dist/eval/evalClient.js.map +1 -1
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/output/io.d.ts +4 -0
  44. package/dist/output/io.d.ts.map +1 -1
  45. package/dist/output/io.js +19 -1
  46. package/dist/output/io.js.map +1 -1
  47. package/dist/skill/argus/SKILL.md +16 -0
  48. package/dist/skill/argus/reference/EVAL.md +35 -2
  49. package/dist/skill/argus/reference/INSPECT.md +12 -0
  50. package/dist/skill/argus/reference/PLUGINS.md +16 -2
  51. package/dist/watchers/queryParams.d.ts +1 -0
  52. package/dist/watchers/queryParams.d.ts.map +1 -1
  53. package/dist/watchers/queryParams.js +5 -3
  54. package/dist/watchers/queryParams.js.map +1 -1
  55. package/package.json +4 -4
package/dist/argus.js CHANGED
@@ -5,29 +5,15 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- function __accessProp(key) {
9
- return this[key];
10
- }
11
- var __toESMCache_node;
12
- var __toESMCache_esm;
13
8
  var __toESM = (mod, isNodeMode, target) => {
14
- var canCache = mod != null && typeof mod === "object";
15
- if (canCache) {
16
- var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
- var cached = cache.get(mod);
18
- if (cached)
19
- return cached;
20
- }
21
9
  target = mod != null ? __create(__getProtoOf(mod)) : {};
22
10
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
11
  for (let key of __getOwnPropNames(mod))
24
12
  if (!__hasOwnProp.call(to, key))
25
13
  __defProp(to, key, {
26
- get: __accessProp.bind(mod, key),
14
+ get: () => mod[key],
27
15
  enumerable: true
28
16
  });
29
- if (canCache)
30
- cache.set(mod, to);
31
17
  return to;
32
18
  };
33
19
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -2144,7 +2130,7 @@ var {
2144
2130
  // package.json
2145
2131
  var package_default = {
2146
2132
  name: "@vforsh/argus",
2147
- version: "0.1.22",
2133
+ version: "0.2.0",
2148
2134
  repository: {
2149
2135
  type: "git",
2150
2136
  url: "git+https://github.com/vforsh/argus.git",
@@ -2170,9 +2156,9 @@ var package_default = {
2170
2156
  access: "public"
2171
2157
  },
2172
2158
  dependencies: {
2173
- "@vforsh/argus-core": "^0.1.10",
2174
- "@vforsh/argus-plugin-api": "^0.1.4",
2175
- "@vforsh/argus-watcher": "^0.1.15",
2159
+ "@vforsh/argus-core": "^0.2.0",
2160
+ "@vforsh/argus-plugin-api": "^0.2.0",
2161
+ "@vforsh/argus-watcher": "^0.2.0",
2176
2162
  commander: "14.0.2",
2177
2163
  esbuild: "0.25.12",
2178
2164
  prettier: "3.7.4"
@@ -2270,6 +2256,7 @@ ${examples.map((example) => ` $ ${example}`).join(`
2270
2256
  `;
2271
2257
 
2272
2258
  // ../argus-core/dist/protocol/logs.js
2259
+ var LOG_LEVELS = ["log", "info", "warning", "error", "debug", "exception"];
2273
2260
  var formatLogLevelTag = (level) => {
2274
2261
  switch (level) {
2275
2262
  case "log":
@@ -2461,7 +2448,7 @@ var optionalPoint = (value, key) => {
2461
2448
  // ../argus-core/dist/protocol/http/auth.js
2462
2449
  var AUTH_STATE_METADATA_SCHEMA_VERSION = 1;
2463
2450
  // ../argus-core/dist/protocol/version.js
2464
- var ARGUS_PROTOCOL_VERSION = 1;
2451
+ var ARGUS_PROTOCOL_VERSION = 2;
2465
2452
  // ../argus-core/dist/registry/registry.js
2466
2453
  import fs2 from "node:fs/promises";
2467
2454
  import path3 from "node:path";
@@ -3205,12 +3192,29 @@ var extractErrorMessage = async (response) => {
3205
3192
  var ensureTrailingNewline = (value) => value.endsWith(`
3206
3193
  `) ? value : `${value}
3207
3194
  `;
3195
+ var configureMachineSafeConsole = (argv) => {
3196
+ if (!argv.includes("--json") && !argv.includes("--json-full")) {
3197
+ return;
3198
+ }
3199
+ const writeConsoleError = console.error.bind(console);
3200
+ console.log = writeConsoleError;
3201
+ console.info = writeConsoleError;
3202
+ console.debug = writeConsoleError;
3203
+ };
3208
3204
  var createOutput = (options) => {
3209
3205
  const json = options.json === true;
3206
+ let wroteJsonDocument = false;
3210
3207
  const writeJsonLine = (value) => {
3211
3208
  process.stdout.write(JSON.stringify(value) + `
3212
3209
  `);
3213
3210
  };
3211
+ const writeJson = (value) => {
3212
+ if (wroteJsonDocument) {
3213
+ throw new Error("Attempted to write more than one JSON document to stdout");
3214
+ }
3215
+ wroteJsonDocument = true;
3216
+ writeJsonLine(value);
3217
+ };
3214
3218
  const writeHuman = (text) => {
3215
3219
  const line = ensureTrailingNewline(text);
3216
3220
  if (json) {
@@ -3224,7 +3228,7 @@ var createOutput = (options) => {
3224
3228
  };
3225
3229
  return {
3226
3230
  json,
3227
- writeJson: writeJsonLine,
3231
+ writeJson,
3228
3232
  writeJsonLine,
3229
3233
  writeHuman,
3230
3234
  writeWarn
@@ -6089,12 +6093,279 @@ var buildStatus = (ctx) => {
6089
6093
  };
6090
6094
  };
6091
6095
 
6096
+ // ../argus-watcher/dist/buffer/LogBuffer.js
6097
+ import { randomUUID } from "node:crypto";
6098
+
6099
+ class LogEpochError extends Error {
6100
+ code;
6101
+ constructor(code, message) {
6102
+ super(message);
6103
+ this.name = "LogEpochError";
6104
+ this.code = code;
6105
+ }
6106
+ }
6107
+ var EPOCH_PREFIX = "argus-log-epoch-v1.";
6108
+
6109
+ class LogBuffer {
6110
+ maxSize;
6111
+ streamId = randomUUID();
6112
+ events = [];
6113
+ nextId = 1;
6114
+ waiters = [];
6115
+ epochWaiters = [];
6116
+ constructor(maxSize) {
6117
+ this.maxSize = maxSize;
6118
+ }
6119
+ add(event) {
6120
+ const entry = {
6121
+ ...event,
6122
+ id: this.nextId++
6123
+ };
6124
+ this.events.push(entry);
6125
+ this.trim();
6126
+ this.flushWaiters();
6127
+ this.flushEpochWaiters();
6128
+ return entry;
6129
+ }
6130
+ listAfter(after, filters, limit) {
6131
+ return this.listAfterPosition(after, filters, limit);
6132
+ }
6133
+ getCursor() {
6134
+ return this.beginLogEpoch();
6135
+ }
6136
+ beginLogEpoch() {
6137
+ return encodeEpoch({ v: 1, s: this.streamId, p: this.currentPosition() });
6138
+ }
6139
+ getEpoch() {
6140
+ return this.beginLogEpoch();
6141
+ }
6142
+ getEpochAt(position) {
6143
+ return encodeEpoch({ v: 1, s: this.streamId, p: position });
6144
+ }
6145
+ listAfterEpoch(epoch, filters, limit) {
6146
+ const position = this.resolveEpoch(epoch);
6147
+ const events = this.listAfterPosition(position, filters, limit);
6148
+ return {
6149
+ events,
6150
+ nextCursor: events.length > 0 ? this.getEpochAt(events[events.length - 1]?.id ?? position) : epoch
6151
+ };
6152
+ }
6153
+ waitForAfter(after, filters, limit, timeoutMs) {
6154
+ const immediate = this.listAfter(after, filters, limit);
6155
+ if (immediate.length > 0) {
6156
+ return Promise.resolve(immediate);
6157
+ }
6158
+ return new Promise((resolve) => {
6159
+ const timer = setTimeout(() => {
6160
+ this.waiters = this.waiters.filter((waiter) => waiter.timer !== timer);
6161
+ resolve([]);
6162
+ }, timeoutMs);
6163
+ this.waiters.push({ after, filters, limit, resolve, timer });
6164
+ });
6165
+ }
6166
+ async waitForAfterEpoch(epoch, filters, limit, timeoutMs) {
6167
+ const position = this.resolveEpoch(epoch);
6168
+ const immediate = this.listAfterPosition(position, filters, limit);
6169
+ if (immediate.length > 0) {
6170
+ return { events: immediate, nextCursor: this.getEpochAt(immediate[immediate.length - 1]?.id ?? position) };
6171
+ }
6172
+ return new Promise((resolve, reject) => {
6173
+ const timer = setTimeout(() => {
6174
+ this.epochWaiters = this.epochWaiters.filter((waiter) => waiter.timer !== timer);
6175
+ resolve({ events: [], nextCursor: epoch });
6176
+ }, timeoutMs);
6177
+ this.epochWaiters.push({ position, filters, limit, resolve, reject, timer });
6178
+ });
6179
+ }
6180
+ getStats() {
6181
+ if (this.events.length === 0) {
6182
+ return { size: this.maxSize, count: 0, minId: null, maxId: null };
6183
+ }
6184
+ return {
6185
+ size: this.maxSize,
6186
+ count: this.events.length,
6187
+ minId: this.events[0]?.id ?? null,
6188
+ maxId: this.events[this.events.length - 1]?.id ?? null
6189
+ };
6190
+ }
6191
+ trim() {
6192
+ if (this.maxSize <= 0) {
6193
+ this.events = [];
6194
+ return;
6195
+ }
6196
+ if (this.events.length <= this.maxSize) {
6197
+ return;
6198
+ }
6199
+ this.events = this.events.slice(this.events.length - this.maxSize);
6200
+ }
6201
+ flushWaiters() {
6202
+ if (this.waiters.length === 0) {
6203
+ return;
6204
+ }
6205
+ const remaining = [];
6206
+ for (const waiter of this.waiters) {
6207
+ const events = this.listAfter(waiter.after, waiter.filters, waiter.limit);
6208
+ if (events.length > 0) {
6209
+ clearTimeout(waiter.timer);
6210
+ waiter.resolve(events);
6211
+ continue;
6212
+ }
6213
+ remaining.push(waiter);
6214
+ }
6215
+ this.waiters = remaining;
6216
+ }
6217
+ flushEpochWaiters() {
6218
+ if (this.epochWaiters.length === 0) {
6219
+ return;
6220
+ }
6221
+ const remaining = [];
6222
+ for (const waiter of this.epochWaiters) {
6223
+ try {
6224
+ this.validatePosition(waiter.position);
6225
+ } catch (error) {
6226
+ clearTimeout(waiter.timer);
6227
+ waiter.reject(error);
6228
+ continue;
6229
+ }
6230
+ const events = this.listAfterPosition(waiter.position, waiter.filters, waiter.limit);
6231
+ if (events.length > 0) {
6232
+ clearTimeout(waiter.timer);
6233
+ waiter.resolve({
6234
+ events,
6235
+ nextCursor: this.getEpochAt(events[events.length - 1]?.id ?? waiter.position)
6236
+ });
6237
+ continue;
6238
+ }
6239
+ remaining.push(waiter);
6240
+ }
6241
+ this.epochWaiters = remaining;
6242
+ }
6243
+ listAfterPosition(position, filters, limit) {
6244
+ return this.events.filter((event) => event.id > position && matchesFilters(event, filters)).slice(0, limit);
6245
+ }
6246
+ resolveEpoch(epoch) {
6247
+ const payload = decodeEpoch(epoch);
6248
+ if (!payload) {
6249
+ throw new LogEpochError("invalid", "Invalid log epoch. Capture a new epoch from the watcher.");
6250
+ }
6251
+ if (payload.s !== this.streamId) {
6252
+ throw new LogEpochError("mismatch", "Log epoch belongs to a different watcher session. Capture a new epoch.");
6253
+ }
6254
+ if (payload.p > this.currentPosition()) {
6255
+ throw new LogEpochError("future", "Log epoch points past the current log stream.");
6256
+ }
6257
+ this.validatePosition(payload.p);
6258
+ return payload.p;
6259
+ }
6260
+ validatePosition(position) {
6261
+ if (this.events.length > 0 && position < (this.events[0]?.id ?? position + 1) - 1) {
6262
+ throw new LogEpochError("evicted", "Log epoch is stale because the ring buffer evicted entries. Capture a new epoch.");
6263
+ }
6264
+ if (this.maxSize === 0 && this.currentPosition() > position) {
6265
+ throw new LogEpochError("evicted", "Log epoch is stale because the ring buffer evicted entries. Capture a new epoch.");
6266
+ }
6267
+ }
6268
+ currentPosition() {
6269
+ return this.nextId - 1;
6270
+ }
6271
+ }
6272
+ var encodeEpoch = (payload) => `${EPOCH_PREFIX}${Buffer.from(JSON.stringify(payload)).toString("base64url")}`;
6273
+ var decodeEpoch = (epoch) => {
6274
+ if (typeof epoch !== "string" || !epoch.startsWith(EPOCH_PREFIX)) {
6275
+ return null;
6276
+ }
6277
+ try {
6278
+ const parsed = JSON.parse(Buffer.from(epoch.slice(EPOCH_PREFIX.length), "base64url").toString("utf8"));
6279
+ if (parsed.v !== 1 || typeof parsed.s !== "string" || !parsed.s || typeof parsed.p !== "number" || !Number.isSafeInteger(parsed.p) || parsed.p < 0) {
6280
+ return null;
6281
+ }
6282
+ return parsed;
6283
+ } catch {
6284
+ return null;
6285
+ }
6286
+ };
6287
+ var matchesFilters = (event, filters) => {
6288
+ if (filters.sinceTs && event.ts < filters.sinceTs) {
6289
+ return false;
6290
+ }
6291
+ if (filters.levels && filters.levels.length > 0 && !filters.levels.includes(event.level)) {
6292
+ return false;
6293
+ }
6294
+ if (filters.source && !event.source.toLowerCase().includes(filters.source.toLowerCase())) {
6295
+ return false;
6296
+ }
6297
+ if (filters.match && filters.match.length > 0) {
6298
+ for (const pattern of filters.match) {
6299
+ if (pattern.test(event.text)) {
6300
+ return true;
6301
+ }
6302
+ }
6303
+ return false;
6304
+ }
6305
+ return true;
6306
+ };
6307
+
6308
+ // ../argus-watcher/dist/http/routes/logEpochQuery.js
6309
+ var parseLogPosition = (url) => {
6310
+ const after = normalizeQueryValue2(url.searchParams.get("after") ?? null);
6311
+ const sinceEpoch = normalizeQueryValue2(url.searchParams.get("sinceEpoch"));
6312
+ if (after && sinceEpoch) {
6313
+ return { error: "Use either after or sinceEpoch, not both." };
6314
+ }
6315
+ if (sinceEpoch) {
6316
+ return { kind: "epoch", epoch: sinceEpoch };
6317
+ }
6318
+ if (after) {
6319
+ return { kind: "epoch", epoch: after };
6320
+ }
6321
+ return { kind: "all" };
6322
+ };
6323
+ var respondLogEpochError = (res, error) => {
6324
+ const status = error.code === "invalid" || error.code === "future" ? 400 : 409;
6325
+ respondJson(res, {
6326
+ ok: false,
6327
+ error: {
6328
+ message: error.message,
6329
+ code: `log_epoch_${error.code}`
6330
+ }
6331
+ }, status);
6332
+ };
6333
+ var listLogsFromPosition = (buffer, position, filters, limit) => {
6334
+ if (position.kind === "epoch") {
6335
+ return buffer.listAfterEpoch(position.epoch, filters, limit);
6336
+ }
6337
+ return createQueryResult(buffer, position, buffer.listAfter(0, filters, limit));
6338
+ };
6339
+ var waitForLogsFromPosition = async (buffer, position, filters, limit, timeoutMs) => {
6340
+ if (position.kind === "epoch") {
6341
+ return buffer.waitForAfterEpoch(position.epoch, filters, limit, timeoutMs);
6342
+ }
6343
+ const events = await buffer.waitForAfter(0, filters, limit, timeoutMs);
6344
+ return createQueryResult(buffer, position, events);
6345
+ };
6346
+ var createQueryResult = (buffer, position, events) => ({
6347
+ events,
6348
+ nextCursor: resolveNextCursor(buffer, position, events)
6349
+ });
6350
+ var resolveNextCursor = (buffer, position, events) => {
6351
+ if (events.length > 0) {
6352
+ return buffer.getEpochAt(events[events.length - 1]?.id ?? 0);
6353
+ }
6354
+ if (position.kind === "epoch") {
6355
+ return position.epoch;
6356
+ }
6357
+ return buffer.getEpoch();
6358
+ };
6359
+
6092
6360
  // ../argus-watcher/dist/http/routes/getLogs.js
6093
6361
  var route2 = defineJsonRoute({
6094
6362
  method: "GET",
6095
6363
  path: "/logs",
6096
6364
  handle: ({ res, url, ctx }) => {
6097
- const after = clampNumber(url.searchParams.get("after"), 0);
6365
+ const position = parseLogPosition(url);
6366
+ if ("error" in position) {
6367
+ return respondLogEpochError(res, new LogEpochError("invalid", position.error));
6368
+ }
6098
6369
  const limit = clampNumber(url.searchParams.get("limit"), 500, 1, 5000);
6099
6370
  const levels = parseLevels(url.searchParams.get("levels"));
6100
6371
  const match = url.searchParams.getAll("match");
@@ -6112,19 +6383,51 @@ var route2 = defineJsonRoute({
6112
6383
  if (compiledMatch.error) {
6113
6384
  return respondInvalidMatch(res, compiledMatch.error);
6114
6385
  }
6115
- emitRequest(ctx, res, "logs", { after, limit, levels, match: matchPatterns.patterns, matchCase, source, sinceTs });
6116
- const events = ctx.buffer.listAfter(after, { levels, match: compiledMatch.match, source, sinceTs }, limit);
6117
- const nextAfter = events.length > 0 ? events[events.length - 1]?.id ?? after : after;
6118
- return { ok: true, events, nextAfter };
6386
+ emitRequest(ctx, res, "logs", {
6387
+ after: position.kind === "epoch" && url.searchParams.has("after") ? position.epoch : undefined,
6388
+ sinceEpoch: position.kind === "epoch" ? position.epoch : undefined,
6389
+ limit,
6390
+ levels,
6391
+ match: matchPatterns.patterns,
6392
+ matchCase,
6393
+ source,
6394
+ sinceTs
6395
+ });
6396
+ try {
6397
+ const result = listLogsFromPosition(ctx.buffer, position, { levels, match: compiledMatch.match, source, sinceTs }, limit);
6398
+ return { ok: true, ...result };
6399
+ } catch (error) {
6400
+ if (error instanceof LogEpochError) {
6401
+ return respondLogEpochError(res, error);
6402
+ }
6403
+ throw error;
6404
+ }
6119
6405
  }
6120
6406
  });
6121
6407
 
6122
- // ../argus-watcher/dist/http/routes/getTail.js
6408
+ // ../argus-watcher/dist/http/routes/getLogCursor.js
6123
6409
  var route3 = defineJsonRoute({
6410
+ method: "GET",
6411
+ path: "/logs/cursor",
6412
+ handle: ({ ctx }) => ({ ok: true, cursor: ctx.buffer.getCursor() })
6413
+ });
6414
+
6415
+ // ../argus-watcher/dist/http/routes/getLogEpoch.js
6416
+ var route4 = defineJsonRoute({
6417
+ method: "GET",
6418
+ path: "/logs/epoch",
6419
+ handle: ({ ctx }) => ({ ok: true, epoch: ctx.buffer.beginLogEpoch() })
6420
+ });
6421
+
6422
+ // ../argus-watcher/dist/http/routes/getTail.js
6423
+ var route5 = defineJsonRoute({
6124
6424
  method: "GET",
6125
6425
  path: "/tail",
6126
6426
  handle: async ({ res, url, ctx }) => {
6127
- const after = clampNumber(url.searchParams.get("after"), 0);
6427
+ const position = parseLogPosition(url);
6428
+ if ("error" in position) {
6429
+ return respondLogEpochError(res, new LogEpochError("invalid", position.error));
6430
+ }
6128
6431
  const limit = clampNumber(url.searchParams.get("limit"), 500, 1, 5000);
6129
6432
  const timeoutMs = clampNumber(url.searchParams.get("timeoutMs"), 25000, 1000, 120000);
6130
6433
  const levels = parseLevels(url.searchParams.get("levels"));
@@ -6142,10 +6445,25 @@ var route3 = defineJsonRoute({
6142
6445
  if (compiledMatch.error) {
6143
6446
  return respondInvalidMatch(res, compiledMatch.error);
6144
6447
  }
6145
- emitRequest(ctx, res, "tail", { after, limit, levels, match: matchPatterns.patterns, matchCase, source, timeoutMs });
6146
- const events = await ctx.buffer.waitForAfter(after, { levels, match: compiledMatch.match, source }, limit, timeoutMs);
6147
- const nextAfter = events.length > 0 ? events[events.length - 1]?.id ?? after : after;
6148
- return { ok: true, events, nextAfter, timedOut: events.length === 0 };
6448
+ emitRequest(ctx, res, "tail", {
6449
+ after: position.kind === "epoch" ? position.epoch : undefined,
6450
+ sinceEpoch: position.kind === "epoch" ? position.epoch : undefined,
6451
+ limit,
6452
+ levels,
6453
+ match: matchPatterns.patterns,
6454
+ matchCase,
6455
+ source,
6456
+ timeoutMs
6457
+ });
6458
+ try {
6459
+ const result = await waitForLogsFromPosition(ctx.buffer, position, { levels, match: compiledMatch.match, source }, limit, timeoutMs);
6460
+ return { ok: true, ...result, timedOut: result.events.length === 0 };
6461
+ } catch (error) {
6462
+ if (error instanceof LogEpochError) {
6463
+ return respondLogEpochError(res, error);
6464
+ }
6465
+ throw error;
6466
+ }
6149
6467
  }
6150
6468
  });
6151
6469
 
@@ -6460,7 +6778,7 @@ var hasTruthyFlag = (searchParams, key) => {
6460
6778
  var optionalClampNumber = (value, min) => value == null ? undefined : clampNumber(value, undefined, min);
6461
6779
 
6462
6780
  // ../argus-watcher/dist/http/routes/getNet.js
6463
- var route4 = defineJsonRoute({
6781
+ var route6 = defineJsonRoute({
6464
6782
  method: "GET",
6465
6783
  path: "/net",
6466
6784
  handle: ({ res, url, ctx }) => {
@@ -6479,7 +6797,7 @@ var route4 = defineJsonRoute({
6479
6797
  });
6480
6798
 
6481
6799
  // ../argus-watcher/dist/http/routes/getNetRequests.js
6482
- var route5 = defineJsonRoute({
6800
+ var route7 = defineJsonRoute({
6483
6801
  method: "GET",
6484
6802
  path: "/net/requests",
6485
6803
  handle: ({ res, url, ctx }) => {
@@ -6533,7 +6851,7 @@ var parsePositiveInt2 = (value) => {
6533
6851
  };
6534
6852
 
6535
6853
  // ../argus-watcher/dist/http/routes/getNetRequest.js
6536
- var route6 = defineJsonRoute({
6854
+ var route8 = defineJsonRoute({
6537
6855
  method: "GET",
6538
6856
  path: "/net/request",
6539
6857
  handle: ({ res, url, ctx }) => {
@@ -6617,7 +6935,7 @@ var createNetBodyError = (message, code) => {
6617
6935
  var capitalizePart = (part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`;
6618
6936
 
6619
6937
  // ../argus-watcher/dist/http/routes/getNetRequestBody.js
6620
- var route7 = defineJsonRoute({
6938
+ var route9 = defineJsonRoute({
6621
6939
  method: "GET",
6622
6940
  path: "/net/request/body",
6623
6941
  handle: async ({ res, url, ctx }) => {
@@ -6687,7 +7005,7 @@ var resolveBodySessionId = (ctx, frameId, storedSessionId) => {
6687
7005
  };
6688
7006
 
6689
7007
  // ../argus-watcher/dist/http/routes/getNetTail.js
6690
- var route8 = defineJsonRoute({
7008
+ var route10 = defineJsonRoute({
6691
7009
  method: "GET",
6692
7010
  path: "/net/tail",
6693
7011
  handle: async ({ res, url, ctx }) => {
@@ -6723,7 +7041,7 @@ var pollNetBuffer = async (buffer, after, filters, limit, timeoutMs) => {
6723
7041
  var delay2 = (timeoutMs) => new Promise((resolve) => setTimeout(resolve, timeoutMs));
6724
7042
 
6725
7043
  // ../argus-watcher/dist/http/routes/getNetWebSockets.js
6726
- var route9 = defineJsonRoute({
7044
+ var route11 = defineJsonRoute({
6727
7045
  method: "GET",
6728
7046
  path: "/net/ws",
6729
7047
  handle: ({ res, url, ctx }) => {
@@ -6742,7 +7060,7 @@ var route9 = defineJsonRoute({
6742
7060
  });
6743
7061
 
6744
7062
  // ../argus-watcher/dist/http/routes/getNetWebSocketConnection.js
6745
- var route10 = defineJsonRoute({
7063
+ var route12 = defineJsonRoute({
6746
7064
  method: "GET",
6747
7065
  path: "/net/ws/connection",
6748
7066
  handle: ({ res, url, ctx }) => {
@@ -6764,7 +7082,7 @@ var route10 = defineJsonRoute({
6764
7082
  });
6765
7083
 
6766
7084
  // ../argus-watcher/dist/http/routes/getNetSse.js
6767
- var route11 = defineJsonRoute({
7085
+ var route13 = defineJsonRoute({
6768
7086
  method: "GET",
6769
7087
  path: "/net/sse",
6770
7088
  handle: ({ res, url, ctx }) => {
@@ -6783,7 +7101,7 @@ var route11 = defineJsonRoute({
6783
7101
  });
6784
7102
 
6785
7103
  // ../argus-watcher/dist/http/routes/postNetClear.js
6786
- var route12 = defineJsonRoute({
7104
+ var route14 = defineJsonRoute({
6787
7105
  method: "POST",
6788
7106
  path: "/net/clear",
6789
7107
  handle: ({ res, ctx }) => {
@@ -7268,7 +7586,7 @@ var normalizeStorageEntries = (entries) => entries.filter((entry) => typeof entr
7268
7586
  }));
7269
7587
 
7270
7588
  // ../argus-watcher/dist/http/routes/getAuthCookies.js
7271
- var route13 = defineJsonRoute({
7589
+ var route15 = defineJsonRoute({
7272
7590
  method: "GET",
7273
7591
  path: "/auth/cookies",
7274
7592
  handle: ({ res, url, ctx }) => {
@@ -7283,7 +7601,7 @@ var route13 = defineJsonRoute({
7283
7601
  });
7284
7602
 
7285
7603
  // ../argus-watcher/dist/http/routes/getAuthState.js
7286
- var route14 = defineJsonRoute({
7604
+ var route16 = defineJsonRoute({
7287
7605
  method: "GET",
7288
7606
  path: "/auth/state",
7289
7607
  handle: ({ res, url, ctx }) => {
@@ -7473,7 +7791,7 @@ var applyAuthStateToSession = async (input) => hydrateAuthState({
7473
7791
  });
7474
7792
 
7475
7793
  // ../argus-watcher/dist/http/routes/postAuthStateLoad.js
7476
- var route15 = defineJsonRoute({
7794
+ var route17 = defineJsonRoute({
7477
7795
  method: "POST",
7478
7796
  path: "/auth/state/load",
7479
7797
  parseBody: true,
@@ -7591,14 +7909,305 @@ var expandRemoteObjectViaGetProperties = async (record2, cdp) => {
7591
7909
  return out;
7592
7910
  };
7593
7911
 
7912
+ // ../argus-watcher/dist/cdp/scenarioBridge.js
7913
+ import { randomUUID as randomUUID2 } from "node:crypto";
7914
+ var SCENARIO_ACTION_TIMEOUT_MS = 30000;
7915
+ var DEFAULT_LOG_LIMIT = 500;
7916
+ var MAX_LOG_LIMIT = 5000;
7917
+ var installScenarioBridge = async (session, expression, args, services, timeoutMs) => {
7918
+ const token = randomUUID2();
7919
+ const suffix = token.replaceAll("-", "");
7920
+ const bindingName = `__argusScenarioSend_${suffix}`;
7921
+ const responseName = `__argusScenarioReceive_${suffix}`;
7922
+ const off = session.onEvent("Runtime.bindingCalled", (rawEvent, meta) => {
7923
+ const { name, payload, executionContextId } = rawEvent;
7924
+ if (name !== bindingName || typeof payload !== "string" || typeof executionContextId !== "number" || !Number.isInteger(executionContextId)) {
7925
+ return;
7926
+ }
7927
+ const request = parseBridgeRequest(payload, token);
7928
+ if (!request) {
7929
+ return;
7930
+ }
7931
+ respondToBridgeRequest(session, responseName, request, services, executionContextId, meta, timeoutMs);
7932
+ });
7933
+ try {
7934
+ await session.sendAndWait("Runtime.addBinding", { name: bindingName }, { timeoutMs });
7935
+ } catch (error) {
7936
+ off();
7937
+ throw error;
7938
+ }
7939
+ let disposed = false;
7940
+ return {
7941
+ expression: buildScenarioExpression(expression, { bindingName, responseName, token, args: args ?? {} }),
7942
+ dispose: async () => {
7943
+ if (disposed)
7944
+ return;
7945
+ disposed = true;
7946
+ off();
7947
+ try {
7948
+ await session.sendAndWait("Runtime.removeBinding", { name: bindingName }, { timeoutMs });
7949
+ } catch {}
7950
+ }
7951
+ };
7952
+ };
7953
+ var parseBridgeRequest = (payload, token) => {
7954
+ try {
7955
+ const parsed = JSON.parse(payload);
7956
+ if (typeof parsed !== "object" || parsed == null || Array.isArray(parsed)) {
7957
+ return null;
7958
+ }
7959
+ const { token: requestToken, id, action, payload: requestPayload } = parsed;
7960
+ if (requestToken !== token || typeof id !== "number" || !Number.isInteger(id) || id < 1 || typeof action !== "string") {
7961
+ return null;
7962
+ }
7963
+ return { token: requestToken, id, action, payload: requestPayload };
7964
+ } catch {
7965
+ return null;
7966
+ }
7967
+ };
7968
+ var respondToBridgeRequest = async (session, responseName, request, services, executionContextId, meta, timeoutMs) => {
7969
+ let response;
7970
+ try {
7971
+ response = { id: request.id, ok: true, result: await handleBridgeRequest(request, services) };
7972
+ } catch (error) {
7973
+ response = { id: request.id, ok: false, error: formatError3(error) };
7974
+ }
7975
+ try {
7976
+ await sendBridgeResponse(session, responseName, response, executionContextId, meta, timeoutMs);
7977
+ } catch {}
7978
+ };
7979
+ var handleBridgeRequest = async (request, services) => {
7980
+ switch (request.action) {
7981
+ case "screenshot": {
7982
+ const options = parseScreenshotOptions(request.payload);
7983
+ return services.screenshotter.capture(options);
7984
+ }
7985
+ case "checkpoint": {
7986
+ const payload = requireRecord(request.payload, "checkpoint payload");
7987
+ const name = parseCheckpointName(payload.name);
7988
+ const options = parseScreenshotOptions(payload.options);
7989
+ const fileName = name.endsWith(".png") ? name : `${name}.png`;
7990
+ return services.screenshotter.capture({ ...options, outFile: `scenarios/checkpoints/${fileName}` });
7991
+ }
7992
+ case "logs.cursor":
7993
+ return { cursor: services.buffer.getCursor() };
7994
+ case "logs.read":
7995
+ return readScenarioLogs(services.buffer, request.payload);
7996
+ default:
7997
+ throw new Error(`Unsupported scenario action: ${request.action}`);
7998
+ }
7999
+ };
8000
+ var parseScreenshotOptions = (value) => {
8001
+ if (value == null)
8002
+ return {};
8003
+ const record2 = requireRecord(value, "screenshot options");
8004
+ const selector = record2.selector;
8005
+ const clip = record2.clip;
8006
+ if (selector != null && (typeof selector !== "string" || !selector.trim())) {
8007
+ throw new Error("selector must be a non-empty string");
8008
+ }
8009
+ if (selector != null && clip != null) {
8010
+ throw new Error("selector and clip are mutually exclusive");
8011
+ }
8012
+ return {
8013
+ selector: typeof selector === "string" ? selector : undefined,
8014
+ clip: clip == null ? undefined : parseClip(clip)
8015
+ };
8016
+ };
8017
+ var parseClip = (value) => {
8018
+ const clip = requireRecord(value, "clip");
8019
+ const { x, y, width, height } = clip;
8020
+ if (!isFiniteNumber2(x) || !isFiniteNumber2(y) || !isFiniteNumber2(width) || !isFiniteNumber2(height)) {
8021
+ throw new Error("clip.x, clip.y, clip.width, and clip.height must be finite numbers");
8022
+ }
8023
+ if (width <= 0 || height <= 0) {
8024
+ throw new Error("clip.width and clip.height must be greater than 0");
8025
+ }
8026
+ return { x, y, width, height };
8027
+ };
8028
+ var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
8029
+ var parseCheckpointName = (value) => {
8030
+ if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/.test(value)) {
8031
+ throw new Error("checkpoint name must be 1-100 characters using letters, numbers, dot, underscore, or dash");
8032
+ }
8033
+ return value;
8034
+ };
8035
+ var readScenarioLogs = (buffer, value) => {
8036
+ const payload = requireRecord(value, "logs.read payload");
8037
+ const cursor = payload.cursor;
8038
+ if (typeof cursor !== "string" || !cursor.trim()) {
8039
+ throw new Error("log cursor must be a non-empty opaque cursor");
8040
+ }
8041
+ const { filters, limit } = parseLogOptions(payload.options);
8042
+ return buffer.listAfterEpoch(cursor, filters, limit);
8043
+ };
8044
+ var parseLogOptions = (value) => {
8045
+ if (value == null)
8046
+ return { filters: {}, limit: DEFAULT_LOG_LIMIT };
8047
+ const options = requireRecord(value, "log options");
8048
+ const levels = parseLogLevels(options.levels);
8049
+ const matchCase = parseLogMatchCase(options.matchCase);
8050
+ const match = compileLogMatch(options.match, matchCase);
8051
+ const source = parseLogSource(options.source);
8052
+ const limit = parseLogLimit(options.limit);
8053
+ return {
8054
+ filters: { levels, match, source },
8055
+ limit
8056
+ };
8057
+ };
8058
+ var parseLogLevels = (value) => {
8059
+ if (value == null)
8060
+ return;
8061
+ if (Array.isArray(value) && value.every(isLogLevel))
8062
+ return value;
8063
+ throw new Error(`levels must contain only: ${LOG_LEVELS.join(", ")}`);
8064
+ };
8065
+ var isLogLevel = (value) => typeof value === "string" && LOG_LEVELS.includes(value);
8066
+ var parseLogMatchCase = (value) => {
8067
+ if (value == null || value === "sensitive")
8068
+ return "sensitive";
8069
+ if (value === "insensitive")
8070
+ return value;
8071
+ throw new Error("matchCase must be sensitive or insensitive");
8072
+ };
8073
+ var compileLogMatch = (value, matchCase) => {
8074
+ if (value == null)
8075
+ return;
8076
+ const patterns = Array.isArray(value) ? value : [value];
8077
+ if (patterns.length === 0)
8078
+ return;
8079
+ if (!patterns.every(isNonEmptyString)) {
8080
+ throw new Error("match must be a non-empty string or array of non-empty strings");
8081
+ }
8082
+ try {
8083
+ return patterns.map((pattern) => new RegExp(pattern, matchCase === "insensitive" ? "i" : undefined));
8084
+ } catch (error) {
8085
+ throw new Error(`invalid log match expression: ${formatError3(error)}`);
8086
+ }
8087
+ };
8088
+ var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
8089
+ var parseLogSource = (value) => {
8090
+ if (value == null)
8091
+ return;
8092
+ if (typeof value === "string" && value.trim())
8093
+ return value;
8094
+ throw new Error("source must be a non-empty string");
8095
+ };
8096
+ var parseLogLimit = (value) => {
8097
+ const limit = value ?? DEFAULT_LOG_LIMIT;
8098
+ if (typeof limit === "number" && Number.isInteger(limit) && limit >= 1 && limit <= MAX_LOG_LIMIT)
8099
+ return limit;
8100
+ throw new Error(`limit must be an integer from 1 to ${MAX_LOG_LIMIT}`);
8101
+ };
8102
+ var requireRecord = (value, label) => {
8103
+ if (typeof value !== "object" || value == null || Array.isArray(value)) {
8104
+ throw new Error(`${label} must be an object`);
8105
+ }
8106
+ return value;
8107
+ };
8108
+ var sendBridgeResponse = async (session, responseName, response, executionContextId, meta, timeoutMs) => {
8109
+ await session.sendAndWait("Runtime.evaluate", {
8110
+ expression: `globalThis[${JSON.stringify(responseName)}]?.(${JSON.stringify(response)})`,
8111
+ contextId: executionContextId,
8112
+ returnByValue: true,
8113
+ silent: true
8114
+ }, { timeoutMs, sessionId: meta.sessionId ?? undefined });
8115
+ };
8116
+ var buildScenarioExpression = (expression, options) => `(async () => {
8117
+ const __argusBridge = (() => {
8118
+ const send = globalThis[${JSON.stringify(options.bindingName)}];
8119
+ if (typeof send !== 'function') throw new Error('Argus scenario bridge is unavailable');
8120
+ const pending = new Map();
8121
+ let nextId = 1;
8122
+ const receiveName = ${JSON.stringify(options.responseName)};
8123
+ Object.defineProperty(globalThis, receiveName, {
8124
+ configurable: true,
8125
+ value: (message) => {
8126
+ const entry = pending.get(message?.id);
8127
+ if (!entry) return;
8128
+ pending.delete(message.id);
8129
+ clearTimeout(entry.timeout);
8130
+ if (message.ok) entry.resolve(message.result);
8131
+ else entry.reject(new Error(message.error));
8132
+ },
8133
+ });
8134
+ const request = (action, payload) => new Promise((resolve, reject) => {
8135
+ const id = nextId++;
8136
+ const timeout = setTimeout(() => {
8137
+ pending.delete(id);
8138
+ reject(new Error('Argus scenario action timed out after ${SCENARIO_ACTION_TIMEOUT_MS}ms: ' + action));
8139
+ }, ${SCENARIO_ACTION_TIMEOUT_MS});
8140
+ pending.set(id, { resolve, reject, timeout });
8141
+ try {
8142
+ send(JSON.stringify({ token: ${JSON.stringify(options.token)}, id, action, payload }));
8143
+ } catch (error) {
8144
+ clearTimeout(timeout);
8145
+ pending.delete(id);
8146
+ reject(error);
8147
+ }
8148
+ });
8149
+ const logs = Object.freeze({
8150
+ cursor: async () => (await request('logs.cursor')).cursor,
8151
+ read: (cursor, logOptions) => request('logs.read', { cursor, options: logOptions }),
8152
+ session: async () => {
8153
+ let cursor = (await request('logs.cursor')).cursor;
8154
+ return Object.freeze({
8155
+ get cursor() { return cursor; },
8156
+ async read(logOptions) {
8157
+ const result = await request('logs.read', { cursor, options: logOptions });
8158
+ cursor = result.nextCursor;
8159
+ return result;
8160
+ },
8161
+ });
8162
+ },
8163
+ });
8164
+ const context = Object.freeze({
8165
+ args: Object.freeze(${JSON.stringify(options.args)}),
8166
+ screenshot: (screenshotOptions) => request('screenshot', screenshotOptions),
8167
+ checkpoint: (name, screenshotOptions) => request('checkpoint', { name, options: screenshotOptions }),
8168
+ logs,
8169
+ });
8170
+ return {
8171
+ context,
8172
+ dispose() {
8173
+ delete globalThis[receiveName];
8174
+ for (const entry of pending.values()) {
8175
+ clearTimeout(entry.timeout);
8176
+ entry.reject(new Error('Argus scenario finished before the action completed'));
8177
+ }
8178
+ pending.clear();
8179
+ },
8180
+ };
8181
+ })();
8182
+ const __argusScenarioContext = __argusBridge.context;
8183
+ try {
8184
+ return await (${expression}
8185
+ );
8186
+ } finally {
8187
+ __argusBridge.dispose();
8188
+ }
8189
+ })()`;
8190
+ var formatError3 = (error) => error instanceof Error ? error.message : String(error);
8191
+
7594
8192
  // ../argus-watcher/dist/cdp/eval.js
7595
8193
  var evaluateExpression = async (session, options) => {
7596
8194
  const args = hasEvalArgs(options.args) ? options.args : undefined;
7597
8195
  if (args) {
7598
8196
  await installEvalArgs(session, args, options.timeoutMs);
7599
8197
  }
8198
+ let scenarioBridge;
7600
8199
  try {
7601
- const recordResult = await evaluateAndAwaitRecord(session, options);
8200
+ if (options.scenario) {
8201
+ if (!options.scenarioServices) {
8202
+ throw new Error("Scenario host services are unavailable");
8203
+ }
8204
+ scenarioBridge = await installScenarioBridge(session, options.expression, args, options.scenarioServices, options.timeoutMs);
8205
+ }
8206
+ const recordResult = await evaluateAndAwaitRecord(session, {
8207
+ ...options,
8208
+ expression: scenarioBridge?.expression ?? options.expression,
8209
+ replMode: scenarioBridge ? false : options.replMode
8210
+ });
7602
8211
  if (recordResult.exception)
7603
8212
  return recordResult.response;
7604
8213
  const record2 = recordResult.record;
@@ -7610,6 +8219,7 @@ var evaluateExpression = async (session, options) => {
7610
8219
  exception: null
7611
8220
  };
7612
8221
  } finally {
8222
+ await scenarioBridge?.dispose();
7613
8223
  if (args) {
7614
8224
  await restoreEvalArgs(session, options.timeoutMs);
7615
8225
  }
@@ -7712,7 +8322,7 @@ var shouldMaterializeByValue = (record2) => {
7712
8322
  };
7713
8323
 
7714
8324
  // ../argus-watcher/dist/http/routes/postEval.js
7715
- var route16 = defineJsonRoute({
8325
+ var route18 = defineJsonRoute({
7716
8326
  method: "POST",
7717
8327
  path: "/eval",
7718
8328
  parseBody: true,
@@ -7729,7 +8339,12 @@ var route16 = defineJsonRoute({
7729
8339
  awaitPromise: normalizeBoolean(payload.awaitPromise, true),
7730
8340
  replMode: normalizeBoolean(payload.replMode, true),
7731
8341
  returnByValue: normalizeBoolean(payload.returnByValue, true),
7732
- timeoutMs: normalizeTimeout(payload.timeoutMs)
8342
+ timeoutMs: normalizeTimeout(payload.timeoutMs),
8343
+ scenario: normalizeBoolean(payload.scenario, false),
8344
+ scenarioServices: {
8345
+ buffer: ctx.buffer,
8346
+ screenshotter: ctx.screenshotter
8347
+ }
7733
8348
  })
7734
8349
  });
7735
8350
  var normalizeEvalArgs = (args) => {
@@ -7746,7 +8361,7 @@ var normalizeEvalArgs = (args) => {
7746
8361
  };
7747
8362
 
7748
8363
  // ../argus-watcher/dist/http/routes/postTraceStart.js
7749
- var route17 = defineJsonRoute({
8364
+ var route19 = defineJsonRoute({
7750
8365
  method: "POST",
7751
8366
  path: "/trace/start",
7752
8367
  parseBody: true,
@@ -7755,7 +8370,7 @@ var route17 = defineJsonRoute({
7755
8370
  });
7756
8371
 
7757
8372
  // ../argus-watcher/dist/http/routes/postTraceStop.js
7758
- var route18 = defineJsonRoute({
8373
+ var route20 = defineJsonRoute({
7759
8374
  method: "POST",
7760
8375
  path: "/trace/stop",
7761
8376
  parseBody: true,
@@ -7851,7 +8466,7 @@ var validateClip = (clip) => {
7851
8466
  };
7852
8467
 
7853
8468
  // ../argus-watcher/dist/http/routes/postScreenshot.js
7854
- var route19 = defineJsonRoute({
8469
+ var route21 = defineJsonRoute({
7855
8470
  method: "POST",
7856
8471
  path: "/screenshot",
7857
8472
  parseBody: true,
@@ -8363,7 +8978,7 @@ var countNodes = (nodes) => {
8363
8978
  };
8364
8979
 
8365
8980
  // ../argus-watcher/dist/http/routes/postSnapshot.js
8366
- var route20 = defineJsonRoute({
8981
+ var route22 = defineJsonRoute({
8367
8982
  method: "POST",
8368
8983
  path: "/snapshot",
8369
8984
  parseBody: true,
@@ -8540,7 +9155,7 @@ var locateRoutes = [
8540
9155
  ];
8541
9156
 
8542
9157
  // ../argus-watcher/dist/http/routes/postCodeList.js
8543
- var route21 = defineJsonRoute({
9158
+ var route23 = defineJsonRoute({
8544
9159
  method: "POST",
8545
9160
  path: "/code/list",
8546
9161
  parseBody: true,
@@ -8555,7 +9170,7 @@ var route21 = defineJsonRoute({
8555
9170
  });
8556
9171
 
8557
9172
  // ../argus-watcher/dist/http/routes/postCodeRead.js
8558
- var route22 = defineJsonRoute({
9173
+ var route24 = defineJsonRoute({
8559
9174
  method: "POST",
8560
9175
  path: "/code/read",
8561
9176
  parseBody: true,
@@ -8580,7 +9195,7 @@ var route22 = defineJsonRoute({
8580
9195
  });
8581
9196
 
8582
9197
  // ../argus-watcher/dist/http/routes/postCodeGrep.js
8583
- var route23 = defineJsonRoute({
9198
+ var route25 = defineJsonRoute({
8584
9199
  method: "POST",
8585
9200
  path: "/code/grep",
8586
9201
  parseBody: true,
@@ -8601,7 +9216,7 @@ var route23 = defineJsonRoute({
8601
9216
  });
8602
9217
 
8603
9218
  // ../argus-watcher/dist/http/routes/postCodeEdit.js
8604
- var route24 = defineJsonRoute({
9219
+ var route26 = defineJsonRoute({
8605
9220
  method: "POST",
8606
9221
  path: "/code/edit",
8607
9222
  parseBody: true,
@@ -8958,7 +9573,7 @@ var fillResolvedNodes = async (session, handles, value) => {
8958
9573
  return handles.length;
8959
9574
  };
8960
9575
  // ../argus-watcher/dist/http/routes/postDomTree.js
8961
- var route25 = defineJsonRoute({
9576
+ var route27 = defineJsonRoute({
8962
9577
  method: "POST",
8963
9578
  path: "/dom/tree",
8964
9579
  parseBody: true,
@@ -8981,7 +9596,7 @@ var route25 = defineJsonRoute({
8981
9596
  });
8982
9597
 
8983
9598
  // ../argus-watcher/dist/http/routes/postDomInfo.js
8984
- var route26 = defineJsonRoute({
9599
+ var route28 = defineJsonRoute({
8985
9600
  method: "POST",
8986
9601
  path: "/dom/info",
8987
9602
  parseBody: true,
@@ -9266,7 +9881,7 @@ var defineDomTargetRoute = (input) => defineJsonRoute({
9266
9881
  });
9267
9882
 
9268
9883
  // ../argus-watcher/dist/http/routes/postDomHover.js
9269
- var route27 = defineDomTargetRoute({
9884
+ var route29 = defineDomTargetRoute({
9270
9885
  path: "/dom/hover",
9271
9886
  endpoint: "dom/hover",
9272
9887
  action: "hover",
@@ -9277,7 +9892,7 @@ var route27 = defineDomTargetRoute({
9277
9892
  });
9278
9893
 
9279
9894
  // ../argus-watcher/dist/http/routes/postDomClick.js
9280
- var route28 = defineJsonRoute({
9895
+ var route30 = defineJsonRoute({
9281
9896
  method: "POST",
9282
9897
  path: "/dom/click",
9283
9898
  bodySchema: domClickRequestSchema,
@@ -9325,7 +9940,7 @@ var route28 = defineJsonRoute({
9325
9940
  });
9326
9941
 
9327
9942
  // ../argus-watcher/dist/http/routes/postDomDrag.js
9328
- var route29 = defineJsonRoute({
9943
+ var route31 = defineJsonRoute({
9329
9944
  method: "POST",
9330
9945
  path: "/dom/drag",
9331
9946
  bodySchema: domDragRequestSchema,
@@ -9542,7 +10157,7 @@ var dispatchKeydown = async (session, options) => {
9542
10157
  };
9543
10158
 
9544
10159
  // ../argus-watcher/dist/http/routes/postDomKeydown.js
9545
- var route30 = defineJsonRoute({
10160
+ var route32 = defineJsonRoute({
9546
10161
  method: "POST",
9547
10162
  path: "/dom/keydown",
9548
10163
  parseBody: true,
@@ -9592,7 +10207,7 @@ var route30 = defineJsonRoute({
9592
10207
 
9593
10208
  // ../argus-watcher/dist/http/routes/postDomAdd.js
9594
10209
  var validPositions = ["beforebegin", "afterbegin", "beforeend", "afterend"];
9595
- var route31 = defineJsonRoute({
10210
+ var route33 = defineJsonRoute({
9596
10211
  method: "POST",
9597
10212
  path: "/dom/add",
9598
10213
  parseBody: true,
@@ -9681,7 +10296,7 @@ var selectDomAddNodeIds = (allNodeIds, options) => {
9681
10296
  };
9682
10297
 
9683
10298
  // ../argus-watcher/dist/http/routes/postDomRemove.js
9684
- var route32 = defineJsonRoute({
10299
+ var route34 = defineJsonRoute({
9685
10300
  method: "POST",
9686
10301
  path: "/dom/remove",
9687
10302
  parseBody: true,
@@ -9703,7 +10318,7 @@ var route32 = defineJsonRoute({
9703
10318
 
9704
10319
  // ../argus-watcher/dist/http/routes/postDomModify.js
9705
10320
  var validTypes = ["attr", "class", "style", "text", "html"];
9706
- var route33 = defineJsonRoute({
10321
+ var route35 = defineJsonRoute({
9707
10322
  method: "POST",
9708
10323
  path: "/dom/modify",
9709
10324
  parseBody: true,
@@ -9734,7 +10349,7 @@ var route33 = defineJsonRoute({
9734
10349
  });
9735
10350
 
9736
10351
  // ../argus-watcher/dist/http/routes/postDomSetFile.js
9737
- var route34 = defineJsonRoute({
10352
+ var route36 = defineJsonRoute({
9738
10353
  method: "POST",
9739
10354
  path: "/dom/set-file",
9740
10355
  parseBody: true,
@@ -9772,7 +10387,7 @@ var route34 = defineJsonRoute({
9772
10387
  });
9773
10388
 
9774
10389
  // ../argus-watcher/dist/http/routes/postDomFocus.js
9775
- var route35 = defineDomTargetRoute({
10390
+ var route37 = defineDomTargetRoute({
9776
10391
  path: "/dom/focus",
9777
10392
  endpoint: "dom/focus",
9778
10393
  action: "focus",
@@ -9783,7 +10398,7 @@ var route35 = defineDomTargetRoute({
9783
10398
  });
9784
10399
 
9785
10400
  // ../argus-watcher/dist/http/routes/postDomFill.js
9786
- var route36 = defineDomTargetRoute({
10401
+ var route38 = defineDomTargetRoute({
9787
10402
  path: "/dom/fill",
9788
10403
  endpoint: "dom/fill",
9789
10404
  action: "fill",
@@ -9804,7 +10419,7 @@ var route36 = defineDomTargetRoute({
9804
10419
  });
9805
10420
 
9806
10421
  // ../argus-watcher/dist/http/routes/postDomScroll.js
9807
- var route37 = defineJsonRoute({
10422
+ var route39 = defineJsonRoute({
9808
10423
  method: "POST",
9809
10424
  path: "/dom/scroll",
9810
10425
  parseBody: true,
@@ -9863,7 +10478,7 @@ var getViewportSize = async (session) => {
9863
10478
  };
9864
10479
 
9865
10480
  // ../argus-watcher/dist/http/routes/postDomScrollTo.js
9866
- var route38 = defineJsonRoute({
10481
+ var route40 = defineJsonRoute({
9867
10482
  method: "POST",
9868
10483
  path: "/dom/scroll-to",
9869
10484
  parseBody: true,
@@ -9910,7 +10525,7 @@ var route38 = defineJsonRoute({
9910
10525
  });
9911
10526
 
9912
10527
  // ../argus-watcher/dist/http/routes/getEmulation.js
9913
- var route39 = defineJsonRoute({
10528
+ var route41 = defineJsonRoute({
9914
10529
  method: "GET",
9915
10530
  path: "/emulation",
9916
10531
  endpoint: "emulation",
@@ -9919,7 +10534,7 @@ var route39 = defineJsonRoute({
9919
10534
 
9920
10535
  // ../argus-watcher/dist/http/routes/postEmulation.js
9921
10536
  var validActions = ["set", "clear"];
9922
- var route40 = defineJsonRoute({
10537
+ var route42 = defineJsonRoute({
9923
10538
  method: "POST",
9924
10539
  path: "/emulation",
9925
10540
  parseBody: true,
@@ -9978,7 +10593,7 @@ function validateEmulationRequest(payload) {
9978
10593
  }
9979
10594
 
9980
10595
  // ../argus-watcher/dist/http/routes/getThrottle.js
9981
- var route41 = defineJsonRoute({
10596
+ var route43 = defineJsonRoute({
9982
10597
  method: "GET",
9983
10598
  path: "/throttle",
9984
10599
  endpoint: "throttle",
@@ -9987,7 +10602,7 @@ var route41 = defineJsonRoute({
9987
10602
 
9988
10603
  // ../argus-watcher/dist/http/routes/postThrottle.js
9989
10604
  var validActions2 = ["set", "clear"];
9990
- var route42 = defineJsonRoute({
10605
+ var route44 = defineJsonRoute({
9991
10606
  method: "POST",
9992
10607
  path: "/throttle",
9993
10608
  parseBody: true,
@@ -10015,7 +10630,7 @@ var route42 = defineJsonRoute({
10015
10630
  });
10016
10631
 
10017
10632
  // ../argus-watcher/dist/http/routes/getDialog.js
10018
- var route43 = defineJsonRoute({
10633
+ var route45 = defineJsonRoute({
10019
10634
  method: "GET",
10020
10635
  path: "/dialog",
10021
10636
  endpoint: "dialog/status",
@@ -10023,7 +10638,7 @@ var route43 = defineJsonRoute({
10023
10638
  });
10024
10639
 
10025
10640
  // ../argus-watcher/dist/http/routes/postDialog.js
10026
- var route44 = defineJsonRoute({
10641
+ var route46 = defineJsonRoute({
10027
10642
  method: "POST",
10028
10643
  path: "/dialog",
10029
10644
  parseBody: true,
@@ -10062,7 +10677,7 @@ var route44 = defineJsonRoute({
10062
10677
  });
10063
10678
 
10064
10679
  // ../argus-watcher/dist/http/routes/postVisibility.js
10065
- var route45 = defineJsonRoute({
10680
+ var route47 = defineJsonRoute({
10066
10681
  method: "POST",
10067
10682
  path: "/visibility",
10068
10683
  parseBody: true,
@@ -10179,7 +10794,7 @@ function validateStoragePayload(payload) {
10179
10794
  }
10180
10795
 
10181
10796
  // ../argus-watcher/dist/http/routes/postReload.js
10182
- var route46 = defineJsonRoute({
10797
+ var route48 = defineJsonRoute({
10183
10798
  method: "POST",
10184
10799
  path: "/reload",
10185
10800
  parseBody: true,
@@ -10193,7 +10808,7 @@ var route46 = defineJsonRoute({
10193
10808
  });
10194
10809
 
10195
10810
  // ../argus-watcher/dist/http/routes/postShutdown.js
10196
- var route47 = defineJsonRoute({
10811
+ var route49 = defineJsonRoute({
10197
10812
  method: "POST",
10198
10813
  path: "/shutdown",
10199
10814
  endpoint: "shutdown",
@@ -10208,7 +10823,7 @@ var route47 = defineJsonRoute({
10208
10823
  });
10209
10824
 
10210
10825
  // ../argus-watcher/dist/http/routes/getExtensionTabs.js
10211
- var route48 = defineJsonRoute({
10826
+ var route50 = defineJsonRoute({
10212
10827
  method: "GET",
10213
10828
  path: "/tabs",
10214
10829
  extensionOnly: true,
@@ -10229,7 +10844,7 @@ var route48 = defineJsonRoute({
10229
10844
  });
10230
10845
 
10231
10846
  // ../argus-watcher/dist/http/routes/getExtensionDiagnostics.js
10232
- var route49 = defineJsonRoute({
10847
+ var route51 = defineJsonRoute({
10233
10848
  method: "GET",
10234
10849
  path: "/extension/diagnostics",
10235
10850
  extensionOnly: true,
@@ -10243,7 +10858,7 @@ var route49 = defineJsonRoute({
10243
10858
  });
10244
10859
 
10245
10860
  // ../argus-watcher/dist/http/routes/getTargets.js
10246
- var route50 = defineJsonRoute({
10861
+ var route52 = defineJsonRoute({
10247
10862
  method: "GET",
10248
10863
  path: "/targets",
10249
10864
  extensionOnly: true,
@@ -10258,7 +10873,7 @@ var route50 = defineJsonRoute({
10258
10873
  });
10259
10874
 
10260
10875
  // ../argus-watcher/dist/http/routes/postAttach.js
10261
- var route51 = defineJsonRoute({
10876
+ var route53 = defineJsonRoute({
10262
10877
  method: "POST",
10263
10878
  path: "/attach",
10264
10879
  parseBody: true,
@@ -10281,7 +10896,7 @@ var route51 = defineJsonRoute({
10281
10896
  });
10282
10897
 
10283
10898
  // ../argus-watcher/dist/http/routes/postDetach.js
10284
- var route52 = defineJsonRoute({
10899
+ var route54 = defineJsonRoute({
10285
10900
  method: "POST",
10286
10901
  path: "/detach",
10287
10902
  parseBody: true,
@@ -10306,9 +10921,9 @@ var route52 = defineJsonRoute({
10306
10921
  // ../argus-watcher/dist/http/routes/index.js
10307
10922
  var watcherRoutes = [
10308
10923
  route,
10309
- route2,
10310
10924
  route3,
10311
10925
  route4,
10926
+ route2,
10312
10927
  route5,
10313
10928
  route6,
10314
10929
  route7,
@@ -10317,23 +10932,23 @@ var watcherRoutes = [
10317
10932
  route10,
10318
10933
  route11,
10319
10934
  route12,
10320
- ...netMockRoutes,
10321
10935
  route13,
10936
+ route14,
10937
+ ...netMockRoutes,
10938
+ route15,
10322
10939
  cookieGetRoute,
10323
10940
  cookieSetRoute,
10324
10941
  cookieDeleteRoute,
10325
10942
  cookieClearRoute,
10326
- route14,
10327
- route15,
10328
10943
  route16,
10329
10944
  route17,
10330
10945
  route18,
10331
- ...recordRoutes,
10332
10946
  route19,
10333
10947
  route20,
10334
- ...locateRoutes,
10948
+ ...recordRoutes,
10335
10949
  route21,
10336
10950
  route22,
10951
+ ...locateRoutes,
10337
10952
  route23,
10338
10953
  route24,
10339
10954
  route25,
@@ -10357,18 +10972,20 @@ var watcherRoutes = [
10357
10972
  route43,
10358
10973
  route44,
10359
10974
  route45,
10360
- ...storageRoutes,
10361
10975
  route46,
10362
10976
  route47,
10977
+ ...storageRoutes,
10363
10978
  route48,
10364
10979
  route49,
10365
10980
  route50,
10366
10981
  route51,
10367
- route52
10982
+ route52,
10983
+ route53,
10984
+ route54
10368
10985
  ];
10369
10986
 
10370
10987
  // ../argus-watcher/dist/http/router.js
10371
- var routes = new Map(watcherRoutes.map((route53) => [`${route53.method} ${route53.path}`, route53]));
10988
+ var routes = new Map(watcherRoutes.map((route55) => [`${route55.method} ${route55.path}`, route55]));
10372
10989
  var dispatch = (req, res, url, ctx) => {
10373
10990
  const entry = routes.get(`${req.method} ${url.pathname}`);
10374
10991
  if (!entry || entry.extensionOnly && !ctx.sourceHandle) {
@@ -11032,97 +11649,6 @@ var formatWatcherError = (error) => {
11032
11649
  import os3 from "node:os";
11033
11650
  import path7 from "node:path";
11034
11651
 
11035
- // ../argus-watcher/dist/buffer/LogBuffer.js
11036
- class LogBuffer {
11037
- maxSize;
11038
- events = [];
11039
- nextId = 1;
11040
- waiters = [];
11041
- constructor(maxSize) {
11042
- this.maxSize = maxSize;
11043
- }
11044
- add(event) {
11045
- const entry = {
11046
- ...event,
11047
- id: this.nextId++
11048
- };
11049
- this.events.push(entry);
11050
- this.trim();
11051
- this.flushWaiters();
11052
- return entry;
11053
- }
11054
- listAfter(after, filters, limit) {
11055
- const filtered = this.events.filter((event) => event.id > after && matchesFilters(event, filters));
11056
- return filtered.slice(0, limit);
11057
- }
11058
- waitForAfter(after, filters, limit, timeoutMs) {
11059
- const immediate = this.listAfter(after, filters, limit);
11060
- if (immediate.length > 0) {
11061
- return Promise.resolve(immediate);
11062
- }
11063
- return new Promise((resolve) => {
11064
- const timer = setTimeout(() => {
11065
- this.waiters = this.waiters.filter((waiter) => waiter.timer !== timer);
11066
- resolve([]);
11067
- }, timeoutMs);
11068
- this.waiters.push({ after, filters, limit, resolve, timer });
11069
- });
11070
- }
11071
- getStats() {
11072
- if (this.events.length === 0) {
11073
- return { size: this.maxSize, count: 0, minId: null, maxId: null };
11074
- }
11075
- return {
11076
- size: this.maxSize,
11077
- count: this.events.length,
11078
- minId: this.events[0]?.id ?? null,
11079
- maxId: this.events[this.events.length - 1]?.id ?? null
11080
- };
11081
- }
11082
- trim() {
11083
- if (this.events.length <= this.maxSize) {
11084
- return;
11085
- }
11086
- this.events = this.events.slice(this.events.length - this.maxSize);
11087
- }
11088
- flushWaiters() {
11089
- if (this.waiters.length === 0) {
11090
- return;
11091
- }
11092
- const remaining = [];
11093
- for (const waiter of this.waiters) {
11094
- const events = this.listAfter(waiter.after, waiter.filters, waiter.limit);
11095
- if (events.length > 0) {
11096
- clearTimeout(waiter.timer);
11097
- waiter.resolve(events);
11098
- continue;
11099
- }
11100
- remaining.push(waiter);
11101
- }
11102
- this.waiters = remaining;
11103
- }
11104
- }
11105
- var matchesFilters = (event, filters) => {
11106
- if (filters.sinceTs && event.ts < filters.sinceTs) {
11107
- return false;
11108
- }
11109
- if (filters.levels && filters.levels.length > 0 && !filters.levels.includes(event.level)) {
11110
- return false;
11111
- }
11112
- if (filters.source && !event.source.toLowerCase().includes(filters.source.toLowerCase())) {
11113
- return false;
11114
- }
11115
- if (filters.match && filters.match.length > 0) {
11116
- for (const pattern of filters.match) {
11117
- if (pattern.test(event.text)) {
11118
- return true;
11119
- }
11120
- }
11121
- return false;
11122
- }
11123
- return true;
11124
- };
11125
-
11126
11652
  // ../argus-watcher/dist/buffer/NetBuffer.js
11127
11653
  class NetBuffer {
11128
11654
  maxSize;
@@ -15140,8 +15666,8 @@ var startCdpWatcher = (options) => {
15140
15666
  await connectOnce();
15141
15667
  backoffMs = 1000;
15142
15668
  } catch (error) {
15143
- const reason = `connect_failed: ${formatError3(error)}`;
15144
- options.onLog(createSystemLog(`CDP connection failed: ${formatError3(error)}`));
15669
+ const reason = `connect_failed: ${formatError4(error)}`;
15670
+ options.onLog(createSystemLog(`CDP connection failed: ${formatError4(error)}`));
15145
15671
  options.onStatus({ attached: false, target: null, reason });
15146
15672
  options.onDetach?.(reason);
15147
15673
  await delay4(backoffMs);
@@ -15218,7 +15744,7 @@ var createSystemLog = (message) => ({
15218
15744
  pageTitle: null,
15219
15745
  source: "system"
15220
15746
  });
15221
- var formatError3 = (error) => {
15747
+ var formatError4 = (error) => {
15222
15748
  if (!error) {
15223
15749
  return "Unknown error";
15224
15750
  }
@@ -19712,9 +20238,11 @@ var previewLogEvent = (event) => ({
19712
20238
 
19713
20239
  // dist/watchers/queryParams.js
19714
20240
  var appendAfterLimitParams = (params, options) => {
19715
- const after = parseNumber(options.after);
19716
- if (after != null) {
19717
- params.set("after", String(after));
20241
+ if (options.after?.trim()) {
20242
+ params.set("after", options.after.trim());
20243
+ }
20244
+ if (options.sinceEpoch?.trim()) {
20245
+ params.set("sinceEpoch", options.sinceEpoch.trim());
19718
20246
  }
19719
20247
  const limit = parseNumber(options.limit);
19720
20248
  if (limit != null) {
@@ -19851,6 +20379,14 @@ var appendRepeatedParams = (params, key, values) => {
19851
20379
  };
19852
20380
 
19853
20381
  // dist/commands/logs.js
20382
+ var runLogCursor = defineWatcherCommand({
20383
+ build: () => ({ path: "/logs/cursor", timeoutMs: 5000 }),
20384
+ formatHuman: (response, { output }) => output.writeHuman(response.cursor)
20385
+ });
20386
+ var runLogEpoch = defineWatcherCommand({
20387
+ build: () => ({ path: "/logs/epoch", timeoutMs: 5000 }),
20388
+ formatHuman: (response, { output }) => output.writeHuman(response.epoch)
20389
+ });
19854
20390
  var runLogs = defineWatcherCommand({
19855
20391
  isJson: (options) => options.jsonFull === true,
19856
20392
  build: (_args, options, output) => buildLogsPlan(options, output),
@@ -19892,7 +20428,14 @@ var runTail = async (id, options) => {
19892
20428
  if (!resolved)
19893
20429
  return;
19894
20430
  const { watcher } = resolved;
19895
- let after = parseNumber(options.after) ?? 0;
20431
+ const afterEpoch = options.after?.trim() || undefined;
20432
+ const sinceEpoch = options.sinceEpoch?.trim() || undefined;
20433
+ if (afterEpoch && sinceEpoch) {
20434
+ output.writeWarn("Use either --after or --since-epoch, not both.");
20435
+ process.exitCode = 2;
20436
+ return;
20437
+ }
20438
+ let position = afterEpoch ?? sinceEpoch;
19896
20439
  const timeoutMs = parseNumber(options.timeout) ?? 25000;
19897
20440
  const limit = parseNumber(options.limit);
19898
20441
  let running = true;
@@ -19903,7 +20446,9 @@ var runTail = async (id, options) => {
19903
20446
  process.on("SIGTERM", stop);
19904
20447
  while (running) {
19905
20448
  const params = new URLSearchParams;
19906
- params.set("after", String(after));
20449
+ if (position) {
20450
+ params.set(sinceEpoch ? "sinceEpoch" : "after", position);
20451
+ }
19907
20452
  params.set("timeoutMs", String(timeoutMs));
19908
20453
  if (limit != null) {
19909
20454
  params.set("limit", String(limit));
@@ -19923,24 +20468,22 @@ var runTail = async (id, options) => {
19923
20468
  process.exitCode = 1;
19924
20469
  return;
19925
20470
  }
19926
- if (response.events.length > 0) {
19927
- for (const event of response.events) {
19928
- if (options.jsonFull) {
19929
- output.writeJsonLine({ watcher: watcher.id, event });
19930
- continue;
19931
- }
19932
- if (options.json) {
19933
- const previewEvent = previewLogEvent(event);
19934
- output.writeJsonLine({ watcher: watcher.id, event: previewEvent });
19935
- continue;
19936
- }
19937
- output.writeHuman(formatLogEvent(event, {
19938
- includeTimestamps: watcher.includeTimestamps
19939
- }));
19940
- }
20471
+ for (const event of response.events) {
20472
+ writeTailEvent(event, watcher, options, output);
19941
20473
  }
19942
- after = response.nextAfter;
20474
+ position = response.nextCursor;
20475
+ }
20476
+ };
20477
+ var writeTailEvent = (event, watcher, options, output) => {
20478
+ if (options.jsonFull) {
20479
+ output.writeJsonLine({ watcher: watcher.id, event });
20480
+ return;
20481
+ }
20482
+ if (options.json) {
20483
+ output.writeJsonLine({ watcher: watcher.id, event: previewLogEvent(event) });
20484
+ return;
19943
20485
  }
20486
+ output.writeHuman(formatLogEvent(event, { includeTimestamps: watcher.includeTimestamps }));
19944
20487
  };
19945
20488
 
19946
20489
  // dist/cli/register/logsCommands.js
@@ -19968,7 +20511,8 @@ var logsCommands = [
19968
20511
  options: [
19969
20512
  ...sharedFilterOptions,
19970
20513
  { flags: "--since <duration>", description: "Filter by time window (e.g. 10m, 2h, 30s)" },
19971
- { flags: "--after <id>", description: "Only return events after this id" },
20514
+ { flags: "--after <cursor>", description: "Only return events after this opaque cursor" },
20515
+ { flags: "--since-epoch <epoch>", description: "Only return events after this opaque epoch" },
19972
20516
  { flags: "--limit <count>", description: "Maximum number of events" },
19973
20517
  { flags: "--json", description: "Output bounded JSON preview for automation" },
19974
20518
  { flags: "--json-full", description: "Output full JSON (can be very large)" }
@@ -19980,13 +20524,34 @@ var logsCommands = [
19980
20524
  await runLogs(id, options);
19981
20525
  },
19982
20526
  subcommands: [
20527
+ {
20528
+ name: "epoch",
20529
+ description: "Return an opaque watcher-session log epoch without downloading events",
20530
+ arguments: [{ flags: "[id]", description: "Watcher id to query" }],
20531
+ options: [{ flags: "--json", description: "Output one JSON document for automation" }],
20532
+ examples: ["argus logs epoch app", "argus logs epoch app --json"],
20533
+ action: async (id, options, command) => {
20534
+ await runLogEpoch(id, command.optsWithGlobals?.() ?? options);
20535
+ }
20536
+ },
20537
+ {
20538
+ name: "cursor",
20539
+ description: "Return the current log cursor without downloading events",
20540
+ arguments: [{ flags: "[id]", description: "Watcher id to query" }],
20541
+ options: [{ flags: "--json", description: "Output one JSON document for automation" }],
20542
+ examples: ["argus logs cursor app", "argus logs cursor app --json"],
20543
+ action: async (id, options, command) => {
20544
+ await runLogCursor(id, command.optsWithGlobals?.() ?? options);
20545
+ }
20546
+ },
19983
20547
  {
19984
20548
  name: "tail",
19985
20549
  description: "Stream logs via long-polling",
19986
20550
  arguments: [{ flags: "[id]", description: "Watcher id to follow" }],
19987
20551
  options: [
19988
20552
  ...sharedFilterOptions,
19989
- { flags: "--after <id>", description: "Start after this event id" },
20553
+ { flags: "--after <cursor>", description: "Start after this opaque cursor" },
20554
+ { flags: "--since-epoch <epoch>", description: "Start after this opaque epoch" },
19990
20555
  { flags: "--limit <count>", description: "Maximum number of events per poll" },
19991
20556
  { flags: "--timeout <ms>", description: "Long-poll timeout in milliseconds" },
19992
20557
  { flags: "--json", description: "Output bounded newline-delimited JSON events" },
@@ -19998,10 +20563,11 @@ var logsCommands = [
19998
20563
  "argus logs tail app --json",
19999
20564
  "argus logs tail app --json-full"
20000
20565
  ],
20001
- action: async (id, options) => {
20002
- if (!validateLogsOptions(options))
20566
+ action: async (id, options, command) => {
20567
+ const resolvedOptions = command.optsWithGlobals?.() ?? options;
20568
+ if (!validateLogsOptions(resolvedOptions))
20003
20569
  return;
20004
- await runTail(id, options);
20570
+ await runTail(id, resolvedOptions);
20005
20571
  }
20006
20572
  }
20007
20573
  ]
@@ -20030,7 +20596,8 @@ var evalOnce = async (input) => {
20030
20596
  awaitPromise: input.awaitPromise,
20031
20597
  replMode: input.replMode,
20032
20598
  returnByValue: input.returnByValue,
20033
- timeoutMs: input.timeoutMs
20599
+ timeoutMs: input.timeoutMs,
20600
+ scenario: input.scenario
20034
20601
  };
20035
20602
  const requestTimeoutMs = input.timeoutMs ? input.timeoutMs + 5000 : DEFAULT_EVAL_REQUEST_TIMEOUT_MS;
20036
20603
  let response;
@@ -20088,7 +20655,8 @@ var evalWithRetries = async (input) => {
20088
20655
  replMode: input.replMode,
20089
20656
  returnByValue: input.returnByValue,
20090
20657
  timeoutMs: input.timeoutMs,
20091
- failOnException: input.failOnException
20658
+ failOnException: input.failOnException,
20659
+ scenario: input.scenario
20092
20660
  });
20093
20661
  if (outcome.ok) {
20094
20662
  return { ...outcome, attempt };
@@ -20309,6 +20877,10 @@ import path13 from "node:path";
20309
20877
  var esbuildModulePromise;
20310
20878
  var loadEsbuild = () => esbuildModulePromise ??= import("esbuild");
20311
20879
  var RESULT_BINDING = "__argusEvalBundleResult";
20880
+ var LEGACY_RESULT_BINDING = "__argusEvalLegacyResult";
20881
+ var LEGACY_RESULT_EXPORT = "__argusLegacyResult";
20882
+ var VIRTUAL_ENTRY = "argus:eval-entry";
20883
+ var VIRTUAL_NAMESPACE = "argus-eval-entry";
20312
20884
  var bundleEvalEntry = async (entryPath) => {
20313
20885
  let entryPoint;
20314
20886
  try {
@@ -20320,7 +20892,7 @@ var bundleEvalEntry = async (entryPath) => {
20320
20892
  const esbuild = await loadEsbuild();
20321
20893
  const result = await esbuild.build({
20322
20894
  absWorkingDir: process.cwd(),
20323
- entryPoints: [entryPoint],
20895
+ entryPoints: [VIRTUAL_ENTRY],
20324
20896
  bundle: true,
20325
20897
  write: false,
20326
20898
  splitting: false,
@@ -20343,6 +20915,12 @@ var bundleEvalEntry = async (entryPath) => {
20343
20915
  var createPageEvalBundlePlugin = (entryPoint) => ({
20344
20916
  name: "argus-eval-bundle",
20345
20917
  setup(build) {
20918
+ build.onResolve({ filter: /^argus:eval-entry$/ }, () => ({ path: VIRTUAL_ENTRY, namespace: VIRTUAL_NAMESPACE }));
20919
+ build.onLoad({ filter: /.*/, namespace: VIRTUAL_NAMESPACE }, () => ({
20920
+ contents: buildVirtualEntrySource(entryPoint),
20921
+ loader: "js",
20922
+ resolveDir: process.cwd()
20923
+ }));
20346
20924
  build.onResolve({ filter: /^node:/ }, (args) => bundleError(`Node built-in import ${JSON.stringify(args.path)} is not allowed in page eval.`));
20347
20925
  build.onLoad({ filter: /.*/ }, async (args) => {
20348
20926
  if (await realpath(args.path) !== entryPoint) {
@@ -20350,7 +20928,7 @@ var createPageEvalBundlePlugin = (entryPoint) => ({
20350
20928
  }
20351
20929
  const source = await readFile3(args.path, "utf8");
20352
20930
  return {
20353
- contents: captureFinalExpression(source),
20931
+ contents: exposeLegacyResult(source),
20354
20932
  loader: loaderForPath(args.path)
20355
20933
  };
20356
20934
  });
@@ -20362,12 +20940,23 @@ var createPageEvalBundlePlugin = (entryPoint) => ({
20362
20940
  if (outputs.length !== 1) {
20363
20941
  return bundleError(`Bundle produced ${outputs.length} outputs; expected exactly one script.`);
20364
20942
  }
20365
- if (/\bexport\b/.test(outputs[0]?.text ?? "")) {
20366
- return bundleError("Bundled script contains top-level export statements, which page eval cannot run. Remove exports from the entry file (helpers may still export symbols for import).");
20367
- }
20368
20943
  });
20369
20944
  }
20370
20945
  });
20946
+ var buildVirtualEntrySource = (entryPoint) => `
20947
+ import * as __argusEntry from ${JSON.stringify(entryPoint)};
20948
+ const __argusDefault = __argusEntry.default;
20949
+ if (__argusDefault !== undefined && typeof __argusDefault !== 'function') {
20950
+ throw new TypeError('The default export of an Argus scenario must be a function');
20951
+ }
20952
+ ${RESULT_BINDING} = typeof __argusDefault === 'function'
20953
+ ? await __argusDefault(__argusScenarioContext)
20954
+ : __argusEntry.${LEGACY_RESULT_EXPORT};
20955
+ `;
20956
+ var exposeLegacyResult = (source) => `let ${LEGACY_RESULT_BINDING};
20957
+ ${captureFinalExpression(source)}
20958
+ export { ${LEGACY_RESULT_BINDING} as ${LEGACY_RESULT_EXPORT} };
20959
+ `;
20371
20960
  var captureFinalExpression = (source) => {
20372
20961
  const lines = source.split(/\r?\n/);
20373
20962
  const index = findFinalCodeLine(lines);
@@ -20380,7 +20969,7 @@ var captureFinalExpression = (source) => {
20380
20969
  return source;
20381
20970
  }
20382
20971
  const indent = line.match(/^\s*/)?.[0] ?? "";
20383
- lines[index] = `${indent}${RESULT_BINDING} = (${expression});`;
20972
+ lines[index] = `${indent}${LEGACY_RESULT_BINDING} = (${expression});`;
20384
20973
  return lines.join(`
20385
20974
  `);
20386
20975
  };
@@ -20393,7 +20982,7 @@ var findFinalCodeLine = (lines) => {
20393
20982
  }
20394
20983
  return null;
20395
20984
  };
20396
- var isStatementLike = (source) => /^(?:import|export|const|let|var|function|class|if|for|while|switch|try|catch|finally|return|throw|break|continue)\b/.test(source);
20985
+ var isStatementLike = (source) => source === "}" || /^(?:[{}]|import|export|const|let|var|function|class|if|for|while|switch|try|catch|finally|return|throw|break|continue)\b/.test(source);
20397
20986
  var loaderForPath = (filePath) => {
20398
20987
  const extension = path13.extname(filePath).toLowerCase();
20399
20988
  if (extension === ".ts")
@@ -20553,14 +21142,15 @@ var prepareEvalExpression = async (inline, options, output) => {
20553
21142
  if (args == null) {
20554
21143
  return null;
20555
21144
  }
20556
- const resolvedExpression = await resolveExpression(inline, options, output);
20557
- if (resolvedExpression == null) {
21145
+ const resolved = await resolveExpressionSource(inline, options, output);
21146
+ if (resolved == null) {
20558
21147
  return null;
20559
21148
  }
20560
21149
  if (!options.iframe) {
20561
21150
  return {
20562
- expression: resolvedExpression,
20563
- args: hasEvalArgs2(args) ? args : undefined
21151
+ expression: resolved.expression,
21152
+ args: hasEvalArgs2(args) ? args : undefined,
21153
+ scenario: resolved.scenario
20564
21154
  };
20565
21155
  }
20566
21156
  const iframeTimeoutMs = parseDurationFlagMs(options.iframeTimeout, "--iframe-timeout");
@@ -20569,14 +21159,15 @@ var prepareEvalExpression = async (inline, options, output) => {
20569
21159
  return null;
20570
21160
  }
20571
21161
  return {
20572
- expression: wrapForIframeEval(wrapExpressionWithArgs(resolvedExpression, args), {
21162
+ expression: wrapForIframeEval(wrapExpressionWithArgs(resolved.expression, args), {
20573
21163
  selector: options.iframe,
20574
21164
  namespace: options.iframeNamespace ?? "argus",
20575
21165
  timeoutMs: iframeTimeoutMs.value ?? 5000
20576
- })
21166
+ }),
21167
+ scenario: resolved.scenario
20577
21168
  };
20578
21169
  };
20579
- var resolveExpression = async (inline, options, output) => {
21170
+ var resolveExpressionSource = async (inline, options, output) => {
20580
21171
  const wantsStdin = options.stdin === true || inline === "-";
20581
21172
  const hasInline = inline != null && inline !== "-";
20582
21173
  const filePath = options.file;
@@ -20598,6 +21189,7 @@ var resolveExpression = async (inline, options, output) => {
20598
21189
  return null;
20599
21190
  }
20600
21191
  let expression;
21192
+ let scenario;
20601
21193
  if (hasFile) {
20602
21194
  const fileContent = await readFileContent(filePath, options.file, output);
20603
21195
  if (fileContent == null) {
@@ -20618,6 +21210,7 @@ var resolveExpression = async (inline, options, output) => {
20618
21210
  return null;
20619
21211
  }
20620
21212
  expression = bundled.code;
21213
+ scenario = true;
20621
21214
  } else {
20622
21215
  expression = fileContent;
20623
21216
  }
@@ -20643,7 +21236,8 @@ var resolveExpression = async (inline, options, output) => {
20643
21236
  output.writeWarn("Expression is required. Provide an inline expression, --file, or --stdin (or pass - as expression).");
20644
21237
  return null;
20645
21238
  }
20646
- return await prependInjectSource(expression, options.inject, output);
21239
+ const injected = await prependInjectSource(expression, options.inject, output);
21240
+ return injected == null ? null : { expression: injected, scenario };
20647
21241
  };
20648
21242
  var resolveBundleDecision = (options, fileContent) => {
20649
21243
  if (options.noBundle) {
@@ -23601,7 +24195,8 @@ var pollEval = async (input) => {
23601
24195
  returnByValue: input.returnByValue,
23602
24196
  timeoutMs: input.timeoutMs,
23603
24197
  failOnException: input.failOnException,
23604
- retryCount: input.retryCount
24198
+ retryCount: input.retryCount,
24199
+ scenario: input.scenario
23605
24200
  });
23606
24201
  if (!result.ok) {
23607
24202
  return { kind: "eval-error", failure: result };
@@ -23694,7 +24289,8 @@ var runEval = async (id, rawExpression, options) => {
23694
24289
  returnByValue: options.returnByValue ?? true,
23695
24290
  timeoutMs: timeoutMs.value,
23696
24291
  failOnException: options.failOnException ?? true,
23697
- retryCount: retryCount.value
24292
+ retryCount: retryCount.value,
24293
+ scenario: prepared.scenario
23698
24294
  });
23699
24295
  if (!singleResult.ok) {
23700
24296
  emitter.emitError(singleResult);
@@ -23713,6 +24309,7 @@ var runEval = async (id, rawExpression, options) => {
23713
24309
  timeoutMs: timeoutMs.value,
23714
24310
  failOnException: options.failOnException ?? true,
23715
24311
  retryCount: retryCount.value,
24312
+ scenario: prepared.scenario,
23716
24313
  intervalMs: intervalMs.value,
23717
24314
  count: countValue.value,
23718
24315
  onResult: async (response) => {
@@ -23826,6 +24423,7 @@ var runEvalUntil = async (id, rawExpression, options) => {
23826
24423
  timeoutMs: timeoutMs.value,
23827
24424
  failOnException: options.failOnException ?? true,
23828
24425
  retryCount: retryCount.value,
24426
+ scenario: prepared.scenario,
23829
24427
  intervalMs: pollIntervalMs,
23830
24428
  count: countValue.value,
23831
24429
  totalTimeoutMs: totalTimeoutMs.value,
@@ -23976,6 +24574,7 @@ var evalCommands = [
23976
24574
  'argus eval app "window.store.getState()" --inject ./debug-hooks.js',
23977
24575
  "argus eval app --file ./script.js --arg level=10 --arg mode=fast",
23978
24576
  "argus eval app --file ./script.js --args ./args.json",
24577
+ "argus eval app --file ./scenario.ts --arg level=10 --json",
23979
24578
  'argus eval app "document.title" --json --out ./result.json',
23980
24579
  'argus eval app "Date.now()" --interval 500 --count 10 --out ./poll.ndjson',
23981
24580
  'argus eval app "Date.now()" --interval 500 --count 10 --out ./frames.json --rotate',
@@ -49994,7 +50593,7 @@ var runExtensionTabs = async (options) => {
49994
50593
  returnErrorResponse: true
49995
50594
  });
49996
50595
  } catch (error) {
49997
- writeCommandError(output, options, `${resolved.watcher.id}: failed to list extension tabs (${formatError4(error)})`, formatError4(error));
50596
+ writeCommandError(output, options, `${resolved.watcher.id}: failed to list extension tabs (${formatError5(error)})`, formatError5(error));
49998
50597
  process.exitCode = 1;
49999
50598
  return;
50000
50599
  }
@@ -50055,7 +50654,7 @@ var writeCommandError = (output, options, humanMessage, jsonPayload) => {
50055
50654
  }
50056
50655
  output.writeWarn(humanMessage);
50057
50656
  };
50058
- var formatError4 = (error) => error instanceof Error ? error.message : String(error);
50657
+ var formatError5 = (error) => error instanceof Error ? error.message : String(error);
50059
50658
 
50060
50659
  // dist/commands/extension/tabSelection.js
50061
50660
  var parseTabSelector = (options, missingReason) => {
@@ -50100,7 +50699,7 @@ var fetchExtensionTabs = async (watcher, selector) => {
50100
50699
  }
50101
50700
  return { ok: true, tabs: response.tabs };
50102
50701
  } catch (error) {
50103
- return { ok: false, error: `${watcher.id}: failed to list extension tabs (${formatError5(error)})` };
50702
+ return { ok: false, error: `${watcher.id}: failed to list extension tabs (${formatError6(error)})` };
50104
50703
  }
50105
50704
  };
50106
50705
  var hasTabSelector = (options) => Boolean(options.tab != null || options.url || options.title);
@@ -50130,7 +50729,7 @@ var buildTabsQuery2 = (selector) => {
50130
50729
  }
50131
50730
  return query;
50132
50731
  };
50133
- var formatError5 = (error) => error instanceof Error ? error.message : String(error);
50732
+ var formatError6 = (error) => error instanceof Error ? error.message : String(error);
50134
50733
 
50135
50734
  // dist/commands/extension/tabAttach.js
50136
50735
  var WATCHER_POLL_TIMEOUT_MS = 5000;
@@ -50149,7 +50748,7 @@ var attachTab = async (controlWatcher, tab, options = {}) => {
50149
50748
  }
50150
50749
  return { ok: true, tab: response.tab, watcherId: response.watcherId };
50151
50750
  } catch (error) {
50152
- return { ok: false, error: `${controlWatcher.id}: failed to attach tab (${formatError6(error)})` };
50751
+ return { ok: false, error: `${controlWatcher.id}: failed to attach tab (${formatError7(error)})` };
50153
50752
  }
50154
50753
  };
50155
50754
  var waitForTabWatcher = async (controlWatcher, selector, tab, watcherId) => {
@@ -50228,7 +50827,7 @@ var targetMatchesTab = (target, tab) => {
50228
50827
  return Boolean(target.title && target.title === tab.title && target.url === tab.url);
50229
50828
  };
50230
50829
  var delay8 = (ms3) => new Promise((resolve2) => setTimeout(resolve2, ms3));
50231
- var formatError6 = (error) => error instanceof Error ? error.message : String(error);
50830
+ var formatError7 = (error) => error instanceof Error ? error.message : String(error);
50232
50831
 
50233
50832
  // dist/commands/extension/show.js
50234
50833
  var runExtensionShow = async (id, options, config = {}) => {
@@ -50304,7 +50903,7 @@ var showWatcher = async (watcher, tab, output, options) => {
50304
50903
  returnErrorResponse: true
50305
50904
  });
50306
50905
  } catch (error) {
50307
- writeFailure(output, options, `${watcher.id}: failed to show page (${formatError7(error)})`, 1);
50906
+ writeFailure(output, options, `${watcher.id}: failed to show page (${formatError8(error)})`, 1);
50308
50907
  return;
50309
50908
  }
50310
50909
  if (!response.ok) {
@@ -50353,7 +50952,7 @@ var writeFailure = (output, options, error, exitCode, extra = {}) => {
50353
50952
  }
50354
50953
  process.exitCode = exitCode;
50355
50954
  };
50356
- var formatError7 = (error) => error instanceof Error ? error.message : String(error);
50955
+ var formatError8 = (error) => error instanceof Error ? error.message : String(error);
50357
50956
 
50358
50957
  // dist/commands/extension/attach.js
50359
50958
  var runExtensionAttach = async (options) => {
@@ -50577,7 +51176,7 @@ var fetchExtensionTargets = async (watcher) => {
50577
51176
  }
50578
51177
  return { ok: true, targets: response.targets };
50579
51178
  } catch (error) {
50580
- return { ok: false, error: `${watcher.id}: failed to list extension targets (${formatError8(error)})` };
51179
+ return { ok: false, error: `${watcher.id}: failed to list extension targets (${formatError9(error)})` };
50581
51180
  }
50582
51181
  };
50583
51182
  var selectExtensionTarget = async (watcher, target) => {
@@ -50594,7 +51193,7 @@ var selectExtensionTarget = async (watcher, target) => {
50594
51193
  }
50595
51194
  return { ok: true, tab: response.tab, watcherId: response.watcherId };
50596
51195
  } catch (error) {
50597
- return { ok: false, error: `${watcher.id}: failed to select target (${formatError8(error)})` };
51196
+ return { ok: false, error: `${watcher.id}: failed to select target (${formatError9(error)})` };
50598
51197
  }
50599
51198
  };
50600
51199
  var waitForSelectedTarget = async (watcher, target, options = {}) => {
@@ -50740,7 +51339,7 @@ var fetchWatcherStatus = async (watcher) => {
50740
51339
  try {
50741
51340
  return { ok: true, status: await fetchWatcherJson(watcher, { path: "/status", timeoutMs: 1000 }) };
50742
51341
  } catch (error) {
50743
- return { ok: false, error: `${watcher.id}: failed to read status (${formatError8(error)})` };
51342
+ return { ok: false, error: `${watcher.id}: failed to read status (${formatError9(error)})` };
50744
51343
  }
50745
51344
  };
50746
51345
  var statusMatchesTarget = (status, target) => {
@@ -50765,7 +51364,7 @@ var originOf = (url) => {
50765
51364
  };
50766
51365
  var shortenId = (id) => id.length > 18 ? `${id.slice(0, 14)}...` : id;
50767
51366
  var delay9 = (ms3) => new Promise((resolve2) => setTimeout(resolve2, ms3));
50768
- var formatError8 = (error) => error instanceof Error ? error.message : String(error);
51367
+ var formatError9 = (error) => error instanceof Error ? error.message : String(error);
50769
51368
 
50770
51369
  // dist/commands/extension/use.js
50771
51370
  var runExtensionUse = async (options) => {
@@ -50937,7 +51536,7 @@ var inspectNativeHostState = () => {
50937
51536
  issues: configured ? [] : ["Native messaging hosts are not fully configured."]
50938
51537
  };
50939
51538
  } catch (error) {
50940
- return { configured: false, hosts: [], issues: [formatError9(error)] };
51539
+ return { configured: false, hosts: [], issues: [formatError10(error)] };
50941
51540
  }
50942
51541
  };
50943
51542
  var fetchExtensionDiagnostics = async (watcher) => {
@@ -50952,7 +51551,7 @@ var fetchExtensionDiagnostics = async (watcher) => {
50952
51551
  }
50953
51552
  return { ok: false, error: response.error.message };
50954
51553
  } catch (error) {
50955
- return { ok: false, error: `${watcher.id}: failed to read extension diagnostics (${formatError9(error)})` };
51554
+ return { ok: false, error: `${watcher.id}: failed to read extension diagnostics (${formatError10(error)})` };
50956
51555
  }
50957
51556
  };
50958
51557
  var inspectWatcher = async (id, diagnostics) => {
@@ -50995,10 +51594,10 @@ var fetchWatcherStatus2 = async (watcher) => {
50995
51594
  try {
50996
51595
  return { ok: true, status: await fetchWatcherJson(watcher, { path: "/status", timeoutMs: 1000 }) };
50997
51596
  } catch (error) {
50998
- return { ok: false, error: `${watcher.id}: failed to read status (${formatError9(error)})` };
51597
+ return { ok: false, error: `${watcher.id}: failed to read status (${formatError10(error)})` };
50999
51598
  }
51000
51599
  };
51001
- var formatError9 = (error) => error instanceof Error ? error.message : String(error);
51600
+ var formatError10 = (error) => error instanceof Error ? error.message : String(error);
51002
51601
 
51003
51602
  // dist/commands/extension/targets.js
51004
51603
  var runExtensionTargets = async (id, options) => {
@@ -51462,6 +52061,7 @@ var coreCommandDefinitions = [
51462
52061
  var coreProgramRegistrars = [(program2) => defineCommands(program2, coreCommandDefinitions)];
51463
52062
 
51464
52063
  // dist/bin.js
52064
+ configureMachineSafeConsole(process.argv.slice(2));
51465
52065
  var program2 = createProgram();
51466
52066
  for (const registerProgramPart of coreProgramRegistrars) {
51467
52067
  registerProgramPart(program2);