@cleocode/cleo 2026.10.1 → 2026.10.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.
Files changed (61) hide show
  1. package/bin/cleo.js +17 -1
  2. package/dist/cli/hook-entry.js +372 -0
  3. package/dist/cli/index.js +1774 -329
  4. package/package.json +13 -13
  5. package/studio-dist/client/_app/immutable/chunks/{CMfYgGYJ.js → BJp57kf2.js} +1 -1
  6. package/studio-dist/client/_app/immutable/chunks/{BpRY8_m9.js → Buaay_Q8.js} +1 -1
  7. package/studio-dist/client/_app/immutable/chunks/C3l-lTkq.js +1 -0
  8. package/studio-dist/client/_app/immutable/chunks/CLP4JZvZ.js +3 -0
  9. package/studio-dist/client/_app/immutable/entry/{app.DKqdTuYA.js → app.CczVILch.js} +2 -2
  10. package/studio-dist/client/_app/immutable/entry/start.D7gHmBNS.js +1 -0
  11. package/studio-dist/client/_app/immutable/nodes/{0.BuXCTiZp.js → 0.Zy2IsLEl.js} +1 -1
  12. package/studio-dist/client/_app/immutable/nodes/{1.CsO1BGsz.js → 1.DJN1QI3l.js} +1 -1
  13. package/studio-dist/client/_app/immutable/nodes/{15.Bp-qXNPk.js → 15.B4rwqbHV.js} +1 -1
  14. package/studio-dist/client/_app/immutable/nodes/{16.DMXWbK7I.js → 16.jn-5BG_L.js} +1 -1
  15. package/studio-dist/client/_app/immutable/nodes/{17.CVLdfMFL.js → 17.DnWGC4t9.js} +1 -1
  16. package/studio-dist/client/_app/immutable/nodes/{18.CyQUos9v.js → 18.0zddLZOY.js} +1 -1
  17. package/studio-dist/client/_app/immutable/nodes/{20.Dx3wZ86J.js → 20.DEKHq9Tc.js} +1 -1
  18. package/studio-dist/client/_app/immutable/nodes/{24.CXGl5ZJ3.js → 24.CQB9KP-p.js} +1 -1
  19. package/studio-dist/client/_app/immutable/nodes/25.BaqToZD-.js +39 -0
  20. package/studio-dist/client/_app/immutable/nodes/{26.U1MxbYsk.js → 26.BiE1i4iE.js} +1 -1
  21. package/studio-dist/client/_app/immutable/nodes/{3.CUHmTi6Q.js → 3.BObAOu_-.js} +1 -1
  22. package/studio-dist/client/_app/version.json +1 -1
  23. package/studio-dist/server/chunks/{0-Ban8NQ70.js → 0-BmUoS2yd.js} +3 -3
  24. package/studio-dist/server/chunks/1-CTjj2MYz.js +9 -0
  25. package/studio-dist/server/chunks/{15-C2ukbZuI.js → 15-Dt4kqUxW.js} +3 -3
  26. package/studio-dist/server/chunks/{16-C-gWtKZb.js → 16-kgTLJvbO.js} +3 -3
  27. package/studio-dist/server/chunks/{17-CzQ5BDNx.js → 17-mRYB5141.js} +3 -3
  28. package/studio-dist/server/chunks/{18-Cnqp0uMS.js → 18-BjZ325q5.js} +3 -3
  29. package/studio-dist/server/chunks/{20-D9243OmI.js → 20-DQ2Vrujq.js} +3 -3
  30. package/studio-dist/server/chunks/{24-D-3OyyjO.js → 24-DAeuAfXN.js} +3 -3
  31. package/studio-dist/server/chunks/{25-BC8dXyIT.js → 25-DGCNmzAS.js} +4 -4
  32. package/studio-dist/server/chunks/{26-DIYVHPeE.js → 26-CiN6bbmR.js} +3 -3
  33. package/studio-dist/server/chunks/{3-DDNPJWI0.js → 3-BS2FXYjP.js} +3 -3
  34. package/studio-dist/server/chunks/{_layout.svelte-ouauc7nn.js → _layout.svelte-DJ_UWmGp.js} +4 -4
  35. package/studio-dist/server/chunks/{_page.svelte-ez5VvNrn.js → _page.svelte-BUq8_eQH.js} +3 -3
  36. package/studio-dist/server/chunks/{_page.svelte-ZzSjr8MT.js → _page.svelte-CRnYa4cW.js} +5 -5
  37. package/studio-dist/server/chunks/{_page.svelte-B7CTgxGI.js → _page.svelte-Ca7x-ZvH.js} +4 -4
  38. package/studio-dist/server/chunks/{_page.svelte-BKEo8OSf.js → _page.svelte-CcP_KW3Y.js} +3 -3
  39. package/studio-dist/server/chunks/{_page.svelte-DS8uziG5.js → _page.svelte-Cfv9tDBA.js} +3 -3
  40. package/studio-dist/server/chunks/{_page.svelte-BlIGw3KR.js → _page.svelte-D8dLEr7O.js} +3 -3
  41. package/studio-dist/server/chunks/{_page.svelte-DU-KSkGO.js → _page.svelte-Dk0znswQ.js} +3 -3
  42. package/studio-dist/server/chunks/{_page.svelte-CkagR7NW.js → _page.svelte-J4HjPhfO.js} +3 -3
  43. package/studio-dist/server/chunks/{_page.svelte-Ba45egd6.js → _page.svelte-WR6jUiQE.js} +3 -3
  44. package/studio-dist/server/chunks/{_server.ts-DMqfOwim.js → _server.ts-2BazvYRP.js} +3 -3
  45. package/studio-dist/server/chunks/{_server.ts-CBaXrLT0.js → _server.ts-Bih2-_5O.js} +2 -2
  46. package/studio-dist/server/chunks/{_server.ts-DNL_pHM3.js → _server.ts-C0evMKCk.js} +3 -3
  47. package/studio-dist/server/chunks/{_server.ts-D0rSedle.js → _server.ts-Cr57EKWf.js} +3 -3
  48. package/studio-dist/server/chunks/{_server.ts-DYCIQvnl.js → _server.ts-P4wVVksg.js} +3 -3
  49. package/studio-dist/server/chunks/{client-CM2Un2n3.js → client-Cl295FWH.js} +2 -2
  50. package/studio-dist/server/chunks/{dist-BUqYzm8B.js → dist-CdoCt9zT.js} +92 -27
  51. package/studio-dist/server/chunks/{error.svelte-ZYrc30ps.js → error.svelte-ajn1HNOb.js} +3 -3
  52. package/studio-dist/server/chunks/{http-Dc9ezTZW.js → http-BiQjEmVU.js} +2 -2
  53. package/studio-dist/server/chunks/{internal-BkiUrFap.js → internal-D9MtKHIF.js} +2 -2
  54. package/studio-dist/server/chunks/{stores-C00-wTzq.js → stores-BlknvZ80.js} +2 -2
  55. package/studio-dist/server/index.js +1 -1
  56. package/studio-dist/server/manifest.js +17 -17
  57. package/studio-dist/client/_app/immutable/chunks/BhBqZa2S.js +0 -3
  58. package/studio-dist/client/_app/immutable/chunks/Cltvu8Dg.js +0 -1
  59. package/studio-dist/client/_app/immutable/entry/start.DTRTU1pq.js +0 -1
  60. package/studio-dist/client/_app/immutable/nodes/25.BKYmiCU1.js +0 -39
  61. package/studio-dist/server/chunks/1-CZPXu25_.js +0 -9
