@agentmonitors/cli 0.3.2 → 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();
@@ -2020,13 +2020,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2020
2020
  * @param {string} source - expected values are default/config/env/cli/implied
2021
2021
  * @return {Command} `this` command for chaining
2022
2022
  */
2023
- setOptionValueWithSource(key, value, source5) {
2023
+ setOptionValueWithSource(key, value, source6) {
2024
2024
  if (this._storeOptionsAsProperties) {
2025
2025
  this[key] = value;
2026
2026
  } else {
2027
2027
  this._optionValues[key] = value;
2028
2028
  }
2029
- this._optionValueSources[key] = source5;
2029
+ this._optionValueSources[key] = source6;
2030
2030
  return this;
2031
2031
  }
2032
2032
  /**
@@ -2047,13 +2047,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2047
2047
  * @return {string}
2048
2048
  */
2049
2049
  getOptionValueSourceWithGlobals(key) {
2050
- let source5;
2050
+ let source6;
2051
2051
  this._getCommandAndAncestors().forEach((cmd) => {
2052
2052
  if (cmd.getOptionValueSource(key) !== void 0) {
2053
- source5 = cmd.getOptionValueSource(key);
2053
+ source6 = cmd.getOptionValueSource(key);
2054
2054
  }
2055
2055
  });
2056
- return source5;
2056
+ return source6;
2057
2057
  }
2058
2058
  /**
2059
2059
  * Get user arguments from implied or explicit arguments.
@@ -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) {
@@ -2922,8 +2922,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
2922
2922
  const getErrorMessage = (option2) => {
2923
2923
  const bestOption = findBestOptionFromValue(option2);
2924
2924
  const optionKey = bestOption.attributeName();
2925
- const source5 = this.getOptionValueSource(optionKey);
2926
- if (source5 === "env") {
2925
+ const source6 = this.getOptionValueSource(optionKey);
2926
+ if (source6 === "env") {
2927
2927
  return `environment variable '${bestOption.envVar}'`;
2928
2928
  }
2929
2929
  return `option '${bestOption.flags}'`;
@@ -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
  /**
@@ -3773,13 +3773,13 @@ var require_common = __commonJS({
3773
3773
  else if (isNothing(sequence)) return [];
3774
3774
  return [sequence];
3775
3775
  }
3776
- function extend2(target, source5) {
3776
+ function extend2(target, source6) {
3777
3777
  var index, length, key, sourceKeys;
3778
- if (source5) {
3779
- sourceKeys = Object.keys(source5);
3778
+ if (source6) {
3779
+ sourceKeys = Object.keys(source6);
3780
3780
  for (index = 0, length = sourceKeys.length; index < length; index += 1) {
3781
3781
  key = sourceKeys[index];
3782
- target[key] = source5[key];
3782
+ target[key] = source6[key];
3783
3783
  }
3784
3784
  }
3785
3785
  return target;
@@ -4837,7 +4837,7 @@ var require_function = __commonJS({
4837
4837
  function resolveJavascriptFunction(data) {
4838
4838
  if (data === null) return false;
4839
4839
  try {
4840
- var source5 = "(" + data + ")", ast = esprima.parse(source5, { range: true });
4840
+ var source6 = "(" + data + ")", ast = esprima.parse(source6, { range: true });
4841
4841
  if (ast.type !== "Program" || ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement" || ast.body[0].expression.type !== "ArrowFunctionExpression" && ast.body[0].expression.type !== "FunctionExpression") {
4842
4842
  return false;
4843
4843
  }
@@ -4847,7 +4847,7 @@ var require_function = __commonJS({
4847
4847
  }
4848
4848
  }
4849
4849
  function constructJavascriptFunction(data) {
4850
- var source5 = "(" + data + ")", ast = esprima.parse(source5, { range: true }), params = [], body;
4850
+ var source6 = "(" + data + ")", ast = esprima.parse(source6, { range: true }), params = [], body;
4851
4851
  if (ast.type !== "Program" || ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement" || ast.body[0].expression.type !== "ArrowFunctionExpression" && ast.body[0].expression.type !== "FunctionExpression") {
4852
4852
  throw new Error("Failed to resolve function");
4853
4853
  }
@@ -4856,9 +4856,9 @@ var require_function = __commonJS({
4856
4856
  });
4857
4857
  body = ast.body[0].expression.body.range;
4858
4858
  if (ast.body[0].expression.body.type === "BlockStatement") {
4859
- return new Function(params, source5.slice(body[0] + 1, body[1] - 1));
4859
+ return new Function(params, source6.slice(body[0] + 1, body[1] - 1));
4860
4860
  }
4861
- return new Function(params, "return " + source5.slice(body[0], body[1]));
4861
+ return new Function(params, "return " + source6.slice(body[0], body[1]));
4862
4862
  }
4863
4863
  function representJavascriptFunction(object3) {
4864
4864
  return object3.toString();
@@ -5084,16 +5084,16 @@ var require_loader = __commonJS({
5084
5084
  state.result += _result;
5085
5085
  }
5086
5086
  }
5087
- function mergeMappings(state, destination, source5, overridableKeys) {
5087
+ function mergeMappings(state, destination, source6, overridableKeys) {
5088
5088
  var sourceKeys, key, index, quantity;
5089
- if (!common.isObject(source5)) {
5089
+ if (!common.isObject(source6)) {
5090
5090
  throwError(state, "cannot merge mappings; the provided source object is unacceptable");
5091
5091
  }
5092
- sourceKeys = Object.keys(source5);
5092
+ sourceKeys = Object.keys(source6);
5093
5093
  for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
5094
5094
  key = sourceKeys[index];
5095
5095
  if (!_hasOwnProperty.call(destination, key)) {
5096
- setProperty(destination, key, source5[key]);
5096
+ setProperty(destination, key, source6[key]);
5097
5097
  overridableKeys[key] = true;
5098
5098
  }
5099
5099
  }
@@ -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
  }
@@ -10581,10 +10581,10 @@ var require_fast_uri = __commonJS({
10581
10581
  function normalize2(uri2, options2) {
10582
10582
  if (typeof uri2 === "string") {
10583
10583
  uri2 = /** @type {T} */
10584
- serialize(parse4(uri2, options2), options2);
10584
+ serialize2(parse4(uri2, options2), options2);
10585
10585
  } else if (typeof uri2 === "object") {
10586
10586
  uri2 = /** @type {T} */
10587
- parse4(serialize(uri2, options2), options2);
10587
+ parse4(serialize2(uri2, options2), options2);
10588
10588
  }
10589
10589
  return uri2;
10590
10590
  }
