@agentmonitors/cli 0.4.0 → 0.5.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.
package/dist/index.cjs CHANGED
@@ -1218,7 +1218,7 @@ var require_command = __commonJS({
1218
1218
  init_cjs_shims();
1219
1219
  var EventEmitter2 = require("events").EventEmitter;
1220
1220
  var childProcess = require("child_process");
1221
- var path12 = require("path");
1221
+ var path13 = require("path");
1222
1222
  var fs = require("fs");
1223
1223
  var process3 = require("process");
1224
1224
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2231,9 +2231,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2231
2231
  let launchWithNode = false;
2232
2232
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2233
2233
  function findFile(baseDir, baseName) {
2234
- const localBin = path12.resolve(baseDir, baseName);
2234
+ const localBin = path13.resolve(baseDir, baseName);
2235
2235
  if (fs.existsSync(localBin)) return localBin;
2236
- if (sourceExt.includes(path12.extname(baseName))) return void 0;
2236
+ if (sourceExt.includes(path13.extname(baseName))) return void 0;
2237
2237
  const foundExt = sourceExt.find(
2238
2238
  (ext2) => fs.existsSync(`${localBin}${ext2}`)
2239
2239
  );
@@ -2251,17 +2251,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2251
2251
  } catch {
2252
2252
  resolvedScriptPath = this._scriptPath;
2253
2253
  }
2254
- executableDir = path12.resolve(
2255
- path12.dirname(resolvedScriptPath),
2254
+ executableDir = path13.resolve(
2255
+ path13.dirname(resolvedScriptPath),
2256
2256
  executableDir
2257
2257
  );
2258
2258
  }
2259
2259
  if (executableDir) {
2260
2260
  let localFile = findFile(executableDir, executableFile);
2261
2261
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2262
- const legacyName = path12.basename(
2262
+ const legacyName = path13.basename(
2263
2263
  this._scriptPath,
2264
- path12.extname(this._scriptPath)
2264
+ path13.extname(this._scriptPath)
2265
2265
  );
2266
2266
  if (legacyName !== this._name) {
2267
2267
  localFile = findFile(
@@ -2272,7 +2272,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2272
2272
  }
2273
2273
  executableFile = localFile || executableFile;
2274
2274
  }
2275
- launchWithNode = sourceExt.includes(path12.extname(executableFile));
2275
+ launchWithNode = sourceExt.includes(path13.extname(executableFile));
2276
2276
  let proc2;
2277
2277
  if (process3.platform !== "win32") {
2278
2278
  if (launchWithNode) {
@@ -3187,7 +3187,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3187
3187
  * @return {Command}
3188
3188
  */
3189
3189
  nameFromFilename(filename) {
3190
- this._name = path12.basename(filename, path12.extname(filename));
3190
+ this._name = path13.basename(filename, path13.extname(filename));
3191
3191
  return this;
3192
3192
  }
3193
3193
  /**
@@ -3201,9 +3201,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3201
3201
  * @param {string} [path]
3202
3202
  * @return {(string|null|Command)}
3203
3203
  */
3204
- executableDir(path13) {
3205
- if (path13 === void 0) return this._executableDir;
3206
- this._executableDir = path13;
3204
+ executableDir(path14) {
3205
+ if (path14 === void 0) return this._executableDir;
3206
+ this._executableDir = path14;
3207
3207
  return this;
3208
3208
  }
3209
3209
  /**
@@ -10226,8 +10226,8 @@ var require_utils2 = __commonJS({
10226
10226
  }
10227
10227
  return ind;
10228
10228
  }
10229
- function removeDotSegments(path12) {
10230
- let input = path12;
10229
+ function removeDotSegments(path13) {
10230
+ let input = path13;
10231
10231
  const output = [];
10232
10232
  let nextSlash = -1;
10233
10233
  let len = 0;
@@ -10427,8 +10427,8 @@ var require_schemes = __commonJS({
10427
10427
  wsComponent.secure = void 0;
10428
10428
  }
10429
10429
  if (wsComponent.resourceName) {
10430
- const [path12, query] = wsComponent.resourceName.split("?");
10431
- wsComponent.path = path12 && path12 !== "/" ? path12 : void 0;
10430
+ const [path13, query] = wsComponent.resourceName.split("?");
10431
+ wsComponent.path = path13 && path13 !== "/" ? path13 : void 0;
10432
10432
  wsComponent.query = query;
10433
10433
  wsComponent.resourceName = void 0;
10434
10434
  }
@@ -13851,8 +13851,8 @@ var require_dist = __commonJS({
13851
13851
 
13852
13852
  // src/index.ts
13853
13853
  init_cjs_shims();
13854
- var import_node_fs6 = require("fs");
13855
- var import_node_path9 = require("path");
13854
+ var import_node_fs7 = require("fs");
13855
+ var import_node_path10 = require("path");
13856
13856
  var import_node_url4 = require("url");
13857
13857
 
13858
13858
  // ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
@@ -13971,6 +13971,7 @@ Edit the file to configure your monitor, then run:`);
13971
13971
 
13972
13972
  // src/commands/validate.ts
13973
13973
  init_cjs_shims();
13974
+ var import_node_fs3 = require("fs");
13974
13975
 
13975
13976
  // ../../libs/core/dist/index.js
13976
13977
  init_cjs_shims();
@@ -14468,8 +14469,8 @@ function getErrorMap() {
14468
14469
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
14469
14470
  init_cjs_shims();
14470
14471
  var makeIssue = (params) => {
14471
- const { data, path: path12, errorMaps, issueData } = params;
14472
- const fullPath = [...path12, ...issueData.path || []];
14472
+ const { data, path: path13, errorMaps, issueData } = params;
14473
+ const fullPath = [...path13, ...issueData.path || []];
14473
14474
  const fullIssue = {
14474
14475
  ...issueData,
14475
14476
  path: fullPath
@@ -14589,11 +14590,11 @@ var errorUtil;
14589
14590
 
14590
14591
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
14591
14592
  var ParseInputLazyPath = class {
14592
- constructor(parent, value, path12, key) {
14593
+ constructor(parent, value, path13, key) {
14593
14594
  this._cachedPath = [];
14594
14595
  this.parent = parent;
14595
14596
  this.data = value;
14596
- this._path = path12;
14597
+ this._path = path13;
14597
14598
  this._key = key;
14598
14599
  }
14599
14600
  get path() {
@@ -22659,12 +22660,12 @@ var PathBase = class {
22659
22660
  /**
22660
22661
  * Get the Path object referenced by the string path, resolved from this Path
22661
22662
  */
22662
- resolve(path12) {
22663
- if (!path12) {
22663
+ resolve(path13) {
22664
+ if (!path13) {
22664
22665
  return this;
22665
22666
  }
22666
- const rootPath = this.getRootString(path12);
22667
- const dir = path12.substring(rootPath.length);
22667
+ const rootPath = this.getRootString(path13);
22668
+ const dir = path13.substring(rootPath.length);
22668
22669
  const dirParts = dir.split(this.splitSep);
22669
22670
  const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
22670
22671
  return result;
@@ -23416,8 +23417,8 @@ var PathWin32 = class _PathWin32 extends PathBase {
23416
23417
  /**
23417
23418
  * @internal
23418
23419
  */
23419
- getRootString(path12) {
23420
- return import_node_path2.win32.parse(path12).root;
23420
+ getRootString(path13) {
23421
+ return import_node_path2.win32.parse(path13).root;
23421
23422
  }
23422
23423
  /**
23423
23424
  * @internal
@@ -23463,8 +23464,8 @@ var PathPosix = class _PathPosix extends PathBase {
23463
23464
  /**
23464
23465
  * @internal
23465
23466
  */
23466
- getRootString(path12) {
23467
- return path12.startsWith("/") ? "/" : "";
23467
+ getRootString(path13) {
23468
+ return path13.startsWith("/") ? "/" : "";
23468
23469
  }
23469
23470
  /**
23470
23471
  * @internal
@@ -23553,11 +23554,11 @@ var PathScurryBase = class {
23553
23554
  /**
23554
23555
  * Get the depth of a provided path, string, or the cwd
23555
23556
  */
23556
- depth(path12 = this.cwd) {
23557
- if (typeof path12 === "string") {
23558
- path12 = this.cwd.resolve(path12);
23557
+ depth(path13 = this.cwd) {
23558
+ if (typeof path13 === "string") {
23559
+ path13 = this.cwd.resolve(path13);
23559
23560
  }
23560
- return path12.depth();
23561
+ return path13.depth();
23561
23562
  }
23562
23563
  /**
23563
23564
  * Return the cache of child entries. Exposed so subclasses can create
@@ -24044,9 +24045,9 @@ var PathScurryBase = class {
24044
24045
  process3();
24045
24046
  return results;
24046
24047
  }
24047
- chdir(path12 = this.cwd) {
24048
+ chdir(path13 = this.cwd) {
24048
24049
  const oldCwd = this.cwd;
24049
- this.cwd = typeof path12 === "string" ? this.cwd.resolve(path12) : path12;
24050
+ this.cwd = typeof path13 === "string" ? this.cwd.resolve(path13) : path13;
24050
24051
  this.cwd[setAsCwd](oldCwd);
24051
24052
  }
24052
24053
  };
@@ -24408,8 +24409,8 @@ var MatchRecord = class {
24408
24409
  }
24409
24410
  // match, absolute, ifdir
24410
24411
  entries() {
24411
- return [...this.store.entries()].map(([path12, n]) => [
24412
- path12,
24412
+ return [...this.store.entries()].map(([path13, n]) => [
24413
+ path13,
24413
24414
  !!(n & 2),
24414
24415
  !!(n & 1)
24415
24416
  ]);
@@ -24614,9 +24615,9 @@ var GlobUtil = class {
24614
24615
  signal;
24615
24616
  maxDepth;
24616
24617
  includeChildMatches;
24617
- constructor(patterns, path12, opts) {
24618
+ constructor(patterns, path13, opts) {
24618
24619
  this.patterns = patterns;
24619
- this.path = path12;
24620
+ this.path = path13;
24620
24621
  this.opts = opts;
24621
24622
  this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
24622
24623
  this.includeChildMatches = opts.includeChildMatches !== false;
@@ -24635,11 +24636,11 @@ var GlobUtil = class {
24635
24636
  });
24636
24637
  }
24637
24638
  }
24638
- #ignored(path12) {
24639
- return this.seen.has(path12) || !!this.#ignore?.ignored?.(path12);
24639
+ #ignored(path13) {
24640
+ return this.seen.has(path13) || !!this.#ignore?.ignored?.(path13);
24640
24641
  }
24641
- #childrenIgnored(path12) {
24642
- return !!this.#ignore?.childrenIgnored?.(path12);
24642
+ #childrenIgnored(path13) {
24643
+ return !!this.#ignore?.childrenIgnored?.(path13);
24643
24644
  }
24644
24645
  // backpressure mechanism
24645
24646
  pause() {
@@ -24854,8 +24855,8 @@ var GlobUtil = class {
24854
24855
  };
24855
24856
  var GlobWalker = class extends GlobUtil {
24856
24857
  matches = /* @__PURE__ */ new Set();
24857
- constructor(patterns, path12, opts) {
24858
- super(patterns, path12, opts);
24858
+ constructor(patterns, path13, opts) {
24859
+ super(patterns, path13, opts);
24859
24860
  }
24860
24861
  matchEmit(e) {
24861
24862
  this.matches.add(e);
@@ -24892,8 +24893,8 @@ var GlobWalker = class extends GlobUtil {
24892
24893
  };
24893
24894
  var GlobStream = class extends GlobUtil {
24894
24895
  results;
24895
- constructor(patterns, path12, opts) {
24896
- super(patterns, path12, opts);
24896
+ constructor(patterns, path13, opts) {
24897
+ super(patterns, path13, opts);
24897
24898
  this.results = new Minipass({
24898
24899
  signal: this.signal,
24899
24900
  objectMode: true
@@ -26401,7 +26402,7 @@ Subquery.prototype.getSQL = function() {
26401
26402
  function mapResultRow(columns, row, joinsNotNullableMap) {
26402
26403
  const nullifyMap = {};
26403
26404
  const result = columns.reduce(
26404
- (result2, { path: path12, field }, columnIndex) => {
26405
+ (result2, { path: path13, field }, columnIndex) => {
26405
26406
  let decoder;
26406
26407
  if (is(field, Column)) {
26407
26408
  decoder = field;
@@ -26413,8 +26414,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
26413
26414
  decoder = field.sql.decoder;
26414
26415
  }
26415
26416
  let node = result2;
26416
- for (const [pathChunkIndex, pathChunk] of path12.entries()) {
26417
- if (pathChunkIndex < path12.length - 1) {
26417
+ for (const [pathChunkIndex, pathChunk] of path13.entries()) {
26418
+ if (pathChunkIndex < path13.length - 1) {
26418
26419
  if (!(pathChunk in node)) {
26419
26420
  node[pathChunk] = {};
26420
26421
  }
@@ -26422,8 +26423,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
26422
26423
  } else {
26423
26424
  const rawValue = row[columnIndex];
26424
26425
  const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
26425
- if (joinsNotNullableMap && is(field, Column) && path12.length === 2) {
26426
- const objectName = path12[0];
26426
+ if (joinsNotNullableMap && is(field, Column) && path13.length === 2) {
26427
+ const objectName = path13[0];
26427
26428
  if (!(objectName in nullifyMap)) {
26428
26429
  nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
26429
26430
  } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
@@ -31375,14 +31376,19 @@ function assertValidSegment(path72, segment) {
31375
31376
  );
31376
31377
  }
31377
31378
  }
31378
- function resolveDottedPath(root, path72) {
31379
- if (path72 === "$") return root;
31380
- if (!path72.startsWith("$.")) {
31379
+ function normalizeDottedPath(path72) {
31380
+ if (path72 === "$" || path72.startsWith("$.")) return path72;
31381
+ if (path72.startsWith("$")) {
31381
31382
  throw new Error(
31382
- `Invalid collection path "${path72}": must start with "$." (e.g. "$.tasks")`
31383
+ `Invalid collection path "${path72}": a path beginning with "$" must be explicit-root form ("$" or "$.field"). Write "${path72.slice(1)}" for a bare root-relative path, or "$.${path72.slice(1)}" for explicit-root form.`
31383
31384
  );
31384
31385
  }
31385
- const segments = path72.slice(2).split(".");
31386
+ return `$.${path72}`;
31387
+ }
31388
+ function resolveDottedPath(root, path72) {
31389
+ const normalizedPath = normalizeDottedPath(path72);
31390
+ if (normalizedPath === "$") return root;
31391
+ const segments = normalizedPath.slice(2).split(".");
31386
31392
  let current = root;
31387
31393
  for (const segment of segments) {
31388
31394
  if (segment.length === 0) {
@@ -31397,13 +31403,9 @@ function resolveDottedPath(root, path72) {
31397
31403
  return current;
31398
31404
  }
31399
31405
  function removeDottedPath(value, path72) {
31400
- if (path72 === "$") return;
31401
- if (!path72.startsWith("$.")) {
31402
- throw new Error(
31403
- `Invalid ignore-paths entry "${path72}": must start with "$." (e.g. "$.fetchedAt")`
31404
- );
31405
- }
31406
- const segments = path72.slice(2).split(".");
31406
+ const normalizedPath = normalizeDottedPath(path72);
31407
+ if (normalizedPath === "$") return;
31408
+ const segments = normalizedPath.slice(2).split(".");
31407
31409
  let current = value;
31408
31410
  for (let i = 0; i < segments.length - 1; i++) {
31409
31411
  const segment = segments[i];
@@ -31677,6 +31679,11 @@ function rowToEvent(row) {
31677
31679
  createdAt: row.createdAt
31678
31680
  };
31679
31681
  }
31682
+ function deliveryStateForRow(row) {
31683
+ if (row.acknowledgedAt) return "acknowledged";
31684
+ if (row.firstNotifiedAt) return "claimed";
31685
+ return "unread";
31686
+ }
31680
31687
  function scopeMatches(eventScope, requested) {
31681
31688
  if (!requested) return true;
31682
31689
  for (const [key, value] of Object.entries(requested)) {
@@ -31844,6 +31851,13 @@ var RuntimeStore = class {
31844
31851
  if (query.objectKey)
31845
31852
  conditions.push(eq(monitorEvents.objectKey, query.objectKey));
31846
31853
  if (query.since) conditions.push(gt(monitorEvents.createdAt, query.since));
31854
+ if (query.workspacePath !== void 0) {
31855
+ const workspaceCondition = or(
31856
+ eq(monitorEvents.workspacePath, query.workspacePath),
31857
+ isNull(monitorEvents.workspacePath)
31858
+ );
31859
+ if (workspaceCondition) conditions.push(workspaceCondition);
31860
+ }
31847
31861
  let rows = query.sessionId ? asInternalDb2(this.db).select({
31848
31862
  event: monitorEvents,
31849
31863
  state: sessionEventState
@@ -31918,6 +31932,37 @@ var RuntimeStore = class {
31918
31932
  createdAt: row.createdAt
31919
31933
  }));
31920
31934
  }
31935
+ listDeliveryProjectionsForMonitor(monitorId, workspacePath) {
31936
+ const conditions = [eq(monitorEvents.monitorId, monitorId)];
31937
+ if (workspacePath !== void 0) {
31938
+ const workspaceCondition = or(
31939
+ eq(agentSessions.workspacePath, workspacePath),
31940
+ isNull(agentSessions.workspacePath)
31941
+ );
31942
+ if (workspaceCondition) conditions.push(workspaceCondition);
31943
+ }
31944
+ const rows = asInternalDb2(this.db).select({
31945
+ event: monitorEvents,
31946
+ state: sessionEventState,
31947
+ session: agentSessions
31948
+ }).from(sessionEventState).innerJoin(monitorEvents, eq(sessionEventState.eventId, monitorEvents.id)).innerJoin(
31949
+ agentSessions,
31950
+ eq(sessionEventState.sessionId, agentSessions.id)
31951
+ ).where(and(...conditions)).orderBy(desc(monitorEvents.createdAt)).all();
31952
+ return rows.map(({ event, state, session }) => ({
31953
+ eventId: event.id,
31954
+ sessionId: session.id,
31955
+ sessionRole: session.role,
31956
+ sessionStatus: session.status,
31957
+ deliveryState: deliveryStateForRow(state),
31958
+ workspacePath: session.workspacePath ?? null,
31959
+ createdAt: state.createdAt,
31960
+ ...state.firstNotifiedAt ? { firstNotifiedAt: state.firstNotifiedAt } : {},
31961
+ ...state.lastClaimAt ? { lastClaimAt: state.lastClaimAt } : {},
31962
+ ...state.lastClaimLifecycle ? { lastClaimLifecycle: state.lastClaimLifecycle } : {},
31963
+ ...state.acknowledgedAt ? { acknowledgedAt: state.acknowledgedAt } : {}
31964
+ }));
31965
+ }
31921
31966
  sessionsForWorkspace(workspacePath) {
31922
31967
  return asInternalDb2(this.db).select().from(agentSessions).where(
31923
31968
  workspacePath == null ? isNull(agentSessions.workspacePath) : or(
@@ -32025,6 +32070,14 @@ var DEFAULT_FILE_FINGERPRINT_POLL_MS = 3e4;
32025
32070
  var DEFAULT_API_POLL_MS = 3e5;
32026
32071
  var DEFAULT_HIGH_URGENCY_SETTLE_MS = 15e3;
32027
32072
  var MAX_RECAP_EVENTS = 10;
32073
+ var EXPLAIN_STAGE_LABELS = {
32074
+ definition: "Definition",
32075
+ scheduling: "Scheduling",
32076
+ observation: "Observation",
32077
+ notify: "Notify state",
32078
+ materialization: "Materialization",
32079
+ delivery: "Projection and delivery"
32080
+ };
32028
32081
  function watchConfig(watch) {
32029
32082
  const { type: _type, ...config2 } = watch;
32030
32083
  return config2;
@@ -32043,6 +32096,28 @@ function writeJsonAtomic(filePath2, payload) {
32043
32096
  (0, import_fs3.writeFileSync)(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
32044
32097
  (0, import_fs3.renameSync)(tmpPath, filePath2);
32045
32098
  }
32099
+ function monitorIdFromFilePath(filePath2) {
32100
+ const base = import_path4.default.basename(filePath2);
32101
+ return base === "MONITOR.md" ? import_path4.default.basename(import_path4.default.dirname(filePath2)) : import_path4.default.parse(filePath2).name;
32102
+ }
32103
+ function explainStage(id, status, reason, details) {
32104
+ return {
32105
+ id,
32106
+ label: EXPLAIN_STAGE_LABELS[id],
32107
+ status,
32108
+ reason,
32109
+ ...details ? { details } : {}
32110
+ };
32111
+ }
32112
+ function explainVerdict(stages) {
32113
+ const stopped = stages.find((stage2) => stage2.status !== "ok");
32114
+ const stage = stopped ?? stages[stages.length - 1];
32115
+ return {
32116
+ status: stage?.status ?? "ok",
32117
+ stage: stage?.id ?? "delivery",
32118
+ reason: stage?.reason ?? "Monitor delivered successfully."
32119
+ };
32120
+ }
32046
32121
  function serializeObservation(monitor, observation, observedAt) {
32047
32122
  return { monitor, observation, observedAt };
32048
32123
  }
@@ -32157,6 +32232,320 @@ var AgentMonitorRuntime = class {
32157
32232
  listObservationHistory(query = {}) {
32158
32233
  return this.store.listObservationHistory(query);
32159
32234
  }
32235
+ async explainMonitor(input) {
32236
+ const now = input.now ?? /* @__PURE__ */ new Date();
32237
+ const historyLimit = input.historyLimit ?? 10;
32238
+ const eventLimit = input.eventLimit ?? 10;
32239
+ const stages = [];
32240
+ const scan = await scanMonitors(input.monitorsDir);
32241
+ const parseError = scan.errors.find(
32242
+ (error2) => monitorIdFromFilePath(error2.filePath) === input.monitorId
32243
+ );
32244
+ const monitor = scan.monitors.find(
32245
+ (candidate) => candidate.monitor.id === input.monitorId
32246
+ )?.monitor;
32247
+ const duplicate = scan.duplicateIds.find(
32248
+ (candidate) => candidate.id === input.monitorId
32249
+ );
32250
+ if (parseError) {
32251
+ stages.push(
32252
+ explainStage(
32253
+ "definition",
32254
+ "failure",
32255
+ `MONITOR.md failed to parse or validate: ${parseError.error}`,
32256
+ { filePath: parseError.filePath }
32257
+ )
32258
+ );
32259
+ return {
32260
+ monitorId: input.monitorId,
32261
+ generatedAt: now,
32262
+ stages,
32263
+ verdict: explainVerdict(stages),
32264
+ observations: [],
32265
+ events: [],
32266
+ projections: [],
32267
+ leadSessions: []
32268
+ };
32269
+ }
32270
+ if (!monitor) {
32271
+ stages.push(
32272
+ explainStage(
32273
+ "definition",
32274
+ "failure",
32275
+ `Monitor "${input.monitorId}" was not found in ${input.monitorsDir}.`
32276
+ )
32277
+ );
32278
+ return {
32279
+ monitorId: input.monitorId,
32280
+ generatedAt: now,
32281
+ stages,
32282
+ verdict: explainVerdict(stages),
32283
+ observations: [],
32284
+ events: [],
32285
+ projections: [],
32286
+ leadSessions: []
32287
+ };
32288
+ }
32289
+ if (duplicate) {
32290
+ stages.push(
32291
+ explainStage(
32292
+ "definition",
32293
+ "failure",
32294
+ `Monitor id "${input.monitorId}" is duplicated across ${String(duplicate.filePaths.length)} files.`,
32295
+ { filePaths: duplicate.filePaths }
32296
+ )
32297
+ );
32298
+ return {
32299
+ monitorId: input.monitorId,
32300
+ generatedAt: now,
32301
+ monitor: {
32302
+ id: monitor.id,
32303
+ displayName: monitor.displayName,
32304
+ filePath: monitor.filePath,
32305
+ sourceName: monitor.frontmatter.watch.type,
32306
+ urgency: monitor.frontmatter.urgency
32307
+ },
32308
+ stages,
32309
+ verdict: explainVerdict(stages),
32310
+ observations: [],
32311
+ events: [],
32312
+ projections: [],
32313
+ leadSessions: []
32314
+ };
32315
+ }
32316
+ const sourceName = monitor.frontmatter.watch.type;
32317
+ const source6 = this.registry.get(sourceName);
32318
+ const scopeErrors = source6 ? validateScope(
32319
+ watchConfig(monitor.frontmatter.watch),
32320
+ source6.scopeSchema
32321
+ ) : [`Unknown source "${sourceName}".`];
32322
+ if (scopeErrors.length > 0) {
32323
+ stages.push(
32324
+ explainStage(
32325
+ "definition",
32326
+ "failure",
32327
+ `Monitor definition is invalid: ${scopeErrors.join("; ")}`,
32328
+ { filePath: monitor.filePath, sourceName }
32329
+ )
32330
+ );
32331
+ return {
32332
+ monitorId: input.monitorId,
32333
+ generatedAt: now,
32334
+ monitor: {
32335
+ id: monitor.id,
32336
+ displayName: monitor.displayName,
32337
+ filePath: monitor.filePath,
32338
+ sourceName,
32339
+ urgency: monitor.frontmatter.urgency
32340
+ },
32341
+ stages,
32342
+ verdict: explainVerdict(stages),
32343
+ observations: [],
32344
+ events: [],
32345
+ projections: [],
32346
+ leadSessions: []
32347
+ };
32348
+ }
32349
+ stages.push(
32350
+ explainStage("definition", "ok", "Monitor definition is valid.", {
32351
+ filePath: monitor.filePath,
32352
+ sourceName
32353
+ })
32354
+ );
32355
+ const runtimeState = this.store.getMonitorState(input.monitorId);
32356
+ const schedule = this.scheduleForMonitor(monitor, now);
32357
+ const lastObservationAt = runtimeState.lastObservationAt;
32358
+ const nextDueAt = schedule.due ? now : new Date(
32359
+ (lastObservationAt?.getTime() ?? now.getTime()) + schedule.nextPollMs
32360
+ );
32361
+ stages.push(
32362
+ explainStage(
32363
+ "scheduling",
32364
+ "ok",
32365
+ lastObservationAt ? `Last tick completed at ${lastObservationAt.toISOString()}; next due ${schedule.due ? "now" : nextDueAt.toISOString()}.` : "No completed tick is recorded yet; the monitor is due on the next daemon tick.",
32366
+ {
32367
+ due: schedule.due,
32368
+ nextPollMs: schedule.nextPollMs,
32369
+ nextDueAt: nextDueAt.toISOString(),
32370
+ ...lastObservationAt ? { lastObservationAt: lastObservationAt.toISOString() } : {}
32371
+ }
32372
+ )
32373
+ );
32374
+ const observations = this.store.listObservationHistory({
32375
+ monitorId: input.monitorId,
32376
+ limit: historyLimit
32377
+ });
32378
+ const latestObservation = observations[0];
32379
+ if (!latestObservation) {
32380
+ stages.push(
32381
+ explainStage(
32382
+ "observation",
32383
+ "failure",
32384
+ "No observation history has been recorded for this monitor."
32385
+ )
32386
+ );
32387
+ } else if (latestObservation.result === "errored") {
32388
+ stages.push(
32389
+ explainStage(
32390
+ "observation",
32391
+ "failure",
32392
+ "The most recent source observation errored.",
32393
+ latestObservation.observationData
32394
+ )
32395
+ );
32396
+ } else if (latestObservation.result === "no-change") {
32397
+ stages.push(
32398
+ explainStage(
32399
+ "observation",
32400
+ "healthy",
32401
+ "Source ran, observed 0 changes \u2014 your watched target genuinely hasn\u2019t changed (not a bug).",
32402
+ latestObservation.observationData
32403
+ )
32404
+ );
32405
+ } else if (latestObservation.result === "rebaselined") {
32406
+ stages.push(
32407
+ explainStage(
32408
+ "observation",
32409
+ "healthy",
32410
+ "Source rebaselined and emitted no change \u2014 your watched target is being tracked, nothing to report (not a bug).",
32411
+ latestObservation.observationData
32412
+ )
32413
+ );
32414
+ } else {
32415
+ stages.push(
32416
+ explainStage(
32417
+ "observation",
32418
+ "ok",
32419
+ `The latest observation outcome was ${latestObservation.result}.`,
32420
+ latestObservation.observationData
32421
+ )
32422
+ );
32423
+ }
32424
+ const observationHealthy = latestObservation?.result === "no-change" || latestObservation?.result === "rebaselined";
32425
+ const notifyState = runtimeState.notifyState;
32426
+ const pendingDebounce = notifyState.pendingDebounce;
32427
+ const suppressedUntil = notifyState.suppressedUntil ? new Date(notifyState.suppressedUntil) : null;
32428
+ if (pendingDebounce && new Date(pendingDebounce.dueAt) > now) {
32429
+ stages.push(
32430
+ explainStage(
32431
+ "notify",
32432
+ "pending",
32433
+ `debounce is holding ${String(pendingDebounce.observations.length)} observation(s) until ${pendingDebounce.dueAt}.`,
32434
+ {
32435
+ dueAt: pendingDebounce.dueAt,
32436
+ observations: pendingDebounce.observations.length
32437
+ }
32438
+ )
32439
+ );
32440
+ } else if (suppressedUntil && suppressedUntil > now) {
32441
+ stages.push(
32442
+ explainStage(
32443
+ "notify",
32444
+ "pending",
32445
+ `throttle is suppressing new notifications until ${suppressedUntil.toISOString()}.`,
32446
+ { suppressedUntil: suppressedUntil.toISOString() }
32447
+ )
32448
+ );
32449
+ } else {
32450
+ stages.push(
32451
+ explainStage(
32452
+ "notify",
32453
+ "ok",
32454
+ "No debounce or throttle hold is currently active."
32455
+ )
32456
+ );
32457
+ }
32458
+ const events = this.store.listEvents({
32459
+ monitorId: input.monitorId,
32460
+ // Scope to the explained workspace so a same-id monitor in another
32461
+ // workspace cannot leak its events into this report (issue #94 review).
32462
+ ...input.workspacePath !== void 0 ? { workspacePath: input.workspacePath } : {}
32463
+ }).slice(0, eventLimit);
32464
+ if (events.length === 0) {
32465
+ stages.push(
32466
+ observationHealthy ? explainStage(
32467
+ "materialization",
32468
+ "healthy",
32469
+ "No events materialized \u2014 expected, because the source observed no changes (not a bug)."
32470
+ ) : explainStage(
32471
+ "materialization",
32472
+ "failure",
32473
+ "No monitor_events rows exist for this monitor."
32474
+ )
32475
+ );
32476
+ } else {
32477
+ stages.push(
32478
+ explainStage(
32479
+ "materialization",
32480
+ "ok",
32481
+ `${String(events.length)} recent monitor_events row(s) found.`,
32482
+ { eventIds: events.map((event) => event.id) }
32483
+ )
32484
+ );
32485
+ }
32486
+ const projections = this.store.listDeliveryProjectionsForMonitor(
32487
+ input.monitorId,
32488
+ // Scope to the explained workspace's sessions (plus global sessions) so
32489
+ // projections from other workspaces are not overcounted (issue #94 review).
32490
+ input.workspacePath
32491
+ );
32492
+ const leadSessions = this.store.sessionsForWorkspace(input.workspacePath).filter((session) => session.role === "lead");
32493
+ if (events.length > 0 && projections.length === 0) {
32494
+ stages.push(
32495
+ explainStage(
32496
+ "delivery",
32497
+ "failure",
32498
+ leadSessions.length === 0 ? "No lead session is registered for this workspace, so events were not projected." : "No session_event_state projections exist for the materialized events.",
32499
+ { leadSessions: leadSessions.map((session) => session.id) }
32500
+ )
32501
+ );
32502
+ } else if (events.length > 0) {
32503
+ const counts = projections.reduce(
32504
+ (acc, projection) => {
32505
+ acc[projection.deliveryState] = (acc[projection.deliveryState] ?? 0) + 1;
32506
+ return acc;
32507
+ },
32508
+ {}
32509
+ );
32510
+ stages.push(
32511
+ explainStage(
32512
+ "delivery",
32513
+ "ok",
32514
+ `Events are projected to lead sessions (${Object.entries(counts).map(([state, count]) => `${state}: ${String(count)}`).join(", ")}).`,
32515
+ counts
32516
+ )
32517
+ );
32518
+ } else {
32519
+ stages.push(
32520
+ observationHealthy ? explainStage(
32521
+ "delivery",
32522
+ "healthy",
32523
+ "Nothing to deliver \u2014 the source observed no changes, so there is no signal to project (not a bug)."
32524
+ ) : explainStage(
32525
+ "delivery",
32526
+ "pending",
32527
+ "Delivery has not started because no event has materialized yet."
32528
+ )
32529
+ );
32530
+ }
32531
+ return {
32532
+ monitorId: input.monitorId,
32533
+ generatedAt: now,
32534
+ monitor: {
32535
+ id: monitor.id,
32536
+ displayName: monitor.displayName,
32537
+ filePath: monitor.filePath,
32538
+ sourceName,
32539
+ urgency: monitor.frontmatter.urgency
32540
+ },
32541
+ stages,
32542
+ verdict: explainVerdict(stages),
32543
+ observations,
32544
+ events,
32545
+ projections,
32546
+ leadSessions
32547
+ };
32548
+ }
32160
32549
  acknowledgeSession(sessionId, eventIds) {
32161
32550
  const ids = eventIds ?? this.store.unreadEventsForSession(sessionId).map((e) => e.id);
32162
32551
  this.store.acknowledgeEvents(sessionId, ids);
@@ -32969,7 +33358,7 @@ var scopeSchema2 = {
32969
33358
  properties: {
32970
33359
  path: {
32971
33360
  type: "string",
32972
- description: 'Dotted $.-path to the array within the parsed JSON (e.g. "$.tasks")'
33361
+ description: 'Dotted path to the array within the parsed JSON (e.g. "tasks" or "$.tasks")'
32973
33362
  },
32974
33363
  key: {
32975
33364
  type: "string",
@@ -32978,7 +33367,7 @@ var scopeSchema2 = {
32978
33367
  "ignore-paths": {
32979
33368
  type: "array",
32980
33369
  items: { type: "string" },
32981
- description: "Dotted $.-paths (relative to each element) removed before comparison"
33370
+ description: 'Dotted paths (relative to each element, e.g. "fetchedAt" or "$.fetchedAt") removed before comparison'
32982
33371
  }
32983
33372
  },
32984
33373
  required: ["path", "key"]
@@ -33076,6 +33465,12 @@ function parseScopeConfig3(config2) {
33076
33465
  const cd = config2["change-detection"];
33077
33466
  const rawStrategy = cd?.strategy;
33078
33467
  const strategy = rawStrategy === "json-diff" || rawStrategy === "exit-code" ? rawStrategy : "text-diff";
33468
+ const ignorePaths = parseTopLevelIgnorePaths(cd);
33469
+ if (ignorePaths.length > 0 && strategy !== "json-diff") {
33470
+ throw new Error(
33471
+ "change-detection.ignore-paths requires strategy: json-diff"
33472
+ );
33473
+ }
33079
33474
  const collection = parseKeyedCollectionConfig(config2["change-detection"]);
33080
33475
  if (collection && strategy !== "json-diff") {
33081
33476
  throw new Error("change-detection.collection requires strategy: json-diff");
@@ -33087,7 +33482,16 @@ function parseScopeConfig3(config2) {
33087
33482
  const timeoutMs = typeof rawTimeout === "string" ? parseDuration(rawTimeout) : DEFAULT_TIMEOUT_MS;
33088
33483
  const key = config2["key"];
33089
33484
  const objectKey = typeof key === "string" && key.length > 0 ? key : command.join(" ");
33090
- return { command, cwd, env, timeoutMs, objectKey, strategy, collection };
33485
+ return {
33486
+ command,
33487
+ cwd,
33488
+ env,
33489
+ timeoutMs,
33490
+ objectKey,
33491
+ strategy,
33492
+ ignorePaths,
33493
+ collection
33494
+ };
33091
33495
  }
33092
33496
  async function runCommand(scope) {
33093
33497
  return new Promise((resolve) => {
@@ -33173,18 +33577,75 @@ function sortKeys3(value) {
33173
33577
  }
33174
33578
  return value;
33175
33579
  }
33176
- function hasChanged2(strategy, prev, curr) {
33580
+ function parseTopLevelIgnorePaths(changeDetection) {
33581
+ const rawIgnorePaths = changeDetection?.["ignore-paths"];
33582
+ if (rawIgnorePaths === void 0) return [];
33583
+ if (!Array.isArray(rawIgnorePaths) || !rawIgnorePaths.every((entry) => typeof entry === "string")) {
33584
+ throw new Error(
33585
+ "change-detection.ignore-paths must be an array of strings"
33586
+ );
33587
+ }
33588
+ return rawIgnorePaths;
33589
+ }
33590
+ function normalizeJsonPath(path13) {
33591
+ if (path13 === "$" || path13.startsWith("$.")) return path13;
33592
+ return `$.${path13}`;
33593
+ }
33594
+ function assertValidJsonPathSegment(path13, segment) {
33595
+ if (segment.length === 0) {
33596
+ throw new Error(
33597
+ `Invalid change-detection.ignore-paths entry "${path13}": empty path segment`
33598
+ );
33599
+ }
33600
+ if (/[.[\]*?]/.test(segment)) {
33601
+ throw new Error(
33602
+ `Invalid change-detection.ignore-paths entry "${path13}": unsupported path segment "${segment}"`
33603
+ );
33604
+ }
33605
+ }
33606
+ function stripIgnoredJsonPaths(value, ignorePaths) {
33607
+ if (ignorePaths.length === 0) return value;
33608
+ const cloned = structuredClone(value);
33609
+ for (const path13 of ignorePaths) {
33610
+ removeJsonPath(cloned, path13);
33611
+ }
33612
+ return cloned;
33613
+ }
33614
+ function removeJsonPath(value, path13) {
33615
+ const normalizedPath = normalizeJsonPath(path13);
33616
+ if (normalizedPath === "$") return;
33617
+ const segments = normalizedPath.slice(2).split(".");
33618
+ let current = value;
33619
+ for (let i = 0; i < segments.length - 1; i++) {
33620
+ const segment = segments[i];
33621
+ assertValidJsonPathSegment(path13, segment ?? "");
33622
+ if (current === null || typeof current !== "object") return;
33623
+ if (!Object.hasOwn(current, segment ?? "")) return;
33624
+ current = current[segment ?? ""];
33625
+ }
33626
+ const last = segments.at(-1) ?? "";
33627
+ assertValidJsonPathSegment(path13, last);
33628
+ if (current !== null && typeof current === "object") {
33629
+ Reflect.deleteProperty(current, last);
33630
+ }
33631
+ }
33632
+ function hasChanged2(strategy, ignorePaths, prev, curr) {
33177
33633
  switch (strategy) {
33178
33634
  case "exit-code":
33179
33635
  return prev.exitCode !== curr.exitCode;
33180
- case "json-diff":
33636
+ case "json-diff": {
33637
+ let prevParsed;
33638
+ let currParsed;
33181
33639
  try {
33182
- const prevJson = JSON.stringify(sortKeys3(JSON.parse(prev.stdout)));
33183
- const currJson = JSON.stringify(sortKeys3(JSON.parse(curr.stdout)));
33184
- return prevJson !== currJson;
33640
+ prevParsed = JSON.parse(prev.stdout);
33641
+ currParsed = JSON.parse(curr.stdout);
33185
33642
  } catch {
33186
33643
  return prev.stdout !== curr.stdout;
33187
33644
  }
33645
+ return JSON.stringify(
33646
+ sortKeys3(stripIgnoredJsonPaths(prevParsed, ignorePaths))
33647
+ ) !== JSON.stringify(sortKeys3(stripIgnoredJsonPaths(currParsed, ignorePaths)));
33648
+ }
33188
33649
  case "text-diff":
33189
33650
  return prev.stdout !== curr.stdout;
33190
33651
  }
@@ -33266,7 +33727,7 @@ var scopeSchema3 = {
33266
33727
  properties: {
33267
33728
  path: {
33268
33729
  type: "string",
33269
- description: 'Dotted $.-path to the array within the parsed JSON (e.g. "$.tasks")'
33730
+ description: 'Dotted path to the array within the parsed JSON (e.g. "tasks" or "$.tasks")'
33270
33731
  },
33271
33732
  key: {
33272
33733
  type: "string",
@@ -33275,20 +33736,38 @@ var scopeSchema3 = {
33275
33736
  "ignore-paths": {
33276
33737
  type: "array",
33277
33738
  items: { type: "string" },
33278
- description: "Dotted $.-paths (relative to each element) removed before comparison"
33739
+ description: 'Dotted paths (relative to each element, e.g. "fetchedAt" or "$.fetchedAt") removed before comparison'
33279
33740
  }
33280
33741
  },
33281
- required: ["path", "key"]
33742
+ required: ["path", "key"],
33743
+ additionalProperties: false
33744
+ },
33745
+ "ignore-paths": {
33746
+ type: "array",
33747
+ items: { type: "string" },
33748
+ description: "Dotted paths removed from parsed JSON before plain json-diff comparison"
33282
33749
  }
33283
33750
  },
33751
+ additionalProperties: false,
33284
33752
  // BP3: change-detection.collection requires strategy: json-diff. Under any
33285
33753
  // other strategy (or the defaulted text-diff), presence of `collection` is an
33286
33754
  // authoring-time error.
33287
- if: { required: ["collection"] },
33288
- then: {
33289
- properties: { strategy: { const: "json-diff" } },
33290
- required: ["strategy"]
33291
- }
33755
+ allOf: [
33756
+ {
33757
+ if: { required: ["collection"] },
33758
+ then: {
33759
+ properties: { strategy: { const: "json-diff" } },
33760
+ required: ["strategy"]
33761
+ }
33762
+ },
33763
+ {
33764
+ if: { required: ["ignore-paths"] },
33765
+ then: {
33766
+ properties: { strategy: { const: "json-diff" } },
33767
+ required: ["strategy"]
33768
+ }
33769
+ }
33770
+ ]
33292
33771
  }
33293
33772
  },
33294
33773
  required: ["command"]
@@ -33353,7 +33832,7 @@ var source3 = {
33353
33832
  health: "ok",
33354
33833
  baselined: true
33355
33834
  };
33356
- if (prev !== void 0 && hadBaseline && hasChanged2(scope.strategy, prev, result)) {
33835
+ if (prev !== void 0 && hadBaseline && hasChanged2(scope.strategy, scope.ignorePaths, prev, result)) {
33357
33836
  observations.push(changedObservation(scope, result));
33358
33837
  }
33359
33838
  return { observations, nextState };
@@ -33696,6 +34175,23 @@ function changeDetectionCollectionError(watchConfig2) {
33696
34175
  if (strategy === "json-diff") return void 0;
33697
34176
  return "change-detection.collection requires strategy: json-diff";
33698
34177
  }
34178
+ function oldSourceScopeShapeHint(filePath2) {
34179
+ let content;
34180
+ try {
34181
+ content = (0, import_node_fs3.readFileSync)(filePath2, "utf-8");
34182
+ } catch {
34183
+ return null;
34184
+ }
34185
+ const normalised = content.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
34186
+ const frontmatter = /^---\n(?<frontmatter>[\s\S]*?)\n---/.exec(normalised)?.groups?.["frontmatter"];
34187
+ if (!frontmatter) return null;
34188
+ const rawSource = /^source:\s*(?<source>[^\n#]+)/m.exec(frontmatter)?.groups?.["source"];
34189
+ const source6 = rawSource?.trim().replace(/^['"]|['"]$/g, "");
34190
+ const hasScope = /^scope\s*:/m.test(frontmatter);
34191
+ const hasWatch = /^watch\s*:/m.test(frontmatter);
34192
+ if (!source6 || !hasScope || hasWatch) return null;
34193
+ return `did you mean to use the current watch shape? Move source/scope into watch:, for example: watch: { type: ${source6}, ... }`;
34194
+ }
33699
34195
  var validateCommand = new Command("validate").description("Validate MONITOR.md files in a directory").argument("[path]", "Path to monitors directory", ".claude/monitors").addOption(
33700
34196
  new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")
33701
34197
  ).action(async (monitorPath, options2) => {
@@ -33728,12 +34224,12 @@ var validateCommand = new Command("validate").description("Validate MONITOR.md f
33728
34224
  });
33729
34225
  const duplicateErrors = result.duplicateIds.map((dup) => ({
33730
34226
  filePath: dup.filePaths.join(", "),
33731
- error: `Duplicate monitor id "${dup.id}" \u2014 ids are derived from folder names and must be unique within a tree`
34227
+ error: `Duplicate monitor id "${dup.id}" -- ids are derived from folder names and must be unique within a tree`
33732
34228
  }));
33733
34229
  const allErrors = [
33734
34230
  ...result.errors.map((e) => ({
33735
34231
  filePath: e.filePath,
33736
- error: e.error
34232
+ error: [e.error, oldSourceScopeShapeHint(e.filePath)].filter(Boolean).join("; ")
33737
34233
  })),
33738
34234
  ...scopeErrors.map((e) => ({
33739
34235
  filePath: e.id,
@@ -33983,19 +34479,14 @@ inboxCommand.command("archive").description("Archive a completed or failed inbox
33983
34479
 
33984
34480
  // src/commands/monitor-test.ts
33985
34481
  init_cjs_shims();
33986
- var import_node_fs4 = require("fs");
34482
+ var import_node_path5 = __toESM(require("path"), 1);
34483
+ var import_node_fs5 = require("fs");
33987
34484
  var import_promises4 = require("timers/promises");
33988
34485
 
33989
- // src/runtime-client.ts
33990
- init_cjs_shims();
33991
-
33992
- // src/runtime.ts
33993
- init_cjs_shims();
33994
-
33995
34486
  // src/daemon-ipc.ts
33996
34487
  init_cjs_shims();
33997
34488
  var import_node_crypto = require("crypto");
33998
- var import_node_fs3 = require("fs");
34489
+ var import_node_fs4 = require("fs");
33999
34490
  var import_node_os2 = require("os");
34000
34491
  var import_node_path4 = __toESM(require("path"), 1);
34001
34492
  var import_node_net = __toESM(require("net"), 1);
@@ -34018,6 +34509,7 @@ var daemonMethodSchema = external_exports.enum([
34018
34509
  "events.ack",
34019
34510
  "hook.claim",
34020
34511
  "history.list",
34512
+ "monitor.explain",
34021
34513
  "daemon.tick"
34022
34514
  ]);
34023
34515
  var daemonResponseSchema = external_exports.object({
@@ -34066,6 +34558,13 @@ var historyListParamsSchema = external_exports.object({
34066
34558
  monitorId: external_exports.string().optional(),
34067
34559
  limit: external_exports.number().int().positive().optional()
34068
34560
  });
34561
+ var monitorExplainParamsSchema = external_exports.object({
34562
+ monitorId: external_exports.string(),
34563
+ monitorsDir: external_exports.string(),
34564
+ workspacePath: external_exports.string().optional(),
34565
+ historyLimit: external_exports.number().int().positive().optional(),
34566
+ eventLimit: external_exports.number().int().positive().optional()
34567
+ });
34069
34568
  var daemonTickParamsSchema = external_exports.object({
34070
34569
  monitorsDir: external_exports.string(),
34071
34570
  workspacePath: external_exports.string().optional()
@@ -34075,6 +34574,13 @@ var daemonRequestSchema = external_exports.object({
34075
34574
  method: daemonMethodSchema,
34076
34575
  params: external_exports.record(external_exports.string(), external_exports.unknown())
34077
34576
  });
34577
+ var DaemonConnectionError = class extends Error {
34578
+ constructor(message, cause) {
34579
+ super(message);
34580
+ this.cause = cause;
34581
+ }
34582
+ name = "DaemonConnectionError";
34583
+ };
34078
34584
  function isErrnoException(error2) {
34079
34585
  return typeof error2 === "object" && error2 !== null && "code" in error2;
34080
34586
  }
@@ -34095,7 +34601,7 @@ function resolveSocketPath(overridePath) {
34095
34601
  }
34096
34602
  function cleanupSocket(socketPath) {
34097
34603
  try {
34098
- (0, import_node_fs3.rmSync)(socketPath);
34604
+ (0, import_node_fs4.rmSync)(socketPath);
34099
34605
  } catch (error2) {
34100
34606
  const code = isErrnoException(error2) ? String(error2.code) : "";
34101
34607
  if (code !== "ENOENT") throw error2;
@@ -34136,8 +34642,8 @@ function acquireStartupLock(socketPath) {
34136
34642
  const pidFile = import_node_path4.default.join(lock, "pid");
34137
34643
  const tryMkdir = () => {
34138
34644
  try {
34139
- (0, import_node_fs3.mkdirSync)(lock);
34140
- (0, import_node_fs3.writeFileSync)(pidFile, String(process.pid), "utf-8");
34645
+ (0, import_node_fs4.mkdirSync)(lock);
34646
+ (0, import_node_fs4.writeFileSync)(pidFile, String(process.pid), "utf-8");
34141
34647
  return true;
34142
34648
  } catch (err) {
34143
34649
  if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
@@ -34147,7 +34653,7 @@ function acquireStartupLock(socketPath) {
34147
34653
  if (tryMkdir()) return true;
34148
34654
  let holderPid;
34149
34655
  try {
34150
- holderPid = parseInt((0, import_node_fs3.readFileSync)(pidFile, "utf-8"), 10);
34656
+ holderPid = parseInt((0, import_node_fs4.readFileSync)(pidFile, "utf-8"), 10);
34151
34657
  } catch {
34152
34658
  return false;
34153
34659
  }
@@ -34168,11 +34674,11 @@ function acquireStartupLock(socketPath) {
34168
34674
  return false;
34169
34675
  }
34170
34676
  try {
34171
- (0, import_node_fs3.unlinkSync)(pidFile);
34677
+ (0, import_node_fs4.unlinkSync)(pidFile);
34172
34678
  } catch {
34173
34679
  }
34174
34680
  try {
34175
- (0, import_node_fs3.rmdirSync)(lock);
34681
+ (0, import_node_fs4.rmdirSync)(lock);
34176
34682
  } catch {
34177
34683
  }
34178
34684
  return tryMkdir();
@@ -34181,11 +34687,11 @@ function releaseStartupLock(socketPath) {
34181
34687
  const lock = lockPath(socketPath);
34182
34688
  const pidFile = import_node_path4.default.join(lock, "pid");
34183
34689
  try {
34184
- (0, import_node_fs3.unlinkSync)(pidFile);
34690
+ (0, import_node_fs4.unlinkSync)(pidFile);
34185
34691
  } catch {
34186
34692
  }
34187
34693
  try {
34188
- (0, import_node_fs3.rmdirSync)(lock);
34694
+ (0, import_node_fs4.rmdirSync)(lock);
34189
34695
  } catch {
34190
34696
  }
34191
34697
  }
@@ -34256,6 +34762,16 @@ function handleRequest(runtime, request, stop) {
34256
34762
  })
34257
34763
  );
34258
34764
  }
34765
+ case "monitor.explain": {
34766
+ const params = monitorExplainParamsSchema.parse(request.params);
34767
+ return runtime.explainMonitor({
34768
+ monitorId: params.monitorId,
34769
+ monitorsDir: params.monitorsDir,
34770
+ ...params.workspacePath ? { workspacePath: params.workspacePath } : {},
34771
+ ...params.historyLimit ? { historyLimit: params.historyLimit } : {},
34772
+ ...params.eventLimit ? { eventLimit: params.eventLimit } : {}
34773
+ });
34774
+ }
34259
34775
  case "daemon.tick": {
34260
34776
  const params = daemonTickParamsSchema.parse(request.params);
34261
34777
  return runtime.tick(params.monitorsDir, params.workspacePath);
@@ -34267,7 +34783,7 @@ function createDaemonServer({
34267
34783
  socketPath,
34268
34784
  onStop
34269
34785
  }) {
34270
- (0, import_node_fs3.mkdirSync)(import_node_path4.default.dirname(socketPath), { recursive: true });
34786
+ (0, import_node_fs4.mkdirSync)(import_node_path4.default.dirname(socketPath), { recursive: true });
34271
34787
  let serverClosed = false;
34272
34788
  const server = import_node_net.default.createServer((socket) => {
34273
34789
  let buffer = "";
@@ -34325,7 +34841,7 @@ function createDaemonServer({
34325
34841
  const live = await probeSocket(socketPath);
34326
34842
  if (!live) {
34327
34843
  try {
34328
- (0, import_node_fs3.unlinkSync)(socketPath);
34844
+ (0, import_node_fs4.unlinkSync)(socketPath);
34329
34845
  } catch (unlinkErr) {
34330
34846
  const code = isErrnoException(unlinkErr) ? String(unlinkErr.code) : "";
34331
34847
  if (code !== "ENOENT") throw unlinkErr;
@@ -34391,11 +34907,20 @@ async function callDaemon(method, params = {}, options2 = {}) {
34391
34907
  });
34392
34908
  };
34393
34909
  socket.setTimeout(timeoutMs, () => {
34394
- fail(new Error(`Timed out waiting for AgentMon daemon at ${socketPath}`));
34910
+ fail(
34911
+ new DaemonConnectionError(
34912
+ `Timed out waiting for AgentMon daemon at ${socketPath}`
34913
+ )
34914
+ );
34395
34915
  });
34396
34916
  socket.setEncoding("utf-8");
34397
34917
  socket.on("error", (error2) => {
34398
- fail(error2);
34918
+ fail(
34919
+ new DaemonConnectionError(
34920
+ error2 instanceof Error ? error2.message : String(error2),
34921
+ error2
34922
+ )
34923
+ );
34399
34924
  });
34400
34925
  socket.on("data", (chunk) => {
34401
34926
  buffer += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
@@ -34436,7 +34961,11 @@ async function daemonAvailable(socketPath) {
34436
34961
  }
34437
34962
  }
34438
34963
 
34964
+ // src/runtime-client.ts
34965
+ init_cjs_shims();
34966
+
34439
34967
  // src/runtime.ts
34968
+ init_cjs_shims();
34440
34969
  function createRuntime(dbPath = resolveDbPath()) {
34441
34970
  const db = createDb(dbPath);
34442
34971
  const registry2 = new SourceRegistry();
@@ -34499,6 +35028,13 @@ async function listObservationHistoryClient(query, socketPath) {
34499
35028
  socketPath ? { socketPath } : {}
34500
35029
  );
34501
35030
  }
35031
+ async function explainMonitorClient(input, socketPath) {
35032
+ return await callDaemon(
35033
+ "monitor.explain",
35034
+ input,
35035
+ socketPath ? { socketPath } : {}
35036
+ );
35037
+ }
34502
35038
  async function daemonStatusClient(socketPath) {
34503
35039
  return await callDaemon(
34504
35040
  "status",
@@ -34515,6 +35051,127 @@ async function daemonTickClient(monitorsDir, workspacePath) {
34515
35051
  var monitorTestCommand = new Command("monitor").description(
34516
35052
  "Monitor utilities"
34517
35053
  );
35054
+ var EXPLAIN_STAGE_LABELS2 = {
35055
+ definition: "Definition",
35056
+ scheduling: "Scheduling",
35057
+ observation: "Observation",
35058
+ notify: "Notify state",
35059
+ materialization: "Materialization",
35060
+ delivery: "Projection and delivery"
35061
+ };
35062
+ function monitorIdFromFilePath2(filePath2) {
35063
+ const base = import_node_path5.default.basename(filePath2);
35064
+ return base === "MONITOR.md" ? import_node_path5.default.basename(import_node_path5.default.dirname(filePath2)) : import_node_path5.default.parse(filePath2).name;
35065
+ }
35066
+ function explainStage2(id, status, reason, details) {
35067
+ return {
35068
+ id,
35069
+ label: EXPLAIN_STAGE_LABELS2[id],
35070
+ status,
35071
+ reason,
35072
+ ...details ? { details } : {}
35073
+ };
35074
+ }
35075
+ function explainVerdict2(stages) {
35076
+ const stopped = stages.find((stage2) => stage2.status !== "ok");
35077
+ const stage = stopped ?? stages[stages.length - 1];
35078
+ return {
35079
+ status: stage?.status ?? "ok",
35080
+ stage: stage?.id ?? "delivery",
35081
+ reason: stage?.reason ?? "Monitor delivered successfully."
35082
+ };
35083
+ }
35084
+ function statusGlyph(status) {
35085
+ if (status === "ok") return "\u2713";
35086
+ if (status === "pending") return "\u23F3";
35087
+ if (status === "healthy") return "\u25CB";
35088
+ return "\u2717";
35089
+ }
35090
+ function printExplainText(report) {
35091
+ console.log(`Monitor ${report.monitorId}`);
35092
+ for (const stage of report.stages) {
35093
+ console.log(`${statusGlyph(stage.status)} ${stage.label}: ${stage.reason}`);
35094
+ }
35095
+ console.log(
35096
+ `Verdict: ${report.verdict.status} at ${EXPLAIN_STAGE_LABELS2[report.verdict.stage]} - ${report.verdict.reason}`
35097
+ );
35098
+ }
35099
+ async function buildDaemonUnavailableReport(input) {
35100
+ const generatedAt = /* @__PURE__ */ new Date();
35101
+ const stages = [];
35102
+ const scan = await scanMonitors(input.monitorsDir);
35103
+ const parseError = scan.errors.find(
35104
+ (error2) => monitorIdFromFilePath2(error2.filePath) === input.monitorId
35105
+ );
35106
+ const monitor = scan.monitors.find(
35107
+ (candidate) => candidate.monitor.id === input.monitorId
35108
+ )?.monitor;
35109
+ if (parseError) {
35110
+ stages.push(
35111
+ explainStage2(
35112
+ "definition",
35113
+ "failure",
35114
+ `MONITOR.md failed to parse or validate: ${parseError.error}`,
35115
+ { filePath: parseError.filePath }
35116
+ )
35117
+ );
35118
+ } else if (!monitor) {
35119
+ stages.push(
35120
+ explainStage2(
35121
+ "definition",
35122
+ "failure",
35123
+ `Monitor "${input.monitorId}" was not found in ${input.monitorsDir}.`
35124
+ )
35125
+ );
35126
+ } else {
35127
+ const registry2 = new SourceRegistry();
35128
+ registerCoreSources(registry2);
35129
+ const sourceName = monitor.frontmatter.watch.type;
35130
+ const source6 = registry2.get(sourceName);
35131
+ const { type: _type, ...monitorWatchConfig } = monitor.frontmatter.watch;
35132
+ const scopeErrors = source6 ? validateScope(monitorWatchConfig, source6.scopeSchema) : [`Unknown source "${sourceName}".`];
35133
+ stages.push(
35134
+ scopeErrors.length === 0 ? explainStage2("definition", "ok", "Monitor definition is valid.", {
35135
+ filePath: monitor.filePath,
35136
+ sourceName
35137
+ }) : explainStage2(
35138
+ "definition",
35139
+ "failure",
35140
+ `Monitor definition is invalid: ${scopeErrors.join("; ")}`,
35141
+ { filePath: monitor.filePath, sourceName }
35142
+ )
35143
+ );
35144
+ }
35145
+ if (stages[0]?.status === "ok") {
35146
+ stages.push(
35147
+ explainStage2(
35148
+ "scheduling",
35149
+ "failure",
35150
+ `The daemon is not running or unreachable: ${input.errorMessage}`,
35151
+ { workspacePath: input.workspacePath }
35152
+ )
35153
+ );
35154
+ }
35155
+ return {
35156
+ monitorId: input.monitorId,
35157
+ generatedAt,
35158
+ ...monitor ? {
35159
+ monitor: {
35160
+ id: monitor.id,
35161
+ displayName: monitor.displayName,
35162
+ filePath: monitor.filePath,
35163
+ sourceName: monitor.frontmatter.watch.type,
35164
+ urgency: monitor.frontmatter.urgency
35165
+ }
35166
+ } : {},
35167
+ stages,
35168
+ verdict: explainVerdict2(stages),
35169
+ observations: [],
35170
+ events: [],
35171
+ projections: [],
35172
+ leadSessions: []
35173
+ };
35174
+ }
34518
35175
  function printJsonResult(monitorName, sourceName, baseline, observations) {
34519
35176
  console.log(
34520
35177
  JSON.stringify(
@@ -34598,13 +35255,13 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34598
35255
  new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")
34599
35256
  ).action(async (filePath2, options2) => {
34600
35257
  const json = options2.format === "json";
34601
- if (!(0, import_node_fs4.existsSync)(filePath2)) {
35258
+ if (!(0, import_node_fs5.existsSync)(filePath2)) {
34602
35259
  reportError(`Monitor file not found: ${filePath2}`, json);
34603
35260
  return;
34604
35261
  }
34605
35262
  let content;
34606
35263
  try {
34607
- content = (0, import_node_fs4.readFileSync)(filePath2, "utf-8");
35264
+ content = (0, import_node_fs5.readFileSync)(filePath2, "utf-8");
34608
35265
  } catch (err) {
34609
35266
  const msg = err instanceof Error ? err.message : String(err);
34610
35267
  reportError(`Cannot read monitor file: ${msg}`, json);
@@ -34660,6 +35317,55 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34660
35317
  reportError(`Observation failed: ${message}`, json);
34661
35318
  }
34662
35319
  });
35320
+ monitorTestCommand.command("explain").description("Explain where a monitor's signal currently stops").argument("<monitorId>", "Monitor id to diagnose").option(
35321
+ "--dir <path>",
35322
+ "Directory containing monitor definitions",
35323
+ ".claude/monitors"
35324
+ ).option("--workspace <path>", "Workspace path used by the daemon").option("--socket <path>", "Unix domain socket path for the daemon").option("--history-limit <n>", "Observation history rows to include", "10").option("--event-limit <n>", "Materialized event rows to include", "10").addOption(
35325
+ new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")
35326
+ ).action(
35327
+ async (monitorId, options2) => {
35328
+ const json = options2.format === "json";
35329
+ const monitorsDir = import_node_path5.default.resolve(options2.dir);
35330
+ const workspacePath = import_node_path5.default.resolve(options2.workspace ?? process.cwd());
35331
+ const historyLimit = Number.parseInt(options2.historyLimit, 10);
35332
+ const eventLimit = Number.parseInt(options2.eventLimit, 10);
35333
+ try {
35334
+ const report = await explainMonitorClient(
35335
+ {
35336
+ monitorId,
35337
+ monitorsDir,
35338
+ workspacePath,
35339
+ ...Number.isFinite(historyLimit) && historyLimit > 0 ? { historyLimit } : {},
35340
+ ...Number.isFinite(eventLimit) && eventLimit > 0 ? { eventLimit } : {}
35341
+ },
35342
+ options2.socket
35343
+ );
35344
+ if (json) {
35345
+ console.log(JSON.stringify(report, null, 2));
35346
+ return;
35347
+ }
35348
+ printExplainText(report);
35349
+ } catch (err) {
35350
+ const message = err instanceof Error ? err.message : String(err);
35351
+ if (!(err instanceof DaemonConnectionError)) {
35352
+ reportError(`Explain failed: ${message}`, json);
35353
+ return;
35354
+ }
35355
+ const report = await buildDaemonUnavailableReport({
35356
+ monitorId,
35357
+ monitorsDir,
35358
+ workspacePath,
35359
+ errorMessage: message
35360
+ });
35361
+ if (json) {
35362
+ console.log(JSON.stringify(report, null, 2));
35363
+ return;
35364
+ }
35365
+ printExplainText(report);
35366
+ }
35367
+ }
35368
+ );
34663
35369
  monitorTestCommand.command("history").description(
34664
35370
  "Show recent observation outcomes per tick (triggered / suppressed / no-change / errored / rebaselined)"
34665
35371
  ).argument("[monitorId]", "Filter to a single monitor id").option("--socket <path>", "Unix domain socket path for the daemon").option("--limit <n>", "Maximum rows to return", "50").addOption(
@@ -34711,9 +35417,11 @@ sourceCommand.command("list").description("List installed observation sources").
34711
35417
  const output = sources.map((source6) => {
34712
35418
  const requiredFields = source6.scopeSchema["required"] ?? [];
34713
35419
  const properties = source6.scopeSchema["properties"] ?? {};
35420
+ const configFields = Object.keys(properties);
34714
35421
  return {
34715
35422
  name: source6.name,
34716
- scopeFields: Object.keys(properties),
35423
+ configFields,
35424
+ scopeFields: configFields,
34717
35425
  required: requiredFields
34718
35426
  };
34719
35427
  });
@@ -34729,7 +35437,7 @@ sourceCommand.command("list").description("List installed observation sources").
34729
35437
  const requiredFields = source6.scopeSchema["required"] ?? [];
34730
35438
  const properties = source6.scopeSchema["properties"] ?? {};
34731
35439
  console.log(` ${source6.name}`);
34732
- console.log(` Scope fields: ${Object.keys(properties).join(", ")}`);
35440
+ console.log(` Config fields: ${Object.keys(properties).join(", ")}`);
34733
35441
  console.log(` Required: ${requiredFields.join(", ") || "(none)"}`);
34734
35442
  console.log("");
34735
35443
  }
@@ -35026,15 +35734,15 @@ daemonCommand.command("stop").description("Ask the local AgentMon daemon to stop
35026
35734
 
35027
35735
  // src/commands/session.ts
35028
35736
  init_cjs_shims();
35029
- var import_node_path8 = __toESM(require("path"), 1);
35737
+ var import_node_path9 = __toESM(require("path"), 1);
35030
35738
 
35031
35739
  // src/local-state.ts
35032
35740
  init_cjs_shims();
35033
- var import_node_fs5 = require("fs");
35034
- var import_node_path5 = __toESM(require("path"), 1);
35741
+ var import_node_fs6 = require("fs");
35742
+ var import_node_path6 = __toESM(require("path"), 1);
35035
35743
  var DEFAULT_REAP_AFTER_MS2 = 5 * 60 * 1e3;
35036
35744
  function filePath(workspacePath) {
35037
- return import_node_path5.default.join(workspacePath, ".claude", "agentmonitors.local.md");
35745
+ return import_node_path6.default.join(workspacePath, ".claude", "agentmonitors.local.md");
35038
35746
  }
35039
35747
  function parseFrontmatter(raw) {
35040
35748
  const lines = raw.split("\n");
@@ -35063,7 +35771,7 @@ function parseFrontmatter(raw) {
35063
35771
  function readLocalState(workspacePath) {
35064
35772
  let raw;
35065
35773
  try {
35066
- raw = (0, import_node_fs5.readFileSync)(filePath(workspacePath), "utf-8");
35774
+ raw = (0, import_node_fs6.readFileSync)(filePath(workspacePath), "utf-8");
35067
35775
  } catch {
35068
35776
  return { enabled: false };
35069
35777
  }
@@ -35084,7 +35792,7 @@ function readLocalState(workspacePath) {
35084
35792
  }
35085
35793
  function writeLocalState(workspacePath, state) {
35086
35794
  const target = filePath(workspacePath);
35087
- (0, import_node_fs5.mkdirSync)(import_node_path5.default.dirname(target), { recursive: true });
35795
+ (0, import_node_fs6.mkdirSync)(import_node_path6.default.dirname(target), { recursive: true });
35088
35796
  const lines = [
35089
35797
  "---",
35090
35798
  `enabled: ${String(state.enabled)}`,
@@ -35096,25 +35804,25 @@ function writeLocalState(workspacePath, state) {
35096
35804
  "> Local AgentMon coordination state. Gitignored; safe to delete (it is regenerated).",
35097
35805
  ""
35098
35806
  ];
35099
- (0, import_node_fs5.writeFileSync)(target, lines.join("\n"), "utf-8");
35807
+ (0, import_node_fs6.writeFileSync)(target, lines.join("\n"), "utf-8");
35100
35808
  }
35101
35809
 
35102
35810
  // src/workspace-paths.ts
35103
35811
  init_cjs_shims();
35104
35812
  var import_node_crypto2 = require("crypto");
35105
35813
  var import_node_os3 = __toESM(require("os"), 1);
35106
- var import_node_path6 = __toESM(require("path"), 1);
35814
+ var import_node_path7 = __toESM(require("path"), 1);
35107
35815
  function workspacePaths(workspacePath) {
35108
- const hash = (0, import_node_crypto2.createHash)("sha256").update(import_node_path6.default.resolve(workspacePath)).digest("hex").slice(0, 16);
35109
- const dataRoot = process.env["XDG_DATA_HOME"] ?? import_node_path6.default.join(import_node_os3.default.homedir(), ".local", "share");
35110
- const dir = import_node_path6.default.join(dataRoot, "agentmonitors", "workspaces", hash);
35816
+ const hash = (0, import_node_crypto2.createHash)("sha256").update(import_node_path7.default.resolve(workspacePath)).digest("hex").slice(0, 16);
35817
+ const dataRoot = process.env["XDG_DATA_HOME"] ?? import_node_path7.default.join(import_node_os3.default.homedir(), ".local", "share");
35818
+ const dir = import_node_path7.default.join(dataRoot, "agentmonitors", "workspaces", hash);
35111
35819
  return {
35112
35820
  dir,
35113
- db: import_node_path6.default.join(dir, "inbox.db"),
35821
+ db: import_node_path7.default.join(dir, "inbox.db"),
35114
35822
  // Keep the socket short: a 16-char hash under the data dir stays well under
35115
35823
  // the 100-char limit on most setups; resolveSocketPath's /tmp fallback still
35116
35824
  // applies if a deep home dir pushes it over.
35117
- socket: import_node_path6.default.join(dir, "agentmonitors.sock")
35825
+ socket: import_node_path7.default.join(dir, "agentmonitors.sock")
35118
35826
  };
35119
35827
  }
35120
35828
 
@@ -35122,15 +35830,15 @@ function workspacePaths(workspacePath) {
35122
35830
  init_cjs_shims();
35123
35831
  var import_node_child_process = require("child_process");
35124
35832
  var import_node_url3 = require("url");
35125
- var import_node_path7 = __toESM(require("path"), 1);
35833
+ var import_node_path8 = __toESM(require("path"), 1);
35126
35834
  function cliEntry() {
35127
35835
  const thisFile = (0, import_node_url3.fileURLToPath)(importMetaUrl);
35128
- const isBundle = import_node_path7.default.basename(import_node_path7.default.dirname(thisFile)) === "dist";
35836
+ const isBundle = import_node_path8.default.basename(import_node_path8.default.dirname(thisFile)) === "dist";
35129
35837
  if (isBundle) {
35130
35838
  return thisFile;
35131
35839
  }
35132
- const packageRoot = import_node_path7.default.resolve(import_node_path7.default.dirname(thisFile), "..");
35133
- return import_node_path7.default.join(packageRoot, "dist", "index.cjs");
35840
+ const packageRoot = import_node_path8.default.resolve(import_node_path8.default.dirname(thisFile), "..");
35841
+ return import_node_path8.default.join(packageRoot, "dist", "index.cjs");
35134
35842
  }
35135
35843
  function spawnDetachedDaemon(options2) {
35136
35844
  const args = [
@@ -35337,7 +36045,7 @@ sessionCommand.command("start").description(
35337
36045
  const paths = workspacePaths(workspacePath);
35338
36046
  const socket = resolveSocketPath(state.socket ?? paths.socket);
35339
36047
  const db = state.db ?? paths.db;
35340
- const monitorsDir = import_node_path8.default.join(workspacePath, ".claude", "monitors");
36048
+ const monitorsDir = import_node_path9.default.join(workspacePath, ".claude", "monitors");
35341
36049
  const BOOT_TIMEOUT_MS = 8e3;
35342
36050
  if (!await daemonAvailable(socket)) {
35343
36051
  spawnDetachedDaemon({
@@ -35771,10 +36479,10 @@ function assignProp(target, prop, value) {
35771
36479
  configurable: true
35772
36480
  });
35773
36481
  }
35774
- function getElementAtPath(obj, path12) {
35775
- if (!path12)
36482
+ function getElementAtPath(obj, path13) {
36483
+ if (!path13)
35776
36484
  return obj;
35777
- return path12.reduce((acc, key) => acc?.[key], obj);
36485
+ return path13.reduce((acc, key) => acc?.[key], obj);
35778
36486
  }
35779
36487
  function promiseAllObject(promisesObj) {
35780
36488
  const keys = Object.keys(promisesObj);
@@ -36094,11 +36802,11 @@ function aborted(x2, startIndex = 0) {
36094
36802
  }
36095
36803
  return false;
36096
36804
  }
36097
- function prefixIssues(path12, issues) {
36805
+ function prefixIssues(path13, issues) {
36098
36806
  return issues.map((iss) => {
36099
36807
  var _a2;
36100
36808
  (_a2 = iss).path ?? (_a2.path = []);
36101
- iss.path.unshift(path12);
36809
+ iss.path.unshift(path13);
36102
36810
  return iss;
36103
36811
  });
36104
36812
  }
@@ -43007,9 +43715,9 @@ async function runChannelServe(options2) {
43007
43715
  // src/index.ts
43008
43716
  function getVersion() {
43009
43717
  try {
43010
- const dir = (0, import_node_path9.dirname)((0, import_node_url4.fileURLToPath)(importMetaUrl));
43718
+ const dir = (0, import_node_path10.dirname)((0, import_node_url4.fileURLToPath)(importMetaUrl));
43011
43719
  const pkg = JSON.parse(
43012
- (0, import_node_fs6.readFileSync)((0, import_node_path9.join)(dir, "..", "package.json"), "utf8")
43720
+ (0, import_node_fs7.readFileSync)((0, import_node_path10.join)(dir, "..", "package.json"), "utf8")
43013
43721
  );
43014
43722
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
43015
43723
  } catch {