caveat-cli 0.14.7 → 0.14.9
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-EH3S6X6X.js → chunk-ECC5LJZF.js} +102 -6
- package/dist/{chunk-EH3S6X6X.js.map → chunk-ECC5LJZF.js.map} +1 -1
- package/dist/index.js +196 -98
- package/dist/index.js.map +1 -1
- package/dist/{server-RWVXGVXK.js → server-YQ4DJ2H7.js} +2 -2
- package/package.json +12 -12
- /package/dist/{server-RWVXGVXK.js.map → server-YQ4DJ2H7.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
buildCodexSidecarReadOnlySmokeCommand,
|
|
11
11
|
buildCodexSidecarRunCommand,
|
|
12
12
|
caveatEntriesToSidecarContextBlocks,
|
|
13
|
+
cleanupStalePendingDirs,
|
|
13
14
|
communityAdd,
|
|
14
15
|
communityList,
|
|
15
16
|
communityPull,
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
listStale,
|
|
27
28
|
loadConfig,
|
|
28
29
|
markHit,
|
|
30
|
+
maybeSweepPendingDirs,
|
|
29
31
|
openDb,
|
|
30
32
|
readCodexSessionSignals,
|
|
31
33
|
readSessionSignals,
|
|
@@ -40,7 +42,7 @@ import {
|
|
|
40
42
|
toolErrorReminderText,
|
|
41
43
|
updateEntry,
|
|
42
44
|
userPromptSubmitReminderText
|
|
43
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-ECC5LJZF.js";
|
|
44
46
|
|
|
45
47
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
46
48
|
var require_code = __commonJS({
|
|
@@ -6852,8 +6854,8 @@ var stdoutLogger = {
|
|
|
6852
6854
|
};
|
|
6853
6855
|
|
|
6854
6856
|
// src/commands/init.ts
|
|
6855
|
-
import { existsSync as
|
|
6856
|
-
import { dirname as dirname3, join as
|
|
6857
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, renameSync, rmdirSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
6858
|
+
import { dirname as dirname3, join as join5 } from "node:path";
|
|
6857
6859
|
|
|
6858
6860
|
// src/claudeInstall.ts
|
|
6859
6861
|
import { spawnSync } from "node:child_process";
|
|
@@ -6875,10 +6877,16 @@ function hookCommand(nodePath, cliScriptPath, event) {
|
|
|
6875
6877
|
function upsertHook(settings, event, command) {
|
|
6876
6878
|
settings.hooks ??= {};
|
|
6877
6879
|
const list = settings.hooks[event] ??= [];
|
|
6878
|
-
const
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6880
|
+
const subcommand = command.includes("hook user-prompt-submit") ? "user-prompt-submit" : command.includes("hook post-tool-use") ? "post-tool-use" : command.includes("hook stop") ? "stop" : null;
|
|
6881
|
+
for (const entry of list) {
|
|
6882
|
+
for (const hook of entry.hooks ?? []) {
|
|
6883
|
+
if (isSameHookCommand(hook.command, command)) return "unchanged";
|
|
6884
|
+
if (subcommand && isCaveatClaudeHookCommand(hook.command, subcommand)) {
|
|
6885
|
+
hook.command = command;
|
|
6886
|
+
return "added";
|
|
6887
|
+
}
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6882
6890
|
list.push({ hooks: [{ type: "command", command }] });
|
|
6883
6891
|
return "added";
|
|
6884
6892
|
}
|
|
@@ -6905,6 +6913,13 @@ function findExistingHookCommand(settings, event, command) {
|
|
|
6905
6913
|
function isSameHookCommand(actual, expected) {
|
|
6906
6914
|
return actual === expected || actual.endsWith(` ${expected}`);
|
|
6907
6915
|
}
|
|
6916
|
+
function isEnvPrefixedCommand(command) {
|
|
6917
|
+
return /^[A-Z_][A-Z0-9_]*=/.test(command.trim());
|
|
6918
|
+
}
|
|
6919
|
+
function isCaveatClaudeHookCommand(actual, event) {
|
|
6920
|
+
const lower = actual.toLowerCase();
|
|
6921
|
+
return !isEnvPrefixedCommand(actual) && lower.includes("caveat") && actual.includes(`hook ${event}`);
|
|
6922
|
+
}
|
|
6908
6923
|
function readSettings(path) {
|
|
6909
6924
|
if (!existsSync(path)) return {};
|
|
6910
6925
|
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
@@ -7035,6 +7050,40 @@ function uninstallClaudeIntegration(opts) {
|
|
|
7035
7050
|
};
|
|
7036
7051
|
}
|
|
7037
7052
|
|
|
7053
|
+
// src/nodePath.ts
|
|
7054
|
+
import { existsSync as existsSync2, realpathSync } from "node:fs";
|
|
7055
|
+
import { delimiter, join as join4 } from "node:path";
|
|
7056
|
+
var defaultRealpath = (path) => realpathSync.native(path);
|
|
7057
|
+
function safeRealpath(path, realpath = defaultRealpath) {
|
|
7058
|
+
try {
|
|
7059
|
+
return realpath(path);
|
|
7060
|
+
} catch {
|
|
7061
|
+
return null;
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
function resolveHookNodePath({
|
|
7065
|
+
env = process.env,
|
|
7066
|
+
execPath = process.execPath,
|
|
7067
|
+
platform = process.platform,
|
|
7068
|
+
exists = existsSync2,
|
|
7069
|
+
realpath = defaultRealpath
|
|
7070
|
+
} = {}) {
|
|
7071
|
+
const execRealpath = safeRealpath(execPath, realpath);
|
|
7072
|
+
const pathEnv = env.PATH ?? env.Path ?? "";
|
|
7073
|
+
const names = platform === "win32" ? ["node.exe", "node.cmd", "node.bat", "node"] : ["node"];
|
|
7074
|
+
for (const dir of pathEnv.split(delimiter).filter(Boolean)) {
|
|
7075
|
+
for (const name of names) {
|
|
7076
|
+
const candidate = join4(dir, name);
|
|
7077
|
+
if (!exists(candidate)) continue;
|
|
7078
|
+
const candidateRealpath = safeRealpath(candidate, realpath);
|
|
7079
|
+
if (execRealpath && candidateRealpath && candidateRealpath === execRealpath) {
|
|
7080
|
+
return candidate;
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
return execPath;
|
|
7085
|
+
}
|
|
7086
|
+
|
|
7038
7087
|
// src/commands/init.ts
|
|
7039
7088
|
var KNOWLEDGE_GITIGNORE = [
|
|
7040
7089
|
"# Never commit entries flagged private (visibility: private is enforced by the",
|
|
@@ -7048,7 +7097,7 @@ var KNOWLEDGE_GITIGNORE = [
|
|
|
7048
7097
|
async function runInit(ctx, opts = { skipClaude: false, dryRun: false }) {
|
|
7049
7098
|
ensureUserConfig(ctx.userConfigPath);
|
|
7050
7099
|
ctx.logger.info(`user config: ${ctx.userConfigPath}`);
|
|
7051
|
-
if (!
|
|
7100
|
+
if (!existsSync3(ctx.paths.knowledgeRepo)) {
|
|
7052
7101
|
mkdirSync2(ctx.paths.knowledgeRepo, { recursive: true });
|
|
7053
7102
|
mkdirSync2(ctx.paths.entriesDir, { recursive: true });
|
|
7054
7103
|
ctx.logger.info(`knowledge repo scaffolded: ${ctx.paths.knowledgeRepo}`);
|
|
@@ -7056,20 +7105,31 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }) {
|
|
|
7056
7105
|
ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
|
|
7057
7106
|
}
|
|
7058
7107
|
migrateLegacyCommunityDir(ctx);
|
|
7059
|
-
const gitignorePath =
|
|
7060
|
-
if (!
|
|
7108
|
+
const gitignorePath = join5(ctx.paths.knowledgeRepo, ".gitignore");
|
|
7109
|
+
if (!existsSync3(gitignorePath)) {
|
|
7061
7110
|
writeFileSync2(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
|
|
7062
7111
|
ctx.logger.info(`.gitignore created: ${gitignorePath}`);
|
|
7063
7112
|
}
|
|
7064
7113
|
if (!opts.dryRun) {
|
|
7065
7114
|
const dbDir = dirname3(ctx.paths.dbPath);
|
|
7066
|
-
if (!
|
|
7115
|
+
if (!existsSync3(dbDir)) mkdirSync2(dbDir, { recursive: true });
|
|
7067
7116
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
7068
7117
|
db.close();
|
|
7069
7118
|
ctx.logger.info(`db initialized: ${ctx.paths.dbPath}`);
|
|
7070
7119
|
} else {
|
|
7071
7120
|
ctx.logger.info(`[dry-run] db path: ${ctx.paths.dbPath}`);
|
|
7072
7121
|
}
|
|
7122
|
+
const staleDays = opts.pendingStaleDays ?? 7;
|
|
7123
|
+
if (opts.dryRun) {
|
|
7124
|
+
ctx.logger.info(`[dry-run] would sweep pending dirs older than ${staleDays}d`);
|
|
7125
|
+
} else {
|
|
7126
|
+
const swept = cleanupStalePendingDirs(ctx.caveatHome, { staleDays });
|
|
7127
|
+
if (swept.removed.length > 0) {
|
|
7128
|
+
ctx.logger.info(
|
|
7129
|
+
`pending dirs swept: removed ${swept.removed.length} (kept ${swept.kept}, threshold ${staleDays}d)`
|
|
7130
|
+
);
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7073
7133
|
ctx.logger.info(
|
|
7074
7134
|
"tip: subscribe to a group repo with `caveat community add <github-url>`, then `caveat pull`."
|
|
7075
7135
|
);
|
|
@@ -7083,20 +7143,20 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }) {
|
|
|
7083
7143
|
return;
|
|
7084
7144
|
}
|
|
7085
7145
|
const result = installClaudeIntegration({
|
|
7086
|
-
claudeDir:
|
|
7146
|
+
claudeDir: join5(ctx.userHome, ".claude"),
|
|
7087
7147
|
cliScriptPath,
|
|
7088
|
-
nodePath:
|
|
7148
|
+
nodePath: resolveHookNodePath(),
|
|
7089
7149
|
dryRun: opts.dryRun,
|
|
7090
7150
|
logger: ctx.logger
|
|
7091
7151
|
});
|
|
7092
7152
|
reportInstallResult(ctx, result, opts.dryRun);
|
|
7093
7153
|
}
|
|
7094
7154
|
function migrateLegacyCommunityDir(ctx) {
|
|
7095
|
-
const legacy =
|
|
7155
|
+
const legacy = join5(ctx.paths.knowledgeRepo, "community");
|
|
7096
7156
|
const current = ctx.paths.communityDir;
|
|
7097
7157
|
if (legacy === current) return;
|
|
7098
|
-
if (!
|
|
7099
|
-
if (
|
|
7158
|
+
if (!existsSync3(legacy)) return;
|
|
7159
|
+
if (existsSync3(current)) {
|
|
7100
7160
|
ctx.logger.warn(
|
|
7101
7161
|
`legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
|
|
7102
7162
|
);
|
|
@@ -7105,7 +7165,7 @@ function migrateLegacyCommunityDir(ctx) {
|
|
|
7105
7165
|
mkdirSync2(current, { recursive: true });
|
|
7106
7166
|
for (const entry of readdirSync(legacy, { withFileTypes: true })) {
|
|
7107
7167
|
if (!entry.isDirectory()) continue;
|
|
7108
|
-
renameSync(
|
|
7168
|
+
renameSync(join5(legacy, entry.name), join5(current, entry.name));
|
|
7109
7169
|
}
|
|
7110
7170
|
try {
|
|
7111
7171
|
rmdirSync(legacy);
|
|
@@ -7120,9 +7180,9 @@ function runUninstall(ctx, opts) {
|
|
|
7120
7180
|
process.exit(1);
|
|
7121
7181
|
}
|
|
7122
7182
|
const result = uninstallClaudeIntegration({
|
|
7123
|
-
claudeDir:
|
|
7183
|
+
claudeDir: join5(ctx.userHome, ".claude"),
|
|
7124
7184
|
cliScriptPath,
|
|
7125
|
-
nodePath:
|
|
7185
|
+
nodePath: resolveHookNodePath(),
|
|
7126
7186
|
dryRun: opts.dryRun,
|
|
7127
7187
|
logger: ctx.logger
|
|
7128
7188
|
});
|
|
@@ -7167,29 +7227,29 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
7167
7227
|
}
|
|
7168
7228
|
|
|
7169
7229
|
// src/commands/indexCmd.ts
|
|
7170
|
-
import { existsSync as
|
|
7171
|
-
import { dirname as dirname4, join as
|
|
7230
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, mkdirSync as mkdirSync3 } from "node:fs";
|
|
7231
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
7172
7232
|
function runIndex(ctx, opts) {
|
|
7173
7233
|
const dbDir = dirname4(ctx.paths.dbPath);
|
|
7174
|
-
if (!
|
|
7234
|
+
if (!existsSync4(dbDir)) mkdirSync3(dbDir, { recursive: true });
|
|
7175
7235
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
7176
7236
|
try {
|
|
7177
7237
|
if (opts.full) {
|
|
7178
7238
|
ctx.logger.info("full rebuild: DELETE FROM entries");
|
|
7179
7239
|
rebuildAll(db);
|
|
7180
7240
|
}
|
|
7181
|
-
if (
|
|
7241
|
+
if (existsSync4(ctx.paths.entriesDir)) {
|
|
7182
7242
|
const result = scanSource({ db, source: "own", entriesRoot: ctx.paths.entriesDir });
|
|
7183
7243
|
ctx.logger.info(`own: +${result.added} ~${result.updated} -${result.deleted}`);
|
|
7184
7244
|
} else {
|
|
7185
7245
|
ctx.logger.warn(`entries dir not found: ${ctx.paths.entriesDir}`);
|
|
7186
7246
|
}
|
|
7187
|
-
if (
|
|
7247
|
+
if (existsSync4(ctx.paths.communityDir)) {
|
|
7188
7248
|
for (const entry of readdirSync2(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
7189
7249
|
if (!entry.isDirectory()) continue;
|
|
7190
7250
|
const source = `community/${entry.name}`;
|
|
7191
|
-
const root =
|
|
7192
|
-
if (!
|
|
7251
|
+
const root = join6(ctx.paths.communityDir, entry.name, "entries");
|
|
7252
|
+
if (!existsSync4(root)) continue;
|
|
7193
7253
|
const result = scanSource({ db, source, entriesRoot: root });
|
|
7194
7254
|
ctx.logger.info(`${source}: +${result.added} ~${result.updated} -${result.deleted}`);
|
|
7195
7255
|
}
|
|
@@ -7345,7 +7405,7 @@ function runStats(ctx) {
|
|
|
7345
7405
|
|
|
7346
7406
|
// src/commands/serve.ts
|
|
7347
7407
|
async function runServe(opts) {
|
|
7348
|
-
const { startServer } = await import("./server-
|
|
7408
|
+
const { startServer } = await import("./server-YQ4DJ2H7.js");
|
|
7349
7409
|
const { port, host } = startServer({ port: opts.port });
|
|
7350
7410
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
7351
7411
|
`);
|
|
@@ -12599,8 +12659,8 @@ function emoji() {
|
|
|
12599
12659
|
}
|
|
12600
12660
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
12601
12661
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
12602
|
-
var mac = (
|
|
12603
|
-
const escapedDelim = escapeRegex(
|
|
12662
|
+
var mac = (delimiter2) => {
|
|
12663
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
12604
12664
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
12605
12665
|
};
|
|
12606
12666
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -31417,11 +31477,11 @@ var StdioServerTransport = class {
|
|
|
31417
31477
|
|
|
31418
31478
|
// ../mcp/dist/context.js
|
|
31419
31479
|
import { homedir as homedir2 } from "node:os";
|
|
31420
|
-
import { join as
|
|
31480
|
+
import { join as join7 } from "node:path";
|
|
31421
31481
|
function buildMcpContext(overrides = {}) {
|
|
31422
31482
|
const userHome = overrides.userHome ?? homedir2();
|
|
31423
31483
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
31424
|
-
const userConfigPath =
|
|
31484
|
+
const userConfigPath = join7(userHome, ".caveatrc.json");
|
|
31425
31485
|
const logger = overrides.logger ?? stderrLogger;
|
|
31426
31486
|
const config2 = loadConfig(userConfigPath);
|
|
31427
31487
|
const paths = resolvePaths(caveatHome, config2.knowledgeRepo, userHome);
|
|
@@ -31556,13 +31616,13 @@ function handleListRecent(ctx, args) {
|
|
|
31556
31616
|
}
|
|
31557
31617
|
|
|
31558
31618
|
// ../mcp/dist/tools/pull.js
|
|
31559
|
-
import { existsSync as
|
|
31560
|
-
import { join as
|
|
31619
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3 } from "node:fs";
|
|
31620
|
+
import { join as join8 } from "node:path";
|
|
31561
31621
|
var pullInputShape = {};
|
|
31562
31622
|
async function handlePull(ctx, _args = {}) {
|
|
31563
31623
|
const pulled = [];
|
|
31564
31624
|
const indexed = [];
|
|
31565
|
-
if (
|
|
31625
|
+
if (existsSync5(ctx.paths.communityDir)) {
|
|
31566
31626
|
const results = await communityPull({
|
|
31567
31627
|
communityDir: ctx.paths.communityDir,
|
|
31568
31628
|
logger: ctx.logger
|
|
@@ -31572,16 +31632,16 @@ async function handlePull(ctx, _args = {}) {
|
|
|
31572
31632
|
}
|
|
31573
31633
|
}
|
|
31574
31634
|
rebuildAll(ctx.db);
|
|
31575
|
-
if (
|
|
31635
|
+
if (existsSync5(ctx.paths.entriesDir)) {
|
|
31576
31636
|
const own = scanSource({ db: ctx.db, source: "own", entriesRoot: ctx.paths.entriesDir });
|
|
31577
31637
|
indexed.push({ source: "own", ...own });
|
|
31578
31638
|
}
|
|
31579
|
-
if (
|
|
31639
|
+
if (existsSync5(ctx.paths.communityDir)) {
|
|
31580
31640
|
for (const entry of readdirSync3(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
31581
31641
|
if (!entry.isDirectory()) continue;
|
|
31582
31642
|
const source = `community/${entry.name}`;
|
|
31583
|
-
const root =
|
|
31584
|
-
if (!
|
|
31643
|
+
const root = join8(ctx.paths.communityDir, entry.name, "entries");
|
|
31644
|
+
if (!existsSync5(root)) continue;
|
|
31585
31645
|
const scan = scanSource({ db: ctx.db, source, entriesRoot: root });
|
|
31586
31646
|
indexed.push({ source, ...scan });
|
|
31587
31647
|
}
|
|
@@ -31696,7 +31756,7 @@ async function runMcpServer() {
|
|
|
31696
31756
|
// src/commands/hookCmd.ts
|
|
31697
31757
|
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
31698
31758
|
import {
|
|
31699
|
-
existsSync as
|
|
31759
|
+
existsSync as existsSync6,
|
|
31700
31760
|
mkdirSync as mkdirSync4,
|
|
31701
31761
|
mkdtempSync,
|
|
31702
31762
|
readFileSync as readFileSync3,
|
|
@@ -31705,7 +31765,7 @@ import {
|
|
|
31705
31765
|
writeFileSync as writeFileSync3
|
|
31706
31766
|
} from "node:fs";
|
|
31707
31767
|
import { tmpdir } from "node:os";
|
|
31708
|
-
import { join as
|
|
31768
|
+
import { join as join9 } from "node:path";
|
|
31709
31769
|
import { createHash, randomBytes } from "node:crypto";
|
|
31710
31770
|
var silentLogger = {
|
|
31711
31771
|
info: () => {
|
|
@@ -31755,7 +31815,7 @@ function searchCaveatsFromTextSafely(text) {
|
|
|
31755
31815
|
let db;
|
|
31756
31816
|
try {
|
|
31757
31817
|
const ctx = buildContextSafely();
|
|
31758
|
-
if (!ctx || !
|
|
31818
|
+
if (!ctx || !existsSync6(ctx.paths.dbPath)) return [];
|
|
31759
31819
|
db = openDb({ path: ctx.paths.dbPath });
|
|
31760
31820
|
const hits = findCaveatsForPrompt(db, text, {
|
|
31761
31821
|
selfIdentity: defaultSelfIdentityTokens()
|
|
@@ -31839,7 +31899,7 @@ function stopSignalKey(signals, related) {
|
|
|
31839
31899
|
return createHash("sha256").update(body).digest("hex");
|
|
31840
31900
|
}
|
|
31841
31901
|
function stopStatePath(caveatHome, sessionId) {
|
|
31842
|
-
return
|
|
31902
|
+
return join9(caveatHome, CLAUDE_STOP_STATE_DIR, `${sanitizeClaudeStateId(sessionId)}.txt`);
|
|
31843
31903
|
}
|
|
31844
31904
|
function wasStopReminderQueued(caveatHome, sessionId, key) {
|
|
31845
31905
|
const path = stopStatePath(caveatHome, sessionId);
|
|
@@ -31851,7 +31911,7 @@ function wasStopReminderQueued(caveatHome, sessionId, key) {
|
|
|
31851
31911
|
}
|
|
31852
31912
|
function markStopReminderQueued(caveatHome, sessionId, key) {
|
|
31853
31913
|
const path = stopStatePath(caveatHome, sessionId);
|
|
31854
|
-
mkdirSync4(
|
|
31914
|
+
mkdirSync4(join9(caveatHome, CLAUDE_STOP_STATE_DIR), { recursive: true });
|
|
31855
31915
|
writeFileSync3(path, key, "utf-8");
|
|
31856
31916
|
}
|
|
31857
31917
|
function queueStopForSession(sessionId, signals, related) {
|
|
@@ -31902,7 +31962,7 @@ function isToolError(payload) {
|
|
|
31902
31962
|
return false;
|
|
31903
31963
|
}
|
|
31904
31964
|
function spawnWorker(job) {
|
|
31905
|
-
const workFile =
|
|
31965
|
+
const workFile = join9(
|
|
31906
31966
|
tmpdir(),
|
|
31907
31967
|
`caveat-worker-${Date.now()}-${randomBytes(4).toString("hex")}.json`
|
|
31908
31968
|
);
|
|
@@ -31966,7 +32026,7 @@ function buildToolErrorReminder(job, hits) {
|
|
|
31966
32026
|
const mode = hookCodexSidecarMode();
|
|
31967
32027
|
if (mode === "off") return base;
|
|
31968
32028
|
const projectRoot = process.cwd();
|
|
31969
|
-
const hasSidecarConfig =
|
|
32029
|
+
const hasSidecarConfig = existsSync6(join9(projectRoot, ".codex-sidecar.yml"));
|
|
31970
32030
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
31971
32031
|
const advisory = runCodexSidecarAdvisory({
|
|
31972
32032
|
searchText: job.searchText,
|
|
@@ -32003,7 +32063,7 @@ function buildStopReminder(signals, related) {
|
|
|
32003
32063
|
const mode = hookCodexSidecarMode();
|
|
32004
32064
|
if (mode === "off") return base;
|
|
32005
32065
|
const projectRoot = process.cwd();
|
|
32006
|
-
const hasSidecarConfig =
|
|
32066
|
+
const hasSidecarConfig = existsSync6(join9(projectRoot, ".codex-sidecar.yml"));
|
|
32007
32067
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
32008
32068
|
const advisory = runCodexSidecarAdvisory({
|
|
32009
32069
|
searchText: struggleSearchText(signals),
|
|
@@ -32068,8 +32128,8 @@ function runCodexSidecarAdvisory(input) {
|
|
|
32068
32128
|
"--availability",
|
|
32069
32129
|
"operational"
|
|
32070
32130
|
];
|
|
32071
|
-
const resultDir = mkdtempSync(
|
|
32072
|
-
const resultFile =
|
|
32131
|
+
const resultDir = mkdtempSync(join9(tmpdir(), "caveat-codex-advisory-"));
|
|
32132
|
+
const resultFile = join9(resultDir, "result.json");
|
|
32073
32133
|
args.push("--save-result", resultFile);
|
|
32074
32134
|
const nodeCli = process.env.CAVEAT_CODEX_SIDECAR_NODE_CLI;
|
|
32075
32135
|
if (nodeCli) {
|
|
@@ -32164,6 +32224,11 @@ async function runHook(name, arg) {
|
|
|
32164
32224
|
process.exit(0);
|
|
32165
32225
|
}
|
|
32166
32226
|
if (name === "stop") {
|
|
32227
|
+
try {
|
|
32228
|
+
const ctx = buildContextSafely();
|
|
32229
|
+
if (ctx) maybeSweepPendingDirs(ctx.caveatHome);
|
|
32230
|
+
} catch {
|
|
32231
|
+
}
|
|
32167
32232
|
if (payload.stop_hook_active === true) process.exit(0);
|
|
32168
32233
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
32169
32234
|
const signals = transcriptPath ? loadSignalsSafely(transcriptPath) : null;
|
|
@@ -32179,14 +32244,14 @@ async function runHook(name, arg) {
|
|
|
32179
32244
|
|
|
32180
32245
|
// src/commands/codexHookCmd.ts
|
|
32181
32246
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
32182
|
-
import { existsSync as
|
|
32247
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
32183
32248
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
|
|
32184
|
-
import { join as
|
|
32249
|
+
import { join as join11 } from "node:path";
|
|
32185
32250
|
import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
|
|
32186
32251
|
|
|
32187
32252
|
// src/codexHookInstall.ts
|
|
32188
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
32189
|
-
import { dirname as dirname5, join as
|
|
32253
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
32254
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
32190
32255
|
function quote2(p) {
|
|
32191
32256
|
return p.includes(" ") ? `"${p}"` : p;
|
|
32192
32257
|
}
|
|
@@ -32199,20 +32264,24 @@ function eventCommandFragment(event) {
|
|
|
32199
32264
|
function isSameHookCommand2(actual, expected) {
|
|
32200
32265
|
return actual === expected || actual.endsWith(` ${expected}`);
|
|
32201
32266
|
}
|
|
32267
|
+
function isCaveatCodexHookCommand(actual, event) {
|
|
32268
|
+
const lower = actual.toLowerCase();
|
|
32269
|
+
return lower.includes("caveat") && actual.includes(eventCommandFragment(event));
|
|
32270
|
+
}
|
|
32202
32271
|
function hasCaveatHook(hooksJson, event, fragment) {
|
|
32203
32272
|
return hooksJson.hooks?.[event]?.some(
|
|
32204
32273
|
(entry) => entry.hooks?.some((h) => h.command.includes(fragment))
|
|
32205
32274
|
) ?? false;
|
|
32206
32275
|
}
|
|
32207
32276
|
function readHooks(path) {
|
|
32208
|
-
if (!
|
|
32277
|
+
if (!existsSync7(path)) return {};
|
|
32209
32278
|
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
32210
32279
|
}
|
|
32211
32280
|
function writeJsonWithBackup(path, value) {
|
|
32212
32281
|
const dir = dirname5(path);
|
|
32213
|
-
if (!
|
|
32282
|
+
if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
|
|
32214
32283
|
let backupPath = "";
|
|
32215
|
-
if (
|
|
32284
|
+
if (existsSync7(path)) {
|
|
32216
32285
|
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
32217
32286
|
copyFileSync2(path, backupPath);
|
|
32218
32287
|
}
|
|
@@ -32220,13 +32289,21 @@ function writeJsonWithBackup(path, value) {
|
|
|
32220
32289
|
`, "utf-8");
|
|
32221
32290
|
return backupPath;
|
|
32222
32291
|
}
|
|
32223
|
-
function upsertHook2(hooksJson, event, command) {
|
|
32292
|
+
function upsertHook2(hooksJson, event, command, subcommand) {
|
|
32224
32293
|
hooksJson.hooks ??= {};
|
|
32225
32294
|
const list = hooksJson.hooks[event] ??= [];
|
|
32226
|
-
const
|
|
32227
|
-
(
|
|
32228
|
-
|
|
32229
|
-
|
|
32295
|
+
for (const entry of list) {
|
|
32296
|
+
for (const hook of entry.hooks ?? []) {
|
|
32297
|
+
if (isSameHookCommand2(hook.command, command)) return "unchanged";
|
|
32298
|
+
if (isCaveatCodexHookCommand(hook.command, subcommand)) {
|
|
32299
|
+
hook.command = command;
|
|
32300
|
+
hook.timeoutSec = 5;
|
|
32301
|
+
hook.async = false;
|
|
32302
|
+
hook.statusMessage = null;
|
|
32303
|
+
return "added";
|
|
32304
|
+
}
|
|
32305
|
+
}
|
|
32306
|
+
}
|
|
32230
32307
|
list.push({
|
|
32231
32308
|
hooks: [
|
|
32232
32309
|
{
|
|
@@ -32240,12 +32317,14 @@ function upsertHook2(hooksJson, event, command) {
|
|
|
32240
32317
|
});
|
|
32241
32318
|
return "added";
|
|
32242
32319
|
}
|
|
32243
|
-
function removeHook2(hooksJson, event, command) {
|
|
32320
|
+
function removeHook2(hooksJson, event, command, subcommand) {
|
|
32244
32321
|
const list = hooksJson.hooks?.[event];
|
|
32245
32322
|
if (!list) return false;
|
|
32246
32323
|
const before = list.length;
|
|
32247
32324
|
const filtered = list.filter(
|
|
32248
|
-
(entry) => !entry.hooks?.some(
|
|
32325
|
+
(entry) => !entry.hooks?.some(
|
|
32326
|
+
(h) => isSameHookCommand2(h.command, command) || isCaveatCodexHookCommand(h.command, subcommand)
|
|
32327
|
+
)
|
|
32249
32328
|
);
|
|
32250
32329
|
if (filtered.length === before) return false;
|
|
32251
32330
|
hooksJson.hooks[event] = filtered;
|
|
@@ -32279,9 +32358,9 @@ codex_hooks = true
|
|
|
32279
32358
|
}
|
|
32280
32359
|
function writeConfigWithBackup(path, text) {
|
|
32281
32360
|
const dir = dirname5(path);
|
|
32282
|
-
if (!
|
|
32361
|
+
if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
|
|
32283
32362
|
let backupPath = "";
|
|
32284
|
-
if (
|
|
32363
|
+
if (existsSync7(path)) {
|
|
32285
32364
|
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
32286
32365
|
copyFileSync2(path, backupPath);
|
|
32287
32366
|
}
|
|
@@ -32289,25 +32368,28 @@ function writeConfigWithBackup(path, text) {
|
|
|
32289
32368
|
return backupPath;
|
|
32290
32369
|
}
|
|
32291
32370
|
function installCodexHooks(opts) {
|
|
32292
|
-
const hooksPath =
|
|
32293
|
-
const configPath =
|
|
32371
|
+
const hooksPath = join10(opts.codexHome, "hooks.json");
|
|
32372
|
+
const configPath = join10(opts.codexHome, "config.toml");
|
|
32294
32373
|
const hooksJson = readHooks(hooksPath);
|
|
32295
32374
|
const userPromptSubmit = upsertHook2(
|
|
32296
32375
|
hooksJson,
|
|
32297
32376
|
"UserPromptSubmit",
|
|
32298
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "user-prompt-submit")
|
|
32377
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "user-prompt-submit"),
|
|
32378
|
+
"user-prompt-submit"
|
|
32299
32379
|
);
|
|
32300
32380
|
const postToolUse = upsertHook2(
|
|
32301
32381
|
hooksJson,
|
|
32302
32382
|
"PostToolUse",
|
|
32303
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "post-tool-use")
|
|
32383
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "post-tool-use"),
|
|
32384
|
+
"post-tool-use"
|
|
32304
32385
|
);
|
|
32305
32386
|
const stop = upsertHook2(
|
|
32306
32387
|
hooksJson,
|
|
32307
32388
|
"Stop",
|
|
32308
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "stop")
|
|
32389
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "stop"),
|
|
32390
|
+
"stop"
|
|
32309
32391
|
);
|
|
32310
|
-
const rawConfig =
|
|
32392
|
+
const rawConfig = existsSync7(configPath) ? readFileSync4(configPath, "utf-8") : "";
|
|
32311
32393
|
const enabled = enableCodexHooksFeature(rawConfig);
|
|
32312
32394
|
const anyHookAdded = userPromptSubmit === "added" || postToolUse === "added" || stop === "added";
|
|
32313
32395
|
let backupPath;
|
|
@@ -32333,22 +32415,25 @@ function installCodexHooks(opts) {
|
|
|
32333
32415
|
};
|
|
32334
32416
|
}
|
|
32335
32417
|
function uninstallCodexHooks(opts) {
|
|
32336
|
-
const hooksPath =
|
|
32418
|
+
const hooksPath = join10(opts.codexHome, "hooks.json");
|
|
32337
32419
|
const hooksJson = readHooks(hooksPath);
|
|
32338
32420
|
const userPromptSubmitRemoved = removeHook2(
|
|
32339
32421
|
hooksJson,
|
|
32340
32422
|
"UserPromptSubmit",
|
|
32341
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "user-prompt-submit")
|
|
32423
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "user-prompt-submit"),
|
|
32424
|
+
"user-prompt-submit"
|
|
32342
32425
|
);
|
|
32343
32426
|
const postToolUseRemoved = removeHook2(
|
|
32344
32427
|
hooksJson,
|
|
32345
32428
|
"PostToolUse",
|
|
32346
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "post-tool-use")
|
|
32429
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "post-tool-use"),
|
|
32430
|
+
"post-tool-use"
|
|
32347
32431
|
);
|
|
32348
32432
|
const stopRemoved = removeHook2(
|
|
32349
32433
|
hooksJson,
|
|
32350
32434
|
"Stop",
|
|
32351
|
-
hookCommand2(opts.nodePath, opts.cliScriptPath, "stop")
|
|
32435
|
+
hookCommand2(opts.nodePath, opts.cliScriptPath, "stop"),
|
|
32436
|
+
"stop"
|
|
32352
32437
|
);
|
|
32353
32438
|
let backupPath;
|
|
32354
32439
|
if (opts.dryRun) {
|
|
@@ -32368,7 +32453,7 @@ function uninstallCodexHooks(opts) {
|
|
|
32368
32453
|
};
|
|
32369
32454
|
}
|
|
32370
32455
|
function detectCodexHookInstallation(codexHome) {
|
|
32371
|
-
const hooksPath =
|
|
32456
|
+
const hooksPath = join10(codexHome, "hooks.json");
|
|
32372
32457
|
const hooksJson = readHooks(hooksPath);
|
|
32373
32458
|
const hooks = {
|
|
32374
32459
|
userPromptSubmit: hasCaveatHook(
|
|
@@ -32432,7 +32517,7 @@ function searchCaveatsFromTextSafely2(text) {
|
|
|
32432
32517
|
let db;
|
|
32433
32518
|
try {
|
|
32434
32519
|
const ctx = buildContextSafely2();
|
|
32435
|
-
if (!ctx || !
|
|
32520
|
+
if (!ctx || !existsSync8(ctx.paths.dbPath)) return [];
|
|
32436
32521
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32437
32522
|
const hits = findCaveatsForPrompt(db, text, {
|
|
32438
32523
|
selfIdentity: defaultSelfIdentityTokens()
|
|
@@ -32501,7 +32586,7 @@ function processExitCodeFromText(text) {
|
|
|
32501
32586
|
return m ? Number(m[1]) : null;
|
|
32502
32587
|
}
|
|
32503
32588
|
function transcriptToolOutput(transcriptPath, toolUseId) {
|
|
32504
|
-
if (!transcriptPath || !toolUseId || !
|
|
32589
|
+
if (!transcriptPath || !toolUseId || !existsSync8(transcriptPath)) return null;
|
|
32505
32590
|
let raw = "";
|
|
32506
32591
|
try {
|
|
32507
32592
|
raw = readFileSync5(transcriptPath, "utf-8");
|
|
@@ -32642,7 +32727,7 @@ function stopSignalKey2(signals, related) {
|
|
|
32642
32727
|
return createHash2("sha256").update(body).digest("hex");
|
|
32643
32728
|
}
|
|
32644
32729
|
function stopStatePath2(caveatHome, sessionId) {
|
|
32645
|
-
return
|
|
32730
|
+
return join11(caveatHome, CODEX_STOP_STATE_DIR, `${sanitizeCodexStateId(sessionId)}.txt`);
|
|
32646
32731
|
}
|
|
32647
32732
|
function wasStopReminderQueued2(caveatHome, sessionId, key) {
|
|
32648
32733
|
const path = stopStatePath2(caveatHome, sessionId);
|
|
@@ -32654,7 +32739,7 @@ function wasStopReminderQueued2(caveatHome, sessionId, key) {
|
|
|
32654
32739
|
}
|
|
32655
32740
|
function markStopReminderQueued2(caveatHome, sessionId, key) {
|
|
32656
32741
|
const path = stopStatePath2(caveatHome, sessionId);
|
|
32657
|
-
mkdirSync6(
|
|
32742
|
+
mkdirSync6(join11(caveatHome, CODEX_STOP_STATE_DIR), { recursive: true });
|
|
32658
32743
|
writeFileSync5(path, key, "utf-8");
|
|
32659
32744
|
}
|
|
32660
32745
|
function queueStopForSession2(sessionId, signals, related) {
|
|
@@ -32725,7 +32810,7 @@ async function runCodexWorker(workFile) {
|
|
|
32725
32810
|
await processCodexWorkerJob(job);
|
|
32726
32811
|
process.exit(0);
|
|
32727
32812
|
}
|
|
32728
|
-
function runDiagnostics(codexHome = process.env.CODEX_HOME ??
|
|
32813
|
+
function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join11(homedir3(), ".codex")) {
|
|
32729
32814
|
const features = spawnSync3("codex", ["features", "list"], {
|
|
32730
32815
|
encoding: "utf-8",
|
|
32731
32816
|
maxBuffer: 1024 * 1024
|
|
@@ -32802,10 +32887,10 @@ async function runCodexHook(name, arg) {
|
|
|
32802
32887
|
}
|
|
32803
32888
|
|
|
32804
32889
|
// src/commands/pull.ts
|
|
32805
|
-
import { existsSync as
|
|
32806
|
-
import { join as
|
|
32890
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4 } from "node:fs";
|
|
32891
|
+
import { join as join12 } from "node:path";
|
|
32807
32892
|
async function runPull(ctx) {
|
|
32808
|
-
if (!
|
|
32893
|
+
if (!existsSync9(ctx.paths.communityDir)) {
|
|
32809
32894
|
ctx.logger.info(
|
|
32810
32895
|
"no community repos yet \u2014 add one with `caveat community add <github-url>`."
|
|
32811
32896
|
);
|
|
@@ -32825,15 +32910,15 @@ async function runPull(ctx) {
|
|
|
32825
32910
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
32826
32911
|
try {
|
|
32827
32912
|
rebuildAll(db);
|
|
32828
|
-
if (
|
|
32913
|
+
if (existsSync9(ctx.paths.entriesDir)) {
|
|
32829
32914
|
const own = scanSource({ db, source: "own", entriesRoot: ctx.paths.entriesDir });
|
|
32830
32915
|
ctx.logger.info(`own: +${own.added}`);
|
|
32831
32916
|
}
|
|
32832
32917
|
for (const entry of readdirSync4(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
32833
32918
|
if (!entry.isDirectory()) continue;
|
|
32834
32919
|
const source = `community/${entry.name}`;
|
|
32835
|
-
const root =
|
|
32836
|
-
if (!
|
|
32920
|
+
const root = join12(ctx.paths.communityDir, entry.name, "entries");
|
|
32921
|
+
if (!existsSync9(root)) continue;
|
|
32837
32922
|
const scan = scanSource({ db, source, entriesRoot: root });
|
|
32838
32923
|
ctx.logger.info(`${source}: +${scan.added}`);
|
|
32839
32924
|
}
|
|
@@ -32846,7 +32931,7 @@ async function runPull(ctx) {
|
|
|
32846
32931
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
32847
32932
|
import { mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
32848
32933
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
32849
|
-
import { dirname as dirname6, join as
|
|
32934
|
+
import { dirname as dirname6, join as join13 } from "node:path";
|
|
32850
32935
|
import { cwd, exit } from "node:process";
|
|
32851
32936
|
function runCodexSidecarDiagnostics(logger, opts) {
|
|
32852
32937
|
const plan = buildCodexSidecarDiagnosticsCommand({
|
|
@@ -32878,8 +32963,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
|
|
|
32878
32963
|
process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
|
|
32879
32964
|
exit(0);
|
|
32880
32965
|
}
|
|
32881
|
-
const contextDir = mkdtempSync2(
|
|
32882
|
-
const contextFile =
|
|
32966
|
+
const contextDir = mkdtempSync2(join13(tmpdir3(), "caveat-sidecar-context-"));
|
|
32967
|
+
const contextFile = join13(contextDir, "context.json");
|
|
32883
32968
|
let status = 1;
|
|
32884
32969
|
try {
|
|
32885
32970
|
const blocks = collectCaveatContextBlocks(ctx, {
|
|
@@ -33049,13 +33134,26 @@ var program = new Command();
|
|
|
33049
33134
|
program.name("caveat").description("External spec gotcha knowledge base CLI").version(CAVEAT_VERSION);
|
|
33050
33135
|
program.command("init").description(
|
|
33051
33136
|
"Initialize ~/.caveatrc.json, ~/.caveat/, and register Claude Code integration. Add knowledge sources later with `caveat community add <github-url>`."
|
|
33052
|
-
).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--dry-run", "show planned changes without writing", false).
|
|
33053
|
-
|
|
33054
|
-
|
|
33055
|
-
|
|
33056
|
-
|
|
33057
|
-
|
|
33058
|
-
});
|
|
33137
|
+
).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--dry-run", "show planned changes without writing", false).option(
|
|
33138
|
+
"--pending-stale-days <days>",
|
|
33139
|
+
"sweep `<caveatHome>/pending/<sessionId>/` whose newest entry is older than this (default 7)",
|
|
33140
|
+
(raw) => {
|
|
33141
|
+
const n = Number.parseInt(raw, 10);
|
|
33142
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
33143
|
+
throw new Error(`--pending-stale-days expects a non-negative integer (got "${raw}")`);
|
|
33144
|
+
}
|
|
33145
|
+
return n;
|
|
33146
|
+
}
|
|
33147
|
+
).action(
|
|
33148
|
+
async (opts) => {
|
|
33149
|
+
const ctx = buildContext(stdoutLogger);
|
|
33150
|
+
await runInit(ctx, {
|
|
33151
|
+
skipClaude: opts.skipClaude,
|
|
33152
|
+
dryRun: opts.dryRun,
|
|
33153
|
+
pendingStaleDays: opts.pendingStaleDays
|
|
33154
|
+
});
|
|
33155
|
+
}
|
|
33156
|
+
);
|
|
33059
33157
|
program.command("uninstall").description("Remove Claude Code MCP server and hooks registered by `caveat init`").option("--dry-run", "show planned changes without writing", false).action((opts) => {
|
|
33060
33158
|
const ctx = buildContext(stdoutLogger);
|
|
33061
33159
|
runUninstall(ctx, { dryRun: opts.dryRun });
|
|
@@ -33121,7 +33219,7 @@ codexHook.command("install").description("Install Caveat hooks into ~/.codex/hoo
|
|
|
33121
33219
|
const result = installCodexHooks({
|
|
33122
33220
|
codexHome: opts.codexHome,
|
|
33123
33221
|
cliScriptPath,
|
|
33124
|
-
nodePath:
|
|
33222
|
+
nodePath: resolveHookNodePath(),
|
|
33125
33223
|
dryRun: opts.dryRun,
|
|
33126
33224
|
logger: stdoutLogger
|
|
33127
33225
|
});
|
|
@@ -33143,7 +33241,7 @@ codexHook.command("uninstall").description("Remove Caveat-owned Codex hooks from
|
|
|
33143
33241
|
const result = uninstallCodexHooks({
|
|
33144
33242
|
codexHome: opts.codexHome,
|
|
33145
33243
|
cliScriptPath,
|
|
33146
|
-
nodePath:
|
|
33244
|
+
nodePath: resolveHookNodePath(),
|
|
33147
33245
|
dryRun: opts.dryRun,
|
|
33148
33246
|
logger: stdoutLogger
|
|
33149
33247
|
});
|