@@ -10592,13 +10592,13 @@ var require_fast_uri = __commonJS({
10592
10592
  const schemelessOptions = options2 ? Object.assign({ scheme: "null" }, options2) : { scheme: "null" };
10593
10593
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
10594
10594
  schemelessOptions.skipEscape = true;
10595
- return serialize(resolved, schemelessOptions);
10595
+ return serialize2(resolved, schemelessOptions);
10596
10596
  }
10597
10597
  function resolveComponent(base, relative, options2, skipNormalization) {
10598
10598
  const target = {};
10599
10599
  if (!skipNormalization) {
10600
- base = parse4(serialize(base, options2), options2);
10601
- relative = parse4(serialize(relative, options2), options2);
10600
+ base = parse4(serialize2(base, options2), options2);
10601
+ relative = parse4(serialize2(relative, options2), options2);
10602
10602
  }
10603
10603
  options2 = options2 || {};
10604
10604
  if (!options2.tolerant && relative.scheme) {
@@ -10650,19 +10650,19 @@ var require_fast_uri = __commonJS({
10650
10650
  function equal(uriA, uriB, options2) {
10651
10651
  if (typeof uriA === "string") {
10652
10652
  uriA = unescape(uriA);
10653
- uriA = serialize(normalizeComponentEncoding(parse4(uriA, options2), true), { ...options2, skipEscape: true });
10653
+ uriA = serialize2(normalizeComponentEncoding(parse4(uriA, options2), true), { ...options2, skipEscape: true });
10654
10654
  } else if (typeof uriA === "object") {
10655
- uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options2, skipEscape: true });
10655
+ uriA = serialize2(normalizeComponentEncoding(uriA, true), { ...options2, skipEscape: true });
10656
10656
  }
10657
10657
  if (typeof uriB === "string") {
10658
10658
  uriB = unescape(uriB);
10659
- uriB = serialize(normalizeComponentEncoding(parse4(uriB, options2), true), { ...options2, skipEscape: true });
10659
+ uriB = serialize2(normalizeComponentEncoding(parse4(uriB, options2), true), { ...options2, skipEscape: true });
10660
10660
  } else if (typeof uriB === "object") {
10661
- uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options2, skipEscape: true });
10661
+ uriB = serialize2(normalizeComponentEncoding(uriB, true), { ...options2, skipEscape: true });
10662
10662
  }
10663
10663
  return uriA.toLowerCase() === uriB.toLowerCase();
10664
10664
  }
10665
- function serialize(cmpts, opts) {
10665
+ function serialize2(cmpts, opts) {
10666
10666
  const component = {
10667
10667
  host: cmpts.host,
10668
10668
  scheme: cmpts.scheme,
@@ -10818,7 +10818,7 @@ var require_fast_uri = __commonJS({
10818
10818
  resolve,
10819
10819
  resolveComponent,
10820
10820
  equal,
10821
- serialize,
10821
+ serialize: serialize2,
10822
10822
  parse: parse4
10823
10823
  };
10824
10824
  module2.exports = fastUri;
@@ -11553,12 +11553,12 @@ var require_ref = __commonJS({
11553
11553
  function callSyncRef() {
11554
11554
  cxt.result((0, code_1.callValidateCode)(cxt, v, passCxt), () => addEvaluatedFrom(v), () => addErrorsFrom(v));
11555
11555
  }
11556
- function addErrorsFrom(source5) {
11557
- const errs = (0, codegen_1._)`${source5}.errors`;
11556
+ function addErrorsFrom(source6) {
11557
+ const errs = (0, codegen_1._)`${source6}.errors`;
11558
11558
  gen.assign(names_1.default.vErrors, (0, codegen_1._)`${names_1.default.vErrors} === null ? ${errs} : ${names_1.default.vErrors}.concat(${errs})`);
11559
11559
  gen.assign(names_1.default.errors, (0, codegen_1._)`${names_1.default.vErrors}.length`);
11560
11560
  }
11561
- function addEvaluatedFrom(source5) {
11561
+ function addEvaluatedFrom(source6) {
11562
11562
  var _a2;
11563
11563
  if (!it.opts.unevaluated)
11564
11564
  return;
@@ -11569,7 +11569,7 @@ var require_ref = __commonJS({
11569
11569
  it.props = util_1.mergeEvaluated.props(gen, schEvaluated.props, it.props);
11570
11570
  }
11571
11571
  } else {
11572
- const props = gen.var("props", (0, codegen_1._)`${source5}.evaluated.props`);
11572
+ const props = gen.var("props", (0, codegen_1._)`${source6}.evaluated.props`);
11573
11573
  it.props = util_1.mergeEvaluated.props(gen, props, it.props, codegen_1.Name);
11574
11574
  }
11575
11575
  }
@@ -11579,7 +11579,7 @@ var require_ref = __commonJS({
11579
11579
  it.items = util_1.mergeEvaluated.items(gen, schEvaluated.items, it.items);
11580
11580
  }
11581
11581
  } else {
11582
- const items = gen.var("items", (0, codegen_1._)`${source5}.evaluated.items`);
11582
+ const items = gen.var("items", (0, codegen_1._)`${source6}.evaluated.items`);
11583
11583
  it.items = util_1.mergeEvaluated.items(gen, items, it.items, codegen_1.Name);
11584
11584
  }
11585
11585
  }
@@ -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
@@ -13905,6 +13905,23 @@ urgency: normal
13905
13905
  ---
13906
13906
 
13907
13907
  When the API response changes, review the differences and take appropriate action.
13908
+ `.trimStart(),
13909
+ "command-poll": yaml2`
13910
+ ---
13911
+ name: My command monitor
13912
+ watch:
13913
+ type: command-poll
13914
+ command:
13915
+ - git
13916
+ - status
13917
+ - --porcelain
13918
+ interval: 5m
13919
+ change-detection:
13920
+ strategy: text-diff
13921
+ urgency: normal
13922
+ ---
13923
+
13924
+ When the command output changes, review the differences and take appropriate action.
13908
13925
  `.trimStart(),
13909
13926
  schedule: yaml2`
13910
13927
  ---
@@ -13954,6 +13971,7 @@ Edit the file to configure your monitor, then run:`);
13954
13971
 
13955
13972
  // src/commands/validate.ts
13956
13973
  init_cjs_shims();
13974
+ var import_node_fs3 = require("fs");
13957
13975
 
13958
13976
  // ../../libs/core/dist/index.js
13959
13977
  init_cjs_shims();
@@ -14451,8 +14469,8 @@ function getErrorMap() {
14451
14469
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
14452
14470
  init_cjs_shims();
14453
14471
  var makeIssue = (params) => {
14454
- const { data, path: path12, errorMaps, issueData } = params;
14455
- const fullPath = [...path12, ...issueData.path || []];
14472
+ const { data, path: path13, errorMaps, issueData } = params;
14473
+ const fullPath = [...path13, ...issueData.path || []];
14456
14474
  const fullIssue = {
14457
14475
  ...issueData,
14458
14476
  path: fullPath
@@ -14572,11 +14590,11 @@ var errorUtil;
14572
14590
 
14573
14591
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
14574
14592
  var ParseInputLazyPath = class {
14575
- constructor(parent, value, path12, key) {
14593
+ constructor(parent, value, path13, key) {
14576
14594
  this._cachedPath = [];
14577
14595
  this.parent = parent;
14578
14596
  this.data = value;
14579
- this._path = path12;
14597
+ this._path = path13;
14580
14598
  this._key = key;
14581
14599
  }
14582
14600
  get path() {
@@ -22642,12 +22660,12 @@ var PathBase = class {
22642
22660
  /**
22643
22661
  * Get the Path object referenced by the string path, resolved from this Path
22644
22662
  */
22645
- resolve(path12) {
22646
- if (!path12) {
22663
+ resolve(path13) {
22664
+ if (!path13) {
22647
22665
  return this;
22648
22666
  }
22649
- const rootPath = this.getRootString(path12);
22650
- const dir = path12.substring(rootPath.length);
22667
+ const rootPath = this.getRootString(path13);
22668
+ const dir = path13.substring(rootPath.length);
22651
22669
  const dirParts = dir.split(this.splitSep);
22652
22670
  const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
22653
22671
  return result;
@@ -23399,8 +23417,8 @@ var PathWin32 = class _PathWin32 extends PathBase {
23399
23417
  /**
23400
23418
  * @internal
23401
23419
  */
23402
- getRootString(path12) {
23403
- return import_node_path2.win32.parse(path12).root;
23420
+ getRootString(path13) {
23421
+ return import_node_path2.win32.parse(path13).root;
23404
23422
  }
23405
23423
  /**
23406
23424
  * @internal
@@ -23446,8 +23464,8 @@ var PathPosix = class _PathPosix extends PathBase {
23446
23464
  /**
23447
23465
  * @internal
23448
23466
  */
23449
- getRootString(path12) {
23450
- return path12.startsWith("/") ? "/" : "";
23467
+ getRootString(path13) {
23468
+ return path13.startsWith("/") ? "/" : "";
23451
23469
  }
23452
23470
  /**
23453
23471
  * @internal
@@ -23536,11 +23554,11 @@ var PathScurryBase = class {
23536
23554
  /**
23537
23555
  * Get the depth of a provided path, string, or the cwd
23538
23556
  */
23539
- depth(path12 = this.cwd) {
23540
- if (typeof path12 === "string") {
23541
- path12 = this.cwd.resolve(path12);
23557
+ depth(path13 = this.cwd) {
23558
+ if (typeof path13 === "string") {
23559
+ path13 = this.cwd.resolve(path13);
23542
23560
  }
23543
- return path12.depth();
23561
+ return path13.depth();
23544
23562
  }
23545
23563
  /**
23546
23564
  * Return the cache of child entries. Exposed so subclasses can create
@@ -24027,9 +24045,9 @@ var PathScurryBase = class {
24027
24045
  process3();
24028
24046
  return results;
24029
24047
  }
24030
- chdir(path12 = this.cwd) {
24048
+ chdir(path13 = this.cwd) {
24031
24049
  const oldCwd = this.cwd;
24032
- this.cwd = typeof path12 === "string" ? this.cwd.resolve(path12) : path12;
24050
+ this.cwd = typeof path13 === "string" ? this.cwd.resolve(path13) : path13;
24033
24051
  this.cwd[setAsCwd](oldCwd);
24034
24052
  }
24035
24053
  };
@@ -24391,8 +24409,8 @@ var MatchRecord = class {
24391
24409
  }
24392
24410
  // match, absolute, ifdir
24393
24411
  entries() {
24394
- return [...this.store.entries()].map(([path12, n]) => [
24395
- path12,
24412
+ return [...this.store.entries()].map(([path13, n]) => [
24413
+ path13,
24396
24414
  !!(n & 2),
24397
24415
  !!(n & 1)
24398
24416
  ]);
@@ -24597,9 +24615,9 @@ var GlobUtil = class {
24597
24615
  signal;
24598
24616
  maxDepth;
24599
24617
  includeChildMatches;
24600
- constructor(patterns, path12, opts) {
24618
+ constructor(patterns, path13, opts) {
24601
24619
  this.patterns = patterns;
24602
- this.path = path12;
24620
+ this.path = path13;
24603
24621
  this.opts = opts;
24604
24622
  this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
24605
24623
  this.includeChildMatches = opts.includeChildMatches !== false;
@@ -24618,11 +24636,11 @@ var GlobUtil = class {
24618
24636
  });
24619
24637
  }
24620
24638
  }
24621
- #ignored(path12) {
24622
- return this.seen.has(path12) || !!this.#ignore?.ignored?.(path12);
24639
+ #ignored(path13) {
24640
+ return this.seen.has(path13) || !!this.#ignore?.ignored?.(path13);
24623
24641
  }
24624
- #childrenIgnored(path12) {
24625
- return !!this.#ignore?.childrenIgnored?.(path12);
24642
+ #childrenIgnored(path13) {
24643
+ return !!this.#ignore?.childrenIgnored?.(path13);
24626
24644
  }
24627
24645
  // backpressure mechanism
24628
24646
  pause() {
@@ -24837,8 +24855,8 @@ var GlobUtil = class {
24837
24855
  };
24838
24856
  var GlobWalker = class extends GlobUtil {
24839
24857
  matches = /* @__PURE__ */ new Set();
24840
- constructor(patterns, path12, opts) {
24841
- super(patterns, path12, opts);
24858
+ constructor(patterns, path13, opts) {
24859
+ super(patterns, path13, opts);
24842
24860
  }
24843
24861
  matchEmit(e) {
24844
24862
  this.matches.add(e);
@@ -24875,8 +24893,8 @@ var GlobWalker = class extends GlobUtil {
24875
24893
  };
24876
24894
  var GlobStream = class extends GlobUtil {
24877
24895
  results;
24878
- constructor(patterns, path12, opts) {
24879
- super(patterns, path12, opts);
24896
+ constructor(patterns, path13, opts) {
24897
+ super(patterns, path13, opts);
24880
24898
  this.results = new Minipass({
24881
24899
  signal: this.signal,
24882
24900
  objectMode: true
@@ -26384,7 +26402,7 @@ Subquery.prototype.getSQL = function() {
26384
26402
  function mapResultRow(columns, row, joinsNotNullableMap) {
26385
26403
  const nullifyMap = {};
26386
26404
  const result = columns.reduce(
26387
- (result2, { path: path12, field }, columnIndex) => {
26405
+ (result2, { path: path13, field }, columnIndex) => {
26388
26406
  let decoder;
26389
26407
  if (is(field, Column)) {
26390
26408
  decoder = field;
@@ -26396,8 +26414,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
26396
26414
  decoder = field.sql.decoder;
26397
26415
  }
26398
26416
  let node = result2;
26399
- for (const [pathChunkIndex, pathChunk] of path12.entries()) {
26400
- if (pathChunkIndex < path12.length - 1) {
26417
+ for (const [pathChunkIndex, pathChunk] of path13.entries()) {
26418
+ if (pathChunkIndex < path13.length - 1) {
26401
26419
  if (!(pathChunk in node)) {
26402
26420
  node[pathChunk] = {};
26403
26421
  }
@@ -26405,8 +26423,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
26405
26423
  } else {
26406
26424
  const rawValue = row[columnIndex];
26407
26425
  const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
26408
- if (joinsNotNullableMap && is(field, Column) && path12.length === 2) {
26409
- const objectName = path12[0];
26426
+ if (joinsNotNullableMap && is(field, Column) && path13.length === 2) {
26427
+ const objectName = path13[0];
26410
26428
  if (!(objectName in nullifyMap)) {
26411
26429
  nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
26412
26430
  } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
@@ -28669,24 +28687,24 @@ var SQLiteSelectBuilder = class {
28669
28687
  this.withList = config2.withList;
28670
28688
  this.distinct = config2.distinct;
28671
28689
  }
28672
- from(source5) {
28690
+ from(source6) {
28673
28691
  const isPartialSelect = !!this.fields;
28674
28692
  let fields;
28675
28693
  if (this.fields) {
28676
28694
  fields = this.fields;
28677
- } else if (is(source5, Subquery)) {
28695
+ } else if (is(source6, Subquery)) {
28678
28696
  fields = Object.fromEntries(
28679
- Object.keys(source5._.selectedFields).map((key) => [key, source5[key]])
28697
+ Object.keys(source6._.selectedFields).map((key) => [key, source6[key]])
28680
28698
  );
28681
- } else if (is(source5, SQLiteViewBase)) {
28682
- fields = source5[ViewBaseConfig].selectedFields;
28683
- } else if (is(source5, SQL)) {
28699
+ } else if (is(source6, SQLiteViewBase)) {
28700
+ fields = source6[ViewBaseConfig].selectedFields;
28701
+ } else if (is(source6, SQL)) {
28684
28702
  fields = {};
28685
28703
  } else {
28686
- fields = getTableColumns(source5);
28704
+ fields = getTableColumns(source6);
28687
28705
  }
28688
28706
  return new SQLiteSelectBase({
28689
- table: source5,
28707
+ table: source6,
28690
28708
  fields,
28691
28709
  isPartialSelect,
28692
28710
  session: this.session,
@@ -29590,8 +29608,8 @@ var SQLiteUpdateBase = class extends QueryPromise {
29590
29608
  static [entityKind] = "SQLiteUpdate";
29591
29609
  /** @internal */
29592
29610
  config;
29593
- from(source5) {
29594
- this.config.from = source5;
29611
+ from(source6) {
29612
+ this.config.from = source6;
29595
29613
  return this;
29596
29614
  }
29597
29615
  createJoin(joinType) {
@@ -29743,11 +29761,11 @@ var SQLiteCountBuilder = class _SQLiteCountBuilder extends SQL {
29743
29761
  static [entityKind] = "SQLiteCountBuilderAsync";
29744
29762
  [Symbol.toStringTag] = "SQLiteCountBuilderAsync";
29745
29763
  session;
29746
- static buildEmbeddedCount(source5, filters) {
29747
- return sql`(select count(*) from ${source5}${sql.raw(" where ").if(filters)}${filters})`;
29764
+ static buildEmbeddedCount(source6, filters) {
29765
+ return sql`(select count(*) from ${source6}${sql.raw(" where ").if(filters)}${filters})`;
29748
29766
  }
29749
- static buildCount(source5, filters) {
29750
- return sql`select count(*) from ${source5}${sql.raw(" where ").if(filters)}${filters}`;
29767
+ static buildCount(source6, filters) {
29768
+ return sql`select count(*) from ${source6}${sql.raw(" where ").if(filters)}${filters}`;
29751
29769
  }
29752
29770
  then(onfulfilled, onrejected) {
29753
29771
  return Promise.resolve(this.session.count(this.sql)).then(
@@ -30032,8 +30050,8 @@ var BaseSQLiteDatabase = class {
30032
30050
  };
30033
30051
  return { as };
30034
30052
  };
30035
- $count(source5, filters) {
30036
- return new SQLiteCountBuilder({ source: source5, filters, session: this.session });
30053
+ $count(source6, filters) {
30054
+ return new SQLiteCountBuilder({ source: source6, filters, session: this.session });
30037
30055
  }
30038
30056
  /**
30039
30057
  * Incorporates a previously defined CTE (using `$with`) into the main query.
@@ -30607,8 +30625,8 @@ function drizzle(...params) {
30607
30625
  const { connection, client, ...drizzleConfig } = params[0];
30608
30626
  if (client) return construct(client, drizzleConfig);
30609
30627
  if (typeof connection === "object") {
30610
- const { source: source5, ...options2 } = connection;
30611
- const instance2 = new import_better_sqlite3.default(source5, options2);
30628
+ const { source: source6, ...options2 } = connection;
30629
+ const instance2 = new import_better_sqlite3.default(source6, options2);
30612
30630
  return construct(instance2, drizzleConfig);
30613
30631
  }
30614
30632
  const instance = new import_better_sqlite3.default(connection);
@@ -30749,8 +30767,8 @@ var monitorFrontmatterSchema = external_exports.object({
30749
30767
  notify: notifySchema.optional(),
30750
30768
  tags: external_exports.array(external_exports.string()).optional()
30751
30769
  });
30752
- function validateScope(scope, scopeSchema5) {
30753
- const validator = new Validator(scopeSchema5, "7", false);
30770
+ function validateScope(scope, scopeSchema6) {
30771
+ const validator = new Validator(scopeSchema6, "7", false);
30754
30772
  const result = validator.validate(scope);
30755
30773
  if (result.valid) return [];
30756
30774
  const messages = result.errors.map((unit) => {
@@ -31224,13 +31242,13 @@ var InboxService = class {
31224
31242
  };
31225
31243
  var SourceRegistry = class {
31226
31244
  sources = /* @__PURE__ */ new Map();
31227
- register(source5) {
31228
- if (this.sources.has(source5.name)) {
31245
+ register(source6) {
31246
+ if (this.sources.has(source6.name)) {
31229
31247
  throw new Error(
31230
- `Observation source "${source5.name}" is already registered`
31248
+ `Observation source "${source6.name}" is already registered`
31231
31249
  );
31232
31250
  }
31233
- this.sources.set(source5.name, source5);
31251
+ this.sources.set(source6.name, source6);
31234
31252
  }
31235
31253
  get(name) {
31236
31254
  return this.sources.get(name);
@@ -31247,7 +31265,7 @@ var SourceRegistry = class {
31247
31265
  };
31248
31266
  function generateMonitorSchema(sources) {
31249
31267
  const sourceNames = sources.map((s) => s.name);
31250
- const conditionals = sources.map((source5) => ({
31268
+ const conditionals = sources.map((source6) => ({
31251
31269
  if: {
31252
31270
  // `required: ['type']` on the inner `watch` is essential: JSON Schema
31253
31271
  // `properties` constraints are vacuously satisfied when the property is
@@ -31256,14 +31274,14 @@ function generateMonitorSchema(sources) {
31256
31274
  // instead of a clean "watch.type is required".
31257
31275
  properties: {
31258
31276
  watch: {
31259
- properties: { type: { const: source5.name } },
31277
+ properties: { type: { const: source6.name } },
31260
31278
  required: ["type"]
31261
31279
  }
31262
31280
  },
31263
31281
  required: ["watch"]
31264
31282
  },
31265
31283
  then: {
31266
- properties: { watch: source5.scopeSchema }
31284
+ properties: { watch: source6.scopeSchema }
31267
31285
  }
31268
31286
  }));
31269
31287
  return {
@@ -31315,6 +31333,195 @@ function generateMonitorSchema(sources) {
31315
31333
  allOf: conditionals
31316
31334
  };
31317
31335
  }
31336
+ function parseKeyedCollectionConfig(changeDetection) {
31337
+ if (changeDetection === null || typeof changeDetection !== "object" || Array.isArray(changeDetection)) {
31338
+ return void 0;
31339
+ }
31340
+ const collection = changeDetection["collection"];
31341
+ if (collection === void 0) return void 0;
31342
+ if (collection === null || typeof collection !== "object" || Array.isArray(collection)) {
31343
+ throw new Error(
31344
+ 'change-detection.collection must be an object with "path" and "key"'
31345
+ );
31346
+ }
31347
+ const c = collection;
31348
+ const path72 = c["path"];
31349
+ if (typeof path72 !== "string" || path72.length === 0) {
31350
+ throw new Error(
31351
+ "change-detection.collection.path must be a non-empty string"
31352
+ );
31353
+ }
31354
+ const key = c["key"];
31355
+ if (typeof key !== "string" || key.length === 0) {
31356
+ throw new Error(
31357
+ "change-detection.collection.key must be a non-empty string"
31358
+ );
31359
+ }
31360
+ const rawIgnore = c["ignore-paths"];
31361
+ let ignorePaths;
31362
+ if (rawIgnore !== void 0) {
31363
+ if (!Array.isArray(rawIgnore) || !rawIgnore.every((p) => typeof p === "string")) {
31364
+ throw new Error(
31365
+ "change-detection.collection.ignore-paths must be an array of strings"
31366
+ );
31367
+ }
31368
+ ignorePaths = rawIgnore;
31369
+ }
31370
+ return ignorePaths ? { path: path72, key, ignorePaths } : { path: path72, key };
31371
+ }
31372
+ function assertValidSegment(path72, segment) {
31373
+ if (/[[\]*?\s]/.test(segment)) {
31374
+ throw new Error(
31375
+ `Invalid collection path "${path72}": segment "${segment}" contains unsupported syntax (only plain field names are allowed \u2014 no "[index]", wildcards, or filters)`
31376
+ );
31377
+ }
31378
+ }
31379
+ function normalizeDottedPath(path72) {
31380
+ if (path72 === "$" || path72.startsWith("$.")) return path72;
31381
+ if (path72.startsWith("$")) {
31382
+ throw new Error(
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.`
31384
+ );
31385
+ }
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(".");
31392
+ let current = root;
31393
+ for (const segment of segments) {
31394
+ if (segment.length === 0) {
31395
+ throw new Error(`Invalid collection path "${path72}": empty path segment`);
31396
+ }
31397
+ assertValidSegment(path72, segment);
31398
+ if (current === null || typeof current !== "object" || Array.isArray(current)) {
31399
+ return void 0;
31400
+ }
31401
+ current = current[segment];
31402
+ }
31403
+ return current;
31404
+ }
31405
+ function removeDottedPath(value, path72) {
31406
+ const normalizedPath = normalizeDottedPath(path72);
31407
+ if (normalizedPath === "$") return;
31408
+ const segments = normalizedPath.slice(2).split(".");
31409
+ let current = value;
31410
+ for (let i = 0; i < segments.length - 1; i++) {
31411
+ const segment = segments[i];
31412
+ if (segment === void 0 || segment.length === 0) {
31413
+ throw new Error(
31414
+ `Invalid ignore-paths entry "${path72}": empty path segment`
31415
+ );
31416
+ }
31417
+ assertValidSegment(path72, segment);
31418
+ if (current === null || typeof current !== "object" || Array.isArray(current)) {
31419
+ return;
31420
+ }
31421
+ current = current[segment];
31422
+ }
31423
+ const last = segments[segments.length - 1];
31424
+ if (last === void 0 || last.length === 0) {
31425
+ throw new Error(`Invalid ignore-paths entry "${path72}": empty path segment`);
31426
+ }
31427
+ assertValidSegment(path72, last);
31428
+ if (current !== null && typeof current === "object" && !Array.isArray(current)) {
31429
+ Reflect.deleteProperty(current, last);
31430
+ }
31431
+ }
31432
+ function sortKeys(value) {
31433
+ if (Array.isArray(value)) return value.map(sortKeys);
31434
+ if (value !== null && typeof value === "object") {
31435
+ const sorted = {};
31436
+ for (const k of Object.keys(value).sort()) {
31437
+ sorted[k] = sortKeys(value[k]);
31438
+ }
31439
+ return sorted;
31440
+ }
31441
+ return value;
31442
+ }
31443
+ function normalizeElement(element, ignorePaths) {
31444
+ const clone2 = structuredClone(element);
31445
+ if (ignorePaths) {
31446
+ for (const p of ignorePaths) removeDottedPath(clone2, p);
31447
+ }
31448
+ return sortKeys(clone2);
31449
+ }
31450
+ function serialize(value) {
31451
+ return JSON.stringify(value);
31452
+ }
31453
+ function keyValueOf(element, keyField) {
31454
+ if (element === null || typeof element !== "object" || Array.isArray(element)) {
31455
+ throw new Error(
31456
+ `collection element is not an object (cannot read key "${keyField}")`
31457
+ );
31458
+ }
31459
+ const raw = element[keyField];
31460
+ if (typeof raw === "string") return raw;
31461
+ if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
31462
+ throw new Error(
31463
+ `collection element is missing a scalar key field "${keyField}"`
31464
+ );
31465
+ }
31466
+ function diffKeyedCollection(parsedOutput, config2, monitorObjectKey, previousSnapshot, observationFields) {
31467
+ const resolved = resolveDottedPath(parsedOutput, config2.path);
31468
+ if (!Array.isArray(resolved)) {
31469
+ throw new Error(
31470
+ `collection path "${config2.path}" must select an array (got ${resolved === void 0 ? "nothing" : typeof resolved})`
31471
+ );
31472
+ }
31473
+ const current = {};
31474
+ for (const element of resolved) {
31475
+ const keyValue = keyValueOf(element, config2.key);
31476
+ if (Object.prototype.hasOwnProperty.call(current, keyValue)) {
31477
+ throw new Error(
31478
+ `collection key "${config2.key}" value "${keyValue}" is not unique within the collection`
31479
+ );
31480
+ }
31481
+ current[keyValue] = normalizeElement(element, config2.ignorePaths);
31482
+ }
31483
+ if (previousSnapshot === void 0) {
31484
+ return { observations: [], snapshot: current };
31485
+ }
31486
+ const observations = [];
31487
+ const emit = (keyValue, changeKind) => {
31488
+ const objectKey = `${monitorObjectKey}#${keyValue}`;
31489
+ const title = `${titleVerb(changeKind)}: ${objectKey}`;
31490
+ observations.push({
31491
+ title,
31492
+ summary: title,
31493
+ objectKey,
31494
+ changeKind,
31495
+ payload: { ...observationFields?.payload, key: keyValue, changeKind },
31496
+ queryScope: { ...observationFields?.queryScope, objectKey }
31497
+ });
31498
+ };
31499
+ for (const keyValue of Object.keys(current)) {
31500
+ if (!Object.prototype.hasOwnProperty.call(previousSnapshot, keyValue)) {
31501
+ emit(keyValue, "created");
31502
+ } else if (serialize(current[keyValue]) !== serialize(previousSnapshot[keyValue])) {
31503
+ emit(keyValue, "modified");
31504
+ }
31505
+ }
31506
+ for (const keyValue of Object.keys(previousSnapshot)) {
31507
+ if (!Object.prototype.hasOwnProperty.call(current, keyValue)) {
31508
+ emit(keyValue, "descoped");
31509
+ }
31510
+ }
31511
+ return { observations, snapshot: current };
31512
+ }
31513
+ function titleVerb(changeKind) {
31514
+ switch (changeKind) {
31515
+ case "created":
31516
+ return "Item added";
31517
+ case "modified":
31518
+ return "Item changed";
31519
+ case "descoped":
31520
+ return "Item removed";
31521
+ case "deleted":
31522
+ return "Item deleted";
31523
+ }
31524
+ }
31318
31525
  function parseDuration(duration3) {
31319
31526
  const match2 = /^(?<digits>\d+)(?<unit>[smhd])$/.exec(duration3);
31320
31527
  const digits = match2?.groups?.["digits"];
@@ -31472,6 +31679,11 @@ function rowToEvent(row) {
31472
31679
  createdAt: row.createdAt
31473
31680
  };
31474
31681
  }
31682
+ function deliveryStateForRow(row) {
31683
+ if (row.acknowledgedAt) return "acknowledged";
31684
+ if (row.firstNotifiedAt) return "claimed";
31685
+ return "unread";
31686
+ }
31475
31687
  function scopeMatches(eventScope, requested) {
31476
31688
  if (!requested) return true;
31477
31689
  for (const [key, value] of Object.entries(requested)) {
@@ -31639,6 +31851,13 @@ var RuntimeStore = class {
31639
31851
  if (query.objectKey)
31640
31852
  conditions.push(eq(monitorEvents.objectKey, query.objectKey));
31641
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
+ }
31642
31861
  let rows = query.sessionId ? asInternalDb2(this.db).select({
31643
31862
  event: monitorEvents,
31644
31863
  state: sessionEventState
@@ -31713,6 +31932,37 @@ var RuntimeStore = class {
31713
31932
  createdAt: row.createdAt
31714
31933
  }));
31715
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
+ }
31716
31966
  sessionsForWorkspace(workspacePath) {
31717
31967
  return asInternalDb2(this.db).select().from(agentSessions).where(
31718
31968
  workspacePath == null ? isNull(agentSessions.workspacePath) : or(
@@ -31820,6 +32070,14 @@ var DEFAULT_FILE_FINGERPRINT_POLL_MS = 3e4;
31820
32070
  var DEFAULT_API_POLL_MS = 3e5;
31821
32071
  var DEFAULT_HIGH_URGENCY_SETTLE_MS = 15e3;
31822
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
+ };
31823
32081
  function watchConfig(watch) {
31824
32082
  const { type: _type, ...config2 } = watch;
31825
32083
  return config2;
@@ -31838,6 +32096,28 @@ function writeJsonAtomic(filePath2, payload) {
31838
32096
  (0, import_fs3.writeFileSync)(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
31839
32097
  (0, import_fs3.renameSync)(tmpPath, filePath2);
31840
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
+ }
31841
32121
  function serializeObservation(monitor, observation, observedAt) {
31842
32122
  return { monitor, observation, observedAt };
31843
32123
  }
@@ -31952,6 +32232,320 @@ var AgentMonitorRuntime = class {
31952
32232
  listObservationHistory(query = {}) {
31953
32233
  return this.store.listObservationHistory(query);
31954
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
+ }
31955
32549
  acknowledgeSession(sessionId, eventIds) {
31956
32550
  const ids = eventIds ?? this.store.unreadEventsForSession(sessionId).map((e) => e.id);
31957
32551
  this.store.acknowledgeEvents(sessionId, ids);
@@ -32099,8 +32693,8 @@ var AgentMonitorRuntime = class {
32099
32693
  for (const parsed of result.monitors) {
32100
32694
  const monitor = parsed.monitor;
32101
32695
  const sourceName = monitor.frontmatter.watch.type;
32102
- const source5 = this.registry.get(sourceName);
32103
- if (!source5) {
32696
+ const source6 = this.registry.get(sourceName);
32697
+ if (!source6) {
32104
32698
  throw new Error(
32105
32699
  `Monitor "${monitor.id}" references unknown source "${sourceName}".`
32106
32700
  );
@@ -32112,7 +32706,7 @@ var AgentMonitorRuntime = class {
32112
32706
  let observationResult;
32113
32707
  try {
32114
32708
  const monitorState2 = this.store.getMonitorState(monitor.id);
32115
- observationResult = await source5.observe(
32709
+ observationResult = await source6.observe(
32116
32710
  watchConfig(monitor.frontmatter.watch),
32117
32711
  {
32118
32712
  previousState: monitorState2.sourceState,
@@ -32263,18 +32857,18 @@ var AgentMonitorRuntime = class {
32263
32857
  for (const parsed of result.monitors) {
32264
32858
  const monitor = parsed.monitor;
32265
32859
  const sourceName = monitor.frontmatter.watch.type;
32266
- const source5 = this.registry.get(sourceName);
32267
- if (!source5) {
32860
+ const source6 = this.registry.get(sourceName);
32861
+ if (!source6) {
32268
32862
  throw new Error(
32269
32863
  `Monitor "${monitor.id}" references unknown source "${sourceName}".`
32270
32864
  );
32271
32865
  }
32272
- if (!source5.watch) continue;
32866
+ if (!source6.watch) continue;
32273
32867
  if (this.activeWatchers.has(monitor.id)) continue;
32274
32868
  const controller = new AbortController();
32275
32869
  controllers.set(monitor.id, controller);
32276
32870
  this.activeWatchers.add(monitor.id);
32277
- const watch = source5.watch.bind(source5);
32871
+ const watch = source6.watch.bind(source6);
32278
32872
  tasks.push(
32279
32873
  this.consumeWatch(
32280
32874
  monitor,
@@ -32668,12 +33262,17 @@ function parseScopeConfig2(config2) {
32668
33262
  const cd = config2["change-detection"];
32669
33263
  const strategy = cd?.strategy;
32670
33264
  const changeDetection = strategy === "status-code" || strategy === "json-diff" ? strategy : "text-diff";
33265
+ const collection = parseKeyedCollectionConfig(config2["change-detection"]);
33266
+ if (collection && changeDetection !== "json-diff") {
33267
+ throw new Error("change-detection.collection requires strategy: json-diff");
33268
+ }
32671
33269
  return {
32672
33270
  url,
32673
33271
  auth: config2["auth"],
32674
33272
  headers: config2["headers"],
32675
33273
  method: typeof config2["method"] === "string" ? config2["method"] : void 0,
32676
- changeDetection
33274
+ changeDetection,
33275
+ collection
32677
33276
  };
32678
33277
  }
32679
33278
  function resolveAuth(auth) {
@@ -32693,12 +33292,12 @@ function resolveAuth(auth) {
32693
33292
  const encoded = Buffer.from(`${username}:${password}`).toString("base64");
32694
33293
  return { Authorization: `Basic ${encoded}` };
32695
33294
  }
32696
- function sortKeys(value) {
32697
- if (Array.isArray(value)) return value.map(sortKeys);
33295
+ function sortKeys2(value) {
33296
+ if (Array.isArray(value)) return value.map(sortKeys2);
32698
33297
  if (value !== null && typeof value === "object") {
32699
33298
  const sorted = {};
32700
33299
  for (const key of Object.keys(value).sort()) {
32701
- sorted[key] = sortKeys(value[key]);
33300
+ sorted[key] = sortKeys2(value[key]);
32702
33301
  }
32703
33302
  return sorted;
32704
33303
  }
@@ -32710,8 +33309,8 @@ function hasChanged(strategy, prev, curr) {
32710
33309
  return prev.status !== curr.status;
32711
33310
  case "json-diff":
32712
33311
  try {
32713
- const prevJson = JSON.stringify(sortKeys(JSON.parse(prev.body)));
32714
- const currJson = JSON.stringify(sortKeys(JSON.parse(curr.body)));
33312
+ const prevJson = JSON.stringify(sortKeys2(JSON.parse(prev.body)));
33313
+ const currJson = JSON.stringify(sortKeys2(JSON.parse(curr.body)));
32715
33314
  return prevJson !== currJson;
32716
33315
  } catch {
32717
33316
  return prev.body !== curr.body;
@@ -32750,7 +33349,37 @@ var scopeSchema2 = {
32750
33349
  strategy: {
32751
33350
  type: "string",
32752
33351
  enum: ["json-diff", "text-diff", "status-code"]
33352
+ },
33353
+ // Keyed-collection mode (003 §12). The `collection` block is only valid
33354
+ // under `strategy: json-diff`; the `if/then` below enforces that at
33355
+ // authoring time (BP3).
33356
+ collection: {
33357
+ type: "object",
33358
+ properties: {
33359
+ path: {
33360
+ type: "string",
33361
+ description: 'Dotted path to the array within the parsed JSON (e.g. "tasks" or "$.tasks")'
33362
+ },
33363
+ key: {
33364
+ type: "string",
33365
+ description: "Field on each element used as the per-object identity"
33366
+ },
33367
+ "ignore-paths": {
33368
+ type: "array",
33369
+ items: { type: "string" },
33370
+ description: 'Dotted paths (relative to each element, e.g. "fetchedAt" or "$.fetchedAt") removed before comparison'
33371
+ }
33372
+ },
33373
+ required: ["path", "key"]
32753
33374
  }
33375
+ },
33376
+ // BP3: change-detection.collection requires strategy: json-diff. Under any
33377
+ // other strategy (or the defaulted text-diff), presence of `collection` is an
33378
+ // authoring-time error.
33379
+ if: { required: ["collection"] },
33380
+ then: {
33381
+ properties: { strategy: { const: "json-diff" } },
33382
+ required: ["strategy"]
32754
33383
  }
32755
33384
  }
32756
33385
  },
@@ -32761,15 +33390,30 @@ var source2 = {
32761
33390
  stateful: true,
32762
33391
  scopeSchema: scopeSchema2,
32763
33392
  async observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
32764
- const { url, auth, headers, method, changeDetection } = parseScopeConfig2(config2);
33393
+ const { url, auth, headers, method, changeDetection, collection } = parseScopeConfig2(config2);
32765
33394
  const authHeaders = resolveAuth(auth);
32766
33395
  const response = await fetch(url, {
32767
33396
  method: method ?? "GET",
32768
33397
  headers: { ...authHeaders, ...headers }
32769
33398
  });
32770
33399
  const body = await response.text();
32771
- const curr = { body, status: response.status };
32772
33400
  const prev = context.previousState && typeof context.previousState === "object" && !Array.isArray(context.previousState) ? context.previousState : void 0;
33401
+ if (collection) {
33402
+ const result = diffKeyedCollection(
33403
+ JSON.parse(body),
33404
+ collection,
33405
+ url,
33406
+ prev?.keyedSnapshot,
33407
+ { payload: { url }, queryScope: { url } }
33408
+ );
33409
+ const curr2 = {
33410
+ body,
33411
+ status: response.status,
33412
+ keyedSnapshot: result.snapshot
33413
+ };
33414
+ return { observations: result.observations, nextState: curr2 };
33415
+ }
33416
+ const curr = { body, status: response.status };
32773
33417
  if (prev !== void 0 && hasChanged(changeDetection, prev, curr)) {
32774
33418
  return {
32775
33419
  observations: [
@@ -32804,9 +33448,425 @@ var source2 = {
32804
33448
  };
32805
33449
  var index_default2 = source2;
32806
33450
 
32807
- // ../../plugins/source-schedule/dist/index.js
33451
+ // ../../plugins/source-command-poll/dist/index.js
32808
33452
  init_cjs_shims();
33453
+ var import_child_process = require("child_process");
33454
+ var DEFAULT_TIMEOUT_MS = 3e4;
33455
+ var SIGKILL_GRACE_MS = 5e3;
33456
+ var STDOUT_CAP_BYTES = 1024 * 1024;
33457
+ var STDERR_TAIL_CHARS = 2e3;
32809
33458
  function parseScopeConfig3(config2) {
33459
+ const command = config2["command"];
33460
+ if (!Array.isArray(command) || command.length === 0 || !command.every((c) => typeof c === "string")) {
33461
+ throw new Error(
33462
+ 'scope.command must be a non-empty array of strings (argv form, e.g. ["git", "status"])'
33463
+ );
33464
+ }
33465
+ const cd = config2["change-detection"];
33466
+ const rawStrategy = cd?.strategy;
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
+ }
33474
+ const collection = parseKeyedCollectionConfig(config2["change-detection"]);
33475
+ if (collection && strategy !== "json-diff") {
33476
+ throw new Error("change-detection.collection requires strategy: json-diff");
33477
+ }
33478
+ const cwd = typeof config2["cwd"] === "string" ? config2["cwd"] : void 0;
33479
+ const rawEnv = config2["env"];
33480
+ const env = rawEnv !== null && typeof rawEnv === "object" && !Array.isArray(rawEnv) && Object.values(rawEnv).every((v) => typeof v === "string") ? rawEnv : void 0;
33481
+ const rawTimeout = config2["timeout"];
33482
+ const timeoutMs = typeof rawTimeout === "string" ? parseDuration(rawTimeout) : DEFAULT_TIMEOUT_MS;
33483
+ const key = config2["key"];
33484
+ const objectKey = typeof key === "string" && key.length > 0 ? key : command.join(" ");
33485
+ return {
33486
+ command,
33487
+ cwd,
33488
+ env,
33489
+ timeoutMs,
33490
+ objectKey,
33491
+ strategy,
33492
+ ignorePaths,
33493
+ collection
33494
+ };
33495
+ }
33496
+ async function runCommand(scope) {
33497
+ return new Promise((resolve) => {
33498
+ const [file, ...args] = scope.command;
33499
+ const child = (0, import_child_process.execFile)(
33500
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
33501
+ file,
33502
+ args,
33503
+ {
33504
+ cwd: scope.cwd,
33505
+ // `env` is merged over the inherited daemon environment (003 §11.1).
33506
+ env: scope.env ? { ...process.env, ...scope.env } : process.env,
33507
+ // We enforce the timeout ourselves (SIGTERM→SIGKILL) rather than relying on
33508
+ // execFile's `timeout`, so the grace escalation matches the spec exactly.
33509
+ shell: false,
33510
+ // Bound stdout capture at the 1 MiB cap (003 §11.2). When the child overruns,
33511
+ // execFile kills it and reports ERR_CHILD_PROCESS_STDIO_MAXBUFFER with the
33512
+ // captured-so-far bytes — we treat that as a truncated result, not a failure.
33513
+ maxBuffer: STDOUT_CAP_BYTES,
33514
+ encoding: "buffer"
33515
+ },
33516
+ (error2, stdoutBuf, stderrBuf) => {
33517
+ if (settled) return;
33518
+ settled = true;
33519
+ clearTimeout(killTimer);
33520
+ clearTimeout(graceTimer);
33521
+ const stderrFull = stderrBuf instanceof Buffer ? stderrBuf.toString("utf8") : "";
33522
+ const stderrTail = stderrFull.slice(-STDERR_TAIL_CHARS);
33523
+ const err = error2;
33524
+ const overflowed = err?.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
33525
+ if (timedOut) {
33526
+ resolve({
33527
+ kind: "failure",
33528
+ error: `Command timed out after ${String(scope.timeoutMs)}ms`,
33529
+ stderrTail
33530
+ });
33531
+ return;
33532
+ }
33533
+ if (err !== null && typeof err.code === "string" && !overflowed) {
33534
+ resolve({
33535
+ kind: "failure",
33536
+ error: err.message,
33537
+ stderrTail
33538
+ });
33539
+ return;
33540
+ }
33541
+ const buf = Buffer.isBuffer(stdoutBuf) ? stdoutBuf : Buffer.from(String(stdoutBuf), "utf8");
33542
+ const { text: text2, truncated } = capStdout(buf, overflowed);
33543
+ const exitCode = err != null && typeof err.code === "number" ? err.code : 0;
33544
+ resolve({
33545
+ kind: "result",
33546
+ result: { stdout: text2, exitCode, truncated }
33547
+ });
33548
+ }
33549
+ );
33550
+ let settled = false;
33551
+ let timedOut = false;
33552
+ let graceTimer;
33553
+ const killTimer = setTimeout(() => {
33554
+ timedOut = true;
33555
+ child.kill("SIGTERM");
33556
+ graceTimer = setTimeout(() => {
33557
+ child.kill("SIGKILL");
33558
+ }, SIGKILL_GRACE_MS);
33559
+ graceTimer.unref();
33560
+ }, scope.timeoutMs);
33561
+ killTimer.unref();
33562
+ });
33563
+ }
33564
+ function capStdout(stdout, overflowed) {
33565
+ const truncated = overflowed || stdout.length > STDOUT_CAP_BYTES;
33566
+ const slice = stdout.length > STDOUT_CAP_BYTES ? stdout.subarray(0, STDOUT_CAP_BYTES) : stdout;
33567
+ return { text: slice.toString("utf8"), truncated };
33568
+ }
33569
+ function sortKeys3(value) {
33570
+ if (Array.isArray(value)) return value.map(sortKeys3);
33571
+ if (value !== null && typeof value === "object") {
33572
+ const sorted = {};
33573
+ for (const key of Object.keys(value).sort()) {
33574
+ sorted[key] = sortKeys3(value[key]);
33575
+ }
33576
+ return sorted;
33577
+ }
33578
+ return value;
33579
+ }
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) {
33633
+ switch (strategy) {
33634
+ case "exit-code":
33635
+ return prev.exitCode !== curr.exitCode;
33636
+ case "json-diff": {
33637
+ let prevParsed;
33638
+ let currParsed;
33639
+ try {
33640
+ prevParsed = JSON.parse(prev.stdout);
33641
+ currParsed = JSON.parse(curr.stdout);
33642
+ } catch {
33643
+ return prev.stdout !== curr.stdout;
33644
+ }
33645
+ return JSON.stringify(
33646
+ sortKeys3(stripIgnoredJsonPaths(prevParsed, ignorePaths))
33647
+ ) !== JSON.stringify(sortKeys3(stripIgnoredJsonPaths(currParsed, ignorePaths)));
33648
+ }
33649
+ case "text-diff":
33650
+ return prev.stdout !== curr.stdout;
33651
+ }
33652
+ }
33653
+ function isCommandState(value) {
33654
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
33655
+ return false;
33656
+ }
33657
+ const v = value;
33658
+ return typeof v["stdout"] === "string" && typeof v["exitCode"] === "number" && typeof v["truncated"] === "boolean" && (v["health"] === "ok" || v["health"] === "failing") && typeof v["baselined"] === "boolean";
33659
+ }
33660
+ function changedObservation(scope, result) {
33661
+ return {
33662
+ title: `Command output changed: ${scope.objectKey}`,
33663
+ summary: `Command output changed: ${scope.objectKey}`,
33664
+ payload: {
33665
+ command: scope.command,
33666
+ exitCode: result.exitCode,
33667
+ strategy: scope.strategy,
33668
+ stdout: result.stdout,
33669
+ truncated: result.truncated
33670
+ },
33671
+ snapshotText: result.stdout,
33672
+ objectKey: scope.objectKey,
33673
+ queryScope: { command: scope.objectKey },
33674
+ snapshot: {
33675
+ command: scope.command,
33676
+ exitCode: result.exitCode,
33677
+ stdoutLength: result.stdout.length,
33678
+ strategy: scope.strategy
33679
+ },
33680
+ changeKind: "modified"
33681
+ };
33682
+ }
33683
+ var scopeSchema3 = {
33684
+ type: "object",
33685
+ properties: {
33686
+ command: {
33687
+ type: "array",
33688
+ items: { type: "string" },
33689
+ minItems: 1,
33690
+ description: "Argv array; command[0] is the executable (resolved via PATH). Spawned directly, never via a shell."
33691
+ },
33692
+ cwd: {
33693
+ type: "string",
33694
+ description: "Working directory for the child process"
33695
+ },
33696
+ env: {
33697
+ type: "object",
33698
+ additionalProperties: { type: "string" },
33699
+ description: "Literal env vars merged over the inherited daemon environment"
33700
+ },
33701
+ timeout: {
33702
+ type: "string",
33703
+ pattern: "^\\d+[smhd]$",
33704
+ description: 'Wall-clock limit (e.g. "30s"). Expiry is an execution failure.'
33705
+ },
33706
+ key: {
33707
+ type: "string",
33708
+ description: "Overrides the observation objectKey (defaults to the joined argv)"
33709
+ },
33710
+ interval: {
33711
+ type: "string",
33712
+ pattern: "^\\d+[smhd]$",
33713
+ description: 'Polling interval (e.g., "5m"). Used by the scheduling engine, not by this plugin directly.'
33714
+ },
33715
+ "change-detection": {
33716
+ type: "object",
33717
+ properties: {
33718
+ strategy: {
33719
+ type: "string",
33720
+ enum: ["text-diff", "json-diff", "exit-code"]
33721
+ },
33722
+ // Keyed-collection mode (003 §12). The `collection` block is only valid
33723
+ // under `strategy: json-diff`; the `if/then` below enforces that at
33724
+ // authoring time (BP3).
33725
+ collection: {
33726
+ type: "object",
33727
+ properties: {
33728
+ path: {
33729
+ type: "string",
33730
+ description: 'Dotted path to the array within the parsed JSON (e.g. "tasks" or "$.tasks")'
33731
+ },
33732
+ key: {
33733
+ type: "string",
33734
+ description: "Field on each element used as the per-object identity"
33735
+ },
33736
+ "ignore-paths": {
33737
+ type: "array",
33738
+ items: { type: "string" },
33739
+ description: 'Dotted paths (relative to each element, e.g. "fetchedAt" or "$.fetchedAt") removed before comparison'
33740
+ }
33741
+ },
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"
33749
+ }
33750
+ },
33751
+ additionalProperties: false,
33752
+ // BP3: change-detection.collection requires strategy: json-diff. Under any
33753
+ // other strategy (or the defaulted text-diff), presence of `collection` is an
33754
+ // authoring-time error.
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
+ ]
33771
+ }
33772
+ },
33773
+ required: ["command"]
33774
+ };
33775
+ var source3 = {
33776
+ name: "command-poll",
33777
+ stateful: true,
33778
+ scopeSchema: scopeSchema3,
33779
+ async observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
33780
+ const scope = parseScopeConfig3(config2);
33781
+ const prev = isCommandState(context.previousState) ? context.previousState : void 0;
33782
+ const outcome = await runCommand(scope);
33783
+ if (outcome.kind === "failure") {
33784
+ const wasFailing = prev?.health === "failing";
33785
+ const nextState2 = {
33786
+ stdout: prev?.stdout ?? "",
33787
+ exitCode: prev?.exitCode ?? 0,
33788
+ truncated: prev?.truncated ?? false,
33789
+ health: "failing",
33790
+ baselined: prev?.baselined ?? false,
33791
+ // Carry the keyed baseline forward untouched so recovery diffs against it.
33792
+ ...prev?.keyedSnapshot ? { keyedSnapshot: prev.keyedSnapshot } : {}
33793
+ };
33794
+ return {
33795
+ observations: wasFailing ? [] : [failingObservation(scope, outcome)],
33796
+ nextState: nextState2
33797
+ };
33798
+ }
33799
+ const result = outcome.result;
33800
+ const recovered = prev?.health === "failing";
33801
+ const hadBaseline = prev?.baselined ?? false;
33802
+ const observations = [];
33803
+ if (recovered) {
33804
+ observations.push(recoveredObservation(scope));
33805
+ }
33806
+ if (scope.collection) {
33807
+ const result2 = diffKeyedCollection(
33808
+ JSON.parse(result.stdout),
33809
+ scope.collection,
33810
+ scope.objectKey,
33811
+ hadBaseline ? prev?.keyedSnapshot : void 0,
33812
+ {
33813
+ payload: { command: scope.command },
33814
+ queryScope: { command: scope.objectKey }
33815
+ }
33816
+ );
33817
+ observations.push(...result2.observations);
33818
+ const nextState2 = {
33819
+ stdout: result.stdout,
33820
+ exitCode: result.exitCode,
33821
+ truncated: result.truncated,
33822
+ health: "ok",
33823
+ baselined: true,
33824
+ keyedSnapshot: result2.snapshot
33825
+ };
33826
+ return { observations, nextState: nextState2 };
33827
+ }
33828
+ const nextState = {
33829
+ stdout: result.stdout,
33830
+ exitCode: result.exitCode,
33831
+ truncated: result.truncated,
33832
+ health: "ok",
33833
+ baselined: true
33834
+ };
33835
+ if (prev !== void 0 && hadBaseline && hasChanged2(scope.strategy, scope.ignorePaths, prev, result)) {
33836
+ observations.push(changedObservation(scope, result));
33837
+ }
33838
+ return { observations, nextState };
33839
+ }
33840
+ };
33841
+ function failingObservation(scope, outcome) {
33842
+ return {
33843
+ title: `Command failing: ${scope.objectKey}`,
33844
+ summary: `Command failing: ${scope.objectKey}`,
33845
+ payload: {
33846
+ command: scope.command,
33847
+ error: outcome.error,
33848
+ stderrTail: outcome.stderrTail
33849
+ },
33850
+ objectKey: scope.objectKey,
33851
+ queryScope: { command: scope.objectKey },
33852
+ changeKind: "modified"
33853
+ };
33854
+ }
33855
+ function recoveredObservation(scope) {
33856
+ return {
33857
+ title: `Command recovered: ${scope.objectKey}`,
33858
+ summary: `Command recovered: ${scope.objectKey}`,
33859
+ payload: { command: scope.command },
33860
+ objectKey: scope.objectKey,
33861
+ queryScope: { command: scope.objectKey },
33862
+ changeKind: "modified"
33863
+ };
33864
+ }
33865
+ var index_default3 = source3;
33866
+
33867
+ // ../../plugins/source-schedule/dist/index.js
33868
+ init_cjs_shims();
33869
+ function parseScopeConfig4(config2) {
32810
33870
  const cron = config2["cron"];
32811
33871
  if (typeof cron !== "string") {
32812
33872
  throw new Error("scope.cron must be a string");
@@ -32817,7 +33877,7 @@ function parseScopeConfig3(config2) {
32817
33877
  label: typeof config2["label"] === "string" ? config2["label"] : void 0
32818
33878
  };
32819
33879
  }
32820
- var scopeSchema3 = {
33880
+ var scopeSchema4 = {
32821
33881
  type: "object",
32822
33882
  properties: {
32823
33883
  cron: {
@@ -32835,11 +33895,11 @@ var scopeSchema3 = {
32835
33895
  },
32836
33896
  required: ["cron"]
32837
33897
  };
32838
- var source3 = {
33898
+ var source4 = {
32839
33899
  name: "schedule",
32840
- scopeSchema: scopeSchema3,
33900
+ scopeSchema: scopeSchema4,
32841
33901
  observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
32842
- const { cron, timezone, label } = parseScopeConfig3(config2);
33902
+ const { cron, timezone, label } = parseScopeConfig4(config2);
32843
33903
  return Promise.resolve({
32844
33904
  observations: [
32845
33905
  {
@@ -32861,12 +33921,12 @@ var source3 = {
32861
33921
  });
32862
33922
  }
32863
33923
  };
32864
- var index_default3 = source3;
33924
+ var index_default4 = source4;
32865
33925
 
32866
33926
  // ../../plugins/source-incoming-changes/dist/index.js
32867
33927
  init_cjs_shims();
32868
- var import_child_process = require("child_process");
32869
- function parseScopeConfig4(config2) {
33928
+ var import_child_process2 = require("child_process");
33929
+ function parseScopeConfig5(config2) {
32870
33930
  const paths = config2["paths"];
32871
33931
  if (!Array.isArray(paths) || !paths.every((p) => typeof p === "string")) {
32872
33932
  throw new Error("scope.paths must be an array of strings");
@@ -32882,7 +33942,7 @@ var MAX_BUFFER = 64 * 1024 * 1024;
32882
33942
  function tryResolveCurrentRef(cwd, branch) {
32883
33943
  const ref = branch ?? "HEAD";
32884
33944
  try {
32885
- const raw = (0, import_child_process.execFileSync)("git", ["rev-parse", "--end-of-options", ref], {
33945
+ const raw = (0, import_child_process2.execFileSync)("git", ["rev-parse", "--end-of-options", ref], {
32886
33946
  cwd,
32887
33947
  encoding: "utf-8",
32888
33948
  maxBuffer: MAX_BUFFER
@@ -32907,7 +33967,7 @@ function tryGetDiffEntries(cwd, fromRef, toRef, paths) {
32907
33967
  ];
32908
33968
  let output;
32909
33969
  try {
32910
- output = (0, import_child_process.execFileSync)("git", args, {
33970
+ output = (0, import_child_process2.execFileSync)("git", args, {
32911
33971
  cwd,
32912
33972
  encoding: "buffer",
32913
33973
  maxBuffer: MAX_BUFFER
@@ -32943,7 +34003,7 @@ function tryGetDiffEntries(cwd, fromRef, toRef, paths) {
32943
34003
  }
32944
34004
  function getFileContent(cwd, ref, filePath2) {
32945
34005
  try {
32946
- const content = (0, import_child_process.execFileSync)("git", ["show", `${ref}:${filePath2}`], {
34006
+ const content = (0, import_child_process2.execFileSync)("git", ["show", `${ref}:${filePath2}`], {
32947
34007
  cwd,
32948
34008
  encoding: "buffer",
32949
34009
  maxBuffer: MAX_BUFFER
@@ -32985,7 +34045,7 @@ function buildObservation(entry, fromRef, toRef, cwd) {
32985
34045
  }
32986
34046
  return observation;
32987
34047
  }
32988
- var scopeSchema4 = {
34048
+ var scopeSchema5 = {
32989
34049
  $schema: "http://json-schema.org/draft-07/schema#",
32990
34050
  type: "object",
32991
34051
  properties: {
@@ -33010,13 +34070,13 @@ var scopeSchema4 = {
33010
34070
  },
33011
34071
  required: ["paths"]
33012
34072
  };
33013
- var source4 = {
34073
+ var source5 = {
33014
34074
  name: "incoming-changes",
33015
34075
  stateful: true,
33016
- scopeSchema: scopeSchema4,
34076
+ scopeSchema: scopeSchema5,
33017
34077
  observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
33018
34078
  try {
33019
- const { paths, branch, cwd } = parseScopeConfig4(config2);
34079
+ const { paths, branch, cwd } = parseScopeConfig5(config2);
33020
34080
  const currentRef = tryResolveCurrentRef(cwd, branch);
33021
34081
  if (currentRef === void 0) {
33022
34082
  return Promise.resolve({ observations: [] });
@@ -33056,7 +34116,7 @@ var source4 = {
33056
34116
  }
33057
34117
  }
33058
34118
  };
33059
- var index_default4 = source4;
34119
+ var index_default5 = source5;
33060
34120
 
33061
34121
  // src/sources.ts
33062
34122
  function registerCoreSources(registry2) {
@@ -33064,6 +34124,7 @@ function registerCoreSources(registry2) {
33064
34124
  registry2.register(index_default2);
33065
34125
  registry2.register(index_default3);
33066
34126
  registry2.register(index_default4);
34127
+ registry2.register(index_default5);
33067
34128
  }
33068
34129
 
33069
34130
  // src/validation.ts
@@ -33104,6 +34165,33 @@ function requireDirectory(dirPath, json) {
33104
34165
  }
33105
34166
 
33106
34167
  // src/commands/validate.ts
34168
+ function changeDetectionCollectionError(watchConfig2) {
34169
+ const cd = watchConfig2["change-detection"];
34170
+ if (cd === null || typeof cd !== "object" || Array.isArray(cd))
34171
+ return void 0;
34172
+ const cdObj = cd;
34173
+ if (cdObj["collection"] === void 0) return void 0;
34174
+ const strategy = cdObj["strategy"];
34175
+ if (strategy === "json-diff") return void 0;
34176
+ return "change-detection.collection requires strategy: json-diff";
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
+ }
33107
34195
  var validateCommand = new Command("validate").description("Validate MONITOR.md files in a directory").argument("[path]", "Path to monitors directory", ".claude/monitors").addOption(
33108
34196
  new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")
33109
34197
  ).action(async (monitorPath, options2) => {
@@ -33114,8 +34202,8 @@ var validateCommand = new Command("validate").description("Validate MONITOR.md f
33114
34202
  const scopeErrors = [];
33115
34203
  const validMonitors = result.monitors.filter((m) => {
33116
34204
  const sourceName = m.monitor.frontmatter.watch.type;
33117
- const source5 = registry2.get(sourceName);
33118
- if (!source5) {
34205
+ const source6 = registry2.get(sourceName);
34206
+ if (!source6) {
33119
34207
  scopeErrors.push({
33120
34208
  id: m.monitor.id,
33121
34209
  errors: [
@@ -33125,21 +34213,23 @@ var validateCommand = new Command("validate").description("Validate MONITOR.md f
33125
34213
  return false;
33126
34214
  }
33127
34215
  const { type: _type, ...watchConfig2 } = m.monitor.frontmatter.watch;
33128
- const errors = validateScope(watchConfig2, source5.scopeSchema);
33129
- if (errors.length > 0) {
33130
- scopeErrors.push({ id: m.monitor.id, errors });
34216
+ const errors = validateScope(watchConfig2, source6.scopeSchema);
34217
+ const collectionError = changeDetectionCollectionError(watchConfig2);
34218
+ const allScopeErrors = collectionError ? [collectionError, ...errors.filter((e) => !e.includes("then"))] : errors;
34219
+ if (allScopeErrors.length > 0) {
34220
+ scopeErrors.push({ id: m.monitor.id, errors: allScopeErrors });
33131
34221
  return false;
33132
34222
  }
33133
34223
  return true;
33134
34224
  });
33135
34225
  const duplicateErrors = result.duplicateIds.map((dup) => ({
33136
34226
  filePath: dup.filePaths.join(", "),
33137
- 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`
33138
34228
  }));
33139
34229
  const allErrors = [
33140
34230
  ...result.errors.map((e) => ({
33141
34231
  filePath: e.filePath,
33142
- error: e.error
34232
+ error: [e.error, oldSourceScopeShapeHint(e.filePath)].filter(Boolean).join("; ")
33143
34233
  })),
33144
34234
  ...scopeErrors.map((e) => ({
33145
34235
  filePath: e.id,
@@ -33389,19 +34479,14 @@ inboxCommand.command("archive").description("Archive a completed or failed inbox
33389
34479
 
33390
34480
  // src/commands/monitor-test.ts
33391
34481
  init_cjs_shims();
33392
- var import_node_fs4 = require("fs");
34482
+ var import_node_path5 = __toESM(require("path"), 1);
34483
+ var import_node_fs5 = require("fs");
33393
34484
  var import_promises4 = require("timers/promises");
33394
34485
 
33395
- // src/runtime-client.ts
33396
- init_cjs_shims();
33397
-
33398
- // src/runtime.ts
33399
- init_cjs_shims();
33400
-
33401
34486
  // src/daemon-ipc.ts
33402
34487
  init_cjs_shims();
33403
34488
  var import_node_crypto = require("crypto");
33404
- var import_node_fs3 = require("fs");
34489
+ var import_node_fs4 = require("fs");
33405
34490
  var import_node_os2 = require("os");
33406
34491
  var import_node_path4 = __toESM(require("path"), 1);
33407
34492
  var import_node_net = __toESM(require("net"), 1);
@@ -33424,6 +34509,7 @@ var daemonMethodSchema = external_exports.enum([
33424
34509
  "events.ack",
33425
34510
  "hook.claim",
33426
34511
  "history.list",
34512
+ "monitor.explain",
33427
34513
  "daemon.tick"
33428
34514
  ]);
33429
34515
  var daemonResponseSchema = external_exports.object({
@@ -33472,6 +34558,13 @@ var historyListParamsSchema = external_exports.object({
33472
34558
  monitorId: external_exports.string().optional(),
33473
34559
  limit: external_exports.number().int().positive().optional()
33474
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
+ });
33475
34568
  var daemonTickParamsSchema = external_exports.object({
33476
34569
  monitorsDir: external_exports.string(),
33477
34570
  workspacePath: external_exports.string().optional()
@@ -33481,6 +34574,13 @@ var daemonRequestSchema = external_exports.object({
33481
34574
  method: daemonMethodSchema,
33482
34575
  params: external_exports.record(external_exports.string(), external_exports.unknown())
33483
34576
  });
34577
+ var DaemonConnectionError = class extends Error {
34578
+ constructor(message, cause) {
34579
+ super(message);
34580
+ this.cause = cause;
34581
+ }
34582
+ name = "DaemonConnectionError";
34583
+ };
33484
34584
  function isErrnoException(error2) {
33485
34585
  return typeof error2 === "object" && error2 !== null && "code" in error2;
33486
34586
  }
@@ -33501,7 +34601,7 @@ function resolveSocketPath(overridePath) {
33501
34601
  }
33502
34602
  function cleanupSocket(socketPath) {
33503
34603
  try {
33504
- (0, import_node_fs3.rmSync)(socketPath);
34604
+ (0, import_node_fs4.rmSync)(socketPath);
33505
34605
  } catch (error2) {
33506
34606
  const code = isErrnoException(error2) ? String(error2.code) : "";
33507
34607
  if (code !== "ENOENT") throw error2;
@@ -33542,8 +34642,8 @@ function acquireStartupLock(socketPath) {
33542
34642
  const pidFile = import_node_path4.default.join(lock, "pid");
33543
34643
  const tryMkdir = () => {
33544
34644
  try {
33545
- (0, import_node_fs3.mkdirSync)(lock);
33546
- (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");
33547
34647
  return true;
33548
34648
  } catch (err) {
33549
34649
  if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
@@ -33553,7 +34653,7 @@ function acquireStartupLock(socketPath) {
33553
34653
  if (tryMkdir()) return true;
33554
34654
  let holderPid;
33555
34655
  try {
33556
- holderPid = parseInt((0, import_node_fs3.readFileSync)(pidFile, "utf-8"), 10);
34656
+ holderPid = parseInt((0, import_node_fs4.readFileSync)(pidFile, "utf-8"), 10);
33557
34657
  } catch {
33558
34658
  return false;
33559
34659
  }
@@ -33574,11 +34674,11 @@ function acquireStartupLock(socketPath) {
33574
34674
  return false;
33575
34675
  }
33576
34676
  try {
33577
- (0, import_node_fs3.unlinkSync)(pidFile);
34677
+ (0, import_node_fs4.unlinkSync)(pidFile);
33578
34678
  } catch {
33579
34679
  }
33580
34680
  try {
33581
- (0, import_node_fs3.rmdirSync)(lock);
34681
+ (0, import_node_fs4.rmdirSync)(lock);
33582
34682
  } catch {
33583
34683
  }
33584
34684
  return tryMkdir();
@@ -33587,11 +34687,11 @@ function releaseStartupLock(socketPath) {
33587
34687
  const lock = lockPath(socketPath);
33588
34688
  const pidFile = import_node_path4.default.join(lock, "pid");
33589
34689
  try {
33590
- (0, import_node_fs3.unlinkSync)(pidFile);
34690
+ (0, import_node_fs4.unlinkSync)(pidFile);
33591
34691
  } catch {
33592
34692
  }
33593
34693
  try {
33594
- (0, import_node_fs3.rmdirSync)(lock);
34694
+ (0, import_node_fs4.rmdirSync)(lock);
33595
34695
  } catch {
33596
34696
  }
33597
34697
  }
@@ -33662,6 +34762,16 @@ function handleRequest(runtime, request, stop) {
33662
34762
  })
33663
34763
  );
33664
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
+ }
33665
34775
  case "daemon.tick": {
33666
34776
  const params = daemonTickParamsSchema.parse(request.params);
33667
34777
  return runtime.tick(params.monitorsDir, params.workspacePath);
@@ -33673,7 +34783,7 @@ function createDaemonServer({
33673
34783
  socketPath,
33674
34784
  onStop
33675
34785
  }) {
33676
- (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 });
33677
34787
  let serverClosed = false;
33678
34788
  const server = import_node_net.default.createServer((socket) => {
33679
34789
  let buffer = "";
@@ -33731,7 +34841,7 @@ function createDaemonServer({
33731
34841
  const live = await probeSocket(socketPath);
33732
34842
  if (!live) {
33733
34843
  try {
33734
- (0, import_node_fs3.unlinkSync)(socketPath);
34844
+ (0, import_node_fs4.unlinkSync)(socketPath);
33735
34845
  } catch (unlinkErr) {
33736
34846
  const code = isErrnoException(unlinkErr) ? String(unlinkErr.code) : "";
33737
34847
  if (code !== "ENOENT") throw unlinkErr;
@@ -33797,11 +34907,20 @@ async function callDaemon(method, params = {}, options2 = {}) {
33797
34907
  });
33798
34908
  };
33799
34909
  socket.setTimeout(timeoutMs, () => {
33800
- 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
+ );
33801
34915
  });
33802
34916
  socket.setEncoding("utf-8");
33803
34917
  socket.on("error", (error2) => {
33804
- fail(error2);
34918
+ fail(
34919
+ new DaemonConnectionError(
34920
+ error2 instanceof Error ? error2.message : String(error2),
34921
+ error2
34922
+ )
34923
+ );
33805
34924
  });
33806
34925
  socket.on("data", (chunk) => {
33807
34926
  buffer += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
@@ -33842,7 +34961,11 @@ async function daemonAvailable(socketPath) {
33842
34961
  }
33843
34962
  }
33844
34963
 
34964
+ // src/runtime-client.ts
34965
+ init_cjs_shims();
34966
+
33845
34967
  // src/runtime.ts
34968
+ init_cjs_shims();
33846
34969
  function createRuntime(dbPath = resolveDbPath()) {
33847
34970
  const db = createDb(dbPath);
33848
34971
  const registry2 = new SourceRegistry();
@@ -33905,6 +35028,13 @@ async function listObservationHistoryClient(query, socketPath) {
33905
35028
  socketPath ? { socketPath } : {}
33906
35029
  );
33907
35030
  }
35031
+ async function explainMonitorClient(input, socketPath) {
35032
+ return await callDaemon(
35033
+ "monitor.explain",
35034
+ input,
35035
+ socketPath ? { socketPath } : {}
35036
+ );
35037
+ }
33908
35038
  async function daemonStatusClient(socketPath) {
33909
35039
  return await callDaemon(
33910
35040
  "status",
@@ -33921,6 +35051,127 @@ async function daemonTickClient(monitorsDir, workspacePath) {
33921
35051
  var monitorTestCommand = new Command("monitor").description(
33922
35052
  "Monitor utilities"
33923
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
+ }
33924
35175
  function printJsonResult(monitorName, sourceName, baseline, observations) {
33925
35176
  console.log(
33926
35177
  JSON.stringify(
@@ -33967,24 +35218,24 @@ function createFollowupObservationContext(context) {
33967
35218
  previousState: context.previousState
33968
35219
  };
33969
35220
  }
33970
- async function handleStatefulSource(source5, scope, monitorName, json, context) {
35221
+ async function handleStatefulSource(source6, scope, monitorName, json, context) {
33971
35222
  if (!json) {
33972
35223
  console.log(
33973
35224
  `
33974
- Baseline established. The "${source5.name}" source requires a prior baseline before it can detect changes.`
35225
+ Baseline established. The "${source6.name}" source requires a prior baseline before it can detect changes.`
33975
35226
  );
33976
35227
  console.log(
33977
35228
  "Running a second observation to demonstrate change detection...\n"
33978
35229
  );
33979
35230
  }
33980
35231
  await (0, import_promises4.setTimeout)(100);
33981
- const secondResult = await source5.observe(
35232
+ const secondResult = await source6.observe(
33982
35233
  scope,
33983
35234
  createFollowupObservationContext(context)
33984
35235
  );
33985
35236
  const secondObservations = secondResult.observations;
33986
35237
  if (json) {
33987
- printJsonResult(monitorName, source5.name, true, secondObservations);
35238
+ printJsonResult(monitorName, source6.name, true, secondObservations);
33988
35239
  return;
33989
35240
  }
33990
35241
  if (secondObservations.length > 0) {
@@ -33994,7 +35245,7 @@ Baseline established. The "${source5.name}" source requires a prior baseline bef
33994
35245
  console.log(
33995
35246
  "No changes detected since baseline. This is expected \u2014 both observations happened within the same command invocation."
33996
35247
  );
33997
- const messages = SOURCE_TEST_MESSAGES[source5.name] ?? DEFAULT_TEST_MESSAGES;
35248
+ const messages = SOURCE_TEST_MESSAGES[source6.name] ?? DEFAULT_TEST_MESSAGES;
33998
35249
  for (const msg of messages) {
33999
35250
  console.log(`
34000
35251
  ${msg}`);
@@ -34004,13 +35255,13 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34004
35255
  new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")
34005
35256
  ).action(async (filePath2, options2) => {
34006
35257
  const json = options2.format === "json";
34007
- if (!(0, import_node_fs4.existsSync)(filePath2)) {
35258
+ if (!(0, import_node_fs5.existsSync)(filePath2)) {
34008
35259
  reportError(`Monitor file not found: ${filePath2}`, json);
34009
35260
  return;
34010
35261
  }
34011
35262
  let content;
34012
35263
  try {
34013
- content = (0, import_node_fs4.readFileSync)(filePath2, "utf-8");
35264
+ content = (0, import_node_fs5.readFileSync)(filePath2, "utf-8");
34014
35265
  } catch (err) {
34015
35266
  const msg = err instanceof Error ? err.message : String(err);
34016
35267
  reportError(`Cannot read monitor file: ${msg}`, json);
@@ -34023,8 +35274,8 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34023
35274
  }
34024
35275
  const registry2 = new SourceRegistry();
34025
35276
  registerCoreSources(registry2);
34026
- const source5 = registry2.get(result.monitor.frontmatter.watch.type);
34027
- if (!source5) {
35277
+ const source6 = registry2.get(result.monitor.frontmatter.watch.type);
35278
+ if (!source6) {
34028
35279
  reportError(
34029
35280
  `Unknown source: "${result.monitor.frontmatter.watch.type}". Available: ${registry2.names().join(", ")}`,
34030
35281
  json
@@ -34035,27 +35286,27 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34035
35286
  const { type: _type, ...monitorWatchConfig } = result.monitor.frontmatter.watch;
34036
35287
  if (!json) {
34037
35288
  console.log(
34038
- `Testing monitor "${monitorName}" (source: ${source5.name})...`
35289
+ `Testing monitor "${monitorName}" (source: ${source6.name})...`
34039
35290
  );
34040
35291
  }
34041
35292
  try {
34042
35293
  let context = { now: /* @__PURE__ */ new Date() };
34043
- const firstResult = await source5.observe(monitorWatchConfig, context);
35294
+ const firstResult = await source6.observe(monitorWatchConfig, context);
34044
35295
  const observations = firstResult.observations;
34045
35296
  context = {
34046
35297
  now: /* @__PURE__ */ new Date(),
34047
35298
  previousState: firstResult.nextState
34048
35299
  };
34049
- if (observations.length === 0 && source5.stateful) {
35300
+ if (observations.length === 0 && source6.stateful) {
34050
35301
  await handleStatefulSource(
34051
- source5,
35302
+ source6,
34052
35303
  monitorWatchConfig,
34053
35304
  monitorName,
34054
35305
  json,
34055
35306
  context
34056
35307
  );
34057
35308
  } else if (json) {
34058
- printJsonResult(monitorName, source5.name, false, observations);
35309
+ printJsonResult(monitorName, source6.name, false, observations);
34059
35310
  } else if (observations.length === 0) {
34060
35311
  console.log("No observations produced.");
34061
35312
  } else {
@@ -34066,6 +35317,55 @@ monitorTestCommand.command("test").description("Dry-run a monitor observation so
34066
35317
  reportError(`Observation failed: ${message}`, json);
34067
35318
  }
34068
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
+ );
34069
35369
  monitorTestCommand.command("history").description(
34070
35370
  "Show recent observation outcomes per tick (triggered / suppressed / no-change / errored / rebaselined)"
34071
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(
@@ -34114,12 +35414,14 @@ sourceCommand.command("list").description("List installed observation sources").
34114
35414
  registerCoreSources(registry2);
34115
35415
  const sources = registry2.list();
34116
35416
  if (options2.format === "json") {
34117
- const output = sources.map((source5) => {
34118
- const requiredFields = source5.scopeSchema["required"] ?? [];
34119
- const properties = source5.scopeSchema["properties"] ?? {};
35417
+ const output = sources.map((source6) => {
35418
+ const requiredFields = source6.scopeSchema["required"] ?? [];
35419
+ const properties = source6.scopeSchema["properties"] ?? {};
35420
+ const configFields = Object.keys(properties);
34120
35421
  return {
34121
- name: source5.name,
34122
- scopeFields: Object.keys(properties),
35422
+ name: source6.name,
35423
+ configFields,
35424
+ scopeFields: configFields,
34123
35425
  required: requiredFields
34124
35426
  };
34125
35427
  });
@@ -34131,11 +35433,11 @@ sourceCommand.command("list").description("List installed observation sources").
34131
35433
  return;
34132
35434
  }
34133
35435
  console.log("Installed sources:\n");
34134
- for (const source5 of sources) {
34135
- const requiredFields = source5.scopeSchema["required"] ?? [];
34136
- const properties = source5.scopeSchema["properties"] ?? {};
34137
- console.log(` ${source5.name}`);
34138
- console.log(` Scope fields: ${Object.keys(properties).join(", ")}`);
35436
+ for (const source6 of sources) {
35437
+ const requiredFields = source6.scopeSchema["required"] ?? [];
35438
+ const properties = source6.scopeSchema["properties"] ?? {};
35439
+ console.log(` ${source6.name}`);
35440
+ console.log(` Config fields: ${Object.keys(properties).join(", ")}`);
34139
35441
  console.log(` Required: ${requiredFields.join(", ") || "(none)"}`);
34140
35442
  console.log("");
34141
35443
  }
@@ -34432,15 +35734,15 @@ daemonCommand.command("stop").description("Ask the local AgentMon daemon to stop
34432
35734
 
34433
35735
  // src/commands/session.ts
34434
35736
  init_cjs_shims();
34435
- var import_node_path8 = __toESM(require("path"), 1);
35737
+ var import_node_path9 = __toESM(require("path"), 1);
34436
35738
 
34437
35739
  // src/local-state.ts
34438
35740
  init_cjs_shims();
34439
- var import_node_fs5 = require("fs");
34440
- var import_node_path5 = __toESM(require("path"), 1);
35741
+ var import_node_fs6 = require("fs");
35742
+ var import_node_path6 = __toESM(require("path"), 1);
34441
35743
  var DEFAULT_REAP_AFTER_MS2 = 5 * 60 * 1e3;
34442
35744
  function filePath(workspacePath) {
34443
- return import_node_path5.default.join(workspacePath, ".claude", "agentmonitors.local.md");
35745
+ return import_node_path6.default.join(workspacePath, ".claude", "agentmonitors.local.md");
34444
35746
  }
34445
35747
  function parseFrontmatter(raw) {
34446
35748
  const lines = raw.split("\n");
@@ -34469,7 +35771,7 @@ function parseFrontmatter(raw) {
34469
35771
  function readLocalState(workspacePath) {
34470
35772
  let raw;
34471
35773
  try {
34472
- raw = (0, import_node_fs5.readFileSync)(filePath(workspacePath), "utf-8");
35774
+ raw = (0, import_node_fs6.readFileSync)(filePath(workspacePath), "utf-8");
34473
35775
  } catch {
34474
35776
  return { enabled: false };
34475
35777
  }
@@ -34490,7 +35792,7 @@ function readLocalState(workspacePath) {
34490
35792
  }
34491
35793
  function writeLocalState(workspacePath, state) {
34492
35794
  const target = filePath(workspacePath);
34493
- (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 });
34494
35796
  const lines = [
34495
35797
  "---",
34496
35798
  `enabled: ${String(state.enabled)}`,
@@ -34502,25 +35804,25 @@ function writeLocalState(workspacePath, state) {
34502
35804
  "> Local AgentMon coordination state. Gitignored; safe to delete (it is regenerated).",
34503
35805
  ""
34504
35806
  ];
34505
- (0, import_node_fs5.writeFileSync)(target, lines.join("\n"), "utf-8");
35807
+ (0, import_node_fs6.writeFileSync)(target, lines.join("\n"), "utf-8");
34506
35808
  }
34507
35809
 
34508
35810
  // src/workspace-paths.ts
34509
35811
  init_cjs_shims();
34510
35812
  var import_node_crypto2 = require("crypto");
34511
35813
  var import_node_os3 = __toESM(require("os"), 1);
34512
- var import_node_path6 = __toESM(require("path"), 1);
35814
+ var import_node_path7 = __toESM(require("path"), 1);
34513
35815
  function workspacePaths(workspacePath) {
34514
- const hash = (0, import_node_crypto2.createHash)("sha256").update(import_node_path6.default.resolve(workspacePath)).digest("hex").slice(0, 16);
34515
- const dataRoot = process.env["XDG_DATA_HOME"] ?? import_node_path6.default.join(import_node_os3.default.homedir(), ".local", "share");
34516
- 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);
34517
35819
  return {
34518
35820
  dir,
34519
- db: import_node_path6.default.join(dir, "inbox.db"),
35821
+ db: import_node_path7.default.join(dir, "inbox.db"),
34520
35822
  // Keep the socket short: a 16-char hash under the data dir stays well under
34521
35823
  // the 100-char limit on most setups; resolveSocketPath's /tmp fallback still
34522
35824
  // applies if a deep home dir pushes it over.
34523
- socket: import_node_path6.default.join(dir, "agentmonitors.sock")
35825
+ socket: import_node_path7.default.join(dir, "agentmonitors.sock")
34524
35826
  };
34525
35827
  }
34526
35828
 
@@ -34528,15 +35830,15 @@ function workspacePaths(workspacePath) {
34528
35830
  init_cjs_shims();
34529
35831
  var import_node_child_process = require("child_process");
34530
35832
  var import_node_url3 = require("url");
34531
- var import_node_path7 = __toESM(require("path"), 1);
35833
+ var import_node_path8 = __toESM(require("path"), 1);
34532
35834
  function cliEntry() {
34533
35835
  const thisFile = (0, import_node_url3.fileURLToPath)(importMetaUrl);
34534
- 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";
34535
35837
  if (isBundle) {
34536
35838
  return thisFile;
34537
35839
  }
34538
- const packageRoot = import_node_path7.default.resolve(import_node_path7.default.dirname(thisFile), "..");
34539
- 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");
34540
35842
  }
34541
35843
  function spawnDetachedDaemon(options2) {
34542
35844
  const args = [
@@ -34743,7 +36045,7 @@ sessionCommand.command("start").description(
34743
36045
  const paths = workspacePaths(workspacePath);
34744
36046
  const socket = resolveSocketPath(state.socket ?? paths.socket);
34745
36047
  const db = state.db ?? paths.db;
34746
- const monitorsDir = import_node_path8.default.join(workspacePath, ".claude", "monitors");
36048
+ const monitorsDir = import_node_path9.default.join(workspacePath, ".claude", "monitors");
34747
36049
  const BOOT_TIMEOUT_MS = 8e3;
34748
36050
  if (!await daemonAvailable(socket)) {
34749
36051
  spawnDetachedDaemon({
@@ -35136,10 +36438,10 @@ function cached(getter) {
35136
36438
  function nullish(input) {
35137
36439
  return input === null || input === void 0;
35138
36440
  }
35139
- function cleanRegex(source5) {
35140
- const start = source5.startsWith("^") ? 1 : 0;
35141
- const end = source5.endsWith("$") ? source5.length - 1 : source5.length;
35142
- return source5.slice(start, end);
36441
+ function cleanRegex(source6) {
36442
+ const start = source6.startsWith("^") ? 1 : 0;
36443
+ const end = source6.endsWith("$") ? source6.length - 1 : source6.length;
36444
+ return source6.slice(start, end);
35143
36445
  }
35144
36446
  function floatSafeRemainder2(val, step) {
35145
36447
  const valDecCount = (val.toString().split(".")[1] || "").length;
@@ -35177,10 +36479,10 @@ function assignProp(target, prop, value) {
35177
36479
  configurable: true
35178
36480
  });
35179
36481
  }
35180
- function getElementAtPath(obj, path12) {
35181
- if (!path12)
36482
+ function getElementAtPath(obj, path13) {
36483
+ if (!path13)
35182
36484
  return obj;
35183
- return path12.reduce((acc, key) => acc?.[key], obj);
36485
+ return path13.reduce((acc, key) => acc?.[key], obj);
35184
36486
  }
35185
36487
  function promiseAllObject(promisesObj) {
35186
36488
  const keys = Object.keys(promisesObj);
@@ -35500,11 +36802,11 @@ function aborted(x2, startIndex = 0) {
35500
36802
  }
35501
36803
  return false;
35502
36804
  }
35503
- function prefixIssues(path12, issues) {
36805
+ function prefixIssues(path13, issues) {
35504
36806
  return issues.map((iss) => {
35505
36807
  var _a2;
35506
36808
  (_a2 = iss).path ?? (_a2.path = []);
35507
- iss.path.unshift(path12);
36809
+ iss.path.unshift(path13);
35508
36810
  return iss;
35509
36811
  });
35510
36812
  }
@@ -42413,9 +43715,9 @@ async function runChannelServe(options2) {
42413
43715
  // src/index.ts
42414
43716
  function getVersion() {
42415
43717
  try {
42416
- 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));
42417
43719
  const pkg = JSON.parse(
42418
- (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")
42419
43721
  );
42420
43722
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
42421
43723
  } catch {