lazycodex-ai 5.0.0-beta.49 → 5.0.0-beta.50
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/cli/index.js +4682 -14969
- package/dist/cli-node/index.js +4727 -15014
- package/package.json +1 -1
- package/packages/lsp-daemon/dist/cli.js +181 -181
- package/packages/lsp-daemon/dist/client.js +232 -232
- package/packages/lsp-daemon/dist/index.js +132 -132
- package/packages/lsp-tools-mcp/dist/cli.js +103 -101
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +14 -14
- package/packages/lsp-tools-mcp/dist/mcp.js +129 -129
- package/packages/lsp-tools-mcp/dist/tools.js +47 -47
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +4 -0
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +151 -102
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/directive.md +2 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +35 -24
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +31 -21
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/types.d.ts +3 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +31 -23
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/types.ts +3 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +133 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +3 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +298 -298
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/README.md +2 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +123 -0
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +38 -30
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +6 -0
- package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +38 -2
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +24 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +66 -357
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +66 -358
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/README.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-low.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +63 -63
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/model-catalog.json +16 -7
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +8 -4
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +18 -90
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +3 -1
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +12 -12
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +14 -4
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +25 -1
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +35 -35
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +107 -15
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +318 -569
|
@@ -74,7 +74,8 @@ function runSubagentStopHook(input, fs) {
|
|
|
74
74
|
return "";
|
|
75
75
|
if (transcriptHasContextPressureMarker(input.transcript_path, fs))
|
|
76
76
|
return "";
|
|
77
|
-
|
|
77
|
+
const receiptFailure = getEvidenceReceiptFailure(input, fs);
|
|
78
|
+
if (receiptFailure === null) {
|
|
78
79
|
clearAttemptState(input.cwd, input.session_id, input.agent_id, fs);
|
|
79
80
|
return "";
|
|
80
81
|
}
|
|
@@ -87,7 +88,9 @@ function runSubagentStopHook(input, fs) {
|
|
|
87
88
|
writeAttemptState(input.cwd, input.session_id, input.agent_id, { attempts }, fs);
|
|
88
89
|
return JSON.stringify({
|
|
89
90
|
decision: "block",
|
|
90
|
-
reason:
|
|
91
|
+
reason: `Evidence receipt rejected: ${receiptFailure}.
|
|
92
|
+
|
|
93
|
+
${renderDirective(attempts, input.last_assistant_message)}`
|
|
91
94
|
});
|
|
92
95
|
}
|
|
93
96
|
var CONTEXT_PRESSURE_MARKERS = [
|
|
@@ -109,19 +112,19 @@ function transcriptHasContextPressureMarker(transcriptPath, fs) {
|
|
|
109
112
|
throw error;
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
|
-
function
|
|
115
|
+
function getEvidenceReceiptFailure(input, fs) {
|
|
113
116
|
const receiptPath = extractEvidencePath(input.last_assistant_message);
|
|
114
117
|
if (receiptPath === null)
|
|
115
|
-
return
|
|
118
|
+
return "invalid";
|
|
116
119
|
const evidenceRoot = resolve(input.cwd, ".omo", "evidence");
|
|
117
120
|
const resolvedPath = isAbsolute(receiptPath) ? resolve(receiptPath) : resolve(input.cwd, receiptPath);
|
|
118
121
|
if (!isPathInsideDirectory(resolvedPath, evidenceRoot))
|
|
119
|
-
return
|
|
122
|
+
return "invalid";
|
|
120
123
|
try {
|
|
121
|
-
return
|
|
124
|
+
return getEvidenceFileFailure(resolvedPath, evidenceRoot, input, fs);
|
|
122
125
|
} catch (error) {
|
|
123
126
|
if (error instanceof Error)
|
|
124
|
-
return
|
|
127
|
+
return "invalid";
|
|
125
128
|
throw error;
|
|
126
129
|
}
|
|
127
130
|
}
|
|
@@ -129,28 +132,36 @@ function isPathInsideDirectory(filePath, directoryPath) {
|
|
|
129
132
|
const relativePath = relative(directoryPath, filePath);
|
|
130
133
|
return relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
131
134
|
}
|
|
132
|
-
function
|
|
135
|
+
function getEvidenceFileFailure(filePath, evidenceRoot, input, fs) {
|
|
133
136
|
if (!fs.existsSync(filePath))
|
|
134
|
-
return
|
|
135
|
-
const realCwd = realPath(cwd, fs);
|
|
137
|
+
return "invalid";
|
|
138
|
+
const realCwd = realPath(input.cwd, fs);
|
|
136
139
|
const realEvidenceRoot = realPath(evidenceRoot, fs);
|
|
137
140
|
const realFilePath = realPath(filePath, fs);
|
|
138
141
|
if (!isPathInsideDirectory(realEvidenceRoot, realCwd))
|
|
139
|
-
return
|
|
142
|
+
return "invalid";
|
|
140
143
|
if (!isPathInsideDirectory(realFilePath, realEvidenceRoot))
|
|
141
|
-
return
|
|
142
|
-
return isNonEmptyFile(filePath, fs);
|
|
143
|
-
}
|
|
144
|
-
function isNonEmptyFile(filePath, fs) {
|
|
145
|
-
if (!fs.existsSync(filePath))
|
|
146
|
-
return false;
|
|
144
|
+
return "invalid";
|
|
147
145
|
const linkStat = fs.lstatSync?.(filePath) ?? nodeLstatSync(filePath);
|
|
148
146
|
if (linkStat.isSymbolicLink?.() === true)
|
|
149
|
-
return
|
|
147
|
+
return "invalid";
|
|
150
148
|
const stat = fs.statSync(filePath);
|
|
151
|
-
if (stat.
|
|
152
|
-
return
|
|
153
|
-
|
|
149
|
+
if (stat.isFile?.() === false)
|
|
150
|
+
return "invalid";
|
|
151
|
+
if (stat.size <= 0 || fs.readFileSync(filePath, "utf8").trim().length < 40)
|
|
152
|
+
return "placeholder";
|
|
153
|
+
let transcriptStat;
|
|
154
|
+
try {
|
|
155
|
+
transcriptStat = fs.statSync(input.transcript_path);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (error instanceof Error)
|
|
158
|
+
return null;
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
const transcriptStart = transcriptStat.birthtimeMs ?? transcriptStat.ctimeMs;
|
|
162
|
+
if (transcriptStart !== undefined && (stat.mtimeMs === undefined || stat.mtimeMs < transcriptStart))
|
|
163
|
+
return "stale";
|
|
164
|
+
return null;
|
|
154
165
|
}
|
|
155
166
|
function realPath(path, fs) {
|
|
156
167
|
return fs.realpathSync?.(path) ?? nodeRealpathSync(path);
|
|
@@ -211,13 +222,13 @@ function parseHookInput(raw) {
|
|
|
211
222
|
}
|
|
212
223
|
}
|
|
213
224
|
function readStdin() {
|
|
214
|
-
return new Promise((
|
|
225
|
+
return new Promise((resolve) => {
|
|
215
226
|
let data = "";
|
|
216
227
|
processStdin.setEncoding("utf8");
|
|
217
228
|
processStdin.on("data", (chunk) => {
|
|
218
229
|
data += chunk;
|
|
219
230
|
});
|
|
220
|
-
processStdin.once("error", () =>
|
|
221
|
-
processStdin.once("end", () =>
|
|
231
|
+
processStdin.once("error", () => resolve(data));
|
|
232
|
+
processStdin.once("end", () => resolve(data));
|
|
222
233
|
});
|
|
223
234
|
}
|
|
@@ -11,7 +11,8 @@ export function runSubagentStopHook(input, fs) {
|
|
|
11
11
|
return "";
|
|
12
12
|
if (transcriptHasContextPressureMarker(input.transcript_path, fs))
|
|
13
13
|
return "";
|
|
14
|
-
|
|
14
|
+
const receiptFailure = getEvidenceReceiptFailure(input, fs);
|
|
15
|
+
if (receiptFailure === null) {
|
|
15
16
|
clearAttemptState(input.cwd, input.session_id, input.agent_id, fs);
|
|
16
17
|
return "";
|
|
17
18
|
}
|
|
@@ -24,7 +25,7 @@ export function runSubagentStopHook(input, fs) {
|
|
|
24
25
|
writeAttemptState(input.cwd, input.session_id, input.agent_id, { attempts }, fs);
|
|
25
26
|
return JSON.stringify({
|
|
26
27
|
decision: "block",
|
|
27
|
-
reason: renderDirective(attempts, input.last_assistant_message)
|
|
28
|
+
reason: `Evidence receipt rejected: ${receiptFailure}.\n\n${renderDirective(attempts, input.last_assistant_message)}`,
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
const CONTEXT_PRESSURE_MARKERS = [
|
|
@@ -47,20 +48,20 @@ function transcriptHasContextPressureMarker(transcriptPath, fs) {
|
|
|
47
48
|
throw error;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
|
-
function
|
|
51
|
+
function getEvidenceReceiptFailure(input, fs) {
|
|
51
52
|
const receiptPath = extractEvidencePath(input.last_assistant_message);
|
|
52
53
|
if (receiptPath === null)
|
|
53
|
-
return
|
|
54
|
+
return "invalid";
|
|
54
55
|
const evidenceRoot = resolve(input.cwd, ".omo", "evidence");
|
|
55
56
|
const resolvedPath = isAbsolute(receiptPath) ? resolve(receiptPath) : resolve(input.cwd, receiptPath);
|
|
56
57
|
if (!isPathInsideDirectory(resolvedPath, evidenceRoot))
|
|
57
|
-
return
|
|
58
|
+
return "invalid";
|
|
58
59
|
try {
|
|
59
|
-
return
|
|
60
|
+
return getEvidenceFileFailure(resolvedPath, evidenceRoot, input, fs);
|
|
60
61
|
}
|
|
61
62
|
catch (error) {
|
|
62
63
|
if (error instanceof Error)
|
|
63
|
-
return
|
|
64
|
+
return "invalid";
|
|
64
65
|
throw error;
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -68,28 +69,37 @@ function isPathInsideDirectory(filePath, directoryPath) {
|
|
|
68
69
|
const relativePath = relative(directoryPath, filePath);
|
|
69
70
|
return relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
70
71
|
}
|
|
71
|
-
function
|
|
72
|
+
function getEvidenceFileFailure(filePath, evidenceRoot, input, fs) {
|
|
72
73
|
if (!fs.existsSync(filePath))
|
|
73
|
-
return
|
|
74
|
-
const realCwd = realPath(cwd, fs);
|
|
74
|
+
return "invalid";
|
|
75
|
+
const realCwd = realPath(input.cwd, fs);
|
|
75
76
|
const realEvidenceRoot = realPath(evidenceRoot, fs);
|
|
76
77
|
const realFilePath = realPath(filePath, fs);
|
|
77
78
|
if (!isPathInsideDirectory(realEvidenceRoot, realCwd))
|
|
78
|
-
return
|
|
79
|
+
return "invalid";
|
|
79
80
|
if (!isPathInsideDirectory(realFilePath, realEvidenceRoot))
|
|
80
|
-
return
|
|
81
|
-
return isNonEmptyFile(filePath, fs);
|
|
82
|
-
}
|
|
83
|
-
function isNonEmptyFile(filePath, fs) {
|
|
84
|
-
if (!fs.existsSync(filePath))
|
|
85
|
-
return false;
|
|
81
|
+
return "invalid";
|
|
86
82
|
const linkStat = fs.lstatSync?.(filePath) ?? nodeLstatSync(filePath);
|
|
87
83
|
if (linkStat.isSymbolicLink?.() === true)
|
|
88
|
-
return
|
|
84
|
+
return "invalid";
|
|
89
85
|
const stat = fs.statSync(filePath);
|
|
90
|
-
if (stat.
|
|
91
|
-
return
|
|
92
|
-
|
|
86
|
+
if (stat.isFile?.() === false)
|
|
87
|
+
return "invalid";
|
|
88
|
+
if (stat.size <= 0 || fs.readFileSync(filePath, "utf8").trim().length < 40)
|
|
89
|
+
return "placeholder";
|
|
90
|
+
let transcriptStat;
|
|
91
|
+
try {
|
|
92
|
+
transcriptStat = fs.statSync(input.transcript_path);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof Error)
|
|
96
|
+
return null;
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
const transcriptStart = transcriptStat.birthtimeMs ?? transcriptStat.ctimeMs;
|
|
100
|
+
if (transcriptStart !== undefined && (stat.mtimeMs === undefined || stat.mtimeMs < transcriptStart))
|
|
101
|
+
return "stale";
|
|
102
|
+
return null;
|
|
93
103
|
}
|
|
94
104
|
function realPath(path, fs) {
|
|
95
105
|
return fs.realpathSync?.(path) ?? nodeRealpathSync(path);
|
|
@@ -18,6 +18,9 @@ export type StopHookOutput = {
|
|
|
18
18
|
};
|
|
19
19
|
export type FileStat = {
|
|
20
20
|
readonly size: number;
|
|
21
|
+
readonly mtimeMs?: number;
|
|
22
|
+
readonly birthtimeMs?: number;
|
|
23
|
+
readonly ctimeMs?: number;
|
|
21
24
|
readonly isFile?: () => boolean;
|
|
22
25
|
readonly isSymbolicLink?: () => boolean;
|
|
23
26
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
|
|
10
10
|
"timeout": 10,
|
|
11
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
11
|
+
"statusMessage": "(OmO 5.0.0-beta.50) Verifying LazyCodex Executor Evidence"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-lazycodex-executor-verify",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.50",
|
|
4
4
|
"description": "Codex SubagentStop evidence verifier for LazyCodex executor completions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -3,16 +3,19 @@ import { isAbsolute, relative, resolve } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { renderDirective } from "./directive.js";
|
|
5
5
|
import { clearAttemptState, MAX_ATTEMPTS, readAttemptState, writeAttemptState } from "./state.js";
|
|
6
|
-
import type { HookFileSystem, StopHookOutput, SubagentStopInput } from "./types.js";
|
|
6
|
+
import type { FileStat, HookFileSystem, StopHookOutput, SubagentStopInput } from "./types.js";
|
|
7
7
|
import { SUBAGENT_STOP_EVENT } from "./types.js";
|
|
8
8
|
|
|
9
9
|
const RECEIPT_ENFORCED_AGENTS = new Set(["lazycodex-worker-low", "lazycodex-worker-medium", "lazycodex-worker-high"]);
|
|
10
10
|
|
|
11
|
+
type EvidenceReceiptFailure = "invalid" | "placeholder" | "stale" | null;
|
|
12
|
+
|
|
11
13
|
export function runSubagentStopHook(input: unknown, fs: HookFileSystem): string {
|
|
12
14
|
if (!isSubagentStopInput(input)) return "";
|
|
13
15
|
if (!RECEIPT_ENFORCED_AGENTS.has(input.agent_type)) return "";
|
|
14
16
|
if (transcriptHasContextPressureMarker(input.transcript_path, fs)) return "";
|
|
15
|
-
|
|
17
|
+
const receiptFailure = getEvidenceReceiptFailure(input, fs);
|
|
18
|
+
if (receiptFailure === null) {
|
|
16
19
|
clearAttemptState(input.cwd, input.session_id, input.agent_id, fs);
|
|
17
20
|
return "";
|
|
18
21
|
}
|
|
@@ -25,7 +28,7 @@ export function runSubagentStopHook(input: unknown, fs: HookFileSystem): string
|
|
|
25
28
|
writeAttemptState(input.cwd, input.session_id, input.agent_id, { attempts }, fs);
|
|
26
29
|
return JSON.stringify({
|
|
27
30
|
decision: "block",
|
|
28
|
-
reason: renderDirective(attempts, input.last_assistant_message)
|
|
31
|
+
reason: `Evidence receipt rejected: ${receiptFailure}.\n\n${renderDirective(attempts, input.last_assistant_message)}`,
|
|
29
32
|
} satisfies StopHookOutput);
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -49,16 +52,16 @@ function transcriptHasContextPressureMarker(transcriptPath: string, fs: HookFile
|
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
function
|
|
55
|
+
function getEvidenceReceiptFailure(input: SubagentStopInput, fs: HookFileSystem): EvidenceReceiptFailure {
|
|
53
56
|
const receiptPath = extractEvidencePath(input.last_assistant_message);
|
|
54
|
-
if (receiptPath === null) return
|
|
57
|
+
if (receiptPath === null) return "invalid";
|
|
55
58
|
const evidenceRoot = resolve(input.cwd, ".omo", "evidence");
|
|
56
59
|
const resolvedPath = isAbsolute(receiptPath) ? resolve(receiptPath) : resolve(input.cwd, receiptPath);
|
|
57
|
-
if (!isPathInsideDirectory(resolvedPath, evidenceRoot)) return
|
|
60
|
+
if (!isPathInsideDirectory(resolvedPath, evidenceRoot)) return "invalid";
|
|
58
61
|
try {
|
|
59
|
-
return
|
|
62
|
+
return getEvidenceFileFailure(resolvedPath, evidenceRoot, input, fs);
|
|
60
63
|
} catch (error) {
|
|
61
|
-
if (error instanceof Error) return
|
|
64
|
+
if (error instanceof Error) return "invalid";
|
|
62
65
|
throw error;
|
|
63
66
|
}
|
|
64
67
|
}
|
|
@@ -68,28 +71,33 @@ function isPathInsideDirectory(filePath: string, directoryPath: string): boolean
|
|
|
68
71
|
return relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
function
|
|
74
|
+
function getEvidenceFileFailure(
|
|
72
75
|
filePath: string,
|
|
73
76
|
evidenceRoot: string,
|
|
74
|
-
|
|
77
|
+
input: SubagentStopInput,
|
|
75
78
|
fs: HookFileSystem,
|
|
76
|
-
):
|
|
77
|
-
if (!fs.existsSync(filePath)) return
|
|
78
|
-
const realCwd = realPath(cwd, fs);
|
|
79
|
+
): EvidenceReceiptFailure {
|
|
80
|
+
if (!fs.existsSync(filePath)) return "invalid";
|
|
81
|
+
const realCwd = realPath(input.cwd, fs);
|
|
79
82
|
const realEvidenceRoot = realPath(evidenceRoot, fs);
|
|
80
83
|
const realFilePath = realPath(filePath, fs);
|
|
81
|
-
if (!isPathInsideDirectory(realEvidenceRoot, realCwd)) return
|
|
82
|
-
if (!isPathInsideDirectory(realFilePath, realEvidenceRoot)) return
|
|
83
|
-
return isNonEmptyFile(filePath, fs);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function isNonEmptyFile(filePath: string, fs: HookFileSystem): boolean {
|
|
87
|
-
if (!fs.existsSync(filePath)) return false;
|
|
84
|
+
if (!isPathInsideDirectory(realEvidenceRoot, realCwd)) return "invalid";
|
|
85
|
+
if (!isPathInsideDirectory(realFilePath, realEvidenceRoot)) return "invalid";
|
|
88
86
|
const linkStat = fs.lstatSync?.(filePath) ?? nodeLstatSync(filePath);
|
|
89
|
-
if (linkStat.isSymbolicLink?.() === true) return
|
|
87
|
+
if (linkStat.isSymbolicLink?.() === true) return "invalid";
|
|
90
88
|
const stat = fs.statSync(filePath);
|
|
91
|
-
if (stat.
|
|
92
|
-
|
|
89
|
+
if (stat.isFile?.() === false) return "invalid";
|
|
90
|
+
if (stat.size <= 0 || fs.readFileSync(filePath, "utf8").trim().length < 40) return "placeholder";
|
|
91
|
+
let transcriptStat: FileStat;
|
|
92
|
+
try {
|
|
93
|
+
transcriptStat = fs.statSync(input.transcript_path);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error instanceof Error) return null;
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
const transcriptStart = transcriptStat.birthtimeMs ?? transcriptStat.ctimeMs;
|
|
99
|
+
if (transcriptStart !== undefined && (stat.mtimeMs === undefined || stat.mtimeMs < transcriptStart)) return "stale";
|
|
100
|
+
return null;
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
function realPath(path: string, fs: HookFileSystem): string {
|
|
@@ -21,6 +21,9 @@ export type StopHookOutput = {
|
|
|
21
21
|
|
|
22
22
|
export type FileStat = {
|
|
23
23
|
readonly size: number;
|
|
24
|
+
readonly mtimeMs?: number;
|
|
25
|
+
readonly birthtimeMs?: number;
|
|
26
|
+
readonly ctimeMs?: number;
|
|
24
27
|
readonly isFile?: () => boolean;
|
|
25
28
|
readonly isSymbolicLink?: () => boolean;
|
|
26
29
|
};
|
|
@@ -59,7 +59,7 @@ describe("lazycodex executor verify CLI", () => {
|
|
|
59
59
|
const cwd = createWorkspace();
|
|
60
60
|
const artifactPath = join(cwd, ".omo", "evidence", "receipt.txt");
|
|
61
61
|
mkdirSync(join(cwd, ".omo", "evidence"), { recursive: true });
|
|
62
|
-
writeFileSync(artifactPath, "
|
|
62
|
+
writeFileSync(artifactPath, "Command: verify\nExit code: 0\nOutput: all checks passed.\n");
|
|
63
63
|
const payload = JSON.stringify(
|
|
64
64
|
createPayload(cwd, { last_assistant_message: `EVIDENCE_RECORDED: ${artifactPath}` }),
|
|
65
65
|
);
|
package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts
CHANGED
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
writeFileSync,
|
|
13
13
|
} from "node:fs";
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
|
-
import { join } from "node:path";
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
16
16
|
import { platform } from "node:process";
|
|
17
17
|
import { afterEach, describe, expect, it } from "vitest";
|
|
18
18
|
|
|
19
19
|
import { runSubagentStopHook } from "../src/codex-hook.js";
|
|
20
|
-
import type { SubagentStopInput } from "../src/types.js";
|
|
20
|
+
import type { FileStat, HookFileSystem, SubagentStopInput } from "../src/types.js";
|
|
21
21
|
|
|
22
22
|
const cleanupRoots: string[] = [];
|
|
23
23
|
|
|
@@ -71,7 +71,7 @@ describe("lazycodex executor SubagentStop verifier", () => {
|
|
|
71
71
|
runSubagentStopHook(createInput(cwd), nodeFileSystem);
|
|
72
72
|
const artifactPath = join(cwd, ".omo", "evidence", "receipt.txt");
|
|
73
73
|
mkdirSync(join(cwd, ".omo", "evidence"), { recursive: true });
|
|
74
|
-
writeFileSync(artifactPath, "
|
|
74
|
+
writeFileSync(artifactPath, "Command: verify\nExit code: 0\nOutput: all checks passed.\n");
|
|
75
75
|
|
|
76
76
|
// when
|
|
77
77
|
const output = runSubagentStopHook(
|
|
@@ -140,7 +140,7 @@ describe("lazycodex executor SubagentStop verifier", () => {
|
|
|
140
140
|
const outsideReceipt = join(outsideRoot, "receipt.txt");
|
|
141
141
|
const linkPath = join(cwd, ".omo", "evidence", "outside-dir");
|
|
142
142
|
mkdirSync(join(cwd, ".omo", "evidence"), { recursive: true });
|
|
143
|
-
writeFileSync(outsideReceipt, "outside\n");
|
|
143
|
+
writeFileSync(outsideReceipt, "outside evidence root\n".repeat(3));
|
|
144
144
|
symlinkSync(outsideRoot, linkPath, platform === "win32" ? "junction" : "dir");
|
|
145
145
|
|
|
146
146
|
// when
|
|
@@ -186,7 +186,7 @@ describe("lazycodex executor SubagentStop verifier", () => {
|
|
|
186
186
|
// given
|
|
187
187
|
const cwd = createWorkspace();
|
|
188
188
|
mkdirSync(join(cwd, ".omo"), { recursive: true });
|
|
189
|
-
writeFileSync(join(cwd, ".omo", "outside.txt"), "outside\n");
|
|
189
|
+
writeFileSync(join(cwd, ".omo", "outside.txt"), "outside evidence root\n".repeat(3));
|
|
190
190
|
|
|
191
191
|
// when
|
|
192
192
|
const output = runSubagentStopHook(
|
|
@@ -251,6 +251,132 @@ describe("lazycodex executor SubagentStop verifier", () => {
|
|
|
251
251
|
});
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
+
describe("receipt content and freshness", () => {
|
|
255
|
+
it.each(["placeholder evidence\n", "x".repeat(39), ` ${"x".repeat(39)}\n`])(
|
|
256
|
+
"#given a short trimmed receipt %j #when the worker stops #then blocks as placeholder",
|
|
257
|
+
(content) => {
|
|
258
|
+
// given
|
|
259
|
+
const { input, fs } = createMemoryReceipt(content, { mtimeMs: 2_000 }, { birthtimeMs: 1_000 });
|
|
260
|
+
|
|
261
|
+
// when
|
|
262
|
+
const output = runSubagentStopHook(input, fs);
|
|
263
|
+
|
|
264
|
+
// then
|
|
265
|
+
expect(parseBlockOutput(output).reason).toContain("placeholder");
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
it("#given a 200-character receipt older than transcript birth #when the worker stops #then blocks as stale", () => {
|
|
270
|
+
// given
|
|
271
|
+
const { input, fs } = createMemoryReceipt("x".repeat(200), { mtimeMs: 999 }, { birthtimeMs: 1_000 });
|
|
272
|
+
|
|
273
|
+
// when
|
|
274
|
+
const output = runSubagentStopHook(input, fs);
|
|
275
|
+
|
|
276
|
+
// then
|
|
277
|
+
expect(parseBlockOutput(output).reason).toContain("stale");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("#given a fresh 200-character receipt #when transcript birth precedes ctime #then passes using birthtime", () => {
|
|
281
|
+
// given
|
|
282
|
+
const { input, fs } = createMemoryReceipt(
|
|
283
|
+
"x".repeat(200),
|
|
284
|
+
{ mtimeMs: 1_001 },
|
|
285
|
+
{ birthtimeMs: 1_000, ctimeMs: 3_000 },
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// when
|
|
289
|
+
const output = runSubagentStopHook(input, fs);
|
|
290
|
+
|
|
291
|
+
// then
|
|
292
|
+
expect(output).toBe("");
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("#given a 200-character receipt and unstatable transcript #when the worker stops #then skips freshness", () => {
|
|
296
|
+
// given
|
|
297
|
+
const { input, fs } = createMemoryReceipt("x".repeat(200), { mtimeMs: 0 });
|
|
298
|
+
|
|
299
|
+
// when
|
|
300
|
+
const output = runSubagentStopHook({ ...input, transcript_path: "/nonexistent" }, fs);
|
|
301
|
+
|
|
302
|
+
// then
|
|
303
|
+
expect(output).toBe("");
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("#given 40 trimmed characters with mtime equal to transcript birth #when the worker stops #then passes", () => {
|
|
307
|
+
// given
|
|
308
|
+
const { input, fs } = createMemoryReceipt(` ${"x".repeat(40)}\n`, { mtimeMs: 1_000 }, { birthtimeMs: 1_000 });
|
|
309
|
+
|
|
310
|
+
// when
|
|
311
|
+
const output = runSubagentStopHook(input, fs);
|
|
312
|
+
|
|
313
|
+
// then
|
|
314
|
+
expect(output).toBe("");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it.each([999, 1_000])(
|
|
318
|
+
"#given no transcript birthtime and receipt mtime %i #when the worker stops #then uses ctime",
|
|
319
|
+
(mtimeMs) => {
|
|
320
|
+
// given
|
|
321
|
+
const { input, fs } = createMemoryReceipt("x".repeat(200), { mtimeMs }, { ctimeMs: 1_000 });
|
|
322
|
+
|
|
323
|
+
// when
|
|
324
|
+
const output = runSubagentStopHook(input, fs);
|
|
325
|
+
|
|
326
|
+
// then
|
|
327
|
+
if (mtimeMs < 1_000) expect(parseBlockOutput(output).reason).toContain("stale");
|
|
328
|
+
else expect(output).toBe("");
|
|
329
|
+
},
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
function createMemoryReceipt(
|
|
334
|
+
content: string,
|
|
335
|
+
receiptStat: Partial<FileStat>,
|
|
336
|
+
transcriptStat?: Partial<FileStat>,
|
|
337
|
+
): { readonly input: SubagentStopInput; readonly fs: HookFileSystem } {
|
|
338
|
+
const cwd = resolve("receipt-workspace");
|
|
339
|
+
const transcriptPath = join(cwd, "transcript.jsonl");
|
|
340
|
+
const files = new Map<string, { readonly content: string; readonly stat: Partial<FileStat> }>([
|
|
341
|
+
[join(cwd, ".omo", "evidence", "receipt.txt"), { content, stat: receiptStat }],
|
|
342
|
+
]);
|
|
343
|
+
if (transcriptStat !== undefined) files.set(transcriptPath, { content: "", stat: transcriptStat });
|
|
344
|
+
const fileAt = (path: string) => {
|
|
345
|
+
const file = files.get(path);
|
|
346
|
+
if (file === undefined) throw new Error(`ENOENT: ${path}`);
|
|
347
|
+
return file;
|
|
348
|
+
};
|
|
349
|
+
const statAt = (path: string): FileStat => {
|
|
350
|
+
const file = fileAt(path);
|
|
351
|
+
return { size: file.content.length, isFile: () => true, isSymbolicLink: () => false, ...file.stat };
|
|
352
|
+
};
|
|
353
|
+
const fs: HookFileSystem = {
|
|
354
|
+
existsSync: (path) => files.has(path),
|
|
355
|
+
lstatSync: statAt,
|
|
356
|
+
mkdirSync: () => undefined,
|
|
357
|
+
readFileSync: (path) => fileAt(path).content,
|
|
358
|
+
realpathSync: (path) => resolve(path),
|
|
359
|
+
renameSync: (oldPath, newPath) => {
|
|
360
|
+
files.set(newPath, fileAt(oldPath));
|
|
361
|
+
files.delete(oldPath);
|
|
362
|
+
},
|
|
363
|
+
rmSync: (path) => {
|
|
364
|
+
files.delete(path);
|
|
365
|
+
},
|
|
366
|
+
statSync: statAt,
|
|
367
|
+
writeFileSync: (path, data) => {
|
|
368
|
+
files.set(path, { content: data, stat: {} });
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
return {
|
|
372
|
+
input: createInput(cwd, {
|
|
373
|
+
transcript_path: transcriptPath,
|
|
374
|
+
last_assistant_message: "done\nEVIDENCE_RECORDED: .omo/evidence/receipt.txt",
|
|
375
|
+
}),
|
|
376
|
+
fs,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
254
380
|
type BlockOutput = {
|
|
255
381
|
readonly decision: "block";
|
|
256
382
|
readonly reason: string;
|
|
@@ -278,7 +404,7 @@ function createWorkspaceWithParentOutsideReceipt(): { readonly cwd: string } {
|
|
|
278
404
|
const root = createWorkspace();
|
|
279
405
|
const cwd = join(root, "project");
|
|
280
406
|
mkdirSync(cwd, { recursive: true });
|
|
281
|
-
writeFileSync(join(root, "outside.txt"), "outside\n");
|
|
407
|
+
writeFileSync(join(root, "outside.txt"), "outside evidence root\n".repeat(3));
|
|
282
408
|
return { cwd };
|
|
283
409
|
}
|
|
284
410
|
|
|
@@ -291,7 +417,7 @@ function existingReceiptTargetOutsideEvidenceRoot(): string {
|
|
|
291
417
|
if (existsSync("/etc/passwd") && statSync("/etc/passwd").size > 0) return "/etc/passwd";
|
|
292
418
|
const root = createWorkspace();
|
|
293
419
|
const receiptPath = join(root, "outside.txt");
|
|
294
|
-
writeFileSync(receiptPath, "outside\n");
|
|
420
|
+
writeFileSync(receiptPath, "outside evidence root\n".repeat(3));
|
|
295
421
|
return receiptPath;
|
|
296
422
|
}
|
|
297
423
|
|
|
@@ -66,6 +66,7 @@ sync_latest_source openai/codex "$LAZYCODEX_SOURCE_ROOT/openai-codex-source"
|
|
|
66
66
|
- Installed LazyCodex version: the `version` in the installed plugin manifest, discoverable with `find "${CODEX_HOME:-$HOME/.codex}/plugins" -path '*/.codex-plugin/plugin.json'`. Installed plugins live under `$CODEX_HOME/plugins/cache/<marketplace>/<name>/<version>/`.
|
|
67
67
|
- Latest LazyCodex version from `$LAZYCODEX_SOURCE_ROOT/lazycodex-source` (release tags or the version stamped in the repo) and latest Codex release (`gh release view --repo openai/codex`).
|
|
68
68
|
- OS, install method, and `lazycodex` / `lazycodex-ai` bin links resolving (`command -v`).
|
|
69
|
+
- Astra readiness. The LazyCodex catalog default is `gpt-6-astra`, which Codex only knows from codex-cli 0.153.1 onward. First release tag containing the `models.json` change: `rust-v0.153.1` (backport commit `5cc1c94b8e`). Reproduce on a full clone with tags: `git -C <codex-clone> log --format='%h %d' -S gpt-6-astra -- codex-rs/models-manager/models.json`, then `git -C <codex-clone> tag --contains 5cc1c94b8e | sort -V | head -1`; a shallow clone or one without tags returns nothing. Record the installed version from `codex --version`, the root `model` in `$CODEX_HOME/config.toml` (informational only, it doesn't change the verdict), and, when `$CODEX_HOME/models_cache.json` exists, whether it contains `gpt-6-astra` (`grep -c gpt-6-astra "${CODEX_HOME:-$HOME/.codex}/models_cache.json"`). Verdict: PASS when `codex --version` is 0.153.1 or newer and `models_cache.json` is either absent or lists `gpt-6-astra`. WARN when the version is older than 0.153.1, or the cache exists but lacks `gpt-6-astra`; remediation is upgrading Codex (`npm install -g @openai/codex@latest`, or the package manager that installed `codex`), then starting Codex once so `models_cache.json` refreshes.
|
|
69
70
|
3. Check config and wiring against the latest installer, not against assumptions. Read what the current installer under `$LAZYCODEX_SOURCE_ROOT/lazycodex-source` writes (installer sources live in the omo-codex package, e.g. `scripts/install/`), then verify the local equivalents:
|
|
70
71
|
- `$CODEX_HOME/config.toml` exists and parses; LazyCodex-managed entries match what the latest installer would write.
|
|
71
72
|
- Plugin payload present and non-empty: read `.codex-plugin/plugin.json`; when that manifest declares a `hooks` array, validate every direct hook path declared by the manifest; require `hooks/hooks.json` only when the manifest declares it; do not require retired paths such as `components/workflow-selector` or `hooks/user-prompt-submit-selecting-lazycodex-workflow.json` unless the current manifest declares them.
|
|
@@ -96,6 +97,7 @@ sync_latest_source openai/codex "$LAZYCODEX_SOURCE_ROOT/openai-codex-source"
|
|
|
96
97
|
| Check | Verdict | Evidence |
|
|
97
98
|
| --- | --- | --- |
|
|
98
99
|
| Versions current | PASS/WARN/FAIL | [command output or file:line] |
|
|
100
|
+
| Astra readiness | PASS/WARN | [`codex --version` vs the 0.153.1 floor; `gpt-6-astra` present/absent in `$CODEX_HOME/models_cache.json`; configured root `model`] |
|
|
99
101
|
| config.toml integrity | PASS/WARN/FAIL | [evidence] |
|
|
100
102
|
| Plugin payload wiring | PASS/WARN/FAIL | [evidence] |
|
|
101
103
|
| Bin links / aliases | PASS/WARN/FAIL | [evidence] |
|
|
@@ -103,7 +105,7 @@ sync_latest_source openai/codex "$LAZYCODEX_SOURCE_ROOT/openai-codex-source"
|
|
|
103
105
|
| Drift vs latest source | PASS/WARN/FAIL | [evidence, citing `$LAZYCODEX_SOURCE_ROOT/lazycodex-source` or `$LAZYCODEX_SOURCE_ROOT/openai-codex-source` paths] |
|
|
104
106
|
|
|
105
107
|
### Remediations
|
|
106
|
-
1. [Most important fix first: exact command or config edit, and what it resolves.]
|
|
108
|
+
1. [Most important fix first: exact command or config edit, and what it resolves. When Astra readiness is WARN: upgrade Codex to 0.153.1 or newer and relaunch it once so `models_cache.json` picks up `gpt-6-astra`.]
|
|
107
109
|
|
|
108
110
|
### Known Issues Matched
|
|
109
111
|
- [issue URL — or "none found"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "5.0.0-beta.
|
|
4
|
-
"inputDigest": "sha256:
|
|
3
|
+
"version": "5.0.0-beta.50",
|
|
4
|
+
"inputDigest": "sha256:27672c2cd34eb3b44fc226b7e4e9137af0d0acedbb729fe92cdd663602ae6846",
|
|
5
5
|
"outputs": [
|
|
6
6
|
{
|
|
7
7
|
"path": "cli.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "cli.js",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "54d3621c04697495054be69fd6328d7b9044034801b295868b23bd92d344a816"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "codex-hook-cli.d.ts",
|