caveat-cli 0.16.1 → 0.16.3

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.js CHANGED
@@ -10,27 +10,30 @@ import {
10
10
  __commonJS,
11
11
  __export,
12
12
  __toESM,
13
+ acknowledgeRuntimeErrors,
13
14
  acquireReindexLock,
14
- appendPendingReminder,
15
+ buildAndPublishPendingReminder,
15
16
  buildCodexSidecarDiagnosticsCommand,
16
17
  buildCodexSidecarReadOnlySmokeCommand,
17
18
  buildCodexSidecarRunCommand,
18
19
  buildHookSignalSidecarContextBlock,
20
+ buildPendingSemanticKey,
19
21
  caveatEntriesToSidecarContextBlocks,
20
22
  cleanupStalePendingDirs,
21
23
  communityAdd,
22
24
  communityList,
23
25
  communityPull,
24
26
  communityRemove,
27
+ compactRuntimeErrors,
25
28
  computeEntriesDigest,
26
29
  createKeyserverKeyProvider,
27
30
  decideCodexSidecarExecution,
28
31
  defaultSelfIdentityTokens,
29
- drainGlobalPendingReminders,
30
- drainPendingReminders,
32
+ drainPendingRemindersDetailed,
31
33
  ensureUserConfig,
32
34
  findCaveatHome,
33
- findCaveatsForPrompt,
35
+ findCaveatsForHook,
36
+ findCaveatsForHookSegments,
34
37
  get,
35
38
  hasAnyStruggleSignal,
36
39
  initOwnSync,
@@ -40,6 +43,7 @@ import {
40
43
  logHookQueryMiss,
41
44
  markHit,
42
45
  maybeSweepPendingDirs,
46
+ observeRuntimeError,
43
47
  openDb,
44
48
  prewarmSealedKeys,
45
49
  publishOwn,
@@ -53,7 +57,10 @@ import {
53
57
  resetAutoSyncFailureState,
54
58
  resolvePaths,
55
59
  runAutoSync,
60
+ runtimeErrorsDiagnostics,
61
+ runtimeErrorsSnapshot,
56
62
  search,
63
+ setRuntimeErrorStatus,
57
64
  stderrLogger,
58
65
  stopReminderText,
59
66
  struggleSearchText,
@@ -63,7 +70,7 @@ import {
63
70
  userPromptSubmitReminderText,
64
71
  writeDigestMarker,
65
72
  writeUserConfigPatch
66
- } from "./chunk-HCLEIAGO.js";
73
+ } from "./chunk-PD5E6TFL.js";
67
74
 
68
75
  // ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
69
76
  var require_code = __commonJS({
@@ -442,11 +449,11 @@ var require_codegen = __commonJS({
442
449
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
443
450
  return `${varKind} ${this.name}${rhs};` + _n;
444
451
  }
445
- optimizeNames(names, constants2) {
452
+ optimizeNames(names, constants4) {
446
453
  if (!names[this.name.str])
447
454
  return;
448
455
  if (this.rhs)
449
- this.rhs = optimizeExpr(this.rhs, names, constants2);
456
+ this.rhs = optimizeExpr(this.rhs, names, constants4);
450
457
  return this;
451
458
  }
452
459
  get names() {
@@ -463,10 +470,10 @@ var require_codegen = __commonJS({
463
470
  render({ _n }) {
464
471
  return `${this.lhs} = ${this.rhs};` + _n;
465
472
  }
466
- optimizeNames(names, constants2) {
473
+ optimizeNames(names, constants4) {
467
474
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
468
475
  return;
469
- this.rhs = optimizeExpr(this.rhs, names, constants2);
476
+ this.rhs = optimizeExpr(this.rhs, names, constants4);
470
477
  return this;
471
478
  }
472
479
  get names() {
@@ -527,8 +534,8 @@ var require_codegen = __commonJS({
527
534
  optimizeNodes() {
528
535
  return `${this.code}` ? this : void 0;
529
536
  }
530
- optimizeNames(names, constants2) {
531
- this.code = optimizeExpr(this.code, names, constants2);
537
+ optimizeNames(names, constants4) {
538
+ this.code = optimizeExpr(this.code, names, constants4);
532
539
  return this;
533
540
  }
534
541
  get names() {
@@ -557,12 +564,12 @@ var require_codegen = __commonJS({
557
564
  }
558
565
  return nodes.length > 0 ? this : void 0;
559
566
  }
560
- optimizeNames(names, constants2) {
567
+ optimizeNames(names, constants4) {
561
568
  const { nodes } = this;
562
569
  let i = nodes.length;
563
570
  while (i--) {
564
571
  const n = nodes[i];
565
- if (n.optimizeNames(names, constants2))
572
+ if (n.optimizeNames(names, constants4))
566
573
  continue;
567
574
  subtractNames(names, n.names);
568
575
  nodes.splice(i, 1);
@@ -615,12 +622,12 @@ var require_codegen = __commonJS({
615
622
  return void 0;
616
623
  return this;
617
624
  }
618
- optimizeNames(names, constants2) {
625
+ optimizeNames(names, constants4) {
619
626
  var _a3;
620
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants2);
621
- if (!(super.optimizeNames(names, constants2) || this.else))
627
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
628
+ if (!(super.optimizeNames(names, constants4) || this.else))
622
629
  return;
623
- this.condition = optimizeExpr(this.condition, names, constants2);
630
+ this.condition = optimizeExpr(this.condition, names, constants4);
624
631
  return this;
625
632
  }
626
633
  get names() {
@@ -643,10 +650,10 @@ var require_codegen = __commonJS({
643
650
  render(opts) {
644
651
  return `for(${this.iteration})` + super.render(opts);
645
652
  }
646
- optimizeNames(names, constants2) {
647
- if (!super.optimizeNames(names, constants2))
653
+ optimizeNames(names, constants4) {
654
+ if (!super.optimizeNames(names, constants4))
648
655
  return;
649
- this.iteration = optimizeExpr(this.iteration, names, constants2);
656
+ this.iteration = optimizeExpr(this.iteration, names, constants4);
650
657
  return this;
651
658
  }
652
659
  get names() {
@@ -682,10 +689,10 @@ var require_codegen = __commonJS({
682
689
  render(opts) {
683
690
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
684
691
  }
685
- optimizeNames(names, constants2) {
686
- if (!super.optimizeNames(names, constants2))
692
+ optimizeNames(names, constants4) {
693
+ if (!super.optimizeNames(names, constants4))
687
694
  return;
688
- this.iterable = optimizeExpr(this.iterable, names, constants2);
695
+ this.iterable = optimizeExpr(this.iterable, names, constants4);
689
696
  return this;
690
697
  }
691
698
  get names() {
@@ -727,11 +734,11 @@ var require_codegen = __commonJS({
727
734
  (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
728
735
  return this;
729
736
  }
730
- optimizeNames(names, constants2) {
737
+ optimizeNames(names, constants4) {
731
738
  var _a3, _b;
732
- super.optimizeNames(names, constants2);
733
- (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants2);
734
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants2);
739
+ super.optimizeNames(names, constants4);
740
+ (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
741
+ (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants4);
735
742
  return this;
736
743
  }
737
744
  get names() {
@@ -1032,7 +1039,7 @@ var require_codegen = __commonJS({
1032
1039
  function addExprNames(names, from) {
1033
1040
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
1034
1041
  }
1035
- function optimizeExpr(expr, names, constants2) {
1042
+ function optimizeExpr(expr, names, constants4) {
1036
1043
  if (expr instanceof code_1.Name)
1037
1044
  return replaceName(expr);
1038
1045
  if (!canOptimize(expr))
@@ -1047,14 +1054,14 @@ var require_codegen = __commonJS({
1047
1054
  return items;
1048
1055
  }, []));
1049
1056
  function replaceName(n) {
1050
- const c = constants2[n.str];
1057
+ const c = constants4[n.str];
1051
1058
  if (c === void 0 || names[n.str] !== 1)
1052
1059
  return n;
1053
1060
  delete names[n.str];
1054
1061
  return c;
1055
1062
  }
1056
1063
  function canOptimize(e) {
1057
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== void 0);
1064
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants4[c.str] !== void 0);
1058
1065
  }
1059
1066
  }
1060
1067
  function subtractNames(names, from) {
@@ -6881,8 +6888,8 @@ import { dirname as dirname4, join as join8 } from "node:path";
6881
6888
 
6882
6889
  // src/claudeInstall.ts
6883
6890
  import { spawnSync } from "node:child_process";
6884
- import { copyFileSync, existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
6885
- import { dirname as dirname2, join as join3 } from "node:path";
6891
+ import { accessSync, constants, copyFileSync, existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, statSync, writeFileSync } from "node:fs";
6892
+ import { dirname as dirname2, isAbsolute, join as join3 } from "node:path";
6886
6893
  var EVENT_USER_PROMPT_SUBMIT = "UserPromptSubmit";
6887
6894
  var EVENT_POST_TOOL_USE = "PostToolUse";
6888
6895
  var EVENT_POST_TOOL_USE_FAILURE = "PostToolUseFailure";
@@ -6901,10 +6908,10 @@ function upsertHook(settings, event, command) {
6901
6908
  const list = settings.hooks[event] ??= [];
6902
6909
  const subcommand = command.includes("hook user-prompt-submit") ? "user-prompt-submit" : command.includes("hook post-tool-use") ? "post-tool-use" : command.includes("hook stop") ? "stop" : null;
6903
6910
  for (const entry of list) {
6904
- for (const hook of entry.hooks ?? []) {
6905
- if (isSameHookCommand(hook.command, command)) return "unchanged";
6906
- if (subcommand && isCaveatClaudeHookCommand(hook.command, subcommand)) {
6907
- hook.command = command;
6911
+ for (const hook2 of entry.hooks ?? []) {
6912
+ if (isSameHookCommand(hook2.command, command)) return "unchanged";
6913
+ if (subcommand && isCaveatClaudeHookCommand(hook2.command, subcommand)) {
6914
+ hook2.command = command;
6908
6915
  return "added";
6909
6916
  }
6910
6917
  }
@@ -6942,6 +6949,36 @@ function isCaveatClaudeHookCommand(actual, event) {
6942
6949
  const lower = actual.toLowerCase();
6943
6950
  return !isEnvPrefixedCommand(actual) && lower.includes("caveat") && actual.includes(`hook ${event}`);
6944
6951
  }
6952
+ function commandTokens(command) {
6953
+ const tokens = [];
6954
+ const pattern = /"([^"]*)"|([^\s"]+)/g;
6955
+ let end = 0;
6956
+ let match;
6957
+ while ((match = pattern.exec(command)) !== null) {
6958
+ if (command.slice(end, match.index).trim()) return null;
6959
+ tokens.push(match[1] ?? match[2]);
6960
+ end = pattern.lastIndex;
6961
+ }
6962
+ return command.slice(end).trim() ? null : tokens;
6963
+ }
6964
+ function isCanonicalAsset(path, expectedPath, mode) {
6965
+ if (typeof path !== "string" || !isAbsolute(path) || !isAbsolute(expectedPath)) return false;
6966
+ try {
6967
+ accessSync(path, mode);
6968
+ return statSync(path).isFile() && realpathSync(path) === realpathSync(expectedPath);
6969
+ } catch {
6970
+ return false;
6971
+ }
6972
+ }
6973
+ function isCanonicalCaveatClaudeHookCommand(actual, event, nodePath, cliScriptPath) {
6974
+ const tokens = commandTokens(actual);
6975
+ return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath, constants.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants.R_OK) && tokens[2] === "hook" && tokens[3] === event;
6976
+ }
6977
+ function isCaveatClaudeMcpRegistration(value, nodePath, cliScriptPath) {
6978
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
6979
+ const server = value;
6980
+ return Object.keys(server).length === 4 && ["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.keys(server.env).length === 0;
6981
+ }
6945
6982
  function readSettings(path) {
6946
6983
  if (!existsSync(path)) return {};
6947
6984
  return JSON.parse(readFileSync2(path, "utf-8"));
@@ -7073,8 +7110,8 @@ function uninstallClaudeIntegration(opts) {
7073
7110
  }
7074
7111
 
7075
7112
  // src/codexHookInstall.ts
7076
- import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
7077
- import { dirname as dirname3, join as join4 } from "node:path";
7113
+ import { accessSync as accessSync2, constants as constants2, copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, realpathSync as realpathSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
7114
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4 } from "node:path";
7078
7115
  import { parse as parseToml } from "smol-toml";
7079
7116
  function quote2(p) {
7080
7117
  return p.includes(" ") ? `"${p}"` : p;
@@ -7092,6 +7129,31 @@ function isCaveatCodexHookCommand(actual, event) {
7092
7129
  const lower = actual.toLowerCase();
7093
7130
  return lower.includes("caveat") && actual.includes(eventCommandFragment(event));
7094
7131
  }
7132
+ function commandTokens2(command) {
7133
+ const tokens = [];
7134
+ const pattern = /"([^"]*)"|([^\s"]+)/g;
7135
+ let end = 0;
7136
+ let match;
7137
+ while ((match = pattern.exec(command)) !== null) {
7138
+ if (command.slice(end, match.index).trim()) return null;
7139
+ tokens.push(match[1] ?? match[2]);
7140
+ end = pattern.lastIndex;
7141
+ }
7142
+ return command.slice(end).trim() ? null : tokens;
7143
+ }
7144
+ function isCanonicalAsset2(path, expectedPath, mode) {
7145
+ if (typeof path !== "string" || !isAbsolute2(path) || !isAbsolute2(expectedPath)) return false;
7146
+ try {
7147
+ accessSync2(path, mode);
7148
+ return statSync2(path).isFile() && realpathSync2(path) === realpathSync2(expectedPath);
7149
+ } catch {
7150
+ return false;
7151
+ }
7152
+ }
7153
+ function isCanonicalCaveatCodexHookCommand(actual, event, nodePath, cliScriptPath) {
7154
+ const tokens = commandTokens2(actual);
7155
+ return tokens?.length === 4 && isCanonicalAsset2(tokens[0], nodePath, constants2.X_OK) && isCanonicalAsset2(tokens[1], cliScriptPath, constants2.R_OK) && tokens[2] === "codex-hook" && tokens[3] === event;
7156
+ }
7095
7157
  function hasCaveatHook(hooksJson, event, fragment) {
7096
7158
  return hooksJson.hooks?.[event]?.some(
7097
7159
  (entry) => entry.hooks?.some((h) => h.command.includes(fragment))
@@ -7117,13 +7179,13 @@ function upsertHook2(hooksJson, event, command, subcommand) {
7117
7179
  hooksJson.hooks ??= {};
7118
7180
  const list = hooksJson.hooks[event] ??= [];
7119
7181
  for (const entry of list) {
7120
- for (const hook of entry.hooks ?? []) {
7121
- if (isSameHookCommand2(hook.command, command)) return "unchanged";
7122
- if (isCaveatCodexHookCommand(hook.command, subcommand)) {
7123
- hook.command = command;
7124
- hook.timeoutSec = 5;
7125
- hook.async = false;
7126
- hook.statusMessage = null;
7182
+ for (const hook2 of entry.hooks ?? []) {
7183
+ if (isSameHookCommand2(hook2.command, command)) return "unchanged";
7184
+ if (isCaveatCodexHookCommand(hook2.command, subcommand)) {
7185
+ hook2.command = command;
7186
+ hook2.timeoutSec = 5;
7187
+ hook2.async = false;
7188
+ hook2.statusMessage = null;
7127
7189
  return "added";
7128
7190
  }
7129
7191
  }
@@ -7502,9 +7564,9 @@ function askOnce(question) {
7502
7564
  }
7503
7565
 
7504
7566
  // src/nodePath.ts
7505
- import { existsSync as existsSync3, realpathSync } from "node:fs";
7567
+ import { existsSync as existsSync3, realpathSync as realpathSync3 } from "node:fs";
7506
7568
  import { delimiter, join as join5 } from "node:path";
7507
- var defaultRealpath = (path) => realpathSync.native(path);
7569
+ var defaultRealpath = (path) => realpathSync3.native(path);
7508
7570
  function safeRealpath(path, realpath = defaultRealpath) {
7509
7571
  try {
7510
7572
  return realpath(path);
@@ -7544,6 +7606,16 @@ import { spawnSync as spawnSync3 } from "node:child_process";
7544
7606
  import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
7545
7607
  import { tmpdir } from "node:os";
7546
7608
  import { join as join6 } from "node:path";
7609
+ var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
7610
+ var MAX_HOOK_SIDECAR_TIMEOUT_MS = 24e4;
7611
+ function resolveHookSidecarTimeoutMs(raw) {
7612
+ if (raw === void 0) return DEFAULT_HOOK_SIDECAR_TIMEOUT_MS;
7613
+ const value = Number(raw);
7614
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_HOOK_SIDECAR_TIMEOUT_MS) {
7615
+ throw new Error(`CAVEAT_HOOK_CODEX_SIDECAR_TIMEOUT_MS must be an integer from 1 to ${MAX_HOOK_SIDECAR_TIMEOUT_MS}`);
7616
+ }
7617
+ return value;
7618
+ }
7547
7619
  function compactFailureMessage(message) {
7548
7620
  const singleLine = message.replace(/\s+/g, " ").trim();
7549
7621
  if (!singleLine) return "unknown error";
@@ -7607,7 +7679,9 @@ function runCodexSidecarAdvisory(input) {
7607
7679
  const result = spawnSync3(process.execPath, args, {
7608
7680
  cwd: input.projectRoot,
7609
7681
  encoding: "utf-8",
7610
- timeout: Number(process.env.CAVEAT_HOOK_CODEX_SIDECAR_TIMEOUT_MS ?? 12e4),
7682
+ // Keep at least one minute between the longest supported model call and
7683
+ // the pending single-flight claim TTL (five minutes).
7684
+ timeout: resolveHookSidecarTimeoutMs(process.env.CAVEAT_HOOK_CODEX_SIDECAR_TIMEOUT_MS),
7611
7685
  maxBuffer: 10 * 1024 * 1024
7612
7686
  });
7613
7687
  if (result.error) {
@@ -8036,7 +8110,13 @@ async function runIndex(ctx, opts) {
8036
8110
  for (const failure of failures) {
8037
8111
  ctx.logger.warn(`${failure.source}: sealed key prewarm failed: ${errorMessage2(failure.error)}`);
8038
8112
  }
8039
- const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
8113
+ let db;
8114
+ try {
8115
+ db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
8116
+ } catch (error51) {
8117
+ observeRuntimeError("CAVEAT.DATABASE_OPEN_FAILED", { version: CAVEAT_VERSION });
8118
+ throw error51;
8119
+ }
8040
8120
  try {
8041
8121
  if (opts.full) {
8042
8122
  ctx.logger.info("full rebuild: DELETE FROM entries");
@@ -8051,6 +8131,9 @@ async function runIndex(ctx, opts) {
8051
8131
  }
8052
8132
  }
8053
8133
  writeDigestMarker(ctx.caveatHome, computeEntriesDigest(ctx.paths));
8134
+ } catch (error51) {
8135
+ observeRuntimeError("CAVEAT.INDEX_FAILED", { version: CAVEAT_VERSION });
8136
+ throw error51;
8054
8137
  } finally {
8055
8138
  db.close();
8056
8139
  }
@@ -8205,7 +8288,7 @@ function runStats(ctx) {
8205
8288
 
8206
8289
  // src/commands/serve.ts
8207
8290
  async function runServe(opts) {
8208
- const { startServer } = await import("./server-EASKBCNK.js");
8291
+ const { startServer } = await import("./server-ZMIRSFMH.js");
8209
8292
  const { port, host } = startServer({ port: opts.port });
8210
8293
  process.stdout.write(`[caveat] web portal: http://${host}:${port}/
8211
8294
  `);
@@ -8626,18 +8709,18 @@ var ParseStatus = class _ParseStatus {
8626
8709
  if (this.value !== "aborted")
8627
8710
  this.value = "aborted";
8628
8711
  }
8629
- static mergeArray(status, results) {
8712
+ static mergeArray(status2, results) {
8630
8713
  const arrayValue = [];
8631
8714
  for (const s of results) {
8632
8715
  if (s.status === "aborted")
8633
8716
  return INVALID;
8634
8717
  if (s.status === "dirty")
8635
- status.dirty();
8718
+ status2.dirty();
8636
8719
  arrayValue.push(s.value);
8637
8720
  }
8638
- return { status: status.value, value: arrayValue };
8721
+ return { status: status2.value, value: arrayValue };
8639
8722
  }
8640
- static async mergeObjectAsync(status, pairs) {
8723
+ static async mergeObjectAsync(status2, pairs) {
8641
8724
  const syncPairs = [];
8642
8725
  for (const pair of pairs) {
8643
8726
  const key = await pair.key;
@@ -8647,9 +8730,9 @@ var ParseStatus = class _ParseStatus {
8647
8730
  value
8648
8731
  });
8649
8732
  }
8650
- return _ParseStatus.mergeObjectSync(status, syncPairs);
8733
+ return _ParseStatus.mergeObjectSync(status2, syncPairs);
8651
8734
  }
8652
- static mergeObjectSync(status, pairs) {
8735
+ static mergeObjectSync(status2, pairs) {
8653
8736
  const finalObject = {};
8654
8737
  for (const pair of pairs) {
8655
8738
  const { key, value } = pair;
@@ -8658,14 +8741,14 @@ var ParseStatus = class _ParseStatus {
8658
8741
  if (value.status === "aborted")
8659
8742
  return INVALID;
8660
8743
  if (key.status === "dirty")
8661
- status.dirty();
8744
+ status2.dirty();
8662
8745
  if (value.status === "dirty")
8663
- status.dirty();
8746
+ status2.dirty();
8664
8747
  if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
8665
8748
  finalObject[key.value] = value.value;
8666
8749
  }
8667
8750
  }
8668
- return { status: status.value, value: finalObject };
8751
+ return { status: status2.value, value: finalObject };
8669
8752
  }
8670
8753
  };
8671
8754
  var INVALID = Object.freeze({
@@ -9125,7 +9208,7 @@ var ZodString = class _ZodString2 extends ZodType {
9125
9208
  });
9126
9209
  return INVALID;
9127
9210
  }
9128
- const status = new ParseStatus();
9211
+ const status2 = new ParseStatus();
9129
9212
  let ctx = void 0;
9130
9213
  for (const check2 of this._def.checks) {
9131
9214
  if (check2.kind === "min") {
@@ -9139,7 +9222,7 @@ var ZodString = class _ZodString2 extends ZodType {
9139
9222
  exact: false,
9140
9223
  message: check2.message
9141
9224
  });
9142
- status.dirty();
9225
+ status2.dirty();
9143
9226
  }
9144
9227
  } else if (check2.kind === "max") {
9145
9228
  if (input.data.length > check2.value) {
@@ -9152,7 +9235,7 @@ var ZodString = class _ZodString2 extends ZodType {
9152
9235
  exact: false,
9153
9236
  message: check2.message
9154
9237
  });
9155
- status.dirty();
9238
+ status2.dirty();
9156
9239
  }
9157
9240
  } else if (check2.kind === "length") {
9158
9241
  const tooBig = input.data.length > check2.value;
@@ -9178,7 +9261,7 @@ var ZodString = class _ZodString2 extends ZodType {
9178
9261
  message: check2.message
9179
9262
  });
9180
9263
  }
9181
- status.dirty();
9264
+ status2.dirty();
9182
9265
  }
9183
9266
  } else if (check2.kind === "email") {
9184
9267
  if (!emailRegex.test(input.data)) {
@@ -9188,7 +9271,7 @@ var ZodString = class _ZodString2 extends ZodType {
9188
9271
  code: ZodIssueCode.invalid_string,
9189
9272
  message: check2.message
9190
9273
  });
9191
- status.dirty();
9274
+ status2.dirty();
9192
9275
  }
9193
9276
  } else if (check2.kind === "emoji") {
9194
9277
  if (!emojiRegex) {
@@ -9201,7 +9284,7 @@ var ZodString = class _ZodString2 extends ZodType {
9201
9284
  code: ZodIssueCode.invalid_string,
9202
9285
  message: check2.message
9203
9286
  });
9204
- status.dirty();
9287
+ status2.dirty();
9205
9288
  }
9206
9289
  } else if (check2.kind === "uuid") {
9207
9290
  if (!uuidRegex.test(input.data)) {
@@ -9211,7 +9294,7 @@ var ZodString = class _ZodString2 extends ZodType {
9211
9294
  code: ZodIssueCode.invalid_string,
9212
9295
  message: check2.message
9213
9296
  });
9214
- status.dirty();
9297
+ status2.dirty();
9215
9298
  }
9216
9299
  } else if (check2.kind === "nanoid") {
9217
9300
  if (!nanoidRegex.test(input.data)) {
@@ -9221,7 +9304,7 @@ var ZodString = class _ZodString2 extends ZodType {
9221
9304
  code: ZodIssueCode.invalid_string,
9222
9305
  message: check2.message
9223
9306
  });
9224
- status.dirty();
9307
+ status2.dirty();
9225
9308
  }
9226
9309
  } else if (check2.kind === "cuid") {
9227
9310
  if (!cuidRegex.test(input.data)) {
@@ -9231,7 +9314,7 @@ var ZodString = class _ZodString2 extends ZodType {
9231
9314
  code: ZodIssueCode.invalid_string,
9232
9315
  message: check2.message
9233
9316
  });
9234
- status.dirty();
9317
+ status2.dirty();
9235
9318
  }
9236
9319
  } else if (check2.kind === "cuid2") {
9237
9320
  if (!cuid2Regex.test(input.data)) {
@@ -9241,7 +9324,7 @@ var ZodString = class _ZodString2 extends ZodType {
9241
9324
  code: ZodIssueCode.invalid_string,
9242
9325
  message: check2.message
9243
9326
  });
9244
- status.dirty();
9327
+ status2.dirty();
9245
9328
  }
9246
9329
  } else if (check2.kind === "ulid") {
9247
9330
  if (!ulidRegex.test(input.data)) {
@@ -9251,7 +9334,7 @@ var ZodString = class _ZodString2 extends ZodType {
9251
9334
  code: ZodIssueCode.invalid_string,
9252
9335
  message: check2.message
9253
9336
  });
9254
- status.dirty();
9337
+ status2.dirty();
9255
9338
  }
9256
9339
  } else if (check2.kind === "url") {
9257
9340
  try {
@@ -9263,7 +9346,7 @@ var ZodString = class _ZodString2 extends ZodType {
9263
9346
  code: ZodIssueCode.invalid_string,
9264
9347
  message: check2.message
9265
9348
  });
9266
- status.dirty();
9349
+ status2.dirty();
9267
9350
  }
9268
9351
  } else if (check2.kind === "regex") {
9269
9352
  check2.regex.lastIndex = 0;
@@ -9275,7 +9358,7 @@ var ZodString = class _ZodString2 extends ZodType {
9275
9358
  code: ZodIssueCode.invalid_string,
9276
9359
  message: check2.message
9277
9360
  });
9278
- status.dirty();
9361
+ status2.dirty();
9279
9362
  }
9280
9363
  } else if (check2.kind === "trim") {
9281
9364
  input.data = input.data.trim();
@@ -9287,7 +9370,7 @@ var ZodString = class _ZodString2 extends ZodType {
9287
9370
  validation: { includes: check2.value, position: check2.position },
9288
9371
  message: check2.message
9289
9372
  });
9290
- status.dirty();
9373
+ status2.dirty();
9291
9374
  }
9292
9375
  } else if (check2.kind === "toLowerCase") {
9293
9376
  input.data = input.data.toLowerCase();
@@ -9301,7 +9384,7 @@ var ZodString = class _ZodString2 extends ZodType {
9301
9384
  validation: { startsWith: check2.value },
9302
9385
  message: check2.message
9303
9386
  });
9304
- status.dirty();
9387
+ status2.dirty();
9305
9388
  }
9306
9389
  } else if (check2.kind === "endsWith") {
9307
9390
  if (!input.data.endsWith(check2.value)) {
@@ -9311,7 +9394,7 @@ var ZodString = class _ZodString2 extends ZodType {
9311
9394
  validation: { endsWith: check2.value },
9312
9395
  message: check2.message
9313
9396
  });
9314
- status.dirty();
9397
+ status2.dirty();
9315
9398
  }
9316
9399
  } else if (check2.kind === "datetime") {
9317
9400
  const regex = datetimeRegex(check2);
@@ -9322,7 +9405,7 @@ var ZodString = class _ZodString2 extends ZodType {
9322
9405
  validation: "datetime",
9323
9406
  message: check2.message
9324
9407
  });
9325
- status.dirty();
9408
+ status2.dirty();
9326
9409
  }
9327
9410
  } else if (check2.kind === "date") {
9328
9411
  const regex = dateRegex;
@@ -9333,7 +9416,7 @@ var ZodString = class _ZodString2 extends ZodType {
9333
9416
  validation: "date",
9334
9417
  message: check2.message
9335
9418
  });
9336
- status.dirty();
9419
+ status2.dirty();
9337
9420
  }
9338
9421
  } else if (check2.kind === "time") {
9339
9422
  const regex = timeRegex(check2);
@@ -9344,7 +9427,7 @@ var ZodString = class _ZodString2 extends ZodType {
9344
9427
  validation: "time",
9345
9428
  message: check2.message
9346
9429
  });
9347
- status.dirty();
9430
+ status2.dirty();
9348
9431
  }
9349
9432
  } else if (check2.kind === "duration") {
9350
9433
  if (!durationRegex.test(input.data)) {
@@ -9354,7 +9437,7 @@ var ZodString = class _ZodString2 extends ZodType {
9354
9437
  code: ZodIssueCode.invalid_string,
9355
9438
  message: check2.message
9356
9439
  });
9357
- status.dirty();
9440
+ status2.dirty();
9358
9441
  }
9359
9442
  } else if (check2.kind === "ip") {
9360
9443
  if (!isValidIP(input.data, check2.version)) {
@@ -9364,7 +9447,7 @@ var ZodString = class _ZodString2 extends ZodType {
9364
9447
  code: ZodIssueCode.invalid_string,
9365
9448
  message: check2.message
9366
9449
  });
9367
- status.dirty();
9450
+ status2.dirty();
9368
9451
  }
9369
9452
  } else if (check2.kind === "jwt") {
9370
9453
  if (!isValidJWT(input.data, check2.alg)) {
@@ -9374,7 +9457,7 @@ var ZodString = class _ZodString2 extends ZodType {
9374
9457
  code: ZodIssueCode.invalid_string,
9375
9458
  message: check2.message
9376
9459
  });
9377
- status.dirty();
9460
+ status2.dirty();
9378
9461
  }
9379
9462
  } else if (check2.kind === "cidr") {
9380
9463
  if (!isValidCidr(input.data, check2.version)) {
@@ -9384,7 +9467,7 @@ var ZodString = class _ZodString2 extends ZodType {
9384
9467
  code: ZodIssueCode.invalid_string,
9385
9468
  message: check2.message
9386
9469
  });
9387
- status.dirty();
9470
+ status2.dirty();
9388
9471
  }
9389
9472
  } else if (check2.kind === "base64") {
9390
9473
  if (!base64Regex.test(input.data)) {
@@ -9394,7 +9477,7 @@ var ZodString = class _ZodString2 extends ZodType {
9394
9477
  code: ZodIssueCode.invalid_string,
9395
9478
  message: check2.message
9396
9479
  });
9397
- status.dirty();
9480
+ status2.dirty();
9398
9481
  }
9399
9482
  } else if (check2.kind === "base64url") {
9400
9483
  if (!base64urlRegex.test(input.data)) {
@@ -9404,13 +9487,13 @@ var ZodString = class _ZodString2 extends ZodType {
9404
9487
  code: ZodIssueCode.invalid_string,
9405
9488
  message: check2.message
9406
9489
  });
9407
- status.dirty();
9490
+ status2.dirty();
9408
9491
  }
9409
9492
  } else {
9410
9493
  util.assertNever(check2);
9411
9494
  }
9412
9495
  }
9413
- return { status: status.value, value: input.data };
9496
+ return { status: status2.value, value: input.data };
9414
9497
  }
9415
9498
  _regex(regex, validation, message) {
9416
9499
  return this.refinement((data) => regex.test(data), {
@@ -9686,7 +9769,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
9686
9769
  return INVALID;
9687
9770
  }
9688
9771
  let ctx = void 0;
9689
- const status = new ParseStatus();
9772
+ const status2 = new ParseStatus();
9690
9773
  for (const check2 of this._def.checks) {
9691
9774
  if (check2.kind === "int") {
9692
9775
  if (!util.isInteger(input.data)) {
@@ -9697,7 +9780,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
9697
9780
  received: "float",
9698
9781
  message: check2.message
9699
9782
  });
9700
- status.dirty();
9783
+ status2.dirty();
9701
9784
  }
9702
9785
  } else if (check2.kind === "min") {
9703
9786
  const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
@@ -9711,7 +9794,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
9711
9794
  exact: false,
9712
9795
  message: check2.message
9713
9796
  });
9714
- status.dirty();
9797
+ status2.dirty();
9715
9798
  }
9716
9799
  } else if (check2.kind === "max") {
9717
9800
  const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
@@ -9725,7 +9808,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
9725
9808
  exact: false,
9726
9809
  message: check2.message
9727
9810
  });
9728
- status.dirty();
9811
+ status2.dirty();
9729
9812
  }
9730
9813
  } else if (check2.kind === "multipleOf") {
9731
9814
  if (floatSafeRemainder(input.data, check2.value) !== 0) {
@@ -9735,7 +9818,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
9735
9818
  multipleOf: check2.value,
9736
9819
  message: check2.message
9737
9820
  });
9738
- status.dirty();
9821
+ status2.dirty();
9739
9822
  }
9740
9823
  } else if (check2.kind === "finite") {
9741
9824
  if (!Number.isFinite(input.data)) {
@@ -9744,13 +9827,13 @@ var ZodNumber = class _ZodNumber extends ZodType {
9744
9827
  code: ZodIssueCode.not_finite,
9745
9828
  message: check2.message
9746
9829
  });
9747
- status.dirty();
9830
+ status2.dirty();
9748
9831
  }
9749
9832
  } else {
9750
9833
  util.assertNever(check2);
9751
9834
  }
9752
9835
  }
9753
- return { status: status.value, value: input.data };
9836
+ return { status: status2.value, value: input.data };
9754
9837
  }
9755
9838
  gte(value, message) {
9756
9839
  return this.setLimit("min", value, true, errorUtil.toString(message));
@@ -9915,7 +9998,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
9915
9998
  return this._getInvalidInput(input);
9916
9999
  }
9917
10000
  let ctx = void 0;
9918
- const status = new ParseStatus();
10001
+ const status2 = new ParseStatus();
9919
10002
  for (const check2 of this._def.checks) {
9920
10003
  if (check2.kind === "min") {
9921
10004
  const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
@@ -9928,7 +10011,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
9928
10011
  inclusive: check2.inclusive,
9929
10012
  message: check2.message
9930
10013
  });
9931
- status.dirty();
10014
+ status2.dirty();
9932
10015
  }
9933
10016
  } else if (check2.kind === "max") {
9934
10017
  const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
@@ -9941,7 +10024,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
9941
10024
  inclusive: check2.inclusive,
9942
10025
  message: check2.message
9943
10026
  });
