@brainervirus/workit-codex 8.36.0 → 8.37.1
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.
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
recordHookRun2
|
|
20
20
|
} from "./workit-hook-w6s3hcyz.js";
|
|
21
|
+
import {
|
|
22
|
+
budgetHooks2
|
|
23
|
+
} from "./workit-hook-b8nrcfzr.js";
|
|
21
24
|
// packages/workit-core/src/hooks/descriptor.ts
|
|
22
25
|
var support = (descriptor, axis) => {
|
|
23
26
|
if (axis.startsWith("event:"))
|
|
@@ -22620,7 +22623,8 @@ function handleHook(input, deps) {
|
|
|
22620
22623
|
const decision = decide(input, deps);
|
|
22621
22624
|
if (deps.descriptor.transport !== "hook-process" || !PRE_TOOL.has(input.event.kind) || decision.kind === "deny" || decision.kind === "ask")
|
|
22622
22625
|
return decision;
|
|
22623
|
-
const delta = standingDelta(input)
|
|
22626
|
+
const delta = [standingDelta(input), deps.budget?.line(input) ?? null].filter(Boolean).join(`
|
|
22627
|
+
`) || null;
|
|
22624
22628
|
if (!delta)
|
|
22625
22629
|
return decision;
|
|
22626
22630
|
return decision.kind === "rewrite" || decision.kind === "update-input" ? { ...decision, text: [decision.text, delta].filter(Boolean).join(`
|
|
@@ -22730,7 +22734,11 @@ function decide(input, deps) {
|
|
|
22730
22734
|
case "subagent.start":
|
|
22731
22735
|
if (workitRole(descriptor, event.agentType) === "judge")
|
|
22732
22736
|
trackJudge(input, event.agentId, true);
|
|
22733
|
-
seedStanding({
|
|
22737
|
+
seedStanding({
|
|
22738
|
+
...input,
|
|
22739
|
+
session: { ...input.session, agentId: event.agentId }
|
|
22740
|
+
});
|
|
22741
|
+
deps.budget?.start(input, event.agentId, event.agentType);
|
|
22734
22742
|
return {
|
|
22735
22743
|
kind: "context",
|
|
22736
22744
|
text: subagentStartText(input, descriptor, event)
|
|
@@ -22743,13 +22751,19 @@ function decide(input, deps) {
|
|
|
22743
22751
|
case "tool.pre":
|
|
22744
22752
|
if (event.skill)
|
|
22745
22753
|
recordSkillLoad(input, event.skill, "tool");
|
|
22746
|
-
if (event.agentInput && input.host === "claude_code")
|
|
22747
|
-
|
|
22754
|
+
if (event.agentInput && input.host === "claude_code") {
|
|
22755
|
+
const spawn = spawnDecision(descriptor, input.cwd, event.agentInput);
|
|
22756
|
+
if (spawn.kind !== "deny")
|
|
22757
|
+
deps.budget?.spawn(input, event.agentInput);
|
|
22758
|
+
return spawn;
|
|
22759
|
+
}
|
|
22748
22760
|
return NONE6;
|
|
22749
22761
|
case "stop":
|
|
22750
22762
|
return usable2(descriptor.events.stop.support) ? stopDecision(input, descriptor) : NONE6;
|
|
22751
22763
|
case "subagent.stop":
|
|
22752
22764
|
trackJudge(input, event.agentId, false);
|
|
22765
|
+
if (event.agentId)
|
|
22766
|
+
deps.budget?.stop(input, event.agentId);
|
|
22753
22767
|
return NONE6;
|
|
22754
22768
|
case "prompt.submit":
|
|
22755
22769
|
return NONE6;
|
|
@@ -22773,7 +22787,8 @@ var dispatchHook = (adapter, raw, env = process.env) => {
|
|
|
22773
22787
|
try {
|
|
22774
22788
|
const decision = handleHook(parsed.input, {
|
|
22775
22789
|
descriptor,
|
|
22776
|
-
addendum: adapter.addendum?.(parsed.input) ?? null
|
|
22790
|
+
addendum: adapter.addendum?.(parsed.input) ?? null,
|
|
22791
|
+
budget: adapter.budget
|
|
22777
22792
|
});
|
|
22778
22793
|
return { ...adapter.render(decision, parsed.native), error: null };
|
|
22779
22794
|
} catch (error) {
|
|
@@ -22906,7 +22921,7 @@ var CLAUDE_CODE_DESCRIPTOR = {
|
|
|
22906
22921
|
"shell.post": { support: "native", native: "PostToolUse" },
|
|
22907
22922
|
"subagent.start": { support: "native", native: "SubagentStart" },
|
|
22908
22923
|
"prompt.submit": { support: "native", native: "UserPromptSubmit" },
|
|
22909
|
-
"subagent.stop": { support: "
|
|
22924
|
+
"subagent.stop": { support: "native", native: "SubagentStop" },
|
|
22910
22925
|
"compact.pre": { support: "none", native: null },
|
|
22911
22926
|
stop: { support: "native", native: "Stop" }
|
|
22912
22927
|
},
|
|
@@ -23810,9 +23825,10 @@ function warnOnSurfaceFallback(env = process.env) {
|
|
|
23810
23825
|
process.stderr.write(`[workit] unrecognized CODEX_INTERNAL_ORIGINATOR_OVERRIDE=${JSON.stringify(override)} — treating surface as codex_cli
|
|
23811
23826
|
`);
|
|
23812
23827
|
}
|
|
23828
|
+
var adapter = { ...codexAdapter, budget: budgetHooks2 };
|
|
23813
23829
|
var runCodexHook = async (stdin = process.stdin) => {
|
|
23814
23830
|
warnOnSurfaceFallback();
|
|
23815
|
-
process.exitCode = await runHookProcess(
|
|
23831
|
+
process.exitCode = await runHookProcess(adapter, stdin, process.stdout, process.stderr, process.env, { startedAt: PROCESS_START });
|
|
23816
23832
|
};
|
|
23817
23833
|
if (false)
|
|
23818
23834
|
;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
gitStoreDir2
|
|
4
|
+
} from "./workit-hook-jy7y0gdx.js";
|
|
5
|
+
|
|
6
|
+
// packages/workit-core/src/hooks/budget-signal.ts
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
var hash = (text) => createHash("sha256").update(text).digest("hex").slice(0, 32);
|
|
11
|
+
var budgetDir = (store) => path.join(store, "budget");
|
|
12
|
+
var agentBase = (store, session, agentId) => path.join(budgetDir(store), hash(`${session}\x00${agentId ?? ""}`));
|
|
13
|
+
var spawnsFile = (store, session) => path.join(budgetDir(store), `spawns-${hash(session)}.jsonl`);
|
|
14
|
+
var spawnBudget = (prompt) => {
|
|
15
|
+
const found = /^TIMEBOX:[^\n]*?\b(\d+)\s+tool calls\b/mu.exec(prompt);
|
|
16
|
+
const n = found ? Number(found[1]) : NaN;
|
|
17
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
18
|
+
};
|
|
19
|
+
var noteSpawnBudget = (cwd, session, type, prompt) => {
|
|
20
|
+
try {
|
|
21
|
+
const store = session ? gitStoreDir2(cwd) : null;
|
|
22
|
+
if (!store)
|
|
23
|
+
return;
|
|
24
|
+
fs.mkdirSync(budgetDir(store), { recursive: true });
|
|
25
|
+
fs.appendFileSync(spawnsFile(store, session), `${JSON.stringify({ type: type ?? "", n: spawnBudget(prompt) })}
|
|
26
|
+
`);
|
|
27
|
+
} catch {}
|
|
28
|
+
};
|
|
29
|
+
var readBudget = (file) => {
|
|
30
|
+
try {
|
|
31
|
+
const { limit, told } = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
32
|
+
return typeof limit === "number" && limit > 0 ? { limit, told: Number(told) || 0 } : null;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var claimSpawnBudget = (cwd, session, agentId, agentType) => {
|
|
38
|
+
try {
|
|
39
|
+
const store = session ? gitStoreDir2(cwd) : null;
|
|
40
|
+
if (!store)
|
|
41
|
+
return null;
|
|
42
|
+
const file = spawnsFile(store, session);
|
|
43
|
+
const entries = fs.readFileSync(file, "utf8").split(`
|
|
44
|
+
`).filter(Boolean).map((line) => JSON.parse(line));
|
|
45
|
+
const at = entries.findIndex((entry) => entry.type === (agentType ?? ""));
|
|
46
|
+
if (at < 0)
|
|
47
|
+
return null;
|
|
48
|
+
const [{ n }] = entries.splice(at, 1);
|
|
49
|
+
fs.writeFileSync(file, entries.map((entry) => `${JSON.stringify(entry)}
|
|
50
|
+
`).join(""));
|
|
51
|
+
if (typeof n !== "number" || n <= 0)
|
|
52
|
+
return null;
|
|
53
|
+
startBudget(store, session, agentId, n);
|
|
54
|
+
return n;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var startBudget = (store, session, agentId, n) => {
|
|
60
|
+
const dir = budgetDir(store);
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
const cutoff = Date.now() - 604800000;
|
|
63
|
+
for (const name of fs.readdirSync(dir))
|
|
64
|
+
try {
|
|
65
|
+
if (fs.statSync(path.join(dir, name)).mtimeMs < cutoff)
|
|
66
|
+
fs.rmSync(path.join(dir, name));
|
|
67
|
+
} catch {}
|
|
68
|
+
const base = agentBase(store, session, agentId);
|
|
69
|
+
fs.writeFileSync(`${base}.json`, JSON.stringify({ limit: n, told: 0 }));
|
|
70
|
+
fs.rmSync(`${base}.calls`, { force: true });
|
|
71
|
+
};
|
|
72
|
+
var tickBudget = (cwd, session, agentId) => {
|
|
73
|
+
try {
|
|
74
|
+
const store = session ? gitStoreDir2(cwd) : null;
|
|
75
|
+
if (!store)
|
|
76
|
+
return false;
|
|
77
|
+
const base = agentBase(store, session, agentId);
|
|
78
|
+
const budget = readBudget(`${base}.json`);
|
|
79
|
+
if (!budget)
|
|
80
|
+
return false;
|
|
81
|
+
fs.appendFileSync(`${base}.calls`, ".");
|
|
82
|
+
return fs.statSync(`${base}.calls`).size >= budget.limit * (budget.told + 1);
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var lineFor = (calls) => `Tool-call budget reached (${calls}): commit your work, write your report, stop.`;
|
|
88
|
+
var reachedOf = (cwd, session, agentId) => {
|
|
89
|
+
const store = session ? gitStoreDir2(cwd) : null;
|
|
90
|
+
const base = store && agentBase(store, session, agentId);
|
|
91
|
+
const budget = base && readBudget(`${base}.json`);
|
|
92
|
+
if (!budget)
|
|
93
|
+
return null;
|
|
94
|
+
return { base, budget, reached: Math.floor(fs.statSync(`${base}.calls`).size / budget.limit) };
|
|
95
|
+
};
|
|
96
|
+
var dropBudget = (cwd, session, agentId) => {
|
|
97
|
+
const store = session ? gitStoreDir2(cwd) : null;
|
|
98
|
+
if (store)
|
|
99
|
+
for (const ext of [".json", ".calls"])
|
|
100
|
+
fs.rmSync(agentBase(store, session, agentId) + ext, { force: true });
|
|
101
|
+
};
|
|
102
|
+
var budgetLine = (cwd, session, agentId) => {
|
|
103
|
+
try {
|
|
104
|
+
const at = reachedOf(cwd, session, agentId);
|
|
105
|
+
if (!at || at.reached <= at.budget.told)
|
|
106
|
+
return null;
|
|
107
|
+
fs.writeFileSync(`${at.base}.json`, JSON.stringify({ ...at.budget, told: at.reached }));
|
|
108
|
+
return lineFor(at.budget.limit * at.reached);
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var CODEX_GATED = new Set(["bash", "unifiedexec", "shell", "applypatch", "edit", "write"]);
|
|
114
|
+
var observeHookBudget2 = (payload) => {
|
|
115
|
+
try {
|
|
116
|
+
const value = JSON.parse(payload);
|
|
117
|
+
if (value.hook_event_name !== "PreToolUse" || typeof value.session_id !== "string")
|
|
118
|
+
return false;
|
|
119
|
+
const cwd = typeof value.cwd === "string" ? value.cwd : ".";
|
|
120
|
+
const agentId = typeof value.agent_id === "string" && value.agent_id.trim() ? value.agent_id : null;
|
|
121
|
+
if (agentId)
|
|
122
|
+
return tickBudget(cwd, value.session_id, agentId);
|
|
123
|
+
const tool = typeof value.tool_name === "string" ? value.tool_name : "";
|
|
124
|
+
const spawn = value.tool_input;
|
|
125
|
+
if (CODEX_GATED.has(tool.toLowerCase().replace(/[_-]/g, "")) || !spawn || typeof spawn !== "object")
|
|
126
|
+
return false;
|
|
127
|
+
const fields = spawn;
|
|
128
|
+
const prompt = Object.values(fields).find((field) => typeof field === "string" && field.includes("TIMEBOX:"));
|
|
129
|
+
const type = [fields.agent_type, fields.subagent_type].find((field) => typeof field === "string");
|
|
130
|
+
if (prompt !== undefined || type !== undefined)
|
|
131
|
+
noteSpawnBudget(cwd, value.session_id, type ?? null, prompt ?? "");
|
|
132
|
+
return false;
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var budgetHooks2 = {
|
|
138
|
+
line: (input) => budgetLine(input.cwd, input.session.id ?? "", input.session.agentId),
|
|
139
|
+
start: (input, agentId, agentType) => void claimSpawnBudget(input.cwd, input.session.id ?? "", agentId, agentType),
|
|
140
|
+
spawn: (input, spawn) => {
|
|
141
|
+
if (!input.session.agentId)
|
|
142
|
+
noteSpawnBudget(input.cwd, input.session.id ?? "", String(spawn.subagent_type || "general-purpose"), String(spawn.prompt ?? ""));
|
|
143
|
+
},
|
|
144
|
+
stop: (input, agentId) => {
|
|
145
|
+
try {
|
|
146
|
+
dropBudget(input.cwd, input.session.id ?? "", agentId);
|
|
147
|
+
} catch {}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export { observeHookBudget2, budgetHooks2 };
|
package/dist/workit-hook.js
CHANGED
|
@@ -37,6 +37,7 @@ if (tooOld) {
|
|
|
37
37
|
var { maybeHeavy, stateDir } = await import("./workit-hook-9pq84bdw.js");
|
|
38
38
|
var { standingPending } = await import("./workit-hook-mk64s4fk.js");
|
|
39
39
|
var { recordHookRun } = await import("./workit-hook-b9ansxvm.js");
|
|
40
|
+
var { observeHookBudget } = await import("./workit-hook-3g6cv3hd.js");
|
|
40
41
|
var payload = "";
|
|
41
42
|
for await (const chunk of process.stdin)
|
|
42
43
|
payload += String(chunk);
|
|
@@ -75,13 +76,13 @@ var quietEvent = () => {
|
|
|
75
76
|
return null;
|
|
76
77
|
}
|
|
77
78
|
};
|
|
78
|
-
var quiet = quietEvent();
|
|
79
|
+
var quiet = observeHookBudget(payload) ? null : quietEvent();
|
|
79
80
|
if (quiet) {
|
|
80
81
|
if (quiet === "PreToolUse")
|
|
81
82
|
recordHookRun(process.env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || process.env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli", quiet);
|
|
82
83
|
process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: quiet } })}
|
|
83
84
|
`);
|
|
84
85
|
} else {
|
|
85
|
-
const { runCodexHook } = await import("./workit-hook-
|
|
86
|
+
const { runCodexHook } = await import("./workit-hook-4hyzn1m0.js");
|
|
86
87
|
await runCodexHook([payload]);
|
|
87
88
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-codex",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.37.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
|
|
6
6
|
"keywords": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"build": "bun scripts/build.ts"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@brainervirus/workit-core": "^8.
|
|
43
|
-
"@brainervirus/workit-mcp": "^8.
|
|
42
|
+
"@brainervirus/workit-core": "^8.37.1",
|
|
43
|
+
"@brainervirus/workit-mcp": "^8.37.1"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=24"
|