caveat-cli 0.19.10 → 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/index.js +56 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,6 +66,9 @@ output also exposes `connectors.cursor.compatibility_status` for diagnosis,
|
|
|
66
66
|
but callers do not duplicate Caveat's Cursor event set, command rules, or
|
|
67
67
|
timeout checks. Without `--require-connector cursor`, the v1 aggregate keeps
|
|
68
68
|
its existing Claude/Codex readiness semantics.
|
|
69
|
+
For Grok, use `caveat factory-diagnostics --json --require-connector grok` to
|
|
70
|
+
check the enabled Caveat MCP registration and executable paths. A live MCP and
|
|
71
|
+
model smoke remain separate checks.
|
|
69
72
|
|
|
70
73
|
With either host enabled, Caveat surfaces matching entries at three moments:
|
|
71
74
|
before prompts, after failed tools, and after struggle-heavy sessions. Stop
|
|
@@ -87,6 +90,8 @@ caveat uninstall # reverse `caveat init` Claude integration
|
|
|
87
90
|
caveat codex-hook diagnostics # inspect Codex hook availability/install state
|
|
88
91
|
caveat factory-diagnostics --json --require-connector cursor
|
|
89
92
|
# machine gate for a host that requires Cursor
|
|
93
|
+
caveat factory-diagnostics --json --require-connector grok
|
|
94
|
+
# machine gate for a host that requires Grok MCP
|
|
90
95
|
```
|
|
91
96
|
|
|
92
97
|
## Sharing: two boundaries, two commands
|
package/dist/index.js
CHANGED
|
@@ -458,11 +458,11 @@ var require_codegen = __commonJS({
|
|
|
458
458
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
459
459
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
460
460
|
}
|
|
461
|
-
optimizeNames(names,
|
|
461
|
+
optimizeNames(names, constants5) {
|
|
462
462
|
if (!names[this.name.str])
|
|
463
463
|
return;
|
|
464
464
|
if (this.rhs)
|
|
465
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
465
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
466
466
|
return this;
|
|
467
467
|
}
|
|
468
468
|
get names() {
|
|
@@ -479,10 +479,10 @@ var require_codegen = __commonJS({
|
|
|
479
479
|
render({ _n }) {
|
|
480
480
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
481
481
|
}
|
|
482
|
-
optimizeNames(names,
|
|
482
|
+
optimizeNames(names, constants5) {
|
|
483
483
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
484
484
|
return;
|
|
485
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
485
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
486
486
|
return this;
|
|
487
487
|
}
|
|
488
488
|
get names() {
|
|
@@ -543,8 +543,8 @@ var require_codegen = __commonJS({
|
|
|
543
543
|
optimizeNodes() {
|
|
544
544
|
return `${this.code}` ? this : void 0;
|
|
545
545
|
}
|
|
546
|
-
optimizeNames(names,
|
|
547
|
-
this.code = optimizeExpr(this.code, names,
|
|
546
|
+
optimizeNames(names, constants5) {
|
|
547
|
+
this.code = optimizeExpr(this.code, names, constants5);
|
|
548
548
|
return this;
|
|
549
549
|
}
|
|
550
550
|
get names() {
|
|
@@ -573,12 +573,12 @@ var require_codegen = __commonJS({
|
|
|
573
573
|
}
|
|
574
574
|
return nodes.length > 0 ? this : void 0;
|
|
575
575
|
}
|
|
576
|
-
optimizeNames(names,
|
|
576
|
+
optimizeNames(names, constants5) {
|
|
577
577
|
const { nodes } = this;
|
|
578
578
|
let i = nodes.length;
|
|
579
579
|
while (i--) {
|
|
580
580
|
const n = nodes[i];
|
|
581
|
-
if (n.optimizeNames(names,
|
|
581
|
+
if (n.optimizeNames(names, constants5))
|
|
582
582
|
continue;
|
|
583
583
|
subtractNames(names, n.names);
|
|
584
584
|
nodes.splice(i, 1);
|
|
@@ -631,12 +631,12 @@ var require_codegen = __commonJS({
|
|
|
631
631
|
return void 0;
|
|
632
632
|
return this;
|
|
633
633
|
}
|
|
634
|
-
optimizeNames(names,
|
|
634
|
+
optimizeNames(names, constants5) {
|
|
635
635
|
var _a3;
|
|
636
|
-
this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
637
|
-
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))
|
|
638
638
|
return;
|
|
639
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
639
|
+
this.condition = optimizeExpr(this.condition, names, constants5);
|
|
640
640
|
return this;
|
|
641
641
|
}
|
|
642
642
|
get names() {
|
|
@@ -659,10 +659,10 @@ var require_codegen = __commonJS({
|
|
|
659
659
|
render(opts) {
|
|
660
660
|
return `for(${this.iteration})` + super.render(opts);
|
|
661
661
|
}
|
|
662
|
-
optimizeNames(names,
|
|
663
|
-
if (!super.optimizeNames(names,
|
|
662
|
+
optimizeNames(names, constants5) {
|
|
663
|
+
if (!super.optimizeNames(names, constants5))
|
|
664
664
|
return;
|
|
665
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
665
|
+
this.iteration = optimizeExpr(this.iteration, names, constants5);
|
|
666
666
|
return this;
|
|
667
667
|
}
|
|
668
668
|
get names() {
|
|
@@ -698,10 +698,10 @@ var require_codegen = __commonJS({
|
|
|
698
698
|
render(opts) {
|
|
699
699
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
700
700
|
}
|
|
701
|
-
optimizeNames(names,
|
|
702
|
-
if (!super.optimizeNames(names,
|
|
701
|
+
optimizeNames(names, constants5) {
|
|
702
|
+
if (!super.optimizeNames(names, constants5))
|
|
703
703
|
return;
|
|
704
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
704
|
+
this.iterable = optimizeExpr(this.iterable, names, constants5);
|
|
705
705
|
return this;
|
|
706
706
|
}
|
|
707
707
|
get names() {
|
|
@@ -743,11 +743,11 @@ var require_codegen = __commonJS({
|
|
|
743
743
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
744
744
|
return this;
|
|
745
745
|
}
|
|
746
|
-
optimizeNames(names,
|
|
746
|
+
optimizeNames(names, constants5) {
|
|
747
747
|
var _a3, _b;
|
|
748
|
-
super.optimizeNames(names,
|
|
749
|
-
(_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
750
|
-
(_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);
|
|
751
751
|
return this;
|
|
752
752
|
}
|
|
753
753
|
get names() {
|
|
@@ -1048,7 +1048,7 @@ var require_codegen = __commonJS({
|
|
|
1048
1048
|
function addExprNames(names, from) {
|
|
1049
1049
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
1050
1050
|
}
|
|
1051
|
-
function optimizeExpr(expr, names,
|
|
1051
|
+
function optimizeExpr(expr, names, constants5) {
|
|
1052
1052
|
if (expr instanceof code_1.Name)
|
|
1053
1053
|
return replaceName(expr);
|
|
1054
1054
|
if (!canOptimize(expr))
|
|
@@ -1063,14 +1063,14 @@ var require_codegen = __commonJS({
|
|
|
1063
1063
|
return items;
|
|
1064
1064
|
}, []));
|
|
1065
1065
|
function replaceName(n) {
|
|
1066
|
-
const c =
|
|
1066
|
+
const c = constants5[n.str];
|
|
1067
1067
|
if (c === void 0 || names[n.str] !== 1)
|
|
1068
1068
|
return n;
|
|
1069
1069
|
delete names[n.str];
|
|
1070
1070
|
return c;
|
|
1071
1071
|
}
|
|
1072
1072
|
function canOptimize(e) {
|
|
1073
|
-
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);
|
|
1074
1074
|
}
|
|
1075
1075
|
}
|
|
1076
1076
|
function subtractNames(names, from) {
|
|
@@ -6896,7 +6896,7 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync, rename
|
|
|
6896
6896
|
import { dirname as dirname3, join as join8 } from "node:path";
|
|
6897
6897
|
|
|
6898
6898
|
// src/claudeInstall.ts
|
|
6899
|
-
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";
|
|
6900
6900
|
import { join as join4 } from "node:path";
|
|
6901
6901
|
|
|
6902
6902
|
// src/installShared.ts
|
|
@@ -6957,9 +6957,13 @@ function claudeMcpConfigPath(claudeDir, env = process.env) {
|
|
|
6957
6957
|
}
|
|
6958
6958
|
|
|
6959
6959
|
// src/mcpInstall.ts
|
|
6960
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
6960
|
+
import { constants, existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
6961
6961
|
import { isDeepStrictEqual } from "node:util";
|
|
6962
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
|
+
}
|
|
6963
6967
|
function object(value) {
|
|
6964
6968
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6965
6969
|
}
|
|
@@ -7063,12 +7067,12 @@ function isCanonicalCaveatClaudeHookCommand(actual, event, nodePath, cliScriptPa
|
|
|
7063
7067
|
const [actualNodePath, actualCliScriptPath, subcommand, actualEvent] = tokens ?? [];
|
|
7064
7068
|
if (tokens?.length !== 4 || actualNodePath === void 0 || actualCliScriptPath === void 0 || subcommand !== "hook" || actualEvent !== event) return false;
|
|
7065
7069
|
if (actual !== hookCommand(actualNodePath, actualCliScriptPath, event)) return false;
|
|
7066
|
-
return isCanonicalAsset(actualNodePath, nodePath,
|
|
7070
|
+
return isCanonicalAsset(actualNodePath, nodePath, constants2.X_OK) && isCanonicalAsset(actualCliScriptPath, cliScriptPath, constants2.R_OK);
|
|
7067
7071
|
}
|
|
7068
7072
|
function isCaveatClaudeMcpRegistration(value, nodePath, cliScriptPath) {
|
|
7069
7073
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7070
7074
|
const server = value;
|
|
7071
|
-
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");
|
|
7072
7076
|
}
|
|
7073
7077
|
function readSettings(path) {
|
|
7074
7078
|
if (!existsSync3(path)) return {};
|
|
@@ -7150,7 +7154,7 @@ function uninstallClaudeIntegration(opts) {
|
|
|
7150
7154
|
}
|
|
7151
7155
|
|
|
7152
7156
|
// src/codexHookInstall.ts
|
|
7153
|
-
import { constants as
|
|
7157
|
+
import { constants as constants3, existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
7154
7158
|
import { join as join5 } from "node:path";
|
|
7155
7159
|
import { parse as parseToml } from "smol-toml";
|
|
7156
7160
|
function hookCommand2(nodePath, cliScriptPath, event, platform = process.platform) {
|
|
@@ -7175,7 +7179,7 @@ function isCaveatCodexHookCommand(actual, event) {
|
|
|
7175
7179
|
function isCanonicalCaveatCodexHookCommand(actual, event, nodePath, cliScriptPath) {
|
|
7176
7180
|
const parsed = commandTokens(actual);
|
|
7177
7181
|
const tokens = parsed?.[0] === "&" ? parsed.slice(1) : parsed;
|
|
7178
|
-
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;
|
|
7179
7183
|
}
|
|
7180
7184
|
function isCanonicalCaveatCodexHookEntry(value, event, nodePath, cliScriptPath) {
|
|
7181
7185
|
if (!isPlainRecord(value) || typeof value.type !== "string" || typeof value.command !== "string") return false;
|
|
@@ -7534,7 +7538,7 @@ function detectCodexHookInstallation(codexHome) {
|
|
|
7534
7538
|
// src/cursorInstall.ts
|
|
7535
7539
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
7536
7540
|
import { join as join6 } from "node:path";
|
|
7537
|
-
import { constants as
|
|
7541
|
+
import { constants as constants4 } from "node:fs";
|
|
7538
7542
|
var TIMEOUT_SEC = 10;
|
|
7539
7543
|
function hookCommand3(nodePath, cliScriptPath, event) {
|
|
7540
7544
|
return `${quoteCommandPath(nodePath)} ${quoteCommandPath(cliScriptPath)} cursor-hook ${event}`;
|
|
@@ -7548,7 +7552,7 @@ function isCaveatCursorHookCommand(actual, event) {
|
|
|
7548
7552
|
}
|
|
7549
7553
|
function isCanonicalCaveatCursorHookCommand(actual, event, nodePath, cliScriptPath) {
|
|
7550
7554
|
const tokens = commandTokens(actual);
|
|
7551
|
-
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;
|
|
7552
7556
|
}
|
|
7553
7557
|
function isCanonicalCaveatCursorHookEntry(value, event, nodePath, cliScriptPath) {
|
|
7554
7558
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -34593,6 +34597,20 @@ function claudeRegistration(path, nodePath, cliScriptPath) {
|
|
|
34593
34597
|
return unverified("config_unreadable");
|
|
34594
34598
|
}
|
|
34595
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
|
+
}
|
|
34596
34614
|
function claudeHooks(claudeDir, nodePath, cliScriptPath) {
|
|
34597
34615
|
try {
|
|
34598
34616
|
const settings = JSON.parse(readFileSync12(join18(claudeDir, "settings.json"), "utf8"));
|
|
@@ -34690,7 +34708,7 @@ function sync(own) {
|
|
|
34690
34708
|
}
|
|
34691
34709
|
}
|
|
34692
34710
|
function factoryDiagnostics(ctx, codexHome = resolveAgentConfigPaths(ctx.userHome).codexHome, requiredConnectors = []) {
|
|
34693
|
-
const { claudeDir, claudeMcp, cursorDir } = resolveAgentConfigPaths(ctx.userHome);
|
|
34711
|
+
const { claudeDir, claudeMcp, cursorDir, grokHome } = resolveAgentConfigPaths(ctx.userHome);
|
|
34694
34712
|
const nodePath = process.execPath;
|
|
34695
34713
|
const cliScriptPath = process.argv[1] ?? "";
|
|
34696
34714
|
const db = database(ctx.paths.dbPath);
|
|
@@ -34701,13 +34719,15 @@ function factoryDiagnostics(ctx, codexHome = resolveAgentConfigPaths(ctx.userHom
|
|
|
34701
34719
|
} catch {
|
|
34702
34720
|
}
|
|
34703
34721
|
const codexHook2 = (present) => present === void 0 ? unverified("config_unreadable") : !present ? hook(false) : feature.status === "ready" ? hook(true) : { ...feature };
|
|
34704
|
-
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 } } };
|
|
34705
34724
|
const aggregate = (all) => all.includes("not_ready") ? "not_ready" : all.includes("unverified") ? "unverified" : "ready";
|
|
34706
34725
|
const connectorStatus = (connector) => aggregate([...Object.values(connector.hooks), ...connector.mcp ? [connector.mcp] : []].map((v) => v.status));
|
|
34707
34726
|
output.connectors.claude.status = connectorStatus(output.connectors.claude);
|
|
34708
34727
|
output.connectors.codex.status = connectorStatus(output.connectors.codex);
|
|
34709
34728
|
const statuses = [output.database.status, output.sync.status, output.connectors.claude.status, output.connectors.codex.status];
|
|
34710
34729
|
if (requiredConnectors.includes("cursor")) statuses.push(output.connectors.cursor.compatibility_status);
|
|
34730
|
+
if (requiredConnectors.includes("grok")) statuses.push(output.connectors.grok.status);
|
|
34711
34731
|
output.overall.status = aggregate(statuses);
|
|
34712
34732
|
return output;
|
|
34713
34733
|
}
|
|
@@ -34773,7 +34793,7 @@ function collectRepeatable(value, previous) {
|
|
|
34773
34793
|
}
|
|
34774
34794
|
program.name("caveat").description("External spec gotcha knowledge base CLI").version(CAVEAT_VERSION);
|
|
34775
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) => {
|
|
34776
|
-
const unsupported = opts.requireConnector.filter((name) => name !== "cursor");
|
|
34796
|
+
const unsupported = opts.requireConnector.filter((name) => name !== "cursor" && name !== "grok");
|
|
34777
34797
|
if (unsupported.length > 0) throw new Error(`unsupported factory connector: ${unsupported.join(", ")}`);
|
|
34778
34798
|
const requiredConnectors = [...new Set(opts.requireConnector)];
|
|
34779
34799
|
const output = factoryDiagnostics(buildContext(stdoutLogger), void 0, requiredConnectors);
|