caveat-cli 0.17.2 → 0.17.4

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
@@ -38,14 +38,18 @@ import {
38
38
  get,
39
39
  hasAnyStruggleSignal,
40
40
  initOwnSync,
41
+ isPrivateOwnerStat,
42
+ isWindows,
41
43
  listRecent,
42
44
  listStale,
43
45
  loadConfig,
44
46
  logHookQueryMiss,
45
47
  markHit,
46
48
  maybeSweepPendingDirs,
49
+ nodeExecutableNames,
47
50
  observeRuntimeError,
48
51
  openDb,
52
+ powershellCallPrefix,
49
53
  prewarmSealedKeys,
50
54
  publishOwn,
51
55
  readCodexSessionSignals,
@@ -72,7 +76,7 @@ import {
72
76
  userPromptSubmitReminderText,
73
77
  writeDigestMarker,
74
78
  writeUserConfigPatch
75
- } from "./chunk-TRIQ5WFY.js";
79
+ } from "./chunk-ZBHCOA6R.js";
76
80
 
77
81
  // ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
78
82
  var require_code = __commonJS({
@@ -6885,25 +6889,67 @@ var stdoutLogger = {
6885
6889
 
6886
6890
  // src/commands/init.ts
6887
6891
  import { spawnSync as spawnSync4 } from "node:child_process";
6888
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync, renameSync, rmdirSync, writeFileSync as writeFileSync4 } from "node:fs";
6889
- import { dirname as dirname4, join as join8 } from "node:path";
6892
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync, renameSync, rmdirSync, writeFileSync as writeFileSync3 } from "node:fs";
6893
+ import { dirname as dirname3, join as join8 } from "node:path";
6890
6894
 
6891
6895
  // src/claudeInstall.ts
6892
6896
  import { spawnSync } from "node:child_process";
6893
- import { accessSync, constants, copyFileSync, existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, statSync, writeFileSync } from "node:fs";
6894
- import { dirname as dirname2, isAbsolute, join as join3 } from "node:path";
6897
+ import { constants, existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
6898
+ import { join as join3 } from "node:path";
6899
+
6900
+ // src/installShared.ts
6901
+ import { accessSync, copyFileSync, existsSync, mkdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
6902
+ import { dirname as dirname2, isAbsolute } from "node:path";
6903
+ function quoteIfSpaces(p) {
6904
+ return p.includes(" ") ? `"${p}"` : p;
6905
+ }
6906
+ function commandTokens(command) {
6907
+ const tokens = [];
6908
+ const pattern = /"([^"]*)"|([^\s"]+)/g;
6909
+ let end = 0;
6910
+ let match;
6911
+ while ((match = pattern.exec(command)) !== null) {
6912
+ if (command.slice(end, match.index).trim()) return null;
6913
+ tokens.push(match[1] ?? match[2]);
6914
+ end = pattern.lastIndex;
6915
+ }
6916
+ return command.slice(end).trim() ? null : tokens;
6917
+ }
6918
+ function isCanonicalAsset(path, expectedPath, mode) {
6919
+ if (typeof path !== "string" || !isAbsolute(path) || !isAbsolute(expectedPath)) return false;
6920
+ try {
6921
+ accessSync(path, mode);
6922
+ return statSync(path).isFile() && realpathSync(path) === realpathSync(expectedPath);
6923
+ } catch {
6924
+ return false;
6925
+ }
6926
+ }
6927
+ function writeFileWithBackup(path, text) {
6928
+ const dir = dirname2(path);
6929
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
6930
+ let backupPath = "";
6931
+ if (existsSync(path)) {
6932
+ backupPath = `${path}.caveat-backup-${Date.now()}`;
6933
+ copyFileSync(path, backupPath);
6934
+ }
6935
+ writeFileSync(path, text, "utf-8");
6936
+ return backupPath;
6937
+ }
6938
+ function writeJsonWithBackup(path, value) {
6939
+ return writeFileWithBackup(path, `${JSON.stringify(value, null, 2)}
6940
+ `);
6941
+ }
6942
+
6943
+ // src/claudeInstall.ts
6895
6944
  var EVENT_USER_PROMPT_SUBMIT = "UserPromptSubmit";
6896
6945
  var EVENT_POST_TOOL_USE = "PostToolUse";
6897
6946
  var EVENT_POST_TOOL_USE_FAILURE = "PostToolUseFailure";
6898
6947
  var EVENT_STOP = "Stop";
6899
- function quote(p) {
6900
- return p.includes(" ") ? `"${p}"` : p;
6901
- }
6902
6948
  function mcpArgs(cliScriptPath) {
6903
6949
  return ["--disable-warning=ExperimentalWarning", cliScriptPath, "mcp-server"];
6904
6950
  }
6905
6951
  function hookCommand(nodePath, cliScriptPath, event) {
6906
- return `${quote(nodePath)} ${quote(cliScriptPath)} hook ${event}`;
6952
+ return `${quoteIfSpaces(nodePath)} ${quoteIfSpaces(cliScriptPath)} hook ${event}`;
6907
6953
  }
6908
6954
  function upsertHook(settings, event, command) {
6909
6955
  settings.hooks ??= {};
@@ -6951,27 +6997,6 @@ function isCaveatClaudeHookCommand(actual, event) {
6951
6997
  const lower = actual.toLowerCase();
6952
6998
  return !isEnvPrefixedCommand(actual) && lower.includes("caveat") && actual.includes(`hook ${event}`);
6953
6999
  }
6954
- function commandTokens(command) {
6955
- const tokens = [];
6956
- const pattern = /"([^"]*)"|([^\s"]+)/g;
6957
- let end = 0;
6958
- let match;
6959
- while ((match = pattern.exec(command)) !== null) {
6960
- if (command.slice(end, match.index).trim()) return null;
6961
- tokens.push(match[1] ?? match[2]);
6962
- end = pattern.lastIndex;
6963
- }
6964
- return command.slice(end).trim() ? null : tokens;
6965
- }
6966
- function isCanonicalAsset(path, expectedPath, mode) {
6967
- if (typeof path !== "string" || !isAbsolute(path) || !isAbsolute(expectedPath)) return false;
6968
- try {
6969
- accessSync(path, mode);
6970
- return statSync(path).isFile() && realpathSync(path) === realpathSync(expectedPath);
6971
- } catch {
6972
- return false;
6973
- }
6974
- }
6975
7000
  function isCanonicalCaveatClaudeHookCommand(actual, event, nodePath, cliScriptPath) {
6976
7001
  const tokens = commandTokens(actual);
6977
7002
  return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath, constants.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants.R_OK) && tokens[2] === "hook" && tokens[3] === event;
@@ -6982,19 +7007,11 @@ function isCaveatClaudeMcpRegistration(value, nodePath, cliScriptPath) {
6982
7007
  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;
6983
7008
  }
6984
7009
  function readSettings(path) {
6985
- if (!existsSync(path)) return {};
7010
+ if (!existsSync2(path)) return {};
6986
7011
  return JSON.parse(readFileSync2(path, "utf-8"));
6987
7012
  }
6988
7013
  function writeSettings(path, settings) {
6989
- const dir = dirname2(path);
6990
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
6991
- let backupPath = "";
6992
- if (existsSync(path)) {
6993
- backupPath = `${path}.caveat-backup-${Date.now()}`;
6994
- copyFileSync(path, backupPath);
6995
- }
6996
- writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf-8");
6997
- return backupPath;
7014
+ return writeJsonWithBackup(path, settings);
6998
7015
  }
6999
7016
  var CLAUDE_BIN = "claude";
7000
7017
  function shellQuote(s) {
@@ -7112,51 +7129,36 @@ function uninstallClaudeIntegration(opts) {
7112
7129
  }
7113
7130
 
7114
7131
  // src/codexHookInstall.ts
7115
- 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";
7116
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4 } from "node:path";
7132
+ import { constants as constants2, existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
7133
+ import { join as join4 } from "node:path";
7117
7134
  import { parse as parseToml } from "smol-toml";
7118
- function quote2(p) {
7119
- return p.includes(" ") ? `"${p}"` : p;
7120
- }
7121
7135
  function hookCommand2(nodePath, cliScriptPath, event, platform = process.platform) {
7122
- const prefix = platform === "win32" ? "& " : "";
7123
- return `${prefix}${quote2(nodePath)} ${quote2(cliScriptPath)} codex-hook ${event}`;
7136
+ return `${powershellCallPrefix(platform)}${quoteIfSpaces(nodePath)} ${quoteIfSpaces(cliScriptPath)} codex-hook ${event}`;
7124
7137
  }
7125
7138
  function eventCommandFragment(event) {
7126
7139
  return `codex-hook ${event}`;
7127
7140
  }
7128
7141
  function isSameHookCommand2(actual, expected) {
7129
- return actual === expected || actual.endsWith(` ${expected}`);
7142
+ const normalizedTokens = (command) => {
7143
+ const parsed = commandTokens(command);
7144
+ return parsed?.[0] === "&" ? parsed.slice(1) : parsed;
7145
+ };
7146
+ const actualTokens = normalizedTokens(actual);
7147
+ const expectedTokens = normalizedTokens(expected);
7148
+ return actualTokens !== null && expectedTokens !== null && actualTokens.length === expectedTokens.length && actualTokens.every((token, index) => token === expectedTokens[index]);
7130
7149
  }
7131
7150
  function isCaveatCodexHookCommand(actual, event) {
7132
7151
  const lower = actual.toLowerCase();
7133
7152
  return lower.includes("caveat") && actual.includes(eventCommandFragment(event));
7134
7153
  }
7135
- function commandTokens2(command) {
7136
- const tokens = [];
7137
- const pattern = /"([^"]*)"|([^\s"]+)/g;
7138
- let end = 0;
7139
- let match;
7140
- while ((match = pattern.exec(command)) !== null) {
7141
- if (command.slice(end, match.index).trim()) return null;
7142
- tokens.push(match[1] ?? match[2]);
7143
- end = pattern.lastIndex;
7144
- }
7145
- return command.slice(end).trim() ? null : tokens;
7146
- }
7147
- function isCanonicalAsset2(path, expectedPath, mode) {
7148
- if (typeof path !== "string" || !isAbsolute2(path) || !isAbsolute2(expectedPath)) return false;
7149
- try {
7150
- accessSync2(path, mode);
7151
- return statSync2(path).isFile() && realpathSync2(path) === realpathSync2(expectedPath);
7152
- } catch {
7153
- return false;
7154
- }
7155
- }
7156
7154
  function isCanonicalCaveatCodexHookCommand(actual, event, nodePath, cliScriptPath) {
7157
- const parsed = commandTokens2(actual);
7155
+ const parsed = commandTokens(actual);
7158
7156
  const tokens = parsed?.[0] === "&" ? parsed.slice(1) : parsed;
7159
- 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;
7157
+ return tokens?.length === 4 && isCanonicalAsset(tokens[0], nodePath, constants2.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants2.R_OK) && tokens[2] === "codex-hook" && tokens[3] === event;
7158
+ }
7159
+ function isCanonicalCaveatCodexHookEntry(value, event, nodePath, cliScriptPath) {
7160
+ if (!isPlainRecord(value) || typeof value.type !== "string" || typeof value.command !== "string") return false;
7161
+ return value.type === "command" && isCanonicalCaveatCodexHookCommand(value.command, event, nodePath, cliScriptPath) && value.timeout === 5 && value.timeoutSec === void 0 && value.async === false && value.statusMessage === null;
7160
7162
  }
