caveat-cli 0.19.9 → 0.19.11
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/README.md +5 -0
- package/dist/{chunk-ITQLGM4K.js → chunk-PFYFYJNS.js} +103 -41
- package/dist/chunk-PFYFYJNS.js.map +1 -0
- package/dist/index.js +149 -47
- package/dist/index.js.map +1 -1
- package/dist/{server-H4BWLLZ2.js → server-JXBPTQNU.js} +55 -2
- package/dist/server-JXBPTQNU.js.map +1 -0
- package/package.json +3 -3
- package/dist/chunk-ITQLGM4K.js.map +0 -1
- package/dist/server-H4BWLLZ2.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -37,6 +37,8 @@ import {
|
|
|
37
37
|
isPrivateOwnerStat,
|
|
38
38
|
isWindows,
|
|
39
39
|
isWindowsEnv,
|
|
40
|
+
jevObservationId,
|
|
41
|
+
listJevObservations,
|
|
40
42
|
listRecent,
|
|
41
43
|
listStale,
|
|
42
44
|
loadConfig,
|
|
@@ -59,6 +61,7 @@ import {
|
|
|
59
61
|
releaseReindexLock,
|
|
60
62
|
resetAutoSyncFailureState,
|
|
61
63
|
resolvePaths,
|
|
64
|
+
reviewJevObservation,
|
|
62
65
|
runAutoSync,
|
|
63
66
|
runWindowsAcl,
|
|
64
67
|
runtimeErrorsDiagnostics,
|
|
@@ -71,10 +74,12 @@ import {
|
|
|
71
74
|
toolErrorReminderText,
|
|
72
75
|
triggerAutoSync,
|
|
73
76
|
updateEntry,
|
|
77
|
+
updateJevDelivery,
|
|
74
78
|
userPromptSubmitReminderText,
|
|
75
79
|
writeDigestMarker,
|
|
80
|
+
writeJevObservation,
|
|
76
81
|
writeUserConfigPatch
|
|
77
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-PFYFYJNS.js";
|
|
78
83
|
|
|
79
84
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
80
85
|
var require_code = __commonJS({
|
|
@@ -453,11 +458,11 @@ var require_codegen = __commonJS({
|
|
|
453
458
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
454
459
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
455
460
|
}
|
|
456
|
-
optimizeNames(names,
|
|
461
|
+
optimizeNames(names, constants5) {
|
|
457
462
|
if (!names[this.name.str])
|
|
458
463
|
return;
|
|
459
464
|
if (this.rhs)
|
|
460
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
465
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
461
466
|
return this;
|
|
462
467
|
}
|
|
463
468
|
get names() {
|
|
@@ -474,10 +479,10 @@ var require_codegen = __commonJS({
|
|
|
474
479
|
render({ _n }) {
|
|
475
480
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
476
481
|
}
|
|
477
|
-
optimizeNames(names,
|
|
482
|
+
optimizeNames(names, constants5) {
|
|
478
483
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
479
484
|
return;
|
|
480
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
485
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
481
486
|
return this;
|
|
482
487
|
}
|
|
483
488
|
get names() {
|
|
@@ -538,8 +543,8 @@ var require_codegen = __commonJS({
|
|
|
538
543
|
optimizeNodes() {
|
|
539
544
|
return `${this.code}` ? this : void 0;
|
|
540
545
|
}
|
|
541
|
-
optimizeNames(names,
|
|
542
|
-
this.code = optimizeExpr(this.code, names,
|
|
546
|
+
optimizeNames(names, constants5) {
|
|
547
|
+
this.code = optimizeExpr(this.code, names, constants5);
|
|
543
548
|
return this;
|
|
544
549
|
}
|
|
545
550
|
get names() {
|
|
@@ -568,12 +573,12 @@ var require_codegen = __commonJS({
|
|
|
568
573
|
}
|
|
569
574
|
return nodes.length > 0 ? this : void 0;
|
|
570
575
|
}
|
|
571
|
-
optimizeNames(names,
|
|
576
|
+
optimizeNames(names, constants5) {
|
|
572
577
|
const { nodes } = this;
|
|
573
578
|
let i = nodes.length;
|
|
574
579
|
while (i--) {
|
|
575
580
|
const n = nodes[i];
|
|
576
|
-
if (n.optimizeNames(names,
|
|
581
|
+
if (n.optimizeNames(names, constants5))
|
|
577
582
|
continue;
|
|
578
583
|
subtractNames(names, n.names);
|
|
579
584
|
nodes.splice(i, 1);
|
|
@@ -626,12 +631,12 @@ var require_codegen = __commonJS({
|
|
|
626
631
|
return void 0;
|
|
627
632
|
return this;
|
|
628
633
|
}
|
|
629
|
-
optimizeNames(names,
|
|
634
|
+
optimizeNames(names, constants5) {
|
|
630
635
|
var _a3;
|
|
631
|
-
this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
632
|
-
if (!(super.optimizeNames(names,
|
|
636
|
+
this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants5);
|
|
637
|
+
if (!(super.optimizeNames(names, constants5) || this.else))
|
|
633
638
|
return;
|
|
634
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
639
|
+
this.condition = optimizeExpr(this.condition, names, constants5);
|
|
635
640
|
return this;
|
|
636
641
|
}
|
|
637
642
|
get names() {
|
|
@@ -654,10 +659,10 @@ var require_codegen = __commonJS({
|
|
|
654
659
|
render(opts) {
|
|
655
660
|
return `for(${this.iteration})` + super.render(opts);
|
|
656
661
|
}
|
|
657
|
-
optimizeNames(names,
|
|
658
|
-
if (!super.optimizeNames(names,
|
|
662
|
+
optimizeNames(names, constants5) {
|
|
663
|
+
if (!super.optimizeNames(names, constants5))
|
|
659
664
|
return;
|
|
660
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
665
|
+
this.iteration = optimizeExpr(this.iteration, names, constants5);
|
|
661
666
|
return this;
|
|
662
667
|
}
|
|
663
668
|
get names() {
|
|
@@ -693,10 +698,10 @@ var require_codegen = __commonJS({
|
|
|
693
698
|
render(opts) {
|
|
694
699
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
695
700
|
}
|
|
696
|
-
optimizeNames(names,
|
|
697
|
-
if (!super.optimizeNames(names,
|
|
701
|
+
optimizeNames(names, constants5) {
|
|
702
|
+
if (!super.optimizeNames(names, constants5))
|
|
698
703
|
return;
|
|
699
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
704
|
+
this.iterable = optimizeExpr(this.iterable, names, constants5);
|
|
700
705
|
return this;
|
|
701
706
|
}
|
|
702
707
|
get names() {
|
|
@@ -738,11 +743,11 @@ var require_codegen = __commonJS({
|
|
|
738
743
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
739
744
|
return this;
|
|
740
745
|
}
|
|
741
|
-
optimizeNames(names,
|
|
746
|
+
optimizeNames(names, constants5) {
|
|
742
747
|
var _a3, _b;
|
|
743
|
-
super.optimizeNames(names,
|
|
744
|
-
(_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
745
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
748
|
+
super.optimizeNames(names, constants5);
|
|
749
|
+
(_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants5);
|
|
750
|
+
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants5);
|
|
746
751
|
return this;
|
|
747
752
|
}
|
|
748
753
|
get names() {
|
|
@@ -1043,7 +1048,7 @@ var require_codegen = __commonJS({
|
|
|
1043
1048
|
function addExprNames(names, from) {
|
|
1044
1049
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
1045
1050
|
}
|
|
1046
|
-
function optimizeExpr(expr, names,
|
|
1051
|
+
function optimizeExpr(expr, names, constants5) {
|
|
1047
1052
|
if (expr instanceof code_1.Name)
|
|
1048
1053
|
return replaceName(expr);
|
|
1049
1054
|
if (!canOptimize(expr))
|
|
@@ -1058,14 +1063,14 @@ var require_codegen = __commonJS({
|
|
|
1058
1063
|
return items;
|
|
1059
1064
|
}, []));
|
|
1060
1065
|
function replaceName(n) {
|
|
1061
|
-
const c =
|
|
1066
|
+
const c = constants5[n.str];
|
|
1062
1067
|
if (c === void 0 || names[n.str] !== 1)
|
|
1063
1068
|
return n;
|
|
1064
1069
|
delete names[n.str];
|
|
1065
1070
|
return c;
|
|
1066
1071
|
}
|
|
1067
1072
|
function canOptimize(e) {
|
|
1068
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
1073
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants5[c.str] !== void 0);
|
|
1069
1074
|
}
|
|
1070
1075
|
}
|
|
1071
1076
|
function subtractNames(names, from) {
|
|
@@ -6891,7 +6896,7 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync, rename
|
|
|
6891
6896
|
import { dirname as dirname3, join as join8 } from "node:path";
|
|
6892
6897
|
|
|
6893
6898
|
// src/claudeInstall.ts
|
|
6894
|
-
import { constants, existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
6899
|
+
import { constants as constants2, existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
6895
6900
|
import { join as join4 } from "node:path";
|
|
6896
6901
|
|
|
6897
6902
|
// src/installShared.ts
|
|
@@ -6952,9 +6957,13 @@ function claudeMcpConfigPath(claudeDir, env = process.env) {
|
|
|
6952
6957
|
}
|
|
6953
6958
|
|
|
6954
6959
|
// src/mcpInstall.ts
|
|
6955
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
6960
|
+
import { constants, existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
6956
6961
|
import { isDeepStrictEqual } from "node:util";
|
|
6957
6962
|
import { parse, stringify } from "smol-toml";
|
|
6963
|
+
function isCaveatStdioMcpRegistration(value, nodePath, cliScriptPath) {
|
|
6964
|
+
if (!object(value)) return false;
|
|
6965
|
+
return isCanonicalAsset(value.command, nodePath, constants.X_OK) && Array.isArray(value.args) && value.args.length === 3 && value.args[0] === "--disable-warning=ExperimentalWarning" && isCanonicalAsset(value.args[1], cliScriptPath, constants.R_OK) && value.args[2] === "mcp-server";
|
|
6966
|
+
}
|
|
6958
6967
|
function object(value) {
|
|
6959
6968
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6960
6969
|
}
|
|
@@ -7058,12 +7067,12 @@ function isCanonicalCaveatClaudeHookCommand(actual, event, nodePath, cliScriptPa
|
|
|
7058
7067
|
const [actualNodePath, actualCliScriptPath, subcommand, actualEvent] = tokens ?? [];
|
|
7059
7068
|
if (tokens?.length !== 4 || actualNodePath === void 0 || actualCliScriptPath === void 0 || subcommand !== "hook" || actualEvent !== event) return false;
|
|
7060
7069
|
if (actual !== hookCommand(actualNodePath, actualCliScriptPath, event)) return false;
|
|
7061
|
-
return isCanonicalAsset(actualNodePath, nodePath,
|
|
7070
|
+
return isCanonicalAsset(actualNodePath, nodePath, constants2.X_OK) && isCanonicalAsset(actualCliScriptPath, cliScriptPath, constants2.R_OK);
|
|
7062
7071
|
}
|
|
7063
7072
|
function isCaveatClaudeMcpRegistration(value, nodePath, cliScriptPath) {
|
|
7064
7073
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7065
7074
|
const server = value;
|
|
7066
|
-
return ["args", "command", "env", "type"].every((key) => Object.hasOwn(server, key)) && server.type === "stdio" &&
|
|
7075
|
+
return ["args", "command", "env", "type"].every((key) => Object.hasOwn(server, key)) && server.type === "stdio" && isCaveatStdioMcpRegistration(server, nodePath, cliScriptPath) && server.env !== null && typeof server.env === "object" && !Array.isArray(server.env) && Object.values(server.env).every((value2) => typeof value2 === "string");
|
|
7067
7076
|
}
|
|
7068
7077
|
function readSettings(path) {
|
|
7069
7078
|
if (!existsSync3(path)) return {};
|
|
@@ -7145,7 +7154,7 @@ function uninstallClaudeIntegration(opts) {
|
|
|
7145
7154
|
}
|
|
7146
7155
|
|
|
7147
7156
|
// src/codexHookInstall.ts
|
|
7148
|
-
import { constants as
|
|
7157
|
+
import { constants as constants3, existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
7149
7158
|
import { join as join5 } from "node:path";
|
|
7150
7159
|
import { parse as parseToml } from "smol-toml";
|
|
7151
7160
|
function hookCommand2(nodePath, cliScriptPath, event, platform = process.platform) {
|
|
@@ -7170,7 +7179,7 @@ function isCaveatCodexHookCommand(actual, event) {
|
|
|
7170
7179
|
function isCanonicalCaveatCodexHookCommand(actual, event, nodePath, cliScriptPath) {
|
|
7171
7180
|
const parsed = commandTokens(actual);
|
|
7172
7181
|
const tokens = parsed?.[0] === "&" ? parsed.slice(1) : parsed;
|
|
7173
|
-
return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath,
|
|
7182
|
+
return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath, constants3.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants3.R_OK) && tokens[2] === "codex-hook" && tokens[3] === event;
|
|
7174
7183
|
}
|
|
7175
7184
|
function isCanonicalCaveatCodexHookEntry(value, event, nodePath, cliScriptPath) {
|
|
7176
7185
|
if (!isPlainRecord(value) || typeof value.type !== "string" || typeof value.command !== "string") return false;
|
|
@@ -7529,7 +7538,7 @@ function detectCodexHookInstallation(codexHome) {
|
|
|
7529
7538
|
// src/cursorInstall.ts
|
|
7530
7539
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
7531
7540
|
import { join as join6 } from "node:path";
|
|
7532
|
-
import { constants as
|
|
7541
|
+
import { constants as constants4 } from "node:fs";
|
|
7533
7542
|
var TIMEOUT_SEC = 10;
|
|
7534
7543
|
function hookCommand3(nodePath, cliScriptPath, event) {
|
|
7535
7544
|
return `${quoteCommandPath(nodePath)} ${quoteCommandPath(cliScriptPath)} cursor-hook ${event}`;
|
|
@@ -7543,7 +7552,7 @@ function isCaveatCursorHookCommand(actual, event) {
|
|
|
7543
7552
|
}
|
|
7544
7553
|
function isCanonicalCaveatCursorHookCommand(actual, event, nodePath, cliScriptPath) {
|
|
7545
7554
|
const tokens = commandTokens(actual);
|
|
7546
|
-
return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath,
|
|
7555
|
+
return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath, constants4.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants4.R_OK) && tokens[2] === "cursor-hook" && tokens[3] === event;
|
|
7547
7556
|
}
|
|
7548
7557
|
function isCanonicalCaveatCursorHookEntry(value, event, nodePath, cliScriptPath) {
|
|
7549
7558
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -8390,7 +8399,7 @@ function runStats(ctx) {
|
|
|
8390
8399
|
|
|
8391
8400
|
// src/commands/serve.ts
|
|
8392
8401
|
async function runServe(opts) {
|
|
8393
|
-
const { startServer } = await import("./server-
|
|
8402
|
+
const { startServer } = await import("./server-JXBPTQNU.js");
|
|
8394
8403
|
const { port, host } = startServer({ port: opts.port });
|
|
8395
8404
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8396
8405
|
`);
|
|
@@ -33274,12 +33283,23 @@ async function judgeStruggle(key, turns, ask = callJev) {
|
|
|
33274
33283
|
criteria: { ...options, none: "No listed term would retrieve useful knowledge about this problem." }
|
|
33275
33284
|
};
|
|
33276
33285
|
const response = await ask(key, { turns }, questions);
|
|
33277
|
-
const
|
|
33278
|
-
|
|
33279
|
-
|
|
33286
|
+
const repeatedProblem = noul(response.answers.repeated_problem);
|
|
33287
|
+
const clearlyStuck = noul(response.answers.clearly_stuck);
|
|
33288
|
+
const struggling = repeatedProblem >= STRUGGLE_THRESHOLD && clearlyStuck >= STRUGGLE_THRESHOLD;
|
|
33289
|
+
const choice = terms.length > 0 ? response.answers.search_term : void 0;
|
|
33290
|
+
const selected = terms.length > 0 ? searchTermChoices(choice, terms) : [];
|
|
33291
|
+
const termChoices = terms.map((term, index) => ({ term, probability: choice.probabilities[`term_${index}`] }));
|
|
33292
|
+
return {
|
|
33293
|
+
struggling,
|
|
33294
|
+
terms: struggling ? selected : [],
|
|
33295
|
+
repeatedProblem,
|
|
33296
|
+
clearlyStuck,
|
|
33297
|
+
termChoices,
|
|
33298
|
+
noneProbability: choice ? choice.probabilities.none : null
|
|
33299
|
+
};
|
|
33280
33300
|
}
|
|
33281
33301
|
async function rankKnowledge(key, turns, candidates, ask = callJev) {
|
|
33282
|
-
if (candidates.length === 0) return null;
|
|
33302
|
+
if (candidates.length === 0) return { selected: null, scores: [] };
|
|
33283
33303
|
const state = {
|
|
33284
33304
|
turns,
|
|
33285
33305
|
currentHostOs: fingerprint().os,
|
|
@@ -33302,14 +33322,16 @@ async function rankKnowledge(key, turns, candidates, ask = callJev) {
|
|
|
33302
33322
|
const response = await ask(key, state, questions);
|
|
33303
33323
|
let best = null;
|
|
33304
33324
|
let bestScore = MATCH_THRESHOLD;
|
|
33325
|
+
const scores = [];
|
|
33305
33326
|
for (let index = 0; index < candidates.length; index++) {
|
|
33306
33327
|
const score = noul(response.answers[`candidate_${index}`]);
|
|
33328
|
+
scores.push(score);
|
|
33307
33329
|
if (score >= MATCH_THRESHOLD && (best === null || score > bestScore)) {
|
|
33308
33330
|
best = candidates[index];
|
|
33309
33331
|
bestScore = score;
|
|
33310
33332
|
}
|
|
33311
33333
|
}
|
|
33312
|
-
return best;
|
|
33334
|
+
return { selected: best, scores };
|
|
33313
33335
|
}
|
|
33314
33336
|
function quotePowerShell(value) {
|
|
33315
33337
|
return `'${value.replaceAll("'", "''")}'`;
|
|
@@ -33374,13 +33396,46 @@ async function runJevStruggle(ctx, host, payload, deps = {}) {
|
|
|
33374
33396
|
const key = (deps.readKey ?? readJevKey)(ctx.caveatHome);
|
|
33375
33397
|
const ask = deps.ask ?? callJev;
|
|
33376
33398
|
const judgment = await judgeStruggle(key, context.turns, ask);
|
|
33399
|
+
const observationId = jevObservationId(host, sessionId, turnKey);
|
|
33400
|
+
const base = {
|
|
33401
|
+
schema: "caveat.jev_observation.v1",
|
|
33402
|
+
id: observationId,
|
|
33403
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33404
|
+
host,
|
|
33405
|
+
sessionId,
|
|
33406
|
+
projectRoot,
|
|
33407
|
+
transcriptPath,
|
|
33408
|
+
turns: context.turns.map(({ originSessionId, turnNumber, truncated }) => ({ originSessionId, turnNumber, truncated })),
|
|
33409
|
+
thinkingAvailable: context.thinkingAvailable,
|
|
33410
|
+
model: MODEL,
|
|
33411
|
+
repeatedProblem: judgment.repeatedProblem,
|
|
33412
|
+
clearlyStuck: judgment.clearlyStuck,
|
|
33413
|
+
struggleThreshold: STRUGGLE_THRESHOLD,
|
|
33414
|
+
struggling: judgment.struggling,
|
|
33415
|
+
termChoices: judgment.termChoices,
|
|
33416
|
+
noneProbability: judgment.noneProbability,
|
|
33417
|
+
selectedTerms: judgment.terms,
|
|
33418
|
+
query: judgment.terms.join(" "),
|
|
33419
|
+
matchThreshold: MATCH_THRESHOLD,
|
|
33420
|
+
review: null
|
|
33421
|
+
};
|
|
33377
33422
|
state.lastTurn = turnKey;
|
|
33378
33423
|
if (!judgment.struggling) {
|
|
33424
|
+
writeJevObservation(ctx.caveatHome, {
|
|
33425
|
+
...base,
|
|
33426
|
+
ftsHits: [],
|
|
33427
|
+
candidates: [],
|
|
33428
|
+
selectedRef: null,
|
|
33429
|
+
noticeText: null,
|
|
33430
|
+
decision: "below_struggle_threshold",
|
|
33431
|
+
delivery: "none"
|
|
33432
|
+
});
|
|
33379
33433
|
saveState(ctx.caveatHome, sessionId, state);
|
|
33380
33434
|
return null;
|
|
33381
33435
|
}
|
|
33382
33436
|
let candidates = [];
|
|
33383
33437
|
const query = judgment.terms.join(" ");
|
|
33438
|
+
let ftsHits = [];
|
|
33384
33439
|
if (query) {
|
|
33385
33440
|
if (!existsSync14(ctx.paths.dbPath)) throw new Error("jev_knowledge_index_missing");
|
|
33386
33441
|
const db = openDb({ path: ctx.paths.dbPath });
|
|
@@ -33388,26 +33443,41 @@ async function runJevStruggle(ctx, host, payload, deps = {}) {
|
|
|
33388
33443
|
const taskText = context.turns.map((turn) => `${turn.user}
|
|
33389
33444
|
${turn.assistant}
|
|
33390
33445
|
${turn.thinking}`).join("\n");
|
|
33391
|
-
|
|
33446
|
+
const hits = search(db, { query, limit: MAX_CANDIDATES });
|
|
33447
|
+
ftsHits = hits.map((hit) => `${hit.source}/${hit.id}`);
|
|
33448
|
+
candidates = hits.filter((hit) => environmentAppliesToTask(hit.environment, taskText, fingerprint().os)).map((hit) => ({ hit, entry: get(db, hit.id, hit.source) })).filter((item) => item.entry !== null).filter((item) => Boolean(item.entry.sections.Resolution));
|
|
33392
33449
|
} finally {
|
|
33393
33450
|
db.close();
|
|
33394
33451
|
}
|
|
33395
33452
|
}
|
|
33396
|
-
const
|
|
33453
|
+
const ranked = await rankKnowledge(key, context.turns, candidates, ask);
|
|
33454
|
+
const selected = ranked.selected;
|
|
33397
33455
|
const id = selected ? `${selected.hit.source}/${selected.hit.id}` : null;
|
|
33398
33456
|
const term = query || "_none";
|
|
33399
|
-
|
|
33457
|
+
const suppressed = Boolean(id && (state.deliveredIds.includes(id) || wasHitDelivered(ctx.caveatHome, sessionId, id)) || !id && state.notifiedTerms.includes(term));
|
|
33458
|
+
const noticeText = reminder(selected);
|
|
33459
|
+
writeJevObservation(ctx.caveatHome, {
|
|
33460
|
+
...base,
|
|
33461
|
+
ftsHits,
|
|
33462
|
+
candidates: candidates.map((candidate, index) => ({ ref: `${candidate.hit.source}/${candidate.hit.id}`, score: ranked.scores[index] })),
|
|
33463
|
+
selectedRef: id,
|
|
33464
|
+
noticeText: suppressed ? null : noticeText,
|
|
33465
|
+
decision: id ? "matched" : !query ? "no_terms" : candidates.length === 0 ? "no_candidates" : "below_match_threshold",
|
|
33466
|
+
delivery: suppressed ? "suppressed" : "pending"
|
|
33467
|
+
});
|
|
33468
|
+
if (suppressed) {
|
|
33400
33469
|
saveState(ctx.caveatHome, sessionId, state);
|
|
33401
33470
|
return null;
|
|
33402
33471
|
}
|
|
33403
33472
|
return {
|
|
33404
|
-
text:
|
|
33473
|
+
text: noticeText,
|
|
33405
33474
|
ref: id,
|
|
33406
33475
|
delivered: () => {
|
|
33407
33476
|
const current = loadState(ctx.caveatHome, sessionId);
|
|
33408
33477
|
current.lastTurn = turnKey;
|
|
33409
33478
|
if (id && !current.deliveredIds.includes(id)) current.deliveredIds.push(id);
|
|
33410
33479
|
if (!id && !current.notifiedTerms.includes(term)) current.notifiedTerms.push(term);
|
|
33480
|
+
updateJevDelivery(ctx.caveatHome, observationId);
|
|
33411
33481
|
saveState(ctx.caveatHome, sessionId, current);
|
|
33412
33482
|
if (selected) {
|
|
33413
33483
|
const db = openDb({ path: ctx.paths.dbPath });
|
|
@@ -34527,6 +34597,20 @@ function claudeRegistration(path, nodePath, cliScriptPath) {
|
|
|
34527
34597
|
return unverified("config_unreadable");
|
|
34528
34598
|
}
|
|
34529
34599
|
}
|
|
34600
|
+
function grokRegistration(path, nodePath, cliScriptPath) {
|
|
34601
|
+
if (!existsSync18(path)) return status(false, "not_registered");
|
|
34602
|
+
try {
|
|
34603
|
+
const config2 = parseToml2(readFileSync12(path, "utf8"));
|
|
34604
|
+
if (!isRecord2(config2) || !isRecord2(config2.mcp_servers)) return status(false, "not_registered");
|
|
34605
|
+
const server = config2.mcp_servers.caveat;
|
|
34606
|
+
if (!isRecord2(server)) return status(false, "not_registered");
|
|
34607
|
+
if (server.enabled === false) return status(false, "disabled");
|
|
34608
|
+
if (server.enabled !== void 0 && server.enabled !== true) return unverified("config_invalid");
|
|
34609
|
+
return status(isCaveatStdioMcpRegistration(server, nodePath, cliScriptPath), "not_registered");
|
|
34610
|
+
} catch {
|
|
34611
|
+
return unverified("config_unreadable");
|
|
34612
|
+
}
|
|
34613
|
+
}
|
|
34530
34614
|
function claudeHooks(claudeDir, nodePath, cliScriptPath) {
|
|
34531
34615
|
try {
|
|
34532
34616
|
const settings = JSON.parse(readFileSync12(join18(claudeDir, "settings.json"), "utf8"));
|
|
@@ -34624,7 +34708,7 @@ function sync(own) {
|
|
|
34624
34708
|
}
|
|
34625
34709
|
}
|
|
34626
34710
|
function factoryDiagnostics(ctx, codexHome = resolveAgentConfigPaths(ctx.userHome).codexHome, requiredConnectors = []) {
|
|
34627
|
-
const { claudeDir, claudeMcp, cursorDir } = resolveAgentConfigPaths(ctx.userHome);
|
|
34711
|
+
const { claudeDir, claudeMcp, cursorDir, grokHome } = resolveAgentConfigPaths(ctx.userHome);
|
|
34628
34712
|
const nodePath = process.execPath;
|
|
34629
34713
|
const cliScriptPath = process.argv[1] ?? "";
|
|
34630
34714
|
const db = database(ctx.paths.dbPath);
|
|
@@ -34635,13 +34719,15 @@ function factoryDiagnostics(ctx, codexHome = resolveAgentConfigPaths(ctx.userHom
|
|
|
34635
34719
|
} catch {
|
|
34636
34720
|
}
|
|
34637
34721
|
const codexHook2 = (present) => present === void 0 ? unverified("config_unreadable") : !present ? hook(false) : feature.status === "ready" ? hook(true) : { ...feature };
|
|
34638
|
-
const
|
|
34722
|
+
const grokMcp = grokRegistration(join18(grokHome, "config.toml"), nodePath, cliScriptPath);
|
|
34723
|
+
const output = { schema: "caveat.native_factory_diagnostics.v1", product: "caveat", version: CAVEAT_VERSION, overall: { status: "unverified" }, database: db, sync: sync(ctx.paths.knowledgeRepo), connectors: { claude: { status: "unverified", mcp: claudeRegistration(claudeMcp, nodePath, cliScriptPath), hooks: claudeHooks(claudeDir, nodePath, cliScriptPath) }, codex: { status: "unverified", hooks: { user_prompt_submit: codexHook2(installedCodexHooks?.userPromptSubmit), post_tool_use: codexHook2(installedCodexHooks?.postToolUse), stop: codexHook2(installedCodexHooks?.stop) } }, cursor: diagnoseCursorHookConnector(cursorDir, nodePath, cliScriptPath), grok: { status: grokMcp.status, mcp: grokMcp } } };
|
|
34639
34724
|
const aggregate = (all) => all.includes("not_ready") ? "not_ready" : all.includes("unverified") ? "unverified" : "ready";
|
|
34640
34725
|
const connectorStatus = (connector) => aggregate([...Object.values(connector.hooks), ...connector.mcp ? [connector.mcp] : []].map((v) => v.status));
|
|
34641
34726
|
output.connectors.claude.status = connectorStatus(output.connectors.claude);
|
|
34642
34727
|
output.connectors.codex.status = connectorStatus(output.connectors.codex);
|
|
34643
34728
|
const statuses = [output.database.status, output.sync.status, output.connectors.claude.status, output.connectors.codex.status];
|
|
34644
34729
|
if (requiredConnectors.includes("cursor")) statuses.push(output.connectors.cursor.compatibility_status);
|
|
34730
|
+
if (requiredConnectors.includes("grok")) statuses.push(output.connectors.grok.status);
|
|
34645
34731
|
output.overall.status = aggregate(statuses);
|
|
34646
34732
|
return output;
|
|
34647
34733
|
}
|
|
@@ -34689,6 +34775,15 @@ function jevStatus(ctx) {
|
|
|
34689
34775
|
})}
|
|
34690
34776
|
`);
|
|
34691
34777
|
}
|
|
34778
|
+
function listJevCases(ctx) {
|
|
34779
|
+
process.stdout.write(`${JSON.stringify({ schema: "caveat.jev_cases.v1", cases: listJevObservations(ctx.caveatHome) })}
|
|
34780
|
+
`);
|
|
34781
|
+
}
|
|
34782
|
+
function reviewJevCase(ctx, id, verdict, note) {
|
|
34783
|
+
const item = reviewJevObservation(ctx.caveatHome, id, verdict, note);
|
|
34784
|
+
process.stdout.write(`${JSON.stringify({ id: item.id, review: item.review })}
|
|
34785
|
+
`);
|
|
34786
|
+
}
|
|
34692
34787
|
|
|
34693
34788
|
// src/index.ts
|
|
34694
34789
|
var program = new Command();
|
|
@@ -34698,7 +34793,7 @@ function collectRepeatable(value, previous) {
|
|
|
34698
34793
|
}
|
|
34699
34794
|
program.name("caveat").description("External spec gotcha knowledge base CLI").version(CAVEAT_VERSION);
|
|
34700
34795
|
program.command("factory-diagnostics").description("Emit read-only factory diagnostics").requiredOption("--json", "emit the versioned JSON contract").option("--require-connector <name>", "include a connector in overall readiness (repeatable)", collectRepeatable, []).action((opts) => {
|
|
34701
|
-
const unsupported = opts.requireConnector.filter((name) => name !== "cursor");
|
|
34796
|
+
const unsupported = opts.requireConnector.filter((name) => name !== "cursor" && name !== "grok");
|
|
34702
34797
|
if (unsupported.length > 0) throw new Error(`unsupported factory connector: ${unsupported.join(", ")}`);
|
|
34703
34798
|
const requiredConnectors = [...new Set(opts.requireConnector)];
|
|
34704
34799
|
const output = factoryDiagnostics(buildContext(stdoutLogger), void 0, requiredConnectors);
|
|
@@ -34717,6 +34812,13 @@ jev.command("disable").action(() => {
|
|
|
34717
34812
|
jev.command("status").action(() => {
|
|
34718
34813
|
jevStatus(buildContext(stdoutLogger));
|
|
34719
34814
|
});
|
|
34815
|
+
jev.command("cases").requiredOption("--json", "emit case records").action(() => {
|
|
34816
|
+
listJevCases(buildContext(stdoutLogger));
|
|
34817
|
+
});
|
|
34818
|
+
jev.command("review <id> <verdict>").description("Review one case: correct | incorrect | missed | none | unclear").option("--note <text>", "short reason for the verdict", "").action((id, verdict, opts) => {
|
|
34819
|
+
if (!["correct", "incorrect", "missed", "none", "unclear"].includes(verdict)) throw new Error("jev_review_verdict_invalid");
|
|
34820
|
+
reviewJevCase(buildContext(stdoutLogger), id, verdict, opts.note);
|
|
34821
|
+
});
|
|
34720
34822
|
var parseLimit = (value) => {
|
|
34721
34823
|
const parsed = parseCursor(value);
|
|
34722
34824
|
if (parsed < 1 || parsed > 256) throw Error("invalid_limit");
|