caveat-cli 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HCLEIAGO.js → chunk-3MLJQLWY.js} +307 -87
- package/dist/{chunk-HCLEIAGO.js.map → chunk-3MLJQLWY.js.map} +1 -1
- package/dist/index.js +161 -49
- package/dist/index.js.map +1 -1
- package/dist/{server-EASKBCNK.js → server-LAJCQXS3.js} +2 -2
- package/package.json +2 -2
- /package/dist/{server-EASKBCNK.js.map → server-LAJCQXS3.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -11,11 +11,12 @@ import {
|
|
|
11
11
|
__export,
|
|
12
12
|
__toESM,
|
|
13
13
|
acquireReindexLock,
|
|
14
|
-
|
|
14
|
+
buildAndPublishPendingReminder,
|
|
15
15
|
buildCodexSidecarDiagnosticsCommand,
|
|
16
16
|
buildCodexSidecarReadOnlySmokeCommand,
|
|
17
17
|
buildCodexSidecarRunCommand,
|
|
18
18
|
buildHookSignalSidecarContextBlock,
|
|
19
|
+
buildPendingSemanticKey,
|
|
19
20
|
caveatEntriesToSidecarContextBlocks,
|
|
20
21
|
cleanupStalePendingDirs,
|
|
21
22
|
communityAdd,
|
|
@@ -26,11 +27,11 @@ import {
|
|
|
26
27
|
createKeyserverKeyProvider,
|
|
27
28
|
decideCodexSidecarExecution,
|
|
28
29
|
defaultSelfIdentityTokens,
|
|
29
|
-
|
|
30
|
-
drainPendingReminders,
|
|
30
|
+
drainPendingRemindersDetailed,
|
|
31
31
|
ensureUserConfig,
|
|
32
32
|
findCaveatHome,
|
|
33
|
-
|
|
33
|
+
findCaveatsForHook,
|
|
34
|
+
findCaveatsForHookSegments,
|
|
34
35
|
get,
|
|
35
36
|
hasAnyStruggleSignal,
|
|
36
37
|
initOwnSync,
|
|
@@ -63,7 +64,7 @@ import {
|
|
|
63
64
|
userPromptSubmitReminderText,
|
|
64
65
|
writeDigestMarker,
|
|
65
66
|
writeUserConfigPatch
|
|
66
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-3MLJQLWY.js";
|
|
67
68
|
|
|
68
69
|
// ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
69
70
|
var require_code = __commonJS({
|
|
@@ -7544,6 +7545,16 @@ import { spawnSync as spawnSync3 } from "node:child_process";
|
|
|
7544
7545
|
import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
7545
7546
|
import { tmpdir } from "node:os";
|
|
7546
7547
|
import { join as join6 } from "node:path";
|
|
7548
|
+
var DEFAULT_HOOK_SIDECAR_TIMEOUT_MS = 12e4;
|
|
7549
|
+
var MAX_HOOK_SIDECAR_TIMEOUT_MS = 24e4;
|
|
7550
|
+
function resolveHookSidecarTimeoutMs(raw) {
|
|
7551
|
+
if (raw === void 0) return DEFAULT_HOOK_SIDECAR_TIMEOUT_MS;
|
|
7552
|
+
const value = Number(raw);
|
|
7553
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_HOOK_SIDECAR_TIMEOUT_MS) {
|
|
7554
|
+
throw new Error(`CAVEAT_HOOK_CODEX_SIDECAR_TIMEOUT_MS must be an integer from 1 to ${MAX_HOOK_SIDECAR_TIMEOUT_MS}`);
|
|
7555
|
+
}
|
|
7556
|
+
return value;
|
|
7557
|
+
}
|
|
7547
7558
|
function compactFailureMessage(message) {
|
|
7548
7559
|
const singleLine = message.replace(/\s+/g, " ").trim();
|
|
7549
7560
|
if (!singleLine) return "unknown error";
|
|
@@ -7607,7 +7618,9 @@ function runCodexSidecarAdvisory(input) {
|
|
|
7607
7618
|
const result = spawnSync3(process.execPath, args, {
|
|
7608
7619
|
cwd: input.projectRoot,
|
|
7609
7620
|
encoding: "utf-8",
|
|
7610
|
-
|
|
7621
|
+
// Keep at least one minute between the longest supported model call and
|
|
7622
|
+
// the pending single-flight claim TTL (five minutes).
|
|
7623
|
+
timeout: resolveHookSidecarTimeoutMs(process.env.CAVEAT_HOOK_CODEX_SIDECAR_TIMEOUT_MS),
|
|
7611
7624
|
maxBuffer: 10 * 1024 * 1024
|
|
7612
7625
|
});
|
|
7613
7626
|
if (result.error) {
|
|
@@ -8205,7 +8218,7 @@ function runStats(ctx) {
|
|
|
8205
8218
|
|
|
8206
8219
|
// src/commands/serve.ts
|
|
8207
8220
|
async function runServe(opts) {
|
|
8208
|
-
const { startServer } = await import("./server-
|
|
8221
|
+
const { startServer } = await import("./server-LAJCQXS3.js");
|
|
8209
8222
|
const { port, host } = startServer({ port: opts.port });
|
|
8210
8223
|
process.stdout.write(`[caveat] web portal: http://${host}:${port}/
|
|
8211
8224
|
`);
|
|
@@ -32670,8 +32683,10 @@ function buildContextSafely() {
|
|
|
32670
32683
|
return null;
|
|
32671
32684
|
}
|
|
32672
32685
|
}
|
|
32673
|
-
function
|
|
32674
|
-
|
|
32686
|
+
function searchCaveatsSafely(input) {
|
|
32687
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
32688
|
+
const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
|
|
32689
|
+
if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
|
|
32675
32690
|
let db;
|
|
32676
32691
|
let caveatHome;
|
|
32677
32692
|
let hits;
|
|
@@ -32680,9 +32695,10 @@ function searchCaveatsFromTextSafely(text, surface) {
|
|
|
32680
32695
|
if (!ctx || !existsSync10(ctx.paths.dbPath)) return [];
|
|
32681
32696
|
caveatHome = ctx.caveatHome;
|
|
32682
32697
|
db = openDb({ path: ctx.paths.dbPath });
|
|
32683
|
-
|
|
32698
|
+
const searchOptions = {
|
|
32684
32699
|
selfIdentity: defaultSelfIdentityTokens()
|
|
32685
|
-
}
|
|
32700
|
+
};
|
|
32701
|
+
hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
|
|
32686
32702
|
} catch (err) {
|
|
32687
32703
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32688
32704
|
process.stderr.write(`[caveat:hook] search error: ${msg}
|
|
@@ -32699,7 +32715,7 @@ function searchCaveatsFromTextSafely(text, surface) {
|
|
|
32699
32715
|
}
|
|
32700
32716
|
} else {
|
|
32701
32717
|
try {
|
|
32702
|
-
logHookQueryMiss({ caveatHome, agent: "claude", surface, query:
|
|
32718
|
+
logHookQueryMiss({ caveatHome, agent: "claude", surface: inputs[0].surface, query: queryForLog });
|
|
32703
32719
|
} catch (err) {
|
|
32704
32720
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32705
32721
|
process.stderr.write(`[caveat:hook] query log error: ${msg}
|
|
@@ -32725,13 +32741,19 @@ function loadSignalsSafely(path) {
|
|
|
32725
32741
|
function systemReminderOutput(text) {
|
|
32726
32742
|
return `<system-reminder>${text.replace(/</g, "\u2039").replace(/>/g, "\u203A")}</system-reminder>`;
|
|
32727
32743
|
}
|
|
32744
|
+
function claudePendingCleanupFailureText() {
|
|
32745
|
+
return "[caveat:hook] pending reminder cleanup failed";
|
|
32746
|
+
}
|
|
32728
32747
|
function drainForSession(sessionId) {
|
|
32729
32748
|
const ctx = buildContextSafely();
|
|
32730
32749
|
if (!ctx) return [];
|
|
32731
|
-
|
|
32732
|
-
|
|
32733
|
-
|
|
32734
|
-
|
|
32750
|
+
const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
|
|
32751
|
+
const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
|
|
32752
|
+
for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
|
|
32753
|
+
process.stderr.write(`${claudePendingCleanupFailureText()}
|
|
32754
|
+
`);
|
|
32755
|
+
}
|
|
32756
|
+
return [...local.reminders, ...global.reminders];
|
|
32735
32757
|
}
|
|
32736
32758
|
function claudeContextDedupeKey(text) {
|
|
32737
32759
|
if (text.startsWith(CLAUDE_STOP_REMINDER_PREFIX)) return "claude-stop-reminder";
|
|
@@ -32750,7 +32772,7 @@ function compactClaudeContexts(contexts) {
|
|
|
32750
32772
|
}
|
|
32751
32773
|
selected.reverse();
|
|
32752
32774
|
const limited = selected.slice(-CLAUDE_MAX_CONTEXT_BLOCKS);
|
|
32753
|
-
const omitted =
|
|
32775
|
+
const omitted = selected.length - limited.length;
|
|
32754
32776
|
if (omitted > 0) {
|
|
32755
32777
|
limited.push(
|
|
32756
32778
|
`[caveat] pending reminder ${omitted} \u4EF6\u3092\u91CD\u8907\u307E\u305F\u306F\u4E0A\u9650\u306B\u3088\u308A\u7701\u7565\u3057\u307E\u3057\u305F\u3002`
|
|
@@ -32795,8 +32817,20 @@ function queueStopForSession(sessionId, signals, related) {
|
|
|
32795
32817
|
if (!ctx) return;
|
|
32796
32818
|
const key = stopSignalKey(signals, related);
|
|
32797
32819
|
if (wasStopReminderQueued(ctx.caveatHome, sessionId, key)) return;
|
|
32820
|
+
let result;
|
|
32821
|
+
try {
|
|
32822
|
+
result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
|
|
32823
|
+
agent: "claude",
|
|
32824
|
+
surface: "stop",
|
|
32825
|
+
refs: related,
|
|
32826
|
+
stopSignalDigest: key
|
|
32827
|
+
}), () => buildStopReminder(signals, related));
|
|
32828
|
+
} catch {
|
|
32829
|
+
process.stderr.write("[caveat:hook] pending reminder build or publish failed\n");
|
|
32830
|
+
return;
|
|
32831
|
+
}
|
|
32832
|
+
if (!result.ran) return;
|
|
32798
32833
|
try {
|
|
32799
|
-
appendPendingReminder(ctx.caveatHome, sessionId, buildStopReminder(signals, related));
|
|
32800
32834
|
markStopReminderQueued(ctx.caveatHome, sessionId, key);
|
|
32801
32835
|
} catch (err) {
|
|
32802
32836
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -32827,6 +32861,20 @@ function extractToolResponseText(response) {
|
|
|
32827
32861
|
}
|
|
32828
32862
|
return "";
|
|
32829
32863
|
}
|
|
32864
|
+
function toolTopicText(payload) {
|
|
32865
|
+
const parts = [];
|
|
32866
|
+
const toolName = payload.tool_name ?? payload.toolName;
|
|
32867
|
+
if (typeof toolName === "string") parts.push(toolName);
|
|
32868
|
+
const input = payload.tool_input ?? payload.toolInput;
|
|
32869
|
+
if (typeof input === "string") parts.push(input);
|
|
32870
|
+
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
32871
|
+
const record2 = input;
|
|
32872
|
+
for (const key of ["command", "cmd", "query", "url"]) {
|
|
32873
|
+
if (typeof record2[key] === "string") parts.push(record2[key]);
|
|
32874
|
+
}
|
|
32875
|
+
}
|
|
32876
|
+
return parts.join("\n");
|
|
32877
|
+
}
|
|
32830
32878
|
function isToolError(payload) {
|
|
32831
32879
|
if (payload.hook_event_name === "PostToolUseFailure") return true;
|
|
32832
32880
|
const resp = payload.tool_response ?? payload.toolResponse;
|
|
@@ -32850,7 +32898,7 @@ function spawnWorker(job) {
|
|
|
32850
32898
|
workDir = mkdtempSync2(join12(root, "job-"));
|
|
32851
32899
|
chmodSync(workDir, 448);
|
|
32852
32900
|
workFile = join12(workDir, `${randomBytes(4).toString("hex")}.json`);
|
|
32853
|
-
writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/
|
|
32901
|
+
writeFileSync5(workFile, JSON.stringify({ ...job, schemaVersion: "caveat-worker-job/v2" }), { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
32854
32902
|
} catch (err) {
|
|
32855
32903
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32856
32904
|
process.stderr.write(`[caveat:hook] worker writefile error: ${msg}
|
|
@@ -32894,15 +32942,27 @@ async function runWorker(workFile) {
|
|
|
32894
32942
|
} catch {
|
|
32895
32943
|
process.exit(0);
|
|
32896
32944
|
}
|
|
32897
|
-
if (!job.
|
|
32898
|
-
const hits =
|
|
32945
|
+
if (!job.failureText || !job.sessionId) process.exit(0);
|
|
32946
|
+
const hits = searchCaveatsSafely({
|
|
32947
|
+
topicText: job.topicText,
|
|
32948
|
+
failureText: job.failureText,
|
|
32949
|
+
surface: "tool_error"
|
|
32950
|
+
});
|
|
32899
32951
|
if (hits.length === 0) process.exit(0);
|
|
32900
32952
|
const ctx = buildContextSafely();
|
|
32901
32953
|
if (!ctx) process.exit(0);
|
|
32954
|
+
let result;
|
|
32902
32955
|
try {
|
|
32903
|
-
|
|
32956
|
+
result = buildAndPublishPendingReminder(ctx.caveatHome, job.sessionId, buildPendingSemanticKey({
|
|
32957
|
+
agent: "claude",
|
|
32958
|
+
surface: "tool_error",
|
|
32959
|
+
refs: hits
|
|
32960
|
+
}), () => buildToolErrorReminder(job, hits));
|
|
32904
32961
|
} catch {
|
|
32962
|
+
process.stderr.write("[caveat:hook] pending reminder build or publish failed\n");
|
|
32963
|
+
process.exit(0);
|
|
32905
32964
|
}
|
|
32965
|
+
if (!result.ran) process.exit(0);
|
|
32906
32966
|
process.exit(0);
|
|
32907
32967
|
}
|
|
32908
32968
|
function cleanupWorkerDir(workDir, root) {
|
|
@@ -32969,12 +33029,20 @@ function isStaleWorkerJobDir(path) {
|
|
|
32969
33029
|
const stat = lstatSync(file2);
|
|
32970
33030
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
32971
33031
|
if (!stat.isFile() || stat.isSymbolicLink() || !hasPrivateOwnership(stat, uid)) return false;
|
|
32972
|
-
return
|
|
33032
|
+
return isKnownStaleWorkerJob(JSON.parse(readFileSync5(file2, "utf-8")));
|
|
32973
33033
|
}
|
|
32974
33034
|
function hasPrivateOwnership(stat, uid) {
|
|
32975
33035
|
return process.platform === "win32" || (stat.mode & 63) === 0 && (uid === void 0 || stat.uid === uid);
|
|
32976
33036
|
}
|
|
32977
33037
|
function isWorkerJob(value) {
|
|
33038
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
33039
|
+
const job = value;
|
|
33040
|
+
const keys = Object.keys(job).sort();
|
|
33041
|
+
if (!(keys.length === 4 && keys.join(",") === "failureText,schemaVersion,sessionId,topicText") && !(keys.length === 5 && keys.join(",") === "additionalContext,failureText,schemaVersion,sessionId,topicText")) return false;
|
|
33042
|
+
return job.schemaVersion === "caveat-worker-job/v2" && typeof job.sessionId === "string" && typeof job.topicText === "string" && typeof job.failureText === "string" && (job.additionalContext === void 0 || job.additionalContext !== null && typeof job.additionalContext === "object" && !Array.isArray(job.additionalContext));
|
|
33043
|
+
}
|
|
33044
|
+
function isKnownStaleWorkerJob(value) {
|
|
33045
|
+
if (isWorkerJob(value)) return true;
|
|
32978
33046
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
32979
33047
|
const job = value;
|
|
32980
33048
|
const keys = Object.keys(job).sort();
|
|
@@ -33070,7 +33138,7 @@ function buildToolErrorReminder(job, hits) {
|
|
|
33070
33138
|
const hasSidecarConfig = existsSync10(join12(projectRoot, ".codex-sidecar.yml"));
|
|
33071
33139
|
if (mode === "auto" && !hasSidecarConfig) return base;
|
|
33072
33140
|
const advisory = runCodexSidecarAdvisory({
|
|
33073
|
-
searchText: job.
|
|
33141
|
+
searchText: job.failureText,
|
|
33074
33142
|
limit: hits.length,
|
|
33075
33143
|
projectRoot,
|
|
33076
33144
|
prompt: [
|
|
@@ -33170,7 +33238,7 @@ async function runHook(name, arg) {
|
|
|
33170
33238
|
const contexts = name === "stop" ? [] : drainForSession(sessionId);
|
|
33171
33239
|
if (name === "user-prompt-submit") {
|
|
33172
33240
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
33173
|
-
const hits =
|
|
33241
|
+
const hits = searchCaveatsSafely({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
|
|
33174
33242
|
if (hits.length > 0) {
|
|
33175
33243
|
contexts.push(userPromptSubmitReminderText(hits));
|
|
33176
33244
|
}
|
|
@@ -33198,7 +33266,8 @@ async function runHook(name, arg) {
|
|
|
33198
33266
|
toolName: payload.tool_name ?? payload.toolName,
|
|
33199
33267
|
failureKind
|
|
33200
33268
|
});
|
|
33201
|
-
|
|
33269
|
+
const topicText = toolTopicText(payload);
|
|
33270
|
+
spawnWorker({ sessionId, topicText, failureText: errText, ...additionalContext ? { additionalContext } : {} });
|
|
33202
33271
|
}
|
|
33203
33272
|
process.exit(0);
|
|
33204
33273
|
}
|
|
@@ -33231,7 +33300,11 @@ async function runHook(name, arg) {
|
|
|
33231
33300
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
33232
33301
|
const signals = transcriptPath ? loadSignalsSafely(transcriptPath) : null;
|
|
33233
33302
|
if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
|
|
33234
|
-
const related =
|
|
33303
|
+
const related = searchCaveatsSafely(signals.errorSnippets.map((failureText) => ({
|
|
33304
|
+
topicText: "",
|
|
33305
|
+
failureText,
|
|
33306
|
+
surface: "stop"
|
|
33307
|
+
})));
|
|
33235
33308
|
queueStopForSession(sessionId, signals, related);
|
|
33236
33309
|
process.exit(0);
|
|
33237
33310
|
}
|
|
@@ -33285,8 +33358,10 @@ function buildContextSafely2() {
|
|
|
33285
33358
|
return null;
|
|
33286
33359
|
}
|
|
33287
33360
|
}
|
|
33288
|
-
function
|
|
33289
|
-
|
|
33361
|
+
function searchCaveatsSafely2(input) {
|
|
33362
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
33363
|
+
const queryForLog = inputs.map((item) => item.surface === "user_prompt" ? item.topicText || item.failureText : item.failureText).filter(Boolean).join("\n");
|
|
33364
|
+
if (inputs.length === 0 || inputs.every((item) => !item.topicText && !item.failureText)) return [];
|
|
33290
33365
|
let db;
|
|
33291
33366
|
let caveatHome;
|
|
33292
33367
|
let hits;
|
|
@@ -33295,9 +33370,10 @@ function searchCaveatsFromTextSafely2(text, surface) {
|
|
|
33295
33370
|
if (!ctx || !existsSync11(ctx.paths.dbPath)) return [];
|
|
33296
33371
|
caveatHome = ctx.caveatHome;
|
|
33297
33372
|
db = openDb({ path: ctx.paths.dbPath });
|
|
33298
|
-
|
|
33373
|
+
const searchOptions = {
|
|
33299
33374
|
selfIdentity: defaultSelfIdentityTokens()
|
|
33300
|
-
}
|
|
33375
|
+
};
|
|
33376
|
+
hits = inputs.length === 1 ? findCaveatsForHook(db, inputs[0], searchOptions) : findCaveatsForHookSegments(db, inputs, searchOptions);
|
|
33301
33377
|
} catch (err) {
|
|
33302
33378
|
const msg = err instanceof Error ? err.message : String(err);
|
|
33303
33379
|
process.stderr.write(`[caveat:codex-hook] search error: ${msg}
|
|
@@ -33314,7 +33390,7 @@ function searchCaveatsFromTextSafely2(text, surface) {
|
|
|
33314
33390
|
}
|
|
33315
33391
|
} else {
|
|
33316
33392
|
try {
|
|
33317
|
-
logHookQueryMiss({ caveatHome, agent: "codex", surface, query:
|
|
33393
|
+
logHookQueryMiss({ caveatHome, agent: "codex", surface: inputs[0].surface, query: queryForLog });
|
|
33318
33394
|
} catch (err) {
|
|
33319
33395
|
const msg = err instanceof Error ? err.message : String(err);
|
|
33320
33396
|
process.stderr.write(`[caveat:codex-hook] query log error: ${msg}
|
|
@@ -33443,15 +33519,17 @@ function buildCodexPostToolUseWorkerJob(payload) {
|
|
|
33443
33519
|
const responseText = extractToolResponseText2(payload.tool_response ?? payload.toolResponse);
|
|
33444
33520
|
const inputText = toolInputText(payload.tool_input);
|
|
33445
33521
|
const transcriptOutput = transcriptPath && toolUseId ? transcriptToolOutput(transcriptPath, toolUseId) : null;
|
|
33446
|
-
const
|
|
33522
|
+
const topicText = inputText.trim();
|
|
33523
|
+
const failureText = [responseText, transcriptOutput ?? ""].map((s) => s.trim()).filter(Boolean).join("\n");
|
|
33447
33524
|
const knownError = isCodexToolError(payload);
|
|
33448
33525
|
if (knownError) {
|
|
33449
|
-
return { sessionId,
|
|
33526
|
+
return { sessionId, topicText, failureText, knownError: true, transcriptPath, toolUseId };
|
|
33450
33527
|
}
|
|
33451
|
-
if (transcriptPath && toolUseId && isShellLikeTool(payload) &&
|
|
33528
|
+
if (transcriptPath && toolUseId && isShellLikeTool(payload) && (topicText || failureText)) {
|
|
33452
33529
|
return {
|
|
33453
33530
|
sessionId,
|
|
33454
|
-
|
|
33531
|
+
topicText,
|
|
33532
|
+
failureText,
|
|
33455
33533
|
knownError: false,
|
|
33456
33534
|
allowSymptomOnly: true,
|
|
33457
33535
|
transcriptPath,
|
|
@@ -33468,13 +33546,19 @@ function codexContextOutput(text, eventName = "UserPromptSubmit") {
|
|
|
33468
33546
|
}
|
|
33469
33547
|
});
|
|
33470
33548
|
}
|
|
33549
|
+
function codexPendingCleanupFailureText() {
|
|
33550
|
+
return "[caveat:codex-hook] pending reminder cleanup failed";
|
|
33551
|
+
}
|
|
33471
33552
|
function drainForSession2(sessionId) {
|
|
33472
33553
|
const ctx = buildContextSafely2();
|
|
33473
33554
|
if (!ctx) return [];
|
|
33474
|
-
|
|
33475
|
-
|
|
33476
|
-
|
|
33477
|
-
|
|
33555
|
+
const local = drainPendingRemindersDetailed(ctx.caveatHome, sessionId);
|
|
33556
|
+
const global = drainPendingRemindersDetailed(ctx.caveatHome, "_global");
|
|
33557
|
+
for (const _failure of [...local.cleanupFailures, ...global.cleanupFailures]) {
|
|
33558
|
+
process.stderr.write(`${codexPendingCleanupFailureText()}
|
|
33559
|
+
`);
|
|
33560
|
+
}
|
|
33561
|
+
return [...local.reminders, ...global.reminders];
|
|
33478
33562
|
}
|
|
33479
33563
|
function codexContextDedupeKey(text) {
|
|
33480
33564
|
if (text.startsWith(CODEX_STOP_REMINDER_PREFIX)) return "codex-stop-reminder";
|
|
@@ -33493,7 +33577,7 @@ function compactCodexContexts(contexts) {
|
|
|
33493
33577
|
}
|
|
33494
33578
|
selected.reverse();
|
|
33495
33579
|
const limited = selected.slice(-CODEX_MAX_CONTEXT_BLOCKS);
|
|
33496
|
-
const omitted =
|
|
33580
|
+
const omitted = selected.length - limited.length;
|
|
33497
33581
|
if (omitted > 0) {
|
|
33498
33582
|
limited.push(`[caveat] pending reminder ${omitted} \u4EF6\u3092\u91CD\u8907\u307E\u305F\u306F\u4E0A\u9650\u306B\u3088\u308A\u7701\u7565\u3057\u307E\u3057\u305F\u3002`);
|
|
33499
33583
|
}
|
|
@@ -33536,8 +33620,20 @@ function queueStopForSession2(sessionId, signals, related) {
|
|
|
33536
33620
|
if (!ctx) return;
|
|
33537
33621
|
const key = stopSignalKey2(signals, related);
|
|
33538
33622
|
if (wasStopReminderQueued2(ctx.caveatHome, sessionId, key)) return;
|
|
33623
|
+
let result;
|
|
33624
|
+
try {
|
|
33625
|
+
result = buildAndPublishPendingReminder(ctx.caveatHome, sessionId, buildPendingSemanticKey({
|
|
33626
|
+
agent: "codex",
|
|
33627
|
+
surface: "stop",
|
|
33628
|
+
refs: related,
|
|
33629
|
+
stopSignalDigest: key
|
|
33630
|
+
}), () => stopReminderText(signals, related));
|
|
33631
|
+
} catch {
|
|
33632
|
+
process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
|
|
33633
|
+
return;
|
|
33634
|
+
}
|
|
33635
|
+
if (!result.ran) return;
|
|
33539
33636
|
try {
|
|
33540
|
-
appendPendingReminder(ctx.caveatHome, sessionId, stopReminderText(signals, related));
|
|
33541
33637
|
markStopReminderQueued2(ctx.caveatHome, sessionId, key);
|
|
33542
33638
|
} catch (err) {
|
|
33543
33639
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -33555,8 +33651,8 @@ async function waitForTranscriptOutput(transcriptPath, toolUseId) {
|
|
|
33555
33651
|
return null;
|
|
33556
33652
|
}
|
|
33557
33653
|
async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
33558
|
-
if (!job.
|
|
33559
|
-
let
|
|
33654
|
+
if (!job.topicText && !job.failureText || !job.sessionId) return;
|
|
33655
|
+
let failureText = job.failureText;
|
|
33560
33656
|
let knownError = job.knownError === true;
|
|
33561
33657
|
if (opts.waitForTranscript && job.transcriptPath && job.toolUseId) {
|
|
33562
33658
|
const transcriptOutput = await waitForTranscriptOutput(job.transcriptPath, job.toolUseId);
|
|
@@ -33566,18 +33662,30 @@ async function processCodexWorkerJob(job, opts = { waitForTranscript: true }) {
|
|
|
33566
33662
|
if (exit2 === 0) return;
|
|
33567
33663
|
knownError = true;
|
|
33568
33664
|
}
|
|
33569
|
-
|
|
33665
|
+
failureText = [failureText, transcriptOutput].filter(Boolean).join("\n");
|
|
33570
33666
|
}
|
|
33571
33667
|
}
|
|
33572
33668
|
if (!knownError && job.allowSymptomOnly !== true) return;
|
|
33573
|
-
const hits =
|
|
33669
|
+
const hits = searchCaveatsSafely2({
|
|
33670
|
+
topicText: job.topicText,
|
|
33671
|
+
failureText,
|
|
33672
|
+
surface: "tool_error"
|
|
33673
|
+
});
|
|
33574
33674
|
if (hits.length === 0) return;
|
|
33575
33675
|
const ctx = buildContextSafely2();
|
|
33576
33676
|
if (!ctx) return;
|
|
33677
|
+
let result;
|
|
33577
33678
|
try {
|
|
33578
|
-
|
|
33679
|
+
result = buildAndPublishPendingReminder(ctx.caveatHome, job.sessionId, buildPendingSemanticKey({
|
|
33680
|
+
agent: "codex",
|
|
33681
|
+
surface: "tool_error",
|
|
33682
|
+
refs: hits
|
|
33683
|
+
}), () => toolErrorReminderText(hits));
|
|
33579
33684
|
} catch {
|
|
33685
|
+
process.stderr.write("[caveat:codex-hook] pending reminder build or publish failed\n");
|
|
33686
|
+
return;
|
|
33580
33687
|
}
|
|
33688
|
+
if (!result.ran) return;
|
|
33581
33689
|
}
|
|
33582
33690
|
async function runCodexWorker(workFile) {
|
|
33583
33691
|
let raw;
|
|
@@ -33649,7 +33757,7 @@ async function runCodexHook(name, arg) {
|
|
|
33649
33757
|
if (name === "user-prompt-submit") {
|
|
33650
33758
|
const contexts = sessionId ? drainForSession2(sessionId) : [];
|
|
33651
33759
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
33652
|
-
const hits =
|
|
33760
|
+
const hits = searchCaveatsSafely2({ topicText: prompt, failureText: prompt, surface: "user_prompt" });
|
|
33653
33761
|
if (hits.length > 0) {
|
|
33654
33762
|
contexts.push(userPromptSubmitReminderText(hits));
|
|
33655
33763
|
}
|
|
@@ -33694,7 +33802,11 @@ async function runCodexHook(name, arg) {
|
|
|
33694
33802
|
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
|
|
33695
33803
|
const signals = transcriptPath ? loadSignalsSafely2(transcriptPath) : null;
|
|
33696
33804
|
if (!signals || !hasAnyStruggleSignal(signals)) process.exit(0);
|
|
33697
|
-
const related =
|
|
33805
|
+
const related = searchCaveatsSafely2(signals.errorSnippets.map((failureText) => ({
|
|
33806
|
+
topicText: "",
|
|
33807
|
+
failureText,
|
|
33808
|
+
surface: "stop"
|
|
33809
|
+
})));
|
|
33698
33810
|
if (sessionId) queueStopForSession2(sessionId, signals, related);
|
|
33699
33811
|
process.exit(0);
|
|
33700
33812
|
}
|