package/bin/cleo.js CHANGED
@@ -105,7 +105,23 @@ function heapCapApplied() {
105
105
  return carriesCap((process.env.NODE_OPTIONS ?? '').split(/\s+/));
106
106
  }
107
107
 
108
- if (heapCapApplied()) {
108
+ if (
109
+ args[0] === 'hook' &&
110
+ args[1] === 'heavy-command' &&
111
+ !args.includes('--help') &&
112
+ !args.includes('-h')
113
+ ) {
114
+ // T12983: `cleo hook heavy-command` runs before every shell command an agent
115
+ // issues, so it skips the re-exec and the CLI bootstrap and loads only the
116
+ // hook runtime (`cleo hook --help` still goes through the CLI). Hooks are
117
+ // fail-open: a failure here exits 0 and the agent's command runs unchanged.
118
+ try {
119
+ const { runHookCli } = await import(resolve(__dirname, '../dist/cli/hook-entry.js'));
120
+ process.exitCode = await runHookCli(args.slice(1));
121
+ } catch (err) {
122
+ process.stderr.write(`[cleo hook] skipped: ${err instanceof Error ? err.message : err}\n`);
123
+ }
124
+ } else if (heapCapApplied()) {
109
125
  // Single-process path: signals reach the CLI directly, no child to orphan.
110
126
  await import(cliPath);
111
127
  } else {
@@ -0,0 +1,372 @@
1
+ (() => {
2
+ const _origEmitWarning = process.emitWarning;
3
+ process.emitWarning = function(warning, type, code, ctor) {
4
+ if (typeof warning === 'object' && warning.name === 'ExperimentalWarning' && typeof warning.message === 'string' && /SQLite is an experimental feature/i.test(warning.message)) {
5
+ return;
6
+ }
7
+ if (typeof warning === 'string' && /SQLite is an experimental feature/i.test(warning)) {
8
+ return;
9
+ }
10
+ return _origEmitWarning.call(process, warning, type, code, ctor);
11
+ };
12
+ })();
13
+
14
+ // packages/cleo/src/cli/hook-entry.ts
15
+ import { readdirSync, readFileSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { join } from "node:path";
18
+ var HEAVY_HOOK_PROVIDERS = [
19
+ "claude-code",
20
+ "codex",
21
+ "kimi",
22
+ "opencode"
23
+ ];
24
+ var BASH_DEFAULT_MS = 12e4;
25
+ var BASH_MAX_MS = 6e5;
26
+ var MIN_WAIT_SEC = 30;
27
+ var MAX_WAIT_SEC = 300;
28
+ var DEFAULT_WAIT_SEC = 60;
29
+ var REWRITE_MODES = /* @__PURE__ */ new Set(["bypassPermissions", "auto"]);
30
+ var MAX_STDIN_BYTES = 1024 * 1024;
31
+ async function readProcessStdin() {
32
+ if (process.stdin.isTTY) return "";
33
+ const chunks = [];
34
+ let size = 0;
35
+ for await (const chunk of process.stdin) {
36
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
37
+ size += buf.length;
38
+ if (size > MAX_STDIN_BYTES) return "";
39
+ chunks.push(buf);
40
+ }
41
+ return Buffer.concat(chunks).toString("utf-8");
42
+ }
43
+ function processHookIo() {
44
+ return {
45
+ readStdin: readProcessStdin,
46
+ writeStdout: (text) => process.stdout.write(text),
47
+ // stdout-discipline-allowed: PreToolUse hook protocol, the harness parses this JSON (not LAFS, not rendered output) // stdout-write-allowed: PreToolUse hook protocol output read raw by the harness
48
+ writeStderr: (text) => process.stderr.write(text),
49
+ env: process.env,
50
+ cwd: process.cwd()
51
+ };
52
+ }
53
+ function isRecord(value) {
54
+ return typeof value === "object" && value !== null && !Array.isArray(value);
55
+ }
56
+ function parseHookInput(text) {
57
+ let raw;
58
+ try {
59
+ raw = JSON.parse(text);
60
+ } catch {
61
+ return null;
62
+ }
63
+ if (!isRecord(raw)) return null;
64
+ const toolInput = raw.tool_input;
65
+ if (!isRecord(toolInput) || typeof toolInput.command !== "string") return null;
66
+ const toolName = typeof raw.tool_name === "string" ? raw.tool_name : void 0;
67
+ if (toolName !== void 0 && !/^(bash|shell|exec_command)$/i.test(toolName)) return null;
68
+ const str = (v) => typeof v === "string" ? v : void 0;
69
+ return {
70
+ ...toolName === void 0 ? {} : { tool_name: toolName },
71
+ tool_input: { ...toolInput, command: toolInput.command },
72
+ ...str(raw.cwd) === void 0 ? {} : { cwd: str(raw.cwd) },
73
+ ...str(raw.permission_mode) === void 0 ? {} : { permission_mode: str(raw.permission_mode) }
74
+ };
75
+ }
76
+ function positiveMs(value) {
77
+ const n = value === void 0 ? Number.NaN : Number(value);
78
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : void 0;
79
+ }
80
+ function heavyHookWaitBudget(provider, toolInput, env = {}) {
81
+ if (toolInput.run_in_background === true) return {};
82
+ if (provider !== "claude-code" && provider !== "opencode") {
83
+ return { waitTimeoutSec: DEFAULT_WAIT_SEC };
84
+ }
85
+ const fromEnv = provider === "claude-code";
86
+ const def = (fromEnv ? positiveMs(env.BASH_DEFAULT_TIMEOUT_MS) : void 0) ?? BASH_DEFAULT_MS;
87
+ const max = Math.max(
88
+ (fromEnv ? positiveMs(env.BASH_MAX_TIMEOUT_MS) : void 0) ?? BASH_MAX_MS,
89
+ def
90
+ );
91
+ const asked = typeof toolInput.timeout === "number" && toolInput.timeout > 0 ? toolInput.timeout : def;
92
+ const effective = Math.min(asked, max);
93
+ const room = Math.floor((max - effective) / 1e3);
94
+ const waitTimeoutSec = Math.max(
95
+ MIN_WAIT_SEC,
96
+ Math.min(MAX_WAIT_SEC, Math.round(effective / 1e3), room)
97
+ );
98
+ return { waitTimeoutSec, timeoutMs: Math.min(max, effective + waitTimeoutSec * 1e3) };
99
+ }
100
+ function heavyHookContext(plan, pressure, provider = "claude-code") {
101
+ const lines = [];
102
+ const governed = plan.action === "none" ? "" : plan.segments.map((s) => s.governed).join(" ; ");
103
+ if (plan.action === "rewrite" && provider === "kimi") {
104
+ lines.push(
105
+ `[cleo] Not run: heavy commands share the machine-wide resource budget. Re-run it as: ${plan.command}`
106
+ );
107
+ } else if (plan.action === "rewrite") {
108
+ lines.push(
109
+ `[cleo] Routed heavy work through the machine-wide budget: ${governed}. cleo run passes the command its stdin, stdout, stderr and exit code; exit 75 means it was not admitted before the wait ran out (E_RESOURCE_DEFERRED on stderr lists holders and ways forward).`
110
+ );
111
+ } else if (plan.action === "warn") {
112
+ lines.push(
113
+ `[cleo] Heavy command not rewritten because ${plan.reason}. Run it governed so it shares the machine-wide budget: ${governed}`
114
+ );
115
+ }
116
+ if (pressure !== null) lines.push(pressure);
117
+ return lines.join("\n");
118
+ }
119
+ function demote(plan, reason) {
120
+ return plan.action === "rewrite" ? { action: "warn", reason, segments: plan.segments } : plan;
121
+ }
122
+ function renderHeavyHookAnswer(provider, toolInput, plan, context, timeoutMs) {
123
+ if (plan.action === "none" && context === "") return "";
124
+ const rewrite = plan.action === "rewrite";
125
+ if (provider === "opencode") {
126
+ const answer = {
127
+ ...rewrite ? { command: plan.command } : {},
128
+ ...rewrite && timeoutMs !== void 0 ? { timeout: timeoutMs } : {},
129
+ ...context === "" ? {} : { context }
130
+ };
131
+ return `${JSON.stringify(answer)}
132
+ `;
133
+ }
134
+ if (provider === "kimi") {
135
+ if (!rewrite) return `${context}
136
+ `;
137
+ const deny = {
138
+ hookSpecificOutput: {
139
+ hookEventName: "PreToolUse",
140
+ permissionDecision: "deny",
141
+ permissionDecisionReason: context
142
+ }
143
+ };
144
+ return `${JSON.stringify(deny)}
145
+ `;
146
+ }
147
+ const updatedInput = rewrite ? {
148
+ ...toolInput,
149
+ command: plan.command,
150
+ ...provider === "claude-code" && timeoutMs !== void 0 ? { timeout: timeoutMs } : {}
151
+ } : void 0;
152
+ const output = {
153
+ hookSpecificOutput: {
154
+ hookEventName: "PreToolUse",
155
+ ...rewrite && provider === "codex" ? { permissionDecision: "allow" } : {},
156
+ ...updatedInput === void 0 ? {} : { updatedInput },
157
+ ...context === "" ? {} : { additionalContext: context }
158
+ }
159
+ };
160
+ return `${JSON.stringify(output)}
161
+ `;
162
+ }
163
+ function wordBase(word) {
164
+ return word.split("/").pop() ?? word;
165
+ }
166
+ function heavyRuleWords(argv) {
167
+ const out = [];
168
+ for (const w of argv) {
169
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(w) || w.startsWith("-") || /^\d+$/.test(w)) continue;
170
+ out.push(wordBase(w));
171
+ if (out.length === 4) break;
172
+ }
173
+ return out;
174
+ }
175
+ function ruleWords(pattern) {
176
+ return pattern.split(/[\s:*()]+/).filter((w) => w !== "" && !w.startsWith("-")).map(wordBase);
177
+ }
178
+ function claudeRuleFiles(projectDir, env) {
179
+ const managed = process.platform === "darwin" ? "/Library/Application Support/ClaudeCode/managed-settings.json" : process.platform === "win32" ? "C:\\Program Files\\ClaudeCode\\managed-settings.json" : "/etc/claude-code/managed-settings.json";
180
+ const configDir = env.CLAUDE_CONFIG_DIR || join(env.HOME || homedir(), ".claude");
181
+ return [
182
+ managed,
183
+ join(configDir, "settings.json"),
184
+ join(projectDir, ".claude", "settings.json"),
185
+ join(projectDir, ".claude", "settings.local.json")
186
+ ];
187
+ }
188
+ function claudeGuardedBashRules(files) {
189
+ const patterns = [];
190
+ let unreadable = null;
191
+ for (const file of files) {
192
+ let raw;
193
+ try {
194
+ raw = JSON.parse(readFileSync(file, "utf-8"));
195
+ } catch (err) {
196
+ const code = err.code;
197
+ if (code !== "ENOENT" && code !== "ENOTDIR") unreadable ??= file;
198
+ continue;
199
+ }
200
+ const permissions = isRecord(raw) ? raw.permissions : void 0;
201
+ if (!isRecord(permissions)) continue;
202
+ for (const key of ["deny", "ask"]) {
203
+ const rules = permissions[key];
204
+ if (!Array.isArray(rules)) continue;
205
+ for (const rule of rules) {
206
+ if (typeof rule !== "string") continue;
207
+ const trimmed = rule.trim();
208
+ if (trimmed === "Bash") {
209
+ patterns.push("*");
210
+ continue;
211
+ }
212
+ const match = /^Bash\((.*)\)$/s.exec(trimmed);
213
+ if (match?.[1] !== void 0) patterns.push(match[1]);
214
+ }
215
+ }
216
+ }
217
+ return { patterns, unreadable };
218
+ }
219
+ function codexGuardedWords(projectDir, env) {
220
+ const home = env.CODEX_HOME || join(env.HOME || homedir(), ".codex");
221
+ const out = [];
222
+ for (const dir of [join(home, "rules"), join(projectDir, ".codex", "rules")]) {
223
+ let names;
224
+ try {
225
+ names = readdirSync(dir).filter((n) => n.endsWith(".rules"));
226
+ } catch {
227
+ continue;
228
+ }
229
+ for (const name of names) {
230
+ let text;
231
+ try {
232
+ text = readFileSync(join(dir, name), "utf-8");
233
+ } catch {
234
+ continue;
235
+ }
236
+ if (!/decision\s*=\s*["'](forbidden|prompt)["']/.test(text)) continue;
237
+ for (const m of text.matchAll(/"([^"\\]*)"|'([^'\\]*)'/g)) {
238
+ for (const w of ruleWords(m[1] ?? m[2] ?? "")) out.push(w);
239
+ }
240
+ }
241
+ }
242
+ return out;
243
+ }
244
+ function guardedHeavyCommand(provider, segments, projectDir, env, files = claudeRuleFiles(projectDir, env)) {
245
+ let rules;
246
+ if (provider === "claude-code") {
247
+ const found = claudeGuardedBashRules(files);
248
+ if (found.unreadable !== null) return { kind: "unreadable", file: found.unreadable };
249
+ rules = found.patterns.map(ruleWords);
250
+ if (rules.some((words) => words.length === 0)) return { kind: "all" };
251
+ } else if (provider === "codex") {
252
+ const words = codexGuardedWords(projectDir, env);
253
+ rules = words.length === 0 ? [] : [words];
254
+ } else {
255
+ return null;
256
+ }
257
+ for (const segment of segments) {
258
+ const words = heavyRuleWords(segment.argv);
259
+ const first = words[0];
260
+ if (first === void 0) continue;
261
+ for (const rule of rules) {
262
+ if (provider === "codex") {
263
+ const hit = words.slice(0, 3).find((w) => rule.includes(w));
264
+ if (hit !== void 0) return { kind: "word", word: hit };
265
+ continue;
266
+ }
267
+ const lead = rule[0];
268
+ if (lead !== void 0 && words.includes(lead)) return { kind: "word", word: lead };
269
+ if (rule.includes(first)) return { kind: "word", word: first };
270
+ }
271
+ }
272
+ return null;
273
+ }
274
+ function providerProjectDir(provider, env) {
275
+ return provider === "claude-code" ? env.CLAUDE_PROJECT_DIR || void 0 : void 0;
276
+ }
277
+ async function heavyCommandHook(provider, stdin, io) {
278
+ const envMode = io.env.CLEO_HEAVY_COMMAND_HOOK?.trim().toLowerCase();
279
+ if (envMode === "off") return "";
280
+ const input = parseHookInput(stdin);
281
+ if (input?.tool_input === void 0) return "";
282
+ const core = await import("@cleocode/core/resources/heavy-command.js");
283
+ const cwd = input.cwd ?? io.cwd;
284
+ const budget = heavyHookWaitBudget(provider, input.tool_input, io.env);
285
+ let plan = core.planHeavyCommand(input.tool_input.command, {
286
+ cwd,
287
+ ...budget.waitTimeoutSec === void 0 ? {} : { waitTimeoutSec: budget.waitTimeoutSec }
288
+ });
289
+ if (plan.action === "none") return "";
290
+ const projectRoot = providerProjectDir(provider, io.env) ?? core.heavyHookProjectRoot(cwd);
291
+ const mode = core.resolveHeavyHookMode(
292
+ envMode,
293
+ core.isHeavyCommandHookMode(envMode) ? void 0 : await core.configuredHeavyHookMode(projectRoot)
294
+ );
295
+ if (mode === "off") return "";
296
+ if (mode === "warn") {
297
+ plan = demote(
298
+ plan,
299
+ "the hook is in warn mode (CLEO_HEAVY_COMMAND_HOOK or resources.heavyCommandHook)"
300
+ );
301
+ }
302
+ if (!core.executableOnPath("cleo", io.env.PATH)) plan = demote(plan, "`cleo` is not on PATH");
303
+ if (provider !== "kimi" && !REWRITE_MODES.has(input.permission_mode ?? "")) {
304
+ plan = demote(
305
+ plan,
306
+ `rewriting it would change which permission rules match it, so the hook rewrites only in bypassPermissions or auto mode (this session: ${input.permission_mode ?? "unknown"})`
307
+ );
308
+ }
309
+ if (plan.action === "rewrite") {
310
+ const hit = guardedHeavyCommand(provider, plan.segments, projectRoot, io.env);
311
+ const where = provider === "codex" ? "Codex rules" : "Claude Code settings";
312
+ if (hit?.kind === "word") {
313
+ plan = demote(
314
+ plan,
315
+ `a deny or ask rule in your ${where} names \`${hit.word}\`, and a rewrite would hide the command from it`
316
+ );
317
+ } else if (hit?.kind === "all") {
318
+ plan = demote(
319
+ plan,
320
+ `a deny or ask rule in your ${where} covers every Bash command, and a rewrite would hide the command from it`
321
+ );
322
+ } else if (hit?.kind === "unreadable") {
323
+ plan = demote(
324
+ plan,
325
+ `${hit.file} could not be read or parsed, so the hook cannot tell whether a deny or ask rule names the command`
326
+ );
327
+ }
328
+ }
329
+ const context = heavyHookContext(plan, await core.heavyPressureNotice(), provider);
330
+ return renderHeavyHookAnswer(provider, input.tool_input, plan, context, budget.timeoutMs);
331
+ }
332
+ var USAGE = "usage: cleo hook heavy-command [--provider claude-code|codex|kimi|opencode] < hook-input.json\n";
333
+ async function runHookCli(argv, io = processHookIo()) {
334
+ const [name, ...rest] = argv;
335
+ if (name !== "heavy-command") {
336
+ io.writeStderr(USAGE);
337
+ return 1;
338
+ }
339
+ const flag = rest.findIndex((a) => a === "--provider" || a.startsWith("--provider="));
340
+ const value = flag === -1 ? "claude-code" : rest[flag]?.split("=")[1] ?? rest[flag + 1];
341
+ const provider = HEAVY_HOOK_PROVIDERS.find((p) => p === value);
342
+ if (provider === void 0) {
343
+ io.writeStderr(USAGE);
344
+ return 1;
345
+ }
346
+ try {
347
+ const answer = await heavyCommandHook(provider, await io.readStdin(), io);
348
+ if (answer !== "") io.writeStdout(answer);
349
+ } catch (err) {
350
+ io.writeStderr(
351
+ `[cleo hook] heavy-command skipped: ${err instanceof Error ? err.message : String(err)}
352
+ `
353
+ );
354
+ }
355
+ return 0;
356
+ }
357
+ export {
358
+ HEAVY_HOOK_PROVIDERS,
359
+ claudeGuardedBashRules,
360
+ claudeRuleFiles,
361
+ codexGuardedWords,
362
+ guardedHeavyCommand,
363
+ heavyCommandHook,
364
+ heavyHookContext,
365
+ heavyHookWaitBudget,
366
+ heavyRuleWords,
367
+ parseHookInput,
368
+ processHookIo,
369
+ renderHeavyHookAnswer,
370
+ runHookCli
371
+ };
372
+ //# sourceMappingURL=hook-entry.js.map