caveat-cli 0.17.3 → 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/{chunk-TRIQ5WFY.js → chunk-ZBHCOA6R.js} +128 -108
- package/dist/chunk-ZBHCOA6R.js.map +1 -0
- package/dist/index.js +297 -532
- package/dist/index.js.map +1 -1
- package/dist/{server-FUWTRVRZ.js → server-GBVHOF67.js} +2 -2
- package/package.json +3 -3
- package/dist/chunk-TRIQ5WFY.js.map +0 -1
- /package/dist/{server-FUWTRVRZ.js.map → server-GBVHOF67.js.map} +0 -0
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-
|
|
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
|
|
6889
|
-
import { dirname as
|
|
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 {
|
|
6894
|
-
import {
|
|
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 `${
|
|
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 (!
|
|
7010
|
+
if (!existsSync2(path)) return {};
|
|
6986
7011
|
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
6987
7012
|
}
|
|
6988
7013
|
function writeSettings(path, settings) {
|
|
6989
|
-
|
|
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,32 @@ function uninstallClaudeIntegration(opts) {
|
|
|
7112
7129
|
}
|
|
7113
7130
|
|
|
7114
7131
|
// src/codexHookInstall.ts
|
|
7115
|
-
import {
|
|
7116
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
7155
|
+
const parsed = commandTokens(actual);
|
|
7158
7156
|
const tokens = parsed?.[0] === "&" ? parsed.slice(1) : parsed;
|
|
7159
|
-
return tokens?.length === 4 &&
|
|
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;
|
|
7160
7158
|
}
|
|
7161
7159
|
function isCanonicalCaveatCodexHookEntry(value, event, nodePath, cliScriptPath) {
|
|
7162
7160
|
if (!isPlainRecord(value) || typeof value.type !== "string" || typeof value.command !== "string") return false;
|
|
@@ -7168,21 +7166,9 @@ function hasCaveatHook(hooksJson, event, fragment) {
|
|
|
7168
7166
|
) ?? false;
|
|
7169
7167
|
}
|
|
7170
7168
|
function readHooks(path) {
|
|
7171
|
-
if (!
|
|
7169
|
+
if (!existsSync3(path)) return {};
|
|
7172
7170
|
return JSON.parse(readFileSync3(path, "utf-8"));
|
|
7173
7171
|
}
|
|
7174
|
-
function writeJsonWithBackup(path, value) {
|
|
7175
|
-
const dir = dirname3(path);
|
|
7176
|
-
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
|
|
7177
|
-
let backupPath = "";
|
|
7178
|
-
if (existsSync2(path)) {
|
|
7179
|
-
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
7180
|
-
copyFileSync2(path, backupPath);
|
|
7181
|
-
}
|
|
7182
|
-
writeFileSync2(path, `${JSON.stringify(value, null, 2)}
|
|
7183
|
-
`, "utf-8");
|
|
7184
|
-
return backupPath;
|
|
7185
|
-
}
|
|
7186
7172
|
function upsertHook2(hooksJson, event, command, subcommand) {
|
|
7187
7173
|
hooksJson.hooks ??= {};
|
|
7188
7174
|
const list = hooksJson.hooks[event] ??= [];
|
|
@@ -7404,21 +7390,10 @@ function maskTomlStringsAndComments(raw) {
|
|
|
7404
7390
|
}
|
|
7405
7391
|
return output;
|
|
7406
7392
|
}
|
|
7407
|
-
function writeConfigWithBackup(path, text) {
|
|
7408
|
-
const dir = dirname3(path);
|
|
7409
|
-
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
|
|
7410
|
-
let backupPath = "";
|
|
7411
|
-
if (existsSync2(path)) {
|
|
7412
|
-
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
7413
|
-
copyFileSync2(path, backupPath);
|
|
7414
|
-
}
|
|
7415
|
-
writeFileSync2(path, text, "utf-8");
|
|
7416
|
-
return backupPath;
|
|
7417
|
-
}
|
|
7418
7393
|
function installCodexHooks(opts) {
|
|
7419
7394
|
const hooksPath = join4(opts.codexHome, "hooks.json");
|
|
7420
7395
|
const configPath = join4(opts.codexHome, "config.toml");
|
|
7421
|
-
const rawConfig =
|
|
7396
|
+
const rawConfig = existsSync3(configPath) ? readFileSync3(configPath, "utf-8") : "";
|
|
7422
7397
|
const enabled = enableCodexHooksFeature(rawConfig);
|
|
7423
7398
|
if (enabled.status === "blocked") {
|
|
7424
7399
|
return {
|
|
@@ -7458,7 +7433,7 @@ function installCodexHooks(opts) {
|
|
|
7458
7433
|
if (backup) backupPath = backup;
|
|
7459
7434
|
}
|
|
7460
7435
|
if (enabled.changed) {
|
|
7461
|
-
const backup =
|
|
7436
|
+
const backup = writeFileWithBackup(configPath, enabled.text);
|
|
7462
7437
|
if (backup) configBackupPath = backup;
|
|
7463
7438
|
}
|
|
7464
7439
|
}
|
|
@@ -7582,9 +7557,9 @@ function askOnce(question) {
|
|
|
7582
7557
|
}
|
|
7583
7558
|
|
|
7584
7559
|
// src/nodePath.ts
|
|
7585
|
-
import { existsSync as
|
|
7560
|
+
import { existsSync as existsSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
7586
7561
|
import { delimiter, join as join5 } from "node:path";
|
|
7587
|
-
var defaultRealpath = (path) =>
|
|
7562
|
+
var defaultRealpath = (path) => realpathSync2.native(path);
|
|
7588
7563
|
function safeRealpath(path, realpath = defaultRealpath) {
|
|
7589
7564
|
try {
|
|
7590
7565
|
return realpath(path);
|
|
@@ -7596,12 +7571,12 @@ function resolveHookNodePath({
|
|
|
7596
7571
|
env = process.env,
|
|
7597
7572
|
execPath = process.execPath,
|
|
7598
7573
|
platform = process.platform,
|
|
7599
|
-
exists =
|
|
7574
|
+
exists = existsSync4,
|
|
7600
7575
|
realpath = defaultRealpath
|
|
7601
7576
|
} = {}) {
|
|
7602
7577
|
const execRealpath = safeRealpath(execPath, realpath);
|
|
7603
7578
|
const pathEnv = env.PATH ?? env.Path ?? "";
|
|
7604
|
-
const names = platform
|
|
7579
|
+
const names = nodeExecutableNames(platform);
|
|
7605
7580
|
for (const dir of pathEnv.split(delimiter).filter(Boolean)) {
|
|
7606
7581
|
for (const name of names) {
|
|
7607
7582
|
const candidate = join5(dir, name);
|
|
@@ -7616,12 +7591,12 @@ function resolveHookNodePath({
|
|
|
7616
7591
|
}
|
|
7617
7592
|
|
|
7618
7593
|
// src/commands/publish.ts
|
|
7619
|
-
import { existsSync as
|
|
7594
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
7620
7595
|
import { join as join7 } from "node:path";
|
|
7621
7596
|
|
|
7622
7597
|
// src/commands/codexSidecarAdvisory.ts
|
|
7623
7598
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7624
|
-
import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as
|
|
7599
|
+
import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7625
7600
|
import { tmpdir } from "node:os";
|
|
7626
7601
|
import { join as join6 } from "node:path";
|
|
7627
7602
|
var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
|
|
@@ -7684,7 +7659,7 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7684
7659
|
args.push("--save-result", resultFile);
|
|
7685
7660
|
if (input.additionalContext) {
|
|
7686
7661
|
const additionalContextFile = join6(resultDir, "hook-signal.json");
|
|
7687
|
-
|
|
7662
|
+
writeFileSync2(additionalContextFile, JSON.stringify({ context: [input.additionalContext] }) + "\n", { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
7688
7663
|
args.push("--additional-context-file", additionalContextFile);
|
|
7689
7664
|
}
|
|
7690
7665
|
const nodeCli = process.env.CAVEAT_CODEX_SIDECAR_NODE_CLI;
|
|
@@ -7779,7 +7754,7 @@ async function runPublish(ctx, opts, dependencies = {}) {
|
|
|
7779
7754
|
const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
|
|
7780
7755
|
const confirm = dependencies.confirm ?? askOnce;
|
|
7781
7756
|
const projectRoot = process.cwd();
|
|
7782
|
-
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) =>
|
|
7757
|
+
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) => existsSync5(join7(root, ".codex-sidecar.yml")));
|
|
7783
7758
|
const publishAdvisory = hasCodexSidecarConfig(projectRoot) ? (changes) => {
|
|
7784
7759
|
try {
|
|
7785
7760
|
return dependencies.runCodexSidecarAdvisory?.(changes, projectRoot) ?? formatCodexSidecarAdvisory(runCodexSidecarAdvisory({
|
|
@@ -7838,22 +7813,22 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7838
7813
|
let codexHookState = "not-installed";
|
|
7839
7814
|
ensureUserConfig(ctx.userConfigPath);
|
|
7840
7815
|
ctx.logger.info(`user config: ${ctx.userConfigPath}`);
|
|
7841
|
-
if (!
|
|
7842
|
-
|
|
7843
|
-
|
|
7816
|
+
if (!existsSync6(ctx.paths.knowledgeRepo)) {
|
|
7817
|
+
mkdirSync2(ctx.paths.knowledgeRepo, { recursive: true });
|
|
7818
|
+
mkdirSync2(ctx.paths.entriesDir, { recursive: true });
|
|
7844
7819
|
ctx.logger.info(`knowledge repo scaffolded: ${ctx.paths.knowledgeRepo}`);
|
|
7845
7820
|
} else {
|
|
7846
7821
|
ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
|
|
7847
7822
|
}
|
|
7848
7823
|
migrateLegacyCommunityDir(ctx);
|
|
7849
7824
|
const gitignorePath = join8(ctx.paths.knowledgeRepo, ".gitignore");
|
|
7850
|
-
if (!
|
|
7851
|
-
|
|
7825
|
+
if (!existsSync6(gitignorePath)) {
|
|
7826
|
+
writeFileSync3(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
|
|
7852
7827
|
ctx.logger.info(`.gitignore created: ${gitignorePath}`);
|
|
7853
7828
|
}
|
|
7854
7829
|
if (!opts.dryRun) {
|
|
7855
|
-
const dbDir =
|
|
7856
|
-
if (!
|
|
7830
|
+
const dbDir = dirname3(ctx.paths.dbPath);
|
|
7831
|
+
if (!existsSync6(dbDir)) mkdirSync2(dbDir, { recursive: true });
|
|
7857
7832
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
7858
7833
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
7859
7834
|
for (const failure of failures) {
|
|
@@ -8031,7 +8006,7 @@ function reportEnvironmentSummary(ctx, publishTarget, codexHookState, dryRun) {
|
|
|
8031
8006
|
const prefix = dryRun ? "[dry-run] would have " : "";
|
|
8032
8007
|
const isRepo = gitOutput(["-C", ctx.paths.knowledgeRepo, "rev-parse", "--is-inside-work-tree"]) === "true";
|
|
8033
8008
|
const remote = isRepo ? gitOutput(["-C", ctx.paths.knowledgeRepo, "config", "--get", "remote.origin.url"]) : null;
|
|
8034
|
-
const communityCount =
|
|
8009
|
+
const communityCount = existsSync6(ctx.paths.communityDir) ? readdirSync(ctx.paths.communityDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
|
|
8035
8010
|
ctx.logger.info(`${prefix}environment summary:`);
|
|
8036
8011
|
ctx.logger.info(` own git: ${isRepo ? "repository" : "not initialized"}`);
|
|
8037
8012
|
ctx.logger.info(` private remote: ${remote || "not configured"}`);
|
|
@@ -8046,14 +8021,14 @@ function migrateLegacyCommunityDir(ctx) {
|
|
|
8046
8021
|
const legacy = join8(ctx.paths.knowledgeRepo, "community");
|
|
8047
8022
|
const current = ctx.paths.communityDir;
|
|
8048
8023
|
if (legacy === current) return;
|
|
8049
|
-
if (!
|
|
8050
|
-
if (
|
|
8024
|
+
if (!existsSync6(legacy)) return;
|
|
8025
|
+
if (existsSync6(current)) {
|
|
8051
8026
|
ctx.logger.warn(
|
|
8052
8027
|
`legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
|
|
8053
8028
|
);
|
|
8054
8029
|
return;
|
|
8055
8030
|
}
|
|
8056
|
-
|
|
8031
|
+
mkdirSync2(current, { recursive: true });
|
|
8057
8032
|
for (const entry of readdirSync(legacy, { withFileTypes: true })) {
|
|
8058
8033
|
if (!entry.isDirectory()) continue;
|
|
8059
8034
|
renameSync(join8(legacy, entry.name), join8(current, entry.name));
|
|
@@ -8118,11 +8093,11 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
8118
8093
|
}
|
|
8119
8094
|
|
|
8120
8095
|
// src/commands/indexCmd.ts
|
|
8121
|
-
import { existsSync as
|
|
8122
|
-
import { dirname as
|
|
8096
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3 } from "node:fs";
|
|
8097
|
+
import { dirname as dirname4 } from "node:path";
|
|
8123
8098
|
async function runIndex(ctx, opts) {
|
|
8124
|
-
const dbDir =
|
|
8125
|
-
if (!
|
|
8099
|
+
const dbDir = dirname4(ctx.paths.dbPath);
|
|
8100
|
+
if (!existsSync7(dbDir)) mkdirSync3(dbDir, { recursive: true });
|
|
8126
8101
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
8127
8102
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
8128
8103
|
for (const failure of failures) {
|
|
@@ -8306,7 +8281,7 @@ function runStats(ctx) {
|
|
|
8306
8281
|
|
|
8307
8282
|
// src/commands/serve.ts
|
|
8308
8283
|
async function runServe(opts) {
|
|
8309
|
-
const { startServer } = await import("./server-
|
|
8284
|
+
const { startServer } = await import("./server-GBVHOF67.js");
|
|
8310
8285
|
const { port, host } = startServer({ port: opts.port });
|
|
8311
8286
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8312
8287
|
`);
|
|
@@ -32546,12 +32521,12 @@ function handleListRecent(ctx, args) {
|
|
|
32546
32521
|
}
|
|
32547
32522
|
|
|
32548
32523
|
// ../mcp/dist/tools/pull.js
|
|
32549
|
-
import { existsSync as
|
|
32524
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
32550
32525
|
var pullInputShape = {};
|
|
32551
32526
|
async function handlePull(ctx, _args = {}) {
|
|
32552
32527
|
const pulled = [];
|
|
32553
32528
|
const indexed = [];
|
|
32554
|
-
if (
|
|
32529
|
+
if (existsSync8(ctx.paths.communityDir)) {
|
|
32555
32530
|
const results = await communityPull({
|
|
32556
32531
|
communityDir: ctx.paths.communityDir,
|
|
32557
32532
|
logger: ctx.logger
|
|
@@ -32707,28 +32682,28 @@ async function runMcpServer() {
|
|
|
32707
32682
|
import { spawn as spawn2 } from "node:child_process";
|
|
32708
32683
|
import {
|
|
32709
32684
|
chmodSync,
|
|
32710
|
-
existsSync as
|
|
32685
|
+
existsSync as existsSync11,
|
|
32711
32686
|
lstatSync,
|
|
32712
32687
|
mkdtempSync as mkdtempSync2,
|
|
32713
32688
|
mkdirSync as mkdirSync5,
|
|
32714
32689
|
readdirSync as readdirSync2,
|
|
32715
|
-
readFileSync as
|
|
32716
|
-
realpathSync as
|
|
32690
|
+
readFileSync as readFileSync6,
|
|
32691
|
+
realpathSync as realpathSync3,
|
|
32717
32692
|
rmSync as rmSync2,
|
|
32718
32693
|
writeFileSync as writeFileSync5
|
|
32719
32694
|
} from "node:fs";
|
|
32720
32695
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
32721
|
-
import { basename, dirname as
|
|
32722
|
-
import {
|
|
32696
|
+
import { basename, dirname as dirname5, join as join12 } from "node:path";
|
|
32697
|
+
import { randomBytes } from "node:crypto";
|
|
32723
32698
|
|
|
32724
32699
|
// src/autoReindexTrigger.ts
|
|
32725
32700
|
import { spawn } from "node:child_process";
|
|
32726
|
-
import { existsSync as
|
|
32701
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
32727
32702
|
import { join as join10 } from "node:path";
|
|
32728
32703
|
function maybeTriggerAutoReindex(ctx) {
|
|
32729
32704
|
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") return;
|
|
32730
|
-
if (!
|
|
32731
|
-
if (
|
|
32705
|
+
if (!existsSync9(ctx.paths.dbPath)) return;
|
|
32706
|
+
if (existsSync9(join10(ctx.caveatHome, "index", ".reindex-lock"))) return;
|
|
32732
32707
|
const current = computeEntriesDigest(ctx.paths);
|
|
32733
32708
|
const marker = readDigestMarker(ctx.caveatHome);
|
|
32734
32709
|
if (marker?.digest === current.digest && marker.fileCount === current.fileCount) return;
|
|
@@ -32753,18 +32728,22 @@ function maybeTriggerAutoSync(ctx, debounceMs = AUTO_SYNC_DEBOUNCE_MS) {
|
|
|
32753
32728
|
});
|
|
32754
32729
|
}
|
|
32755
32730
|
|
|
32756
|
-
// src/
|
|
32757
|
-
|
|
32758
|
-
|
|
32759
|
-
|
|
32760
|
-
|
|
32761
|
-
|
|
32762
|
-
|
|
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}
|
|
32763
32744
|
`)
|
|
32764
|
-
};
|
|
32765
|
-
|
|
32766
|
-
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:";
|
|
32767
|
-
var CLAUDE_STOP_STATE_DIR = "claude-stop-state";
|
|
32745
|
+
};
|
|
32746
|
+
}
|
|
32768
32747
|
async function readStdin() {
|
|
32769
32748
|
const chunks = [];
|
|
32770
32749
|
for await (const chunk of process.stdin) {
|
|
@@ -32772,34 +32751,32 @@ async function readStdin() {
|
|
|
32772
32751
|
}
|
|
32773
32752
|
return Buffer.concat(chunks).toString("utf-8");
|
|
32774
32753
|
}
|
|
32775
|
-
function
|
|
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) {
|
|
32776
32763
|
if (!raw) return {};
|
|
32777
32764
|
try {
|
|
32778
32765
|
return JSON.parse(raw);
|
|
32779
32766
|
} catch (err) {
|
|
32780
|
-
|
|
32781
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32782
|
-
process.stderr.write(`[caveat:hook] json parse error: ${msg}
|
|
32783
|
-
`);
|
|
32767
|
+
reportHookError(host, "json parse error", err);
|
|
32784
32768
|
return {};
|
|
32785
32769
|
}
|
|
32786
32770
|
}
|
|
32787
|
-
function
|
|
32788
|
-
const v = payload.session_id ?? payload.sessionId;
|
|
32789
|
-
return typeof v === "string" && v.length > 0 ? v : "_unknown";
|
|
32790
|
-
}
|
|
32791
|
-
function buildContextSafely() {
|
|
32771
|
+
function buildContextSafely(host) {
|
|
32792
32772
|
try {
|
|
32793
|
-
return buildContext(
|
|
32773
|
+
return buildContext(hookSilentLogger(host));
|
|
32794
32774
|
} catch (err) {
|
|
32795
|
-
|
|
32796
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32797
|
-
process.stderr.write(`[caveat:hook] context error: ${msg}
|
|
32798
|
-
`);
|
|
32775
|
+
reportHookError(host, "context error", err);
|
|
32799
32776
|
return null;
|
|
32800
32777
|
}
|
|
32801
32778
|
}
|
|
32802
|
-
function searchCaveatsSafely(input) {
|
|
32779
|
+
function searchCaveatsSafely(host, input) {
|
|
32803
32780
|
const inputs = Array.isArray(input) ? input : [input];
|
|
32804
32781
|
const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
|
|
32805
32782
|
if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
|
|
@@ -32807,8 +32784,8 @@ function searchCaveatsSafely(input) {
|
|
|
32807
32784
|
let caveatHome;
|
|
32808
32785
|
let hits;
|
|
32809
32786
|
try {
|
|
32810
|
-
const ctx = buildContextSafely();
|
|
32811
|
-
if (!ctx || !
|
|
32787
|
+
const ctx = buildContextSafely(host);
|
|
32788
|
+
if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
|
|
32812
32789
|
caveatHome = ctx.caveatHome;
|
|
32813
32790
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32814
32791
|
const searchOptions = {
|
|
@@ -32816,29 +32793,20 @@ function searchCaveatsSafely(input) {
|
|
|
32816
32793
|
};
|
|
32817
32794
|
hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
|
|
32818
32795
|
} catch (err) {
|
|
32819
|
-
|
|
32820
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32821
|
-
process.stderr.write(`[caveat:hook] search error: ${msg}
|
|
32822
|
-
`);
|
|
32796
|
+
reportHookError(host, "search error", err);
|
|
32823
32797
|
return [];
|
|
32824
32798
|
}
|
|
32825
32799
|
if (hits.length > 0) {
|
|
32826
32800
|
try {
|
|
32827
32801
|
markHit(db, hits);
|
|
32828
32802
|
} catch (err) {
|
|
32829
|
-
|
|
32830
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32831
|
-
process.stderr.write(`[caveat:hook] markHit error: ${msg}
|
|
32832
|
-
`);
|
|
32803
|
+
reportHookError(host, "markHit error", err);
|
|
32833
32804
|
}
|
|
32834
32805
|
} else {
|
|
32835
32806
|
try {
|
|
32836
|
-
logHookQueryMiss({ caveatHome, agent:
|
|
32807
|
+
logHookQueryMiss({ caveatHome, agent: host.agent, surface: inputs[0].surface, query: queryForLog });
|
|
32837
32808
|
} catch (err) {
|
|
32838
|
-
|
|
32839
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32840
|
-
process.stderr.write(`[caveat:hook] query log error: ${msg}
|
|
32841
|
-
`);
|
|
32809
|
+
reportHookError(host, "query log error", err);
|
|
32842
32810
|
}
|
|
32843
32811
|
}
|
|
32844
32812
|
try {
|
|
@@ -32847,50 +32815,37 @@ function searchCaveatsSafely(input) {
|
|
|
32847
32815
|
db?.close();
|
|
32848
32816
|
}
|
|
32849
32817
|
}
|
|
32850
|
-
function
|
|
32851
|
-
|
|
32852
|
-
return readSessionSignals(path);
|
|
32853
|
-
} catch (err) {
|
|
32854
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
32855
|
-
process.stderr.write(`[caveat:hook] transcript read error: ${msg}
|
|
32856
|
-
`);
|
|
32857
|
-
return null;
|
|
32858
|
-
}
|
|
32859
|
-
}
|
|
32860
|
-
function systemReminderOutput(text) {
|
|
32861
|
-
return `<system-reminder>${text.replace(/</g, "\u2039").replace(/>/g, "\u203A")}</system-reminder>`;
|
|
32862
|
-
}
|
|
32863
|
-
function claudePendingCleanupFailureText() {
|
|
32864
|
-
return "[caveat:hook] pending reminder cleanup failed";
|
|
32818
|
+
function pendingCleanupFailureText(host) {
|
|
32819
|
+
return `[${host.stderrTag}] pending reminder cleanup failed`;
|
|
32865
32820
|
}
|
|
32866
|
-
function drainForSession(sessionId) {
|
|
32867
|
-
const ctx = buildContextSafely();
|
|
32821
|
+
function drainForSession(host, sessionId) {
|
|
32822
|
+
const ctx = buildContextSafely(host);
|
|
32868
32823
|
if (!ctx) return [];
|
|
32869
32824
|
const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
|
|
32870
32825
|
const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
|
|
32871
32826
|
for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
|
|
32872
|
-
process.stderr.write(`${
|
|
32827
|
+
process.stderr.write(`${pendingCleanupFailureText(host)}
|
|
32873
32828
|
`);
|
|
32874
32829
|
}
|
|
32875
32830
|
return [...local.reminders, ...global.reminders];
|
|
32876
32831
|
}
|
|
32877
|
-
function
|
|
32878
|
-
if (text.startsWith(
|
|
32832
|
+
function contextDedupeKey(host, text) {
|
|
32833
|
+
if (text.startsWith(STOP_REMINDER_PREFIX)) return host.stopDedupeKey;
|
|
32879
32834
|
return text.trim();
|
|
32880
32835
|
}
|
|
32881
|
-
function
|
|
32836
|
+
function compactContexts(host, contexts) {
|
|
32882
32837
|
const selected = [];
|
|
32883
32838
|
const seen = /* @__PURE__ */ new Set();
|
|
32884
32839
|
for (let i = contexts.length - 1; i >= 0; i -= 1) {
|
|
32885
32840
|
const text = contexts[i]?.trim();
|
|
32886
32841
|
if (!text) continue;
|
|
32887
|
-
const key =
|
|
32842
|
+
const key = contextDedupeKey(host, text);
|
|
32888
32843
|
if (seen.has(key)) continue;
|
|
32889
32844
|
seen.add(key);
|
|
32890
32845
|
selected.push(text);
|
|
32891
32846
|
}
|
|
32892
32847
|
selected.reverse();
|
|
32893
|
-
const limited = selected.slice(-
|
|
32848
|
+
const limited = selected.slice(-MAX_CONTEXT_BLOCKS);
|
|
32894
32849
|
const omitted = selected.length - limited.length;
|
|
32895
32850
|
if (omitted > 0) {
|
|
32896
32851
|
limited.push(
|
|
@@ -32899,7 +32854,7 @@ function compactClaudeContexts(contexts) {
|
|
|
32899
32854
|
}
|
|
32900
32855
|
return limited;
|
|
32901
32856
|
}
|
|
32902
|
-
function
|
|
32857
|
+
function sanitizeStateId(raw) {
|
|
32903
32858
|
const clean = raw.replace(/[^A-Za-z0-9_-]/g, "");
|
|
32904
32859
|
return clean.length > 0 ? clean : "_unknown";
|
|
32905
32860
|
}
|
|
@@ -32915,59 +32870,59 @@ function stopSignalKey(signals, related) {
|
|
|
32915
32870
|
});
|
|
32916
32871
|
return createHash("sha256").update(body).digest("hex");
|
|
32917
32872
|
}
|
|
32918
|
-
function stopStatePath(caveatHome, sessionId) {
|
|
32919
|
-
return join11(caveatHome,
|
|
32873
|
+
function stopStatePath(host, caveatHome, sessionId) {
|
|
32874
|
+
return join11(caveatHome, host.stopStateDir, `${sanitizeStateId(sessionId)}.txt`);
|
|
32920
32875
|
}
|
|
32921
|
-
function wasStopReminderQueued(caveatHome, sessionId, key) {
|
|
32922
|
-
const path = stopStatePath(caveatHome, sessionId);
|
|
32876
|
+
function wasStopReminderQueued(host, caveatHome, sessionId, key) {
|
|
32877
|
+
const path = stopStatePath(host, caveatHome, sessionId);
|
|
32923
32878
|
try {
|
|
32924
32879
|
return readFileSync5(path, "utf-8") === key;
|
|
32925
32880
|
} catch {
|
|
32926
32881
|
return false;
|
|
32927
32882
|
}
|
|
32928
32883
|
}
|
|
32929
|
-
function markStopReminderQueued(caveatHome, sessionId, key) {
|
|
32930
|
-
const path = stopStatePath(caveatHome, sessionId);
|
|
32931
|
-
|
|
32932
|
-
|
|
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");
|
|
32933
32888
|
}
|
|
32934
|
-
function queueStopForSession(sessionId, signals, related) {
|
|
32935
|
-
const ctx = buildContextSafely();
|
|
32889
|
+
function queueStopForSession(host, sessionId, signals, related, buildText) {
|
|
32890
|
+
const ctx = buildContextSafely(host);
|
|
32936
32891
|
if (!ctx) return;
|
|
32937
32892
|
const key = stopSignalKey(signals, related);
|
|
32938
|
-
if (wasStopReminderQueued(ctx.caveatHome, sessionId, key)) return;
|
|
32893
|
+
if (wasStopReminderQueued(host, ctx.caveatHome, sessionId, key)) return;
|
|
32939
32894
|
let result;
|
|
32940
32895
|
try {
|
|
32941
32896
|
result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
|
|
32942
|
-
agent:
|
|
32897
|
+
agent: host.agent,
|
|
32943
32898
|
surface: "stop",
|
|
32944
32899
|
refs: related,
|
|
32945
32900
|
stopSignalDigest: key
|
|
32946
|
-
}),
|
|
32901
|
+
}), buildText);
|
|
32947
32902
|
} catch {
|
|
32948
|
-
process.stderr.write(
|
|
32903
|
+
process.stderr.write(`[${host.stderrTag}] pending reminder build or publish failed
|
|
32904
|
+
`);
|
|
32949
32905
|
return;
|
|
32950
32906
|
}
|
|
32951
32907
|
if (!result.ran) return;
|
|
32952
32908
|
try {
|
|
32953
|
-
markStopReminderQueued(ctx.caveatHome, sessionId, key);
|
|
32909
|
+
markStopReminderQueued(host, ctx.caveatHome, sessionId, key);
|
|
32954
32910
|
} catch (err) {
|
|
32955
|
-
|
|
32956
|
-
process.stderr.write(`[caveat:hook] pending reminder write error: ${msg}
|
|
32911
|
+
process.stderr.write(`[${host.stderrTag}] pending reminder write error: ${errorMessage4(err)}
|
|
32957
32912
|
`);
|
|
32958
32913
|
}
|
|
32959
32914
|
}
|
|
32960
32915
|
function extractToolResponseText(response) {
|
|
32961
32916
|
if (typeof response === "string") return response;
|
|
32962
32917
|
if (Array.isArray(response)) {
|
|
32963
|
-
|
|
32964
|
-
|
|
32965
|
-
if (typeof item === "
|
|
32966
|
-
|
|
32967
|
-
|
|
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 : "";
|
|
32968
32923
|
}
|
|
32969
|
-
|
|
32970
|
-
|
|
32924
|
+
return "";
|
|
32925
|
+
}).filter(Boolean).join(" ");
|
|
32971
32926
|
}
|
|
32972
32927
|
if (response !== null && typeof response === "object") {
|
|
32973
32928
|
const r = response;
|
|
@@ -32980,6 +32935,32 @@ function extractToolResponseText(response) {
|
|
|
32980
32935
|
}
|
|
32981
32936
|
return "";
|
|
32982
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
|
+
}
|
|
32983
32964
|
function toolTopicText(payload) {
|
|
32984
32965
|
const parts = [];
|
|
32985
32966
|
const toolName = payload.tool_name ?? payload.toolName;
|
|
@@ -33014,15 +32995,14 @@ function spawnWorker(job) {
|
|
|
33014
32995
|
try {
|
|
33015
32996
|
root = workerRoot();
|
|
33016
32997
|
sweepStaleWorkerDirs(Date.now(), root);
|
|
33017
|
-
workDir = mkdtempSync2(
|
|
32998
|
+
workDir = mkdtempSync2(join12(root, "job-"));
|
|
33018
32999
|
chmodSync(workDir, 448);
|
|
33019
|
-
workFile =
|
|
33000
|
+
workFile = join12(workDir, `${randomBytes(4).toString("hex")}.json`);
|
|
33020
33001
|
writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
33021
33002
|
} catch (err) {
|
|
33022
|
-
|
|
33023
|
-
process.stderr.write(`[caveat:hook] worker writefile error: ${msg}
|
|
33003
|
+
process.stderr.write(`[caveat:hook] worker writefile error: ${errorMessage4(err)}
|
|
33024
33004
|
`);
|
|
33025
|
-
cleanupWorkerDir(workDir, workDir ?
|
|
33005
|
+
cleanupWorkerDir(workDir, workDir ? dirname5(workDir) : void 0);
|
|
33026
33006
|
return;
|
|
33027
33007
|
}
|
|
33028
33008
|
const cliScript = process.argv[1];
|
|
@@ -33038,8 +33018,7 @@ function spawnWorker(job) {
|
|
|
33038
33018
|
);
|
|
33039
33019
|
child.unref();
|
|
33040
33020
|
} catch (err) {
|
|
33041
|
-
|
|
33042
|
-
process.stderr.write(`[caveat:hook] worker spawn error: ${msg}
|
|
33021
|
+
process.stderr.write(`[caveat:hook] worker spawn error: ${errorMessage4(err)}
|
|
33043
33022
|
`);
|
|
33044
33023
|
try {
|
|
33045
33024
|
cleanupWorkerDir(workDir, root);
|
|
@@ -33050,11 +33029,11 @@ function spawnWorker(job) {
|
|
|
33050
33029
|
async function runWorker(workFile) {
|
|
33051
33030
|
let raw;
|
|
33052
33031
|
try {
|
|
33053
|
-
raw =
|
|
33032
|
+
raw = readFileSync6(workFile, "utf-8");
|
|
33054
33033
|
} catch {
|
|
33055
33034
|
process.exit(0);
|
|
33056
33035
|
}
|
|
33057
|
-
cleanupWorkerDir(
|
|
33036
|
+
cleanupWorkerDir(dirname5(workFile), dirname5(dirname5(workFile)));
|
|
33058
33037
|
let job;
|
|
33059
33038
|
try {
|
|
33060
33039
|
job = JSON.parse(raw);
|
|
@@ -33062,13 +33041,13 @@ async function runWorker(workFile) {
|
|
|
33062
33041
|
process.exit(0);
|
|
33063
33042
|
}
|
|
33064
33043
|
if (!job.failureText || !job.sessionId) process.exit(0);
|
|
33065
|
-
const hits = searchCaveatsSafely({
|
|
33044
|
+
const hits = searchCaveatsSafely(CLAUDE_HOST, {
|
|
33066
33045
|
topicText: job.topicText,
|
|
33067
33046
|
failureText: job.failureText,
|
|
33068
33047
|
surface: "tool_error"
|
|
33069
33048
|
});
|
|
33070
33049
|
if (hits.length === 0) process.exit(0);
|
|
33071
|
-
const ctx = buildContextSafely();
|
|
33050
|
+
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33072
33051
|
if (!ctx) process.exit(0);
|
|
33073
33052
|
let result;
|
|
33074
33053
|
try {
|
|
@@ -33095,11 +33074,11 @@ function isOwnedWorkerDir(path, root = workerRoot()) {
|
|
|
33095
33074
|
try {
|
|
33096
33075
|
const inputStat = lstatSync(path);
|
|
33097
33076
|
if (inputStat.isSymbolicLink()) return false;
|
|
33098
|
-
const tmpRoot =
|
|
33099
|
-
const resolved =
|
|
33077
|
+
const tmpRoot = realpathSync3(root);
|
|
33078
|
+
const resolved = realpathSync3(path);
|
|
33100
33079
|
const stat = lstatSync(resolved);
|
|
33101
33080
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33102
|
-
return
|
|
33081
|
+
return dirname5(resolved) === tmpRoot && basename(resolved).startsWith("job-") && stat.isDirectory() && !stat.isSymbolicLink() && hasPrivateOwnership(stat, uid);
|
|
33103
33082
|
} catch {
|
|
33104
33083
|
return false;
|
|
33105
33084
|
}
|
|
@@ -33114,7 +33093,7 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33114
33093
|
}
|
|
33115
33094
|
for (const entry of entries) {
|
|
33116
33095
|
if (!entry.startsWith("job-")) continue;
|
|
33117
|
-
const path =
|
|
33096
|
+
const path = join12(root, entry);
|
|
33118
33097
|
try {
|
|
33119
33098
|
if (!isOwnedWorkerDir(path, root)) continue;
|
|
33120
33099
|
const stat = lstatSync(path);
|
|
@@ -33126,32 +33105,32 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33126
33105
|
}
|
|
33127
33106
|
}
|
|
33128
33107
|
function workerRoot(base = tmpdir2()) {
|
|
33129
|
-
const root =
|
|
33108
|
+
const root = join12(base, WORKER_ROOT);
|
|
33130
33109
|
mkdirSync5(root, { recursive: true, mode: 448 });
|
|
33131
33110
|
const stat = lstatSync(root);
|
|
33132
33111
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33133
33112
|
if (!stat.isDirectory() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) throw new Error("worker root is unsafe");
|
|
33134
|
-
const marker =
|
|
33113
|
+
const marker = join12(root, WORKER_MARKER);
|
|
33135
33114
|
try {
|
|
33136
33115
|
writeFileSync5(marker, "caveat-worker/v1\n", { mode: 384, flag: "wx" });
|
|
33137
33116
|
} catch (error51) {
|
|
33138
33117
|
if (!(error51 && typeof error51 === "object" && "code" in error51 && error51.code === "EEXIST")) throw error51;
|
|
33139
33118
|
}
|
|
33140
33119
|
const markerStat = lstatSync(marker);
|
|
33141
|
-
if (!markerStat.isFile() || markerStat.isSymbolicLink() || !hasPrivateOwnership(markerStat, uid) ||
|
|
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");
|
|
33142
33121
|
return root;
|
|
33143
33122
|
}
|
|
33144
33123
|
function isStaleWorkerJobDir(path) {
|
|
33145
33124
|
const entries = readdirSync2(path);
|
|
33146
33125
|
if (entries.length !== 1 || !entries[0].endsWith(".json")) return false;
|
|
33147
|
-
const file2 =
|
|
33126
|
+
const file2 = join12(path, entries[0]);
|
|
33148
33127
|
const stat = lstatSync(file2);
|
|
33149
33128
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33150
33129
|
if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
|
|
33151
|
-
return isKnownStaleWorkerJob(JSON.parse(
|
|
33130
|
+
return isKnownStaleWorkerJob(JSON.parse(readFileSync6(file2, "utf-8")));
|
|
33152
33131
|
}
|
|
33153
33132
|
function hasPrivateOwnership(stat, uid) {
|
|
33154
|
-
return
|
|
33133
|
+
return isPrivateOwnerStat(stat, uid);
|
|
33155
33134
|
}
|
|
33156
33135
|
function isWorkerJob(value) {
|
|
33157
33136
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -33170,23 +33149,19 @@ function isKnownStaleWorkerJob(value) {
|
|
|
33170
33149
|
}
|
|
33171
33150
|
function writeLastReindex(caveatHome, value) {
|
|
33172
33151
|
try {
|
|
33173
|
-
writeFileSync5(
|
|
33152
|
+
writeFileSync5(join12(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
|
|
33174
33153
|
} catch (err) {
|
|
33175
|
-
|
|
33176
|
-
process.stderr.write(`[caveat:hook] reindex status write error: ${msg}
|
|
33154
|
+
process.stderr.write(`[caveat:hook] reindex status write error: ${errorMessage4(err)}
|
|
33177
33155
|
`);
|
|
33178
33156
|
}
|
|
33179
33157
|
}
|
|
33180
|
-
function errorMessage4(err) {
|
|
33181
|
-
return err instanceof Error ? err.message : String(err);
|
|
33182
|
-
}
|
|
33183
33158
|
async function runReindexWorker() {
|
|
33184
33159
|
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") {
|
|
33185
33160
|
process.stderr.write("[caveat:hook] auto reindex disabled by CAVEAT_INDEX_AUTOSYNC=off\n");
|
|
33186
33161
|
return;
|
|
33187
33162
|
}
|
|
33188
|
-
const ctx = buildContextSafely();
|
|
33189
|
-
if (!ctx || !
|
|
33163
|
+
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33164
|
+
if (!ctx || !existsSync11(ctx.paths.dbPath)) {
|
|
33190
33165
|
process.stderr.write("[caveat:hook] auto reindex skipped: index database does not exist\n");
|
|
33191
33166
|
return;
|
|
33192
33167
|
}
|
|
@@ -33211,7 +33186,7 @@ async function runReindexWorker() {
|
|
|
33211
33186
|
perSource: result.perSource
|
|
33212
33187
|
});
|
|
33213
33188
|
} catch (err) {
|
|
33214
|
-
const msg =
|
|
33189
|
+
const msg = errorMessage4(err);
|
|
33215
33190
|
process.stderr.write(`[caveat:hook] reindex error: ${msg}
|
|
33216
33191
|
`);
|
|
33217
33192
|
writeLastReindex(ctx.caveatHome, {
|
|
@@ -33224,8 +33199,7 @@ async function runReindexWorker() {
|
|
|
33224
33199
|
try {
|
|
33225
33200
|
releaseReindexLock(lock);
|
|
33226
33201
|
} catch (err) {
|
|
33227
|
-
|
|
33228
|
-
process.stderr.write(`[caveat:hook] reindex lock release error: ${msg}
|
|
33202
|
+
process.stderr.write(`[caveat:hook] reindex lock release error: ${errorMessage4(err)}
|
|
33229
33203
|
`);
|
|
33230
33204
|
}
|
|
33231
33205
|
}
|
|
@@ -33235,7 +33209,7 @@ async function runAutoSyncWorker() {
|
|
|
33235
33209
|
process.stderr.write("[caveat:hook] auto sync disabled by CAVEAT_AUTO_SYNC=off\n");
|
|
33236
33210
|
return;
|
|
33237
33211
|
}
|
|
33238
|
-
const ctx = buildContextSafely();
|
|
33212
|
+
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33239
33213
|
if (!ctx) return;
|
|
33240
33214
|
try {
|
|
33241
33215
|
await runAutoSync({
|
|
@@ -33254,7 +33228,7 @@ function buildToolErrorReminder(job, hits) {
|
|
|
33254
33228
|
const mode = hookCodexSidecarMode();
|
|
33255
33229
|
if (mode === "off") return base;
|
|
33256
33230
|
const projectRoot = process.cwd();
|
|
33257
|
-
const hasSidecarConfig =
|
|
33231
|
+
const hasSidecarConfig = existsSync11(join12(projectRoot, ".codex-sidecar.yml"));
|
|
33258
33232
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33259
33233
|
const advisory = runCodexSidecarAdvisory({
|
|
33260
33234
|
searchText: job.failureText,
|
|
@@ -33290,7 +33264,7 @@ function buildStopReminder(signals, related) {
|
|
|
33290
33264
|
const mode = hookCodexSidecarMode();
|
|
33291
33265
|
if (mode === "off") return base;
|
|
33292
33266
|
const projectRoot = process.cwd();
|
|
33293
|
-
const hasSidecarConfig =
|
|
33267
|
+
const hasSidecarConfig = existsSync11(join12(projectRoot, ".codex-sidecar.yml"));
|
|
33294
33268
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33295
33269
|
const advisory = runCodexSidecarAdvisory({
|
|
33296
33270
|
searchText: struggleSearchText(signals),
|
|
@@ -33347,21 +33321,20 @@ async function runHook(name, arg) {
|
|
|
33347
33321
|
try {
|
|
33348
33322
|
raw = await readStdin();
|
|
33349
33323
|
} catch (err) {
|
|
33350
|
-
|
|
33351
|
-
process.stderr.write(`[caveat:hook] stdin read error: ${msg}
|
|
33324
|
+
process.stderr.write(`[caveat:hook] stdin read error: ${errorMessage4(err)}
|
|
33352
33325
|
`);
|
|
33353
33326
|
process.exit(0);
|
|
33354
33327
|
}
|
|
33355
|
-
const payload = parsePayload(raw);
|
|
33328
|
+
const payload = parsePayload(CLAUDE_HOST, raw);
|
|
33356
33329
|
const sessionId = getSessionId(payload);
|
|
33357
|
-
const contexts = name === "stop" ? [] : drainForSession(sessionId);
|
|
33330
|
+
const contexts = name === "stop" ? [] : drainForSession(CLAUDE_HOST, sessionId);
|
|
33358
33331
|
if (name === "user-prompt-submit") {
|
|
33359
33332
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
33360
|
-
const hits = searchCaveatsSafely({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
|
|
33333
|
+
const hits = searchCaveatsSafely(CLAUDE_HOST, { topicText: prompt, failureText: prompt, surface: "user_prompt" });
|
|
33361
33334
|
if (hits.length > 0) {
|
|
33362
33335
|
contexts.push(userPromptSubmitReminderText(hits));
|
|
33363
33336
|
}
|
|
33364
|
-
const compacted =
|
|
33337
|
+
const compacted = compactContexts(CLAUDE_HOST, contexts);
|
|
33365
33338
|
if (compacted.length > 0) {
|
|
33366
33339
|
process.stdout.write(`${systemReminderOutput(compacted.join("\n\n"))}
|
|
33367
33340
|
`);
|
|
@@ -33369,7 +33342,7 @@ async function runHook(name, arg) {
|
|
|
33369
33342
|
process.exit(0);
|
|
33370
33343
|
}
|
|
33371
33344
|
if (name === "post-tool-use") {
|
|
33372
|
-
const compacted =
|
|
33345
|
+
const compacted = compactContexts(CLAUDE_HOST, contexts);
|
|
33373
33346
|
if (compacted.length > 0) {
|
|
33374
33347
|
process.stdout.write(`${systemReminderOutput(compacted.join("\n\n"))}
|
|
33375
33348
|
`);
|
|
@@ -33391,27 +33364,24 @@ async function runHook(name, arg) {
|
|
|
33391
33364
|
process.exit(0);
|
|
33392
33365
|
}
|
|
33393
33366
|
if (name === "stop") {
|
|
33394
|
-
const ctx = buildContextSafely();
|
|
33367
|
+
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33395
33368
|
if (ctx) {
|
|
33396
33369
|
try {
|
|
33397
33370
|
maybeSweepPendingDirs(ctx.caveatHome);
|
|
33398
33371
|
} catch (err) {
|
|
33399
|
-
|
|
33400
|
-
process.stderr.write(`[caveat:hook] pending sweep error: ${msg}
|
|
33372
|
+
process.stderr.write(`[caveat:hook] pending sweep error: ${errorMessage4(err)}
|
|
33401
33373
|
`);
|
|
33402
33374
|
}
|
|
33403
33375
|
try {
|
|
33404
33376
|
maybeTriggerAutoReindex(ctx);
|
|
33405
33377
|
} catch (err) {
|
|
33406
|
-
|
|
33407
|
-
process.stderr.write(`[caveat:hook] auto reindex trigger error: ${msg}
|
|
33378
|
+
process.stderr.write(`[caveat:hook] auto reindex trigger error: ${errorMessage4(err)}
|
|
33408
33379
|
`);
|
|
33409
33380
|
}
|
|
33410
33381
|
try {
|
|
33411
33382
|
maybeTriggerAutoSync(ctx);
|
|
33412
33383
|
} catch (err) {
|
|
33413
|
-
|
|
33414
|
-
process.stderr.write(`[caveat:hook] auto sync trigger error: ${msg}
|
|
33384
|
+
process.stderr.write(`[caveat:hook] auto sync trigger error: ${errorMessage4(err)}
|
|
33415
33385
|
`);
|
|
33416
33386
|
}
|
|
33417
33387
|
}
|
|
@@ -33419,12 +33389,12 @@ async function runHook(name, arg) {
|
|
|
33419
33389
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
33420
33390
|
const signals = transcriptPath ? loadSignalsSafely(transcriptPath) : null;
|
|
33421
33391
|
if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
|
|
33422
|
-
const related = searchCaveatsSafely(signals.errorSnippets.map((failureText) => ({
|
|
33392
|
+
const related = searchCaveatsSafely(CLAUDE_HOST, signals.errorSnippets.map((failureText) => ({
|
|
33423
33393
|
topicText: "",
|
|
33424
33394
|
failureText,
|
|
33425
33395
|
surface: "stop"
|
|
33426
33396
|
})));
|
|
33427
|
-
queueStopForSession(sessionId, signals, related);
|
|
33397
|
+
queueStopForSession(CLAUDE_HOST, sessionId, signals, related, () => buildStopReminder(signals, related));
|
|
33428
33398
|
process.exit(0);
|
|
33429
33399
|
}
|
|
33430
33400
|
process.stderr.write(`[caveat:hook] unknown hook name: ${name}
|
|
@@ -33434,105 +33404,22 @@ async function runHook(name, arg) {
|
|
|
33434
33404
|
|
|
33435
33405
|
// src/commands/codexHookCmd.ts
|
|
33436
33406
|
import { spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
|
|
33437
|
-
import { existsSync as
|
|
33407
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
33438
33408
|
import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
|
|
33439
|
-
import { join as
|
|
33440
|
-
import {
|
|
33441
|
-
var
|
|
33442
|
-
|
|
33443
|
-
|
|
33444
|
-
|
|
33445
|
-
|
|
33446
|
-
|
|
33447
|
-
`)
|
|
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"
|
|
33448
33417
|
};
|
|
33449
|
-
var CODEX_MAX_CONTEXT_BLOCKS = 3;
|
|
33450
|
-
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:";
|
|
33451
|
-
var CODEX_STOP_STATE_DIR = "codex-stop-state";
|
|
33452
|
-
async function readStdin2() {
|
|
33453
|
-
const chunks = [];
|
|
33454
|
-
for await (const chunk of process.stdin) {
|
|
33455
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
33456
|
-
}
|
|
33457
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
33458
|
-
}
|
|
33459
|
-
function parsePayload2(raw) {
|
|
33460
|
-
if (!raw) return {};
|
|
33461
|
-
try {
|
|
33462
|
-
return JSON.parse(raw);
|
|
33463
|
-
} catch (err) {
|
|
33464
|
-
observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
|
|
33465
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33466
|
-
process.stderr.write(`[caveat:codex-hook] json parse error: ${msg}
|
|
33467
|
-
`);
|
|
33468
|
-
return {};
|
|
33469
|
-
}
|
|
33470
|
-
}
|
|
33471
|
-
function buildContextSafely2() {
|
|
33472
|
-
try {
|
|
33473
|
-
return buildContext(silentLogger2);
|
|
33474
|
-
} catch (err) {
|
|
33475
|
-
observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
|
|
33476
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33477
|
-
process.stderr.write(`[caveat:codex-hook] context error: ${msg}
|
|
33478
|
-
`);
|
|
33479
|
-
return null;
|
|
33480
|
-
}
|
|
33481
|
-
}
|
|
33482
|
-
function searchCaveatsSafely2(input) {
|
|
33483
|
-
const inputs = Array.isArray(input) ? input : [input];
|
|
33484
|
-
const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
|
|
33485
|
-
if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
|
|
33486
|
-
let db;
|
|
33487
|
-
let caveatHome;
|
|
33488
|
-
let hits;
|
|
33489
|
-
try {
|
|
33490
|
-
const ctx = buildContextSafely2();
|
|
33491
|
-
if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
|
|
33492
|
-
caveatHome = ctx.caveatHome;
|
|
33493
|
-
db = openDb({ path: ctx.paths.dbPath });
|
|
33494
|
-
const searchOptions = {
|
|
33495
|
-
selfIdentity: defaultSelfIdentityTokens()
|
|
33496
|
-
};
|
|
33497
|
-
hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
|
|
33498
|
-
} catch (err) {
|
|
33499
|
-
observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
|
|
33500
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33501
|
-
process.stderr.write(`[caveat:codex-hook] search error: ${msg}
|
|
33502
|
-
`);
|
|
33503
|
-
return [];
|
|
33504
|
-
}
|
|
33505
|
-
if (hits.length > 0) {
|
|
33506
|
-
try {
|
|
33507
|
-
markHit(db, hits);
|
|
33508
|
-
} catch (err) {
|
|
33509
|
-
observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
|
|
33510
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33511
|
-
process.stderr.write(`[caveat:codex-hook] markHit error: ${msg}
|
|
33512
|
-
`);
|
|
33513
|
-
}
|
|
33514
|
-
} else {
|
|
33515
|
-
try {
|
|
33516
|
-
logHookQueryMiss({ caveatHome, agent: "codex", surface: inputs[0].surface, query: queryForLog });
|
|
33517
|
-
} catch (err) {
|
|
33518
|
-
observeRuntimeError("CAVEAT.CODEX_HOOK_FAILED", { version: CAVEAT_VERSION });
|
|
33519
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33520
|
-
process.stderr.write(`[caveat:codex-hook] query log error: ${msg}
|
|
33521
|
-
`);
|
|
33522
|
-
}
|
|
33523
|
-
}
|
|
33524
|
-
try {
|
|
33525
|
-
return hits;
|
|
33526
|
-
} finally {
|
|
33527
|
-
db?.close();
|
|
33528
|
-
}
|
|
33529
|
-
}
|
|
33530
33418
|
function loadSignalsSafely2(path) {
|
|
33531
33419
|
try {
|
|
33532
33420
|
return readCodexSessionSignals(path);
|
|
33533
33421
|
} catch (err) {
|
|
33534
|
-
|
|
33535
|
-
process.stderr.write(`[caveat:codex-hook] transcript read error: ${msg}
|
|
33422
|
+
process.stderr.write(`[caveat:codex-hook] transcript read error: ${errorMessage4(err)}
|
|
33536
33423
|
`);
|
|
33537
33424
|
return null;
|
|
33538
33425
|
}
|
|
@@ -33541,29 +33428,6 @@ function codexSessionId(payload) {
|
|
|
33541
33428
|
const v = payload.session_id ?? payload.sessionId;
|
|
33542
33429
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
33543
33430
|
}
|
|
33544
|
-
function extractToolResponseText2(response) {
|
|
33545
|
-
if (typeof response === "string") return response;
|
|
33546
|
-
if (Array.isArray(response)) {
|
|
33547
|
-
return response.map((item) => {
|
|
33548
|
-
if (typeof item === "string") return item;
|
|
33549
|
-
if (item !== null && typeof item === "object") {
|
|
33550
|
-
const text = item.text;
|
|
33551
|
-
return typeof text === "string" ? text : "";
|
|
33552
|
-
}
|
|
33553
|
-
return "";
|
|
33554
|
-
}).filter(Boolean).join(" ");
|
|
33555
|
-
}
|
|
33556
|
-
if (response !== null && typeof response === "object") {
|
|
33557
|
-
const r = response;
|
|
33558
|
-
if (typeof r.content === "string") return r.content;
|
|
33559
|
-
if (Array.isArray(r.content)) return extractToolResponseText2(r.content);
|
|
33560
|
-
if (typeof r.output === "string") return r.output;
|
|
33561
|
-
if (typeof r.stdout === "string" || typeof r.stderr === "string") {
|
|
33562
|
-
return [r.stdout, r.stderr].filter((x) => typeof x === "string").join(" ");
|
|
33563
|
-
}
|
|
33564
|
-
}
|
|
33565
|
-
return "";
|
|
33566
|
-
}
|
|
33567
33431
|
function numericExitCode(v) {
|
|
33568
33432
|
return typeof v === "number" && Number.isInteger(v) ? v : null;
|
|
33569
33433
|
}
|
|
@@ -33572,10 +33436,10 @@ function processExitCodeFromText(text) {
|
|
|
33572
33436
|
return m ? Number(m[1]) : null;
|
|
33573
33437
|
}
|
|
33574
33438
|
function transcriptToolOutput(transcriptPath, toolUseId) {
|
|
33575
|
-
if (!transcriptPath || !toolUseId || !
|
|
33439
|
+
if (!transcriptPath || !toolUseId || !existsSync12(transcriptPath)) return null;
|
|
33576
33440
|
let raw = "";
|
|
33577
33441
|
try {
|
|
33578
|
-
raw =
|
|
33442
|
+
raw = readFileSync7(transcriptPath, "utf-8");
|
|
33579
33443
|
} catch {
|
|
33580
33444
|
return null;
|
|
33581
33445
|
}
|
|
@@ -33629,7 +33493,7 @@ function isCodexToolError(payload) {
|
|
|
33629
33493
|
const exit2 = numericExitCode(r.exit_code ?? r.exitCode);
|
|
33630
33494
|
if (exit2 !== null) return exit2 !== 0;
|
|
33631
33495
|
}
|
|
33632
|
-
const responseExit = processExitCodeFromText(
|
|
33496
|
+
const responseExit = processExitCodeFromText(extractToolResponseText(resp));
|
|
33633
33497
|
if (responseExit !== null) return responseExit !== 0;
|
|
33634
33498
|
const transcriptExit = transcriptExitCode(payload);
|
|
33635
33499
|
if (transcriptExit !== null) return transcriptExit !== 0;
|
|
@@ -33640,7 +33504,7 @@ function buildCodexPostToolUseWorkerJob(payload) {
|
|
|
33640
33504
|
if (!sessionId) return null;
|
|
33641
33505
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : void 0;
|
|
33642
33506
|
const toolUseId = typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0;
|
|
33643
|
-
const responseText =
|
|
33507
|
+
const responseText = extractToolResponseText(payload.tool_response ?? payload.toolResponse);
|
|
33644
33508
|
const inputText = toolInputText(payload.tool_input);
|
|
33645
33509
|
const transcriptOutput = transcriptPath && toolUseId ? transcriptToolOutput(transcriptPath, toolUseId) : null;
|
|
33646
33510
|
const topicText = inputText.trim();
|
|
@@ -33670,101 +33534,6 @@ function codexContextOutput(text, eventName = "UserPromptSubmit") {
|
|
|
33670
33534
|
}
|
|
33671
33535
|
});
|
|
33672
33536
|
}
|
|
33673
|
-
function codexPendingCleanupFailureText() {
|
|
33674
|
-
return "[caveat:codex-hook] pending reminder cleanup failed";
|
|
33675
|
-
}
|
|
33676
|
-
function drainForSession2(sessionId) {
|
|
33677
|
-
const ctx = buildContextSafely2();
|
|
33678
|
-
if (!ctx) return [];
|
|
33679
|
-
const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
|
|
33680
|
-
const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
|
|
33681
|
-
for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
|
|
33682
|
-
process.stderr.write(`${codexPendingCleanupFailureText()}
|
|
33683
|
-
`);
|
|
33684
|
-
}
|
|
33685
|
-
return [...local.reminders, ...global.reminders];
|
|
33686
|
-
}
|
|
33687
|
-
function codexContextDedupeKey(text) {
|
|
33688
|
-
if (text.startsWith(CODEX_STOP_REMINDER_PREFIX)) return "codex-stop-reminder";
|
|
33689
|
-
return text.trim();
|
|
33690
|
-
}
|
|
33691
|
-
function compactCodexContexts(contexts) {
|
|
33692
|
-
const selected = [];
|
|
33693
|
-
const seen = /* @__PURE__ */ new Set();
|
|
33694
|
-
for (let i = contexts.length - 1; i >= 0; i -= 1) {
|
|
33695
|
-
const text = contexts[i]?.trim();
|
|
33696
|
-
if (!text) continue;
|
|
33697
|
-
const key = codexContextDedupeKey(text);
|
|
33698
|
-
if (seen.has(key)) continue;
|
|
33699
|
-
seen.add(key);
|
|
33700
|
-
selected.push(text);
|
|
33701
|
-
}
|
|
33702
|
-
selected.reverse();
|
|
33703
|
-
const limited = selected.slice(-CODEX_MAX_CONTEXT_BLOCKS);
|
|
33704
|
-
const omitted = selected.length - limited.length;
|
|
33705
|
-
if (omitted > 0) {
|
|
33706
|
-
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`);
|
|
33707
|
-
}
|
|
33708
|
-
return limited;
|
|
33709
|
-
}
|
|
33710
|
-
function sanitizeCodexStateId(raw) {
|
|
33711
|
-
const clean = raw.replace(/[^A-Za-z0-9_-]/g, "");
|
|
33712
|
-
return clean.length > 0 ? clean : "_unknown";
|
|
33713
|
-
}
|
|
33714
|
-
function stopSignalKey2(signals, related) {
|
|
33715
|
-
const body = JSON.stringify({
|
|
33716
|
-
toolFailureCount: signals.toolFailureCount,
|
|
33717
|
-
fileEditCounts: signals.fileEditCounts.map((e) => [e.path, e.count]),
|
|
33718
|
-
webSearchCount: signals.webSearchCount,
|
|
33719
|
-
webFetchCount: signals.webFetchCount,
|
|
33720
|
-
bashRetryCount: signals.bashRetryCount,
|
|
33721
|
-
searchQueries: signals.searchQueries,
|
|
33722
|
-
related: related.map((h) => [h.source, h.id])
|
|
33723
|
-
});
|
|
33724
|
-
return createHash2("sha256").update(body).digest("hex");
|
|
33725
|
-
}
|
|
33726
|
-
function stopStatePath2(caveatHome, sessionId) {
|
|
33727
|
-
return join12(caveatHome, CODEX_STOP_STATE_DIR, `${sanitizeCodexStateId(sessionId)}.txt`);
|
|
33728
|
-
}
|
|
33729
|
-
function wasStopReminderQueued2(caveatHome, sessionId, key) {
|
|
33730
|
-
const path = stopStatePath2(caveatHome, sessionId);
|
|
33731
|
-
try {
|
|
33732
|
-
return readFileSync6(path, "utf-8") === key;
|
|
33733
|
-
} catch {
|
|
33734
|
-
return false;
|
|
33735
|
-
}
|
|
33736
|
-
}
|
|
33737
|
-
function markStopReminderQueued2(caveatHome, sessionId, key) {
|
|
33738
|
-
const path = stopStatePath2(caveatHome, sessionId);
|
|
33739
|
-
mkdirSync6(join12(caveatHome, CODEX_STOP_STATE_DIR), { recursive: true });
|
|
33740
|
-
writeFileSync6(path, key, "utf-8");
|
|
33741
|
-
}
|
|
33742
|
-
function queueStopForSession2(sessionId, signals, related) {
|
|
33743
|
-
const ctx = buildContextSafely2();
|
|
33744
|
-
if (!ctx) return;
|
|
33745
|
-
const key = stopSignalKey2(signals, related);
|
|
33746
|
-
if (wasStopReminderQueued2(ctx.caveatHome, sessionId, key)) return;
|
|
33747
|
-
let result;
|
|
33748
|
-
try {
|
|
33749
|
-
result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
|
|
33750
|
-
agent: "codex",
|
|
33751
|
-
surface: "stop",
|
|
33752
|
-
refs: related,
|
|
33753
|
-
stopSignalDigest: key
|
|
33754
|
-
}), () => stopReminderText(signals, related));
|
|
33755
|
-
} catch {
|
|
33756
|
-
process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
|
|
33757
|
-
return;
|
|
33758
|
-
}
|
|
33759
|
-
if (!result.ran) return;
|
|
33760
|
-
try {
|
|
33761
|
-
markStopReminderQueued2(ctx.caveatHome, sessionId, key);
|
|
33762
|
-
} catch (err) {
|
|
33763
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
33764
|
-
process.stderr.write(`[caveat:codex-hook] pending reminder write error: ${msg}
|
|
33765
|
-
`);
|
|
33766
|
-
}
|
|
33767
|
-
}
|
|
33768
33537
|
async function waitForTranscriptOutput(transcriptPath, toolUseId) {
|
|
33769
33538
|
const deadline = Date.now() + 2e3;
|
|
33770
33539
|
while (Date.now() <= deadline) {
|
|
@@ -33790,13 +33559,13 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
|
33790
33559
|
}
|
|
33791
33560
|
}
|
|
33792
33561
|
if (!knownError && job.allowSymptomOnly !== true) return;
|
|
33793
|
-
const hits =
|
|
33562
|
+
const hits = searchCaveatsSafely(CODEX_HOST, {
|
|
33794
33563
|
topicText: job.topicText,
|
|
33795
33564
|
failureText,
|
|
33796
33565
|
surface: "tool_error"
|
|
33797
33566
|
});
|
|
33798
33567
|
if (hits.length === 0) return;
|
|
33799
|
-
const ctx =
|
|
33568
|
+
const ctx = buildContextSafely(CODEX_HOST);
|
|
33800
33569
|
if (!ctx) return;
|
|
33801
33570
|
let result;
|
|
33802
33571
|
try {
|
|
@@ -33814,7 +33583,7 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
|
33814
33583
|
async function runCodexWorker(workFile) {
|
|
33815
33584
|
let raw;
|
|
33816
33585
|
try {
|
|
33817
|
-
raw =
|
|
33586
|
+
raw = readFileSync7(workFile, "utf-8");
|
|
33818
33587
|
} catch {
|
|
33819
33588
|
process.exit(0);
|
|
33820
33589
|
}
|
|
@@ -33831,7 +33600,7 @@ async function runCodexWorker(workFile) {
|
|
|
33831
33600
|
await processCodexWorkerJob(job);
|
|
33832
33601
|
process.exit(0);
|
|
33833
33602
|
}
|
|
33834
|
-
function runDiagnostics(codexHome = process.env.CODEX_HOME ??
|
|
33603
|
+
function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join13(homedir3(), ".codex")) {
|
|
33835
33604
|
const features = spawnSync5("codex", ["features", "list"], {
|
|
33836
33605
|
encoding: "utf-8",
|
|
33837
33606
|
maxBuffer: 1024 * 1024,
|
|
@@ -33869,24 +33638,23 @@ async function runCodexHook(name, arg) {
|
|
|
33869
33638
|
}
|
|
33870
33639
|
let raw = "";
|
|
33871
33640
|
try {
|
|
33872
|
-
raw = await
|
|
33641
|
+
raw = await readStdin();
|
|
33873
33642
|
} catch (err) {
|
|
33874
|
-
|
|
33875
|
-
process.stderr.write(`[caveat:codex-hook] stdin read error: ${msg}
|
|
33643
|
+
process.stderr.write(`[caveat:codex-hook] stdin read error: ${errorMessage4(err)}
|
|
33876
33644
|
`);
|
|
33877
33645
|
process.exit(0);
|
|
33878
33646
|
}
|
|
33879
|
-
const payload =
|
|
33647
|
+
const payload = parsePayload(CODEX_HOST, raw);
|
|
33880
33648
|
const sessionId = codexSessionId(payload);
|
|
33881
33649
|
if (!sessionId) process.stderr.write("[caveat:codex-hook] missing session_id; pending drain disabled\n");
|
|
33882
33650
|
if (name === "user-prompt-submit") {
|
|
33883
|
-
const contexts = sessionId ?
|
|
33651
|
+
const contexts = sessionId ? drainForSession(CODEX_HOST, sessionId) : [];
|
|
33884
33652
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
33885
|
-
const hits =
|
|
33653
|
+
const hits = searchCaveatsSafely(CODEX_HOST, { topicText: prompt, failureText: prompt, surface: "user_prompt" });
|
|
33886
33654
|
if (hits.length > 0) {
|
|
33887
33655
|
contexts.push(userPromptSubmitReminderText(hits));
|
|
33888
33656
|
}
|
|
33889
|
-
const compacted =
|
|
33657
|
+
const compacted = compactContexts(CODEX_HOST, contexts);
|
|
33890
33658
|
if (compacted.length > 0) {
|
|
33891
33659
|
process.stdout.write(`${codexContextOutput(compacted.join("\n\n"))}
|
|
33892
33660
|
`);
|
|
@@ -33900,39 +33668,36 @@ async function runCodexHook(name, arg) {
|
|
|
33900
33668
|
}
|
|
33901
33669
|
if (name === "stop") {
|
|
33902
33670
|
try {
|
|
33903
|
-
const ctx =
|
|
33671
|
+
const ctx = buildContextSafely(CODEX_HOST);
|
|
33904
33672
|
if (ctx) {
|
|
33905
33673
|
try {
|
|
33906
33674
|
maybeSweepPendingDirs(ctx.caveatHome);
|
|
33907
33675
|
} catch (err) {
|
|
33908
|
-
|
|
33909
|
-
process.stderr.write(`[caveat:codex-hook] pending sweep error: ${msg}
|
|
33676
|
+
process.stderr.write(`[caveat:codex-hook] pending sweep error: ${errorMessage4(err)}
|
|
33910
33677
|
`);
|
|
33911
33678
|
}
|
|
33912
33679
|
maybeTriggerAutoReindex(ctx);
|
|
33913
33680
|
try {
|
|
33914
33681
|
maybeTriggerAutoSync(ctx);
|
|
33915
33682
|
} catch (err) {
|
|
33916
|
-
|
|
33917
|
-
process.stderr.write(`[caveat:codex-hook] auto sync trigger error: ${msg}
|
|
33683
|
+
process.stderr.write(`[caveat:codex-hook] auto sync trigger error: ${errorMessage4(err)}
|
|
33918
33684
|
`);
|
|
33919
33685
|
}
|
|
33920
33686
|
}
|
|
33921
33687
|
} catch (err) {
|
|
33922
|
-
|
|
33923
|
-
process.stderr.write(`[caveat:codex-hook] auto reindex trigger error: ${msg}
|
|
33688
|
+
process.stderr.write(`[caveat:codex-hook] auto reindex trigger error: ${errorMessage4(err)}
|
|
33924
33689
|
`);
|
|
33925
33690
|
}
|
|
33926
33691
|
if (payload.stop_hook_active === true) process.exit(0);
|
|
33927
33692
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
33928
33693
|
const signals = transcriptPath ? loadSignalsSafely2(transcriptPath) : null;
|
|
33929
33694
|
if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
|
|
33930
|
-
const related =
|
|
33695
|
+
const related = searchCaveatsSafely(CODEX_HOST, signals.errorSnippets.map((failureText) => ({
|
|
33931
33696
|
topicText: "",
|
|
33932
33697
|
failureText,
|
|
33933
33698
|
surface: "stop"
|
|
33934
33699
|
})));
|
|
33935
|
-
if (sessionId)
|
|
33700
|
+
if (sessionId) queueStopForSession(CODEX_HOST, sessionId, signals, related, () => stopReminderText(signals, related));
|
|
33936
33701
|
process.exit(0);
|
|
33937
33702
|
}
|
|
33938
33703
|
process.stderr.write(`[caveat:codex-hook] unknown hook name: ${name}
|
|
@@ -33941,9 +33706,9 @@ async function runCodexHook(name, arg) {
|
|
|
33941
33706
|
}
|
|
33942
33707
|
|
|
33943
33708
|
// src/commands/pull.ts
|
|
33944
|
-
import { existsSync as
|
|
33709
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
33945
33710
|
async function runPull(ctx) {
|
|
33946
|
-
const hasCommunityDir =
|
|
33711
|
+
const hasCommunityDir = existsSync13(ctx.paths.communityDir);
|
|
33947
33712
|
if (!hasCommunityDir) {
|
|
33948
33713
|
ctx.logger.info(
|
|
33949
33714
|
"no community repos yet \u2014 add one with `caveat community add <github-url>`."
|
|
@@ -34043,9 +33808,9 @@ async function runSync(ctx, opts, dependencies = {}) {
|
|
|
34043
33808
|
|
|
34044
33809
|
// src/commands/codexSidecar.ts
|
|
34045
33810
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
34046
|
-
import { closeSync, constants as constants3, fstatSync, lstatSync as lstatSync2, mkdirSync as
|
|
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";
|
|
34047
33812
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
34048
|
-
import { basename as basename2, dirname as
|
|
33813
|
+
import { basename as basename2, dirname as dirname6, join as join14 } from "node:path";
|
|
34049
33814
|
import { cwd, exit } from "node:process";
|
|
34050
33815
|
function runCodexSidecarDiagnostics(logger, opts) {
|
|
34051
33816
|
const plan = buildCodexSidecarDiagnosticsCommand({
|
|
@@ -34077,8 +33842,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
|
|
|
34077
33842
|
process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
|
|
34078
33843
|
exit(0);
|
|
34079
33844
|
}
|
|
34080
|
-
const contextDir = mkdtempSync3(
|
|
34081
|
-
const contextFile =
|
|
33845
|
+
const contextDir = mkdtempSync3(join14(tmpdir4(), "caveat-sidecar-context-"));
|
|
33846
|
+
const contextFile = join14(contextDir, "context.json");
|
|
34082
33847
|
let status2 = 1;
|
|
34083
33848
|
try {
|
|
34084
33849
|
const blocks = collectCaveatContextBlocks(ctx, {
|
|
@@ -34143,16 +33908,16 @@ function readHookSignalAdditionalContextFile(path, testProbe) {
|
|
|
34143
33908
|
return [block];
|
|
34144
33909
|
}
|
|
34145
33910
|
function assertPrivateRegular(stat, uid, platform) {
|
|
34146
|
-
const privateOwner =
|
|
33911
|
+
const privateOwner = isPrivateOwnerStat(stat, uid, platform);
|
|
34147
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");
|
|
34148
33913
|
}
|
|
34149
33914
|
function assertWindowsPrivateTempContainer(path, platform) {
|
|
34150
|
-
if (platform
|
|
34151
|
-
const parent =
|
|
33915
|
+
if (!isWindows(platform)) return;
|
|
33916
|
+
const parent = dirname6(path);
|
|
34152
33917
|
const parentStat = lstatSync2(parent);
|
|
34153
|
-
const resolvedParent =
|
|
34154
|
-
const resolvedTemp =
|
|
34155
|
-
if (parentStat.isSymbolicLink() || !parentStat.isDirectory() ||
|
|
33918
|
+
const resolvedParent = realpathSync4(parent);
|
|
33919
|
+
const resolvedTemp = realpathSync4(tmpdir4());
|
|
33920
|
+
if (parentStat.isSymbolicLink() || !parentStat.isDirectory() || dirname6(resolvedParent) !== resolvedTemp || !basename2(resolvedParent).startsWith("caveat-")) {
|
|
34156
33921
|
throw new Error("additional context file must be inside a reserved per-user Caveat temporary directory");
|
|
34157
33922
|
}
|
|
34158
33923
|
}
|
|
@@ -34241,7 +34006,7 @@ function executePlan(logger, command, args, options = {}) {
|
|
|
34241
34006
|
}
|
|
34242
34007
|
function saveStructuredResult(path, stdout) {
|
|
34243
34008
|
const parsed = JSON.parse(stdout);
|
|
34244
|
-
|
|
34009
|
+
mkdirSync6(dirname6(path), { recursive: true });
|
|
34245
34010
|
writeFileSync7(path, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
34246
34011
|
}
|
|
34247
34012
|
function shellDisplayQuote(value) {
|
|
@@ -34330,8 +34095,8 @@ function runCommunityRemove(ctx, handle, opts) {
|
|
|
34330
34095
|
|
|
34331
34096
|
// src/commands/factoryDiagnostics.ts
|
|
34332
34097
|
import { execFileSync } from "node:child_process";
|
|
34333
|
-
import { existsSync as
|
|
34334
|
-
import { join as
|
|
34098
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
34099
|
+
import { join as join15 } from "node:path";
|
|
34335
34100
|
import { DatabaseSync } from "node:sqlite";
|
|
34336
34101
|
import { parse as parseToml2 } from "smol-toml";
|
|
34337
34102
|
var status = (ok, reason) => ({ status: ok ? "ready" : "not_ready", reason_code: ok ? "ready" : reason });
|
|
@@ -34343,10 +34108,10 @@ function isRecord2(value) {
|
|
|
34343
34108
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34344
34109
|
}
|
|
34345
34110
|
function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
34346
|
-
const path =
|
|
34347
|
-
if (!
|
|
34111
|
+
const path = join15(home, ".claude.json");
|
|
34112
|
+
if (!existsSync14(path)) return status(false, "not_registered");
|
|
34348
34113
|
try {
|
|
34349
|
-
const value = JSON.parse(
|
|
34114
|
+
const value = JSON.parse(readFileSync8(path, "utf8"));
|
|
34350
34115
|
if (!isRecord2(value) || !isRecord2(value.mcpServers)) return status(false, "not_registered");
|
|
34351
34116
|
return status(isCaveatClaudeMcpRegistration(value.mcpServers.caveat, nodePath, cliScriptPath), "not_registered");
|
|
34352
34117
|
} catch {
|
|
@@ -34355,7 +34120,7 @@ function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
|
34355
34120
|
}
|
|
34356
34121
|
function claudeHooks(home, nodePath, cliScriptPath) {
|
|
34357
34122
|
try {
|
|
34358
|
-
const settings = JSON.parse(
|
|
34123
|
+
const settings = JSON.parse(readFileSync8(join15(home, ".claude", "settings.json"), "utf8"));
|
|
34359
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;
|
|
34360
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")) };
|
|
34361
34126
|
} catch {
|
|
@@ -34377,7 +34142,7 @@ function strictSearchSchema(db) {
|
|
|
34377
34142
|
return columns.map((column) => `${column.name}:${column.hidden}`).join(",") === "id:0,title:0,body:0,tags:0,entries_fts:1,rank:1";
|
|
34378
34143
|
}
|
|
34379
34144
|
function database(path) {
|
|
34380
|
-
if (!
|
|
34145
|
+
if (!existsSync14(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
|
|
34381
34146
|
try {
|
|
34382
34147
|
const db = new DatabaseSync(path, { readOnly: true });
|
|
34383
34148
|
try {
|
|
@@ -34402,10 +34167,10 @@ function database(path) {
|
|
|
34402
34167
|
}
|
|
34403
34168
|
}
|
|
34404
34169
|
function codexFeature(codexHome) {
|
|
34405
|
-
const path =
|
|
34406
|
-
if (!
|
|
34170
|
+
const path = join15(codexHome, "config.toml");
|
|
34171
|
+
if (!existsSync14(path)) return status(false, "feature_disabled");
|
|
34407
34172
|
try {
|
|
34408
|
-
const config2 = parseToml2(
|
|
34173
|
+
const config2 = parseToml2(readFileSync8(path, "utf8"));
|
|
34409
34174
|
if (!isRecord2(config2.features)) return status(false, "feature_disabled");
|
|
34410
34175
|
const features = config2.features;
|
|
34411
34176
|
return status(features.hooks === true && features.codex_hooks === void 0, "feature_disabled");
|
|
@@ -34414,7 +34179,7 @@ function codexFeature(codexHome) {
|
|
|
34414
34179
|
}
|
|
34415
34180
|
}
|
|
34416
34181
|
function codexHooks(codexHome, nodePath, cliScriptPath) {
|
|
34417
|
-
const value = JSON.parse(
|
|
34182
|
+
const value = JSON.parse(readFileSync8(join15(codexHome, "hooks.json"), "utf8"));
|
|
34418
34183
|
if (!isRecord2(value) || !isRecord2(value.hooks)) throw Error("config_unreadable");
|
|
34419
34184
|
const hooks = value.hooks;
|
|
34420
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)));
|
|
@@ -34449,7 +34214,7 @@ function sync(own) {
|
|
|
34449
34214
|
return unverified("upstream_unavailable");
|
|
34450
34215
|
}
|
|
34451
34216
|
}
|
|
34452
|
-
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ??
|
|
34217
|
+
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join15(ctx.userHome, ".codex")) {
|
|
34453
34218
|
const nodePath = process.execPath;
|
|
34454
34219
|
const cliScriptPath = process.argv[1] ?? "";
|
|
34455
34220
|
const db = database(ctx.paths.dbPath);
|