feat(omo-codex): block budgeted create_goal calls

This commit is contained in:
YeonGyu-Kim
2026-05-28 14:19:14 +09:00
parent 68848233c4
commit 1d3847a6d3
7 changed files with 219 additions and 1 deletions
@@ -5,8 +5,11 @@ import { Readable, Writable } from "node:stream";
import { describe, expect, it } from "vitest";
import {
applyPreToolUseGoalBudgetGuard,
applyUserPromptUltragoalSteering,
type PreToolUsePayload,
parseUserPromptSubmitPayload,
runPreToolUseGoalBudgetGuardCli,
runUltragoalHookCli,
type UserPromptSubmitPayload,
} from "../src/codex-hook.js";
@@ -50,6 +53,21 @@ function payload(prompt: string, cwd: string): UserPromptSubmitPayload {
return { cwd, hook_event_name: "UserPromptSubmit", prompt, session_id: "s1" };
}
function preToolPayload(toolName: string, toolInput: unknown): PreToolUsePayload {
return {
cwd: "/repo",
hook_event_name: "PreToolUse",
model: "gpt-5.5",
permission_mode: "default",
session_id: "s1",
tool_input: toolInput,
tool_name: toolName,
tool_use_id: "call-1",
transcript_path: null,
turn_id: "turn-1",
};
}
function payloadWithRuntimeEvent(hookEventName: string): UserPromptSubmitPayload {
const input = payload(
'OMO_ULTRAGOAL_STEER: {"kind":"annotate_ledger","source":"user_prompt_submit","evidence":"x","rationale":"y"}',
@@ -185,3 +203,64 @@ describe("runUltragoalHookCli (stdin/stdout integration)", () => {
expect(capture.read()).toBe("");
});
});
describe("applyPreToolUseGoalBudgetGuard", () => {
it("#given create_goal sets token_budget #when PreToolUse runs #then it blocks with unlimited-goal warning", () => {
// given
const input = preToolPayload("create_goal", { objective: "Ship the feature", token_budget: 5000 });
// when
const output = applyPreToolUseGoalBudgetGuard(input);
// then
const parsed = JSON.parse(output);
expect(parsed).toMatchObject({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
},
});
expect(parsed.hookSpecificOutput.permissionDecisionReason).toContain("Do not set token_budget on create_goal");
expect(parsed.hookSpecificOutput.permissionDecisionReason).toContain("unlimited");
});
it("#given create_goal omits token_budget #when PreToolUse runs #then it stays silent", () => {
// given
const input = preToolPayload("create_goal", { objective: "Ship the feature" });
// when
const output = applyPreToolUseGoalBudgetGuard(input);
// then
expect(output).toBe("");
});
it("#given a neighboring tool includes token_budget text #when PreToolUse runs #then it stays silent", () => {
// given
const input = preToolPayload("update_goal", { status: "complete", token_budget: 5000 });
// when
const output = applyPreToolUseGoalBudgetGuard(input);
// then
expect(output).toBe("");
});
});
describe("runPreToolUseGoalBudgetGuardCli", () => {
it("#given Codex PreToolUse stdin with budgeted create_goal #when CLI hook runs #then it writes blocking JSON", async () => {
// given
const stdin = Readable.from([
JSON.stringify(preToolPayload("create_goal", { objective: "Ship", token_budget: 1 })),
]);
const capture = captureStdout();
// when
await runPreToolUseGoalBudgetGuardCli(stdin, capture.stdout);
// then
const parsed = JSON.parse(capture.read());
expect(parsed.hookSpecificOutput.permissionDecision).toBe("deny");
expect(parsed.hookSpecificOutput.permissionDecisionReason).toContain("unlimited");
});
});