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 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
@@ -11638,12 +11638,12 @@ var init_task_callback = __esm({
11638
11638
  init_utils();
11639
11639
  }
11640
11640
  });
11641
- function changeWorkingDirectoryTask(directory, root) {
11641
+ function changeWorkingDirectoryTask(directory2, root) {
11642
11642
  return adhocExecTask((instance) => {
11643
- if (!folderExists(directory)) {
11644
- throw new Error(`Git.cwd: cannot change to non-directory "${directory}"`);
11643
+ if (!folderExists(directory2)) {
11644
+ throw new Error(`Git.cwd: cannot change to non-directory "${directory2}"`);
11645
11645
  }
11646
- return (root || instance).cwd = directory;
11646
+ return (root || instance).cwd = directory2;
11647
11647
  });
11648
11648
  }
11649
11649
  var init_change_working_directory = __esm({
@@ -13042,15 +13042,15 @@ var init_clone = __esm({
13042
13042
  "use strict";
13043
13043
  init_task();
13044
13044
  init_utils();
13045
- cloneTask = (repo, directory, customArgs) => {
13045
+ cloneTask = (repo, directory2, customArgs) => {
13046
13046
  const commands = ["clone", ...customArgs];
13047
13047
  filterString(repo) && commands.push(c(repo));
13048
- filterString(directory) && commands.push(c(directory));
13048
+ filterString(directory2) && commands.push(c(directory2));
13049
13049
  return straightThroughStringTask(commands);
13050
13050
  };
13051
- cloneMirrorTask = (repo, directory, customArgs) => {
13051
+ cloneMirrorTask = (repo, directory2, customArgs) => {
13052
13052
  append(customArgs, "--mirror");
13053
- return cloneTask(repo, directory, customArgs);
13053
+ return cloneTask(repo, directory2, customArgs);
13054
13054
  };
13055
13055
  }
13056
13056
  });
@@ -13103,16 +13103,16 @@ var init_simple_git_api = __esm({
13103
13103
  trailingFunctionArgument(arguments)
13104
13104
  );
13105
13105
  }
13106
- cwd(directory) {
13106
+ cwd(directory2) {
13107
13107
  const next = trailingFunctionArgument(arguments);
13108
- if (typeof directory === "string") {
13109
- return this._runTask(changeWorkingDirectoryTask(directory, this._executor), next);
13108
+ if (typeof directory2 === "string") {
13109
+ return this._runTask(changeWorkingDirectoryTask(directory2, this._executor), next);
13110
13110
  }
13111
- if (typeof directory?.path === "string") {
13111
+ if (typeof directory2?.path === "string") {
13112
13112
  return this._runTask(
13113
13113
  changeWorkingDirectoryTask(
13114
- directory.path,
13115
- directory.root && this._executor || void 0
13114
+ directory2.path,
13115
+ directory2.root && this._executor || void 0
13116
13116
  ),
13117
13117
  next
13118
13118
  );
@@ -17156,14 +17156,14 @@ function ensureSafeDir(dir, isWin, options2 = {}) {
17156
17156
  var WINDOWS_ACL_VERIFY = String.raw`$ErrorActionPreference='Stop';$p=$env:CAVEAT_ACL_PATH;$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value;$acl=Get-Acl -LiteralPath $p;$owner=$acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value;if($owner -ne $sid){exit 41};$rules=@($acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier]));if($rules.Count -ne 1){exit 42};$r=$rules[0];if($r.IdentityReference.Value -ne $sid -or $r.AccessControlType -ne 'Allow' -or $r.IsInherited -or ($r.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl){exit 43}`;
17157
17157
  var WINDOWS_ACL_APPLY = String.raw`$ErrorActionPreference='Stop';$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User;$acl=if($isDir){New-Object System.Security.AccessControl.DirectorySecurity}else{New-Object System.Security.AccessControl.FileSecurity};$acl.SetAccessRuleProtection($true,$false);$flags=if($isDir){[System.Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'}else{[System.Security.AccessControl.InheritanceFlags]::None};$rule=New-Object System.Security.AccessControl.FileSystemAccessRule($sid,'FullControl',$flags,[System.Security.AccessControl.PropagationFlags]::None,[System.Security.AccessControl.AccessControlType]::Allow);$acl.SetOwner($sid);$acl.AddAccessRule($rule);Set-Acl -LiteralPath $p -AclObject $acl;` + WINDOWS_ACL_VERIFY;
17158
17158
  var WINDOWS_ACL_TIMEOUT_MS = 3e4;
17159
- function runWindowsAcl(path, directory, apply) {
17160
- const result = spawnSync("pwsh.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", apply ? WINDOWS_ACL_APPLY : WINDOWS_ACL_VERIFY], { env: { ...process.env, CAVEAT_ACL_PATH: path, CAVEAT_ACL_DIRECTORY: directory ? "1" : "0" }, encoding: "utf-8", timeout: WINDOWS_ACL_TIMEOUT_MS, windowsHide: true });
17159
+ function runWindowsAcl(path, directory2, apply) {
17160
+ const result = spawnSync("pwsh.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", apply ? WINDOWS_ACL_APPLY : WINDOWS_ACL_VERIFY], { env: { ...process.env, CAVEAT_ACL_PATH: path, CAVEAT_ACL_DIRECTORY: directory2 ? "1" : "0" }, encoding: "utf-8", timeout: WINDOWS_ACL_TIMEOUT_MS, windowsHide: true });
17161
17161
  if (result.error !== void 0) throw Error(`store_unsafe: powershell spawn ${result.error.code ?? result.error.message}`);
17162
17162
  if (result.status !== 0) throw Error(`store_unsafe: powershell exit=${result.status} signal=${result.signal ?? "none"} stderr=${(result.stderr ?? "").replace(/\s+/g, " ").trim().slice(0, 400) || "(empty)"}`);
17163
17163
  }
17164
- function secureWindowsAcl(path, runner, directory = false, apply = false) {
17164
+ function secureWindowsAcl(path, runner, directory2 = false, apply = false) {
17165
17165
  try {
17166
- (runner ?? runWindowsAcl)(path, directory, apply);
17166
+ (runner ?? runWindowsAcl)(path, directory2, apply);
17167
17167
  } catch (cause) {
17168
17168
  throw Error("store_unsafe", { cause });
17169
17169
  }
@@ -17377,6 +17377,63 @@ function compactRuntimeErrors(options2 = {}) {
17377
17377
  return snapshot(normalized);
17378
17378
  }
17379
17379
 
17380
+ // ../../packages/core/dist/jevObservations.js
17381
+ import { createHash as createHash8, randomBytes as randomBytes4 } from "node:crypto";
17382
+ import { existsSync as existsSync17, mkdirSync as mkdirSync9, readFileSync as readFileSync15, readdirSync as readdirSync9, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
17383
+ import { join as join14 } from "node:path";
17384
+ var JEV_OBSERVATION_SCHEMA = "caveat.jev_observation.v1";
17385
+ var directory = (home) => join14(home, "jev-observations");
17386
+ var pathFor = (home, id) => {
17387
+ if (!/^[0-9a-f]{64}$/.test(id)) throw new Error("jev_observation_id_invalid");
17388
+ return join14(directory(home), `${id}.json`);
17389
+ };
17390
+ function jevObservationId(host, sessionId, turnKey) {
17391
+ return createHash8("sha256").update(`${host}\0${sessionId}\0${turnKey}`).digest("hex");
17392
+ }
17393
+ function validate2(value) {
17394
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("jev_observation_invalid");
17395
+ const item = value;
17396
+ if (item.schema !== JEV_OBSERVATION_SCHEMA || typeof item.id !== "string" || !/^[0-9a-f]{64}$/.test(item.id) || !["claude", "codex"].includes(item.host) || typeof item.observedAt !== "string" || typeof item.sessionId !== "string" || typeof item.projectRoot !== "string" || typeof item.transcriptPath !== "string" || !Array.isArray(item.turns) || item.turns.some((turn) => typeof turn.originSessionId !== "string" || !Number.isSafeInteger(turn.turnNumber) || typeof turn.truncated !== "boolean") || typeof item.thinkingAvailable !== "boolean" || typeof item.model !== "string" || ![item.repeatedProblem, item.clearlyStuck, item.struggleThreshold, item.matchThreshold].every((score) => typeof score === "number" && Number.isFinite(score) && score >= 0 && score <= 1) || typeof item.struggling !== "boolean" || !Array.isArray(item.termChoices) || item.termChoices.some((choice) => typeof choice.term !== "string" || typeof choice.probability !== "number") || item.noneProbability !== null && typeof item.noneProbability !== "number" || !Array.isArray(item.selectedTerms) || item.selectedTerms.some((term) => typeof term !== "string") || typeof item.query !== "string" || !Array.isArray(item.ftsHits) || item.ftsHits.some((ref) => typeof ref !== "string") || !Array.isArray(item.candidates) || item.candidates.some((candidate) => typeof candidate.ref !== "string" || typeof candidate.score !== "number" || !Number.isFinite(candidate.score)) || item.selectedRef !== null && typeof item.selectedRef !== "string" || item.noticeText !== null && typeof item.noticeText !== "string" || !["below_struggle_threshold", "no_terms", "no_candidates", "below_match_threshold", "matched"].includes(item.decision) || !["none", "pending", "delivered", "suppressed"].includes(item.delivery) || item.review !== null && (!item.review || typeof item.review !== "object" || !["correct", "incorrect", "missed", "none", "unclear"].includes(item.review.verdict) || typeof item.review.note !== "string" || typeof item.review.reviewedAt !== "string")) throw new Error("jev_observation_invalid");
17397
+ }
17398
+ function readJevObservation(home, id) {
17399
+ const value = JSON.parse(readFileSync15(pathFor(home, id), "utf8"));
17400
+ validate2(value);
17401
+ if (value.id !== id) throw new Error("jev_observation_id_mismatch");
17402
+ return value;
17403
+ }
17404
+ function listJevObservations(home) {
17405
+ const dir = directory(home);
17406
+ if (!existsSync17(dir)) return [];
17407
+ return readdirSync9(dir).filter((name) => /^[0-9a-f]{64}\.json$/.test(name)).map((name) => readJevObservation(home, name.slice(0, -5))).sort((a, b2) => b2.observedAt.localeCompare(a.observedAt) || b2.id.localeCompare(a.id));
17408
+ }
17409
+ function writeJevObservation(home, item) {
17410
+ validate2(item);
17411
+ const dir = directory(home);
17412
+ mkdirSync9(dir, { recursive: true, mode: 448 });
17413
+ const path = pathFor(home, item.id);
17414
+ const temporary = `${path}.${randomBytes4(6).toString("hex")}.tmp`;
17415
+ try {
17416
+ writeFileSync10(temporary, `${JSON.stringify(item)}
17417
+ `, { encoding: "utf8", mode: 384, flag: "wx" });
17418
+ renameSync5(temporary, path);
17419
+ } finally {
17420
+ rmSync7(temporary, { force: true });
17421
+ }
17422
+ }
17423
+ function updateJevDelivery(home, id) {
17424
+ const item = readJevObservation(home, id);
17425
+ if (item.delivery !== "pending") throw new Error("jev_observation_not_pending");
17426
+ writeJevObservation(home, { ...item, delivery: "delivered" });
17427
+ }
17428
+ function reviewJevObservation(home, id, verdict, note = "") {
17429
+ const item = readJevObservation(home, id);
17430
+ const adviceDelivered = item.delivery === "delivered" && item.selectedRef !== null;
17431
+ if (item.delivery === "pending" || item.delivery === "suppressed" || adviceDelivered && !["correct", "incorrect", "unclear"].includes(verdict) || !adviceDelivered && !["missed", "none", "unclear"].includes(verdict)) throw new Error("jev_review_verdict_invalid");
17432
+ const updated = { ...item, review: { verdict, note, reviewedAt: (/* @__PURE__ */ new Date()).toISOString() } };
17433
+ writeJevObservation(home, updated);
17434
+ return updated;
17435
+ }
17436
+
17380
17437
  // ../../packages/core/dist/env.js
17381
17438
  var import_semver = __toESM(require_semver2(), 1);
17382
17439
  function fingerprint2() {
@@ -17410,10 +17467,10 @@ function environmentAppliesToTask(environment, taskText, hostPlatform2) {
17410
17467
  }
17411
17468
 
17412
17469
  // ../../packages/core/dist/id.js
17413
- import { randomBytes as randomBytes4 } from "node:crypto";
17470
+ import { randomBytes as randomBytes5 } from "node:crypto";
17414
17471
  function randomHex(hexChars) {
17415
17472
  const bytes = Math.ceil(hexChars / 2);
17416
- return randomBytes4(bytes).toString("hex").slice(0, hexChars);
17473
+ return randomBytes5(bytes).toString("hex").slice(0, hexChars);
17417
17474
  }
17418
17475
  function slugify(title, now2 = () => /* @__PURE__ */ new Date()) {
17419
17476
  const lowered = title.toLowerCase();
@@ -17438,7 +17495,7 @@ function generateSourceSession(now2 = () => /* @__PURE__ */ new Date()) {
17438
17495
  }
17439
17496
 
17440
17497
  // ../../packages/core/dist/writer.js
17441
- import { existsSync as existsSync17, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
17498
+ import { existsSync as existsSync18, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "node:fs";
17442
17499
  import { dirname as dirname9 } from "node:path";
17443
17500
  function buildEntry(frontmatter, sections) {
17444
17501
  const bodyParts = [];
@@ -17458,13 +17515,13 @@ ${body}${body ? "\n" : ""}`;
17458
17515
  }
17459
17516
  function writeEntryFile(filePath, content) {
17460
17517
  const dir = dirname9(filePath);
17461
- if (!existsSync17(dir)) mkdirSync9(dir, { recursive: true });
17462
- writeFileSync10(filePath, content, "utf-8");
17518
+ if (!existsSync18(dir)) mkdirSync10(dir, { recursive: true });
17519
+ writeFileSync11(filePath, content, "utf-8");
17463
17520
  }
17464
17521
 
17465
17522
  // ../../packages/core/dist/record.js
17466
17523
  import { statSync as statSync8 } from "node:fs";
17467
- import { join as join14 } from "node:path";
17524
+ import { join as join15 } from "node:path";
17468
17525
  var DEFAULT_CATEGORY = "misc";
17469
17526
  function recordEntry(input, opts) {
17470
17527
  const now2 = opts.now ?? (() => /* @__PURE__ */ new Date());
@@ -17500,7 +17557,7 @@ function recordEntry(input, opts) {
17500
17557
  const built = buildEntry(frontmatter, sections);
17501
17558
  const category = input.category ?? DEFAULT_CATEGORY;
17502
17559
  const relPath = `${category}/${id}.md`;
17503
- const filePath = join14(opts.entriesRoot, relPath);
17560
+ const filePath = join15(opts.entriesRoot, relPath);
17504
17561
  writeEntryFile(filePath, built.content);
17505
17562
  const stat = statSync8(filePath);
17506
17563
  upsertEntry(opts.db, {
@@ -17530,8 +17587,8 @@ function formatYmd(d) {
17530
17587
  }
17531
17588
 
17532
17589
  // ../../packages/core/dist/update.js
17533
- import { readFileSync as readFileSync15, statSync as statSync9, writeFileSync as writeFileSync11 } from "node:fs";
17534
- import { join as join15 } from "node:path";
17590
+ import { readFileSync as readFileSync16, statSync as statSync9, writeFileSync as writeFileSync12 } from "node:fs";
17591
+ import { join as join16 } from "node:path";
17535
17592
  var IMMUTABLE_KEYS = /* @__PURE__ */ new Set([
17536
17593
  "id",
17537
17594
  "created_at",
@@ -17550,8 +17607,8 @@ function updateEntry(id, patch, opts) {
17550
17607
  throw new Error(`caveat not found: id=${id} source=${source}`);
17551
17608
  }
17552
17609
  const relPath = row.path;
17553
- const filePath = join15(opts.entriesRoot, relPath);
17554
- const raw = readFileSync15(filePath, "utf-8");
17610
+ const filePath = join16(opts.entriesRoot, relPath);
17611
+ const raw = readFileSync16(filePath, "utf-8");
17555
17612
  const parsed = parseMarkdown(raw);
17556
17613
  if (patch.frontmatter) {
17557
17614
  for (const key of Object.keys(patch.frontmatter)) {
@@ -17592,7 +17649,7 @@ function updateEntry(id, patch, opts) {
17592
17649
  }
17593
17650
  }
17594
17651
  const built = buildEntry(mergedFrontmatter, mergedSections);
17595
- writeFileSync11(filePath, built.content, "utf-8");
17652
+ writeFileSync12(filePath, built.content, "utf-8");
17596
17653
  const stat = statSync9(filePath);
17597
17654
  upsertEntry(opts.db, {
17598
17655
  id,
@@ -17629,16 +17686,16 @@ function markHit(db, keys, now2 = () => (/* @__PURE__ */ new Date()).toISOString
17629
17686
  }
17630
17687
 
17631
17688
  // ../../packages/core/dist/hookQueryLog.js
17632
- import { appendFileSync, chmodSync as chmodSync2, mkdirSync as mkdirSync10, renameSync as renameSync5, statSync as statSync10, unlinkSync as unlinkSync3 } from "node:fs";
17633
- import { join as join16, resolve as resolve3 } from "node:path";
17689
+ import { appendFileSync, chmodSync as chmodSync2, mkdirSync as mkdirSync11, renameSync as renameSync6, statSync as statSync10, unlinkSync as unlinkSync3 } from "node:fs";
17690
+ import { join as join17, resolve as resolve3 } from "node:path";
17634
17691
  var CAVEAT_HOOK_QUERY_LOG_ENV = "CAVEAT_HOOK_QUERY_LOG";
17635
17692
  var HOOK_QUERY_LOG_MAX_BYTES = 1024 * 1024;
17636
17693
  var HOOK_QUERY_LOG_MAX_QUERY_CODE_UNITS = 1e3;
17637
17694
  var fsDependencies = {
17638
17695
  appendFileSync,
17639
17696
  chmodSync: chmodSync2,
17640
- mkdirSync: mkdirSync10,
17641
- renameSync: renameSync5,
17697
+ mkdirSync: mkdirSync11,
17698
+ renameSync: renameSync6,
17642
17699
  statSync: statSync10,
17643
17700
  unlinkSync: unlinkSync3
17644
17701
  };
@@ -17654,8 +17711,8 @@ function chmodExistingFile(path, dependencies) {
17654
17711
  }
17655
17712
  function logHookQueryMiss(miss, dependencies = fsDependencies) {
17656
17713
  if (process.env[CAVEAT_HOOK_QUERY_LOG_ENV] !== "on") return;
17657
- const metricsDir = join16(resolve3(miss.caveatHome), "metrics");
17658
- const activePath = join16(metricsDir, "hook-search-misses.jsonl");
17714
+ const metricsDir = join17(resolve3(miss.caveatHome), "metrics");
17715
+ const activePath = join17(metricsDir, "hook-search-misses.jsonl");
17659
17716
  const backupPath = `${activePath}.1`;
17660
17717
  const record = JSON.stringify({
17661
17718
  at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -17696,15 +17753,15 @@ function logHookQueryMiss(miss, dependencies = fsDependencies) {
17696
17753
  }
17697
17754
 
17698
17755
  // ../../packages/core/dist/proposalEval.js
17699
- import { createHash as createHash8 } from "node:crypto";
17756
+ import { createHash as createHash9 } from "node:crypto";
17700
17757
  import { isAbsolute as isAbsolute2, relative as relative4, resolve as resolve4, sep } from "node:path";
17701
17758
 
17702
17759
  // ../../packages/core/dist/proposalExecution.js
17703
- import { createHash as createHash9 } from "node:crypto";
17760
+ import { createHash as createHash10 } from "node:crypto";
17704
17761
  import { basename as basename3, isAbsolute as isAbsolute3 } from "node:path";
17705
17762
 
17706
17763
  // ../../packages/core/dist/proposalExecutionCompiler.js
17707
- import { createHash as createHash10 } from "node:crypto";
17764
+ import { createHash as createHash11 } from "node:crypto";
17708
17765
 
17709
17766
  export {
17710
17767
  __commonJS,
@@ -17778,7 +17835,12 @@ export {
17778
17835
  runtimeErrorsSnapshot,
17779
17836
  acknowledgeRuntimeErrors,
17780
17837
  setRuntimeErrorStatus,
17781
- compactRuntimeErrors
17838
+ compactRuntimeErrors,
17839
+ jevObservationId,
17840
+ listJevObservations,
17841
+ writeJevObservation,
17842
+ updateJevDelivery,
17843
+ reviewJevObservation
17782
17844
  };
17783
17845
  /*! Bundled license information:
17784
17846
 
@@ -17801,4 +17863,4 @@ strip-bom-string/index.js:
17801
17863
  js-yaml/dist/js-yaml.mjs:
17802
17864
  (*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT *)
17803
17865
  */
17804
- //# sourceMappingURL=chunk-ITQLGM4K.js.map
17866
+ //# sourceMappingURL=chunk-PFYFYJNS.js.map