caveat-cli 0.14.9 → 0.15.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 +15 -0
- package/dist/{chunk-ECC5LJZF.js → chunk-Z2XLYCR3.js} +641 -82
- package/dist/chunk-Z2XLYCR3.js.map +1 -0
- package/dist/index.js +318 -80
- package/dist/index.js.map +1 -1
- package/dist/{server-YQ4DJ2H7.js → server-DCE3ODHI.js} +2 -2
- package/package.json +12 -12
- package/dist/chunk-ECC5LJZF.js.map +0 -1
- /package/dist/{server-YQ4DJ2H7.js.map → server-DCE3ODHI.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
import { createRequire as __caveat_createRequire } from 'node:module';
|
|
3
3
|
const require = __caveat_createRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
|
+
KNOWLEDGE_GITIGNORE,
|
|
5
6
|
__commonJS,
|
|
6
7
|
__export,
|
|
7
8
|
__toESM,
|
|
9
|
+
acquireReindexLock,
|
|
8
10
|
appendPendingReminder,
|
|
9
11
|
buildCodexSidecarDiagnosticsCommand,
|
|
10
12
|
buildCodexSidecarReadOnlySmokeCommand,
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
communityList,
|
|
16
18
|
communityPull,
|
|
17
19
|
communityRemove,
|
|
20
|
+
computeEntriesDigest,
|
|
18
21
|
decideCodexSidecarExecution,
|
|
19
22
|
defaultSelfIdentityTokens,
|
|
20
23
|
drainPendingReminders,
|
|
@@ -23,26 +26,34 @@ import {
|
|
|
23
26
|
findCaveatsForPrompt,
|
|
24
27
|
get,
|
|
25
28
|
hasAnyStruggleSignal,
|
|
29
|
+
initOwnSync,
|
|
26
30
|
listRecent,
|
|
27
31
|
listStale,
|
|
28
32
|
loadConfig,
|
|
29
33
|
markHit,
|
|
30
34
|
maybeSweepPendingDirs,
|
|
31
35
|
openDb,
|
|
36
|
+
publishOwn,
|
|
32
37
|
readCodexSessionSignals,
|
|
38
|
+
readDigestMarker,
|
|
33
39
|
readSessionSignals,
|
|
34
40
|
rebuildAll,
|
|
35
41
|
recordEntry,
|
|
42
|
+
reindexAllSources,
|
|
43
|
+
releaseReindexLock,
|
|
36
44
|
resolvePaths,
|
|
37
45
|
scanSource,
|
|
38
46
|
search,
|
|
39
47
|
stderrLogger,
|
|
40
48
|
stopReminderText,
|
|
41
49
|
struggleSearchText,
|
|
50
|
+
syncOwn,
|
|
42
51
|
toolErrorReminderText,
|
|
43
52
|
updateEntry,
|
|
44
|
-
userPromptSubmitReminderText
|
|
45
|
-
|
|
53
|
+
userPromptSubmitReminderText,
|
|
54
|
+
writeDigestMarker,
|
|
55
|
+
writeUserConfigPatch
|
|
56
|
+
} from "./chunk-Z2XLYCR3.js";
|
|
46
57
|
|
|
47
58
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
48
59
|
var require_code = __commonJS({
|
|
@@ -7085,15 +7096,6 @@ function resolveHookNodePath({
|
|
|
7085
7096
|
}
|
|
7086
7097
|
|
|
7087
7098
|
// src/commands/init.ts
|
|
7088
|
-
var KNOWLEDGE_GITIGNORE = [
|
|
7089
|
-
"# Never commit entries flagged private (visibility: private is enforced by the",
|
|
7090
|
-
"# pre-commit gate, but this is a filename-level backup guard).",
|
|
7091
|
-
"*.private.md",
|
|
7092
|
-
"",
|
|
7093
|
-
"# Obsidian per-user config: workspace layout, theme, plugin state, cache.",
|
|
7094
|
-
".obsidian/",
|
|
7095
|
-
""
|
|
7096
|
-
].join("\n");
|
|
7097
7099
|
async function runInit(ctx, opts = { skipClaude: false, dryRun: false }) {
|
|
7098
7100
|
ensureUserConfig(ctx.userConfigPath);
|
|
7099
7101
|
ctx.logger.info(`user config: ${ctx.userConfigPath}`);
|
|
@@ -7114,7 +7116,12 @@ async function runInit(ctx, opts = { skipClaude: false, dryRun: false }) {
|
|
|
7114
7116
|
const dbDir = dirname3(ctx.paths.dbPath);
|
|
7115
7117
|
if (!existsSync3(dbDir)) mkdirSync2(dbDir, { recursive: true });
|
|
7116
7118
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
7117
|
-
|
|
7119
|
+
try {
|
|
7120
|
+
reindexAllSources({ db, paths: ctx.paths, logger: ctx.logger });
|
|
7121
|
+
writeDigestMarker(ctx.caveatHome, computeEntriesDigest(ctx.paths));
|
|
7122
|
+
} finally {
|
|
7123
|
+
db.close();
|
|
7124
|
+
}
|
|
7118
7125
|
ctx.logger.info(`db initialized: ${ctx.paths.dbPath}`);
|
|
7119
7126
|
} else {
|
|
7120
7127
|
ctx.logger.info(`[dry-run] db path: ${ctx.paths.dbPath}`);
|
|
@@ -7227,8 +7234,8 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
7227
7234
|
}
|
|
7228
7235
|
|
|
7229
7236
|
// src/commands/indexCmd.ts
|
|
7230
|
-
import { existsSync as existsSync4,
|
|
7231
|
-
import { dirname as dirname4
|
|
7237
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "node:fs";
|
|
7238
|
+
import { dirname as dirname4 } from "node:path";
|
|
7232
7239
|
function runIndex(ctx, opts) {
|
|
7233
7240
|
const dbDir = dirname4(ctx.paths.dbPath);
|
|
7234
7241
|
if (!existsSync4(dbDir)) mkdirSync3(dbDir, { recursive: true });
|
|
@@ -7238,22 +7245,15 @@ function runIndex(ctx, opts) {
|
|
|
7238
7245
|
ctx.logger.info("full rebuild: DELETE FROM entries");
|
|
7239
7246
|
rebuildAll(db);
|
|
7240
7247
|
}
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
if (existsSync4(ctx.paths.communityDir)) {
|
|
7248
|
-
for (const entry of readdirSync2(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
7249
|
-
if (!entry.isDirectory()) continue;
|
|
7250
|
-
const source = `community/${entry.name}`;
|
|
7251
|
-
const root = join6(ctx.paths.communityDir, entry.name, "entries");
|
|
7252
|
-
if (!existsSync4(root)) continue;
|
|
7253
|
-
const result = scanSource({ db, source, entriesRoot: root });
|
|
7254
|
-
ctx.logger.info(`${source}: +${result.added} ~${result.updated} -${result.deleted}`);
|
|
7248
|
+
const result = reindexAllSources({ db, paths: ctx.paths, logger: ctx.logger });
|
|
7249
|
+
for (const [source, scan] of Object.entries(result.perSource)) {
|
|
7250
|
+
if (source === "own") {
|
|
7251
|
+
ctx.logger.info(`own: +${scan.added} ~${scan.updated} -${scan.deleted}`);
|
|
7252
|
+
} else {
|
|
7253
|
+
ctx.logger.info(`${source}: +${scan.added} ~${scan.updated} -${scan.deleted}`);
|
|
7255
7254
|
}
|
|
7256
7255
|
}
|
|
7256
|
+
writeDigestMarker(ctx.caveatHome, computeEntriesDigest(ctx.paths));
|
|
7257
7257
|
} finally {
|
|
7258
7258
|
db.close();
|
|
7259
7259
|
}
|
|
@@ -7405,7 +7405,7 @@ function runStats(ctx) {
|
|
|
7405
7405
|
|
|
7406
7406
|
// src/commands/serve.ts
|
|
7407
7407
|
async function runServe(opts) {
|
|
7408
|
-
const { startServer } = await import("./server-
|
|
7408
|
+
const { startServer } = await import("./server-DCE3ODHI.js");
|
|
7409
7409
|
const { port, host } = startServer({ port: opts.port });
|
|
7410
7410
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
7411
7411
|
`);
|
|
@@ -31477,11 +31477,11 @@ var StdioServerTransport = class {
|
|
|
31477
31477
|
|
|
31478
31478
|
// ../mcp/dist/context.js
|
|
31479
31479
|
import { homedir as homedir2 } from "node:os";
|
|
31480
|
-
import { join as
|
|
31480
|
+
import { join as join6 } from "node:path";
|
|
31481
31481
|
function buildMcpContext(overrides = {}) {
|
|
31482
31482
|
const userHome = overrides.userHome ?? homedir2();
|
|
31483
31483
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
31484
|
-
const userConfigPath =
|
|
31484
|
+
const userConfigPath = join6(userHome, ".caveatrc.json");
|
|
31485
31485
|
const logger = overrides.logger ?? stderrLogger;
|
|
31486
31486
|
const config2 = loadConfig(userConfigPath);
|
|
31487
31487
|
const paths = resolvePaths(caveatHome, config2.knowledgeRepo, userHome);
|
|
@@ -31616,8 +31616,8 @@ function handleListRecent(ctx, args) {
|
|
|
31616
31616
|
}
|
|
31617
31617
|
|
|
31618
31618
|
// ../mcp/dist/tools/pull.js
|
|
31619
|
-
import { existsSync as existsSync5, readdirSync as
|
|
31620
|
-
import { join as
|
|
31619
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2 } from "node:fs";
|
|
31620
|
+
import { join as join7 } from "node:path";
|
|
31621
31621
|
var pullInputShape = {};
|
|
31622
31622
|
async function handlePull(ctx, _args = {}) {
|
|
31623
31623
|
const pulled = [];
|
|
@@ -31637,10 +31637,10 @@ async function handlePull(ctx, _args = {}) {
|
|
|
31637
31637
|
indexed.push({ source: "own", ...own });
|
|
31638
31638
|
}
|
|
31639
31639
|
if (existsSync5(ctx.paths.communityDir)) {
|
|
31640
|
-
for (const entry of
|
|
31640
|
+
for (const entry of readdirSync2(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
31641
31641
|
if (!entry.isDirectory()) continue;
|
|
31642
31642
|
const source = `community/${entry.name}`;
|
|
31643
|
-
const root =
|
|
31643
|
+
const root = join7(ctx.paths.communityDir, entry.name, "entries");
|
|
31644
31644
|
if (!existsSync5(root)) continue;
|
|
31645
31645
|
const scan = scanSource({ db: ctx.db, source, entriesRoot: root });
|
|
31646
31646
|
indexed.push({ source, ...scan });
|
|
@@ -31754,9 +31754,9 @@ async function runMcpServer() {
|
|
|
31754
31754
|
}
|
|
31755
31755
|
|
|
31756
31756
|
// src/commands/hookCmd.ts
|
|
31757
|
-
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
31757
|
+
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
31758
31758
|
import {
|
|
31759
|
-
existsSync as
|
|
31759
|
+
existsSync as existsSync7,
|
|
31760
31760
|
mkdirSync as mkdirSync4,
|
|
31761
31761
|
mkdtempSync,
|
|
31762
31762
|
readFileSync as readFileSync3,
|
|
@@ -31767,6 +31767,31 @@ import {
|
|
|
31767
31767
|
import { tmpdir } from "node:os";
|
|
31768
31768
|
import { join as join9 } from "node:path";
|
|
31769
31769
|
import { createHash, randomBytes } from "node:crypto";
|
|
31770
|
+
|
|
31771
|
+
// src/autoReindexTrigger.ts
|
|
31772
|
+
import { spawn } from "node:child_process";
|
|
31773
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
31774
|
+
import { join as join8 } from "node:path";
|
|
31775
|
+
function maybeTriggerAutoReindex(ctx) {
|
|
31776
|
+
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") return;
|
|
31777
|
+
if (!existsSync6(ctx.paths.dbPath)) return;
|
|
31778
|
+
if (existsSync6(join8(ctx.caveatHome, "index", ".reindex-lock"))) return;
|
|
31779
|
+
const current = computeEntriesDigest(ctx.paths);
|
|
31780
|
+
const marker = readDigestMarker(ctx.caveatHome);
|
|
31781
|
+
if (marker?.digest === current.digest && marker.fileCount === current.fileCount) return;
|
|
31782
|
+
const cliScript = process.argv[1];
|
|
31783
|
+
if (!cliScript) throw new Error("current Caveat CLI script path is unavailable");
|
|
31784
|
+
const child = spawn(
|
|
31785
|
+
process.execPath,
|
|
31786
|
+
// execArgv を継承して親と同じランタイム(例: テストハーネスの --import tsx)で
|
|
31787
|
+
// worker を起動する。素の node だと TS ソース実行のテスト環境で worker が即死する。
|
|
31788
|
+
[...process.execArgv, "--disable-warning=ExperimentalWarning", cliScript, "hook", "reindex"],
|
|
31789
|
+
{ detached: true, stdio: "ignore", windowsHide: true }
|
|
31790
|
+
);
|
|
31791
|
+
child.unref();
|
|
31792
|
+
}
|
|
31793
|
+
|
|
31794
|
+
// src/commands/hookCmd.ts
|
|
31770
31795
|
var silentLogger = {
|
|
31771
31796
|
info: () => {
|
|
31772
31797
|
},
|
|
@@ -31815,7 +31840,7 @@ function searchCaveatsFromTextSafely(text) {
|
|
|
31815
31840
|
let db;
|
|
31816
31841
|
try {
|
|
31817
31842
|
const ctx = buildContextSafely();
|
|
31818
|
-
if (!ctx || !
|
|
31843
|
+
if (!ctx || !existsSync7(ctx.paths.dbPath)) return [];
|
|
31819
31844
|
db = openDb({ path: ctx.paths.dbPath });
|
|
31820
31845
|
const hits = findCaveatsForPrompt(db, text, {
|
|
31821
31846
|
selfIdentity: defaultSelfIdentityTokens()
|
|
@@ -31977,7 +32002,7 @@ function spawnWorker(job) {
|
|
|
31977
32002
|
const cliScript = process.argv[1];
|
|
31978
32003
|
if (!cliScript) return;
|
|
31979
32004
|
try {
|
|
31980
|
-
const child =
|
|
32005
|
+
const child = spawn2(
|
|
31981
32006
|
process.execPath,
|
|
31982
32007
|
["--disable-warning=ExperimentalWarning", cliScript, "hook", "worker", workFile],
|
|
31983
32008
|
{ detached: true, stdio: "ignore", windowsHide: true }
|
|
@@ -32021,12 +32046,65 @@ async function runWorker(workFile) {
|
|
|
32021
32046
|
}
|
|
32022
32047
|
process.exit(0);
|
|
32023
32048
|
}
|
|
32049
|
+
function writeLastReindex(caveatHome, value) {
|
|
32050
|
+
try {
|
|
32051
|
+
writeFileSync3(join9(caveatHome, "index", ".last-reindex.json"), JSON.stringify(value), "utf-8");
|
|
32052
|
+
} catch (err) {
|
|
32053
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32054
|
+
process.stderr.write(`[caveat:hook] reindex status write error: ${msg}
|
|
32055
|
+
`);
|
|
32056
|
+
}
|
|
32057
|
+
}
|
|
32058
|
+
function runReindexWorker() {
|
|
32059
|
+
if (process.env.CAVEAT_INDEX_AUTOSYNC === "off") {
|
|
32060
|
+
process.stderr.write("[caveat:hook] auto reindex disabled by CAVEAT_INDEX_AUTOSYNC=off\n");
|
|
32061
|
+
return;
|
|
32062
|
+
}
|
|
32063
|
+
const ctx = buildContextSafely();
|
|
32064
|
+
if (!ctx || !existsSync7(ctx.paths.dbPath)) {
|
|
32065
|
+
process.stderr.write("[caveat:hook] auto reindex skipped: index database does not exist\n");
|
|
32066
|
+
return;
|
|
32067
|
+
}
|
|
32068
|
+
const lock = acquireReindexLock(ctx.caveatHome);
|
|
32069
|
+
if (!lock) return;
|
|
32070
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
32071
|
+
let db;
|
|
32072
|
+
try {
|
|
32073
|
+
const digest = computeEntriesDigest(ctx.paths);
|
|
32074
|
+
db = openDb({ path: ctx.paths.dbPath, logger: silentLogger });
|
|
32075
|
+
const result = reindexAllSources({ db, paths: ctx.paths, logger: silentLogger });
|
|
32076
|
+
writeDigestMarker(ctx.caveatHome, digest);
|
|
32077
|
+
writeLastReindex(ctx.caveatHome, {
|
|
32078
|
+
startedAt,
|
|
32079
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32080
|
+
perSource: result.perSource
|
|
32081
|
+
});
|
|
32082
|
+
} catch (err) {
|
|
32083
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32084
|
+
process.stderr.write(`[caveat:hook] reindex error: ${msg}
|
|
32085
|
+
`);
|
|
32086
|
+
writeLastReindex(ctx.caveatHome, {
|
|
32087
|
+
startedAt,
|
|
32088
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32089
|
+
error: msg
|
|
32090
|
+
});
|
|
32091
|
+
} finally {
|
|
32092
|
+
db?.close();
|
|
32093
|
+
try {
|
|
32094
|
+
releaseReindexLock(lock);
|
|
32095
|
+
} catch (err) {
|
|
32096
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32097
|
+
process.stderr.write(`[caveat:hook] reindex lock release error: ${msg}
|
|
32098
|
+
`);
|
|
32099
|
+
}
|
|
32100
|
+
}
|
|
32101
|
+
}
|
|
32024
32102
|
function buildToolErrorReminder(job, hits) {
|
|
32025
32103
|
const base = toolErrorReminderText(hits);
|
|
32026
32104
|
const mode = hookCodexSidecarMode();
|
|
32027
32105
|
if (mode === "off") return base;
|
|
32028
32106
|
const projectRoot = process.cwd();
|
|
32029
|
-
const hasSidecarConfig =
|
|
32107
|
+
const hasSidecarConfig = existsSync7(join9(projectRoot, ".codex-sidecar.yml"));
|
|
32030
32108
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
32031
32109
|
const advisory = runCodexSidecarAdvisory({
|
|
32032
32110
|
searchText: job.searchText,
|
|
@@ -32063,7 +32141,7 @@ function buildStopReminder(signals, related) {
|
|
|
32063
32141
|
const mode = hookCodexSidecarMode();
|
|
32064
32142
|
if (mode === "off") return base;
|
|
32065
32143
|
const projectRoot = process.cwd();
|
|
32066
|
-
const hasSidecarConfig =
|
|
32144
|
+
const hasSidecarConfig = existsSync7(join9(projectRoot, ".codex-sidecar.yml"));
|
|
32067
32145
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
32068
32146
|
const advisory = runCodexSidecarAdvisory({
|
|
32069
32147
|
searchText: struggleSearchText(signals),
|
|
@@ -32178,6 +32256,10 @@ function runCodexSidecarAdvisory(input) {
|
|
|
32178
32256
|
}
|
|
32179
32257
|
}
|
|
32180
32258
|
async function runHook(name, arg) {
|
|
32259
|
+
if (name === "reindex") {
|
|
32260
|
+
runReindexWorker();
|
|
32261
|
+
process.exit(0);
|
|
32262
|
+
}
|
|
32181
32263
|
if (name === "worker") {
|
|
32182
32264
|
if (!arg) process.exit(0);
|
|
32183
32265
|
await runWorker(arg);
|
|
@@ -32224,10 +32306,22 @@ async function runHook(name, arg) {
|
|
|
32224
32306
|
process.exit(0);
|
|
32225
32307
|
}
|
|
32226
32308
|
if (name === "stop") {
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
|
|
32309
|
+
const ctx = buildContextSafely();
|
|
32310
|
+
if (ctx) {
|
|
32311
|
+
try {
|
|
32312
|
+
maybeSweepPendingDirs(ctx.caveatHome);
|
|
32313
|
+
} catch (err) {
|
|
32314
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32315
|
+
process.stderr.write(`[caveat:hook] pending sweep error: ${msg}
|
|
32316
|
+
`);
|
|
32317
|
+
}
|
|
32318
|
+
try {
|
|
32319
|
+
maybeTriggerAutoReindex(ctx);
|
|
32320
|
+
} catch (err) {
|
|
32321
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32322
|
+
process.stderr.write(`[caveat:hook] auto reindex trigger error: ${msg}
|
|
32323
|
+
`);
|
|
32324
|
+
}
|
|
32231
32325
|
}
|
|
32232
32326
|
if (payload.stop_hook_active === true) process.exit(0);
|
|
32233
32327
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
@@ -32243,14 +32337,14 @@ async function runHook(name, arg) {
|
|
|
32243
32337
|
}
|
|
32244
32338
|
|
|
32245
32339
|
// src/commands/codexHookCmd.ts
|
|
32246
|
-
import { spawn as
|
|
32247
|
-
import { existsSync as
|
|
32340
|
+
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
32341
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
32248
32342
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
|
|
32249
32343
|
import { join as join11 } from "node:path";
|
|
32250
32344
|
import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
|
|
32251
32345
|
|
|
32252
32346
|
// src/codexHookInstall.ts
|
|
32253
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
32347
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
32254
32348
|
import { dirname as dirname5, join as join10 } from "node:path";
|
|
32255
32349
|
function quote2(p) {
|
|
32256
32350
|
return p.includes(" ") ? `"${p}"` : p;
|
|
@@ -32274,14 +32368,14 @@ function hasCaveatHook(hooksJson, event, fragment) {
|
|
|
32274
32368
|
) ?? false;
|
|
32275
32369
|
}
|
|
32276
32370
|
function readHooks(path) {
|
|
32277
|
-
if (!
|
|
32371
|
+
if (!existsSync8(path)) return {};
|
|
32278
32372
|
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
32279
32373
|
}
|
|
32280
32374
|
function writeJsonWithBackup(path, value) {
|
|
32281
32375
|
const dir = dirname5(path);
|
|
32282
|
-
if (!
|
|
32376
|
+
if (!existsSync8(dir)) mkdirSync5(dir, { recursive: true });
|
|
32283
32377
|
let backupPath = "";
|
|
32284
|
-
if (
|
|
32378
|
+
if (existsSync8(path)) {
|
|
32285
32379
|
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
32286
32380
|
copyFileSync2(path, backupPath);
|
|
32287
32381
|
}
|
|
@@ -32358,9 +32452,9 @@ codex_hooks = true
|
|
|
32358
32452
|
}
|
|
32359
32453
|
function writeConfigWithBackup(path, text) {
|
|
32360
32454
|
const dir = dirname5(path);
|
|
32361
|
-
if (!
|
|
32455
|
+
if (!existsSync8(dir)) mkdirSync5(dir, { recursive: true });
|
|
32362
32456
|
let backupPath = "";
|
|
32363
|
-
if (
|
|
32457
|
+
if (existsSync8(path)) {
|
|
32364
32458
|
backupPath = `${path}.caveat-backup-${Date.now()}`;
|
|
32365
32459
|
copyFileSync2(path, backupPath);
|
|
32366
32460
|
}
|
|
@@ -32389,7 +32483,7 @@ function installCodexHooks(opts) {
|
|
|
32389
32483
|
hookCommand2(opts.nodePath, opts.cliScriptPath, "stop"),
|
|
32390
32484
|
"stop"
|
|
32391
32485
|
);
|
|
32392
|
-
const rawConfig =
|
|
32486
|
+
const rawConfig = existsSync8(configPath) ? readFileSync4(configPath, "utf-8") : "";
|
|
32393
32487
|
const enabled = enableCodexHooksFeature(rawConfig);
|
|
32394
32488
|
const anyHookAdded = userPromptSubmit === "added" || postToolUse === "added" || stop === "added";
|
|
32395
32489
|
let backupPath;
|
|
@@ -32517,7 +32611,7 @@ function searchCaveatsFromTextSafely2(text) {
|
|
|
32517
32611
|
let db;
|
|
32518
32612
|
try {
|
|
32519
32613
|
const ctx = buildContextSafely2();
|
|
32520
|
-
if (!ctx || !
|
|
32614
|
+
if (!ctx || !existsSync9(ctx.paths.dbPath)) return [];
|
|
32521
32615
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32522
32616
|
const hits = findCaveatsForPrompt(db, text, {
|
|
32523
32617
|
selfIdentity: defaultSelfIdentityTokens()
|
|
@@ -32586,7 +32680,7 @@ function processExitCodeFromText(text) {
|
|
|
32586
32680
|
return m ? Number(m[1]) : null;
|
|
32587
32681
|
}
|
|
32588
32682
|
function transcriptToolOutput(transcriptPath, toolUseId) {
|
|
32589
|
-
if (!transcriptPath || !toolUseId || !
|
|
32683
|
+
if (!transcriptPath || !toolUseId || !existsSync9(transcriptPath)) return null;
|
|
32590
32684
|
let raw = "";
|
|
32591
32685
|
try {
|
|
32592
32686
|
raw = readFileSync5(transcriptPath, "utf-8");
|
|
@@ -32873,6 +32967,14 @@ async function runCodexHook(name, arg) {
|
|
|
32873
32967
|
process.exit(0);
|
|
32874
32968
|
}
|
|
32875
32969
|
if (name === "stop") {
|
|
32970
|
+
try {
|
|
32971
|
+
const ctx = buildContextSafely2();
|
|
32972
|
+
if (ctx) maybeTriggerAutoReindex(ctx);
|
|
32973
|
+
} catch (err) {
|
|
32974
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32975
|
+
process.stderr.write(`[caveat:codex-hook] auto reindex trigger error: ${msg}
|
|
32976
|
+
`);
|
|
32977
|
+
}
|
|
32876
32978
|
if (payload.stop_hook_active === true) process.exit(0);
|
|
32877
32979
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
32878
32980
|
const signals = transcriptPath ? loadSignalsSafely2(transcriptPath) : null;
|
|
@@ -32887,19 +32989,15 @@ async function runCodexHook(name, arg) {
|
|
|
32887
32989
|
}
|
|
32888
32990
|
|
|
32889
32991
|
// src/commands/pull.ts
|
|
32890
|
-
import { existsSync as
|
|
32891
|
-
import { join as join12 } from "node:path";
|
|
32992
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
32892
32993
|
async function runPull(ctx) {
|
|
32893
|
-
|
|
32994
|
+
const hasCommunityDir = existsSync10(ctx.paths.communityDir);
|
|
32995
|
+
if (!hasCommunityDir) {
|
|
32894
32996
|
ctx.logger.info(
|
|
32895
32997
|
"no community repos yet \u2014 add one with `caveat community add <github-url>`."
|
|
32896
32998
|
);
|
|
32897
|
-
return;
|
|
32898
32999
|
}
|
|
32899
|
-
const pulls = await communityPull({
|
|
32900
|
-
communityDir: ctx.paths.communityDir,
|
|
32901
|
-
logger: ctx.logger
|
|
32902
|
-
});
|
|
33000
|
+
const pulls = hasCommunityDir ? await communityPull({ communityDir: ctx.paths.communityDir, logger: ctx.logger }) : [];
|
|
32903
33001
|
for (const p of pulls) {
|
|
32904
33002
|
if (p.status === "ok") {
|
|
32905
33003
|
ctx.logger.info(`${p.handle}: pulled`);
|
|
@@ -32910,28 +33008,160 @@ async function runPull(ctx) {
|
|
|
32910
33008
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
32911
33009
|
try {
|
|
32912
33010
|
rebuildAll(db);
|
|
32913
|
-
|
|
32914
|
-
|
|
32915
|
-
ctx.logger.info(`own: +${own.added}`);
|
|
32916
|
-
}
|
|
32917
|
-
for (const entry of readdirSync4(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
32918
|
-
if (!entry.isDirectory()) continue;
|
|
32919
|
-
const source = `community/${entry.name}`;
|
|
32920
|
-
const root = join12(ctx.paths.communityDir, entry.name, "entries");
|
|
32921
|
-
if (!existsSync9(root)) continue;
|
|
32922
|
-
const scan = scanSource({ db, source, entriesRoot: root });
|
|
33011
|
+
const result = reindexAllSources({ db, paths: ctx.paths, logger: ctx.logger });
|
|
33012
|
+
for (const [source, scan] of Object.entries(result.perSource)) {
|
|
32923
33013
|
ctx.logger.info(`${source}: +${scan.added}`);
|
|
32924
33014
|
}
|
|
33015
|
+
writeDigestMarker(ctx.caveatHome, computeEntriesDigest(ctx.paths));
|
|
32925
33016
|
} finally {
|
|
32926
33017
|
db.close();
|
|
32927
33018
|
}
|
|
32928
33019
|
}
|
|
32929
33020
|
|
|
32930
|
-
// src/
|
|
33021
|
+
// src/ghSetup.ts
|
|
32931
33022
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
33023
|
+
import { readSync } from "node:fs";
|
|
33024
|
+
function runGh(args) {
|
|
33025
|
+
const result = spawnSync4("gh", args, { encoding: "utf-8" });
|
|
33026
|
+
return { status: result.status, stdout: typeof result.stdout === "string" ? result.stdout : "", stderr: typeof result.stderr === "string" ? result.stderr : "" };
|
|
33027
|
+
}
|
|
33028
|
+
function commandError(result, fallback) {
|
|
33029
|
+
return new Error((result.stderr || result.stdout || fallback).trim());
|
|
33030
|
+
}
|
|
33031
|
+
function askOnce(question) {
|
|
33032
|
+
process.stdout.write(`${question} `);
|
|
33033
|
+
const buf = Buffer.alloc(256);
|
|
33034
|
+
const bytes = readSync(0, buf, 0, buf.length, null);
|
|
33035
|
+
return /^(?:y|yes)$/i.test(buf.toString("utf-8", 0, bytes).trim());
|
|
33036
|
+
}
|
|
33037
|
+
|
|
33038
|
+
// src/commands/sync.ts
|
|
33039
|
+
async function defaultPrivateRepoUrl(opts, deps) {
|
|
33040
|
+
const version2 = deps.ghRunner(["--version"]);
|
|
33041
|
+
if (version2.status !== 0) {
|
|
33042
|
+
throw new Error(
|
|
33043
|
+
"gh is not available. create a private repository named Caveat-Private on GitHub, then run:\n caveat sync --init <url>\n # or install gh and run caveat sync --init"
|
|
33044
|
+
);
|
|
33045
|
+
}
|
|
33046
|
+
const user = deps.ghRunner(["api", "user", "-q", ".login"]);
|
|
33047
|
+
if (user.status !== 0 || !user.stdout.trim()) {
|
|
33048
|
+
throw new Error("gh is not authenticated; run `gh auth login`, then retry `caveat sync --init`");
|
|
33049
|
+
}
|
|
33050
|
+
const login = user.stdout.trim();
|
|
33051
|
+
const name = `${login}/Caveat-Private`;
|
|
33052
|
+
const view = deps.ghRunner(["repo", "view", name]);
|
|
33053
|
+
if (view.status !== 0) {
|
|
33054
|
+
const question = `create private repo github.com/${name}? [y/N]`;
|
|
33055
|
+
if (!opts.yes) {
|
|
33056
|
+
if (!deps.isTty()) {
|
|
33057
|
+
throw new Error(`${question}; rerun with --yes to approve non-interactively`);
|
|
33058
|
+
}
|
|
33059
|
+
if (!deps.confirm(question)) throw new Error("private repository creation cancelled");
|
|
33060
|
+
}
|
|
33061
|
+
const create = deps.ghRunner(["repo", "create", "Caveat-Private", "--private"]);
|
|
33062
|
+
if (create.status !== 0) throw commandError(create, "gh repo create failed");
|
|
33063
|
+
}
|
|
33064
|
+
return `https://github.com/${name}.git`;
|
|
33065
|
+
}
|
|
33066
|
+
async function runSync(ctx, opts, dependencies = {}) {
|
|
33067
|
+
try {
|
|
33068
|
+
const ghRunner = dependencies.ghRunner ?? runGh;
|
|
33069
|
+
const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
|
|
33070
|
+
const confirm = dependencies.confirm ?? askOnce;
|
|
33071
|
+
const initValue = opts.init;
|
|
33072
|
+
if (initValue !== void 0 && initValue !== false) {
|
|
33073
|
+
const url2 = opts.repo ?? (typeof initValue === "string" ? initValue : await defaultPrivateRepoUrl(opts, { ghRunner, isTty, confirm }));
|
|
33074
|
+
const result2 = await initOwnSync({
|
|
33075
|
+
ownDir: ctx.paths.knowledgeRepo,
|
|
33076
|
+
url: url2,
|
|
33077
|
+
caveatHome: ctx.caveatHome,
|
|
33078
|
+
paths: ctx.paths,
|
|
33079
|
+
logger: ctx.logger,
|
|
33080
|
+
trustRemotePrivate: opts.trustRemotePrivate
|
|
33081
|
+
});
|
|
33082
|
+
ctx.logger.info(
|
|
33083
|
+
result2.remoteWasEmpty ? `initialized private sync remote: ${url2}` : `checked out existing private remote: ${url2} (branch ${result2.branch})`
|
|
33084
|
+
);
|
|
33085
|
+
return;
|
|
33086
|
+
}
|
|
33087
|
+
if (opts.repo) throw new Error("--repo requires --init");
|
|
33088
|
+
const result = await syncOwn({
|
|
33089
|
+
ownDir: ctx.paths.knowledgeRepo,
|
|
33090
|
+
caveatHome: ctx.caveatHome,
|
|
33091
|
+
paths: ctx.paths,
|
|
33092
|
+
logger: ctx.logger,
|
|
33093
|
+
trustRemotePrivate: opts.trustRemotePrivate,
|
|
33094
|
+
dryRun: opts.dryRun
|
|
33095
|
+
});
|
|
33096
|
+
if (result.dryRun) {
|
|
33097
|
+
ctx.logger.info(
|
|
33098
|
+
`[dry-run] ${result.changedFiles} local change(s) pending; remote ${result.pushUrls.join(", ")} (${result.probe.kind})`
|
|
33099
|
+
);
|
|
33100
|
+
} else {
|
|
33101
|
+
const rebased = result.pulled ? ", rebased onto remote" : "";
|
|
33102
|
+
ctx.logger.info(`synced ${result.branch} \u2192 origin (${result.changedFiles} local change(s)${rebased})`);
|
|
33103
|
+
}
|
|
33104
|
+
} catch (err) {
|
|
33105
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
33106
|
+
ctx.logger.error(message);
|
|
33107
|
+
process.exitCode = 1;
|
|
33108
|
+
}
|
|
33109
|
+
}
|
|
33110
|
+
|
|
33111
|
+
// src/commands/publish.ts
|
|
33112
|
+
var HTTPS_TARGET_RE = /^https:\/\/github\.com\/[^/]+\/[^/]+?(?:\.git)?\/?$/;
|
|
33113
|
+
var SCP_TARGET_RE = /^git@github\.com:[^/]+\/[^/]+?(?:\.git)?$/;
|
|
33114
|
+
function validatePublishTarget(url2) {
|
|
33115
|
+
if (!HTTPS_TARGET_RE.test(url2) && !SCP_TARGET_RE.test(url2)) throw new Error("invalid publish target: use https://github.com/<org>/<repo>(.git) or git@github.com:<org>/<repo>(.git)");
|
|
33116
|
+
return url2;
|
|
33117
|
+
}
|
|
33118
|
+
async function defaultPublicRepoUrl(opts, deps) {
|
|
33119
|
+
const version2 = deps.ghRunner(["--version"]);
|
|
33120
|
+
if (version2.status !== 0) throw new Error("gh is not available. create a public repository named Caveat-Public on GitHub, then run:\n caveat publish --init <url>\n # or install gh and run caveat publish");
|
|
33121
|
+
const user = deps.ghRunner(["api", "user", "-q", ".login"]);
|
|
33122
|
+
if (user.status !== 0 || !user.stdout.trim()) throw new Error("gh is not authenticated; run `gh auth login`, then retry `caveat publish`");
|
|
33123
|
+
const login = user.stdout.trim();
|
|
33124
|
+
const name = `${login}/Caveat-Public`;
|
|
33125
|
+
const view = deps.ghRunner(["repo", "view", name]);
|
|
33126
|
+
if (view.status !== 0) {
|
|
33127
|
+
const question = `create public repo github.com/${name}? [y/N]`;
|
|
33128
|
+
if (!opts.yes) {
|
|
33129
|
+
if (!deps.isTty()) throw new Error(`${question}; rerun with --yes to approve non-interactively`);
|
|
33130
|
+
if (!deps.confirm(question)) throw new Error("public repository creation cancelled");
|
|
33131
|
+
}
|
|
33132
|
+
const create = deps.ghRunner(["repo", "create", "Caveat-Public", "--public"]);
|
|
33133
|
+
if (create.status !== 0) throw commandError(create, "gh repo create failed");
|
|
33134
|
+
}
|
|
33135
|
+
return `https://github.com/${name}.git`;
|
|
33136
|
+
}
|
|
33137
|
+
async function runPublish(ctx, opts, dependencies = {}) {
|
|
33138
|
+
try {
|
|
33139
|
+
const ghRunner = dependencies.ghRunner ?? runGh;
|
|
33140
|
+
const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
|
|
33141
|
+
const confirm = dependencies.confirm ?? askOnce;
|
|
33142
|
+
let target = ctx.config.publishTarget;
|
|
33143
|
+
if (opts.init !== void 0) {
|
|
33144
|
+
target = validatePublishTarget(opts.init);
|
|
33145
|
+
writeUserConfigPatch(ctx.userConfigPath, { publishTarget: target });
|
|
33146
|
+
}
|
|
33147
|
+
if (!target) {
|
|
33148
|
+
target = await defaultPublicRepoUrl(opts, { ghRunner, isTty, confirm });
|
|
33149
|
+
writeUserConfigPatch(ctx.userConfigPath, { publishTarget: target });
|
|
33150
|
+
}
|
|
33151
|
+
const result = await publishOwn({ paths: ctx.paths, config: { ...ctx.config, publishTarget: target }, logger: ctx.logger, confirmImpl: confirm, isTty, dryRun: opts.dryRun, yes: opts.yes });
|
|
33152
|
+
if (result.dryRun) ctx.logger.info(`[dry-run] ${result.fileCount} public entry(ies) ready to publish`);
|
|
33153
|
+
else if (result.changed) ctx.logger.info(`published ${result.fileCount} public entry(ies)`);
|
|
33154
|
+
} catch (err) {
|
|
33155
|
+
ctx.logger.error(err instanceof Error ? err.message : String(err));
|
|
33156
|
+
process.exitCode = 1;
|
|
33157
|
+
}
|
|
33158
|
+
}
|
|
33159
|
+
|
|
33160
|
+
// src/commands/codexSidecar.ts
|
|
33161
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
32932
33162
|
import { mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
32933
33163
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
32934
|
-
import { dirname as dirname6, join as
|
|
33164
|
+
import { dirname as dirname6, join as join12 } from "node:path";
|
|
32935
33165
|
import { cwd, exit } from "node:process";
|
|
32936
33166
|
function runCodexSidecarDiagnostics(logger, opts) {
|
|
32937
33167
|
const plan = buildCodexSidecarDiagnosticsCommand({
|
|
@@ -32963,8 +33193,8 @@ function runCodexSidecarWithCaveats(ctx, workflow, prompt, opts) {
|
|
|
32963
33193
|
process.stdout.write(JSON.stringify({ status: "skipped", decision }, null, 2) + "\n");
|
|
32964
33194
|
exit(0);
|
|
32965
33195
|
}
|
|
32966
|
-
const contextDir = mkdtempSync2(
|
|
32967
|
-
const contextFile =
|
|
33196
|
+
const contextDir = mkdtempSync2(join12(tmpdir3(), "caveat-sidecar-context-"));
|
|
33197
|
+
const contextFile = join12(contextDir, "context.json");
|
|
32968
33198
|
let status = 1;
|
|
32969
33199
|
try {
|
|
32970
33200
|
const blocks = collectCaveatContextBlocks(ctx, {
|
|
@@ -33028,7 +33258,7 @@ function defaultPreset(workflow) {
|
|
|
33028
33258
|
}
|
|
33029
33259
|
function executePlan(logger, command, args, options = {}) {
|
|
33030
33260
|
logger.info(`[codex-sidecar] ${command} ${args.map(shellDisplayQuote).join(" ")}`);
|
|
33031
|
-
const result =
|
|
33261
|
+
const result = spawnSync5(command, args, { encoding: "utf-8", stdio: "pipe" });
|
|
33032
33262
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
33033
33263
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
33034
33264
|
if (options.saveResult && result.stdout) {
|
|
@@ -33198,6 +33428,14 @@ program.command("pull").description(
|
|
|
33198
33428
|
const ctx = buildContext(stdoutLogger);
|
|
33199
33429
|
await runPull(ctx);
|
|
33200
33430
|
});
|
|
33431
|
+
program.command("sync").description("Sync own Caveat entries to a private git remote").option("--init [url]", "initialize private remote sync (optionally with its URL)").option("--repo <url>", "private remote URL (requires --init)").option("--dry-run", "show pending own-repo changes without writing", false).option("--trust-remote-private", "continue when anonymous remote visibility cannot be determined", false).option("--yes", "approve creating the default GitHub private repository", false).action(async (opts) => {
|
|
33432
|
+
const ctx = buildContext(stdoutLogger);
|
|
33433
|
+
await runSync(ctx, opts);
|
|
33434
|
+
});
|
|
33435
|
+
program.command("publish").description("Mirror own public Caveat entries to a public git repository").option("--init <url>", "set the public mirror target").option("--dry-run", "show public mirror changes without committing or pushing", false).option("--yes", "approve creating a default repository or publishing changes", false).action(async (opts) => {
|
|
33436
|
+
const ctx = buildContext(stdoutLogger);
|
|
33437
|
+
await runPublish(ctx, opts);
|
|
33438
|
+
});
|
|
33201
33439
|
program.command("serve").description("Start the read-only web share portal").option("--port <n>", "port number", (v) => Number(v), 4242).action(async (opts) => {
|
|
33202
33440
|
await runServe({ port: opts.port });
|
|
33203
33441
|
});
|
|
@@ -33205,7 +33443,7 @@ program.command("mcp-server").description("Run the MCP stdio server (registered
|
|
|
33205
33443
|
await runMcpServer();
|
|
33206
33444
|
});
|
|
33207
33445
|
program.command("hook <name> [arg]").description(
|
|
33208
|
-
"Run a Claude Code hook. name: user-prompt-submit | post-tool-use | stop | worker"
|
|
33446
|
+
"Run a Claude Code hook. name: user-prompt-submit | post-tool-use | stop | worker | reindex"
|
|
33209
33447
|
).action(async (name, arg) => {
|
|
33210
33448
|
await runHook(name, arg);
|
|
33211
33449
|
});
|