@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 +1528 -226
- package/dist/index.cjs.map +1 -1
- package/package.json +7 -6
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
|
|
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,
|
|
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] =
|
|
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
|
|
2050
|
+
let source6;
|
|
2051
2051
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
2052
2052
|
if (cmd.getOptionValueSource(key) !== void 0) {
|
|
2053
|
-
|
|
2053
|
+
source6 = cmd.getOptionValueSource(key);
|
|
2054
2054
|
}
|
|
2055
2055
|
});
|
|
2056
|
-
return
|
|
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 =
|
|
2234
|
+
const localBin = path13.resolve(baseDir, baseName);
|
|
2235
2235
|
if (fs.existsSync(localBin)) return localBin;
|
|
2236
|
-
if (sourceExt.includes(
|
|
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 =
|
|
2255
|
-
|
|
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 =
|
|
2262
|
+
const legacyName = path13.basename(
|
|
2263
2263
|
this._scriptPath,
|
|
2264
|
-
|
|
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(
|
|
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
|
|
2926
|
-
if (
|
|
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 =
|
|
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(
|
|
3205
|
-
if (
|
|
3206
|
-
this._executableDir =
|
|
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,
|
|
3776
|
+
function extend2(target, source6) {
|
|
3777
3777
|
var index, length, key, sourceKeys;
|
|
3778
|
-
if (
|
|
3779
|
-
sourceKeys = Object.keys(
|
|
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] =
|
|
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
|
|
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
|
|
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,
|
|
4859
|
+
return new Function(params, source6.slice(body[0] + 1, body[1] - 1));
|
|
4860
4860
|
}
|
|
4861
|
-
return new Function(params, "return " +
|
|
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,
|
|
5087
|
+
function mergeMappings(state, destination, source6, overridableKeys) {
|
|
5088
5088
|
var sourceKeys, key, index, quantity;
|
|
5089
|
-
if (!common.isObject(
|
|
5089
|
+
if (!common.isObject(source6)) {
|
|
5090
5090
|
throwError(state, "cannot merge mappings; the provided source object is unacceptable");
|
|
5091
5091
|
}
|
|
5092
|
-
sourceKeys = Object.keys(
|
|
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,
|
|
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(
|
|
10230
|
-
let input =
|
|
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 [
|
|
10431
|
-
wsComponent.path =
|
|
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
|
-
|
|
10584
|
+
serialize2(parse4(uri2, options2), options2);
|
|
10585
10585
|
} else if (typeof uri2 === "object") {
|
|
10586
10586
|
uri2 = /** @type {T} */
|
|
10587
|
-
parse4(
|
|
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
|
|
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(
|
|
10601
|
-
relative = parse4(
|
|
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 =
|
|
10653
|
+
uriA = serialize2(normalizeComponentEncoding(parse4(uriA, options2), true), { ...options2, skipEscape: true });
|
|
10654
10654
|
} else if (typeof uriA === "object") {
|
|
10655
|
-
uriA =
|
|
10655
|
+
uriA = serialize2(normalizeComponentEncoding(uriA, true), { ...options2, skipEscape: true });
|
|
10656
10656
|
}
|
|
10657
10657
|
if (typeof uriB === "string") {
|
|
10658
10658
|
uriB = unescape(uriB);
|
|
10659
|
-
uriB =
|
|
10659
|
+
uriB = serialize2(normalizeComponentEncoding(parse4(uriB, options2), true), { ...options2, skipEscape: true });
|
|
10660
10660
|
} else if (typeof uriB === "object") {
|
|
10661
|
-
uriB =
|
|
10661
|
+
uriB = serialize2(normalizeComponentEncoding(uriB, true), { ...options2, skipEscape: true });
|
|
10662
10662
|
}
|
|
10663
10663
|
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
10664
10664
|
}
|
|
10665
|
-
function
|
|
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(
|
|
11557
|
-
const errs = (0, codegen_1._)`${
|
|
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(
|
|
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._)`${
|
|
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._)`${
|
|
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
|
|
13855
|
-
var
|
|
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:
|
|
14455
|
-
const fullPath = [...
|
|
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,
|
|
14593
|
+
constructor(parent, value, path13, key) {
|
|
14576
14594
|
this._cachedPath = [];
|
|
14577
14595
|
this.parent = parent;
|
|
14578
14596
|
this.data = value;
|
|
14579
|
-
this._path =
|
|
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(
|
|
22646
|
-
if (!
|
|
22663
|
+
resolve(path13) {
|
|
22664
|
+
if (!path13) {
|
|
22647
22665
|
return this;
|
|
22648
22666
|
}
|
|
22649
|
-
const rootPath = this.getRootString(
|
|
22650
|
-
const dir =
|
|
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(
|
|
23403
|
-
return import_node_path2.win32.parse(
|
|
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(
|
|
23450
|
-
return
|
|
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(
|
|
23540
|
-
if (typeof
|
|
23541
|
-
|
|
23557
|
+
depth(path13 = this.cwd) {
|
|
23558
|
+
if (typeof path13 === "string") {
|
|
23559
|
+
path13 = this.cwd.resolve(path13);
|
|
23542
23560
|
}
|
|
23543
|
-
return
|
|
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(
|
|
24048
|
+
chdir(path13 = this.cwd) {
|
|
24031
24049
|
const oldCwd = this.cwd;
|
|
24032
|
-
this.cwd = typeof
|
|
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(([
|
|
24395
|
-
|
|
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,
|
|
24618
|
+
constructor(patterns, path13, opts) {
|
|
24601
24619
|
this.patterns = patterns;
|
|
24602
|
-
this.path =
|
|
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(
|
|
24622
|
-
return this.seen.has(
|
|
24639
|
+
#ignored(path13) {
|
|
24640
|
+
return this.seen.has(path13) || !!this.#ignore?.ignored?.(path13);
|
|
24623
24641
|
}
|
|
24624
|
-
#childrenIgnored(
|
|
24625
|
-
return !!this.#ignore?.childrenIgnored?.(
|
|
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,
|
|
24841
|
-
super(patterns,
|
|
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,
|
|
24879
|
-
super(patterns,
|
|
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:
|
|
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
|
|
26400
|
-
if (pathChunkIndex <
|
|
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) &&
|
|
26409
|
-
const objectName =
|
|
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(
|
|
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(
|
|
28695
|
+
} else if (is(source6, Subquery)) {
|
|
28678
28696
|
fields = Object.fromEntries(
|
|
28679
|
-
Object.keys(
|
|
28697
|
+
Object.keys(source6._.selectedFields).map((key) => [key, source6[key]])
|
|
28680
28698
|
);
|
|
28681
|
-
} else if (is(
|
|
28682
|
-
fields =
|
|
28683
|
-
} else if (is(
|
|
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(
|
|
28704
|
+
fields = getTableColumns(source6);
|
|
28687
28705
|
}
|
|
28688
28706
|
return new SQLiteSelectBase({
|
|
28689
|
-
table:
|
|
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(
|
|
29594
|
-
this.config.from =
|
|
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(
|
|
29747
|
-
return sql`(select count(*) from ${
|
|
29764
|
+
static buildEmbeddedCount(source6, filters) {
|
|
29765
|
+
return sql`(select count(*) from ${source6}${sql.raw(" where ").if(filters)}${filters})`;
|
|
29748
29766
|
}
|
|
29749
|
-
static buildCount(
|
|
29750
|
-
return sql`select count(*) from ${
|
|
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(
|
|
30036
|
-
return new SQLiteCountBuilder({ source:
|
|
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:
|
|
30611
|
-
const instance2 = new import_better_sqlite3.default(
|
|
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,
|
|
30753
|
-
const validator = new Validator(
|
|
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(
|
|
31228
|
-
if (this.sources.has(
|
|
31245
|
+
register(source6) {
|
|
31246
|
+
if (this.sources.has(source6.name)) {
|
|
31229
31247
|
throw new Error(
|
|
31230
|
-
`Observation source "${
|
|
31248
|
+
`Observation source "${source6.name}" is already registered`
|
|
31231
31249
|
);
|
|
31232
31250
|
}
|
|
31233
|
-
this.sources.set(
|
|
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((
|
|
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:
|
|
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:
|
|
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
|
|
32103
|
-
if (!
|
|
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
|
|
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
|
|
32267
|
-
if (!
|
|
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 (!
|
|
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 =
|
|
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
|
|
32697
|
-
if (Array.isArray(value)) return value.map(
|
|
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] =
|
|
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(
|
|
32714
|
-
const currJson = JSON.stringify(
|
|
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-
|
|
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
|
|
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
|
|
33898
|
+
var source4 = {
|
|
32839
33899
|
name: "schedule",
|
|
32840
|
-
scopeSchema:
|
|
33900
|
+
scopeSchema: scopeSchema4,
|
|
32841
33901
|
observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
|
|
32842
|
-
const { cron, timezone, label } =
|
|
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
|
|
33924
|
+
var index_default4 = source4;
|
|
32865
33925
|
|
|
32866
33926
|
// ../../plugins/source-incoming-changes/dist/index.js
|
|
32867
33927
|
init_cjs_shims();
|
|
32868
|
-
var
|
|
32869
|
-
function
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
34073
|
+
var source5 = {
|
|
33014
34074
|
name: "incoming-changes",
|
|
33015
34075
|
stateful: true,
|
|
33016
|
-
scopeSchema:
|
|
34076
|
+
scopeSchema: scopeSchema5,
|
|
33017
34077
|
observe(config2, context = { now: /* @__PURE__ */ new Date() }) {
|
|
33018
34078
|
try {
|
|
33019
|
-
const { paths, branch, cwd } =
|
|
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
|
|
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
|
|
33118
|
-
if (!
|
|
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,
|
|
33129
|
-
|
|
33130
|
-
|
|
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}"
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
33546
|
-
(0,
|
|
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,
|
|
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,
|
|
34677
|
+
(0, import_node_fs4.unlinkSync)(pidFile);
|
|
33578
34678
|
} catch {
|
|
33579
34679
|
}
|
|
33580
34680
|
try {
|
|
33581
|
-
(0,
|
|
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,
|
|
34690
|
+
(0, import_node_fs4.unlinkSync)(pidFile);
|
|
33591
34691
|
} catch {
|
|
33592
34692
|
}
|
|
33593
34693
|
try {
|
|
33594
|
-
(0,
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
35221
|
+
async function handleStatefulSource(source6, scope, monitorName, json, context) {
|
|
33971
35222
|
if (!json) {
|
|
33972
35223
|
console.log(
|
|
33973
35224
|
`
|
|
33974
|
-
Baseline established. The "${
|
|
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
|
|
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,
|
|
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[
|
|
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,
|
|
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,
|
|
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
|
|
34027
|
-
if (!
|
|
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: ${
|
|
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
|
|
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 &&
|
|
35300
|
+
if (observations.length === 0 && source6.stateful) {
|
|
34050
35301
|
await handleStatefulSource(
|
|
34051
|
-
|
|
35302
|
+
source6,
|
|
34052
35303
|
monitorWatchConfig,
|
|
34053
35304
|
monitorName,
|
|
34054
35305
|
json,
|
|
34055
35306
|
context
|
|
34056
35307
|
);
|
|
34057
35308
|
} else if (json) {
|
|
34058
|
-
printJsonResult(monitorName,
|
|
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((
|
|
34118
|
-
const requiredFields =
|
|
34119
|
-
const 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:
|
|
34122
|
-
|
|
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
|
|
34135
|
-
const requiredFields =
|
|
34136
|
-
const properties =
|
|
34137
|
-
console.log(` ${
|
|
34138
|
-
console.log(`
|
|
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
|
|
35737
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
34436
35738
|
|
|
34437
35739
|
// src/local-state.ts
|
|
34438
35740
|
init_cjs_shims();
|
|
34439
|
-
var
|
|
34440
|
-
var
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
35814
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
34513
35815
|
function workspacePaths(workspacePath) {
|
|
34514
|
-
const hash = (0, import_node_crypto2.createHash)("sha256").update(
|
|
34515
|
-
const dataRoot = process.env["XDG_DATA_HOME"] ??
|
|
34516
|
-
const dir =
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
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 =
|
|
34539
|
-
return
|
|
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 =
|
|
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(
|
|
35140
|
-
const start =
|
|
35141
|
-
const end =
|
|
35142
|
-
return
|
|
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,
|
|
35181
|
-
if (!
|
|
36482
|
+
function getElementAtPath(obj, path13) {
|
|
36483
|
+
if (!path13)
|
|
35182
36484
|
return obj;
|
|
35183
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
43718
|
+
const dir = (0, import_node_path10.dirname)((0, import_node_url4.fileURLToPath)(importMetaUrl));
|
|
42417
43719
|
const pkg = JSON.parse(
|
|
42418
|
-
(0,
|
|
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 {
|