9944
- status.dirty();
10027
+ status2.dirty();
9945
10028
  }
9946
10029
  } else if (check2.kind === "multipleOf") {
9947
10030
  if (input.data % check2.value !== BigInt(0)) {
@@ -9951,13 +10034,13 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
9951
10034
  multipleOf: check2.value,
9952
10035
  message: check2.message
9953
10036
  });
9954
- status.dirty();
10037
+ status2.dirty();
9955
10038
  }
9956
10039
  } else {
9957
10040
  util.assertNever(check2);
9958
10041
  }
9959
10042
  }
9960
- return { status: status.value, value: input.data };
10043
+ return { status: status2.value, value: input.data };
9961
10044
  }
9962
10045
  _getInvalidInput(input) {
9963
10046
  const ctx = this._getOrReturnCtx(input);
@@ -10115,7 +10198,7 @@ var ZodDate = class _ZodDate extends ZodType {
10115
10198
  });
10116
10199
  return INVALID;
10117
10200
  }
10118
- const status = new ParseStatus();
10201
+ const status2 = new ParseStatus();
10119
10202
  let ctx = void 0;
10120
10203
  for (const check2 of this._def.checks) {
10121
10204
  if (check2.kind === "min") {
@@ -10129,7 +10212,7 @@ var ZodDate = class _ZodDate extends ZodType {
10129
10212
  minimum: check2.value,
10130
10213
  type: "date"
10131
10214
  });
10132
- status.dirty();
10215
+ status2.dirty();
10133
10216
  }
