caveat-cli 0.16.0 → 0.16.1
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-ZNAFNCPW.js → chunk-HCLEIAGO.js} +24 -10
- package/dist/chunk-HCLEIAGO.js.map +1 -0
- package/dist/index.js +158 -44
- package/dist/index.js.map +1 -1
- package/dist/{server-SZAVLE56.js → server-EASKBCNK.js} +2 -2
- package/package.json +5 -4
- package/dist/chunk-ZNAFNCPW.js.map +0 -1
- /package/dist/{server-SZAVLE56.js.map → server-EASKBCNK.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
userPromptSubmitReminderText,
|
|
64
64
|
writeDigestMarker,
|
|
65
65
|
writeUserConfigPatch
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-HCLEIAGO.js";
|
|
67
67
|
|
|
68
68
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
69
69
|
var require_code = __commonJS({
|
|
@@ -7075,6 +7075,7 @@ function uninstallClaudeIntegration(opts) {
|
|
|
7075
7075
|
// src/codexHookInstall.ts
|
|
7076
7076
|
import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7077
7077
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
7078
|
+
import { parse as parseToml } from "smol-toml";
|
|
7078
7079
|
function quote2(p) {
|
|
7079
7080
|
return p.includes(" ") ? `"${p}"` : p;
|
|
7080
7081
|
}
|
|
@@ -7154,74 +7155,183 @@ function removeHook2(hooksJson, event, command, subcommand) {
|
|
|
7154
7155
|
return true;
|
|
7155
7156
|
}
|
|
7156
7157
|
function enableCodexHooksFeature(raw) {
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
if (unsupportedFeatureShape) {
|
|
7158
|
+
let parsed;
|
|
7159
|
+
try {
|
|
7160
|
+
parsed = parseToml(raw);
|
|
7161
|
+
} catch {
|
|
7162
7162
|
return {
|
|
7163
7163
|
status: "blocked",
|
|
7164
7164
|
text: raw,
|
|
7165
7165
|
changed: false,
|
|
7166
|
-
reason: "config.toml
|
|
7166
|
+
reason: "config.toml is invalid TOML; fix it before installing Caveat hooks"
|
|
7167
7167
|
};
|
|
7168
7168
|
}
|
|
7169
|
-
const
|
|
7170
|
-
if (
|
|
7169
|
+
const featureValue = parsed.features;
|
|
7170
|
+
if (featureValue !== void 0 && !isPlainRecord(featureValue)) {
|
|
7171
|
+
return {
|
|
7172
|
+
status: "blocked",
|
|
7173
|
+
text: raw,
|
|
7174
|
+
changed: false,
|
|
7175
|
+
reason: "config.toml features value is not a table"
|
|
7176
|
+
};
|
|
7177
|
+
}
|
|
7178
|
+
const features = featureValue;
|
|
7179
|
+
const canonicalValue = features?.hooks;
|
|
7180
|
+
const legacyValue = features?.codex_hooks;
|
|
7181
|
+
if (canonicalValue !== void 0 && typeof canonicalValue !== "boolean") {
|
|
7182
|
+
return { status: "blocked", text: raw, changed: false, reason: "[features].hooks must be boolean" };
|
|
7183
|
+
}
|
|
7184
|
+
if (legacyValue !== void 0 && typeof legacyValue !== "boolean") {
|
|
7185
|
+
return { status: "blocked", text: raw, changed: false, reason: "[features].codex_hooks must be boolean" };
|
|
7186
|
+
}
|
|
7187
|
+
if (canonicalValue === false) {
|
|
7188
|
+
return { status: "blocked", text: raw, changed: false, reason: "[features].hooks is explicitly false" };
|
|
7189
|
+
}
|
|
7190
|
+
if (legacyValue === false) {
|
|
7171
7191
|
return {
|
|
7172
7192
|
status: "blocked",
|
|
7173
7193
|
text: raw,
|
|
7174
7194
|
changed: false,
|
|
7175
|
-
reason: "
|
|
7195
|
+
reason: canonicalValue === true ? "[features].hooks conflicts with the deprecated codex_hooks alias" : "[features].codex_hooks is explicitly false"
|
|
7176
7196
|
};
|
|
7177
7197
|
}
|
|
7178
|
-
|
|
7179
|
-
|
|
7198
|
+
if (canonicalValue === true && legacyValue === void 0) {
|
|
7199
|
+
return { status: "enabled", text: raw, changed: false };
|
|
7200
|
+
}
|
|
7201
|
+
const lines = raw.split(/\r?\n/);
|
|
7202
|
+
const codeLines = maskTomlStringsAndComments(raw).split(/\r?\n/);
|
|
7203
|
+
const featureHeaders = codeLines.map((line, index) => /^\s*\[\s*features\s*]\s*$/.test(line) ? index : -1).filter((index) => index >= 0);
|
|
7204
|
+
if (featureValue === void 0) {
|
|
7180
7205
|
const prefix = raw.trimEnd();
|
|
7181
7206
|
const text = `${prefix}${prefix ? "\n\n" : ""}[features]
|
|
7182
|
-
|
|
7207
|
+
hooks = true
|
|
7183
7208
|
`;
|
|
7184
7209
|
return { status: "enabled", text, changed: true };
|
|
7185
7210
|
}
|
|
7211
|
+
if (featureHeaders.length !== 1) {
|
|
7212
|
+
return {
|
|
7213
|
+
status: "blocked",
|
|
7214
|
+
text: raw,
|
|
7215
|
+
changed: false,
|
|
7216
|
+
reason: "config.toml uses a features table shape that Caveat will not rewrite safely"
|
|
7217
|
+
};
|
|
7218
|
+
}
|
|
7219
|
+
const featuresStart = featureHeaders[0];
|
|
7186
7220
|
const assignments = [];
|
|
7187
7221
|
for (let i = featuresStart + 1; i < lines.length; i += 1) {
|
|
7188
|
-
if (/^\s*\[\[
|
|
7222
|
+
if (/^\s*\[\[?/.test(codeLines[i])) {
|
|
7189
7223
|
break;
|
|
7190
7224
|
}
|
|
7191
|
-
const assignment = /^\s*codex_hooks
|
|
7225
|
+
const assignment = /^\s*(hooks|codex_hooks)\s*=/.exec(codeLines[i]);
|
|
7192
7226
|
if (assignment) {
|
|
7193
|
-
assignments.push({ index: i,
|
|
7194
|
-
} else if (/^\s*["']codex_hooks["']\s*=/.test(lines[i])) {
|
|
7195
|
-
return {
|
|
7196
|
-
status: "blocked",
|
|
7197
|
-
text: raw,
|
|
7198
|
-
changed: false,
|
|
7199
|
-
reason: "[features].codex_hooks uses a quoted key that Caveat will not rewrite safely"
|
|
7200
|
-
};
|
|
7227
|
+
assignments.push({ index: i, key: assignment[1] });
|
|
7201
7228
|
}
|
|
7202
7229
|
}
|
|
7203
|
-
|
|
7230
|
+
const canonical = assignments.filter((assignment) => assignment.key === "hooks");
|
|
7231
|
+
const legacy = assignments.filter((assignment) => assignment.key === "codex_hooks");
|
|
7232
|
+
if (canonicalValue !== void 0 && canonical.length !== 1 || legacyValue !== void 0 && legacy.length !== 1) {
|
|
7204
7233
|
return {
|
|
7205
7234
|
status: "blocked",
|
|
7206
7235
|
text: raw,
|
|
7207
7236
|
changed: false,
|
|
7208
|
-
reason: "[features].
|
|
7237
|
+
reason: "[features].hooks uses a key shape that Caveat will not rewrite safely"
|
|
7209
7238
|
};
|
|
7210
7239
|
}
|
|
7211
|
-
const
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
}
|
|
7240
|
+
const current = canonical[0];
|
|
7241
|
+
const deprecated = legacy[0];
|
|
7242
|
+
if (canonicalValue === true && legacyValue === true && current && deprecated) {
|
|
7243
|
+
const inlineComment = /(#.*)$/.exec(lines[deprecated.index])?.[1];
|
|
7244
|
+
lines.splice(deprecated.index, 1);
|
|
7245
|
+
if (inlineComment) {
|
|
7246
|
+
const canonicalIndex = current.index > deprecated.index ? current.index - 1 : current.index;
|
|
7247
|
+
lines.splice(canonicalIndex + 1, 0, inlineComment);
|
|
7248
|
+
}
|
|
7249
|
+
return { status: "enabled", text: `${lines.join("\n").trimEnd()}
|
|
7250
|
+
`, changed: true };
|
|
7220
7251
|
}
|
|
7221
|
-
|
|
7252
|
+
if (legacyValue === true && canonicalValue === void 0 && deprecated) {
|
|
7253
|
+
lines[deprecated.index] = lines[deprecated.index].replace(/\bcodex_hooks\b/, "hooks");
|
|
7254
|
+
return { status: "enabled", text: `${lines.join("\n").trimEnd()}
|
|
7255
|
+
`, changed: true };
|
|
7256
|
+
}
|
|
7257
|
+
lines.splice(featuresStart + 1, 0, "hooks = true");
|
|
7222
7258
|
return { status: "enabled", text: `${lines.join("\n").trimEnd()}
|
|
7223
7259
|
`, changed: true };
|
|
7224
7260
|
}
|
|
7261
|
+
function isPlainRecord(value) {
|
|
7262
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7263
|
+
}
|
|
7264
|
+
function maskTomlStringsAndComments(raw) {
|
|
7265
|
+
let state = "code";
|
|
7266
|
+
let output = "";
|
|
7267
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
7268
|
+
const char = raw[i];
|
|
7269
|
+
const triple = raw.slice(i, i + 3);
|
|
7270
|
+
if (char === "\n") {
|
|
7271
|
+
output += "\n";
|
|
7272
|
+
if (state === "comment") state = "code";
|
|
7273
|
+
continue;
|
|
7274
|
+
}
|
|
7275
|
+
if (state === "comment") {
|
|
7276
|
+
output += " ";
|
|
7277
|
+
continue;
|
|
7278
|
+
}
|
|
7279
|
+
if (state === "basic") {
|
|
7280
|
+
output += " ";
|
|
7281
|
+
if (char === "\\" && i + 1 < raw.length) {
|
|
7282
|
+
output += raw[i + 1] === "\n" ? "\n" : " ";
|
|
7283
|
+
i += 1;
|
|
7284
|
+
} else if (char === '"') state = "code";
|
|
7285
|
+
continue;
|
|
7286
|
+
}
|
|
7287
|
+
if (state === "literal") {
|
|
7288
|
+
output += " ";
|
|
7289
|
+
if (char === "'") state = "code";
|
|
7290
|
+
continue;
|
|
7291
|
+
}
|
|
7292
|
+
if (state === "multi-basic") {
|
|
7293
|
+
if (triple === '"""') {
|
|
7294
|
+
output += " ";
|
|
7295
|
+
i += 2;
|
|
7296
|
+
state = "code";
|
|
7297
|
+
} else {
|
|
7298
|
+
output += " ";
|
|
7299
|
+
if (char === "\\" && i + 1 < raw.length) {
|
|
7300
|
+
output += raw[i + 1] === "\n" ? "\n" : " ";
|
|
7301
|
+
i += 1;
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
continue;
|
|
7305
|
+
}
|
|
7306
|
+
if (state === "multi-literal") {
|
|
7307
|
+
if (triple === "'''") {
|
|
7308
|
+
output += " ";
|
|
7309
|
+
i += 2;
|
|
7310
|
+
state = "code";
|
|
7311
|
+
} else output += " ";
|
|
7312
|
+
continue;
|
|
7313
|
+
}
|
|
7314
|
+
if (char === "#") {
|
|
7315
|
+
output += " ";
|
|
7316
|
+
state = "comment";
|
|
7317
|
+
} else if (triple === '"""') {
|
|
7318
|
+
output += " ";
|
|
7319
|
+
i += 2;
|
|
7320
|
+
state = "multi-basic";
|
|
7321
|
+
} else if (triple === "'''") {
|
|
7322
|
+
output += " ";
|
|
7323
|
+
i += 2;
|
|
7324
|
+
state = "multi-literal";
|
|
7325
|
+
} else if (char === '"') {
|
|
7326
|
+
output += " ";
|
|
7327
|
+
state = "basic";
|
|
7328
|
+
} else if (char === "'") {
|
|
7329
|
+
output += " ";
|
|
7330
|
+
state = "literal";
|
|
7331
|
+
} else output += char;
|
|
7332
|
+
}
|
|
7333
|
+
return output;
|
|
7334
|
+
}
|
|
7225
7335
|
function writeConfigWithBackup(path, text) {
|
|
7226
7336
|
const dir = dirname3(path);
|
|
7227
7337
|
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
|
|
@@ -7269,7 +7379,7 @@ function installCodexHooks(opts) {
|
|
|
7269
7379
|
let configBackupPath;
|
|
7270
7380
|
if (opts.dryRun) {
|
|
7271
7381
|
opts.logger.info(`[dry-run] would update ${hooksPath}`);
|
|
7272
|
-
opts.logger.info(`[dry-run] would ensure [features].
|
|
7382
|
+
opts.logger.info(`[dry-run] would ensure [features].hooks = true in ${configPath}`);
|
|
7273
7383
|
} else {
|
|
7274
7384
|
if (anyHookAdded) {
|
|
7275
7385
|
const backup = writeJsonWithBackup(hooksPath, hooksJson);
|
|
@@ -7794,7 +7904,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7794
7904
|
if (result.feature === "blocked") {
|
|
7795
7905
|
codexHookState = "skipped";
|
|
7796
7906
|
ctx.logger.warn(
|
|
7797
|
-
`${result.blockedReason}; preserving explicit consent. Set \`
|
|
7907
|
+
`${result.blockedReason}; preserving explicit consent. Set \`hooks = true\` in ${join8(codexHome, "config.toml")}, then rerun \`caveat init\`.`
|
|
7798
7908
|
);
|
|
7799
7909
|
} else if (opts.dryRun) {
|
|
7800
7910
|
codexHookState = "skipped";
|
|
@@ -8095,7 +8205,7 @@ function runStats(ctx) {
|
|
|
8095
8205
|
|
|
8096
8206
|
// src/commands/serve.ts
|
|
8097
8207
|
async function runServe(opts) {
|
|
8098
|
-
const { startServer } = await import("./server-
|
|
8208
|
+
const { startServer } = await import("./server-EASKBCNK.js");
|
|
8099
8209
|
const { port, host } = startServer({ port: opts.port });
|
|
8100
8210
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8101
8211
|
`);
|
|
@@ -33492,10 +33602,11 @@ async function runCodexWorker(workFile) {
|
|
|
33492
33602
|
function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join13(homedir3(), ".codex")) {
|
|
33493
33603
|
const features = spawnSync5("codex", ["features", "list"], {
|
|
33494
33604
|
encoding: "utf-8",
|
|
33495
|
-
maxBuffer: 1024 * 1024
|
|
33605
|
+
maxBuffer: 1024 * 1024,
|
|
33606
|
+
env: codexFeatureListEnv(codexHome)
|
|
33496
33607
|
});
|
|
33497
33608
|
const featureOutput = [features.stdout, features.stderr].filter(Boolean).join("\n");
|
|
33498
|
-
const hasHooks = /^
|
|
33609
|
+
const hasHooks = /^hooks\s+\S+\s+true\b/m.test(featureOutput);
|
|
33499
33610
|
const installation = detectCodexHookInstallation(codexHome);
|
|
33500
33611
|
const result = {
|
|
33501
33612
|
availability: features.error || features.status !== 0 || !hasHooks ? "unavailable" : "available",
|
|
@@ -33505,11 +33616,14 @@ function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join13(homedir3(),
|
|
|
33505
33616
|
codexHome,
|
|
33506
33617
|
hooksPath: installation.hooksPath,
|
|
33507
33618
|
installedHooks: installation.hooks,
|
|
33508
|
-
evidence: featureOutput.split("\n").find((line) => line.trim().startsWith("
|
|
33619
|
+
evidence: featureOutput.split("\n").find((line) => line.trim().startsWith("hooks")) ?? null
|
|
33509
33620
|
};
|
|
33510
33621
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
33511
33622
|
`);
|
|
33512
33623
|
}
|
|
33624
|
+
function codexFeatureListEnv(codexHome, inherited = process.env) {
|
|
33625
|
+
return { ...inherited, CODEX_HOME: codexHome };
|
|
33626
|
+
}
|
|
33513
33627
|
async function runCodexHook(name, arg) {
|
|
33514
33628
|
if (name === "diagnostics") {
|
|
33515
33629
|
runDiagnostics(arg);
|
|
@@ -34068,7 +34182,7 @@ program.command("hook <name> [arg]").description(
|
|
|
34068
34182
|
await runHook(name, arg);
|
|
34069
34183
|
});
|
|
34070
34184
|
var codexHook = program.command("codex-hook").description("Install or run Codex hooks for Caveat");
|
|
34071
|
-
codexHook.command("install").description("Install Caveat hooks into ~/.codex/hooks.json and enable
|
|
34185
|
+
codexHook.command("install").description("Install Caveat hooks into ~/.codex/hooks.json and enable hooks").option("--dry-run", "show planned changes without writing", false).option("--codex-home <path>", "Codex home directory", process.env.CODEX_HOME ?? `${process.env.HOME}/.codex`).action((opts) => {
|
|
34072
34186
|
const cliScriptPath = process.argv[1];
|
|
34073
34187
|
if (!cliScriptPath) {
|
|
34074
34188
|
process.stderr.write("[caveat:error] cannot determine CLI script path\n");
|
|
@@ -34084,10 +34198,10 @@ codexHook.command("install").description("Install Caveat hooks into ~/.codex/hoo
|
|
|
34084
34198
|
stdoutLogger.info(`UserPromptSubmit hook: ${result.hooks.userPromptSubmit}`);
|
|
34085
34199
|
stdoutLogger.info(`PostToolUse hook: ${result.hooks.postToolUse}`);
|
|
34086
34200
|
stdoutLogger.info(`Stop hook: ${result.hooks.stop}`);
|
|
34087
|
-
stdoutLogger.info(`
|
|
34201
|
+
stdoutLogger.info(`hooks feature: ${result.feature}`);
|
|
34088
34202
|
if (result.feature === "blocked") {
|
|
34089
34203
|
stdoutLogger.warn(
|
|
34090
|
-
`${result.blockedReason}; preserving explicit consent. Set \`
|
|
34204
|
+
`${result.blockedReason}; preserving explicit consent. Set \`hooks = true\` in ${opts.codexHome}/config.toml, then rerun \`caveat codex-hook install\`.`
|
|
34091
34205
|
);
|
|
34092
34206
|
}
|
|
34093
34207
|
if (result.backupPath) stdoutLogger.info(`hooks.json backed up: ${result.backupPath}`);
|