caveat-cli 0.17.7 → 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 +492 -124
- 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";
|
|
@@ -6998,9 +6998,10 @@ function isCaveatClaudeHookCommand(actual, event) {
|
|
|
6998
6998
|
return lower.includes("caveat") && actual.includes(`hook ${event}`);
|
|
6999
6999
|
}
|
|
7000
7000
|
function isCanonicalCaveatClaudeHookCommand(actual, event, nodePath, cliScriptPath) {
|
|
7001
|
-
if (actual !== hookCommand(nodePath, cliScriptPath, event)) return false;
|
|
7002
7001
|
const tokens = commandTokens(actual);
|
|
7003
|
-
|
|
7002
|
+
if (tokens?.length !== 4 || tokens[2] !== "hook" || tokens[3] !== event) return false;
|
|
7003
|
+
if (actual !== hookCommand(tokens[0], tokens[1], event)) return false;
|
|
7004
|
+
return isCanonicalAsset(tokens[0], nodePath, constants.X_OK) && isCanonicalAsset(tokens[1], cliScriptPath, constants.R_OK);
|
|
7004
7005
|
}
|
|
7005
7006
|
function isCaveatClaudeMcpRegistration(value, nodePath, cliScriptPath) {
|
|
7006
7007
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -7511,6 +7512,150 @@ function detectCodexHookInstallation(codexHome) {
|
|
|
7511
7512
|
};
|
|
7512
7513
|
}
|
|
7513
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
|
+
|
|
7514
7659
|
// src/ghSetup.ts
|
|
7515
7660
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7516
7661
|
import { readSync } from "node:fs";
|
|
@@ -7558,8 +7703,8 @@ function askOnce(question) {
|
|
|
7558
7703
|
}
|
|
7559
7704
|
|
|
7560
7705
|
// src/nodePath.ts
|
|
7561
|
-
import { existsSync as
|
|
7562
|
-
import { delimiter, join as
|
|
7706
|
+
import { existsSync as existsSync5, realpathSync as realpathSync2 } from "node:fs";
|
|
7707
|
+
import { delimiter, join as join6 } from "node:path";
|
|
7563
7708
|
var defaultRealpath = (path) => realpathSync2.native(path);
|
|
7564
7709
|
function safeRealpath(path, realpath = defaultRealpath) {
|
|
7565
7710
|
try {
|
|
@@ -7572,7 +7717,7 @@ function resolveHookNodePath({
|
|
|
7572
7717
|
env = process.env,
|
|
7573
7718
|
execPath = process.execPath,
|
|
7574
7719
|
platform = process.platform,
|
|
7575
|
-
exists =
|
|
7720
|
+
exists = existsSync5,
|
|
7576
7721
|
realpath = defaultRealpath
|
|
7577
7722
|
} = {}) {
|
|
7578
7723
|
const execRealpath = safeRealpath(execPath, realpath);
|
|
@@ -7580,7 +7725,7 @@ function resolveHookNodePath({
|
|
|
7580
7725
|
const names = nodeExecutableNames(platform);
|
|
7581
7726
|
for (const dir of pathEnv.split(delimiter).filter(Boolean)) {
|
|
7582
7727
|
for (const name of names) {
|
|
7583
|
-
const candidate =
|
|
7728
|
+
const candidate = join6(dir, name);
|
|
7584
7729
|
if (!exists(candidate)) continue;
|
|
7585
7730
|
const candidateRealpath = safeRealpath(candidate, realpath);
|
|
7586
7731
|
if (execRealpath && candidateRealpath && candidateRealpath === execRealpath) {
|
|
@@ -7592,14 +7737,14 @@ function resolveHookNodePath({
|
|
|
7592
7737
|
}
|
|
7593
7738
|
|
|
7594
7739
|
// src/commands/publish.ts
|
|
7595
|
-
import { existsSync as
|
|
7596
|
-
import { join as
|
|
7740
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
7741
|
+
import { join as join8 } from "node:path";
|
|
7597
7742
|
|
|
7598
7743
|
// src/commands/codexSidecarAdvisory.ts
|
|
7599
7744
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7600
|
-
import { mkdtempSync, readFileSync as
|
|
7745
|
+
import { mkdtempSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7601
7746
|
import { tmpdir } from "node:os";
|
|
7602
|
-
import { join as
|
|
7747
|
+
import { join as join7 } from "node:path";
|
|
7603
7748
|
var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
|
|
7604
7749
|
var MAX_HOOK_SIDECAR_TIMEOUT_MS = 24e4;
|
|
7605
7750
|
function resolveHookSidecarTimeoutMs(raw) {
|
|
@@ -7655,11 +7800,11 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7655
7800
|
let resultDir;
|
|
7656
7801
|
let advisory;
|
|
7657
7802
|
try {
|
|
7658
|
-
resultDir = mkdtempSync(
|
|
7659
|
-
const resultFile =
|
|
7803
|
+
resultDir = mkdtempSync(join7(tmpdir(), "caveat-codex-advisory-"));
|
|
7804
|
+
const resultFile = join7(resultDir, "result.json");
|
|
7660
7805
|
args.push("--save-result", resultFile);
|
|
7661
7806
|
if (input.additionalContext) {
|
|
7662
|
-
const additionalContextFile =
|
|
7807
|
+
const additionalContextFile = join7(resultDir, "hook-signal.json");
|
|
7663
7808
|
writeFileSync2(additionalContextFile, JSON.stringify({ context: [input.additionalContext] }) + "\n", { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
7664
7809
|
args.push("--additional-context-file", additionalContextFile);
|
|
7665
7810
|
}
|
|
@@ -7687,7 +7832,7 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7687
7832
|
message: `sidecar command failed: ${sidecarFailureDetail(detail)}`
|
|
7688
7833
|
};
|
|
7689
7834
|
} else {
|
|
7690
|
-
const parsed = JSON.parse(
|
|
7835
|
+
const parsed = JSON.parse(readFileSync5(resultFile, "utf-8"));
|
|
7691
7836
|
if (parsed.status !== "ok" || typeof parsed.summary !== "string") {
|
|
7692
7837
|
advisory = {
|
|
7693
7838
|
status: "failed",
|
|
@@ -7755,7 +7900,7 @@ async function runPublish(ctx, opts, dependencies = {}) {
|
|
|
7755
7900
|
const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
|
|
7756
7901
|
const confirm = dependencies.confirm ?? askOnce;
|
|
7757
7902
|
const projectRoot = process.cwd();
|
|
7758
|
-
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) =>
|
|
7903
|
+
const hasCodexSidecarConfig = dependencies.hasCodexSidecarConfig ?? ((root) => existsSync6(join8(root, ".codex-sidecar.yml")));
|
|
7759
7904
|
const publishAdvisory = hasCodexSidecarConfig(projectRoot) ? (changes) => {
|
|
7760
7905
|
try {
|
|
7761
7906
|
return dependencies.runCodexSidecarAdvisory?.(changes, projectRoot) ?? formatCodexSidecarAdvisory(runCodexSidecarAdvisory({
|
|
@@ -7812,24 +7957,25 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7812
7957
|
const ghRunner = dependencies.ghRunner ?? runGh;
|
|
7813
7958
|
let publishTarget = ctx.config.publishTarget;
|
|
7814
7959
|
let codexHookState = "not-installed";
|
|
7960
|
+
let cursorHookState = "not-installed";
|
|
7815
7961
|
ensureUserConfig(ctx.userConfigPath);
|
|
7816
7962
|
ctx.logger.info(`user config: ${ctx.userConfigPath}`);
|
|
7817
|
-
if (!
|
|
7818
|
-
|
|
7819
|
-
|
|
7963
|
+
if (!existsSync7(ctx.paths.knowledgeRepo)) {
|
|
7964
|
+
mkdirSync3(ctx.paths.knowledgeRepo, { recursive: true });
|
|
7965
|
+
mkdirSync3(ctx.paths.entriesDir, { recursive: true });
|
|
7820
7966
|
ctx.logger.info(`knowledge repo scaffolded: ${ctx.paths.knowledgeRepo}`);
|
|
7821
7967
|
} else {
|
|
7822
7968
|
ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
|
|
7823
7969
|
}
|
|
7824
7970
|
migrateLegacyCommunityDir(ctx);
|
|
7825
|
-
const gitignorePath =
|
|
7826
|
-
if (!
|
|
7971
|
+
const gitignorePath = join9(ctx.paths.knowledgeRepo, ".gitignore");
|
|
7972
|
+
if (!existsSync7(gitignorePath)) {
|
|
7827
7973
|
writeFileSync3(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
|
|
7828
7974
|
ctx.logger.info(`.gitignore created: ${gitignorePath}`);
|
|
7829
7975
|
}
|
|
7830
7976
|
if (!opts.dryRun) {
|
|
7831
7977
|
const dbDir = dirname3(ctx.paths.dbPath);
|
|
7832
|
-
if (!
|
|
7978
|
+
if (!existsSync7(dbDir)) mkdirSync3(dbDir, { recursive: true });
|
|
7833
7979
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
7834
7980
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
7835
7981
|
for (const failure of failures) {
|
|
@@ -7943,7 +8089,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7943
8089
|
ctx.logger.warn("cannot determine CLI script path; skipping Claude integration");
|
|
7944
8090
|
} else {
|
|
7945
8091
|
const result = installClaudeIntegration({
|
|
7946
|
-
claudeDir:
|
|
8092
|
+
claudeDir: join9(ctx.userHome, ".claude"),
|
|
7947
8093
|
cliScriptPath,
|
|
7948
8094
|
nodePath: resolveHookNodePath(),
|
|
7949
8095
|
dryRun: opts.dryRun,
|
|
@@ -7961,7 +8107,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7961
8107
|
codexHookState = "skipped";
|
|
7962
8108
|
ctx.logger.warn("cannot determine CLI script path; skipping Codex hook integration");
|
|
7963
8109
|
} else {
|
|
7964
|
-
const codexHome =
|
|
8110
|
+
const codexHome = join9(ctx.userHome, ".codex");
|
|
7965
8111
|
const result = installCodexHooks({
|
|
7966
8112
|
codexHome,
|
|
7967
8113
|
cliScriptPath,
|
|
@@ -7972,7 +8118,7 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7972
8118
|
if (result.feature === "blocked") {
|
|
7973
8119
|
codexHookState = "skipped";
|
|
7974
8120
|
ctx.logger.warn(
|
|
7975
|
-
`${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\`.`
|
|
7976
8122
|
);
|
|
7977
8123
|
} else if (opts.dryRun) {
|
|
7978
8124
|
codexHookState = "skipped";
|
|
@@ -7982,7 +8128,35 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }, depende
|
|
|
7982
8128
|
}
|
|
7983
8129
|
}
|
|
7984
8130
|
}
|
|
7985
|
-
|
|
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);
|
|
7986
8160
|
}
|
|
7987
8161
|
function detectCodexAvailability() {
|
|
7988
8162
|
const result = spawnSync4("codex --version", {
|
|
@@ -8003,36 +8177,37 @@ function gitOutput(args) {
|
|
|
8003
8177
|
const result = spawnSync4("git", args, { encoding: "utf-8" });
|
|
8004
8178
|
return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() : null;
|
|
8005
8179
|
}
|
|
8006
|
-
function reportEnvironmentSummary(ctx, publishTarget, codexHookState, dryRun) {
|
|
8180
|
+
function reportEnvironmentSummary(ctx, publishTarget, codexHookState, cursorHookState, dryRun) {
|
|
8007
8181
|
const prefix = dryRun ? "[dry-run] would have " : "";
|
|
8008
8182
|
const isRepo = gitOutput(["-C", ctx.paths.knowledgeRepo, "rev-parse", "--is-inside-work-tree"]) === "true";
|
|
8009
8183
|
const remote = isRepo ? gitOutput(["-C", ctx.paths.knowledgeRepo, "config", "--get", "remote.origin.url"]) : null;
|
|
8010
|
-
const communityCount =
|
|
8184
|
+
const communityCount = existsSync7(ctx.paths.communityDir) ? readdirSync(ctx.paths.communityDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
|
|
8011
8185
|
ctx.logger.info(`${prefix}environment summary:`);
|
|
8012
8186
|
ctx.logger.info(` own git: ${isRepo ? "repository" : "not initialized"}`);
|
|
8013
8187
|
ctx.logger.info(` private remote: ${remote || "not configured"}`);
|
|
8014
8188
|
ctx.logger.info(` publish target: ${publishTarget || "not configured"}`);
|
|
8015
8189
|
ctx.logger.info(` community sources: ${communityCount}`);
|
|
8016
8190
|
ctx.logger.info(` codex hook: ${codexHookState}`);
|
|
8191
|
+
ctx.logger.info(` cursor hook: ${cursorHookState}`);
|
|
8017
8192
|
}
|
|
8018
8193
|
function errorMessage(err) {
|
|
8019
8194
|
return err instanceof Error ? err.message : String(err);
|
|
8020
8195
|
}
|
|
8021
8196
|
function migrateLegacyCommunityDir(ctx) {
|
|
8022
|
-
const legacy =
|
|
8197
|
+
const legacy = join9(ctx.paths.knowledgeRepo, "community");
|
|
8023
8198
|
const current = ctx.paths.communityDir;
|
|
8024
8199
|
if (legacy === current) return;
|
|
8025
|
-
if (!
|
|
8026
|
-
if (
|
|
8200
|
+
if (!existsSync7(legacy)) return;
|
|
8201
|
+
if (existsSync7(current)) {
|
|
8027
8202
|
ctx.logger.warn(
|
|
8028
8203
|
`legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
|
|
8029
8204
|
);
|
|
8030
8205
|
return;
|
|
8031
8206
|
}
|
|
8032
|
-
|
|
8207
|
+
mkdirSync3(current, { recursive: true });
|
|
8033
8208
|
for (const entry of readdirSync(legacy, { withFileTypes: true })) {
|
|
8034
8209
|
if (!entry.isDirectory()) continue;
|
|
8035
|
-
renameSync(
|
|
8210
|
+
renameSync(join9(legacy, entry.name), join9(current, entry.name));
|
|
8036
8211
|
}
|
|
8037
8212
|
try {
|
|
8038
8213
|
rmdirSync(legacy);
|
|
@@ -8047,7 +8222,7 @@ function runUninstall(ctx, opts) {
|
|
|
8047
8222
|
process.exit(1);
|
|
8048
8223
|
}
|
|
8049
8224
|
const result = uninstallClaudeIntegration({
|
|
8050
|
-
claudeDir:
|
|
8225
|
+
claudeDir: join9(ctx.userHome, ".claude"),
|
|
8051
8226
|
cliScriptPath,
|
|
8052
8227
|
nodePath: resolveHookNodePath(),
|
|
8053
8228
|
dryRun: opts.dryRun,
|
|
@@ -8094,11 +8269,11 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
8094
8269
|
}
|
|
8095
8270
|
|
|
8096
8271
|
// src/commands/indexCmd.ts
|
|
8097
|
-
import { existsSync as
|
|
8272
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4 } from "node:fs";
|
|
8098
8273
|
import { dirname as dirname4 } from "node:path";
|
|
8099
8274
|
async function runIndex(ctx, opts) {
|
|
8100
8275
|
const dbDir = dirname4(ctx.paths.dbPath);
|
|
8101
|
-
if (!
|
|
8276
|
+
if (!existsSync8(dbDir)) mkdirSync4(dbDir, { recursive: true });
|
|
8102
8277
|
const keyProvider = createKeyserverKeyProvider({ caveatHome: ctx.caveatHome });
|
|
8103
8278
|
const failures = await prewarmSealedKeys({ paths: ctx.paths, keyProvider });
|
|
8104
8279
|
for (const failure of failures) {
|
|
@@ -8282,7 +8457,7 @@ function runStats(ctx) {
|
|
|
8282
8457
|
|
|
8283
8458
|
// src/commands/serve.ts
|
|
8284
8459
|
async function runServe(opts) {
|
|
8285
|
-
const { startServer } = await import("./server-
|
|
8460
|
+
const { startServer } = await import("./server-HKXLHXNN.js");
|
|
8286
8461
|
const { port, host } = startServer({ port: opts.port });
|
|
8287
8462
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8288
8463
|
`);
|
|
@@ -32354,7 +32529,7 @@ var StdioServerTransport = class {
|
|
|
32354
32529
|
|
|
32355
32530
|
// ../mcp/dist/context.js
|
|
32356
32531
|
import { homedir as homedir2 } from "node:os";
|
|
32357
|
-
import { join as
|
|
32532
|
+
import { join as join10 } from "node:path";
|
|
32358
32533
|
|
|
32359
32534
|
// ../mcp/dist/autoSyncTrigger.js
|
|
32360
32535
|
function triggerAutoSyncAfterWrite(caveatHome, logger) {
|
|
@@ -32373,7 +32548,7 @@ function triggerAutoSyncAfterWrite(caveatHome, logger) {
|
|
|
32373
32548
|
function buildMcpContext(overrides = {}) {
|
|
32374
32549
|
const userHome = overrides.userHome ?? homedir2();
|
|
32375
32550
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
32376
|
-
const userConfigPath =
|
|
32551
|
+
const userConfigPath = join10(userHome, ".caveatrc.json");
|
|
32377
32552
|
const logger = overrides.logger ?? stderrLogger;
|
|
32378
32553
|
const config2 = loadConfig(userConfigPath);
|
|
32379
32554
|
const paths = resolvePaths(caveatHome, config2.knowledgeRepo, userHome);
|
|
@@ -32522,12 +32697,12 @@ function handleListRecent(ctx, args) {
|
|
|
32522
32697
|
}
|
|
32523
32698
|
|
|
32524
32699
|
// ../mcp/dist/tools/pull.js
|
|
32525
|
-
import { existsSync as
|
|
32700
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
32526
32701
|
var pullInputShape = {};
|
|
32527
32702
|
async function handlePull(ctx, _args = {}) {
|
|
32528
32703
|
const pulled = [];
|
|
32529
32704
|
const indexed = [];
|
|
32530
|
-
if (
|
|
32705
|
+
if (existsSync9(ctx.paths.communityDir)) {
|
|
32531
32706
|
const results = await communityPull({
|
|
32532
32707
|
communityDir: ctx.paths.communityDir,
|
|
32533
32708
|
logger: ctx.logger
|
|
@@ -32683,28 +32858,28 @@ async function runMcpServer() {
|
|
|
32683
32858
|
import { spawn as spawn2 } from "node:child_process";
|
|
32684
32859
|
import {
|
|
32685
32860
|
chmodSync,
|
|
32686
|
-
existsSync as
|
|
32861
|
+
existsSync as existsSync12,
|
|
32687
32862
|
lstatSync,
|
|
32688
32863
|
mkdtempSync as mkdtempSync2,
|
|
32689
|
-
mkdirSync as
|
|
32864
|
+
mkdirSync as mkdirSync6,
|
|
32690
32865
|
readdirSync as readdirSync2,
|
|
32691
|
-
readFileSync as
|
|
32866
|
+
readFileSync as readFileSync7,
|
|
32692
32867
|
realpathSync as realpathSync3,
|
|
32693
32868
|
rmSync as rmSync2,
|
|
32694
32869
|
writeFileSync as writeFileSync5
|
|
32695
32870
|
} from "node:fs";
|
|
32696
32871
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
32697
|
-
import { basename, dirname as dirname5, join as
|
|
32872
|
+
import { basename, dirname as dirname5, join as join13 } from "node:path";
|
|
32698
32873
|
import { randomBytes } from "node:crypto";
|
|
32699
32874
|
|
|
32700
32875
|
// src/autoReindexTrigger.ts
|
|
32701
32876
|
import { spawn } from "node:child_process";
|
|
32702
|
-
import { existsSync as
|
|
32703
|
-
import { join as
|
|
32877
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
32878
|
+
import { join as join11 } from "node:path";
|
|
32704
32879
|
function maybeTriggerAutoReindex(ctx) {
|
|
32705
32880
|
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") return;
|
|
32706
|
-
if (!
|
|
32707
|
-
if (
|
|
32881
|
+
if (!existsSync10(ctx.paths.dbPath)) return;
|
|
32882
|
+
if (existsSync10(join11(ctx.caveatHome, "index", ".reindex-lock"))) return;
|
|
32708
32883
|
const current = computeEntriesDigest(ctx.paths);
|
|
32709
32884
|
const marker = readDigestMarker(ctx.caveatHome);
|
|
32710
32885
|
if (marker?.digest === current.digest && marker.fileCount === current.fileCount) return;
|
|
@@ -32730,8 +32905,8 @@ function maybeTriggerAutoSync(ctx, debounceMs = AUTO_SYNC_DEBOUNCE_MS) {
|
|
|
32730
32905
|
}
|
|
32731
32906
|
|
|
32732
32907
|
// src/hookShared.ts
|
|
32733
|
-
import { existsSync as
|
|
32734
|
-
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";
|
|
32735
32910
|
import { createHash } from "node:crypto";
|
|
32736
32911
|
var MAX_CONTEXT_BLOCKS = 3;
|
|
32737
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:";
|
|
@@ -32786,7 +32961,7 @@ function searchCaveatsSafely(host, input) {
|
|
|
32786
32961
|
let hits;
|
|
32787
32962
|
try {
|
|
32788
32963
|
const ctx = buildContextSafely(host);
|
|
32789
|
-
if (!ctx || !
|
|
32964
|
+
if (!ctx || !existsSync11(ctx.paths.dbPath)) return [];
|
|
32790
32965
|
caveatHome = ctx.caveatHome;
|
|
32791
32966
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32792
32967
|
const searchOptions = {
|
|
@@ -32872,19 +33047,19 @@ function stopSignalKey(signals, related) {
|
|
|
32872
33047
|
return createHash("sha256").update(body).digest("hex");
|
|
32873
33048
|
}
|
|
32874
33049
|
function stopStatePath(host, caveatHome, sessionId) {
|
|
32875
|
-
return
|
|
33050
|
+
return join12(caveatHome, host.stopStateDir, `${sanitizeStateId(sessionId)}.txt`);
|
|
32876
33051
|
}
|
|
32877
33052
|
function wasStopReminderQueued(host, caveatHome, sessionId, key) {
|
|
32878
33053
|
const path = stopStatePath(host, caveatHome, sessionId);
|
|
32879
33054
|
try {
|
|
32880
|
-
return
|
|
33055
|
+
return readFileSync6(path, "utf-8") === key;
|
|
32881
33056
|
} catch {
|
|
32882
33057
|
return false;
|
|
32883
33058
|
}
|
|
32884
33059
|
}
|
|
32885
33060
|
function markStopReminderQueued(host, caveatHome, sessionId, key) {
|
|
32886
33061
|
const path = stopStatePath(host, caveatHome, sessionId);
|
|
32887
|
-
|
|
33062
|
+
mkdirSync5(join12(caveatHome, host.stopStateDir), { recursive: true });
|
|
32888
33063
|
writeFileSync4(path, key, "utf-8");
|
|
32889
33064
|
}
|
|
32890
33065
|
function queueStopForSession(host, sessionId, signals, related, buildText) {
|
|
@@ -32996,9 +33171,9 @@ function spawnWorker(job) {
|
|
|
32996
33171
|
try {
|
|
32997
33172
|
root = workerRoot();
|
|
32998
33173
|
sweepStaleWorkerDirs(Date.now(), root);
|
|
32999
|
-
workDir = mkdtempSync2(
|
|
33174
|
+
workDir = mkdtempSync2(join13(root, "job-"));
|
|
33000
33175
|
chmodSync(workDir, 448);
|
|
33001
|
-
workFile =
|
|
33176
|
+
workFile = join13(workDir, `${randomBytes(4).toString("hex")}.json`);
|
|
33002
33177
|
writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
33003
33178
|
} catch (err) {
|
|
33004
33179
|
process.stderr.write(`[caveat:hook] worker writefile error: ${errorMessage4(err)}
|
|
@@ -33030,7 +33205,7 @@ function spawnWorker(job) {
|
|
|
33030
33205
|
async function runWorker(workFile) {
|
|
33031
33206
|
let raw;
|
|
33032
33207
|
try {
|
|
33033
|
-
raw =
|
|
33208
|
+
raw = readFileSync7(workFile, "utf-8");
|
|
33034
33209
|
} catch {
|
|
33035
33210
|
process.exit(0);
|
|
33036
33211
|
}
|
|
@@ -33094,7 +33269,7 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33094
33269
|
}
|
|
33095
33270
|
for (const entry of entries) {
|
|
33096
33271
|
if (!entry.startsWith("job-")) continue;
|
|
33097
|
-
const path =
|
|
33272
|
+
const path = join13(root, entry);
|
|
33098
33273
|
try {
|
|
33099
33274
|
if (!isOwnedWorkerDir(path, root)) continue;
|
|
33100
33275
|
const stat = lstatSync(path);
|
|
@@ -33106,29 +33281,29 @@ function sweepStaleWorkerDirs(now = Date.now(), root = workerRoot()) {
|
|
|
33106
33281
|
}
|
|
33107
33282
|
}
|
|
33108
33283
|
function workerRoot(base = tmpdir2()) {
|
|
33109
|
-
const root =
|
|
33110
|
-
|
|
33284
|
+
const root = join13(base, WORKER_ROOT);
|
|
33285
|
+
mkdirSync6(root, { recursive: true, mode: 448 });
|
|
33111
33286
|
const stat = lstatSync(root);
|
|
33112
33287
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33113
33288
|
if (!stat.isDirectory() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) throw new Error("worker root is unsafe");
|
|
33114
|
-
const marker =
|
|
33289
|
+
const marker = join13(root, WORKER_MARKER);
|
|
33115
33290
|
try {
|
|
33116
33291
|
writeFileSync5(marker, "caveat-worker/v1\n", { mode: 384, flag: "wx" });
|
|
33117
33292
|
} catch (error51) {
|
|
33118
33293
|
if (!(error51 && typeof error51 === "object" && "code" in error51 && error51.code === "EEXIST")) throw error51;
|
|
33119
33294
|
}
|
|
33120
33295
|
const markerStat = lstatSync(marker);
|
|
33121
|
-
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");
|
|
33122
33297
|
return root;
|
|
33123
33298
|
}
|
|
33124
33299
|
function isStaleWorkerJobDir(path) {
|
|
33125
33300
|
const entries = readdirSync2(path);
|
|
33126
33301
|
if (entries.length !== 1 || !entries[0].endsWith(".json")) return false;
|
|
33127
|
-
const file2 =
|
|
33302
|
+
const file2 = join13(path, entries[0]);
|
|
33128
33303
|
const stat = lstatSync(file2);
|
|
33129
33304
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33130
33305
|
if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
|
|
33131
|
-
return isKnownStaleWorkerJob(JSON.parse(
|
|
33306
|
+
return isKnownStaleWorkerJob(JSON.parse(readFileSync7(file2, "utf-8")));
|
|
33132
33307
|
}
|
|
33133
33308
|
function hasPrivateOwnership(stat, uid) {
|
|
33134
33309
|
return isPrivateOwnerStat(stat, uid);
|
|
@@ -33150,7 +33325,7 @@ function isKnownStaleWorkerJob(value) {
|
|
|
33150
33325
|
}
|
|
33151
33326
|
function writeLastReindex(caveatHome, value) {
|
|
33152
33327
|
try {
|
|
33153
|
-
writeFileSync5(
|
|
33328
|
+
writeFileSync5(join13(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
|
|
33154
33329
|
} catch (err) {
|
|
33155
33330
|
process.stderr.write(`[caveat:hook] reindex status write error: ${errorMessage4(err)}
|
|
33156
33331
|
`);
|
|
@@ -33162,7 +33337,7 @@ async function runReindexWorker() {
|
|
|
33162
33337
|
return;
|
|
33163
33338
|
}
|
|
33164
33339
|
const ctx = buildContextSafely(CLAUDE_HOST);
|
|
33165
|
-
if (!ctx || !
|
|
33340
|
+
if (!ctx || !existsSync12(ctx.paths.dbPath)) {
|
|
33166
33341
|
process.stderr.write("[caveat:hook] auto reindex skipped: index database does not exist\n");
|
|
33167
33342
|
return;
|
|
33168
33343
|
}
|
|
@@ -33229,7 +33404,7 @@ function buildToolErrorReminder(job, hits) {
|
|
|
33229
33404
|
const mode = hookCodexSidecarMode();
|
|
33230
33405
|
if (mode === "off") return base;
|
|
33231
33406
|
const projectRoot = process.cwd();
|
|
33232
|
-
const hasSidecarConfig =
|
|
33407
|
+
const hasSidecarConfig = existsSync12(join13(projectRoot, ".codex-sidecar.yml"));
|
|
33233
33408
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33234
33409
|
const advisory = runCodexSidecarAdvisory({
|
|
33235
33410
|
searchText: job.failureText,
|
|
@@ -33265,7 +33440,7 @@ function buildStopReminder(signals, related) {
|
|
|
33265
33440
|
const mode = hookCodexSidecarMode();
|
|
33266
33441
|
if (mode === "off") return base;
|
|
33267
33442
|
const projectRoot = process.cwd();
|
|
33268
|
-
const hasSidecarConfig =
|
|
33443
|
+
const hasSidecarConfig = existsSync12(join13(projectRoot, ".codex-sidecar.yml"));
|
|
33269
33444
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33270
33445
|
const advisory = runCodexSidecarAdvisory({
|
|
33271
33446
|
searchText: struggleSearchText(signals),
|
|
@@ -33405,9 +33580,9 @@ async function runHook(name, arg) {
|
|
|
33405
33580
|
|
|
33406
33581
|
// src/commands/codexHookCmd.ts
|
|
33407
33582
|
import { spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
|
|
33408
|
-
import { existsSync as
|
|
33583
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
33409
33584
|
import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
|
|
33410
|
-
import { join as
|
|
33585
|
+
import { join as join14 } from "node:path";
|
|
33411
33586
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
33412
33587
|
var CODEX_HOST = {
|
|
33413
33588
|
agent: "codex",
|
|
@@ -33437,10 +33612,10 @@ function processExitCodeFromText(text) {
|
|
|
33437
33612
|
return m ? Number(m[1]) : null;
|
|
33438
33613
|
}
|
|
33439
33614
|
function transcriptToolOutput(transcriptPath, toolUseId) {
|
|
33440
|
-
if (!transcriptPath || !toolUseId || !
|
|
33615
|
+
if (!transcriptPath || !toolUseId || !existsSync13(transcriptPath)) return null;
|
|
33441
33616
|
let raw = "";
|
|
33442
33617
|
try {
|
|
33443
|
-
raw =
|
|
33618
|
+
raw = readFileSync8(transcriptPath, "utf-8");
|
|
33444
33619
|
} catch {
|
|
33445
33620
|
return null;
|
|
33446
33621
|
}
|
|
@@ -33584,7 +33759,7 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
|
33584
33759
|
async function runCodexWorker(workFile) {
|
|
33585
33760
|
let raw;
|
|
33586
33761
|
try {
|
|
33587
|
-
raw =
|
|
33762
|
+
raw = readFileSync8(workFile, "utf-8");
|
|
33588
33763
|
} catch {
|
|
33589
33764
|
process.exit(0);
|
|
33590
33765
|
}
|
|
@@ -33601,7 +33776,7 @@ async function runCodexWorker(workFile) {
|
|
|
33601
33776
|
await processCodexWorkerJob(job);
|
|
33602
33777
|
process.exit(0);
|
|
33603
33778
|
}
|
|
33604
|
-
function runDiagnostics(codexHome = process.env.CODEX_HOME ??
|
|
33779
|
+
function runDiagnostics(codexHome = process.env.CODEX_HOME ?? join14(homedir3(), ".codex")) {
|
|
33605
33780
|
const features = spawnSync5("codex", ["features", "list"], {
|
|
33606
33781
|
encoding: "utf-8",
|
|
33607
33782
|
maxBuffer: 1024 * 1024,
|
|
@@ -33706,10 +33881,151 @@ async function runCodexHook(name, arg) {
|
|
|
33706
33881
|
process.exit(0);
|
|
33707
33882
|
}
|
|
33708
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
|
+
|
|
33709
34025
|
// src/commands/pull.ts
|
|
33710
|
-
import { existsSync as
|
|
34026
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
33711
34027
|
async function runPull(ctx) {
|
|
33712
|
-
const hasCommunityDir =
|
|
34028
|
+
const hasCommunityDir = existsSync14(ctx.paths.communityDir);
|
|
33713
34029
|
if (!hasCommunityDir) {
|
|
33714
34030
|
ctx.logger.info(
|
|
33715
34031
|
"no community repos yet \u2014 add one with `caveat community add <github-url>`."
|
|
@@ -33809,9 +34125,9 @@ async function runSync(ctx, opts, dependencies = {}) {
|
|
|
33809
34125
|
|
|
33810
34126
|
// src/commands/codexSidecar.ts
|
|
33811
34127
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
33812
|
-
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";
|
|
33813
34129
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
33814
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
34130
|
+
import { basename as basename2, dirname as dirname6, join as join16 } from "node:path";
|
|
33815
34131
|
import { cwd, exit } from "node:process";
|
|
33816
34132
|
function runCodexSidecarDiagnostics(logger, opts) {
|
|
33817
34133
|
const plan = buildCodexSidecarDiagnosticsCommand({
|
|
@@ -33843,8 +34159,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
|
|
|
33843
34159
|
process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
|
|
33844
34160
|
exit(0);
|
|
33845
34161
|
}
|
|
33846
|
-
const contextDir = mkdtempSync3(
|
|
33847
|
-
const contextFile =
|
|
34162
|
+
const contextDir = mkdtempSync3(join16(tmpdir4(), "caveat-sidecar-context-"));
|
|
34163
|
+
const contextFile = join16(contextDir, "context.json");
|
|
33848
34164
|
let status2 = 1;
|
|
33849
34165
|
try {
|
|
33850
34166
|
const blocks = collectCaveatContextBlocks(ctx, {
|
|
@@ -33877,7 +34193,7 @@ function readHookSignalAdditionalContextFile(path, testProbe) {
|
|
|
33877
34193
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
33878
34194
|
assertPrivateRegular(before, uid, platform);
|
|
33879
34195
|
testProbe?.afterLstat?.();
|
|
33880
|
-
const fd = openSync(path,
|
|
34196
|
+
const fd = openSync(path, constants4.O_RDONLY | constants4.O_NONBLOCK | (constants4.O_NOFOLLOW ?? 0));
|
|
33881
34197
|
let raw;
|
|
33882
34198
|
try {
|
|
33883
34199
|
const opened = fstatSync(fd);
|
|
@@ -34007,7 +34323,7 @@ function executePlan(logger, command, args, options = {}) {
|
|
|
34007
34323
|
}
|
|
34008
34324
|
function saveStructuredResult(path, stdout) {
|
|
34009
34325
|
const parsed = JSON.parse(stdout);
|
|
34010
|
-
|
|
34326
|
+
mkdirSync7(dirname6(path), { recursive: true });
|
|
34011
34327
|
writeFileSync7(path, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
34012
34328
|
}
|
|
34013
34329
|
function shellDisplayQuote(value) {
|
|
@@ -34096,8 +34412,8 @@ function runCommunityRemove(ctx, handle, opts) {
|
|
|
34096
34412
|
|
|
34097
34413
|
// src/commands/factoryDiagnostics.ts
|
|
34098
34414
|
import { execFileSync } from "node:child_process";
|
|
34099
|
-
import { existsSync as
|
|
34100
|
-
import { join as
|
|
34415
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
|
|
34416
|
+
import { join as join17 } from "node:path";
|
|
34101
34417
|
import { DatabaseSync } from "node:sqlite";
|
|
34102
34418
|
import { parse as parseToml2 } from "smol-toml";
|
|
34103
34419
|
var status = (ok, reason) => ({ status: ok ? "ready" : "not_ready", reason_code: ok ? "ready" : reason });
|
|
@@ -34109,10 +34425,10 @@ function isRecord2(value) {
|
|
|
34109
34425
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34110
34426
|
}
|
|
34111
34427
|
function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
34112
|
-
const path =
|
|
34113
|
-
if (!
|
|
34428
|
+
const path = join17(home, ".claude.json");
|
|
34429
|
+
if (!existsSync15(path)) return status(false, "not_registered");
|
|
34114
34430
|
try {
|
|
34115
|
-
const value = JSON.parse(
|
|
34431
|
+
const value = JSON.parse(readFileSync9(path, "utf8"));
|
|
34116
34432
|
if (!isRecord2(value) || !isRecord2(value.mcpServers)) return status(false, "not_registered");
|
|
34117
34433
|
return status(isCaveatClaudeMcpRegistration(value.mcpServers.caveat, nodePath, cliScriptPath), "not_registered");
|
|
34118
34434
|
} catch {
|
|
@@ -34121,7 +34437,7 @@ function claudeRegistration(home, nodePath, cliScriptPath) {
|
|
|
34121
34437
|
}
|
|
34122
34438
|
function claudeHooks(home, nodePath, cliScriptPath) {
|
|
34123
34439
|
try {
|
|
34124
|
-
const settings = JSON.parse(
|
|
34440
|
+
const settings = JSON.parse(readFileSync9(join17(home, ".claude", "settings.json"), "utf8"));
|
|
34125
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;
|
|
34126
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")) };
|
|
34127
34443
|
} catch {
|
|
@@ -34143,7 +34459,7 @@ function strictSearchSchema(db) {
|
|
|
34143
34459
|
return columns.map((column) => `${column.name}:${column.hidden}`).join(",") === "id:0,title:0,body:0,tags:0,entries_fts:1,rank:1";
|
|
34144
34460
|
}
|
|
34145
34461
|
function database(path) {
|
|
34146
|
-
if (!
|
|
34462
|
+
if (!existsSync15(path)) return { status: "not_ready", reason_code: "missing", schema_version: null, supported_schema_version: 3, migration_status: "unverified" };
|
|
34147
34463
|
try {
|
|
34148
34464
|
const db = new DatabaseSync(path, { readOnly: true });
|
|
34149
34465
|
try {
|
|
@@ -34168,10 +34484,10 @@ function database(path) {
|
|
|
34168
34484
|
}
|
|
34169
34485
|
}
|
|
34170
34486
|
function codexFeature(codexHome) {
|
|
34171
|
-
const path =
|
|
34172
|
-
if (!
|
|
34487
|
+
const path = join17(codexHome, "config.toml");
|
|
34488
|
+
if (!existsSync15(path)) return status(false, "feature_disabled");
|
|
34173
34489
|
try {
|
|
34174
|
-
const config2 = parseToml2(
|
|
34490
|
+
const config2 = parseToml2(readFileSync9(path, "utf8"));
|
|
34175
34491
|
if (!isRecord2(config2.features)) return status(false, "feature_disabled");
|
|
34176
34492
|
const features = config2.features;
|
|
34177
34493
|
return status(features.hooks === true && features.codex_hooks === void 0, "feature_disabled");
|
|
@@ -34180,7 +34496,7 @@ function codexFeature(codexHome) {
|
|
|
34180
34496
|
}
|
|
34181
34497
|
}
|
|
34182
34498
|
function codexHooks(codexHome, nodePath, cliScriptPath) {
|
|
34183
|
-
const value = JSON.parse(
|
|
34499
|
+
const value = JSON.parse(readFileSync9(join17(codexHome, "hooks.json"), "utf8"));
|
|
34184
34500
|
if (!isRecord2(value) || !isRecord2(value.hooks)) throw Error("config_unreadable");
|
|
34185
34501
|
const hooks = value.hooks;
|
|
34186
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)));
|
|
@@ -34215,7 +34531,7 @@ function sync(own) {
|
|
|
34215
34531
|
return unverified("upstream_unavailable");
|
|
34216
34532
|
}
|
|
34217
34533
|
}
|
|
34218
|
-
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ??
|
|
34534
|
+
function factoryDiagnostics(ctx, codexHome = process.env.CODEX_HOME ?? join17(ctx.userHome, ".codex")) {
|
|
34219
34535
|
const nodePath = process.execPath;
|
|
34220
34536
|
const cliScriptPath = process.argv[1] ?? "";
|
|
34221
34537
|
const db = database(ctx.paths.dbPath);
|
|
@@ -34290,7 +34606,7 @@ for (const action of ["resolve", "reopen"]) runtimeErrors.command(`${action} <fi
|
|
|
34290
34606
|
});
|
|
34291
34607
|
program.command("init").description(
|
|
34292
34608
|
"Initialize ~/.caveatrc.json, ~/.caveat/, and register Claude Code integration. Add knowledge sources later with `caveat community add <github-url>`."
|
|
34293
|
-
).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(
|
|
34294
34610
|
"--pending-stale-days <days>",
|
|
34295
34611
|
"sweep `<caveatHome>/pending/<sessionId>/` whose newest entry is older than this (default 7)",
|
|
34296
34612
|
(raw) => {
|
|
@@ -34310,7 +34626,8 @@ program.command("init").description(
|
|
|
34310
34626
|
sync: opts.sync,
|
|
34311
34627
|
publishTarget: opts.publishTarget,
|
|
34312
34628
|
yes: opts.yes,
|
|
34313
|
-
skipCodexHook: opts.skipCodexHook
|
|
34629
|
+
skipCodexHook: opts.skipCodexHook,
|
|
34630
|
+
skipCursorHook: opts.skipCursorHook
|
|
34314
34631
|
});
|
|
34315
34632
|
}
|
|
34316
34633
|
);
|
|
@@ -34438,6 +34755,57 @@ codexHook.command("stop").description("Run the Codex Stop hook").action(async ()
|
|
|
34438
34755
|
codexHook.command("worker <workFile>").description("Run the detached Codex hook worker").action(async (workFile) => {
|
|
34439
34756
|
await runCodexHook("worker", workFile);
|
|
34440
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
|
+
});
|
|
34441
34809
|
var codexSidecar = program.command("codex-sidecar").description("Check Codex sidecar availability for the current repository");
|
|
34442
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) => {
|
|
34443
34811
|
runCodexSidecarDiagnostics(stdoutLogger, opts);
|