10134
10217
  } else if (check2.kind === "max") {
10135
10218
  if (input.data.getTime() > check2.value) {
@@ -10142,14 +10225,14 @@ var ZodDate = class _ZodDate extends ZodType {
10142
10225
  maximum: check2.value,
10143
10226
  type: "date"
10144
10227
  });
10145
- status.dirty();
10228
+ status2.dirty();
10146
10229
  }
10147
10230
  } else {
10148
10231
  util.assertNever(check2);
10149
10232
  }
10150
10233
  }
10151
10234
  return {
10152
- status: status.value,
10235
+ status: status2.value,
10153
10236
  value: new Date(input.data.getTime())
10154
10237
  };
10155
10238
  }
@@ -10335,7 +10418,7 @@ ZodVoid.create = (params) => {
10335
10418
  };
10336
10419
  var ZodArray = class _ZodArray extends ZodType {
10337
10420
  _parse(input) {
10338
- const { ctx, status } = this._processInputParams(input);
10421
+ const { ctx, status: status2 } = this._processInputParams(input);
10339
10422
  const def = this._def;
10340
10423
  if (ctx.parsedType !== ZodParsedType.array) {
10341
10424
  addIssueToContext(ctx, {
@@ -10358,7 +10441,7 @@ var ZodArray = class _ZodArray extends ZodType {
10358
10441
  exact: true,
10359
10442
  message: def.exactLength.message
10360
10443
  });
10361
- status.dirty();
10444
+ status2.dirty();
10362
10445
  }
10363
10446
  }
10364
10447
  if (def.minLength !== null) {
@@ -10371,7 +10454,7 @@ var ZodArray = class _ZodArray extends ZodType {
10371
10454
  exact: false,
10372
10455
  message: def.minLength.message
10373
10456
  });
10374
- status.dirty();
10457
+ status2.dirty();
10375
10458
  }
10376
10459
  }
10377
10460
  if (def.maxLength !== null) {
@@ -10384,20 +10467,20 @@ var ZodArray = class _ZodArray extends ZodType {
10384
10467
  exact: false,
10385
10468
  message: def.maxLength.message
10386
10469
  });
10387
- status.dirty();
10470
+ status2.dirty();
10388
10471
  }
10389
10472
  }
10390
10473
  if (ctx.common.async) {
10391
10474
  return Promise.all([...ctx.data].map((item, i) => {
10392
10475
  return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i));
10393
10476
  })).then((result2) => {
10394
- return ParseStatus.mergeArray(status, result2);
10477
+ return ParseStatus.mergeArray(status2, result2);
10395
10478
  });
10396
10479
  }
10397
10480
  const result = [...ctx.data].map((item, i) => {
10398
10481
  return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i));
10399
10482
  });
10400
- return ParseStatus.mergeArray(status, result);
10483
+ return ParseStatus.mergeArray(status2, result);
10401
10484
  }
10402
10485
  get element() {
10403
10486
  return this._def.type;
@@ -10486,7 +10569,7 @@ var ZodObject = class _ZodObject extends ZodType {
10486
10569
  });
10487
10570
  return INVALID;
10488
10571
  }
10489
- const { status, ctx } = this._processInputParams(input);
10572
+ const { status: status2, ctx } = this._processInputParams(input);
10490
10573
  const { shape, keys: shapeKeys } = this._getCached();
10491
10574
  const extraKeys = [];
10492
10575
  if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) {
@@ -10521,7 +10604,7 @@ var ZodObject = class _ZodObject extends ZodType {
10521
10604
  code: ZodIssueCode.unrecognized_keys,
10522
10605
  keys: extraKeys
10523
10606
  });
10524
- status.dirty();
10607
+ status2.dirty();
10525
10608
  }
10526
10609
  } else if (unknownKeys === "strip") {
10527
10610
  } else {
@@ -10555,10 +10638,10 @@ var ZodObject = class _ZodObject extends ZodType {
10555
10638
  }
10556
10639
  return syncPairs;
10557
10640
  }).then((syncPairs) => {
10558
- return ParseStatus.mergeObjectSync(status, syncPairs);
10641
+ return ParseStatus.mergeObjectSync(status2, syncPairs);
10559
10642
  });
10560
10643
  } else {
10561
- return ParseStatus.mergeObjectSync(status, pairs);
10644
+ return ParseStatus.mergeObjectSync(status2, pairs);
10562
10645
  }
10563
10646
  }
