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 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, constants4) {
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, constants4);
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, constants4) {
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, constants4);
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, constants4) {
547
- this.code = optimizeExpr(this.code, names, constants4);
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, constants4) {
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, constants4))
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, constants4) {
634
+ optimizeNames(names, constants5) {
635
635
  var _a3;
636
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
637
- if (!(super.optimizeNames(names, constants4) || this.else))
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, constants4);
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, constants4) {
663
- if (!super.optimizeNames(names, constants4))
662
+ optimizeNames(names, constants5) {
663
+ if (!super.optimizeNames(names, constants5))
664
664
  return;
665
- this.iteration = optimizeExpr(this.iteration, names, constants4);
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, constants4) {
702
- if (!super.optimizeNames(names, constants4))
701
+ optimizeNames(names, constants5) {
702
+ if (!super.optimizeNames(names, constants5))
703
703
  return;
704
- this.iterable = optimizeExpr(this.iterable, names, constants4);
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, constants4) {
746
+ optimizeNames(names, constants5) {
747
747
  var _a3, _b;
748
- super.optimizeNames(names, constants4);
749
- (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
750
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants4);
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, constants4) {
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 = constants4[n.str];
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 && constants4[c.str] !== void 0);
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, constants.X_OK) && isCanonicalAsset(actualCliScriptPath, cliScriptPath, constants.R_OK);
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" && isCanonicalAsset(server.command, nodePath, constants.X_OK) && Array.isArray(server.args) && server.args.length === 3 && server.args[0] === "--disable-warning=ExperimentalWarning" && isCanonicalAsset(server.args[1], cliScriptPath, constants.R_OK) && server.args[2] === "mcp-server" && server.env !== null && typeof server.env === "object" && !Array.isArray(server.env) && Object.values(server.env).every((value2) => typeof value2 === "string");
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 constants2, existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
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, constants2.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants2.R_OK) && tokens[2] === "codex-hook" && tokens[3] === event;
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 constants3 } from "node:fs";
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, constants3.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants3.R_OK) && tokens[2] === "cursor-hook" && tokens[3] === event;
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 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) } };
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);