7161
7163
  function hasCaveatHook(hooksJson, event, fragment) {
7162
7164
  return hooksJson.hooks?.[event]?.some(
@@ -7164,30 +7166,20 @@ function hasCaveatHook(hooksJson, event, fragment) {
7164
7166
  ) ?? false;
7165
7167
  }
7166
7168
  function readHooks(path) {
7167
- if (!existsSync2(path)) return {};
7169
+ if (!existsSync3(path)) return {};
7168
7170
  return JSON.parse(readFileSync3(path, "utf-8"));
7169
7171
  }
7170
- function writeJsonWithBackup(path, value) {
7171
- const dir = dirname3(path);
7172
- if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
7173
- let backupPath = "";
7174
- if (existsSync2(path)) {
7175
- backupPath = `${path}.caveat-backup-${Date.now()}`;
7176
- copyFileSync2(path, backupPath);
7177
- }
7178
- writeFileSync2(path, `${JSON.stringify(value, null, 2)}
7179
- `, "utf-8");
7180
- return backupPath;
7181
- }
7182
7172
  function upsertHook2(hooksJson, event, command, subcommand) {
7183
7173
  hooksJson.hooks ??= {};
7184
7174
  const list = hooksJson.hooks[event] ??= [];
7185
7175
  for (const entry of list) {
7186
7176
  for (const hook2 of entry.hooks ?? []) {
7187
- if (isSameHookCommand2(hook2.command, command)) return "unchanged";
7188
- if (isCaveatCodexHookCommand(hook2.command, subcommand)) {
7177
+ if (isSameHookCommand2(hook2.command, command) && hook2.type === "command" && hook2.timeout === 5 && hook2.timeoutSec === void 0 && hook2.async === false && hook2.statusMessage === null) return "unchanged";
7178
+ if (isSameHookCommand2(hook2.command, command) || isCaveatCodexHookCommand(hook2.command, subcommand)) {
7189
7179
  hook2.command = command;
7190
- hook2.timeoutSec = 5;
7180
+ hook2.type = "command";
7181
+ hook2.timeout = 5;
7182
+ delete hook2.timeoutSec;
7191
7183
  hook2.async = false;
7192
7184
  hook2.statusMessage = null;
7193
7185
  return "added";
@@ -7199,7 +7191,7 @@ function upsertHook2(hooksJson, event, command, subcommand) {
7199
7191
  {
7200
7192
  type: "command",
7201
7193
  command,
7202
- timeoutSec: 5,
7194
+ timeout: 5,
7203
7195
  async: false,
7204
7196
  statusMessage: null
7205
7197
  }
@@ -7398,21 +7390,10 @@ function maskTomlStringsAndComments(raw) {
7398
7390
  }
7399
7391
  return output;
7400
7392
  }
7401
- function writeConfigWithBackup(path, text) {
7402
- const dir = dirname3(path);
7403
- if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
7404
- let backupPath = "";
7405
- if (existsSync2(path)) {
7406
- backupPath = `${path}.caveat-backup-${Date.now()}`;
7407
- copyFileSync2(path, backupPath);
7408
- }
7409
- writeFileSync2(path, text, "utf-8");
7410
- return backupPath;
7411
- }
7412
7393
  function installCodexHooks(opts) {
7413
7394
  const hooksPath = join4(opts.codexHome, "hooks.json");
7414
7395
  const configPath = join4(opts.codexHome, "config.toml");
7415
- const rawConfig = existsSync2(configPath) ? readFileSync3(configPath, "utf-8") : "";
7396
+ const rawConfig = existsSync3(configPath) ? readFileSync3(configPath, "utf-8") : "";
7416
7397
  const enabled = enableCodexHooksFeature(rawConfig);
7417
7398
  if (enabled.status === "blocked") {
7418
7399
  return {
@@ -7452,7 +7433,7 @@ function installCodexHooks(opts) {
7452
7433
  if (backup) backupPath = backup;
7453
7434
  }
7454
7435
  if (enabled.changed) {
7455
- const backup = writeConfigWithBackup(configPath, enabled.text);
7436
+ const backup = writeFileWithBackup(configPath, enabled.text);
7456
7437
  if (backup) configBackupPath = backup;
7457
7438
  }
7458
7439
  }
@@ -7513,11 +7494,19 @@ function detectCodexHookInstallation(codexHome) {
7513
7494
  postToolUse: hasCaveatHook(hooksJson, "PostToolUse", eventCommandFragment("post-tool-use")),
7514
7495
  stop: hasCaveatHook(hooksJson, "Stop", eventCommandFragment("stop"))
7515
7496
  };
7497
+ const hasLegacyTimeoutSec = (event, fragment) => hooksJson.hooks?.[event]?.some((entry) => entry.hooks?.some((hook2) => hook2.command.includes(fragment) && hook2.timeoutSec !== void 0)) ?? false;
7498
+ const legacyTimeoutSec = {
7499
+ userPromptSubmit: hasLegacyTimeoutSec("UserPromptSubmit", eventCommandFragment("user-prompt-submit")),
7500
+ postToolUse: hasLegacyTimeoutSec("PostToolUse", eventCommandFragment("post-tool-use")),
7501
+ stop: hasLegacyTimeoutSec("Stop", eventCommandFragment("stop"))
7502
+ };
7516
7503
  const count = Object.values(hooks).filter(Boolean).length;
7504
+ const hasLegacy = Object.values(legacyTimeoutSec).some(Boolean);
7517
7505
  return {
7518
- installation: count === 0 ? "not-installed" : count === 3 ? "installed" : "partial",
7506
+ installation: count === 0 ? "not-installed" : count === 3 && !hasLegacy ? "installed" : "partial",
7519
7507
  hooksPath,
7520
- hooks
7508
+ hooks,
7509
+ legacyTimeoutSec
7521
7510
  };
7522
7511
  }
7523
7512
 
@@ -7568,9 +7557,9 @@ function askOnce(question) {
7568
7557
  }
7569
7558
 
7570
7559
  // src/nodePath.ts
7571
- import { existsSync as existsSync3, realpathSync as realpathSync3 } from "node:fs";
7560
+ import { existsSync as existsSync4, realpathSync as realpathSync2 } from "node:fs";
7572
7561
  import { delimiter, join as join5 } from "node:path";
7573
- var defaultRealpath = (path) => realpathSync3.native(path);
7562
+ var defaultRealpath = (path) => realpathSync2.native(path);
7574
7563
  function safeRealpath(path, realpath = defaultRealpath) {
7575
7564
  try {
7576
7565
  return realpath(path);
@@ -7582,12 +7571,12 @@ function resolveHookNodePath({
7582
7571
  env = process.env,
7583
7572
  execPath = process.execPath,
7584
7573
  platform = process.platform,
7585
- exists = existsSync3,
7574
+ exists = existsSync4,
7586
7575
  realpath = defaultRealpath
7587
7576
  } = {}) {
7588
7577
  const execRealpath = safeRealpath(execPath, realpath);
7589
7578
  const pathEnv = env.PATH ?? env.Path ?? "";
7590
- const names = platform === "win32" ? ["node.exe", "node.cmd", "node.bat", "node"] : ["node"];
7579
+ const names = nodeExecutableNames(platform);
7591
7580
  for (const dir of pathEnv.split(delimiter).filter(Boolean)) {
7592
7581
  for (const name of names) {
7593
7582
  const candidate = join5(dir, name);
@@ -7602,12 +7591,12 @@ function resolveHookNodePath({
7602
7591
  }
7603
7592
 
7604
7593
  // src/commands/publish.ts
7605
- import { existsSync as existsSync4 } from "node:fs";
7594
+ import { existsSync as existsSync5 } from "node:fs";
7606
7595
  import { join as join7 } from "node:path";
7607
7596
 
7608
7597
  // src/commands/codexSidecarAdvisory.ts
7609
7598
  import { spawnSync as spawnSync3 } from "node:child_process";
7610
- import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
7599
+ import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
7611
7600
  import { tmpdir } from "node:os";
7612
7601
  import { join as join6 } from "node:path";
7613
7602
  var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
@@ -7670,7 +7659,7 @@ function runCodexSidecarAdvisory(input) {
7670
7659
  args.push("--save-result", resultFile);
7671
7660
  if (input.additionalContext) {
7672
7661
  const additionalContextFile = join6(resultDir, "hook-signal.json");
7673
- writeFileSync3(additionalContextFile, JSON.stringify({ context: [input.additionalContext] }) + "\n", { encoding: "utf-8", mode: 384, flag: "wx" });
7662
+ writeFileSync2(additionalContextFile, JSON.stringify({ context: [input.additionalContext] }) + "\n", { encoding: "utf-8", mode: 384, flag: "wx" });
7674
7663
  args.push("--additional-context-file", additionalContextFile);
7675
7664
  }
7676
7665
  const nodeCli = process.env.CAVEAT_CODEX_SIDECAR_NODE_CLI;
@@ -7765,7 +7754,7 @@ async function runPublish(ctx, opts, dependencies = {}) {
7765
7754
  const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
7766
7755
  const confirm = dependencies.confirm ?? askOnce;
7767
7756
  const projectRoot = process.cwd();
7768
- const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) => existsSync4(join7(root, ".codex-sidecar.yml")));
7757
+ const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) => existsSync5(join7(root, ".codex-sidecar.yml")));
7769
7758
  const publishAdvisory = hasCodexSidecarConfig(projectRoot) ? (changes) => {
7770
7759
  try {
7771
7760
  return dependencies.runCodexSidecarAdvisory?.(changes, projectRoot) ?? formatCodexSidecarAdvisory(runCodexSidecarAdvisory({
@@ -7824,22 +7813,22 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
7824
7813
  let codexHookState = "not-installed";
7825
7814
  ensureUserConfig(ctx.userConfigPath);
7826
7815
  ctx.logger.info(`user config: ${ctx.userConfigPath}`);
7827
- if (!existsSync5(ctx.paths.knowledgeRepo)) {
7828
- mkdirSync3(ctx.paths.knowledgeRepo, { recursive: true });
7829
- mkdirSync3(ctx.paths.entriesDir, { recursive: true });
7816
+ if (!existsSync6(ctx.paths.knowledgeRepo)) {
7817
+ mkdirSync2(ctx.paths.knowledgeRepo, { recursive: true });
7818
+ mkdirSync2(ctx.paths.entriesDir, { recursive: true });
7830
7819
  ctx.logger.info(`knowledge repo scaffolded: ${ctx.paths.knowledgeRepo}`);
7831
7820
  } else {
7832
7821
  ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
7833
7822
  }
7834
7823
  migrateLegacyCommunityDir(ctx);
7835
7824
  const gitignorePath = join8(ctx.paths.knowledgeRepo, ".gitignore");
7836
- if (!existsSync5(gitignorePath)) {
7837
- writeFileSync4(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
7825
+ if (!existsSync6(gitignorePath)) {
7826
+ writeFileSync3(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
7838
7827
  ctx.logger.info(`.gitignore created: ${gitignorePath}`);
7839
7828
  }
7840
7829
  if (!opts.dryRun) {
7841
- const dbDir = dirname4(ctx.paths.dbPath);
7842
- if (!existsSync5(dbDir)) mkdirSync3(dbDir, { recursive: true });
7830
+ const dbDir = dirname3(ctx.paths.dbPath);
7831
+ if (!existsSync6(dbDir)) mkdirSync2(dbDir, { recursive: true });
7843
7832
  const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
7844
7833
  const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
7845
7834
  for (const failure of failures) {
@@ -8017,7 +8006,7 @@ function reportEnvironmentSummary(ctx, publishTarget, codexHookState, dryRun) {
8017
8006
  const prefix = dryRun ? "[dry-run] would have " : "";
8018
8007
  const isRepo = gitOutput(["-C", ctx.paths.knowledgeRepo, "rev-parse", "--is-inside-work-tree"]) === "true";
8019
8008
  const remote = isRepo ? gitOutput(["-C", ctx.paths.knowledgeRepo, "config", "--get", "remote.origin.url"]) : null;
8020
- const communityCount = existsSync5(ctx.paths.communityDir) ? readdirSync(ctx.paths.communityDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
8009
+ const communityCount = existsSync6(ctx.paths.communityDir) ? readdirSync(ctx.paths.communityDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
8021
8010
  ctx.logger.info(`${prefix}environment summary:`);
8022
8011
  ctx.logger.info(` own git: ${isRepo ? "repository" : "not initialized"}`);
8023
8012
  ctx.logger.info(` private remote: ${remote || "not configured"}`);
@@ -8032,14 +8021,14 @@ function migrateLegacyCommunityDir(ctx) {
8032
8021
  const legacy = join8(ctx.paths.knowledgeRepo, "community");
8033
8022
  const current = ctx.paths.communityDir;
8034
8023
  if (legacy === current) return;
8035
- if (!existsSync5(legacy)) return;
8036
- if (existsSync5(current)) {
8024
+ if (!existsSync6(legacy)) return;
8025
+ if (existsSync6(current)) {
8037
8026
  ctx.logger.warn(
8038
8027
  `legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
8039
8028
  );
8040
8029
  return;
8041
8030
  }
8042
- mkdirSync3(current, { recursive: true });
8031
+ mkdirSync2(current, { recursive: true });
8043
8032
  for (const entry of readdirSync(legacy, { withFileTypes: true })) {
8044
8033
  if (!entry.isDirectory()) continue;
8045
8034
  renameSync(join8(legacy, entry.name), join8(current, entry.name));
@@ -8104,11 +8093,11 @@ function reportInstallResult(ctx, result, dryRun) {
8104
8093
  }
8105
8094
 
8106
8095
  // src/commands/indexCmd.ts
8107
- import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "node:fs";
8108
- import { dirname as dirname5 } from "node:path";
8096
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3 } from "node:fs";
8097
+ import { dirname as dirname4 } from "node:path";
8109
8098
  async function runIndex(ctx, opts) {
8110
- const dbDir = dirname5(ctx.paths.dbPath);
8111
- if (!existsSync6(dbDir)) mkdirSync4(dbDir, { recursive: true });
8099
+ const dbDir = dirname4(ctx.paths.dbPath);
8100
+ if (!existsSync7(dbDir)) mkdirSync3(dbDir, { recursive: true });
8112
8101
  const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
8113
8102
  const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
8114
8103
  for (const failure of failures) {
@@ -8292,7 +8281,7 @@ function runStats(ctx) {
8292
8281
 
8293
8282
  // src/commands/serve.ts
8294
8283
  async function runServe(opts) {
8295
- const { startServer } = await import("./server-FUWTRVRZ.js");
8284
+ const { startServer } = await import("./server-GBVHOF67.js");
8296
8285
  const { port, host } = startServer({ port: opts.port });
8297
8286
  process.stdout.write(`[caveat] web portal: http://${host}:${port}/
8298
8287
  `);
@@ -32532,12 +32521,12 @@ function handleListRecent(ctx, args) {
32532
32521
  }
32533
32522
 
32534
32523
  // ../mcp/dist/tools/pull.js
32535
- import { existsSync as existsSync7 } from "node:fs";
32524
+ import { existsSync as existsSync8 } from "node:fs";
32536
32525
  var pullInputShape = {};
32537
32526
  async function handlePull(ctx, _args = {}) {
32538
32527
  const pulled = [];
32539
32528
  const indexed = [];
32540
- if (existsSync7(ctx.paths.communityDir)) {
32529
+ if (existsSync8(ctx.paths.communityDir)) {
32541
32530
  const results = await communityPull({
32542
32531
  communityDir: ctx.paths.communityDir,
32543
32532
  logger: ctx.logger
@@ -32693,28 +32682,28 @@ async function runMcpServer() {
32693
32682
  import { spawn as spawn2 } from "node:child_process";
32694
32683
  import {
32695
32684
  chmodSync,
32696
- existsSync as existsSync9,
32685
+ existsSync as existsSync11,
32697
32686
  lstatSync,
32698
32687
  mkdtempSync as mkdtempSync2,
32699
32688
  mkdirSync as mkdirSync5,
32700
32689
  readdirSync as readdirSync2,
32701
- readFileSync as readFileSync5,
32702
- realpathSync as realpathSync4,
32690
+ readFileSync as readFileSync6,
32691
+ realpathSync as realpathSync3,
32703
32692
  rmSync as rmSync2,
32704
32693
  writeFileSync as writeFileSync5
32705
32694
  } from "node:fs";
32706
32695
  import { tmpdir as tmpdir2 } from "node:os";
32707
- import { basename, dirname as dirname6, join as join11 } from "node:path";
32708
- import { createHash, randomBytes } from "node:crypto";
32696
+ import { basename, dirname as dirname5, join as join12 } from "node:path";
32697
+ import { randomBytes } from "node:crypto";
32709
32698
 
32710
32699
  // src/autoReindexTrigger.ts
32711
32700
  import { spawn } from "node:child_process";
32712
- import { existsSync as existsSync8 } from "node:fs";
32701
+ import { existsSync as existsSync9 } from "node:fs";
32713
32702
  import { join as join10 } from "node:path";
32714
32703
  function maybeTriggerAutoReindex(ctx) {
32715
32704
  if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") return;
32716
- if (!existsSync8(ctx.paths.dbPath)) return;
32717
- if (existsSync8(join10(ctx.caveatHome, "index", ".reindex-lock"))) return;
32705
+ if (!existsSync9(ctx.paths.dbPath)) return;
32706
+ if (existsSync9(join10(ctx.caveatHome, "index", ".reindex-lock"))) return;
32718
32707
  const current = computeEntriesDigest(ctx.paths);
32719
32708
  const marker = readDigestMarker(ctx.caveatHome);
32720
32709
  if (marker?.digest === current.digest && marker.fileCount === current.fileCount) return;
@@ -32739,18 +32728,22 @@ function maybeTriggerAutoSync(ctx, debounceMs = AUTO_SYNC_DEBOUNCE_MS) {
32739
32728
  });
32740
32729
  }
32741
32730
 
32742
- // src/commands/hookCmd.ts
32743
- var silentLogger = {
32744
- info: () => {
32745
- },
32746
- warn: () => {
32747
- },
32748
- error: (m) => process.stderr.write(`[caveat:hook] ${m}
32731
+ // src/hookShared.ts
32732
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
32733
+ import { join as join11 } from "node:path";
32734
+ import { createHash } from "node:crypto";
32735
+ var MAX_CONTEXT_BLOCKS = 3;
32736
+ var STOP_REMINDER_PREFIX = "[caveat] \u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u5F53\u305F\u3063\u305F\u53EF\u80FD\u6027\u3092\u793A\u3059\u30B7\u30B0\u30CA\u30EB:";
32737
+ function hookSilentLogger(host) {
32738
+ return {
32739
+ info: () => {
32740
+ },
32741
+ warn: () => {
32742
+ },
32743
+ error: (m) => process.stderr.write(`[${host.stderrTag}] ${m}
32749
32744
  `)
32750
- };
32751
- var CLAUDE_MAX_CONTEXT_BLOCKS = 3;
32752
- var CLAUDE_STOP_REMINDER_PREFIX = "[caveat] \u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u5F53\u305F\u3063\u305F\u53EF\u80FD\u6027\u3092\u793A\u3059\u30B7\u30B0\u30CA\u30EB:";
32753
- var CLAUDE_STOP_STATE_DIR = "claude-stop-state";
32745
+ };
32746
+ }
32754
32747
  async function readStdin() {
32755
32748
  const chunks = [];
32756
32749
  for await (const chunk of process.stdin) {
@@ -32758,34 +32751,32 @@ async function readStdin() {
32758
32751
  }
32759
32752
  return Buffer.concat(chunks).toString("utf-8");
32760
32753
  }
32761
- function parsePayload(raw) {
32754
+ function errorMessage4(err) {
32755
+ return err instanceof Error ? err.message : String(err);
32756
+ }
32757
+ function reportHookError(host, phase, err) {
32758
+ observeRuntimeError(host.errorCode, { version: CAVEAT_VERSION });
32759
+ process.stderr.write(`[${host.stderrTag}] ${phase}: ${errorMessage4(err)}
32760
+ `);
32761
+ }
32762
+ function parsePayload(host, raw) {
32762
32763
  if (!raw) return {};
32763
32764
  try {
32764
32765
  return JSON.parse(raw);
32765
32766
  } catch (err) {
32766
- observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32767
- const msg = err instanceof Error ? err.message : String(err);
32768
- process.stderr.write(`[caveat:hook] json parse error: ${msg}
32769
- `);
32767
+ reportHookError(host, "json parse error", err);
32770
32768
  return {};
32771
32769
  }
32772
32770
  }
32773
- function getSessionId(payload) {
32774
- const v = payload.session_id ?? payload.sessionId;
32775
- return typeof v === "string" && v.length > 0 ? v : "_unknown";
32776
- }
32777
- function buildContextSafely() {
32771
+ function buildContextSafely(host) {
32778
32772
  try {
32779
- return buildContext(silentLogger);
32773
+ return buildContext(hookSilentLogger(host));
32780
32774
  } catch (err) {
32781
- observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32782
- const msg = err instanceof Error ? err.message : String(err);
32783
- process.stderr.write(`[caveat:hook] context error: ${msg}
32784
- `);
32775
+ reportHookError(host, "context error", err);
32785
32776
  return null;
32786
32777
  }
32787
32778
  }
32788
- function searchCaveatsSafely(input) {
32779
+ function searchCaveatsSafely(host, input) {
32789
32780
  const inputs = Array.isArray(input) ? input : [input];
32790
32781
  const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
32791
32782
  if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
@@ -32793,8 +32784,8 @@ function searchCaveatsSafely(input) {
32793
32784
  let caveatHome;
32794
32785
  let hits;
32795
32786
  try {
32796
- const ctx = buildContextSafely();
32797
- if (!ctx || !existsSync9(ctx.paths.dbPath)) return [];
32787
+ const ctx = buildContextSafely(host);
32788
+ if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
32798
32789
  caveatHome = ctx.caveatHome;
32799
32790
  db = openDb({ path: ctx.paths.dbPath });
32800
32791
  const searchOptions = {
@@ -32802,29 +32793,20 @@ function searchCaveatsSafely(input) {
32802
32793
  };
32803
32794
  hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
32804
32795
  } catch (err) {
32805
- observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32806
- const msg = err instanceof Error ? err.message : String(err);
32807
- process.stderr.write(`[caveat:hook] search error: ${msg}
32808
- `);
32796
+ reportHookError(host, "search error", err);
32809
32797
  return [];
32810
32798
  }
32811
32799
  if (hits.length > 0) {
32812
32800
  try {
32813
32801
  markHit(db, hits);
32814
32802
  } catch (err) {
32815
- observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32816
- const msg = err instanceof Error ? err.message : String(err);
32817
- process.stderr.write(`[caveat:hook] markHit error: ${msg}
32818
- `);
32803
+ reportHookError(host, "markHit error", err);
32819
32804
  }
32820
32805
  } else {
32821
32806
  try {
32822
- logHookQueryMiss({ caveatHome, agent: "claude", surface: inputs[0].surface, query: queryForLog });
32807
+ logHookQueryMiss({ caveatHome, agent: host.agent, surface: inputs[0].surface, query: queryForLog });
32823
32808
  } catch (err) {
32824
- observeRuntimeError("CAVEAT.CLAUDE_HOOK_FAILED", { version: CAVEAT_VERSION });
32825
- const msg = err instanceof Error ? err.message : String(err);
32826
- process.stderr.write(`[caveat:hook] query log error: ${msg}
32827
- `);
32809
+ reportHookError(host, "query log error", err);
32828
32810
  }
32829
32811
  }
32830
32812
  try {
@@ -32833,50 +32815,37 @@ function searchCaveatsSafely(input) {
32833
32815
  db?.close();
32834
32816
  }
32835
32817
  }
32836
- function loadSignalsSafely(path) {
32837
- try {
32838
- return readSessionSignals(path);
32839
- } catch (err) {
32840
- const msg = err instanceof Error ? err.message : String(err);
32841
- process.stderr.write(`[caveat:hook] transcript read error: ${msg}
32842
- `);
32843
- return null;
32844
- }
32845
- }
32846
- function systemReminderOutput(text) {
32847
- return `<system-reminder>${text.replace(/</g, "\u2039").replace(/>/g, "\u203A")}</system-reminder>`;
32818
+ function pendingCleanupFailureText(host) {
32819
+ return `[${host.stderrTag}] pending reminder cleanup failed`;
32848
32820
  }
32849
- function claudePendingCleanupFailureText() {
32850
- return "[caveat:hook] pending reminder cleanup failed";
32851
- }
32852
- function drainForSession(sessionId) {
32853
- const ctx = buildContextSafely();
32821
+ function drainForSession(host, sessionId) {
32822
+ const ctx = buildContextSafely(host);
32854
32823
  if (!ctx) return [];
32855
32824
  const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
32856
32825
  const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
32857
32826
  for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
32858
- process.stderr.write(`${claudePendingCleanupFailureText()}
32827
+ process.stderr.write(`${pendingCleanupFailureText(host)}
32859
32828
  `);
32860
32829
  }
32861
32830
  return [...local.reminders, ...global.reminders];
32862
32831
  }
32863
- function claudeContextDedupeKey(text) {
32864
- if (text.startsWith(CLAUDE_STOP_REMINDER_PREFIX)) return "claude-stop-reminder";
32832
+ function contextDedupeKey(host, text) {
32833
+ if (text.startsWith(STOP_REMINDER_PREFIX)) return host.stopDedupeKey;
32865
32834
  return text.trim();
32866
32835
  }
32867
- function compactClaudeContexts(contexts) {
32836
+ function compactContexts(host, contexts) {
32868
32837
  const selected = [];
32869
32838
  const seen = /* @__PURE__ */ new Set();
32870
32839
  for (let i = contexts.length - 1; i >= 0; i -= 1) {
32871
32840
  const text = contexts[i]?.trim();
32872
32841
  if (!text) continue;
32873
- const key = claudeContextDedupeKey(text);
32842
+ const key = contextDedupeKey(host, text);
32874
32843
  if (seen.has(key)) continue;
32875
32844
  seen.add(key);
32876
32845
  selected.push(text);
32877
32846
  }
32878
32847
  selected.reverse();
32879
- const limited = selected.slice(-CLAUDE_MAX_CONTEXT_BLOCKS);
32848
+ const limited = selected.slice(-MAX_CONTEXT_BLOCKS);
32880
32849
  const omitted = selected.length - limited.length;
32881
32850
  if (omitted > 0) {
32882
32851
  limited.push(
@@ -32885,7 +32854,7 @@ function compactClaudeContexts(contexts) {
32885
32854
  }
32886
32855
  return limited;
32887
32856
  }
32888
- function sanitizeClaudeStateId(raw) {
32857
+ function sanitizeStateId(raw) {
32889
32858
  const clean = raw.replace(/[^A-Za-z0-9_-]/g, "");
32890
32859
  return clean.length > 0 ? clean : "_unknown";
32891
32860
  }
@@ -32901,59 +32870,59 @@ function stopSignalKey(signals, related) {
32901
32870
  });
32902
32871
  return createHash("sha256").update(body).digest("hex");
32903
32872
  }
32904
- function stopStatePath(caveatHome, sessionId) {
32905
- return join11(caveatHome, CLAUDE_STOP_STATE_DIR, `${sanitizeClaudeStateId(sessionId)}.txt`);
32873
+ function stopStatePath(host, caveatHome, sessionId) {
32874
+ return join11(caveatHome, host.stopStateDir, `${sanitizeStateId(sessionId)}.txt`);
32906
32875
  }
32907
- function wasStopReminderQueued(caveatHome, sessionId, key) {
32908
- const path = stopStatePath(caveatHome, sessionId);
32876
+ function wasStopReminderQueued(host, caveatHome, sessionId, key) {
32877
+ const path = stopStatePath(host, caveatHome, sessionId);
32909
32878
  try {
32910
32879
  return readFileSync5(path, "utf-8") === key;
32911
32880
  } catch {
32912
32881
  return false;
32913
32882
  }
32914
32883
  }
32915
- function markStopReminderQueued(caveatHome, sessionId, key) {
32916
- const path = stopStatePath(caveatHome, sessionId);
32917
- mkdirSync5(join11(caveatHome, CLAUDE_STOP_STATE_DIR), { recursive: true });
32918
- writeFileSync5(path, key, "utf-8");
32884
+ function markStopReminderQueued(host, caveatHome, sessionId, key) {
32885
+ const path = stopStatePath(host, caveatHome, sessionId);
32886
+ mkdirSync4(join11(caveatHome, host.stopStateDir), { recursive: true });
32887
+ writeFileSync4(path, key, "utf-8");
32919
32888
  }
32920
- function queueStopForSession(sessionId, signals, related) {
32921
- const ctx = buildContextSafely();
32889
+ function queueStopForSession(host, sessionId, signals, related, buildText) {
32890
+ const ctx = buildContextSafely(host);
32922
32891
  if (!ctx) return;
32923
32892
  const key = stopSignalKey(signals, related);
32924
- if (wasStopReminderQueued(ctx.caveatHome, sessionId, key)) return;
32893
+ if (wasStopReminderQueued(host, ctx.caveatHome, sessionId, key)) return;
32925
32894
  let result;
32926
32895
  try {
32927
32896
  result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
32928
- agent: "claude",
32897
+ agent: host.agent,
32929
32898
  surface: "stop",
32930
32899
  refs: related,
32931
32900
  stopSignalDigest: key
32932
- }), () => buildStopReminder(signals, related));
32901
+ }), buildText);
32933
32902
  } catch {
32934
- process.stderr.write("[caveat:hook] pending reminder build or publish failed\n");
32903
+ process.stderr.write(`[${host.stderrTag}] pending reminder build or publish failed
32904
+ `);
32935
32905
  return;
32936
32906
  }
32937
32907
  if (!result.ran) return;
32938
32908
  try {
32939
- markStopReminderQueued(ctx.caveatHome, sessionId, key);
32909
+ markStopReminderQueued(host, ctx.caveatHome, sessionId, key);
32940
32910
  } catch (err) {
32941
- const msg = err instanceof Error ? err.message : String(err);
32942
- process.stderr.write(`[caveat:hook] pending reminder write error: ${msg}
32911
+ process.stderr.write(`[${host.stderrTag}] pending reminder write error: ${errorMessage4(err)}
32943
32912
  `);
32944
32913
  }
32945
32914
  }
32946
32915
  function extractToolResponseText(response) {
32947
32916
  if (typeof response === "string") return response;
32948
32917
  if (Array.isArray(response)) {
32949
- const parts = [];
32950
- for (const item of response) {
32951
- if (typeof item === "string") parts.push(item);
32952
- else if (item !== null && typeof item === "object" && typeof item.text === "string") {
32953
- parts.push(item.text);
32918
+ return response.map((item) => {
32919
+ if (typeof item === "string") return item;
32920
+ if (item !== null && typeof item === "object") {
32921
+ const text = item.text;
32922
+ return typeof text === "string" ? text : "";
32954
32923
  }
32955
- }
32956
- return parts.join(" ");
32924
+ return "";
32925
+ }).filter(Boolean).join(" ");
32957
32926
  }
32958
32927
  if (response !== null && typeof response === "object") {
32959
32928
  const r = response;
@@ -32966,6 +32935,32 @@ function extractToolResponseText(response) {
32966
32935
  }
32967
32936
  return "";
32968
32937
  }
32938
+
32939
+ // src/commands/hookCmd.ts
32940
+ var CLAUDE_HOST = {
32941
+ agent: "claude",
32942
+ stderrTag: "caveat:hook",
32943
+ errorCode: "CAVEAT.CLAUDE_HOOK_FAILED",
32944
+ stopStateDir: "claude-stop-state",
32945
+ stopDedupeKey: "claude-stop-reminder"
32946
+ };
32947
+ var silentLogger = hookSilentLogger(CLAUDE_HOST);
32948
+ function getSessionId(payload) {
32949
+ const v = payload.session_id ?? payload.sessionId;
32950
+ return typeof v === "string" && v.length > 0 ? v : "_unknown";
32951
+ }
32952
+ function loadSignalsSafely(path) {
32953
+ try {
32954
+ return readSessionSignals(path);
32955
+ } catch (err) {
32956
+ process.stderr.write(`[caveat:hook] transcript read error: ${errorMessage4(err)}
32957
+ `);
32958
+ return null;
32959
+ }
32960
+ }
32961
+ function systemReminderOutput(text) {
32962
+ return `<system-reminder>${text.replace(/</g, "\u2039").replace(/>/g, "\u203A")}</system-reminder>`;
32963
+ }
32969
32964
  function toolTopicText(payload) {
32970
32965
  const parts = [];
32971
32966
  const toolName = payload.tool_name ?? payload.toolName;
@@ -33000,15 +32995,14 @@ function spawnWorker(job) {
33000
32995
  try {
33001
32996
  root = workerRoot();
33002
32997
  sweepStaleWorkerDirs(Date.now(), root);
33003
- workDir = mkdtempSync2(join11(root, "job-"));
32998
+ workDir = mkdtempSync2(join12(root, "job-"));
33004
32999
  chmodSync(workDir, 448);
33005
- workFile = join11(workDir, `${randomBytes(4).toString("hex")}.json`);
33000
+ workFile = join12(workDir, `${randomBytes(4).toString("hex")}.json`);
33006
33001
  writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
33007
33002
  } catch (err) {
33008
- const msg = err instanceof Error ? err.message : String(err);
33009
- process.stderr.write(`[caveat:hook] worker writefile error: ${msg}
33003
+ process.stderr.write(`[caveat:hook] worker writefile error: ${errorMessage4(err)}
33010
33004
  `);
33011
- cleanupWorkerDir(workDir, workDir ? dirname6(workDir) : void 0);
33005
+ cleanupWorkerDir(workDir, workDir ? dirname5(workDir) : void 0);
33012
33006
  return;
33013
33007
  }
33014
33008
  const cliScript = process.argv[1];
@@ -33024,8 +33018,7 @@ function spawnWorker(job) {
33024
33018
  );
33025
33019
  child.unref();
33026
33020
  } catch (err) {
33027
- const msg = err instanceof Error ? err.message : String(err);
33028
- process.stderr.write(`[caveat:hook] worker spawn error: ${msg}
33021
+ process.stderr.write(`[caveat:hook] worker spawn error: ${errorMessage4(err)}
33029
33022
  `);
33030
33023
  try {
33031
33024
  cleanupWorkerDir(workDir, root);
@@ -33036,11 +33029,11 @@ function spawnWorker(job) {
33036
33029
  async function runWorker(workFile) {
33037
33030
  let raw;
33038
33031
  try {
33039
- raw = readFileSync5(workFile, "utf-8");
33032
+ raw = readFileSync6(workFile, "utf-8");
33040
33033
  } catch {
33041
33034
  process.exit(0);
33042
33035
  }
33043
- cleanupWorkerDir(dirname6(workFile), dirname6(dirname6(workFile)));
33036
+ cleanupWorkerDir(dirname5(workFile), dirname5(dirname5(workFile)));
33044
33037
  let job;
33045
33038
  try {
33046
33039
  job = JSON.parse(raw);
@@ -33048,13 +33041,13 @@ async function runWorker(workFile) {
33048
33041
  process.exit(0);
33049
33042
  }
33050
33043
  if (!job.failureText || !job.sessionId) process.exit(0);
33051
- const hits = searchCaveatsSafely({
33044
+ const hits = searchCaveatsSafely(CLAUDE_HOST, {
33052
33045
  topicText: job.topicText,
33053
33046
  failureText: job.failureText,
33054
33047
  surface: "tool_error"
33055
33048
  });
33056
33049
  if (hits.length === 0) process.exit(0);
33057
- const ctx = buildContextSafely();
33050
+ const ctx = buildContextSafely(CLAUDE_HOST);
33058
33051
  if (!ctx) process.exit(0);
33059
33052
  let result;
33060
33053
  try {
@@ -33081,11 +33074,11 @@ function isOwnedWorkerDir(path, root = workerRoot()) {
33081
33074
  try {
33082
33075
  const inputStat = lstatSync(path);
33083
33076
  if (inputStat.isSymbolicLink()) return false;
33084
- const tmpRoot = realpathSync4(root);
33085
- const resolved = realpathSync4(path);
33077
+ const tmpRoot = realpathSync3(root);
33078
+ const resolved = realpathSync3(path);
33086
33079
  const stat = lstatSync(resolved);
33087
33080
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
33088
- return dirname6(resolved) === tmpRoot && basename(resolved).startsWith("job-") && stat.isDirectory() && !stat.isSymbolicLink() && hasPrivateOwnership(stat, uid);
33081
+ return dirname5(resolved) === tmpRoot && basename(resolved).startsWith("job-") && stat.isDirectory() && !stat.isSymbolicLink() && hasPrivateOwnership(stat, uid);
33089
33082
  } catch {
33090
33083
  return false;
33091
33084
  }
@@ -33100,7 +33093,7 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
33100
33093
  }
33101
33094
  for (const entry of entries) {
33102
33095
  if (!entry.startsWith("job-")) continue;
33103
- const path = join11(root, entry);
33096
+ const path = join12(root, entry);
33104
33097
  try {
33105
33098
  if (!isOwnedWorkerDir(path, root)) continue;
33106
33099
  const stat = lstatSync(path);
@@ -33112,32 +33105,32 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
33112
33105
  }
33113
33106
  }
33114
33107
  function workerRoot(base = tmpdir2()) {
33115
- const root = join11(base, WORKER_ROOT);
33108
+ const root = join12(base, WORKER_ROOT);
33116
33109
  mkdirSync5(root, { recursive: true, mode: 448 });
33117
33110
  const stat = lstatSync(root);
33118
33111
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
33119
33112
  if (!stat.isDirectory() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) throw new Error("worker root is unsafe");
33120
- const marker = join11(root, WORKER_MARKER);
33113
+ const marker = join12(root, WORKER_MARKER);
33121
33114
  try {
33122
33115
  writeFileSync5(marker, "caveat-worker/v1\n", { mode: 384, flag: "wx" });
33123
33116
  } catch (error51) {
33124
33117
  if (!(error51 && typeof error51 === "object" && "code" in error51 && error51.code === "EEXIST")) throw error51;
33125
33118
  }
33126
33119
  const markerStat = lstatSync(marker);
33127
- if (!markerStat.isFile() || markerStat.isSymbolicLink() || !hasPrivateOwnership(markerStat, uid) || readFileSync5(marker, "utf-8") !== "caveat-worker/v1\n") throw new Error("worker root marker is invalid");
33120
+ if (!markerStat.isFile() || markerStat.isSymbolicLink() || !hasPrivateOwnership(markerStat, uid) || readFileSync6(marker, "utf-8") !== "caveat-worker/v1\n") throw new Error("worker root marker is invalid");
33128
33121
  return root;
33129
33122
  }
33130
33123
  function isStaleWorkerJobDir(path) {
33131
33124
  const entries = readdirSync2(path);
33132
33125
  if (entries.length !== 1 || !entries[0].endsWith(".json")) return false;
33133
- const file2 = join11(path, entries[0]);
33126
+ const file2 = join12(path, entries[0]);
33134
33127
  const stat = lstatSync(file2);
33135
33128
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
33136
33129
  if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
33137
- return isKnownStaleWorkerJob(JSON.parse(readFileSync5(file2, "utf-8")));
33130
+ return isKnownStaleWorkerJob(JSON.parse(readFileSync6(file2, "utf-8")));
33138
33131
  }
33139
33132
  function hasPrivateOwnership(stat, uid) {
33140
- return process.platform === "win32" || (stat.mode & 63) === 0 && (uid === void 0 || stat.uid === uid);
33133
+ return isPrivateOwnerStat(stat, uid);
33141
33134
  }
33142
33135
  function isWorkerJob(value) {
33143
33136
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
@@ -33156,23 +33149,19 @@ function isKnownStaleWorkerJob(value) {
33156
33149
  }
33157
33150
  function writeLastReindex(caveatHome, value) {
33158
33151
  try {
33159
- writeFileSync5(join11(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
33152
+ writeFileSync5(join12(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
33160
33153
  } catch (err) {
33161
- const msg = err instanceof Error ? err.message : String(err);
33162
- process.stderr.write(`[caveat:hook] reindex status write error: ${msg}
33154
+ process.stderr.write(`[caveat:hook] reindex status write error: ${errorMessage4(err)}
33163
33155
  `);
33164
33156
  }
33165
33157
  }
33166
- function errorMessage4(err) {
33167
- return err instanceof Error ? err.message : String(err);
33168
- }
33169
33158
  async function runReindexWorker() {
33170
33159
  if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") {
33171
33160
  process.stderr.write("[caveat:hook] auto reindex disabled by CAVEAT_INDEX_AUTOSYNC=off\n");
33172
33161
  return;
33173
33162
  }
33174
- const ctx = buildContextSafely();
33175
- if (!ctx || !existsSync9(ctx.paths.dbPath)) {
33163
+ const ctx = buildContextSafely(CLAUDE_HOST);
33164
+ if (!ctx || !existsSync11(ctx.paths.dbPath)) {
33176
33165
  process.stderr.write("[caveat:hook] auto reindex skipped: index database does not exist\n");
33177
33166
  return;
33178
33167
  }
@@ -33197,7 +33186,7 @@ async function runReindexWorker() {
33197
33186
  perSource: result.perSource
33198
33187
  });
33199
33188
  } catch (err) {
33200
- const msg = err instanceof Error ? err.message : String(err);
33189
+ const msg = errorMessage4(err);
33201
33190
  process.stderr.write(`[caveat:hook] reindex error: ${msg}
33202
33191
  `);
33203
33192
  writeLastReindex(ctx.caveatHome, {
@@ -33210,8 +33199,7 @@ async function runReindexWorker() {
33210
33199
  try {
33211
33200
  releaseReindexLock(lock);
33212
33201
  } catch (err) {
33213
- const msg = err instanceof Error ? err.message : String(err);
33214
- process.stderr.write(`[caveat:hook] reindex lock release error: ${msg}
33202
+ process.stderr.write(`[caveat:hook] reindex lock release error: ${errorMessage4(err)}
33215
33203
  `);
33216
33204
  }
33217
33205
  }
@@ -33221,7 +33209,7 @@ async function runAutoSyncWorker() {
33221
33209
  process.stderr.write("[caveat:hook] auto sync disabled by CAVEAT_AUTO_SYNC=off\n");
33222
33210
  return;
33223
33211
  }
33224
- const ctx = buildContextSafely();
33212
+ const ctx = buildContextSafely(CLAUDE_HOST);
33225
33213
  if (!ctx) return;
33226
33214
  try {
33227
33215
  await runAutoSync({
@@ -33240,7 +33228,7 @@ function buildToolErrorReminder(job, hits) {
33240
33228
  const mode = hookCodexSidecarMode();
33241
33229
  if (mode === "off") return base;
33242
33230
  const projectRoot = process.cwd();
33243
- const hasSidecarConfig = existsSync9(join11(projectRoot, ".codex-sidecar.yml"));
33231
+ const hasSidecarConfig = existsSync11(join12(projectRoot, ".codex-sidecar.yml"));
33244
33232
  if (mode === "auto" && !hasSidecarConfig) return base;
33245
33233
  const advisory = runCodexSidecarAdvisory({
33246
33234
  searchText: job.failureText,
@@ -33276,7 +33264,7 @@ function buildStopReminder(signals, related) {
33276
33264
  const mode = hookCodexSidecarMode();
33277
33265
  if (mode === "off") return base;
33278
33266
  const projectRoot = process.cwd();
33279
- const hasSidecarConfig = existsSync9(join11(projectRoot, ".codex-sidecar.yml"));
33267
+ const hasSidecarConfig = existsSync11(join12(projectRoot, ".codex-sidecar.yml"));
33280
33268
  if (mode === "auto" && !hasSidecarConfig) return base;
33281
33269
  const advisory = runCodexSidecarAdvisory({
33282
33270
  searchText: struggleSearchText(signals),
@@ -33333,21 +33321,20 @@ async function runHook(name, arg) {
33333
33321
  try {
33334
33322
  raw = await readStdin();
33335
33323
  } catch (err) {
33336
- const msg = err instanceof Error ? err.message : String(err);
33337
- process.stderr.write(`[caveat:hook] stdin read error: ${msg}
33324
+ process.stderr.write(`[caveat:hook] stdin read error: ${errorMessage4(err)}
33338
33325
  `);
33339
33326
  process.exit(0);
33340
33327
  }
33341
- const payload = parsePayload(raw);
33328
+ const payload = parsePayload(CLAUDE_HOST, raw);
33342
33329
  const sessionId = getSessionId(payload);
33343
- const contexts = name === "stop" ? [] : drainForSession(sessionId);
33330
+ const contexts = name === "stop" ? [] : drainForSession(CLAUDE_HOST, sessionId);
33344
33331
  if (name === "user-prompt-submit") {
33345
33332
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
33346
- const hits = searchCaveatsSafely({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
33333
+ const hits = searchCaveatsSafely(CLAUDE_HOST, { topicText: prompt, failureText: prompt, surface: "user_prompt" });
33347
33334
  if (hits.length > 0) {
33348
33335
  contexts.push(userPromptSubmitReminderText(hits));
33349
33336
  }
33350
- const compacted = compactClaudeContexts(contexts);
33337
+ const compacted = compactContexts(CLAUDE_HOST, contexts);
33351
33338
  if (compacted.length > 0) {
33352
33339
  process.stdout.write(`${systemReminderOutput(compacted.join("\n\n"))}
33353
33340
  `);
@@ -33355,7 +33342,7 @@ async function runHook(name, arg) {
33355
33342
  process.exit(0);
33356
33343
  }
33357
33344
  if (name === "post-tool-use") {
33358
- const compacted = compactClaudeContexts(contexts);
33345
+ const compacted = compactContexts(CLAUDE_HOST, contexts);
33359
33346
  if (compacted.length > 0) {
33360
33347
  process.stdout.write(`${systemReminderOutput(compacted.join("\n\n"))}
33361
33348
  `);
@@ -33377,27 +33364,24 @@ async function runHook(name, arg) {
33377
33364
  process.exit(0);
33378
33365
  }
33379
33366
  if (name === "stop") {
33380
- const ctx = buildContextSafely();
33367
+ const ctx = buildContextSafely(CLAUDE_HOST);
33381
33368
  if (ctx) {
33382
33369
  try {
33383
33370
  maybeSweepPendingDirs(ctx.caveatHome);
33384
33371
  } catch (err) {
33385
- const msg = err instanceof Error ? err.message : String(err);
33386
- process.stderr.write(`[caveat:hook] pending sweep error: ${msg}
33372
+ process.stderr.write(`[caveat:hook] pending sweep error: ${errorMessage4(err)}
33387
33373
  `);
33388
33374
  }
33389
33375
  try {
33390
33376
  maybeTriggerAutoReindex(ctx);
33391
33377
  } catch (err) {
33392
- const msg = err instanceof Error ? err.message : String(err);
33393
- process.stderr.write(`[caveat:hook] auto reindex trigger error: ${msg}
33378
+ process.stderr.write(`[caveat:hook] auto reindex trigger error: ${errorMessage4(err)}
33394
33379
  `);
33395
33380
  }
33396
33381
  try {
33397
33382
  maybeTriggerAutoSync(ctx);
33398
33383
  } catch (err) {
33399
- const msg = err instanceof Error ? err.message : String(err);
33400
- process.stderr.write(`[caveat:hook] auto sync trigger error: ${msg}
33384
+ process.stderr.write(`[caveat:hook] auto sync trigger error: ${errorMessage4(err)}
33401
33385
  `);
33402
33386
  }
33403
33387
  }
@@ -33405,12 +33389,12 @@ async function runHook(name, arg) {
33405
33389
  const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
33406
33390
  const signals = transcriptPath ? loadSignalsSafely(transcriptPath) : null;
33407
33391
  if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
33408
- const related = searchCaveatsSafely(signals.errorSnippets.map((failureText) => ({
33392
+ const related = searchCaveatsSafely(CLAUDE_HOST, signals.errorSnippets.map((failureText) => ({
33409
33393
  topicText: "",
33410
33394
  failureText,
33411
33395
  surface: "stop"
33412
33396
  })));
33413
- queueStopForSession(sessionId, signals, related);
33397
+ queueStopForSession(CLAUDE_HOST, sessionId, signals, related, () => buildStopReminder(signals, related));
33414
33398
  process.exit(0);
33415
33399
  }
33416
33400
  process.stderr.write(`[caveat:hook] unknown hook name: ${name}
@@ -33420,105 +33404,22 @@ async function runHook(name, arg) {
33420
33404
 
33421
33405
  // src/commands/codexHookCmd.ts
33422
33406
  import { spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
33423
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
33407
+ import { existsSync as existsSync12, readFileSync as readFileSync7, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
33424
33408
  import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
33425
- import { join as join12 } from "node:path";
33426
- import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
33427
- var silentLogger2 = {
33428
- info: () => {
33429
- },
33430
- warn: () => {
33431
- },
33432
- error: (m) => process.stderr.write(`[caveat:codex-hook] ${m}
33433
- `)
33409
+ import { join as join13 } from "node:path";
33410
+ import { randomBytes as randomBytes2 } from "node:crypto";
33411
+ var CODEX_HOST = {
33412
+ agent: "codex",
33413
+ stderrTag: "caveat:codex-hook",
33414
+ errorCode: "CAVEAT.CODEX_HOOK_FAILED",
33415
+ stopStateDir: "codex-stop-state",
33416
+ stopDedupeKey: "codex-stop-reminder"
33434
33417
  };
33435
- var CODEX_MAX_CONTEXT_BLOCKS = 3;
33436
- var CODEX_STOP_REMINDER_PREFIX = "[caveat] \u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u5F53\u305F\u3063\u305F\u53EF\u80FD\u6027\u3092\u793A\u3059\u30B7\u30B0\u30CA\u30EB:";
33437
- var CODEX_STOP_STATE_DIR = "codex-stop-state";
33438
- async function readStdin2() {
33439
- const chunks = [];
33440
- for await (const chunk of process.stdin) {
33441
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
33442
- }
33443
- return Buffer.concat(chunks).toString("utf-8");
33444
- }
33445
- function parsePayload2(raw) {
33446
- if (!raw) return {};
33447
- try {
33448
- return JSON.parse(raw);
33449
- } catch (err) {
33450
- observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33451
- const msg = err instanceof Error ? err.message : String(err);
33452
- process.stderr.write(`[caveat:codex-hook] json parse error: ${msg}
33453
- `);
33454
- return {};
33455
- }
33456
- }
33457
- function buildContextSafely2() {
33458
- try {
33459
- return buildContext(silentLogger2);
33460
- } catch (err) {
33461
- observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33462
- const msg = err instanceof Error ? err.message : String(err);
33463
- process.stderr.write(`[caveat:codex-hook] context error: ${msg}
33464
- `);
33465
- return null;
33466
- }
33467
- }
33468
- function searchCaveatsSafely2(input) {
33469
- const inputs = Array.isArray(input) ? input : [input];
33470
- const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
33471
- if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
33472
- let db;
33473
- let caveatHome;
33474
- let hits;
33475
- try {
33476
- const ctx = buildContextSafely2();
33477
- if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
33478
- caveatHome = ctx.caveatHome;
33479
- db = openDb({ path: ctx.paths.dbPath });
33480
- const searchOptions = {
33481
- selfIdentity: defaultSelfIdentityTokens()
33482
- };
33483
- hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
33484
- } catch (err) {
33485
- observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33486
- const msg = err instanceof Error ? err.message : String(err);
33487
- process.stderr.write(`[caveat:codex-hook] search error: ${msg}
33488
- `);
33489
- return [];
33490
- }
33491
- if (hits.length > 0) {
33492
- try {
33493
- markHit(db, hits);
33494
- } catch (err) {
33495
- observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33496
- const msg = err instanceof Error ? err.message : String(err);
33497
- process.stderr.write(`[caveat:codex-hook] markHit error: ${msg}
33498
- `);
33499
- }
33500
- } else {
33501
- try {
33502
- logHookQueryMiss({ caveatHome, agent: "codex", surface: inputs[0].surface, query: queryForLog });
33503
- } catch (err) {
33504
- observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
33505
- const msg = err instanceof Error ? err.message : String(err);
33506
- process.stderr.write(`[caveat:codex-hook] query log error: ${msg}
33507
- `);
33508
- }
33509
- }
33510
- try {
33511
- return hits;
33512
- } finally {
33513
- db?.close();
33514
- }
33515
- }
33516
33418
  function loadSignalsSafely2(path) {
33517
33419
  try {
33518
33420
  return readCodexSessionSignals(path);
33519
33421
  } catch (err) {
33520
- const msg = err instanceof Error ? err.message : String(err);
33521
- process.stderr.write(`[caveat:codex-hook] transcript read error: ${msg}
33422
+ process.stderr.write(`[caveat:codex-hook] transcript read error: ${errorMessage4(err)}
33522
33423
  `);
33523
33424
  return null;
33524
33425
  }
@@ -33527,29 +33428,6 @@ function codexSessionId(payload) {
33527
33428
  const v = payload.session_id ?? payload.sessionId;
33528
33429
  return typeof v === "string" && v.length > 0 ? v : null;
33529
33430
  }
33530
- function extractToolResponseText2(response) {
33531
- if (typeof response === "string") return response;
33532
- if (Array.isArray(response)) {
33533
- return response.map((item) => {
33534
- if (typeof item === "string") return item;
33535
- if (item !== null && typeof item === "object") {
33536
- const text = item.text;
33537
- return typeof text === "string" ? text : "";
33538
- }
33539
- return "";
33540
- }).filter(Boolean).join(" ");
33541
- }
33542
- if (response !== null && typeof response === "object") {
33543
- const r = response;
33544
- if (typeof r.content === "string") return r.content;
33545
- if (Array.isArray(r.content)) return extractToolResponseText2(r.content);
33546
- if (typeof r.output === "string") return r.output;
33547
- if (typeof r.stdout === "string" || typeof r.stderr === "string") {
33548
- return [r.stdout, r.stderr].filter((x) => typeof x === "string").join(" ");
33549
- }
33550
- }
33551
- return "";
33552
- }
33553
33431
  function numericExitCode(v) {
33554
33432
  return typeof v === "number" && Number.isInteger(v) ? v : null;
33555
33433
  }
@@ -33558,10 +33436,10 @@ function processExitCodeFromText(text) {
33558
33436
  return m ? Number(m[1]) : null;
33559
33437
  }
33560
33438
  function transcriptToolOutput(transcriptPath, toolUseId) {
33561
- if (!transcriptPath || !toolUseId || !existsSync10(transcriptPath)) return null;
33439
+ if (!transcriptPath || !toolUseId || !existsSync12(transcriptPath)) return null;
33562
33440
  let raw = "";
33563
33441
  try {
33564
- raw = readFileSync6(transcriptPath, "utf-8");
33442
+ raw = readFileSync7(transcriptPath, "utf-8");
33565
33443
  } catch {
33566
33444
  return null;
33567
33445
  }
@@ -33615,7 +33493,7 @@ function isCodexToolError(payload) {
33615
33493
  const exit2 = numericExitCode(r.exit_code ?? r.exitCode);
33616
33494
  if (exit2 !== null) return exit2 !== 0;
33617
33495
  }
33618
- const responseExit = processExitCodeFromText(extractToolResponseText2(resp));
33496
+ const responseExit = processExitCodeFromText(extractToolResponseText(resp));
33619
33497
  if (responseExit !== null) return responseExit !== 0;
33620
33498
  const transcriptExit = transcriptExitCode(payload);
33621
33499
  if (transcriptExit !== null) return transcriptExit !== 0;
@@ -33626,7 +33504,7 @@ function buildCodexPostToolUseWorkerJob(payload) {
33626
33504
  if (!sessionId) return null;
33627
33505
  const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : void 0;
33628
33506
  const toolUseId = typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0;
33629
- const responseText = extractToolResponseText2(payload.tool_response ?? payload.toolResponse);
33507
+ const responseText = extractToolResponseText(payload.tool_response ?? payload.toolResponse);
33630
33508
  const inputText = toolInputText(payload.tool_input);
33631
33509
  const transcriptOutput = transcriptPath && toolUseId ? transcriptToolOutput(transcriptPath, toolUseId) : null;
33632
33510
  const topicText = inputText.trim();
@@ -33656,101 +33534,6 @@ function codexContextOutput(text, eventName = "UserPromptSubmit") {
33656
33534
  }
33657
33535
  });
33658
33536
  }
33659
- function codexPendingCleanupFailureText() {
33660
- return "[caveat:codex-hook] pending reminder cleanup failed";
33661
- }
33662
- function drainForSession2(sessionId) {
33663
- const ctx = buildContextSafely2();
33664
- if (!ctx) return [];
33665
- const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
33666
- const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
33667
- for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
33668
- process.stderr.write(`${codexPendingCleanupFailureText()}
33669
- `);
33670
- }
33671
- return [...local.reminders, ...global.reminders];
33672
- }
33673
- function codexContextDedupeKey(text) {
33674
- if (text.startsWith(CODEX_STOP_REMINDER_PREFIX)) return "codex-stop-reminder";
33675
- return text.trim();
33676
- }
33677
- function compactCodexContexts(contexts) {
33678
- const selected = [];
33679
- const seen = /* @__PURE__ */ new Set();
33680
- for (let i = contexts.length - 1; i >= 0; i -= 1) {
33681
- const text = contexts[i]?.trim();
33682
- if (!text) continue;
33683
- const key = codexContextDedupeKey(text);
33684
- if (seen.has(key)) continue;
33685
- seen.add(key);
33686
- selected.push(text);
33687
- }
33688
- selected.reverse();
33689
- const limited = selected.slice(-CODEX_MAX_CONTEXT_BLOCKS);
33690
- const omitted = selected.length - limited.length;
33691
- if (omitted > 0) {
33692
- 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`);
33693
- }
33694
- return limited;
33695
- }
33696
- function sanitizeCodexStateId(raw) {
33697
- const clean = raw.replace(/[^A-Za-z0-9_-]/g, "");
33698
- return clean.length > 0 ? clean : "_unknown";
33699
- }
33700
- function stopSignalKey2(signals, related) {
33701
- const body = JSON.stringify({
33702
- toolFailureCount: signals.toolFailureCount,
33703
- fileEditCounts: signals.fileEditCounts.map((e) => [e.path, e.count]),
33704
- webSearchCount: signals.webSearchCount,
33705
- webFetchCount: signals.webFetchCount,
33706
- bashRetryCount: signals.bashRetryCount,
33707
- searchQueries: signals.searchQueries,
33708
- related: related.map((h) => [h.source, h.id])
33709
- });
33710
- return createHash2("sha256").update(body).digest("hex");
33711
- }
33712
- function stopStatePath2(caveatHome, sessionId) {
33713
- return join12(caveatHome, CODEX_STOP_STATE_DIR, `${sanitizeCodexStateId(sessionId)}.txt`);
33714
- }
33715
- function wasStopReminderQueued2(caveatHome, sessionId, key) {
33716
- const path = stopStatePath2(caveatHome, sessionId);
33717
- try {
33718
- return readFileSync6(path, "utf-8") === key;
33719
- } catch {
33720
- return false;
33721
- }
33722
- }
33723
- function markStopReminderQueued2(caveatHome, sessionId, key) {
33724
- const path = stopStatePath2(caveatHome, sessionId);
33725
- mkdirSync6(join12(caveatHome, CODEX_STOP_STATE_DIR), { recursive: true });
33726
- writeFileSync6(path, key, "utf-8");
33727
- }
33728
- function queueStopForSession2(sessionId, signals, related) {
33729
- const ctx = buildContextSafely2();
33730
- if (!ctx) return;
33731
- const key = stopSignalKey2(signals, related);
33732
- if (wasStopReminderQueued2(ctx.caveatHome, sessionId, key)) return;
33733
- let result;
33734
- try {
33735
- result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
33736
- agent: "codex",
33737
- surface: "stop",
33738
- refs: related,
33739
- stopSignalDigest: key
33740
- }), () => stopReminderText(signals, related));
33741
- } catch {
33742
- process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
33743
- return;
33744
- }
33745
- if (!result.ran) return;
33746
- try {
33747
- markStopReminderQueued2(ctx.caveatHome, sessionId, key);
33748
- } catch (err) {
33749
- const msg = err instanceof Error ? err.message : String(err);
33750
- process.stderr.write(`[caveat:codex-hook] pending reminder write error: ${msg}
33751
- `);
33752
- }
33753
- }
33754
33537
  async function waitForTranscriptOutput(transcriptPath, toolUseId) {
33755
33538
  const deadline = Date.now() + 2e3;
33756
33539
  while (Date.now() <= deadline) {
@@ -33776,13 +33559,13 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
33776
33559
  }
33777
33560
  }
33778
33561
  if (!knownError && job.allowSymptomOnly !== true) return;
33779
- const hits = searchCaveatsSafely2({
33562
+ const hits = searchCaveatsSafely(CODEX_HOST, {
33780
33563
  topicText: job.topicText,
33781
33564
  failureText,
33782
33565
  surface: "tool_error"
33783
33566
  });
33784
33567
  if (hits.length === 0) return;
33785
- const ctx = buildContextSafely2();
33568
+ const ctx = buildContextSafely(CODEX_HOST);
33786
33569
  if (!ctx) return;
33787
33570
  let result;
33788
33571
  try {
@@ -33800,7 +33583,7 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
33800
33583
  async function runCodexWorker(workFile) {
33801
33584
  let raw;
33802
33585
  try {
33803
- raw = readFileSync6(workFile, "utf-8");
33586
+ raw = readFileSync7(workFile, "utf-8");
33804
33587
  } catch {
33805
33588
  process.exit(0);
33806
33589
  }
@@ -33817,7 +33600,7 @@ async function runCodexWorker(workFile) {
33817
33600
  await processCodexWorkerJob(job);
33818
33601
  process.exit(0);
33819
33602
  }
33820
- function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join12(homedir3(), ".codex")) {
33603
+ function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join13(homedir3(), ".codex")) {
33821
33604
  const features = spawnSync5("codex", ["features", "list"], {
33822
33605
  encoding: "utf-8",
33823
33606
  maxBuffer: 1024 * 1024,
@@ -33834,6 +33617,7 @@ function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join12(homedir3(),
33834
33617
  codexHome,
33835
33618
  hooksPath: installation.hooksPath,
33836
33619
  installedHooks: installation.hooks,
33620
+ legacyTimeoutSec: installation.legacyTimeoutSec,
33837
33621
  evidence: featureOutput.split("\n").find((line) => line.trim().startsWith("hooks")) ?? null
33838
33622
  };
33839
33623
  process.stdout.write(`${JSON.stringify(result, null, 2)}
@@ -33854,24 +33638,23 @@ async function runCodexHook(name, arg) {
33854
33638
  }
33855
33639
  let raw = "";
33856
33640
  try {
33857
- raw = await readStdin2();
33641
+ raw = await readStdin();
33858
33642
  } catch (err) {
33859
- const msg = err instanceof Error ? err.message : String(err);
33860
- process.stderr.write(`[caveat:codex-hook] stdin read error: ${msg}
33643
+ process.stderr.write(`[caveat:codex-hook] stdin read error: ${errorMessage4(err)}
33861
33644
  `);
33862
33645
  process.exit(0);
33863
33646
  }
33864
- const payload = parsePayload2(raw);
33647
+ const payload = parsePayload(CODEX_HOST, raw);
33865
33648
  const sessionId = codexSessionId(payload);
33866
33649
  if (!sessionId) process.stderr.write("[caveat:codex-hook] missing session_id; pending drain disabled\n");
33867
33650
  if (name === "user-prompt-submit") {
33868
- const contexts = sessionId ? drainForSession2(sessionId) : [];
33651
+ const contexts = sessionId ? drainForSession(CODEX_HOST, sessionId) : [];
33869
33652
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
33870
- const hits = searchCaveatsSafely2({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
33653
+ const hits = searchCaveatsSafely(CODEX_HOST, { topicText: prompt, failureText: prompt, surface: "user_prompt" });
33871
33654
  if (hits.length > 0) {
33872
33655
  contexts.push(userPromptSubmitReminderText(hits));
33873
33656
  }
33874
- const compacted = compactCodexContexts(contexts);
33657
+ const compacted = compactContexts(CODEX_HOST, contexts);
33875
33658
  if (compacted.length > 0) {
33876
33659
  process.stdout.write(`${codexContextOutput(compacted.join("\n\n"))}
33877
33660
  `);
@@ -33885,39 +33668,36 @@ async function runCodexHook(name, arg) {
33885
33668
  }
33886
33669
  if (name === "stop") {
33887
33670
  try {
33888
- const ctx = buildContextSafely2();
33671
+ const ctx = buildContextSafely(CODEX_HOST);
33889
33672
  if (ctx) {
33890
33673
  try {
33891
33674
  maybeSweepPendingDirs(ctx.caveatHome);
33892
33675
  } catch (err) {
33893
- const msg = err instanceof Error ? err.message : String(err);
33894
- process.stderr.write(`[caveat:codex-hook] pending sweep error: ${msg}
33676
+ process.stderr.write(`[caveat:codex-hook] pending sweep error: ${errorMessage4(err)}
33895
33677
  `);
33896
33678
  }
33897
33679
  maybeTriggerAutoReindex(ctx);
33898
33680
  try {
33899
33681
  maybeTriggerAutoSync(ctx);
33900
33682
  } catch (err) {
33901
- const msg = err instanceof Error ? err.message : String(err);
33902
- process.stderr.write(`[caveat:codex-hook] auto sync trigger error: ${msg}
33683
+ process.stderr.write(`[caveat:codex-hook] auto sync trigger error: ${errorMessage4(err)}
33903
33684
  `);
33904
33685
  }
33905
33686
  }
33906
33687
  } catch (err) {
33907
- const msg = err instanceof Error ? err.message : String(err);
33908
- process.stderr.write(`[caveat:codex-hook] auto reindex trigger error: ${msg}
33688
+ process.stderr.write(`[caveat:codex-hook] auto reindex trigger error: ${errorMessage4(err)}
33909
33689
  `);
33910
33690
  }
33911
33691
  if (payload.stop_hook_active === true) process.exit(0);
33912
33692
  const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
33913
33693
  const signals = transcriptPath ? loadSignalsSafely2(transcriptPath) : null;
33914
33694
  if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
33915
- const related = searchCaveatsSafely2(signals.errorSnippets.map((failureText) => ({
33695
+ const related = searchCaveatsSafely(CODEX_HOST, signals.errorSnippets.map((failureText) => ({
33916
33696
  topicText: "",
33917
33697
  failureText,
33918
33698
  surface: "stop"
33919
33699
  })));
33920
- if (sessionId) queueStopForSession2(sessionId, signals, related);
33700
+ if (sessionId) queueStopForSession(CODEX_HOST, sessionId, signals, related, () => stopReminderText(signals, related));
33921
33701
  process.exit(0);
33922
33702
  }
33923
33703
  process.stderr.write(`[caveat:codex-hook] unknown hook name: ${name}
@@ -33926,9 +33706,9 @@ async function runCodexHook(name, arg) {
33926
33706
  }
33927
33707
 
33928
33708
  // src/commands/pull.ts
33929
- import { existsSync as existsSync11 } from "node:fs";
33709
+ import { existsSync as existsSync13 } from "node:fs";
33930
33710
  async function runPull(ctx) {
33931
- const hasCommunityDir = existsSync11(ctx.paths.communityDir);
33711
+ const hasCommunityDir = existsSync13(ctx.paths.communityDir);
33932
33712
  if (!hasCommunityDir) {
33933
33713
  ctx.logger.info(
33934
33714
  "no community repos yet \u2014 add one with `caveat community add <github-url>`."
@@ -34028,9 +33808,9 @@ async function runSync(ctx, opts, dependencies = {}) {
34028
33808
 
34029
33809
  // src/commands/codexSidecar.ts
34030
33810
  import { spawnSync as spawnSync6 } from "node:child_process";
34031
- 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";
33811
+ import { closeSync, constants as constants3, fstatSync, lstatSync as lstatSync2, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync3, openSync, readSync as readSync2, realpathSync as realpathSync4, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
34032
33812
  import { tmpdir as tmpdir4 } from "node:os";
34033
- import { basename as basename2, dirname as dirname7, join as join13 } from "node:path";
33813
+ import { basename as basename2, dirname as dirname6, join as join14 } from "node:path";
34034
33814
  import { cwd, exit } from "node:process";
34035
33815
  function runCodexSidecarDiagnostics(logger, opts) {
34036
33816
  const plan = buildCodexSidecarDiagnosticsCommand({
@@ -34062,8 +33842,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
34062
33842
  process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
34063
33843
  exit(0);
34064
33844
  }
34065
- const contextDir = mkdtempSync3(join13(tmpdir4(), "caveat-sidecar-context-"));
34066
- const contextFile = join13(contextDir, "context.json");
33845
+ const contextDir = mkdtempSync3(join14(tmpdir4(), "caveat-sidecar-context-"));
33846
+ const contextFile = join14(contextDir, "context.json");
34067
33847
  let status2 = 1;
34068
33848
  try {
34069
33849
  const blocks = collectCaveatContextBlocks(ctx, {
@@ -34128,16 +33908,16 @@ function readHookSignalAdditionalContextFile(path, testProbe) {
34128
33908
  return [block];
34129
33909
  }
34130
33910
  function assertPrivateRegular(stat, uid, platform) {
34131
- const privateOwner = platform === "win32" || (stat.mode & 63) === 0 && (uid === void 0 || stat.uid === uid);
33911
+ const privateOwner = isPrivateOwnerStat(stat, uid, platform);
34132
33912
  if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_ADDITIONAL_CONTEXT_BYTES || !privateOwner) throw new Error("additional context file must be a private owner-only regular file within 4096 bytes");
34133
33913
  }
34134
33914
  function assertWindowsPrivateTempContainer(path, platform) {
34135
- if (platform !== "win32") return;
34136
- const parent = dirname7(path);
33915
+ if (!isWindows(platform)) return;
33916
+ const parent = dirname6(path);
34137
33917
  const parentStat = lstatSync2(parent);
34138
- const resolvedParent = realpathSync5(parent);
34139
- const resolvedTemp = realpathSync5(tmpdir4());
34140
- if (parentStat.isSymbolicLink() || !parentStat.isDirectory() || dirname7(resolvedParent) !== resolvedTemp || !basename2(resolvedParent).startsWith("caveat-")) {
33918
+ const resolvedParent = realpathSync4(parent);
33919
+ const resolvedTemp = realpathSync4(tmpdir4());
33920
+ if (parentStat.isSymbolicLink() || !parentStat.isDirectory() || dirname6(resolvedParent) !== resolvedTemp || !basename2(resolvedParent).startsWith("caveat-")) {
34141
33921
  throw new Error("additional context file must be inside a reserved per-user Caveat temporary directory");
34142
33922
  }
34143
33923
  }
@@ -34226,7 +34006,7 @@ function executePlan(logger, command, args, options = {}) {
34226
34006
  }
34227
34007
  function saveStructuredResult(path, stdout) {
34228
34008
  const parsed = JSON.parse(stdout);
34229
- mkdirSync7(dirname7(path), { recursive: true });
34009
+ mkdirSync6(dirname6(path), { recursive: true });
34230
34010
  writeFileSync7(path, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
34231
34011
  }
34232
34012
  function shellDisplayQuote(value) {
@@ -34315,8 +34095,8 @@ function runCommunityRemove(ctx, handle, opts) {
34315
34095
 
34316
34096
  // src/commands/factoryDiagnostics.ts
34317
34097
  import { execFileSync } from "node:child_process";
34318
- import { existsSync as existsSync12, readFileSync as readFileSync7 } from "node:fs";
34319
- import { join as join14 } from "node:path";
34098
+ import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
34099
+ import { join as join15 } from "node:path";
34320
34100
  import { DatabaseSync } from "node:sqlite";
34321
34101
  import { parse as parseToml2 } from "smol-toml";
34322
34102
  var status = (ok, reason) => ({ status: ok ? "ready" : "not_ready", reason_code: ok ? "ready" : reason });
@@ -34328,10 +34108,10 @@ function isRecord2(value) {
34328
34108
  return typeof value === "object" && value !== null && !Array.isArray(value);
34329
34109
  }
34330
34110
  function claudeRegistration(home, nodePath, cliScriptPath) {
34331
- const path = join14(home, ".claude.json");
34332
- if (!existsSync12(path)) return status(false, "not_registered");
34111
+ const path = join15(home, ".claude.json");
34112
+ if (!existsSync14(path)) return status(false, "not_registered");
34333
34113
  try {
34334
- const value = JSON.parse(readFileSync7(path, "utf8"));
34114
+ const value = JSON.parse(readFileSync8(path, "utf8"));
34335
34115
  if (!isRecord2(value) || !isRecord2(value.mcpServers)) return status(false, "not_registered");
34336
34116
  return status(isCaveatClaudeMcpRegistration(value.mcpServers.caveat, nodePath, cliScriptPath), "not_registered");
34337
34117
  } catch {
@@ -34340,7 +34120,7 @@ function claudeRegistration(home, nodePath, cliScriptPath) {
34340
34120
  }
34341
34121
  function claudeHooks(home, nodePath, cliScriptPath) {
34342
34122
  try {
34343
- const settings = JSON.parse(readFileSync7(join14(home, ".claude", "settings.json"), "utf8"));
34123
+ const settings = JSON.parse(readFileSync8(join15(home, ".claude", "settings.json"), "utf8"));
34344
34124
  const present = (event, subcommand) => settings.hooks?.[event]?.some((entry) => entry.hooks?.some((item) => typeof item.command === "string" && isCanonicalCaveatClaudeHookCommand(item.command, subcommand, nodePath, cliScriptPath))) ?? false;
34345
34125
  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")) };
34346
34126
  } catch {
@@ -34362,7 +34142,7 @@ function strictSearchSchema(db) {
34362
34142
  return columns.map((column) => `${column.name}:${column.hidden}`).join(",") === "id:0,title:0,body:0,tags:0,entries_fts:1,rank:1";
34363
34143
  }
34364
34144
  function database(path) {
34365
- if (!existsSync12(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
34145
+ if (!existsSync14(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
34366
34146
  try {
34367
34147
  const db = new DatabaseSync(path, { readOnly: true });
34368
34148
  try {
@@ -34387,10 +34167,10 @@ function database(path) {
34387
34167
  }
34388
34168
  }
34389
34169
  function codexFeature(codexHome) {
34390
- const path = join14(codexHome, "config.toml");
34391
- if (!existsSync12(path)) return status(false, "feature_disabled");
34170
+ const path = join15(codexHome, "config.toml");
34171
+ if (!existsSync14(path)) return status(false, "feature_disabled");
34392
34172
  try {
34393
- const config2 = parseToml2(readFileSync7(path, "utf8"));
34173
+ const config2 = parseToml2(readFileSync8(path, "utf8"));
34394
34174
  if (!isRecord2(config2.features)) return status(false, "feature_disabled");
34395
34175
  const features = config2.features;
34396
34176
  return status(features.hooks === true && features.codex_hooks === void 0, "feature_disabled");
@@ -34399,10 +34179,10 @@ function codexFeature(codexHome) {
34399
34179
  }
34400
34180
  }
34401
34181
  function codexHooks(codexHome, nodePath, cliScriptPath) {
34402
- const value = JSON.parse(readFileSync7(join14(codexHome, "hooks.json"), "utf8"));
34182
+ const value = JSON.parse(readFileSync8(join15(codexHome, "hooks.json"), "utf8"));
34403
34183
  if (!isRecord2(value) || !isRecord2(value.hooks)) throw Error("config_unreadable");
34404
34184
  const hooks = value.hooks;
34405
- 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)));
34185
+ const present = (event, subcommand) => Array.isArray(hooks[event]) && hooks[event].some((entry) => isRecord2(entry) && Array.isArray(entry.hooks) && entry.hooks.some((item) => isCanonicalCaveatCodexHookEntry(item, subcommand, nodePath, cliScriptPath)));
34406
34186
  return { userPromptSubmit: present("UserPromptSubmit", "user-prompt-submit"), postToolUse: present("PostToolUse", "post-tool-use"), stop: present("Stop", "stop") };
34407
34187
  }
34408
34188
  function sync(own) {
@@ -34434,7 +34214,7 @@ function sync(own) {
34434
34214
  return unverified("upstream_unavailable");
34435
34215
  }
34436
34216
  }
34437
- function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join14(ctx.userHome, ".codex")) {
34217
+ function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join15(ctx.userHome, ".codex")) {
34438
34218
  const nodePath = process.execPath;
34439
34219
  const cliScriptPath = process.argv[1] ?? "";
34440
34220
  const db = database(ctx.paths.dbPath);