10564
10647
  get shape() {
@@ -11036,7 +11119,7 @@ function mergeValues(a, b) {
11036
11119
  }
11037
11120
  var ZodIntersection = class extends ZodType {
11038
11121
  _parse(input) {
11039
- const { status, ctx } = this._processInputParams(input);
11122
+ const { status: status2, ctx } = this._processInputParams(input);
11040
11123
  const handleParsed = (parsedLeft, parsedRight) => {
11041
11124
  if (isAborted(parsedLeft) || isAborted(parsedRight)) {
11042
11125
  return INVALID;
@@ -11049,9 +11132,9 @@ var ZodIntersection = class extends ZodType {
11049
11132
  return INVALID;
11050
11133
  }
11051
11134
  if (isDirty(parsedLeft) || isDirty(parsedRight)) {
11052
- status.dirty();
11135
+ status2.dirty();
11053
11136
  }
11054
- return { status: status.value, value: merged.data };
11137
+ return { status: status2.value, value: merged.data };
11055
11138
  };
11056
11139
  if (ctx.common.async) {
11057
11140
  return Promise.all([
@@ -11089,7 +11172,7 @@ ZodIntersection.create = (left, right, params) => {
11089
11172
  };
11090
11173
  var ZodTuple = class _ZodTuple extends ZodType {
11091
11174
  _parse(input) {
11092
- const { status, ctx } = this._processInputParams(input);
11175
+ const { status: status2, ctx } = this._processInputParams(input);
11093
11176
  if (ctx.parsedType !== ZodParsedType.array) {
11094
11177
  addIssueToContext(ctx, {
11095
11178
  code: ZodIssueCode.invalid_type,
@@ -11117,7 +11200,7 @@ var ZodTuple = class _ZodTuple extends ZodType {
11117
11200
  exact: false,
11118
11201
  type: "array"
11119
11202
  });
11120
- status.dirty();
11203
+ status2.dirty();
11121
11204
  }
11122
11205
  const items = [...ctx.data].map((item, itemIndex) => {
11123
11206
  const schema = this._def.items[itemIndex] || this._def.rest;
@@ -11127,10 +11210,10 @@ var ZodTuple = class _ZodTuple extends ZodType {
11127
11210
  }).filter((x) => !!x);
11128
11211
  if (ctx.common.async) {
11129
11212
  return Promise.all(items).then((results) => {
11130
- return ParseStatus.mergeArray(status, results);
11213
+ return ParseStatus.mergeArray(status2, results);
11131
11214
  });
11132
11215
  } else {
11133
- return ParseStatus.mergeArray(status, items);
11216
+ return ParseStatus.mergeArray(status2, items);
11134
11217
  }
11135
11218
  }
11136
11219
  get items() {
@@ -11162,7 +11245,7 @@ var ZodRecord = class _ZodRecord extends ZodType {
11162
11245
  return this._def.valueType;
11163
11246
  }
11164
11247
  _parse(input) {
11165
- const { status, ctx } = this._processInputParams(input);
11248
+ const { status: status2, ctx } = this._processInputParams(input);
11166
11249
  if (ctx.parsedType !== ZodParsedType.object) {
11167
11250
  addIssueToContext(ctx, {
11168
11251
  code: ZodIssueCode.invalid_type,
@@ -11182,9 +11265,9 @@ var ZodRecord = class _ZodRecord extends ZodType {
11182
11265
  });
11183
11266
  }
11184
11267
  if (ctx.common.async) {
11185
- return ParseStatus.mergeObjectAsync(status, pairs);
11268
+ return ParseStatus.mergeObjectAsync(status2, pairs);
11186
11269
  } else {
11187
- return ParseStatus.mergeObjectSync(status, pairs);
11270
+ return ParseStatus.mergeObjectSync(status2, pairs);
11188
11271
  }
11189
11272
  }
11190
11273
  get element() {
@@ -11215,7 +11298,7 @@ var ZodMap = class extends ZodType {
11215
11298
  return this._def.valueType;
11216
11299
  }
11217
11300
  _parse(input) {
11218
- const { status, ctx } = this._processInputParams(input);
11301
+ const { status: status2, ctx } = this._processInputParams(input);
11219
11302
  if (ctx.parsedType !== ZodParsedType.map) {
11220
11303
  addIssueToContext(ctx, {
11221
11304
  code: ZodIssueCode.invalid_type,
@@ -11242,11 +11325,11 @@ var ZodMap = class extends ZodType {
11242
11325
  return INVALID;
11243
11326
  }
11244
11327
  if (key.status === "dirty" || value.status === "dirty") {
11245
- status.dirty();
11328
+ status2.dirty();
11246
11329
  }
11247
11330
  finalMap.set(key.value, value.value);
11248
11331
  }
11249
- return { status: status.value, value: finalMap };
11332
+ return { status: status2.value, value: finalMap };
11250
11333
  });
11251
11334
  } else {
11252
11335
  const finalMap = /* @__PURE__ */ new Map();
@@ -11257,11 +11340,11 @@ var ZodMap = class extends ZodType {
11257
11340
  return INVALID;
11258
11341
  }
11259
11342
  if (key.status === "dirty" || value.status === "dirty") {
11260
- status.dirty();
11343
+ status2.dirty();
11261
11344
  }
11262
11345
  finalMap.set(key.value, value.value);
11263
11346
  }
11264
- return { status: status.value, value: finalMap };
11347
+ return { status: status2.value, value: finalMap };
11265
11348
  }
11266
11349
  }
11267
11350
  };
@@ -11275,7 +11358,7 @@ ZodMap.create = (keyType, valueType, params) => {
11275
11358
  };
11276
11359
  var ZodSet = class _ZodSet extends ZodType {
11277
11360
  _parse(input) {
11278
- const { status, ctx } = this._processInputParams(input);
11361
+ const { status: status2, ctx } = this._processInputParams(input);
11279
11362
  if (ctx.parsedType !== ZodParsedType.set) {
11280
11363
  addIssueToContext(ctx, {
11281
11364
  code: ZodIssueCode.invalid_type,
@@ -11295,7 +11378,7 @@ var ZodSet = class _ZodSet extends ZodType {
11295
11378
  exact: false,
11296
11379
  message: def.minSize.message
11297
11380
  });
11298
- status.dirty();
11381
+ status2.dirty();
11299
11382
  }
11300
11383
  }
11301
11384
  if (def.maxSize !== null) {
@@ -11308,7 +11391,7 @@ var ZodSet = class _ZodSet extends ZodType {
11308
11391
  exact: false,
11309
11392
  message: def.maxSize.message
11310
11393
  });
11311
- status.dirty();
11394
+ status2.dirty();
11312
11395
  }
11313
11396
  }
11314
11397
  const valueType = this._def.valueType;
@@ -11318,10 +11401,10 @@ var ZodSet = class _ZodSet extends ZodType {
11318
11401
  if (element.status === "aborted")
11319
11402
  return INVALID;
11320
11403
  if (element.status === "dirty")
11321
- status.dirty();
11404
+ status2.dirty();
11322
11405
  parsedSet.add(element.value);
11323
11406
  }
11324
- return { status: status.value, value: parsedSet };
11407
+ return { status: status2.value, value: parsedSet };
11325
11408
  }
11326
11409
  const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i)));
11327
11410
  if (ctx.common.async) {
@@ -11652,15 +11735,15 @@ var ZodEffects = class extends ZodType {
11652
11735
  return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects ? this._def.schema.sourceType() : this._def.schema;
11653
11736
  }
11654
11737
  _parse(input) {
11655
- const { status, ctx } = this._processInputParams(input);
11738
+ const { status: status2, ctx } = this._processInputParams(input);
11656
11739
  const effect = this._def.effect || null;
11657
11740
  const checkCtx = {
11658
11741
  addIssue: (arg) => {
11659
11742
  addIssueToContext(ctx, arg);
11660
11743
  if (arg.fatal) {
11661
- status.abort();
11744
+ status2.abort();
11662
11745
  } else {
11663
- status.dirty();
11746
+ status2.dirty();
11664
11747
  }
11665
11748
  },
11666
11749
  get path() {
@@ -11672,7 +11755,7 @@ var ZodEffects = class extends ZodType {
11672
11755
  const processed = effect.transform(ctx.data, checkCtx);
11673
11756
  if (ctx.common.async) {
11674
11757
  return Promise.resolve(processed).then(async (processed2) => {
11675
- if (status.value === "aborted")
11758
+ if (status2.value === "aborted")
11676
11759
  return INVALID;
11677
11760
  const result = await this._def.schema._parseAsync({
11678
11761
  data: processed2,
@@ -11683,12 +11766,12 @@ var ZodEffects = class extends ZodType {
11683
11766
  return INVALID;
11684
11767
  if (result.status === "dirty")
11685
11768
  return DIRTY(result.value);
11686
- if (status.value === "dirty")
11769
+ if (status2.value === "dirty")
11687
11770
  return DIRTY(result.value);
11688
11771
  return result;
11689
11772
  });
11690
11773
  } else {
11691
- if (status.value === "aborted")
11774
+ if (status2.value === "aborted")
11692
11775
  return INVALID;
11693
11776
  const result = this._def.schema._parseSync({
11694
11777
  data: processed,
@@ -11699,7 +11782,7 @@ var ZodEffects = class extends ZodType {
11699
11782
  return INVALID;
11700
11783
  if (result.status === "dirty")
11701
11784
  return DIRTY(result.value);
11702
- if (status.value === "dirty")
11785
+ if (status2.value === "dirty")
11703
11786
  return DIRTY(result.value);
11704
11787
  return result;
11705
11788
  }
@@ -11724,17 +11807,17 @@ var ZodEffects = class extends ZodType {
11724
11807
  if (inner.status === "aborted")
11725
11808
  return INVALID;
11726
11809
  if (inner.status === "dirty")
11727
- status.dirty();
11810
+ status2.dirty();
11728
11811
  executeRefinement(inner.value);
11729
- return { status: status.value, value: inner.value };
11812
+ return { status: status2.value, value: inner.value };
11730
11813
  } else {
11731
11814
  return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
11732
11815
  if (inner.status === "aborted")
11733
11816
  return INVALID;
11734
11817
  if (inner.status === "dirty")
11735
- status.dirty();
11818
+ status2.dirty();
11736
11819
  return executeRefinement(inner.value).then(() => {
11737
- return { status: status.value, value: inner.value };
11820
+ return { status: status2.value, value: inner.value };
11738
11821
  });
11739
11822
  });
11740
11823
  }
@@ -11752,13 +11835,13 @@ var ZodEffects = class extends ZodType {
11752
11835
  if (result instanceof Promise) {
11753
11836
  throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
11754
11837
  }
11755
- return { status: status.value, value: result };
11838
+ return { status: status2.value, value: result };
11756
11839
  } else {
11757
11840
  return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
11758
11841
  if (!isValid(base))
11759
11842
  return INVALID;
11760
11843
  return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
11761
- status: status.value,
11844
+ status: status2.value,
11762
11845
  value: result
11763
11846
  }));
11764
11847
  });
@@ -11936,7 +12019,7 @@ var ZodBranded = class extends ZodType {
11936
12019
  };
11937
12020
  var ZodPipeline = class _ZodPipeline extends ZodType {
11938
12021
  _parse(input) {
11939
- const { status, ctx } = this._processInputParams(input);
12022
+ const { status: status2, ctx } = this._processInputParams(input);
11940
12023
  if (ctx.common.async) {
11941
12024
  const handleAsync = async () => {
11942
12025
  const inResult = await this._def.in._parseAsync({
@@ -11947,7 +12030,7 @@ var ZodPipeline = class _ZodPipeline extends ZodType {
11947
12030
  if (inResult.status === "aborted")
11948
12031
  return INVALID;
11949
12032
  if (inResult.status === "dirty") {
11950
- status.dirty();
12033
+ status2.dirty();
11951
12034
  return DIRTY(inResult.value);
11952
12035
  } else {
11953
12036
  return this._def.out._parseAsync({
@@ -11967,7 +12050,7 @@ var ZodPipeline = class _ZodPipeline extends ZodType {
11967
12050
  if (inResult.status === "aborted")
11968
12051
  return INVALID;
11969
12052
  if (inResult.status === "dirty") {
11970
- status.dirty();
12053
+ status2.dirty();
11971
12054
  return {
11972
12055
  status: "dirty",
11973
12056
  value: inResult.value
@@ -28324,8 +28407,8 @@ var UrlElicitationRequiredError = class extends McpError {
28324
28407
  };
28325
28408
 
28326
28409
  // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
28327
- function isTerminal(status) {
28328
- return status === "completed" || status === "failed" || status === "cancelled";
28410
+ function isTerminal(status2) {
28411
+ return status2 === "completed" || status2 === "failed" || status2 === "cancelled";
28329
28412
  }
28330
28413
 
28331
28414
  // ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@4.4.3/node_modules/zod-to-json-schema/dist/esm/Options.js
@@ -30544,8 +30627,8 @@ var Protocol = class {
30544
30627
  }
30545
30628
  return task;
30546
30629
  },
30547
- storeTaskResult: async (taskId, status, result) => {
30548
- await taskStore.storeTaskResult(taskId, status, result, sessionId);
30630
+ storeTaskResult: async (taskId, status2, result) => {
30631
+ await taskStore.storeTaskResult(taskId, status2, result, sessionId);
30549
30632
  const task = await taskStore.getTask(taskId, sessionId);
30550
30633
  if (task) {
30551
30634
  const notification = TaskStatusNotificationSchema.parse({
@@ -30561,15 +30644,15 @@ var Protocol = class {
30561
30644
  getTaskResult: (taskId) => {
30562
30645
  return taskStore.getTaskResult(taskId, sessionId);
30563
30646
  },
30564
- updateTaskStatus: async (taskId, status, statusMessage) => {
30647
+ updateTaskStatus: async (taskId, status2, statusMessage) => {
30565
30648
  const task = await taskStore.getTask(taskId, sessionId);
30566
30649
  if (!task) {
30567
30650
  throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
30568
30651
  }
30569
30652
  if (isTerminal(task.status)) {
30570
- throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
30653
+ throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status2}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
30571
30654
  }
30572
- await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
30655
+ await taskStore.updateTaskStatus(taskId, status2, statusMessage, sessionId);
30573
30656
  const updatedTask = await taskStore.getTask(taskId, sessionId);
30574
30657
  if (updatedTask) {
30575
30658
  const notification = TaskStatusNotificationSchema.parse({
@@ -32470,7 +32553,21 @@ function jsonResult(data) {
32470
32553
  ]
32471
32554
  };
32472
32555
  }
32473
- function registerAllTools(server, ctx) {
32556
+ function expectedControlFlow(error51) {
32557
+ const message = error51 instanceof Error ? error51.message : "";
32558
+ return /^caveat not found:/.test(message) || /^community エントリは購読物/.test(message) || /^immutable frontmatter key:/.test(message);
32559
+ }
32560
+ function observeToolFailure(handler, productVersion = "0.0.0") {
32561
+ return async (args) => {
32562
+ try {
32563
+ return jsonResult(await handler(args));
32564
+ } catch (error51) {
32565
+ if (!expectedControlFlow(error51)) observeRuntimeError("CAVEAT.MCP_TOOL_FAILED", { version: productVersion });
32566
+ throw error51;
32567
+ }
32568
+ };
32569
+ }
32570
+ function registerAllTools(server, ctx, productVersion = "0.0.0") {
32474
32571
  server.registerTool(
32475
32572
  "caveat_search",
32476
32573
  {
@@ -32478,7 +32575,7 @@ function registerAllTools(server, ctx) {
32478
32575
  description: 'Search the "caveats" knowledge base \u2014 records of time-wasting traps someone already diagnosed, including external-spec issues (GPU/driver/CUDA versions, native-module builds, IDE/shell quirks, platform-specific behavior, library version incompatibilities) and reusable repo-specific context. Call this FIRST when a problem smells like a known trap \u2014 before reading stack traces top-to-bottom or trying fixes. Query: 3+ chars, plain tokens only (no OR/NEAR/other FTS5 operators). If it returns 0 hits, retry with synonyms and Japanese/English paraphrases. Returns summary rows including `{id, source}` \u2014 pass BOTH to caveat_get for the full body.',
32479
32576
  inputSchema: searchInputShape
32480
32577
  },
32481
- async (args) => jsonResult(handleSearch(ctx, args))
32578
+ observeToolFailure((args) => handleSearch(ctx, args), productVersion)
32482
32579
  );
32483
32580
  server.registerTool(
32484
32581
  "caveat_get",
@@ -32487,7 +32584,7 @@ function registerAllTools(server, ctx) {
32487
32584
  description: 'Fetch the full body (frontmatter + H2 sections + text) of a caveat by id. IMPORTANT: when the id came from caveat_search, you MUST pass the `source` field from that same result (e.g., "community/Caveat"). The default source is "own" only; omitting source for a community entry returns not-found.',
32488
32585
  inputSchema: getInputShape
32489
32586
  },
32490
- async (args) => jsonResult(handleGet(ctx, args))
32587
+ observeToolFailure((args) => handleGet(ctx, args), productVersion)
32491
32588
  );
32492
32589
  server.registerTool(
32493
32590
  "caveat_record",
@@ -32496,7 +32593,7 @@ function registerAllTools(server, ctx) {
32496
32593
  description: "Create a new caveat: a reusable record of a time-wasting trap (wrong driver, version mismatch, platform bug, IDE quirk, native-module issue, or repo-specific context) so future sessions can find it via caveat_search. REQUIRED BEFORE CALLING: run caveat_search first to avoid duplicates. Set visibility using this binary criterion: `public` if a third party could reproduce it; `private` if it is repo/workflow-specific or depends on intentional local design; when unclear, prefer `private`; follow an explicit user visibility choice. Qualifies: specific symptom + diagnosed cause (or `outcome: impossible` verdict) + environment fingerprint. Does NOT qualify: ordinary project-internal logic bugs, user preferences, session summaries, or ephemeral task notes; reusable repo-specific traps may be `private`. Auto-fills source_session and environment defaults; source_project is left null by design (shared knowledge must not leak per-user project names).",
32497
32594
  inputSchema: recordInputShape
32498
32595
  },
32499
- async (args) => jsonResult(handleRecord(ctx, args))
32596
+ observeToolFailure((args) => handleRecord(ctx, args), productVersion)
32500
32597
  );
32501
32598
  server.registerTool(
32502
32599
  "caveat_update",
@@ -32505,7 +32602,7 @@ function registerAllTools(server, ctx) {
32505
32602
  description: "Patch an existing caveat \u2014 use when newer evidence extends or corrects one that already exists. Frontmatter shallow-merges, but array fields (tags etc.) REPLACE rather than append \u2014 to add one tag, read the current list first, then patch with the full new array. Sections match by case-insensitive H2 heading. When changing `Symptom`, preserve raw errors verbatim and add stable Japanese/English symptom keywords when known; do not force or guess translations. Immutable keys: id, created_at, source_session, source_project. Common uses: bump `last_verified` after re-confirming, add a resolution when it was `tentative`, flip `outcome` to `impossible`.",
32506
32603
  inputSchema: updateInputShape
32507
32604
  },
32508
- async (args) => jsonResult(handleUpdate(ctx, args))
32605
+ observeToolFailure((args) => handleUpdate(ctx, args), productVersion)
32509
32606
  );
32510
32607
  server.registerTool(
32511
32608
  "caveat_list_recent",
@@ -32514,7 +32611,7 @@ function registerAllTools(server, ctx) {
32514
32611
  description: "List caveats ordered by updated_at DESC. Use for browsing recent additions \u2014 e.g., showing the user what is new after caveat_pull. Not for search; use caveat_search when you have a query.",
32515
32612
  inputSchema: listRecentInputShape
32516
32613
  },
32517
- async (args) => jsonResult(handleListRecent(ctx, args))
32614
+ observeToolFailure((args) => handleListRecent(ctx, args), productVersion)
32518
32615
  );
32519
32616
  server.registerTool(
32520
32617
  "caveat_pull",
@@ -32523,7 +32620,7 @@ function registerAllTools(server, ctx) {
32523
32620
  description: "git-pull every subscribed community caveat repo (added via `caveat community add`) and re-index. Call when: (a) the user explicitly asks about others' knowledge on a topic, or (b) caveat_search returned empty for a query that feels like it should have hits and a subscribed repo might be stale. Do NOT call reflexively at session start \u2014 it is cheap but not free, and stale-by-minutes is acceptable. Safe and idempotent.",
32524
32621
  inputSchema: pullInputShape
32525
32622
  },
32526
- async (args) => jsonResult(await handlePull(ctx, args))
32623
+ observeToolFailure((args) => handlePull(ctx, args), productVersion)
32527
32624
  );
32528
32625
  }
32529
32626
 
@@ -32534,7 +32631,7 @@ async function startMcpStdioServer(overrides = {}) {
32534
32631
  { name: "caveat", version: "0.0.0" },
32535
32632
  { capabilities: { tools: {} } }
32536
32633
  );
32537
- registerAllTools(server, ctx);
32634
+ registerAllTools(server, ctx, overrides.productVersion);
32538
32635
  const transport = new StdioServerTransport();
32539
32636
  await server.connect(transport);
32540
32637
  const shutdown = () => {
@@ -32560,7 +32657,12 @@ if (invokedPath && thisPath && invokedPath.toLowerCase() === thisPath.toLowerCas
32560
32657
 
32561
32658
  // src/commands/mcpServer.ts
32562
32659
  async function runMcpServer() {
32563
- await startMcpStdioServer();
32660
+ try {
32661
+ await startMcpStdioServer({ productVersion: CAVEAT_VERSION });
32662
+ } catch (error51) {
32663
+ observeRuntimeError("CAVEAT.MCP_SERVER_FAILED", { version: CAVEAT_VERSION });
32664
+ throw error51;
32665
+ }
32564
32666
  }
32565
32667
 
32566
32668
  // src/commands/hookCmd.ts
@@ -32573,7 +32675,7 @@ import {
32573
32675
  mkdirSync as mkdirSync5,
32574
32676
  readdirSync as readdirSync2,
32575
32677
  readFileSync as readFileSync5,
32576
- realpathSync as realpathSync2,
32678
+ realpathSync as realpathSync4,
32577
32679
  rmSync as rmSync2,
32578
32680
  writeFileSync as writeFileSync5
32579
32681
  } from "node:fs";
@@ -32606,14 +32708,14 @@ function maybeTriggerAutoReindex(ctx) {
32606
32708
 
32607
32709
  // src/autoSyncTrigger.ts
32608
32710
  import { spawn as spawn2 } from "node:child_process";
32609
- import { existsSync as existsSync9, statSync } from "node:fs";
32711
+ import { existsSync as existsSync9, statSync as statSync3 } from "node:fs";
32610
32712
  import { join as join11 } from "node:path";
32611
32713
  function maybeTriggerAutoSync(ctx) {
32612
32714
  if (process.env[CAVEAT_AUTO_SYNC_ENV] === "off") return;
32613
32715
  const statePath = join11(ctx.caveatHome, "sync", ".last-autosync.json");
32614
32716
  const debounceMs = Number(process.env.CAVEAT_AUTO_SYNC_DEBOUNCE_MS ?? AUTO_SYNC_DEBOUNCE_MS);
32615
32717
  try {
32616
- if (existsSync9(statePath) && Date.now() - statSync(statePath).mtimeMs < debounceMs) return;
32718
+ if (existsSync9(statePath) && Date.now() - statSync3(statePath).mtimeMs < debounceMs) return;
32617
32719
  } catch {
32618
32720
  }
32619
32721
  const cliScript = process.argv[1];
@@ -32650,6 +32752,7 @@ function parsePayload(raw) {
32650
32752
  try {
32651
32753
  return JSON.parse(raw);
32652
32754
  } catch (err) {
32755
+ observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32653
32756
  const msg = err instanceof Error ? err.message : String(err);
32654
32757
  process.stderr.write(`[caveat:hook] json parse error: ${msg}
32655
32758
  `);
@@ -32664,14 +32767,17 @@ function buildContextSafely() {
32664
32767
  try {
32665
32768
  return buildContext(silentLogger);
32666
32769
  } catch (err) {
32770
+ observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32667
32771
  const msg = err instanceof Error ? err.message : String(err);
32668
32772
  process.stderr.write(`[caveat:hook] context error: ${msg}
32669
32773
  `);
32670
32774
  return null;
32671
32775
  }
32672
32776
  }
32673
- function searchCaveatsFromTextSafely(text, surface) {
32674
- if (!text) return [];
32777
+ function searchCaveatsSafely(input) {
32778
+ const inputs = Array.isArray(input) ? input : [input];
32779
+ const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
32780
+ if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
32675
32781
  let db;
32676
32782
  let caveatHome;
32677
32783
  let hits;
@@ -32680,10 +32786,12 @@ function searchCaveatsFromTextSafely(text, surface) {
32680
32786
  if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
32681
32787
  caveatHome = ctx.caveatHome;
32682
32788
  db = openDb({ path: ctx.paths.dbPath });
32683
- hits = findCaveatsForPrompt(db, text, {
32789
+ const searchOptions = {
32684
32790
  selfIdentity: defaultSelfIdentityTokens()
32685
- });
32791
+ };
32792
+ hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
32686
32793
  } catch (err) {
32794
+ observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32687
32795
  const msg = err instanceof Error ? err.message : String(err);
32688
32796
  process.stderr.write(`[caveat:hook] search error: ${msg}
32689
32797
  `);
@@ -32693,14 +32801,16 @@ function searchCaveatsFromTextSafely(text, surface) {
32693
32801
  try {
32694
32802
  markHit(db, hits);
32695
32803
  } catch (err) {
32804
+ observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32696
32805
  const msg = err instanceof Error ? err.message : String(err);
32697
32806
  process.stderr.write(`[caveat:hook] markHit error: ${msg}
32698
32807
  `);
32699
32808
  }
32700
32809
  } else {
32701
32810
  try {
32702
- logHookQueryMiss({ caveatHome, agent: "claude", surface, query: text });
32811
+ logHookQueryMiss({ caveatHome, agent: "claude", surface: inputs[0].surface, query: queryForLog });
32703
32812
  } catch (err) {
32813
+ observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32704
32814
  const msg = err instanceof Error ? err.message : String(err);
32705
32815
  process.stderr.write(`[caveat:hook] query log error: ${msg}
32706
32816
  `);
@@ -32725,13 +32835,19 @@ function loadSignalsSafely(path) {
32725
32835
  function systemReminderOutput(text) {
32726
32836
  return `<system-reminder>${text.replace(/</g, "\u2039").replace(/>/g, "\u203A")}</system-reminder>`;
32727
32837
  }
32838
+ function claudePendingCleanupFailureText() {
32839
+ return "[caveat:hook] pending reminder cleanup failed";
32840
+ }
32728
32841
  function drainForSession(sessionId) {
32729
32842
  const ctx = buildContextSafely();
32730
32843
  if (!ctx) return [];
32731
- return [
32732
- ...drainPendingReminders(ctx.caveatHome, sessionId),
32733
- ...drainGlobalPendingReminders(ctx.caveatHome)
32734
- ];
32844
+ const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
32845
+ const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
32846
+ for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
32847
+ process.stderr.write(`${claudePendingCleanupFailureText()}
32848
+ `);
32849
+ }
32850
+ return [...local.reminders, ...global.reminders];
32735
32851
  }
32736
32852
  function claudeContextDedupeKey(text) {
32737
32853
  if (text.startsWith(CLAUDE_STOP_REMINDER_PREFIX)) return "claude-stop-reminder";
@@ -32750,7 +32866,7 @@ function compactClaudeContexts(contexts) {
32750
32866
  }
32751
32867
  selected.reverse();
32752
32868
  const limited = selected.slice(-CLAUDE_MAX_CONTEXT_BLOCKS);
32753
- const omitted = contexts.filter((t) => t.trim().length > 0).length - limited.length;
32869
+ const omitted = selected.length - limited.length;
32754
32870
  if (omitted > 0) {
32755
32871
  limited.push(
32756
32872
  `[caveat] pending reminder ${omitted} \u4EF6\u3092\u91CD\u8907\u307E\u305F\u306F\u4E0A\u9650\u306B\u3088\u308A\u7701\u7565\u3057\u307E\u3057\u305F\u3002`
@@ -32795,8 +32911,20 @@ function queueStopForSession(sessionId, signals, related) {
32795
32911
  if (!ctx) return;
32796
32912
  const key = stopSignalKey(signals, related);
32797
32913
  if (wasStopReminderQueued(ctx.caveatHome, sessionId, key)) return;
32914
+ let result;
32915
+ try {
32916
+ result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
32917
+ agent: "claude",
32918
+ surface: "stop",
32919
+ refs: related,
32920
+ stopSignalDigest: key
32921
+ }), () => buildStopReminder(signals, related));
32922
+ } catch {
32923
+ process.stderr.write("[caveat:hook] pending reminder build or publish failed\n");
32924
+ return;
32925
+ }
32926
+ if (!result.ran) return;
32798
32927
  try {
32799
- appendPendingReminder(ctx.caveatHome, sessionId, buildStopReminder(signals, related));
32800
32928
  markStopReminderQueued(ctx.caveatHome, sessionId, key);
32801
32929
  } catch (err) {
32802
32930
  const msg = err instanceof Error ? err.message : String(err);
@@ -32827,6 +32955,20 @@ function extractToolResponseText(response) {
32827
32955
  }
32828
32956
  return "";
32829
32957
  }
32958
+ function toolTopicText(payload) {
32959
+ const parts = [];
32960
+ const toolName = payload.tool_name ?? payload.toolName;
32961
+ if (typeof toolName === "string") parts.push(toolName);
32962
+ const input = payload.tool_input ?? payload.toolInput;
32963
+ if (typeof input === "string") parts.push(input);
32964
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
32965
+ const record2 = input;
32966
+ for (const key of ["command", "cmd", "query", "url"]) {
32967
+ if (typeof record2[key] === "string") parts.push(record2[key]);
32968
+ }
32969
+ }
32970
+ return parts.join("\n");
32971
+ }
32830
32972
  function isToolError(payload) {
32831
32973
  if (payload.hook_event_name === "PostToolUseFailure") return true;
32832
32974
  const resp = payload.tool_response ?? payload.toolResponse;
@@ -32850,7 +32992,7 @@ function spawnWorker(job) {
32850
32992
  workDir = mkdtempSync2(join12(root, "job-"));
32851
32993
  chmodSync(workDir, 448);
32852
32994
  workFile = join12(workDir, `${randomBytes(4).toString("hex")}.json`);
32853
- writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v1" }), { encoding: "utf-8", mode: 384, flag: "wx" });
32995
+ writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
32854
32996
  } catch (err) {
32855
32997
  const msg = err instanceof Error ? err.message : String(err);
32856
32998
  process.stderr.write(`[caveat:hook] worker writefile error: ${msg}
@@ -32894,15 +33036,27 @@ async function runWorker(workFile) {
32894
33036
  } catch {
32895
33037
  process.exit(0);
32896
33038
  }
32897
- if (!job.searchText || !job.sessionId) process.exit(0);
32898
- const hits = searchCaveatsFromTextSafely(job.searchText, "tool_error");
33039
+ if (!job.failureText || !job.sessionId) process.exit(0);
33040
+ const hits = searchCaveatsSafely({
33041
+ topicText: job.topicText,
33042
+ failureText: job.failureText,
33043
+ surface: "tool_error"
33044
+ });
32899
33045
  if (hits.length === 0) process.exit(0);
32900
33046
  const ctx = buildContextSafely();
32901
33047
  if (!ctx) process.exit(0);
33048
+ let result;
32902
33049
  try {
32903
- appendPendingReminder(ctx.caveatHome, job.sessionId, buildToolErrorReminder(job, hits));
33050
+ result = buildAndPublishPendingReminder(ctx.caveatHome, job.sessionId, buildPendingSemanticKey({
33051
+ agent: "claude",
33052
+ surface: "tool_error",
33053
+ refs: hits
33054
+ }), () => buildToolErrorReminder(job, hits));
32904
33055
  } catch {
33056
+ process.stderr.write("[caveat:hook] pending reminder build or publish failed\n");
33057
+ process.exit(0);
32905
33058
  }
33059
+ if (!result.ran) process.exit(0);
32906
33060
  process.exit(0);
32907
33061
  }
32908
33062
  function cleanupWorkerDir(workDir, root) {
@@ -32916,8 +33070,8 @@ function isOwnedWorkerDir(path, root = workerRoot()) {
32916
33070
  try {
32917
33071
  const inputStat = lstatSync(path);
32918
33072
  if (inputStat.isSymbolicLink()) return false;
32919
- const tmpRoot = realpathSync2(root);
32920
- const resolved = realpathSync2(path);
33073
+ const tmpRoot = realpathSync4(root);
33074
+ const resolved = realpathSync4(path);
32921
33075
  const stat = lstatSync(resolved);
32922
33076
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
32923
33077
  return dirname6(resolved) === tmpRoot && basename(resolved).startsWith("job-") && stat.isDirectory() && !stat.isSymbolicLink() && hasPrivateOwnership(stat, uid);
@@ -32969,12 +33123,20 @@ function isStaleWorkerJobDir(path) {
32969
33123
  const stat = lstatSync(file2);
32970
33124
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
32971
33125
  if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
32972
- return isWorkerJob(JSON.parse(readFileSync5(file2, "utf-8")));
33126
+ return isKnownStaleWorkerJob(JSON.parse(readFileSync5(file2, "utf-8")));
32973
33127
  }
32974
33128
  function hasPrivateOwnership(stat, uid) {
32975
33129
  return process.platform === "win32" || (stat.mode & 63) === 0 && (uid === void 0 || stat.uid === uid);
32976
33130
  }
32977
33131
  function isWorkerJob(value) {
33132
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
33133
+ const job = value;
33134
+ const keys = Object.keys(job).sort();
33135
+ if (!(keys.length === 4 && keys.join(",") === "failureText,schemaVersion,sessionId,topicText") && !(keys.length === 5 && keys.join(",") === "additionalContext,failureText,schemaVersion,sessionId,topicText")) return false;
33136
+ return job.schemaVersion === "caveat-worker-job/v2" && typeof job.sessionId === "string" && typeof job.topicText === "string" && typeof job.failureText === "string" && (job.additionalContext === void 0 || job.additionalContext !== null && typeof job.additionalContext === "object" && !Array.isArray(job.additionalContext));
33137
+ }
33138
+ function isKnownStaleWorkerJob(value) {
33139
+ if (isWorkerJob(value)) return true;
32978
33140
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
32979
33141
  const job = value;
32980
33142
  const keys = Object.keys(job).sort();
@@ -33070,7 +33232,7 @@ function buildToolErrorReminder(job, hits) {
33070
33232
  const hasSidecarConfig = existsSync10(join12(projectRoot, ".codex-sidecar.yml"));
33071
33233
  if (mode === "auto" && !hasSidecarConfig) return base;
33072
33234
  const advisory = runCodexSidecarAdvisory({
33073
- searchText: job.searchText,
33235
+ searchText: job.failureText,
33074
33236
  limit: hits.length,
33075
33237
  projectRoot,
33076
33238
  prompt: [
@@ -33170,7 +33332,7 @@ async function runHook(name, arg) {
33170
33332
  const contexts = name === "stop" ? [] : drainForSession(sessionId);
33171
33333
  if (name === "user-prompt-submit") {
33172
33334
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
33173
- const hits = searchCaveatsFromTextSafely(prompt, "user_prompt");
33335
+ const hits = searchCaveatsSafely({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
33174
33336
  if (hits.length > 0) {
33175
33337
  contexts.push(userPromptSubmitReminderText(hits));
33176
33338
  }
@@ -33198,7 +33360,8 @@ async function runHook(name, arg) {
33198
33360
  toolName: payload.tool_name ?? payload.toolName,
33199
33361
  failureKind
33200
33362
  });
33201
- spawnWorker({ sessionId, searchText: errText, ...additionalContext ? { additionalContext } : {} });
33363
+ const topicText = toolTopicText(payload);
33364
+ spawnWorker({ sessionId, topicText, failureText: errText, ...additionalContext ? { additionalContext } : {} });
33202
33365
  }
33203
33366
  process.exit(0);
33204
33367
  }
@@ -33231,7 +33394,11 @@ async function runHook(name, arg) {
33231
33394
  const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
33232
33395
  const signals = transcriptPath ? loadSignalsSafely(transcriptPath) : null;
33233
33396
  if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
33234
- const related = searchCaveatsFromTextSafely(struggleSearchText(signals), "stop");
33397
+ const related = searchCaveatsSafely(signals.errorSnippets.map((failureText) => ({
33398
+ topicText: "",
33399
+ failureText,
33400
+ surface: "stop"
33401
+ })));
33235
33402
  queueStopForSession(sessionId, signals, related);
33236
33403
  process.exit(0);
33237
33404
  }
@@ -33269,6 +33436,7 @@ function parsePayload2(raw) {
33269
33436
  try {
33270
33437
  return JSON.parse(raw);
33271
33438
  } catch (err) {
33439
+ observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33272
33440
  const msg = err instanceof Error ? err.message : String(err);
33273
33441
  process.stderr.write(`[caveat:codex-hook] json parse error: ${msg}
33274
33442
  `);
@@ -33279,14 +33447,17 @@ function buildContextSafely2() {
33279
33447
  try {
33280
33448
  return buildContext(silentLogger2);
33281
33449
  } catch (err) {
33450
+ observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33282
33451
  const msg = err instanceof Error ? err.message : String(err);
33283
33452
  process.stderr.write(`[caveat:codex-hook] context error: ${msg}
33284
33453
  `);
33285
33454
  return null;
33286
33455
  }
33287
33456
  }
33288
- function searchCaveatsFromTextSafely2(text, surface) {
33289
- if (!text) return [];
33457
+ function searchCaveatsSafely2(input) {
33458
+ const inputs = Array.isArray(input) ? input : [input];
33459
+ const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
33460
+ if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
33290
33461
  let db;
33291
33462
  let caveatHome;
33292
33463
  let hits;
@@ -33295,10 +33466,12 @@ function searchCaveatsFromTextSafely2(text, surface) {
33295
33466
  if (!ctx || !existsSync11(ctx.paths.dbPath)) return [];
33296
33467
  caveatHome = ctx.caveatHome;
33297
33468
  db = openDb({ path: ctx.paths.dbPath });
33298
- hits = findCaveatsForPrompt(db, text, {
33469
+ const searchOptions = {
33299
33470
  selfIdentity: defaultSelfIdentityTokens()
33300
- });
33471
+ };
33472
+ hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
33301
33473
  } catch (err) {
33474
+ observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33302
33475
  const msg = err instanceof Error ? err.message : String(err);
33303
33476
  process.stderr.write(`[caveat:codex-hook] search error: ${msg}
33304
33477
  `);
@@ -33308,14 +33481,16 @@ function searchCaveatsFromTextSafely2(text, surface) {
33308
33481
  try {
33309
33482
  markHit(db, hits);
33310
33483
  } catch (err) {
33484
+ observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33311
33485
  const msg = err instanceof Error ? err.message : String(err);
33312
33486
  process.stderr.write(`[caveat:codex-hook] markHit error: ${msg}
33313
33487
  `);
33314
33488
  }
33315
33489
  } else {
33316
33490
  try {
33317
- logHookQueryMiss({ caveatHome, agent: "codex", surface, query: text });
33491
+ logHookQueryMiss({ caveatHome, agent: "codex", surface: inputs[0].surface, query: queryForLog });
33318
33492
  } catch (err) {
33493
+ observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33319
33494
  const msg = err instanceof Error ? err.message : String(err);
33320
33495
  process.stderr.write(`[caveat:codex-hook] query log error: ${msg}
33321
33496
  `);
@@ -33443,15 +33618,17 @@ function buildCodexPostToolUseWorkerJob(payload) {
33443
33618
  const responseText = extractToolResponseText2(payload.tool_response ?? payload.toolResponse);
33444
33619
  const inputText = toolInputText(payload.tool_input);
33445
33620
  const transcriptOutput = transcriptPath && toolUseId ? transcriptToolOutput(transcriptPath, toolUseId) : null;
33446
- const searchText = [inputText, responseText, transcriptOutput ?? ""].map((s) => s.trim()).filter(Boolean).join("\n");
33621
+ const topicText = inputText.trim();
33622
+ const failureText = [responseText, transcriptOutput ?? ""].map((s) => s.trim()).filter(Boolean).join("\n");
33447
33623
  const knownError = isCodexToolError(payload);
33448
33624
  if (knownError) {
33449
- return { sessionId, searchText, knownError: true, transcriptPath, toolUseId };
33625
+ return { sessionId, topicText, failureText, knownError: true, transcriptPath, toolUseId };
33450
33626
  }
33451
- if (transcriptPath && toolUseId && isShellLikeTool(payload) && searchText) {
33627
+ if (transcriptPath && toolUseId && isShellLikeTool(payload) && (topicText || failureText)) {
33452
33628
  return {
33453
33629
  sessionId,
33454
- searchText,
33630
+ topicText,
33631
+ failureText,
33455
33632
  knownError: false,
33456
33633
  allowSymptomOnly: true,
33457
33634
  transcriptPath,
@@ -33468,13 +33645,19 @@ function codexContextOutput(text, eventName = "UserPromptSubmit") {
33468
33645
  }
33469
33646
  });
33470
33647
  }
33648
+ function codexPendingCleanupFailureText() {
33649
+ return "[caveat:codex-hook] pending reminder cleanup failed";
33650
+ }
33471
33651
  function drainForSession2(sessionId) {
33472
33652
  const ctx = buildContextSafely2();
33473
33653
  if (!ctx) return [];
33474
- return [
33475
- ...drainPendingReminders(ctx.caveatHome, sessionId),
33476
- ...drainGlobalPendingReminders(ctx.caveatHome)
33477
- ];
33654
+ const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
33655
+ const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
33656
+ for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
33657
+ process.stderr.write(`${codexPendingCleanupFailureText()}
33658
+ `);
33659
+ }
33660
+ return [...local.reminders, ...global.reminders];
33478
33661
  }
33479
33662
  function codexContextDedupeKey(text) {
33480
33663
  if (text.startsWith(CODEX_STOP_REMINDER_PREFIX)) return "codex-stop-reminder";
@@ -33493,7 +33676,7 @@ function compactCodexContexts(contexts) {
33493
33676
  }
33494
33677
  selected.reverse();
33495
33678
  const limited = selected.slice(-CODEX_MAX_CONTEXT_BLOCKS);
33496
- const omitted = contexts.filter((t) => t.trim().length > 0).length - limited.length;
33679
+ const omitted = selected.length - limited.length;
33497
33680
  if (omitted > 0) {
33498
33681
  limited.push(`[caveat] pending reminder ${omitted} \u4EF6\u3092\u91CD\u8907\u307E\u305F\u306F\u4E0A\u9650\u306B\u3088\u308A\u7701\u7565\u3057\u307E\u3057\u305F\u3002`);
33499
33682
  }
@@ -33536,8 +33719,20 @@ function queueStopForSession2(sessionId, signals, related) {
33536
33719
  if (!ctx) return;
33537
33720
  const key = stopSignalKey2(signals, related);
33538
33721
  if (wasStopReminderQueued2(ctx.caveatHome, sessionId, key)) return;
33722
+ let result;
33723
+ try {
33724
+ result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
33725
+ agent: "codex",
33726
+ surface: "stop",
33727
+ refs: related,
33728
+ stopSignalDigest: key
33729
+ }), () => stopReminderText(signals, related));
33730
+ } catch {
33731
+ process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
33732
+ return;
33733
+ }
33734
+ if (!result.ran) return;
33539
33735
  try {
33540
- appendPendingReminder(ctx.caveatHome, sessionId, stopReminderText(signals, related));
33541
33736
  markStopReminderQueued2(ctx.caveatHome, sessionId, key);
33542
33737
  } catch (err) {
33543
33738
  const msg = err instanceof Error ? err.message : String(err);
@@ -33555,8 +33750,8 @@ async function waitForTranscriptOutput(transcriptPath, toolUseId) {
33555
33750
  return null;
33556
33751
  }
33557
33752
  async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
33558
- if (!job.searchText || !job.sessionId) return;
33559
- let searchText = job.searchText;
33753
+ if (!job.topicText && !job.failureText || !job.sessionId) return;
33754
+ let failureText = job.failureText;
33560
33755
  let knownError = job.knownError === true;
33561
33756
  if (opts.waitForTranscript && job.transcriptPath && job.toolUseId) {
33562
33757
  const transcriptOutput = await waitForTranscriptOutput(job.transcriptPath, job.toolUseId);
@@ -33566,18 +33761,30 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
33566
33761
  if (exit2 === 0) return;
33567
33762
  knownError = true;
33568
33763
  }
33569
- searchText = [searchText, transcriptOutput].filter(Boolean).join("\n");
33764
+ failureText = [failureText, transcriptOutput].filter(Boolean).join("\n");
33570
33765
  }
33571
33766
  }
33572
33767
  if (!knownError && job.allowSymptomOnly !== true) return;
33573
- const hits = searchCaveatsFromTextSafely2(searchText, "tool_error");
33768
+ const hits = searchCaveatsSafely2({
33769
+ topicText: job.topicText,
33770
+ failureText,
33771
+ surface: "tool_error"
33772
+ });
33574
33773
  if (hits.length === 0) return;
33575
33774
  const ctx = buildContextSafely2();
33576
33775
  if (!ctx) return;
33776
+ let result;
33577
33777
  try {
33578
- appendPendingReminder(ctx.caveatHome, job.sessionId, toolErrorReminderText(hits));
33778
+ result = buildAndPublishPendingReminder(ctx.caveatHome, job.sessionId, buildPendingSemanticKey({
33779
+ agent: "codex",
33780
+ surface: "tool_error",
33781
+ refs: hits
33782
+ }), () => toolErrorReminderText(hits));
33579
33783
  } catch {
33784
+ process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
33785
+ return;
33580
33786
  }
33787
+ if (!result.ran) return;
33581
33788
  }
33582
33789
  async function runCodexWorker(workFile) {
33583
33790
  let raw;
@@ -33649,7 +33856,7 @@ async function runCodexHook(name, arg) {
33649
33856
  if (name === "user-prompt-submit") {
33650
33857
  const contexts = sessionId ? drainForSession2(sessionId) : [];
33651
33858
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
33652
- const hits = searchCaveatsFromTextSafely2(prompt, "user_prompt");
33859
+ const hits = searchCaveatsSafely2({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
33653
33860
  if (hits.length > 0) {
33654
33861
  contexts.push(userPromptSubmitReminderText(hits));
33655
33862
  }
@@ -33694,7 +33901,11 @@ async function runCodexHook(name, arg) {
33694
33901
  const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
33695
33902
  const signals = transcriptPath ? loadSignalsSafely2(transcriptPath) : null;
33696
33903
  if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
33697
- const related = searchCaveatsFromTextSafely2(struggleSearchText(signals), "stop");
33904
+ const related = searchCaveatsSafely2(signals.errorSnippets.map((failureText) => ({
33905
+ topicText: "",
33906
+ failureText,
33907
+ surface: "stop"
33908
+ })));
33698
33909
  if (sessionId) queueStopForSession2(sessionId, signals, related);
33699
33910
  process.exit(0);
33700
33911
  }
@@ -33751,6 +33962,11 @@ async function defaultPrivateRepoUrl(opts, deps) {
33751
33962
  });
33752
33963
  }
33753
33964
  async function runSync(ctx, opts, dependencies = {}) {
33965
+ if (opts.repo && (opts.init === void 0 || opts.init === false)) {
33966
+ ctx.logger.error("--repo requires --init");
33967
+ process.exitCode = 1;
33968
+ return;
33969
+ }
33754
33970
  try {
33755
33971
  const ghRunner = dependencies.ghRunner ?? runGh;
33756
33972
  const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
@@ -33771,7 +33987,6 @@ async function runSync(ctx, opts, dependencies = {}) {
33771
33987
  );
33772
33988
  return;
33773
33989
  }
33774
- if (opts.repo) throw new Error("--repo requires --init");
33775
33990
  const result = await syncOwn({
33776
33991
  ownDir: ctx.paths.knowledgeRepo,
33777
33992
  caveatHome: ctx.caveatHome,
@@ -33793,6 +34008,7 @@ async function runSync(ctx, opts, dependencies = {}) {
33793
34008
  }
33794
34009
  }
33795
34010
  } catch (err) {
34011
+ observeRuntimeError("CAVEAT.SYNC_FAILED", { version: CAVEAT_VERSION });
33796
34012
  const message = err instanceof Error ? err.message : String(err);
33797
34013
  ctx.logger.error(message);
33798
34014
  process.exitCode = 1;
@@ -33801,7 +34017,7 @@ async function runSync(ctx, opts, dependencies = {}) {
33801
34017
 
33802
34018
  // src/commands/codexSidecar.ts
33803
34019
  import { spawnSync as spawnSync6 } from "node:child_process";
33804
- import { closeSync, constants, fstatSync, lstatSync as lstatSync2, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync3, openSync, readSync as readSync2, realpathSync as realpathSync3, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
34020
+ import { closeSync, constants as constants3, fstatSync, lstatSync as lstatSync2, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync3, openSync, readSync as readSync2, realpathSync as realpathSync5, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
33805
34021
  import { tmpdir as tmpdir4 } from "node:os";
33806
34022
  import { basename as basename2, dirname as dirname7, join as join14 } from "node:path";
33807
34023
  import { cwd, exit } from "node:process";
@@ -33837,7 +34053,7 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
33837
34053
  }
33838
34054
  const contextDir = mkdtempSync3(join14(tmpdir4(), "caveat-sidecar-context-"));
33839
34055
  const contextFile = join14(contextDir, "context.json");
33840
- let status = 1;
34056
+ let status2 = 1;
33841
34057
  try {
33842
34058
  const blocks = collectCaveatContextBlocks(ctx, {
33843
34059
  query: opts.query ?? prompt ?? "",
@@ -33855,11 +34071,11 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
33855
34071
  contextFile,
33856
34072
  cli: cliSpec(opts)
33857
34073
  });
33858
- status = executePlan(ctx.logger, plan.command, plan.args, { saveResult: opts.saveResult });
34074
+ status2 = executePlan(ctx.logger, plan.command, plan.args, { saveResult: opts.saveResult });
33859
34075
  } finally {
33860
34076
  rmSync3(contextDir, { recursive: true, force: true });
33861
34077
  }
33862
- exit(status);
34078
+ exit(status2);
33863
34079
  }
33864
34080
  var MAX_ADDITIONAL_CONTEXT_BYTES = 4096;
33865
34081
  function readHookSignalAdditionalContextFile(path, testProbe) {
@@ -33869,7 +34085,7 @@ function readHookSignalAdditionalContextFile(path, testProbe) {
33869
34085
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
33870
34086
  assertPrivateRegular(before, uid, platform);
33871
34087
  testProbe?.afterLstat?.();
33872
- const fd = openSync(path, constants.O_RDONLY | constants.O_NONBLOCK | (constants.O_NOFOLLOW ?? 0));
34088
+ const fd = openSync(path, constants3.O_RDONLY | constants3.O_NONBLOCK | (constants3.O_NOFOLLOW ?? 0));
33873
34089
  let raw;
33874
34090
  try {
33875
34091
  const opened = fstatSync(fd);
@@ -33908,8 +34124,8 @@ function assertWindowsPrivateTempContainer(path, platform) {
33908
34124
  if (platform !== "win32") return;
33909
34125
  const parent = dirname7(path);
33910
34126
  const parentStat = lstatSync2(parent);
33911
- const resolvedParent = realpathSync3(parent);
33912
- const resolvedTemp = realpathSync3(tmpdir4());
34127
+ const resolvedParent = realpathSync5(parent);
34128
+ const resolvedTemp = realpathSync5(tmpdir4());
33913
34129
  if (parentStat.isSymbolicLink() || !parentStat.isDirectory() || dirname7(resolvedParent) !== resolvedTemp || !basename2(resolvedParent).startsWith("caveat-")) {
33914
34130
  throw new Error("additional context file must be inside a reserved per-user Caveat temporary directory");
33915
34131
  }
@@ -34086,12 +34302,200 @@ function runCommunityRemove(ctx, handle, opts) {
34086
34302
  }
34087
34303
  }
34088
34304
 
34305
+ // src/commands/factoryDiagnostics.ts
34306
+ import { execFileSync } from "node:child_process";
34307
+ import { existsSync as existsSync13, readFileSync as readFileSync7 } from "node:fs";
34308
+ import { join as join15 } from "node:path";
34309
+ import { DatabaseSync } from "node:sqlite";
34310
+ import { parse as parseToml2 } from "smol-toml";
34311
+ var status = (ok, reason) => ({ status: ok ? "ready" : "not_ready", reason_code: ok ? "ready" : reason });
34312
+ var unverified = (reason) => ({ status: "unverified", reason_code: reason });
34313
+ function hook(present) {
34314
+ return status(present, "not_installed");
34315
+ }
34316
+ function isRecord2(value) {
34317
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34318
+ }
34319
+ function claudeRegistration(home, nodePath, cliScriptPath) {
34320
+ const path = join15(home, ".claude.json");
34321
+ if (!existsSync13(path)) return status(false, "not_registered");
34322
+ try {
34323
+ const value = JSON.parse(readFileSync7(path, "utf8"));
34324
+ if (!isRecord2(value) || !isRecord2(value.mcpServers)) return status(false, "not_registered");
34325
+ return status(isCaveatClaudeMcpRegistration(value.mcpServers.caveat, nodePath, cliScriptPath), "not_registered");
34326
+ } catch {
34327
+ return unverified("config_unreadable");
34328
+ }
34329
+ }
34330
+ function claudeHooks(home, nodePath, cliScriptPath) {
34331
+ try {
34332
+ const settings = JSON.parse(readFileSync7(join15(home, ".claude", "settings.json"), "utf8"));
34333
+ const present = (event, subcommand) => settings.hooks?.[event]?.some((entry) => entry.hooks?.some((item) => typeof item.command === "string" && isCanonicalCaveatClaudeHookCommand(item.command, subcommand, nodePath, cliScriptPath))) ?? false;
34334
+ return { user_prompt_submit: hook(present("UserPromptSubmit", "user-prompt-submit")), post_tool_use: hook(present("PostToolUse", "post-tool-use")), post_tool_use_failure: hook(present("PostToolUseFailure", "post-tool-use")), stop: hook(present("Stop", "stop")) };
34335
+ } catch {
34336
+ const bad = unverified("config_unreadable");
34337
+ return { user_prompt_submit: { ...bad }, post_tool_use: { ...bad }, post_tool_use_failure: { ...bad }, stop: { ...bad } };
34338
+ }
34339
+ }
34340
+ var EXPECTED_SEARCH_SQL = /* @__PURE__ */ new Map([
34341
+ ["entries_fts", "create virtual table entries_fts using fts5( id unindexed, title, body, tags, content='entries', content_rowid='rowid', tokenize='trigram' )"],
34342
+ ["entries_ai", "create trigger entries_ai after insert on entries begin insert into entries_fts(rowid, id, title, body, tags) values (new.rowid, new.id, new.title, new.body, new.tags); end"],
34343
+ ["entries_ad", "create trigger entries_ad after delete on entries begin insert into entries_fts(entries_fts, rowid, id, title, body, tags) values('delete', old.rowid, old.id, old.title, old.body, old.tags); end"],
34344
+ ["entries_au", "create trigger entries_au after update on entries begin insert into entries_fts(entries_fts, rowid, id, title, body, tags) values('delete', old.rowid, old.id, old.title, old.body, old.tags); insert into entries_fts(rowid, id, title, body, tags) values (new.rowid, new.id, new.title, new.body, new.tags); end"]
34345
+ ]);
34346
+ function strictSearchSchema(db) {
34347
+ const normalize = (sql) => (sql ?? "").toLowerCase().replace(/\s+/g, " ");
34348
+ const objects = db.prepare("SELECT name, sql FROM sqlite_master WHERE name = 'entries_fts' OR (type = 'trigger' AND tbl_name = 'entries')").all();
34349
+ if (objects.length !== EXPECTED_SEARCH_SQL.size || objects.some((object3) => normalize(object3.sql) !== EXPECTED_SEARCH_SQL.get(object3.name))) return false;
34350
+ const columns = db.prepare("PRAGMA table_xinfo(entries_fts)").all();
34351
+ return columns.map((column) => `${column.name}:${column.hidden}`).join(",") === "id:0,title:0,body:0,tags:0,entries_fts:1,rank:1";
34352
+ }
34353
+ function database(path) {
34354
+ if (!existsSync13(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
34355
+ try {
34356
+ const db = new DatabaseSync(path, { readOnly: true });
34357
+ try {
34358
+ const row = db.prepare("PRAGMA user_version").get();
34359
+ const columns = db.prepare("PRAGMA table_info(entries)").all().map((entry) => entry.name);
34360
+ const expectedColumns = ["rowid", "id", "source", "path", "title", "body", "frontmatter_json", "tags", "confidence", "visibility", "file_mtime", "indexed_at", "last_hit_at", "topical_text", "symptom_text"];
34361
+ const objects = db.prepare("SELECT type, name, tbl_name, sql FROM sqlite_master WHERE name = 'entries_fts' OR (type = 'trigger' AND tbl_name = 'entries')").all();
34362
+ const normalized = (sql) => (sql ?? "").toLowerCase().replace(/\s+/g, " ");
34363
+ const ftsSql = normalized(objects.find((entry) => entry.type === "table" && entry.name === "entries_fts")?.sql ?? null);
34364
+ const fts = ftsSql.startsWith("create virtual table entries_fts using fts5(") && ftsSql.includes("content='entries'") && ftsSql.includes("content_rowid='rowid'") && ftsSql.includes("tokenize='trigram'");
34365
+ const triggers = new Map(objects.filter((entry) => entry.type === "trigger").map((entry) => [entry.name, normalized(entry.sql)]));
34366
+ const triggerShape = triggers.size === 3 && triggers.get("entries_ai")?.includes("after insert on entries") && triggers.get("entries_ai")?.includes("insert into entries_fts") && triggers.get("entries_ad")?.includes("after delete on entries") && triggers.get("entries_ad")?.includes("values('delete'") && triggers.get("entries_au")?.includes("after update on entries") && triggers.get("entries_au")?.includes("values('delete'") && (triggers.get("entries_au")?.match(/insert into entries_fts/g)?.length ?? 0) === 2;
34367
+ const indexes = db.prepare("PRAGMA index_list(entries)").all();
34368
+ const uniqueSourceId = indexes.some((index) => index.unique === 1 && db.prepare(`PRAGMA index_info(${JSON.stringify(index.name)})`).all().map((part) => part.name).join(",") === "source,id");
34369
+ const current = row.user_version === 3 && columns.join(",") === expectedColumns.join(",") && fts && Boolean(triggerShape) && uniqueSourceId && strictSearchSchema(db);
34370
+ return { status: current ? "ready" : "not_ready", reason_code: current ? "ready" : "schema_contract_mismatch", schema_version: row.user_version, supported_schema_version: 3, migration_status: current ? "current" : "failed" };
34371
+ } finally {
34372
+ db.close();
34373
+ }
34374
+ } catch {
34375
+ return { status: "unverified", reason_code: "open_failed", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
34376
+ }
34377
+ }
34378
+ function codexFeature(codexHome) {
34379
+ const path = join15(codexHome, "config.toml");
34380
+ if (!existsSync13(path)) return status(false, "feature_disabled");
34381
+ try {
34382
+ const config2 = parseToml2(readFileSync7(path, "utf8"));
34383
+ if (!isRecord2(config2.features)) return status(false, "feature_disabled");
34384
+ const features = config2.features;
34385
+ return status(features.hooks === true && features.codex_hooks === void 0, "feature_disabled");
34386
+ } catch {
34387
+ return unverified("config_unreadable");
34388
+ }
34389
+ }
34390
+ function codexHooks(codexHome, nodePath, cliScriptPath) {
34391
+ const value = JSON.parse(readFileSync7(join15(codexHome, "hooks.json"), "utf8"));
34392
+ if (!isRecord2(value) || !isRecord2(value.hooks)) throw Error("config_unreadable");
34393
+ const hooks = value.hooks;
34394
+ const present = (event, subcommand) => Array.isArray(hooks[event]) && hooks[event].some((entry) => isRecord2(entry) && Array.isArray(entry.hooks) && entry.hooks.some((item) => isRecord2(item) && typeof item.command === "string" && isCanonicalCaveatCodexHookCommand(item.command, subcommand, nodePath, cliScriptPath)));
34395
+ return { userPromptSubmit: present("UserPromptSubmit", "user-prompt-submit"), postToolUse: present("PostToolUse", "post-tool-use"), stop: present("Stop", "stop") };
34396
+ }
34397
+ function sync(own) {
34398
+ try {
34399
+ execFileSync("git", ["-C", own, "rev-parse", "--is-inside-work-tree"], { stdio: "ignore" });
34400
+ } catch {
34401
+ return status(false, "not_git_worktree");
34402
+ }
34403
+ try {
34404
+ execFileSync("git", ["-C", own, "remote", "get-url", "origin"], { stdio: "ignore" });
34405
+ } catch {
34406
+ return status(false, "origin_missing");
34407
+ }
34408
+ try {
34409
+ const dirty = execFileSync("git", ["-C", own, "status", "--porcelain=v1", "--untracked-files=normal"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3, env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" } }).trim();
34410
+ if (dirty) return status(false, "worktree_dirty");
34411
+ const upstream = execFileSync("git", ["-C", own, "rev-parse", "--symbolic-full-name", "@{upstream}"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
34412
+ if (!upstream.startsWith("refs/remotes/origin/")) return status(false, "upstream_not_origin");
34413
+ const remoteRef = `refs/heads/${upstream.slice("refs/remotes/origin/".length)}`;
34414
+ const remote = execFileSync("git", ["-C", own, "ls-remote", "--exit-code", "origin", remoteRef], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 1e4, maxBuffer: 16384 }).trim().split(/\s+/)[0];
34415
+ const head = execFileSync("git", ["-C", own, "rev-parse", "HEAD"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
34416
+ if (!/^[0-9a-f]{40}$/.test(remote ?? "") || !/^[0-9a-f]{40}$/.test(head)) return unverified("sync_hash_unparseable");
34417
+ if (remote !== head) return status(false, "remote_mismatch");
34418
+ const counts = execFileSync("git", ["-C", own, "rev-list", "--left-right", "--count", "@{upstream}...HEAD"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim().split(/\s+/).map(Number);
34419
+ if (counts.length !== 2 || counts.some((value) => !Number.isSafeInteger(value) || value < 0)) return unverified("sync_count_unparseable");
34420
+ if (counts[0] === 0 && counts[1] === 0) return status(true, "ready");
34421
+ return status(false, counts[0] && counts[1] ? "diverged" : counts[0] ? "behind" : "ahead");
34422
+ } catch {
34423
+ return unverified("upstream_unavailable");
34424
+ }
34425
+ }
34426
+ function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join15(ctx.userHome, ".codex")) {
34427
+ const nodePath = process.execPath;
34428
+ const cliScriptPath = process.argv[1] ?? "";
34429
+ const db = database(ctx.paths.dbPath);
34430
+ const feature = codexFeature(codexHome);
34431
+ let installedCodexHooks = null;
34432
+ try {
34433
+ installedCodexHooks = codexHooks(codexHome, nodePath, cliScriptPath);
34434
+ } catch {
34435
+ }
34436
+ const codexHook2 = (present) => present === void 0 ? unverified("config_unreadable") : !present ? hook(false) : feature.status === "ready" ? hook(true) : { ...feature };
34437
+ 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(ctx.userHome, nodePath, cliScriptPath), hooks: claudeHooks(ctx.userHome, nodePath, cliScriptPath) }, codex: { status: "unverified", hooks: { user_prompt_submit: codexHook2(installedCodexHooks?.userPromptSubmit), post_tool_use: codexHook2(installedCodexHooks?.postToolUse), stop: codexHook2(installedCodexHooks?.stop) } } } };
34438
+ const aggregate = (all) => all.includes("not_ready") ? "not_ready" : all.includes("unverified") ? "unverified" : "ready";
34439
+ const connectorStatus = (connector) => aggregate([...Object.values(connector.hooks), ...connector.mcp ? [connector.mcp] : []].map((v) => v.status));
34440
+ output.connectors.claude.status = connectorStatus(output.connectors.claude);
34441
+ output.connectors.codex.status = connectorStatus(output.connectors.codex);
34442
+ const statuses = [output.database.status, output.sync.status, output.connectors.claude.status, output.connectors.codex.status];
34443
+ output.overall.status = aggregate(statuses);
34444
+ return output;
34445
+ }
34446
+
34447
+ // src/commands/runtimeErrors.ts
34448
+ function runRuntimeErrors(action, value, opts = {}) {
34449
+ const runtime = { version: CAVEAT_VERSION };
34450
+ if (action === "snapshot") return runtimeErrorsSnapshot(opts.afterCursor ?? 0, opts.limit ?? 256, runtime);
34451
+ if (action === "diagnostics") return runtimeErrorsDiagnostics(runtime);
34452
+ if (action === "ack") return acknowledgeRuntimeErrors(parseCursor(value), runtime);
34453
+ if (action === "resolve") return setRuntimeErrorStatus(value ?? "", "resolved", runtime);
34454
+ if (action === "reopen") return setRuntimeErrorStatus(value ?? "", "open", runtime);
34455
+ if (action === "compact") return compactRuntimeErrors(runtime);
34456
+ throw new Error("unknown_runtime_errors_action");
34457
+ }
34458
+ function parseCursor(value) {
34459
+ if (!value || !/^(?:0|[1-9][0-9]*)$/.test(value)) throw Error("invalid_cursor");
34460
+ const parsed = Number(value);
34461
+ if (!Number.isSafeInteger(parsed)) throw Error("invalid_cursor");
34462
+ return parsed;
34463
+ }
34464
+
34089
34465
  // src/index.ts
34090
34466
  var program = new Command();
34091
34467
  function collectRepeatable(value, previous) {
34092
34468
  return [...previous, value];
34093
34469
  }
34094
34470
  program.name("caveat").description("External spec gotcha knowledge base CLI").version(CAVEAT_VERSION);
34471
+ program.command("factory-diagnostics").description("Emit read-only factory diagnostics").requiredOption("--json", "emit the versioned JSON contract").action((opts) => {
34472
+ const output = factoryDiagnostics(buildContext(stdoutLogger));
34473
+ process.stdout.write(`${JSON.stringify(output)}
34474
+ `);
34475
+ if (output.overall.status !== "ready") process.exitCode = 1;
34476
+ });
34477
+ var runtimeErrors = program.command("runtime-errors").description("Inspect Caveat opt-in runtime errors");
34478
+ var parseLimit = (value) => {
34479
+ const parsed = parseCursor(value);
34480
+ if (parsed < 1 || parsed > 256) throw Error("invalid_limit");
34481
+ return parsed;
34482
+ };
34483
+ runtimeErrors.command("snapshot").requiredOption("--json", "emit JSON").option("--after-cursor <n>", "cursor", parseCursor, 0).option("--limit <n>", "limit", parseLimit, 256).action((opts) => {
34484
+ process.stdout.write(`${JSON.stringify(runRuntimeErrors("snapshot", void 0, opts))}
34485
+ `);
34486
+ });
34487
+ for (const action of ["diagnostics", "compact"]) runtimeErrors.command(action).requiredOption("--json", "emit JSON").action(() => {
34488
+ process.stdout.write(`${JSON.stringify(runRuntimeErrors(action))}
34489
+ `);
34490
+ });
34491
+ runtimeErrors.command("ack <cursor>").requiredOption("--json", "emit JSON").action((cursor) => {
34492
+ process.stdout.write(`${JSON.stringify(runRuntimeErrors("ack", cursor))}
34493
+ `);
34494
+ });
34495
+ for (const action of ["resolve", "reopen"]) runtimeErrors.command(`${action} <fingerprint>`).requiredOption("--json", "emit JSON").action((fingerprint) => {
34496
+ process.stdout.write(`${JSON.stringify(runRuntimeErrors(action, fingerprint))}
34497
+ `);
34498
+ });
34095
34499
  program.command("init").description(
34096
34500
  "Initialize ~/.caveatrc.json, ~/.caveat/, and register Claude Code integration. Add knowledge sources later with `caveat community add <github-url>`."
34097
34501
  ).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--sync [url]", "initialize private sync (optionally with its URL)").option("--publish-target [url]", "configure the sealed public mirror target").option("--yes", "approve creating conventional GitHub repositories", false).option("--skip-codex-hook", "skip Codex hook installation", false).option("--dry-run", "show planned changes without writing", false).option(