caveat-cli 0.17.8 → 0.18.0
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/README.md +3 -0
- package/dist/{chunk-ZBHCOA6R.js → chunk-KAULUIC4.js} +7 -3
- package/dist/{chunk-ZBHCOA6R.js.map → chunk-KAULUIC4.js.map} +1 -1
- package/dist/index.js +489 -122
- package/dist/index.js.map +1 -1
- package/dist/{server-GBVHOF67.js → server-HKXLHXNN.js} +2 -2
- package/package.json +12 -13
- /package/dist/{server-GBVHOF67.js.map → server-HKXLHXNN.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
userPromptSubmitReminderText,
|
|
77
77
|
writeDigestMarker,
|
|
78
78
|
writeUserConfigPatch
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-KAULUIC4.js";
|
|
80
80
|
|
|
81
81
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
82
82
|
var require_code = __commonJS({
|
|
@@ -455,11 +455,11 @@ var require_codegen = __commonJS({
|
|
|
455
455
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
456
456
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
457
457
|
}
|
|
458
|
-
optimizeNames(names,
|
|
458
|
+
optimizeNames(names, constants5) {
|
|
459
459
|
if (!names[this.name.str])
|
|
460
460
|
return;
|
|
461
461
|
if (this.rhs)
|
|
462
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
462
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
463
463
|
return this;
|
|
464
464
|
}
|
|
465
465
|
get names() {
|
|
@@ -476,10 +476,10 @@ var require_codegen = __commonJS({
|
|
|
476
476
|
render({ _n }) {
|
|
477
477
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
478
478
|
}
|
|
479
|
-
optimizeNames(names,
|
|
479
|
+
optimizeNames(names, constants5) {
|
|
480
480
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
481
481
|
return;
|
|
482
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
482
|
+
this.rhs = optimizeExpr(this.rhs, names, constants5);
|
|
483
483
|
return this;
|
|
484
484
|
}
|
|
485
485
|
get names() {
|
|
@@ -540,8 +540,8 @@ var require_codegen = __commonJS({
|
|
|
540
540
|
optimizeNodes() {
|
|
541
541
|
return `${this.code}` ? this : void 0;
|
|
542
542
|
}
|
|
543
|
-
optimizeNames(names,
|
|
544
|
-
this.code = optimizeExpr(this.code, names,
|
|
543
|
+
optimizeNames(names, constants5) {
|
|
544
|
+
this.code = optimizeExpr(this.code, names, constants5);
|
|
545
545
|
return this;
|
|
546
546
|
}
|
|
547
547
|
get names() {
|
|
@@ -570,12 +570,12 @@ var require_codegen = __commonJS({
|
|
|
570
570
|
}
|
|
571
571
|
return nodes.length > 0 ? this : void 0;
|
|
572
572
|
}
|
|
573
|
-
optimizeNames(names,
|
|
573
|
+
optimizeNames(names, constants5) {
|
|
574
574
|
const { nodes } = this;
|
|
575
575
|
let i = nodes.length;
|
|
576
576
|
while (i--) {
|
|
577
577
|
const n = nodes[i];
|
|
578
|
-
if (n.optimizeNames(names,
|
|
578
|
+
if (n.optimizeNames(names, constants5))
|
|
579
579
|
continue;
|
|
580
580
|
subtractNames(names, n.names);
|
|
581
581
|
nodes.splice(i, 1);
|
|
@@ -628,12 +628,12 @@ var require_codegen = __commonJS({
|
|
|
628
628
|
return void 0;
|
|
629
629
|
return this;
|
|
630
630
|
}
|
|
631
|
-
optimizeNames(names,
|
|
631
|
+
optimizeNames(names, constants5) {
|
|
632
632
|
var _a3;
|
|
633
|
-
this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
634
|
-
if (!(super.optimizeNames(names,
|
|
633
|
+
this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants5);
|
|
634
|
+
if (!(super.optimizeNames(names, constants5) || this.else))
|
|
635
635
|
return;
|
|
636
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
636
|
+
this.condition = optimizeExpr(this.condition, names, constants5);
|
|
637
637
|
return this;
|
|
638
638
|
}
|
|
639
639
|
get names() {
|
|
@@ -656,10 +656,10 @@ var require_codegen = __commonJS({
|
|
|
656
656
|
render(opts) {
|
|
657
657
|
return `for(${this.iteration})` + super.render(opts);
|
|
658
658
|
}
|
|
659
|
-
optimizeNames(names,
|
|
660
|
-
if (!super.optimizeNames(names,
|
|
659
|
+
optimizeNames(names, constants5) {
|
|
660
|
+
if (!super.optimizeNames(names, constants5))
|
|
661
661
|
return;
|
|
662
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
662
|
+
this.iteration = optimizeExpr(this.iteration, names, constants5);
|
|
663
663
|
return this;
|
|
664
664
|
}
|
|
665
665
|
get names() {
|
|
@@ -695,10 +695,10 @@ var require_codegen = __commonJS({
|
|
|
695
695
|
render(opts) {
|
|
696
696
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
697
697
|
}
|
|
698
|
-
optimizeNames(names,
|
|
699
|
-
if (!super.optimizeNames(names,
|
|
698
|
+
optimizeNames(names, constants5) {
|
|
699
|
+
if (!super.optimizeNames(names, constants5))
|
|
700
700
|
return;
|
|
701
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
701
|
+
this.iterable = optimizeExpr(this.iterable, names, constants5);
|
|
702
702
|
return this;
|
|
703
703
|
}
|
|
704
704
|
get names() {
|
|
@@ -740,11 +740,11 @@ var require_codegen = __commonJS({
|
|
|
740
740
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
741
741
|
return this;
|
|
742
742
|
}
|
|
743
|
-
optimizeNames(names,
|
|
743
|
+
optimizeNames(names, constants5) {
|
|
744
744
|
var _a3, _b;
|
|
745
|
-
super.optimizeNames(names,
|
|
746
|
-
(_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names,
|
|
747
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
745
|
+
super.optimizeNames(names, constants5);
|
|
746
|
+
(_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants5);
|
|
747
|
+
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants5);
|
|
748
748
|
return this;
|
|
749
749
|
}
|
|
750
750
|
get names() {
|
|
@@ -1045,7 +1045,7 @@ var require_codegen = __commonJS({
|
|
|
1045
1045
|
function addExprNames(names, from) {
|
|
1046
1046
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
1047
1047
|
}
|
|
1048
|
-
function optimizeExpr(expr, names,
|
|
1048
|
+
function optimizeExpr(expr, names, constants5) {
|
|
1049
1049
|
if (expr instanceof code_1.Name)
|
|
1050
1050
|
return replaceName(expr);
|
|
1051
1051
|
if (!canOptimize(expr))
|
|
@@ -1060,14 +1060,14 @@ var require_codegen = __commonJS({
|
|
|
1060
1060
|
return items;
|
|
1061
1061
|
}, []));
|
|
1062
1062
|
function replaceName(n) {
|
|
1063
|
-
const c =
|
|
1063
|
+
const c = constants5[n.str];
|
|
1064
1064
|
if (c === void 0 || names[n.str] !== 1)
|
|
1065
1065
|
return n;
|
|
1066
1066
|
delete names[n.str];
|
|
1067
1067
|
return c;
|
|
1068
1068
|
}
|
|
1069
1069
|
function canOptimize(e) {
|
|
1070
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
1070
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants5[c.str] !== void 0);
|
|
1071
1071
|
}
|
|
1072
1072
|
}
|
|
1073
1073
|
function subtractNames(names, from) {
|
|
@@ -6889,8 +6889,8 @@ var stdoutLogger = {
|
|
|
6889
6889
|
|
|
6890
6890
|
// src/commands/init.ts
|
|
6891
6891
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
6892
|
-
import { existsSync as
|
|
6893
|
-
import { dirname as dirname3, join as
|
|
6892
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync, renameSync, rmdirSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
6893
|
+
import { dirname as dirname3, join as join9 } from "node:path";
|
|
6894
6894
|
|
|
6895
6895
|
// src/claudeInstall.ts
|
|
6896
6896
|
import { spawnSync } from "node:child_process";
|
|
@@ -7512,6 +7512,150 @@ function detectCodexHookInstallation(codexHome) {
|
|
|
7512
7512
|
};
|
|
7513
7513
|
}
|
|
7514
7514
|
|
|
7515
|
+
// src/cursorInstall.ts
|
|
7516
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4 } from "node:fs";
|
|
7517
|
+
import { join as join5 } from "node:path";
|
|
7518
|
+
import { constants as constants3 } from "node:fs";
|
|
7519
|
+
var TIMEOUT_SEC = 10;
|
|
7520
|
+
function hookCommand3(nodePath, cliScriptPath, event) {
|
|
7521
|
+
return `${quoteCommandPath(nodePath)} ${quoteCommandPath(cliScriptPath)} cursor-hook ${event}`;
|
|
7522
|
+
}
|
|
7523
|
+
function eventCommandFragment2(event) {
|
|
7524
|
+
return `cursor-hook ${event}`;
|
|
7525
|
+
}
|
|
7526
|
+
function isCaveatCursorHookCommand(actual, event) {
|
|
7527
|
+
const lower = actual.toLowerCase();
|
|
7528
|
+
return lower.includes("caveat") && actual.includes(eventCommandFragment2(event));
|
|
7529
|
+
}
|
|
7530
|
+
function readHooks2(path) {
|
|
7531
|
+
if (!existsSync4(path)) return { version: 1, hooks: {} };
|
|
7532
|
+
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
7533
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7534
|
+
throw new Error(`${path} \u306F object \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`);
|
|
7535
|
+
}
|
|
7536
|
+
const file2 = parsed;
|
|
7537
|
+
if (file2.hooks == null) file2.hooks = {};
|
|
7538
|
+
if (typeof file2.hooks !== "object" || Array.isArray(file2.hooks)) {
|
|
7539
|
+
throw new Error(`${path} \u306E hooks \u306F object \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`);
|
|
7540
|
+
}
|
|
7541
|
+
return file2;
|
|
7542
|
+
}
|
|
7543
|
+
function listFor(file2, event) {
|
|
7544
|
+
const current = file2.hooks?.[event];
|
|
7545
|
+
if (Array.isArray(current)) return current;
|
|
7546
|
+
return [];
|
|
7547
|
+
}
|
|
7548
|
+
function isSameCommand(actual, expected) {
|
|
7549
|
+
const left = commandTokens(actual);
|
|
7550
|
+
const right = commandTokens(expected);
|
|
7551
|
+
return left !== null && right !== null && left.length === right.length && left.every((token, index) => token === right[index]);
|
|
7552
|
+
}
|
|
7553
|
+
function upsertHook3(file2, event, command, subcommand) {
|
|
7554
|
+
file2.hooks ??= {};
|
|
7555
|
+
const list = listFor(file2, event);
|
|
7556
|
+
for (const entry of list) {
|
|
7557
|
+
if (typeof entry.command !== "string") continue;
|
|
7558
|
+
if (isSameCommand(entry.command, command) && entry.timeout === TIMEOUT_SEC) {
|
|
7559
|
+
return "unchanged";
|
|
7560
|
+
}
|
|
7561
|
+
if (isSameCommand(entry.command, command) || isCaveatCursorHookCommand(entry.command, subcommand)) {
|
|
7562
|
+
entry.command = command;
|
|
7563
|
+
entry.timeout = TIMEOUT_SEC;
|
|
7564
|
+
file2.hooks[event] = list;
|
|
7565
|
+
return "added";
|
|
7566
|
+
}
|
|
7567
|
+
}
|
|
7568
|
+
list.push({ command, timeout: TIMEOUT_SEC });
|
|
7569
|
+
file2.hooks[event] = list;
|
|
7570
|
+
return "added";
|
|
7571
|
+
}
|
|
7572
|
+
function removeHook3(file2, event, command, subcommand) {
|
|
7573
|
+
const list = listFor(file2, event);
|
|
7574
|
+
if (list.length === 0) return false;
|
|
7575
|
+
const kept = list.filter((entry) => {
|
|
7576
|
+
if (typeof entry.command !== "string") return true;
|
|
7577
|
+
return !(isSameCommand(entry.command, command) || isCaveatCursorHookCommand(entry.command, subcommand));
|
|
7578
|
+
});
|
|
7579
|
+
if (kept.length === list.length) return false;
|
|
7580
|
+
if (!file2.hooks) return true;
|
|
7581
|
+
if (kept.length > 0) file2.hooks[event] = kept;
|
|
7582
|
+
else delete file2.hooks[event];
|
|
7583
|
+
return true;
|
|
7584
|
+
}
|
|
7585
|
+
function hasCaveatHook2(file2, event, fragment) {
|
|
7586
|
+
return listFor(file2, event).some(
|
|
7587
|
+
(entry) => typeof entry.command === "string" && entry.command.includes(fragment)
|
|
7588
|
+
);
|
|
7589
|
+
}
|
|
7590
|
+
function persist(opts, file2, changed) {
|
|
7591
|
+
const hooksPath = join5(opts.cursorDir, "hooks.json");
|
|
7592
|
+
if (opts.dryRun) {
|
|
7593
|
+
opts.logger.info(`[dry-run] would write Cursor hooks to ${hooksPath}`);
|
|
7594
|
+
return void 0;
|
|
7595
|
+
}
|
|
7596
|
+
if (!changed) return void 0;
|
|
7597
|
+
mkdirSync2(opts.cursorDir, { recursive: true });
|
|
7598
|
+
file2.version = 1;
|
|
7599
|
+
const backup = writeJsonWithBackup(hooksPath, file2);
|
|
7600
|
+
return backup || void 0;
|
|
7601
|
+
}
|
|
7602
|
+
function installCursorHooks(opts) {
|
|
7603
|
+
const hooksPath = join5(opts.cursorDir, "hooks.json");
|
|
7604
|
+
const file2 = readHooks2(hooksPath);
|
|
7605
|
+
const promptCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "user-prompt-submit");
|
|
7606
|
+
const toolCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "post-tool-use");
|
|
7607
|
+
const stopCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "stop");
|
|
7608
|
+
const hooks = {
|
|
7609
|
+
beforeSubmitPrompt: upsertHook3(file2, "beforeSubmitPrompt", promptCmd, "user-prompt-submit"),
|
|
7610
|
+
postToolUse: upsertHook3(file2, "postToolUse", toolCmd, "post-tool-use"),
|
|
7611
|
+
postToolUseFailure: upsertHook3(file2, "postToolUseFailure", toolCmd, "post-tool-use"),
|
|
7612
|
+
stop: upsertHook3(file2, "stop", stopCmd, "stop")
|
|
7613
|
+
};
|
|
7614
|
+
const changed = Object.values(hooks).some((status2) => status2 === "added");
|
|
7615
|
+
const backupPath = persist(opts, file2, changed);
|
|
7616
|
+
return { hooks, backupPath };
|
|
7617
|
+
}
|
|
7618
|
+
function uninstallCursorHooks(opts) {
|
|
7619
|
+
const hooksPath = join5(opts.cursorDir, "hooks.json");
|
|
7620
|
+
const file2 = readHooks2(hooksPath);
|
|
7621
|
+
const promptCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "user-prompt-submit");
|
|
7622
|
+
const toolCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "post-tool-use");
|
|
7623
|
+
const stopCmd = hookCommand3(opts.nodePath, opts.cliScriptPath, "stop");
|
|
7624
|
+
const removed = {
|
|
7625
|
+
beforeSubmitPrompt: removeHook3(file2, "beforeSubmitPrompt", promptCmd, "user-prompt-submit"),
|
|
7626
|
+
postToolUse: removeHook3(file2, "postToolUse", toolCmd, "post-tool-use"),
|
|
7627
|
+
postToolUseFailure: removeHook3(file2, "postToolUseFailure", toolCmd, "post-tool-use"),
|
|
7628
|
+
stop: removeHook3(file2, "stop", stopCmd, "stop")
|
|
7629
|
+
};
|
|
7630
|
+
const changed = Object.values(removed).some(Boolean);
|
|
7631
|
+
const backupPath = persist(opts, file2, changed);
|
|
7632
|
+
return {
|
|
7633
|
+
hooks: {
|
|
7634
|
+
beforeSubmitPrompt: removed.beforeSubmitPrompt ? "added" : "unchanged",
|
|
7635
|
+
postToolUse: removed.postToolUse ? "added" : "unchanged",
|
|
7636
|
+
postToolUseFailure: removed.postToolUseFailure ? "added" : "unchanged",
|
|
7637
|
+
stop: removed.stop ? "added" : "unchanged"
|
|
7638
|
+
},
|
|
7639
|
+
backupPath
|
|
7640
|
+
};
|
|
7641
|
+
}
|
|
7642
|
+
function detectCursorHookInstallation(cursorDir) {
|
|
7643
|
+
const hooksPath = join5(cursorDir, "hooks.json");
|
|
7644
|
+
const file2 = existsSync4(hooksPath) ? readHooks2(hooksPath) : { version: 1, hooks: {} };
|
|
7645
|
+
const hooks = {
|
|
7646
|
+
beforeSubmitPrompt: hasCaveatHook2(file2, "beforeSubmitPrompt", eventCommandFragment2("user-prompt-submit")),
|
|
7647
|
+
postToolUse: hasCaveatHook2(file2, "postToolUse", eventCommandFragment2("post-tool-use")),
|
|
7648
|
+
postToolUseFailure: hasCaveatHook2(file2, "postToolUseFailure", eventCommandFragment2("post-tool-use")),
|
|
7649
|
+
stop: hasCaveatHook2(file2, "stop", eventCommandFragment2("stop"))
|
|
7650
|
+
};
|
|
7651
|
+
const count = Object.values(hooks).filter(Boolean).length;
|
|
7652
|
+
return {
|
|
7653
|
+
installation: count === 0 ? "not-installed" : count === 4 ? "installed" : "partial",
|
|
7654
|
+
hooksPath,
|
|
7655
|
+
hooks
|
|
7656
|
+
};
|
|
7657
|
+
}
|
|
7658
|
+
|
|
7515
7659
|
// src/ghSetup.ts
|
|
7516
7660
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7517
7661
|
import { readSync } from "node:fs";
|
|
@@ -7559,8 +7703,8 @@ function askOnce(question) {
|
|
|
7559
7703
|
}
|
|
7560
7704
|
|
|
7561
7705
|
// src/nodePath.ts
|
|
7562
|
-
import { existsSync as
|
|
7563
|
-
import { delimiter, join as
|
|
7706
|
+
import { existsSync as existsSync5, realpathSync as realpathSync2 } from "node:fs";
|
|
7707
|
+
import { delimiter, join as join6 } from "node:path";
|
|
7564
7708
|
var defaultRealpath = (path) => realpathSync2.native(path);
|
|
7565
7709
|
function safeRealpath(path, realpath = defaultRealpath) {
|
|
7566
7710
|
try {
|
|
@@ -7573,7 +7717,7 @@ function resolveHookNodePath({
|
|
|
7573
7717
|
env = process.env,
|
|
7574
7718
|
execPath = process.execPath,
|
|
7575
7719
|
platform = process.platform,
|
|
7576
|
-
exists =
|
|
7720
|
+
exists = existsSync5,
|
|
7577
7721
|
realpath = defaultRealpath
|
|
7578
7722
|
} = {}) {
|
|
7579
7723
|
const execRealpath = safeRealpath(execPath, realpath);
|
|
@@ -7581,7 +7725,7 @@ function resolveHookNodePath({
|
|
|
7581
7725
|
const names = nodeExecutableNames(platform);
|
|
7582
7726
|
for (const dir of pathEnv.split(delimiter).filter(Boolean)) {
|
|
7583
7727
|
for (const name of names) {
|
|
7584
|
-
const candidate =
|
|
7728
|
+
const candidate = join6(dir, name);
|
|
7585
7729
|
if (!exists(candidate)) continue;
|
|
7586
7730
|
const candidateRealpath = safeRealpath(candidate, realpath);
|
|
7587
7731
|
if (execRealpath && candidateRealpath && candidateRealpath === execRealpath) {
|
|
@@ -7593,14 +7737,14 @@ function resolveHookNodePath({
|
|
|
7593
7737
|
}
|
|
7594
7738
|
|
|
7595
7739
|
// src/commands/publish.ts
|
|
7596
|
-
import { existsSync as
|
|
7597
|
-
import { join as
|
|
7740
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
7741
|
+
import { join as join8 } from "node:path";
|
|
7598
7742
|
|
|
7599
7743
|
// src/commands/codexSidecarAdvisory.ts
|
|
7600
7744
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7601
|
-
import { mkdtempSync, readFileSync as
|
|
7745
|
+
import { mkdtempSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7602
7746
|
import { tmpdir } from "node:os";
|
|
7603
|
-
import { join as
|
|
7747
|
+
import { join as join7 } from "node:path";
|
|
7604
7748
|
var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
|
|
7605
7749
|
var MAX_HOOK_SIDECAR_TIMEOUT_MS = 24e4;
|
|
7606
7750
|
function resolveHookSidecarTimeoutMs(raw) {
|
|
@@ -7656,11 +7800,11 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7656
7800
|
let resultDir;
|
|
7657
7801
|
let advisory;
|
|
7658
7802
|
try {
|
|
7659
|
-
resultDir = mkdtempSync(
|
|
7660
|
-
const resultFile =
|
|
7803
|
+
resultDir = mkdtempSync(join7(tmpdir(), "caveat-codex-advisory-"));
|
|
7804
|
+
const resultFile = join7(resultDir, "result.json");
|
|
7661
7805
|
args.push("--save-result", resultFile);
|
|
7662
7806
|
if (input.additionalContext) {
|
|
7663
|
-
const additionalContextFile =
|
|
7807
|
+
const additionalContextFile = join7(resultDir, "hook-signal.json");
|
|
7664
7808
|
writeFileSync2(additionalContextFile, JSON.stringify({ context: [input.additionalContext] }) + "\n", { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
7665
7809
|
args.push("--additional-context-file", additionalContextFile);
|
|
7666
7810
|
}
|
|
@@ -7688,7 +7832,7 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7688
7832
|
message: `sidecar command failed: ${sidecarFailureDetail(detail)}`
|
|
7689
7833
|
};
|
|
7690
7834
|
} else {
|
|
7691
|
-
const parsed = JSON.parse(
|
|
7835
|
+
const parsed = JSON.parse(readFileSync5(resultFile, "utf-8"));
|
|
7692
7836
|
if (parsed.status !== "ok" || typeof parsed.summary !== "string") {
|
|
7693
7837
|
advisory = {
|
|
7694
7838
|
status: "failed",
|
|
@@ -7756,7 +7900,7 @@ async function runPublish(ctx, opts, dependencies = {}) {
|
|
|
7756
7900
|
const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
|
|
7757
7901
|
const confirm = dependencies.confirm ?? askOnce;
|
|
7758
7902
|
const projectRoot = process.cwd();
|
|
7759
|
-
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) =>
|
|
7903
|
+
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) => existsSync6(join8(root, ".codex-sidecar.yml")));
|
|
7760
7904
|
const publishAdvisory = hasCodexSidecarConfig(projectRoot) ? (changes) => {
|
|
7761
7905
|
try {
|
|
7762
7906
|
return dependencies.runCodexSidecarAdvisory?.(changes, projectRoot) ?? formatCodexSidecarAdvisory(runCodexSidecarAdvisory({
|
|
@@ -7813,24 +7957,25 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7813
7957
|
const ghRunner = dependencies.ghRunner ?? runGh;
|
|
7814
7958
|
let publishTarget = ctx.config.publishTarget;
|
|
7815
7959
|
let codexHookState = "not-installed";
|
|
7960
|
+
let cursorHookState = "not-installed";
|
|
7816
7961
|
ensureUserConfig(ctx.userConfigPath);
|
|
7817
7962
|
ctx.logger.info(`user config: ${ctx.userConfigPath}`);
|
|
7818
|
-
if (!
|
|
7819
|
-
|
|
7820
|
-
|
|
7963
|
+
if (!existsSync7(ctx.paths.knowledgeRepo)) {
|
|
7964
|
+
mkdirSync3(ctx.paths.knowledgeRepo, { recursive: true });
|
|
7965
|
+
mkdirSync3(ctx.paths.entriesDir, { recursive: true });
|
|
7821
7966
|
ctx.logger.info(`knowledge repo scaffolded: ${ctx.paths.knowledgeRepo}`);
|
|
7822
7967
|
} else {
|
|
7823
7968
|
ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
|
|
7824
7969
|
}
|
|
7825
7970
|
migrateLegacyCommunityDir(ctx);
|
|
7826
|
-
const gitignorePath =
|
|
7827
|
-
if (!
|
|
7971
|
+
const gitignorePath = join9(ctx.paths.knowledgeRepo, ".gitignore");
|
|
7972
|
+
if (!existsSync7(gitignorePath)) {
|
|
7828
7973
|
writeFileSync3(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
|
|
7829
7974
|
ctx.logger.info(`.gitignore created: ${gitignorePath}`);
|
|
7830
7975
|
}
|
|
7831
7976
|
if (!opts.dryRun) {
|
|
7832
7977
|
const dbDir = dirname3(ctx.paths.dbPath);
|
|
7833
|
-
if (!
|
|
7978
|
+
if (!existsSync7(dbDir)) mkdirSync3(dbDir, { recursive: true });
|
|
7834
7979
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
7835
7980
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
7836
7981
|
for (const failure of failures) {
|
|
@@ -7944,7 +8089,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7944
8089
|
ctx.logger.warn("cannot determine CLI script path; skipping Claude integration");
|
|
7945
8090
|
} else {
|
|
7946
8091
|
const result = installClaudeIntegration({
|
|
7947
|
-
claudeDir:
|
|
8092
|
+
claudeDir: join9(ctx.userHome, ".claude"),
|
|
7948
8093
|
cliScriptPath,
|
|
7949
8094
|
nodePath: resolveHookNodePath(),
|
|
7950
8095
|
dryRun: opts.dryRun,
|
|
@@ -7962,7 +8107,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7962
8107
|
codexHookState = "skipped";
|
|
7963
8108
|
ctx.logger.warn("cannot determine CLI script path; skipping Codex hook integration");
|
|
7964
8109
|
} else {
|
|
7965
|
-
const codexHome =
|
|
8110
|
+
const codexHome = join9(ctx.userHome, ".codex");
|
|
7966
8111
|
const result = installCodexHooks({
|
|
7967
8112
|
codexHome,
|
|
7968
8113
|
cliScriptPath,
|
|
@@ -7973,7 +8118,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7973
8118
|
if (result.feature === "blocked") {
|
|
7974
8119
|
codexHookState = "skipped";
|
|
7975
8120
|
ctx.logger.warn(
|
|
7976
|
-
`${result.blockedReason}; preserving explicit consent. Set \`hooks = true\` in ${
|
|
8121
|
+
`${result.blockedReason}; preserving explicit consent. Set \`hooks = true\` in ${join9(codexHome, "config.toml")}, then rerun \`caveat init\`.`
|
|
7977
8122
|
);
|
|
7978
8123
|
} else if (opts.dryRun) {
|
|
7979
8124
|
codexHookState = "skipped";
|
|
@@ -7983,7 +8128,35 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7983
8128
|
}
|
|
7984
8129
|
}
|
|
7985
8130
|
}
|
|
7986
|
-
|
|
8131
|
+
if (opts.skipCursorHook) {
|
|
8132
|
+
cursorHookState = "skipped";
|
|
8133
|
+
ctx.logger.info("Cursor hook integration skipped (--skip-cursor-hook)");
|
|
8134
|
+
} else if (existsSync7(join9(ctx.userHome, ".cursor"))) {
|
|
8135
|
+
const cliScriptPath = process.argv[1];
|
|
8136
|
+
if (!cliScriptPath) {
|
|
8137
|
+
cursorHookState = "skipped";
|
|
8138
|
+
ctx.logger.warn("cannot determine CLI script path; skipping Cursor hook integration");
|
|
8139
|
+
} else {
|
|
8140
|
+
const cursorDir = join9(ctx.userHome, ".cursor");
|
|
8141
|
+
const result = installCursorHooks({
|
|
8142
|
+
cursorDir,
|
|
8143
|
+
cliScriptPath,
|
|
8144
|
+
nodePath: resolveHookNodePath(),
|
|
8145
|
+
dryRun: opts.dryRun,
|
|
8146
|
+
logger: ctx.logger
|
|
8147
|
+
});
|
|
8148
|
+
if (opts.dryRun) {
|
|
8149
|
+
cursorHookState = "skipped";
|
|
8150
|
+
ctx.logger.info("[dry-run] would install Cursor hooks");
|
|
8151
|
+
} else {
|
|
8152
|
+
cursorHookState = detectCursorHookInstallation(cursorDir).installation;
|
|
8153
|
+
ctx.logger.info(`Cursor beforeSubmitPrompt hook: ${result.hooks.beforeSubmitPrompt}`);
|
|
8154
|
+
ctx.logger.info(`Cursor postToolUse hook: ${result.hooks.postToolUse}`);
|
|
8155
|
+
ctx.logger.info(`Cursor stop hook: ${result.hooks.stop}`);
|
|
8156
|
+
}
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
8159
|
+
reportEnvironmentSummary(ctx, publishTarget, codexHookState, cursorHookState, opts.dryRun);
|
|
7987
8160
|
}
|
|
7988
8161
|
function detectCodexAvailability() {
|
|
7989
8162
|
const result = spawnSync4("codex --version", {
|
|
@@ -8004,36 +8177,37 @@ function gitOutput(args) {
|
|
|
8004
8177
|
const result = spawnSync4("git", args, { encoding: "utf-8" });
|
|
8005
8178
|
return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() : null;
|
|
8006
8179
|
}
|
|
8007
|
-
function reportEnvironmentSummary(ctx, publishTarget, codexHookState, dryRun) {
|
|
8180
|
+
function reportEnvironmentSummary(ctx, publishTarget, codexHookState, cursorHookState, dryRun) {
|
|
8008
8181
|
const prefix = dryRun ? "[dry-run] would have " : "";
|
|
8009
8182
|
const isRepo = gitOutput(["-C", ctx.paths.knowledgeRepo, "rev-parse", "--is-inside-work-tree"]) === "true";
|
|
8010
8183
|
const remote = isRepo ? gitOutput(["-C", ctx.paths.knowledgeRepo, "config", "--get", "remote.origin.url"]) : null;
|
|
8011
|
-
const communityCount =
|
|
8184
|
+
const communityCount = existsSync7(ctx.paths.communityDir) ? readdirSync(ctx.paths.communityDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
|
|
8012
8185
|
ctx.logger.info(`${prefix}environment summary:`);
|
|
8013
8186
|
ctx.logger.info(` own git: ${isRepo ? "repository" : "not initialized"}`);
|
|
8014
8187
|
ctx.logger.info(` private remote: ${remote || "not configured"}`);
|
|
8015
8188
|
ctx.logger.info(` publish target: ${publishTarget || "not configured"}`);
|
|
8016
8189
|
ctx.logger.info(` community sources: ${communityCount}`);
|
|
8017
8190
|
ctx.logger.info(` codex hook: ${codexHookState}`);
|
|
8191
|
+
ctx.logger.info(` cursor hook: ${cursorHookState}`);
|
|
8018
8192
|
}
|
|
8019
8193
|
function errorMessage(err) {
|
|
8020
8194
|
return err instanceof Error ? err.message : String(err);
|
|
8021
8195
|
}
|
|
8022
8196
|
function migrateLegacyCommunityDir(ctx) {
|
|
8023
|
-
const legacy =
|
|
8197
|
+
const legacy = join9(ctx.paths.knowledgeRepo, "community");
|
|
8024
8198
|
const current = ctx.paths.communityDir;
|
|
8025
8199
|
if (legacy === current) return;
|
|
8026
|
-
if (!
|
|
8027
|
-
if (
|
|
8200
|
+
if (!existsSync7(legacy)) return;
|
|
8201
|
+
if (existsSync7(current)) {
|
|
8028
8202
|
ctx.logger.warn(
|
|
8029
8203
|
`legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
|
|
8030
8204
|
);
|
|
8031
8205
|
return;
|
|
8032
8206
|
}
|
|
8033
|
-
|
|
8207
|
+
mkdirSync3(current, { recursive: true });
|
|
8034
8208
|
for (const entry of readdirSync(legacy, { withFileTypes: true })) {
|
|
8035
8209
|
if (!entry.isDirectory()) continue;
|
|
8036
|
-
renameSync(
|
|
8210
|
+
renameSync(join9(legacy, entry.name), join9(current, entry.name));
|
|
8037
8211
|
}
|
|
8038
8212
|
try {
|
|
8039
8213
|
rmdirSync(legacy);
|
|
@@ -8048,7 +8222,7 @@ function runUninstall(ctx, opts) {
|
|
|
8048
8222
|
process.exit(1);
|
|
8049
8223
|
}
|
|
8050
8224
|
const result = uninstallClaudeIntegration({
|
|
8051
|
-
claudeDir:
|
|
8225
|
+
claudeDir: join9(ctx.userHome, ".claude"),
|
|
8052
8226
|
cliScriptPath,
|
|
8053
8227
|
nodePath: resolveHookNodePath(),
|
|
8054
8228
|
dryRun: opts.dryRun,
|
|
@@ -8095,11 +8269,11 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
8095
8269
|
}
|
|
8096
8270
|
|
|
8097
8271
|
// src/commands/indexCmd.ts
|
|
8098
|
-
import { existsSync as
|
|
8272
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4 } from "node:fs";
|
|
8099
8273
|
import { dirname as dirname4 } from "node:path";
|
|
8100
8274
|
async function runIndex(ctx, opts) {
|
|
8101
8275
|
const dbDir = dirname4(ctx.paths.dbPath);
|
|
8102
|
-
if (!
|
|
8276
|
+
if (!existsSync8(dbDir)) mkdirSync4(dbDir, { recursive: true });
|
|
8103
8277
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
8104
8278
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
8105
8279
|
for (const failure of failures) {
|
|
@@ -8283,7 +8457,7 @@ function runStats(ctx) {
|
|
|
8283
8457
|
|
|
8284
8458
|
// src/commands/serve.ts
|
|
8285
8459
|
async function runServe(opts) {
|
|
8286
|
-
const { startServer } = await import("./server-
|
|
8460
|
+
const { startServer } = await import("./server-HKXLHXNN.js");
|
|
8287
8461
|
const { port, host } = startServer({ port: opts.port });
|
|
8288
8462
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8289
8463
|
`);
|
|
@@ -32355,7 +32529,7 @@ var StdioServerTransport = class {
|
|
|
32355
32529
|
|
|
32356
32530
|
// ../mcp/dist/context.js
|
|
32357
32531
|
import { homedir as homedir2 } from "node:os";
|
|
32358
|
-
import { join as
|
|
32532
|
+
import { join as join10 } from "node:path";
|
|
32359
32533
|
|
|
32360
32534
|
// ../mcp/dist/autoSyncTrigger.js
|
|
32361
32535
|
function triggerAutoSyncAfterWrite(caveatHome, logger) {
|
|
@@ -32374,7 +32548,7 @@ function triggerAutoSyncAfterWrite(caveatHome, logger) {
|
|
|
32374
32548
|
function buildMcpContext(overrides = {}) {
|
|
32375
32549
|
const userHome = overrides.userHome ?? homedir2();
|
|
32376
32550
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
32377
|
-
const userConfigPath =
|
|
32551
|
+
const userConfigPath = join10(userHome, ".caveatrc.json");
|
|
32378
32552
|
const logger = overrides.logger ?? stderrLogger;
|
|
32379
32553
|
const config2 = loadConfig(userConfigPath);
|
|
32380
32554
|
const paths = resolvePaths(caveatHome, config2.knowledgeRepo, userHome);
|
|
@@ -32523,12 +32697,12 @@ function handleListRecent(ctx, args) {
|
|
|
32523
32697
|
}
|
|
32524
32698
|
|
|
32525
32699
|
// ../mcp/dist/tools/pull.js
|
|
32526
|
-
import { existsSync as
|
|
32700
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
32527
32701
|
var pullInputShape = {};
|
|
32528
32702
|
async function handlePull(ctx, _args = {}) {
|
|
32529
32703
|
const pulled = [];
|
|
32530
32704
|
const indexed = [];
|
|
32531
|
-
if (
|
|
32705
|
+
if (existsSync9(ctx.paths.communityDir)) {
|
|
32532
32706
|
const results = await communityPull({
|
|
32533
32707
|
communityDir: ctx.paths.communityDir,
|
|
32534
32708
|
logger: ctx.logger
|
|
@@ -32684,28 +32858,28 @@ async function runMcpServer() {
|
|
|
32684
32858
|
import { spawn as spawn2 } from "node:child_process";
|
|
32685
32859
|
import {
|
|
32686
32860
|
chmodSync,
|
|
32687
|
-
existsSync as
|
|
32861
|
+
existsSync as existsSync12,
|
|
32688
32862
|
lstatSync,
|
|
32689
32863
|
mkdtempSync as mkdtempSync2,
|
|
32690
|
-
mkdirSync as
|
|
32864
|
+
mkdirSync as mkdirSync6,
|
|
32691
32865
|
readdirSync as readdirSync2,
|
|
32692
|
-
readFileSync as
|
|
32866
|
+
readFileSync as readFileSync7,
|
|
32693
32867
|
realpathSync as realpathSync3,
|
|
32694
32868
|
rmSync as rmSync2,
|
|
32695
32869
|
writeFileSync as writeFileSync5
|
|
32696
32870
|
} from "node:fs";
|
|
32697
32871
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
32698
|
-
import { basename, dirname as dirname5, join as
|
|
32872
|
+
import { basename, dirname as dirname5, join as join13 } from "node:path";
|
|
32699
32873
|
import { randomBytes } from "node:crypto";
|
|
32700
32874
|
|
|
32701
32875
|
// src/autoReindexTrigger.ts
|
|
32702
32876
|
import { spawn } from "node:child_process";
|
|
32703
|
-
import { existsSync as
|
|
32704
|
-
import { join as
|
|
32877
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
32878
|
+
import { join as join11 } from "node:path";
|
|
32705
32879
|
function maybeTriggerAutoReindex(ctx) {
|
|
32706
32880
|
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") return;
|
|
32707
|
-
if (!
|
|
32708
|
-
if (
|
|
32881
|
+
if (!existsSync10(ctx.paths.dbPath)) return;
|
|
32882
|
+
if (existsSync10(join11(ctx.caveatHome, "index", ".reindex-lock"))) return;
|
|
32709
32883
|
const current = computeEntriesDigest(ctx.paths);
|
|
32710
32884
|
const marker = readDigestMarker(ctx.caveatHome);
|
|
32711
32885
|
if (marker?.digest === current.digest && marker.fileCount === current.fileCount) return;
|
|
@@ -32731,8 +32905,8 @@ function maybeTriggerAutoSync(ctx, debounceMs = AUTO_SYNC_DEBOUNCE_MS) {
|
|
|
32731
32905
|
}
|
|
32732
32906
|
|
|
32733
32907
|
// src/hookShared.ts
|
|
32734
|
-
import { existsSync as
|
|
32735
|
-
import { join as
|
|
32908
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
32909
|
+
import { join as join12 } from "node:path";
|
|
32736
32910
|
import { createHash } from "node:crypto";
|
|
32737
32911
|
var MAX_CONTEXT_BLOCKS = 3;
|
|
32738
32912
|
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:";
|
|
@@ -32787,7 +32961,7 @@ function searchCaveatsSafely(host, input) {
|
|
|
32787
32961
|
let hits;
|
|
32788
32962
|
try {
|
|
32789
32963
|
const ctx = buildContextSafely(host);
|
|
32790
|
-
if (!ctx || !
|
|
32964
|
+
if (!ctx || !existsSync11(ctx.paths.dbPath)) return [];
|
|
32791
32965
|
caveatHome = ctx.caveatHome;
|
|
32792
32966
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32793
32967
|
const searchOptions = {
|
|
@@ -32873,19 +33047,19 @@ function stopSignalKey(signals, related) {
|
|
|
32873
33047
|
return createHash("sha256").update(body).digest("hex");
|
|
32874
33048
|
}
|
|
32875
33049
|
function stopStatePath(host, caveatHome, sessionId) {
|
|
32876
|
-
return
|
|
33050
|
+
return join12(caveatHome, host.stopStateDir, `${sanitizeStateId(sessionId)}.txt`);
|
|
32877
33051
|
}
|
|
32878
33052
|
function wasStopReminderQueued(host, caveatHome, sessionId, key) {
|
|
32879
33053
|
const path = stopStatePath(host, caveatHome, sessionId);
|
|
32880
33054
|
try {
|
|
32881
|
-
return
|
|
33055
|
+
return readFileSync6(path, "utf-8") === key;
|
|
32882
33056
|
} catch {
|
|
32883
33057
|
return false;
|
|
32884
33058
|
}
|
|
32885
33059
|
}
|
|
32886
33060
|
function markStopReminderQueued(host, caveatHome, sessionId, key) {
|
|
32887
33061
|
const path = stopStatePath(host, caveatHome, sessionId);
|
|
32888
|
-
|
|
33062
|
+
mkdirSync5(join12(caveatHome, host.stopStateDir), { recursive: true });
|
|
32889
33063
|
writeFileSync4(path, key, "utf-8");
|
|
32890
33064
|
}
|
|
32891
33065
|
function queueStopForSession(host, sessionId, signals, related, buildText) {
|
|
@@ -32997,9 +33171,9 @@ function spawnWorker(job) {
|
|
|
32997
33171
|
try {
|
|
32998
33172
|
root = workerRoot();
|
|
32999
33173
|
sweepStaleWorkerDirs(Date.now(), root);
|
|
33000
|
-
workDir = mkdtempSync2(
|
|
33174
|
+
workDir = mkdtempSync2(join13(root, "job-"));
|
|
33001
33175
|
chmodSync(workDir, 448);
|
|
33002
|
-
workFile =
|
|
33176
|
+
workFile = join13(workDir, `${randomBytes(4).toString("hex")}.json`);
|
|
33003
33177
|
writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
33004
33178
|
} catch (err) {
|
|
33005
33179
|
process.stderr.write(`[caveat:hook] worker writefile error: ${errorMessage4(err)}
|
|
@@ -33031,7 +33205,7 @@ function spawnWorker(job) {
|
|
|
33031
33205
|
async function runWorker(workFile) {
|
|
33032
33206
|
let raw;
|
|
33033
33207
|
try {
|
|
33034
|
-
raw =
|
|
33208
|
+
raw = readFileSync7(workFile, "utf-8");
|
|
33035
33209
|
} catch {
|
|
33036
33210
|
process.exit(0);
|
|
33037
33211
|
}
|
|
@@ -33095,7 +33269,7 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33095
33269
|
}
|
|
33096
33270
|
for (const entry of entries) {
|
|
33097
33271
|
if (!entry.startsWith("job-")) continue;
|
|
33098
|
-
const path =
|
|
33272
|
+
const path = join13(root, entry);
|
|
33099
33273
|
try {
|
|
33100
33274
|
if (!isOwnedWorkerDir(path, root)) continue;
|
|
33101
33275
|
const stat = lstatSync(path);
|
|
@@ -33107,29 +33281,29 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33107
33281
|
}
|
|
33108
33282
|
}
|
|
33109
33283
|
function workerRoot(base = tmpdir2()) {
|
|
33110
|
-
const root =
|
|
33111
|
-
|
|
33284
|
+
const root = join13(base, WORKER_ROOT);
|
|
33285
|
+
mkdirSync6(root, { recursive: true, mode: 448 });
|
|
33112
33286
|
const stat = lstatSync(root);
|
|
33113
33287
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33114
33288
|
if (!stat.isDirectory() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) throw new Error("worker root is unsafe");
|
|
33115
|
-
const marker =
|
|
33289
|
+
const marker = join13(root, WORKER_MARKER);
|
|
33116
33290
|
try {
|
|
33117
33291
|
writeFileSync5(marker, "caveat-worker/v1\n", { mode: 384, flag: "wx" });
|
|
33118
33292
|
} catch (error51) {
|
|
33119
33293
|
if (!(error51 && typeof error51 === "object" && "code" in error51 && error51.code === "EEXIST")) throw error51;
|
|
33120
33294
|
}
|
|
33121
33295
|
const markerStat = lstatSync(marker);
|
|
33122
|
-
if (!markerStat.isFile() || markerStat.isSymbolicLink() || !hasPrivateOwnership(markerStat, uid) ||
|
|
33296
|
+
if (!markerStat.isFile() || markerStat.isSymbolicLink() || !hasPrivateOwnership(markerStat, uid) || readFileSync7(marker, "utf-8") !== "caveat-worker/v1\n") throw new Error("worker root marker is invalid");
|
|
33123
33297
|
return root;
|
|
33124
33298
|
}
|
|
33125
33299
|
function isStaleWorkerJobDir(path) {
|
|
33126
33300
|
const entries = readdirSync2(path);
|
|
33127
33301
|
if (entries.length !== 1 || !entries[0].endsWith(".json")) return false;
|
|
33128
|
-
const file2 =
|
|
33302
|
+
const file2 = join13(path, entries[0]);
|
|
33129
33303
|
const stat = lstatSync(file2);
|
|
33130
33304
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33131
33305
|
if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
|
|
33132
|
-
return isKnownStaleWorkerJob(JSON.parse(
|
|
33306
|
+
return isKnownStaleWorkerJob(JSON.parse(readFileSync7(file2, "utf-8")));
|
|
33133
33307
|
}
|
|
33134
33308
|
function hasPrivateOwnership(stat, uid) {
|
|
33135
33309
|
return isPrivateOwnerStat(stat, uid);
|
|
@@ -33151,7 +33325,7 @@ function isKnownStaleWorkerJob(value) {
|
|
|
33151
33325
|
}
|
|
33152
33326
|
function writeLastReindex(caveatHome, value) {
|
|
33153
33327
|
try {
|
|
33154
|
-
writeFileSync5(
|
|
33328
|
+
writeFileSync5(join13(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
|
|
33155
33329
|
} catch (err) {
|
|
33156
33330
|
process.stderr.write(`[caveat:hook] reindex status write error: ${errorMessage4(err)}
|
|
33157
33331
|
`);
|
|
@@ -33163,7 +33337,7 @@ async function runReindexWorker() {
|
|
|
33163
33337
|
return;
|
|
33164
33338
|
}
|
|
33165
33339
|
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33166
|
-
if (!ctx || !
|
|
33340
|
+
if (!ctx || !existsSync12(ctx.paths.dbPath)) {
|
|
33167
33341
|
process.stderr.write("[caveat:hook] auto reindex skipped: index database does not exist\n");
|
|
33168
33342
|
return;
|
|
33169
33343
|
}
|
|
@@ -33230,7 +33404,7 @@ function buildToolErrorReminder(job, hits) {
|
|
|
33230
33404
|
const mode = hookCodexSidecarMode();
|
|
33231
33405
|
if (mode === "off") return base;
|
|
33232
33406
|
const projectRoot = process.cwd();
|
|
33233
|
-
const hasSidecarConfig =
|
|
33407
|
+
const hasSidecarConfig = existsSync12(join13(projectRoot, ".codex-sidecar.yml"));
|
|
33234
33408
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33235
33409
|
const advisory = runCodexSidecarAdvisory({
|
|
33236
33410
|
searchText: job.failureText,
|
|
@@ -33266,7 +33440,7 @@ function buildStopReminder(signals, related) {
|
|
|
33266
33440
|
const mode = hookCodexSidecarMode();
|
|
33267
33441
|
if (mode === "off") return base;
|
|
33268
33442
|
const projectRoot = process.cwd();
|
|
33269
|
-
const hasSidecarConfig =
|
|
33443
|
+
const hasSidecarConfig = existsSync12(join13(projectRoot, ".codex-sidecar.yml"));
|
|
33270
33444
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33271
33445
|
const advisory = runCodexSidecarAdvisory({
|
|
33272
33446
|
searchText: struggleSearchText(signals),
|
|
@@ -33406,9 +33580,9 @@ async function runHook(name, arg) {
|
|
|
33406
33580
|
|
|
33407
33581
|
// src/commands/codexHookCmd.ts
|
|
33408
33582
|
import { spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
|
|
33409
|
-
import { existsSync as
|
|
33583
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
33410
33584
|
import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
|
|
33411
|
-
import { join as
|
|
33585
|
+
import { join as join14 } from "node:path";
|
|
33412
33586
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
33413
33587
|
var CODEX_HOST = {
|
|
33414
33588
|
agent: "codex",
|
|
@@ -33438,10 +33612,10 @@ function processExitCodeFromText(text) {
|
|
|
33438
33612
|
return m ? Number(m[1]) : null;
|
|
33439
33613
|
}
|
|
33440
33614
|
function transcriptToolOutput(transcriptPath, toolUseId) {
|
|
33441
|
-
if (!transcriptPath || !toolUseId || !
|
|
33615
|
+
if (!transcriptPath || !toolUseId || !existsSync13(transcriptPath)) return null;
|
|
33442
33616
|
let raw = "";
|
|
33443
33617
|
try {
|
|
33444
|
-
raw =
|
|
33618
|
+
raw = readFileSync8(transcriptPath, "utf-8");
|
|
33445
33619
|
} catch {
|
|
33446
33620
|
return null;
|
|
33447
33621
|
}
|
|
@@ -33585,7 +33759,7 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
|
33585
33759
|
async function runCodexWorker(workFile) {
|
|
33586
33760
|
let raw;
|
|
33587
33761
|
try {
|
|
33588
|
-
raw =
|
|
33762
|
+
raw = readFileSync8(workFile, "utf-8");
|
|
33589
33763
|
} catch {
|
|
33590
33764
|
process.exit(0);
|
|
33591
33765
|
}
|
|
@@ -33602,7 +33776,7 @@ async function runCodexWorker(workFile) {
|
|
|
33602
33776
|
await processCodexWorkerJob(job);
|
|
33603
33777
|
process.exit(0);
|
|
33604
33778
|
}
|
|
33605
|
-
function runDiagnostics(codexHome = process.env.CODEX_HOME ??
|
|
33779
|
+
function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join14(homedir3(), ".codex")) {
|
|
33606
33780
|
const features = spawnSync5("codex", ["features", "list"], {
|
|
33607
33781
|
encoding: "utf-8",
|
|
33608
33782
|
maxBuffer: 1024 * 1024,
|
|
@@ -33707,10 +33881,151 @@ async function runCodexHook(name, arg) {
|
|
|
33707
33881
|
process.exit(0);
|
|
33708
33882
|
}
|
|
33709
33883
|
|
|
33884
|
+
// src/commands/cursorHookCmd.ts
|
|
33885
|
+
import { homedir as homedir4 } from "node:os";
|
|
33886
|
+
import { join as join15 } from "node:path";
|
|
33887
|
+
var CURSOR_HOST = {
|
|
33888
|
+
agent: "cursor",
|
|
33889
|
+
stderrTag: "caveat:cursor-hook",
|
|
33890
|
+
errorCode: "CAVEAT.CURSOR_HOOK_FAILED",
|
|
33891
|
+
stopStateDir: "cursor-stop-state",
|
|
33892
|
+
stopDedupeKey: "cursor-stop-reminder"
|
|
33893
|
+
};
|
|
33894
|
+
function cursorContextOutput(text) {
|
|
33895
|
+
return JSON.stringify({ additional_context: text });
|
|
33896
|
+
}
|
|
33897
|
+
function cursorSessionId(payload) {
|
|
33898
|
+
for (const key of ["conversation_id", "session_id", "sessionId"]) {
|
|
33899
|
+
const value = payload[key];
|
|
33900
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
33901
|
+
}
|
|
33902
|
+
return "_unknown";
|
|
33903
|
+
}
|
|
33904
|
+
function cursorPrompt(payload) {
|
|
33905
|
+
return typeof payload.prompt === "string" ? payload.prompt : "";
|
|
33906
|
+
}
|
|
33907
|
+
function isCursorToolError(payload) {
|
|
33908
|
+
if (payload.hook_event_name === "postToolUseFailure") return true;
|
|
33909
|
+
if (payload.is_error === true) return true;
|
|
33910
|
+
if (typeof payload.error === "string" && payload.error.length > 0) return true;
|
|
33911
|
+
const resp = payload.tool_response ?? payload.toolResponse;
|
|
33912
|
+
if (resp !== null && typeof resp === "object" && !Array.isArray(resp)) {
|
|
33913
|
+
if (resp.is_error === true) return true;
|
|
33914
|
+
}
|
|
33915
|
+
return false;
|
|
33916
|
+
}
|
|
33917
|
+
function loadSignalsSafely3(path) {
|
|
33918
|
+
try {
|
|
33919
|
+
return readSessionSignals(path);
|
|
33920
|
+
} catch (err) {
|
|
33921
|
+
process.stderr.write(`[caveat:cursor-hook] transcript read error: ${errorMessage4(err)}
|
|
33922
|
+
`);
|
|
33923
|
+
return null;
|
|
33924
|
+
}
|
|
33925
|
+
}
|
|
33926
|
+
function runDiagnostics2(cursorDir = join15(homedir4(), ".cursor")) {
|
|
33927
|
+
const installation = detectCursorHookInstallation(cursorDir);
|
|
33928
|
+
process.stdout.write(`${JSON.stringify({
|
|
33929
|
+
installation: installation.installation,
|
|
33930
|
+
cursorDir,
|
|
33931
|
+
hooksPath: installation.hooksPath,
|
|
33932
|
+
installedHooks: installation.hooks
|
|
33933
|
+
}, null, 2)}
|
|
33934
|
+
`);
|
|
33935
|
+
}
|
|
33936
|
+
async function runCursorHook(name, arg) {
|
|
33937
|
+
if (name === "diagnostics") {
|
|
33938
|
+
runDiagnostics2(arg);
|
|
33939
|
+
return;
|
|
33940
|
+
}
|
|
33941
|
+
let raw = "";
|
|
33942
|
+
try {
|
|
33943
|
+
raw = await readStdin();
|
|
33944
|
+
} catch (err) {
|
|
33945
|
+
process.stderr.write(`[caveat:cursor-hook] stdin read error: ${errorMessage4(err)}
|
|
33946
|
+
`);
|
|
33947
|
+
process.exit(0);
|
|
33948
|
+
}
|
|
33949
|
+
const payload = parsePayload(CURSOR_HOST, raw);
|
|
33950
|
+
const sessionId = cursorSessionId(payload);
|
|
33951
|
+
const contexts = name === "stop" ? [] : drainForSession(CURSOR_HOST, sessionId);
|
|
33952
|
+
if (name === "user-prompt-submit") {
|
|
33953
|
+
const prompt = cursorPrompt(payload);
|
|
33954
|
+
const hits = searchCaveatsSafely(CURSOR_HOST, {
|
|
33955
|
+
topicText: prompt,
|
|
33956
|
+
failureText: prompt,
|
|
33957
|
+
surface: "user_prompt"
|
|
33958
|
+
});
|
|
33959
|
+
if (hits.length > 0) contexts.push(userPromptSubmitReminderText(hits));
|
|
33960
|
+
const compacted = compactContexts(CURSOR_HOST, contexts);
|
|
33961
|
+
if (compacted.length > 0) {
|
|
33962
|
+
process.stdout.write(`${cursorContextOutput(compacted.join("\n\n"))}
|
|
33963
|
+
`);
|
|
33964
|
+
}
|
|
33965
|
+
process.exit(0);
|
|
33966
|
+
}
|
|
33967
|
+
if (name === "post-tool-use") {
|
|
33968
|
+
if (isCursorToolError(payload)) {
|
|
33969
|
+
const errText = extractToolResponseText(
|
|
33970
|
+
payload.tool_response ?? payload.toolResponse ?? payload.error ?? payload
|
|
33971
|
+
);
|
|
33972
|
+
const hits = searchCaveatsSafely(CURSOR_HOST, {
|
|
33973
|
+
topicText: errText,
|
|
33974
|
+
failureText: errText,
|
|
33975
|
+
surface: "tool_error"
|
|
33976
|
+
});
|
|
33977
|
+
if (hits.length > 0) contexts.push(toolErrorReminderText(hits));
|
|
33978
|
+
}
|
|
33979
|
+
const compacted = compactContexts(CURSOR_HOST, contexts);
|
|
33980
|
+
if (compacted.length > 0) {
|
|
33981
|
+
process.stdout.write(`${cursorContextOutput(compacted.join("\n\n"))}
|
|
33982
|
+
`);
|
|
33983
|
+
}
|
|
33984
|
+
process.exit(0);
|
|
33985
|
+
}
|
|
33986
|
+
if (name === "stop") {
|
|
33987
|
+
const ctx = buildContextSafely(CURSOR_HOST);
|
|
33988
|
+
if (ctx) {
|
|
33989
|
+
try {
|
|
33990
|
+
maybeSweepPendingDirs(ctx.caveatHome);
|
|
33991
|
+
} catch (err) {
|
|
33992
|
+
process.stderr.write(`[caveat:cursor-hook] pending sweep error: ${errorMessage4(err)}
|
|
33993
|
+
`);
|
|
33994
|
+
}
|
|
33995
|
+
try {
|
|
33996
|
+
maybeTriggerAutoReindex(ctx);
|
|
33997
|
+
} catch (err) {
|
|
33998
|
+
process.stderr.write(`[caveat:cursor-hook] auto reindex trigger error: ${errorMessage4(err)}
|
|
33999
|
+
`);
|
|
34000
|
+
}
|
|
34001
|
+
try {
|
|
34002
|
+
maybeTriggerAutoSync(ctx);
|
|
34003
|
+
} catch (err) {
|
|
34004
|
+
process.stderr.write(`[caveat:cursor-hook] auto sync trigger error: ${errorMessage4(err)}
|
|
34005
|
+
`);
|
|
34006
|
+
}
|
|
34007
|
+
}
|
|
34008
|
+
if (payload.stop_hook_active === true) process.exit(0);
|
|
34009
|
+
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
34010
|
+
const signals = transcriptPath ? loadSignalsSafely3(transcriptPath) : null;
|
|
34011
|
+
if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
|
|
34012
|
+
const related = searchCaveatsSafely(CURSOR_HOST, signals.errorSnippets.map((failureText) => ({
|
|
34013
|
+
topicText: "",
|
|
34014
|
+
failureText,
|
|
34015
|
+
surface: "stop"
|
|
34016
|
+
})));
|
|
34017
|
+
queueStopForSession(CURSOR_HOST, sessionId, signals, related, () => stopReminderText(signals, related));
|
|
34018
|
+
process.exit(0);
|
|
34019
|
+
}
|
|
34020
|
+
process.stderr.write(`[caveat:cursor-hook] unknown hook name: ${name}
|
|
34021
|
+
`);
|
|
34022
|
+
process.exit(0);
|
|
34023
|
+
}
|
|
34024
|
+
|
|
33710
34025
|
// src/commands/pull.ts
|
|
33711
|
-
import { existsSync as
|
|
34026
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
33712
34027
|
async function runPull(ctx) {
|
|
33713
|
-
const hasCommunityDir =
|
|
34028
|
+
const hasCommunityDir = existsSync14(ctx.paths.communityDir);
|
|
33714
34029
|
if (!hasCommunityDir) {
|
|
33715
34030
|
ctx.logger.info(
|
|
33716
34031
|
"no community repos yet \u2014 add one with `caveat community add <github-url>`."
|
|
@@ -33810,9 +34125,9 @@ async function runSync(ctx, opts, dependencies = {}) {
|
|
|
33810
34125
|
|
|
33811
34126
|
// src/commands/codexSidecar.ts
|
|
33812
34127
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
33813
|
-
import { closeSync, constants as
|
|
34128
|
+
import { closeSync, constants as constants4, fstatSync, lstatSync as lstatSync2, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync3, openSync, readSync as readSync2, realpathSync as realpathSync4, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
33814
34129
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
33815
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
34130
|
+
import { basename as basename2, dirname as dirname6, join as join16 } from "node:path";
|
|
33816
34131
|
import { cwd, exit } from "node:process";
|
|
33817
34132
|
function runCodexSidecarDiagnostics(logger, opts) {
|
|
33818
34133
|
const plan = buildCodexSidecarDiagnosticsCommand({
|
|
@@ -33844,8 +34159,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
|
|
|
33844
34159
|
process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
|
|
33845
34160
|
exit(0);
|
|
33846
34161
|
}
|
|
33847
|
-
const contextDir = mkdtempSync3(
|
|
33848
|
-
const contextFile =
|
|
34162
|
+
const contextDir = mkdtempSync3(join16(tmpdir4(), "caveat-sidecar-context-"));
|
|
34163
|
+
const contextFile = join16(contextDir, "context.json");
|
|
33849
34164
|
let status2 = 1;
|
|
33850
34165
|
try {
|
|
33851
34166
|
const blocks = collectCaveatContextBlocks(ctx, {
|
|
@@ -33878,7 +34193,7 @@ function readHookSignalAdditionalContextFile(path, testProbe) {
|
|
|
33878
34193
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33879
34194
|
assertPrivateRegular(before, uid, platform);
|
|
33880
34195
|
testProbe?.afterLstat?.();
|
|
33881
|
-
const fd = openSync(path,
|
|
34196
|
+
const fd = openSync(path, constants4.O_RDONLY | constants4.O_NONBLOCK | (constants4.O_NOFOLLOW ?? 0));
|
|
33882
34197
|
let raw;
|
|
33883
34198
|
try {
|
|
33884
34199
|
const opened = fstatSync(fd);
|
|
@@ -34008,7 +34323,7 @@ function executePlan(logger, command, args, options = {}) {
|
|
|
34008
34323
|
}
|
|
34009
34324
|
function saveStructuredResult(path, stdout) {
|
|
34010
34325
|
const parsed = JSON.parse(stdout);
|
|
34011
|
-
|
|
34326
|
+
mkdirSync7(dirname6(path), { recursive: true });
|
|
34012
34327
|
writeFileSync7(path, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
34013
34328
|
}
|
|
34014
34329
|
function shellDisplayQuote(value) {
|
|
@@ -34097,8 +34412,8 @@ function runCommunityRemove(ctx, handle, opts) {
|
|
|
34097
34412
|
|
|
34098
34413
|
// src/commands/factoryDiagnostics.ts
|
|
34099
34414
|
import { execFileSync } from "node:child_process";
|
|
34100
|
-
import { existsSync as
|
|
34101
|
-
import { join as
|
|
34415
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
|
|
34416
|
+
import { join as join17 } from "node:path";
|
|
34102
34417
|
import { DatabaseSync } from "node:sqlite";
|
|
34103
34418
|
import { parse as parseToml2 } from "smol-toml";
|
|
34104
34419
|
var status = (ok, reason) => ({ status: ok ? "ready" : "not_ready", reason_code: ok ? "ready" : reason });
|
|
@@ -34110,10 +34425,10 @@ function isRecord2(value) {
|
|
|
34110
34425
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34111
34426
|
}
|
|
34112
34427
|
function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
34113
|
-
const path =
|
|
34114
|
-
if (!
|
|
34428
|
+
const path = join17(home, ".claude.json");
|
|
34429
|
+
if (!existsSync15(path)) return status(false, "not_registered");
|
|
34115
34430
|
try {
|
|
34116
|
-
const value = JSON.parse(
|
|
34431
|
+
const value = JSON.parse(readFileSync9(path, "utf8"));
|
|
34117
34432
|
if (!isRecord2(value) || !isRecord2(value.mcpServers)) return status(false, "not_registered");
|
|
34118
34433
|
return status(isCaveatClaudeMcpRegistration(value.mcpServers.caveat, nodePath, cliScriptPath), "not_registered");
|
|
34119
34434
|
} catch {
|
|
@@ -34122,7 +34437,7 @@ function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
|
34122
34437
|
}
|
|
34123
34438
|
function claudeHooks(home, nodePath, cliScriptPath) {
|
|
34124
34439
|
try {
|
|
34125
|
-
const settings = JSON.parse(
|
|
34440
|
+
const settings = JSON.parse(readFileSync9(join17(home, ".claude", "settings.json"), "utf8"));
|
|
34126
34441
|
const present = (event, subcommand) => settings.hooks?.[event]?.some((entry) => entry.hooks?.some((item) => typeof item.command === "string" && isCanonicalCaveatClaudeHookCommand(item.command, subcommand, nodePath, cliScriptPath))) ?? false;
|
|
34127
34442
|
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")) };
|
|
34128
34443
|
} catch {
|
|
@@ -34144,7 +34459,7 @@ function strictSearchSchema(db) {
|
|
|
34144
34459
|
return columns.map((column) => `${column.name}:${column.hidden}`).join(",") === "id:0,title:0,body:0,tags:0,entries_fts:1,rank:1";
|
|
34145
34460
|
}
|
|
34146
34461
|
function database(path) {
|
|
34147
|
-
if (!
|
|
34462
|
+
if (!existsSync15(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
|
|
34148
34463
|
try {
|
|
34149
34464
|
const db = new DatabaseSync(path, { readOnly: true });
|
|
34150
34465
|
try {
|
|
@@ -34169,10 +34484,10 @@ function database(path) {
|
|
|
34169
34484
|
}
|
|
34170
34485
|
}
|
|
34171
34486
|
function codexFeature(codexHome) {
|
|
34172
|
-
const path =
|
|
34173
|
-
if (!
|
|
34487
|
+
const path = join17(codexHome, "config.toml");
|
|
34488
|
+
if (!existsSync15(path)) return status(false, "feature_disabled");
|
|
34174
34489
|
try {
|
|
34175
|
-
const config2 = parseToml2(
|
|
34490
|
+
const config2 = parseToml2(readFileSync9(path, "utf8"));
|
|
34176
34491
|
if (!isRecord2(config2.features)) return status(false, "feature_disabled");
|
|
34177
34492
|
const features = config2.features;
|
|
34178
34493
|
return status(features.hooks === true && features.codex_hooks === void 0, "feature_disabled");
|
|
@@ -34181,7 +34496,7 @@ function codexFeature(codexHome) {
|
|
|
34181
34496
|
}
|
|
34182
34497
|
}
|
|
34183
34498
|
function codexHooks(codexHome, nodePath, cliScriptPath) {
|
|
34184
|
-
const value = JSON.parse(
|
|
34499
|
+
const value = JSON.parse(readFileSync9(join17(codexHome, "hooks.json"), "utf8"));
|
|
34185
34500
|
if (!isRecord2(value) || !isRecord2(value.hooks)) throw Error("config_unreadable");
|
|
34186
34501
|
const hooks = value.hooks;
|
|
34187
34502
|
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)));
|
|
@@ -34216,7 +34531,7 @@ function sync(own) {
|
|
|
34216
34531
|
return unverified("upstream_unavailable");
|
|
34217
34532
|
}
|
|
34218
34533
|
}
|
|
34219
|
-
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ??
|
|
34534
|
+
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join17(ctx.userHome, ".codex")) {
|
|
34220
34535
|
const nodePath = process.execPath;
|
|
34221
34536
|
const cliScriptPath = process.argv[1] ?? "";
|
|
34222
34537
|
const db = database(ctx.paths.dbPath);
|
|
@@ -34291,7 +34606,7 @@ for (const action of ["resolve", "reopen"]) runtimeErrors.command(`${action} <fi
|
|
|
34291
34606
|
});
|
|
34292
34607
|
program.command("init").description(
|
|
34293
34608
|
"Initialize ~/.caveatrc.json, ~/.caveat/, and register Claude Code integration. Add knowledge sources later with `caveat community add <github-url>`."
|
|
34294
|
-
).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--sync [url]", "initialize private sync (optionally with its URL)").option("--publish-target [url]", "configure the sealed public mirror target").option("--yes", "approve creating conventional GitHub repositories", false).option("--skip-codex-hook", "skip Codex hook installation", false).option("--dry-run", "show planned changes without writing", false).option(
|
|
34609
|
+
).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--sync [url]", "initialize private sync (optionally with its URL)").option("--publish-target [url]", "configure the sealed public mirror target").option("--yes", "approve creating conventional GitHub repositories", false).option("--skip-codex-hook", "skip Codex hook installation", false).option("--skip-cursor-hook", "skip Cursor hook installation", false).option("--dry-run", "show planned changes without writing", false).option(
|
|
34295
34610
|
"--pending-stale-days <days>",
|
|
34296
34611
|
"sweep `<caveatHome>/pending/<sessionId>/` whose newest entry is older than this (default 7)",
|
|
34297
34612
|
(raw) => {
|
|
@@ -34311,7 +34626,8 @@ program.command("init").description(
|
|
|
34311
34626
|
sync: opts.sync,
|
|
34312
34627
|
publishTarget: opts.publishTarget,
|
|
34313
34628
|
yes: opts.yes,
|
|
34314
|
-
skipCodexHook: opts.skipCodexHook
|
|
34629
|
+
skipCodexHook: opts.skipCodexHook,
|
|
34630
|
+
skipCursorHook: opts.skipCursorHook
|
|
34315
34631
|
});
|
|
34316
34632
|
}
|
|
34317
34633
|
);
|
|
@@ -34439,6 +34755,57 @@ codexHook.command("stop").description("Run the Codex Stop hook").action(async ()
|
|
|
34439
34755
|
codexHook.command("worker <workFile>").description("Run the detached Codex hook worker").action(async (workFile) => {
|
|
34440
34756
|
await runCodexHook("worker", workFile);
|
|
34441
34757
|
});
|
|
34758
|
+
var cursorHook = program.command("cursor-hook").description("Install or run Cursor hooks for Caveat");
|
|
34759
|
+
cursorHook.command("install").description("Install Caveat hooks into ~/.cursor/hooks.json (factory hooks are kept)").option("--dry-run", "show planned changes without writing", false).option("--cursor-dir <path>", "Cursor home directory", `${process.env.HOME}/.cursor`).action((opts) => {
|
|
34760
|
+
const cliScriptPath = process.argv[1];
|
|
34761
|
+
if (!cliScriptPath) {
|
|
34762
|
+
process.stderr.write("[caveat:error] cannot determine CLI script path\n");
|
|
34763
|
+
process.exit(1);
|
|
34764
|
+
}
|
|
34765
|
+
const result = installCursorHooks({
|
|
34766
|
+
cursorDir: opts.cursorDir,
|
|
34767
|
+
cliScriptPath,
|
|
34768
|
+
nodePath: resolveHookNodePath(),
|
|
34769
|
+
dryRun: opts.dryRun,
|
|
34770
|
+
logger: stdoutLogger
|
|
34771
|
+
});
|
|
34772
|
+
stdoutLogger.info(`beforeSubmitPrompt hook: ${result.hooks.beforeSubmitPrompt}`);
|
|
34773
|
+
stdoutLogger.info(`postToolUse hook: ${result.hooks.postToolUse}`);
|
|
34774
|
+
stdoutLogger.info(`postToolUseFailure hook: ${result.hooks.postToolUseFailure}`);
|
|
34775
|
+
stdoutLogger.info(`stop hook: ${result.hooks.stop}`);
|
|
34776
|
+
if (result.backupPath) stdoutLogger.info(`hooks.json backed up: ${result.backupPath}`);
|
|
34777
|
+
});
|
|
34778
|
+
cursorHook.command("uninstall").description("Remove Caveat-owned Cursor hooks from ~/.cursor/hooks.json").option("--dry-run", "show planned changes without writing", false).option("--cursor-dir <path>", "Cursor home directory", `${process.env.HOME}/.cursor`).action((opts) => {
|
|
34779
|
+
const cliScriptPath = process.argv[1];
|
|
34780
|
+
if (!cliScriptPath) {
|
|
34781
|
+
process.stderr.write("[caveat:error] cannot determine CLI script path\n");
|
|
34782
|
+
process.exit(1);
|
|
34783
|
+
}
|
|
34784
|
+
const result = uninstallCursorHooks({
|
|
34785
|
+
cursorDir: opts.cursorDir,
|
|
34786
|
+
cliScriptPath,
|
|
34787
|
+
nodePath: resolveHookNodePath(),
|
|
34788
|
+
dryRun: opts.dryRun,
|
|
34789
|
+
logger: stdoutLogger
|
|
34790
|
+
});
|
|
34791
|
+
stdoutLogger.info(`beforeSubmitPrompt hook: ${result.hooks.beforeSubmitPrompt === "added" ? "removed" : "not present"}`);
|
|
34792
|
+
stdoutLogger.info(`postToolUse hook: ${result.hooks.postToolUse === "added" ? "removed" : "not present"}`);
|
|
34793
|
+
stdoutLogger.info(`postToolUseFailure hook: ${result.hooks.postToolUseFailure === "added" ? "removed" : "not present"}`);
|
|
34794
|
+
stdoutLogger.info(`stop hook: ${result.hooks.stop === "added" ? "removed" : "not present"}`);
|
|
34795
|
+
if (result.backupPath) stdoutLogger.info(`hooks.json backed up: ${result.backupPath}`);
|
|
34796
|
+
});
|
|
34797
|
+
cursorHook.command("diagnostics").description("Check local Cursor hook installation").option("--cursor-dir <path>", "Cursor home directory", `${process.env.HOME}/.cursor`).action(async (opts) => {
|
|
34798
|
+
await runCursorHook("diagnostics", opts.cursorDir);
|
|
34799
|
+
});
|
|
34800
|
+
cursorHook.command("user-prompt-submit").description("Run the Cursor beforeSubmitPrompt hook").action(async () => {
|
|
34801
|
+
await runCursorHook("user-prompt-submit");
|
|
34802
|
+
});
|
|
34803
|
+
cursorHook.command("post-tool-use").description("Run the Cursor postToolUse / postToolUseFailure hook").action(async () => {
|
|
34804
|
+
await runCursorHook("post-tool-use");
|
|
34805
|
+
});
|
|
34806
|
+
cursorHook.command("stop").description("Run the Cursor stop hook").action(async () => {
|
|
34807
|
+
await runCursorHook("stop");
|
|
34808
|
+
});
|
|
34442
34809
|
var codexSidecar = program.command("codex-sidecar").description("Check Codex sidecar availability for the current repository");
|
|
34443
34810
|
codexSidecar.command("diagnostics").description("Run codex-sidecar diagnostics for this repository").option("--project <path>", "repository root to check").option("--preset <preset>", "codex-sidecar preset", "review").option("--command <command>", "codex-sidecar executable", "codex-sidecar").option("--node-cli <path>", "development path to codex-sidecar CLI JS").option("--save-result <path>", "write structured SidecarResult JSON to this path").action((opts) => {
|
|
34444
34811
|
runCodexSidecarDiagnostics(stdoutLogger, opts);
|