omnexx 0.5.0 → 0.7.0

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 (48) hide show
  1. package/README.md +53 -4
  2. package/dist/chat-server-X2QSACYD.js +245 -0
  3. package/dist/chat-server-X2QSACYD.js.map +1 -0
  4. package/dist/chat-settings-DZCYNQF5.js +144 -0
  5. package/dist/chat-settings-DZCYNQF5.js.map +1 -0
  6. package/dist/{chunk-OXDXHUTX.js → chunk-2TKRLH7N.js} +279 -345
  7. package/dist/chunk-2TKRLH7N.js.map +1 -0
  8. package/dist/chunk-7PC4SSYS.js +78 -0
  9. package/dist/chunk-7PC4SSYS.js.map +1 -0
  10. package/dist/chunk-7PNGHZYH.js +87 -0
  11. package/dist/chunk-7PNGHZYH.js.map +1 -0
  12. package/dist/{chunk-IJPR52MO.js → chunk-FC5LAF6U.js} +9 -5
  13. package/dist/{chunk-IJPR52MO.js.map → chunk-FC5LAF6U.js.map} +1 -1
  14. package/dist/chunk-JHJW7UQV.js +148 -0
  15. package/dist/chunk-JHJW7UQV.js.map +1 -0
  16. package/dist/{chunk-CLAS22GZ.js → chunk-M23TQTS6.js} +10 -76
  17. package/dist/chunk-M23TQTS6.js.map +1 -0
  18. package/dist/{chunk-TZ3KO3PA.js → chunk-NPXKRK6O.js} +611 -465
  19. package/dist/chunk-NPXKRK6O.js.map +1 -0
  20. package/dist/chunk-UX4MF6V4.js +70 -0
  21. package/dist/chunk-UX4MF6V4.js.map +1 -0
  22. package/dist/{start-Y5B2FUMR.js → chunk-ZA7YDO2B.js} +321 -1038
  23. package/dist/chunk-ZA7YDO2B.js.map +1 -0
  24. package/dist/{chunk-YMIRAOIB.js → chunk-ZCBVW3DZ.js} +41 -6
  25. package/dist/chunk-ZCBVW3DZ.js.map +1 -0
  26. package/dist/{chunk-Y74QSMFT.js → chunk-ZGB5IZJR.js} +28 -164
  27. package/dist/chunk-ZGB5IZJR.js.map +1 -0
  28. package/dist/cli.js +36 -25
  29. package/dist/cli.js.map +1 -1
  30. package/dist/discovery-2LUVI2SX.js +11 -0
  31. package/dist/discovery-2LUVI2SX.js.map +1 -0
  32. package/dist/model-picker-RVX6A2E3.js +21 -0
  33. package/dist/model-picker-RVX6A2E3.js.map +1 -0
  34. package/dist/{ollama-VFXDRFQ4.js → ollama-ELPMF6WY.js} +7 -4
  35. package/dist/{ollama-VFXDRFQ4.js.map → ollama-ELPMF6WY.js.map} +1 -1
  36. package/dist/{print-KUDY6NOG.js → print-KGSMCQ2Y.js} +6 -4
  37. package/dist/{print-KUDY6NOG.js.map → print-KGSMCQ2Y.js.map} +1 -1
  38. package/dist/session-OKHTHELI.js +27 -0
  39. package/dist/session-OKHTHELI.js.map +1 -0
  40. package/dist/start-LAVPSRH2.js +710 -0
  41. package/dist/start-LAVPSRH2.js.map +1 -0
  42. package/package.json +2 -2
  43. package/dist/chunk-CLAS22GZ.js.map +0 -1
  44. package/dist/chunk-OXDXHUTX.js.map +0 -1
  45. package/dist/chunk-TZ3KO3PA.js.map +0 -1
  46. package/dist/chunk-Y74QSMFT.js.map +0 -1
  47. package/dist/chunk-YMIRAOIB.js.map +0 -1
  48. package/dist/start-Y5B2FUMR.js.map +0 -1
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- println
4
- } from "./chunk-CLAS22GZ.js";
5
2
  import {
6
3
  EventLog,
7
4
  PathJail,
@@ -14,6 +11,7 @@ import {
14
11
  applyRemember,
15
12
  buildCodemap,
16
13
  buildCycleContext,
14
+ cacheHitRate,
17
15
  childrenOf,
18
16
  closeSession,
19
17
  coerceSummary,
@@ -21,10 +19,12 @@ import {
21
19
  costUsd,
22
20
  cycleSummarySchema,
23
21
  dailyPauseThreshold,
22
+ emptyTelemetry,
24
23
  ensureFacts,
25
24
  estimateTokens,
26
25
  factSummary,
27
26
  fail,
27
+ fold,
28
28
  getNode,
29
29
  git,
30
30
  inWrapup,
@@ -73,183 +73,25 @@ import {
73
73
  writeFileAtomic,
74
74
  writeIntentTool,
75
75
  writeJsonAtomic
76
- } from "./chunk-TZ3KO3PA.js";
76
+ } from "./chunk-NPXKRK6O.js";
77
+ import {
78
+ println
79
+ } from "./chunk-7PC4SSYS.js";
77
80
  import {
78
81
  ACTION_HINT,
79
82
  ACTION_ROLE,
80
83
  EXIT,
84
+ formatDuration,
85
+ parseDuration,
86
+ resolvePaths
87
+ } from "./chunk-ZGB5IZJR.js";
88
+ import {
81
89
  LockError,
82
90
  OmnexxError,
83
91
  ProviderError,
84
92
  StateError,
85
- UsageError,
86
- formatDuration,
87
- parseDuration,
88
- resolvePaths
89
- } from "./chunk-Y74QSMFT.js";
90
-
91
- // src/security/sandbox-docker.ts
92
- import { randomBytes } from "crypto";
93
- import { execa } from "execa";
94
- import { quote } from "shell-quote";
95
- function clientEnv(env) {
96
- const out = {};
97
- for (const k of [
98
- "PATH",
99
- "HOME",
100
- "DOCKER_HOST",
101
- "DOCKER_CONFIG",
102
- "DOCKER_CONTEXT",
103
- "DOCKER_CERT_PATH",
104
- "DOCKER_TLS_VERIFY"
105
- ]) {
106
- const v = env[k];
107
- if (v !== void 0) out[k] = v;
108
- }
109
- return out;
110
- }
111
- function runArgs(s) {
112
- const d = s.docker;
113
- const mounts = [
114
- "-v",
115
- `${s.worktree}:${s.worktree}:rw`,
116
- "-v",
117
- `${s.tmpDir}:${s.tmpDir}:rw`,
118
- ...s.gitDir ? ["-v", `${s.gitDir}:${s.gitDir}:ro`] : []
119
- ];
120
- return [
121
- "run",
122
- "-d",
123
- "--rm",
124
- "--init",
125
- "--name",
126
- s.name,
127
- "--label",
128
- "org.omnexx.sandbox=1",
129
- "--user",
130
- `${s.uid}:${s.gid}`,
131
- "--network",
132
- d.network,
133
- "--cpus",
134
- d.cpus,
135
- "--memory",
136
- d.memory,
137
- "--pids-limit",
138
- String(d.pids_limit),
139
- "--cap-drop",
140
- "ALL",
141
- "--security-opt",
142
- "no-new-privileges",
143
- "--read-only",
144
- "--tmpfs",
145
- `/tmp:rw,exec,nosuid,size=${d.tmp_size}`,
146
- // HOME and pid files live on their own owner-only tmpfs, not in the shared /tmp.
147
- "--tmpfs",
148
- `/omnexx:rw,exec,nosuid,size=256m,mode=0700,uid=${s.uid},gid=${s.gid}`,
149
- "-e",
150
- "HOME=/omnexx/home",
151
- "-w",
152
- s.worktree,
153
- ...mounts,
154
- d.image,
155
- "sleep",
156
- "infinity"
157
- ];
158
- }
159
- var DockerSandbox = class {
160
- constructor(spec, env) {
161
- this.spec = spec;
162
- this.env = env;
163
- }
164
- spec;
165
- env;
166
- started = false;
167
- docker(args, timeoutMs = 12e4) {
168
- return execa("docker", args, {
169
- env: clientEnv(this.env),
170
- extendEnv: false,
171
- reject: false,
172
- stdin: "ignore",
173
- timeout: timeoutMs
174
- });
175
- }
176
- async start() {
177
- await this.docker(["rm", "-f", this.spec.name]);
178
- const pull = await this.docker(["image", "inspect", this.spec.docker.image]);
179
- if (pull.exitCode !== 0) {
180
- const p = await this.docker(["pull", this.spec.docker.image], 15 * 6e4);
181
- if (p.exitCode !== 0)
182
- throw new OmnexxError(
183
- "sandbox",
184
- `cannot pull ${this.spec.docker.image}: ${p.stderr.split("\n")[0] ?? ""}`,
185
- "check `docker info` and the [docker] image"
186
- );
187
- }
188
- const r = await this.docker(runArgs(this.spec));
189
- if (r.exitCode !== 0) {
190
- throw new OmnexxError(
191
- "sandbox",
192
- `cannot start the sandbox container: ${r.stderr.split("\n").at(-1) ?? ""}`,
193
- "run `omnexx doctor`; is the docker daemon running?"
194
- );
195
- }
196
- await this.docker([
197
- "exec",
198
- this.spec.name,
199
- "mkdir",
200
- "-p",
201
- "-m",
202
- "700",
203
- "/omnexx/home",
204
- "/omnexx/exec"
205
- ]);
206
- this.started = true;
207
- }
208
- async stop() {
209
- if (!this.started) return;
210
- await this.docker(["rm", "-f", this.spec.name]);
211
- this.started = false;
212
- }
213
- /** Run one command inside the container; on timeout/abort the in-container process group dies too. */
214
- exec = (command, opts) => {
215
- const id = randomBytes(6).toString("hex");
216
- const pidFile = `/omnexx/exec/${id}.pid`;
217
- const inner = `setsid sh -c ${quote([command])} & p=$!; echo $p > ${pidFile}; wait $p; s=$?; rm -f ${pidFile}; exit $s`;
218
- const envArgs = Object.entries(opts.env).filter(([k]) => k !== "PATH" && k !== "HOME").flatMap(([k, v]) => ["-e", `${k}=${v}`]);
219
- const argv = [
220
- "docker",
221
- "exec",
222
- ...opts.stdin !== void 0 ? ["-i"] : [],
223
- "-w",
224
- opts.cwd,
225
- ...envArgs,
226
- this.spec.name,
227
- "sh",
228
- "-c",
229
- inner
230
- ];
231
- return runShell(quote(argv), {
232
- ...opts,
233
- env: clientEnv(this.env),
234
- onKill: async () => {
235
- await this.docker(
236
- ["exec", this.spec.name, "sh", "-c", `[ -f ${pidFile} ] && kill -9 -$(cat ${pidFile})`],
237
- 1e4
238
- );
239
- }
240
- });
241
- };
242
- };
243
- async function dockerAvailable(env) {
244
- const r = await execa("docker", ["info", "--format", "{{.ServerVersion}}"], {
245
- env: clientEnv(env),
246
- extendEnv: false,
247
- reject: false,
248
- stdin: "ignore",
249
- timeout: 1e4
250
- });
251
- return r.exitCode === 0 && r.stdout.trim() !== "";
252
- }
93
+ UsageError
94
+ } from "./chunk-7PNGHZYH.js";
253
95
 
254
96
  // src/cli/commands/control.ts
255
97
  import pc from "picocolors";
@@ -448,7 +290,7 @@ function instruction(mode, plan) {
448
290
  return 'There is no plan yet. Explore the repository. Then call write_intent with what the user actually wants (the goal may be one short sentence: infer the intended build from it and from the repo, and record your assumptions instead of asking). Then call write_plan with milestones, expanding only the first one or two into tasks. M1 is the shortest path to a working, checkable v1; widen and polish in later milestones. Every item in the "done when" list of the intent must map to a task that delivers it, and the checks of that task must run a test proving it (not just look for a file or string); commits are only accepted when every test passes, so a task that adds a test also makes it pass. Before the run may finish, an independent audit compares the result with the "done when" list.';
449
291
  const view = plan ? compactPlanView(plan, void 0) : "";
450
292
  const full = plan ? JSON.stringify({
451
- milestones: plan.nodes.filter((n2) => n2.type === "milestone").map((m) => ({
293
+ milestones: plan.nodes.filter((n) => n.type === "milestone").map((m) => ({
452
294
  id: m.id,
453
295
  title: m.title,
454
296
  status: m.status,
@@ -465,7 +307,7 @@ ${full}
465
307
  Expand milestone ${mode.milestoneId} into leaf tasks (ids ${mode.milestoneId}.T01, ...). Call write_plan with the milestone you changed (milestones and tasks you leave out are kept unchanged).`;
466
308
  }
467
309
  if (mode.kind === "split") {
468
- const t = plan?.nodes.find((n2) => n2.id === mode.taskId);
310
+ const t = plan?.nodes.find((n) => n.id === mode.taskId);
469
311
  const evidence = t ? [...t.approachesTried.map((a) => `- tried: ${a}`), ...t.evidence.slice(-2)].join("\n") : "";
470
312
  return `Current plan:
471
313
  ${view}
@@ -642,7 +484,7 @@ ${dry.alreadyPass.join("\n")}`
642
484
  const codemapText = await readTextOr(run.store.file("codemap.json"), "");
643
485
  const codemap = codemapText ? renderCodemap(JSON.parse(codemapText), run.config.context.repo_map_max_tokens) : "# Codebase map\n(not built)";
644
486
  const notes = renderNotes(await run.store.readNotes());
645
- let n2 = 0;
487
+ let n = 0;
646
488
  const toolCtx = {
647
489
  jail: new PathJail(run.worktree),
648
490
  exec: run.exec,
@@ -656,7 +498,7 @@ ${dry.alreadyPass.join("\n")}`
656
498
  notesMaxTokens: run.config.context.notes_max_tokens,
657
499
  today: new Date(run.clock.now()).toISOString().slice(0, 10),
658
500
  signal: run.abort.signal,
659
- nextCommandId: () => `cmd-plan${run.state.cycle}-${++n2}`,
501
+ nextCommandId: () => `cmd-plan${run.state.cycle}-${++n}`,
660
502
  edited: /* @__PURE__ */ new Set()
661
503
  };
662
504
  toolCtx.subagent = subagentRunner(run, toolCtx);
@@ -714,7 +556,7 @@ ${notes}`, cacheBreakpoint: true }
714
556
  if (written) return [];
715
557
  const cap = run.config.budget.max_tokens_per_cycle;
716
558
  const nudge = PLAN_NUDGES.find(
717
- (n3, i) => i >= nudged && (planTurns >= n3.at || planTokens >= cap * n3.tokenShare)
559
+ (n2, i) => i >= nudged && (planTurns >= n2.at || planTokens >= cap * n2.tokenShare)
718
560
  );
719
561
  if (!nudge) return [];
720
562
  nudged = PLAN_NUDGES.indexOf(nudge) + 1;
@@ -857,16 +699,16 @@ ${f.body}`);
857
699
  function allOf(notifiers) {
858
700
  return {
859
701
  async notify(p) {
860
- await Promise.all(notifiers.map((n2) => n2.notify(p)));
702
+ await Promise.all(notifiers.map((n) => n.notify(p)));
861
703
  }
862
704
  };
863
705
  }
864
706
 
865
707
  // src/git/pr.ts
866
- import { execa as execa2 } from "execa";
708
+ import { execa } from "execa";
867
709
  var MAX_BODY = 6e4;
868
710
  async function gh(cwd, args, input) {
869
- const r = await execa2("gh", args, {
711
+ const r = await execa("gh", args, {
870
712
  cwd,
871
713
  reject: false,
872
714
  ...input !== void 0 ? { input } : { stdin: "ignore" },
@@ -960,7 +802,7 @@ var PROBLEM_KEYS = [
960
802
  "message"
961
803
  ];
962
804
  var FINE = /^(ok|pass(ed)?|confirmed|met|done|resolved|none|fine)$/i;
963
- var str = (v, n2) => typeof v === "string" ? v.trim().slice(0, n2) : "";
805
+ var str = (v, n) => typeof v === "string" ? v.trim().slice(0, n) : "";
964
806
  function coerceReview(input) {
965
807
  if (typeof input !== "object" || input === null) return void 0;
966
808
  const o = input;
@@ -1105,6 +947,169 @@ ${codebase}`;
1105
947
  // src/core/supervisor.ts
1106
948
  import { join as join7 } from "path";
1107
949
 
950
+ // src/security/sandbox-docker.ts
951
+ import { randomBytes } from "crypto";
952
+ import { execa as execa2 } from "execa";
953
+ import { quote } from "shell-quote";
954
+ function clientEnv(env) {
955
+ const out = {};
956
+ for (const k of [
957
+ "PATH",
958
+ "HOME",
959
+ "DOCKER_HOST",
960
+ "DOCKER_CONFIG",
961
+ "DOCKER_CONTEXT",
962
+ "DOCKER_CERT_PATH",
963
+ "DOCKER_TLS_VERIFY"
964
+ ]) {
965
+ const v = env[k];
966
+ if (v !== void 0) out[k] = v;
967
+ }
968
+ return out;
969
+ }
970
+ function runArgs(s) {
971
+ const d = s.docker;
972
+ const mounts = [
973
+ "-v",
974
+ `${s.worktree}:${s.worktree}:rw`,
975
+ "-v",
976
+ `${s.tmpDir}:${s.tmpDir}:rw`,
977
+ ...s.gitDir ? ["-v", `${s.gitDir}:${s.gitDir}:ro`] : []
978
+ ];
979
+ return [
980
+ "run",
981
+ "-d",
982
+ "--rm",
983
+ "--init",
984
+ "--name",
985
+ s.name,
986
+ "--label",
987
+ "org.omnexx.sandbox=1",
988
+ "--user",
989
+ `${s.uid}:${s.gid}`,
990
+ "--network",
991
+ d.network,
992
+ "--cpus",
993
+ d.cpus,
994
+ "--memory",
995
+ d.memory,
996
+ "--pids-limit",
997
+ String(d.pids_limit),
998
+ "--cap-drop",
999
+ "ALL",
1000
+ "--security-opt",
1001
+ "no-new-privileges",
1002
+ "--read-only",
1003
+ "--tmpfs",
1004
+ `/tmp:rw,exec,nosuid,size=${d.tmp_size}`,
1005
+ // HOME and pid files live on their own owner-only tmpfs, not in the shared /tmp.
1006
+ "--tmpfs",
1007
+ `/omnexx:rw,exec,nosuid,size=256m,mode=0700,uid=${s.uid},gid=${s.gid}`,
1008
+ "-e",
1009
+ "HOME=/omnexx/home",
1010
+ "-w",
1011
+ s.worktree,
1012
+ ...mounts,
1013
+ d.image,
1014
+ "sleep",
1015
+ "infinity"
1016
+ ];
1017
+ }
1018
+ var DockerSandbox = class {
1019
+ constructor(spec, env) {
1020
+ this.spec = spec;
1021
+ this.env = env;
1022
+ }
1023
+ spec;
1024
+ env;
1025
+ started = false;
1026
+ docker(args, timeoutMs = 12e4) {
1027
+ return execa2("docker", args, {
1028
+ env: clientEnv(this.env),
1029
+ extendEnv: false,
1030
+ reject: false,
1031
+ stdin: "ignore",
1032
+ timeout: timeoutMs
1033
+ });
1034
+ }
1035
+ async start() {
1036
+ await this.docker(["rm", "-f", this.spec.name]);
1037
+ const pull = await this.docker(["image", "inspect", this.spec.docker.image]);
1038
+ if (pull.exitCode !== 0) {
1039
+ const p = await this.docker(["pull", this.spec.docker.image], 15 * 6e4);
1040
+ if (p.exitCode !== 0)
1041
+ throw new OmnexxError(
1042
+ "sandbox",
1043
+ `cannot pull ${this.spec.docker.image}: ${p.stderr.split("\n")[0] ?? ""}`,
1044
+ "check `docker info` and the [docker] image"
1045
+ );
1046
+ }
1047
+ const r = await this.docker(runArgs(this.spec));
1048
+ if (r.exitCode !== 0) {
1049
+ throw new OmnexxError(
1050
+ "sandbox",
1051
+ `cannot start the sandbox container: ${r.stderr.split("\n").at(-1) ?? ""}`,
1052
+ "run `omnexx doctor`; is the docker daemon running?"
1053
+ );
1054
+ }
1055
+ await this.docker([
1056
+ "exec",
1057
+ this.spec.name,
1058
+ "mkdir",
1059
+ "-p",
1060
+ "-m",
1061
+ "700",
1062
+ "/omnexx/home",
1063
+ "/omnexx/exec"
1064
+ ]);
1065
+ this.started = true;
1066
+ }
1067
+ async stop() {
1068
+ if (!this.started) return;
1069
+ await this.docker(["rm", "-f", this.spec.name]);
1070
+ this.started = false;
1071
+ }
1072
+ /** Run one command inside the container; on timeout/abort the in-container process group dies too. */
1073
+ exec = (command, opts) => {
1074
+ const id = randomBytes(6).toString("hex");
1075
+ const pidFile = `/omnexx/exec/${id}.pid`;
1076
+ const inner = `setsid sh -c ${quote([command])} & p=$!; echo $p > ${pidFile}; wait $p; s=$?; rm -f ${pidFile}; exit $s`;
1077
+ const envArgs = Object.entries(opts.env).filter(([k]) => k !== "PATH" && k !== "HOME").flatMap(([k, v]) => ["-e", `${k}=${v}`]);
1078
+ const argv = [
1079
+ "docker",
1080
+ "exec",
1081
+ ...opts.stdin !== void 0 ? ["-i"] : [],
1082
+ "-w",
1083
+ opts.cwd,
1084
+ ...envArgs,
1085
+ this.spec.name,
1086
+ "sh",
1087
+ "-c",
1088
+ inner
1089
+ ];
1090
+ return runShell(quote(argv), {
1091
+ ...opts,
1092
+ env: clientEnv(this.env),
1093
+ onKill: async () => {
1094
+ await this.docker(
1095
+ ["exec", this.spec.name, "sh", "-c", `[ -f ${pidFile} ] && kill -9 -$(cat ${pidFile})`],
1096
+ 1e4
1097
+ );
1098
+ }
1099
+ });
1100
+ };
1101
+ };
1102
+ async function dockerAvailable(env) {
1103
+ const r = await execa2("docker", ["info", "--format", "{{.ServerVersion}}"], {
1104
+ env: clientEnv(env),
1105
+ extendEnv: false,
1106
+ reject: false,
1107
+ stdin: "ignore",
1108
+ timeout: 1e4
1109
+ });
1110
+ return r.exitCode === 0 && r.stdout.trim() !== "";
1111
+ }
1112
+
1108
1113
  // src/daemon/boot-id.ts
1109
1114
  import { readFile as readFile2 } from "fs/promises";
1110
1115
  import { execa as execa3 } from "execa";
@@ -1250,12 +1255,12 @@ var InCycleWatch = class {
1250
1255
  }
1251
1256
  for (const c of calls) {
1252
1257
  const key = `${c.name} ${JSON.stringify(c.input)}`;
1253
- const n2 = (this.calls.get(key) ?? 0) + 1;
1254
- this.calls.set(key, n2);
1255
- if (n2 >= this.limits.repeatedToolCall)
1258
+ const n = (this.calls.get(key) ?? 0) + 1;
1259
+ this.calls.set(key, n);
1260
+ if (n >= this.limits.repeatedToolCall)
1256
1261
  return {
1257
1262
  signal: "repeated_tool_call",
1258
- detail: `called ${c.name} with the same arguments ${n2} times: ${key.slice(0, 200)}`
1263
+ detail: `called ${c.name} with the same arguments ${n} times: ${key.slice(0, 200)}`
1259
1264
  };
1260
1265
  }
1261
1266
  if (turn - this.lastEditTurn >= this.limits.noEditTurns)
@@ -1338,8 +1343,8 @@ function validateQuestions(questions) {
1338
1343
  if (questions.length < 1 || questions.length > MAX_QUESTIONS)
1339
1344
  return `need 1-${MAX_QUESTIONS} questions`;
1340
1345
  for (const q of questions) {
1341
- const n2 = q.type === "choice" ? q.options.length : q.type === "score" ? q.levels.length : 2;
1342
- if (n2 < 2 || n2 > MAX_OPTIONS) return `${q.id}: needs 2-${MAX_OPTIONS} options`;
1346
+ const n = q.type === "choice" ? q.options.length : q.type === "score" ? q.levels.length : 2;
1347
+ if (n < 2 || n > MAX_OPTIONS) return `${q.id}: needs 2-${MAX_OPTIONS} options`;
1343
1348
  }
1344
1349
  return void 0;
1345
1350
  }
@@ -1365,7 +1370,7 @@ function answersMatch(questions, answers) {
1365
1370
 
1366
1371
  // src/judge/state-summary.ts
1367
1372
  var bytes = (v) => Buffer.byteLength(JSON.stringify(v));
1368
- var clipText = (s, n2) => s.length > n2 ? `${s.slice(0, n2)}\u2026` : s;
1373
+ var clipText = (s, n) => s.length > n ? `${s.slice(0, n)}\u2026` : s;
1369
1374
  function fitSummary(input, maxBytes = MAX_STATE_BYTES) {
1370
1375
  const s = structuredClone(input);
1371
1376
  s.goal = clipText(s.goal, 2e3);
@@ -1799,7 +1804,7 @@ async function settleMilestones(run) {
1799
1804
  m.doneAtCycle = run.state.cycle;
1800
1805
  const tag = checkpointTag(run.state.runId, m.id);
1801
1806
  await tagCheckpoint(run.worktree, tag, run.state.lastGreen);
1802
- const tests = run.state.baseline ? Object.values(run.state.baseline).reduce((n2, g) => n2 + (g.tests?.passed ?? 0), 0) : void 0;
1807
+ const tests = run.state.baseline ? Object.values(run.state.baseline).reduce((n, g) => n + (g.tests?.passed ?? 0), 0) : void 0;
1803
1808
  run.state.checkpoints.push({
1804
1809
  milestoneId: m.id,
1805
1810
  sha: run.state.lastGreen,
@@ -1858,11 +1863,11 @@ async function consolidateNotes(run) {
1858
1863
  );
1859
1864
  if (!parsed.success) return false;
1860
1865
  const today = new Date(run.clock.now()).toISOString().slice(0, 10);
1861
- const next = parsed.data.notes.map((n2) => ({
1862
- ...n2,
1863
- date: notes.find((o) => o.id === n2.id)?.date ?? today
1866
+ const next = parsed.data.notes.map((n) => ({
1867
+ ...n,
1868
+ date: notes.find((o) => o.id === n.id)?.date ?? today
1864
1869
  }));
1865
- const keepsFacts = notes.filter((n2) => n2.type === "env" || n2.type === "command").every((f) => next.some((n2) => n2.text === f.text));
1870
+ const keepsFacts = notes.filter((n) => n.type === "env" || n.type === "command").every((f) => next.some((n) => n.text === f.text));
1866
1871
  const shorter = renderNotes(next).length < text.length;
1867
1872
  run.events.emit("notes.consolidation", {
1868
1873
  applied: keepsFacts && shorter,
@@ -2237,7 +2242,7 @@ async function recordFlaky(run, task, flaky) {
2237
2242
  for (const f of flaky) {
2238
2243
  run.events.emit("verify.flaky", { task: task.id, gate: f.gate, ids: f.ids });
2239
2244
  for (const id of f.ids) {
2240
- if (notes.some((n2) => n2.type === "flaky" && n2.text.includes(id))) continue;
2245
+ if (notes.some((n) => n.type === "flaky" && n.text.includes(id))) continue;
2241
2246
  const r = applyRemember(
2242
2247
  notes,
2243
2248
  {
@@ -2266,7 +2271,7 @@ async function recordAntiCheatLessons(run, violations) {
2266
2271
  let changed = false;
2267
2272
  for (const rule of new Set(violations.map((v) => v.rule))) {
2268
2273
  const text = ANTI_CHEAT_LESSON[rule];
2269
- if (notes.some((n2) => n2.text === text)) continue;
2274
+ if (notes.some((n) => n.text === text)) continue;
2270
2275
  const r = applyRemember(
2271
2276
  notes,
2272
2277
  { action: "add", type: "pitfall", text },
@@ -2326,7 +2331,7 @@ function contextBreakdown(ctx) {
2326
2331
  return out;
2327
2332
  }
2328
2333
  function toolContext(run, edited) {
2329
- let n2 = 0;
2334
+ let n = 0;
2330
2335
  const { judge } = run;
2331
2336
  const ctx = {
2332
2337
  jail: new PathJail(run.worktree),
@@ -2341,7 +2346,7 @@ function toolContext(run, edited) {
2341
2346
  notesMaxTokens: run.config.context.notes_max_tokens,
2342
2347
  today: new Date(run.clock.now()).toISOString().slice(0, 10),
2343
2348
  signal: run.abort.signal,
2344
- nextCommandId: () => `cmd-${run.state.cycle}-${++n2}`,
2349
+ nextCommandId: () => `cmd-${run.state.cycle}-${++n}`,
2345
2350
  edited,
2346
2351
  reads: /* @__PURE__ */ new Map(),
2347
2352
  // Advisory, log-only, never awaited by the tool, skipped while the breaker is open.
@@ -2394,7 +2399,7 @@ async function stepAct(run) {
2394
2399
  const task = getNode(plan, run.state.taskId ?? "");
2395
2400
  await prepareWorktree(run);
2396
2401
  const shared = new Set(
2397
- plan.nodes.filter((n2) => n2.id !== task.id).flatMap((n2) => n2.checks.map((c) => c.trim()))
2402
+ plan.nodes.filter((n) => n.id !== task.id).flatMap((n) => n.checks.map((c) => c.trim()))
2398
2403
  );
2399
2404
  const ownCheck = task.checks.some((c) => !shared.has(c.trim()));
2400
2405
  if (task.checks.length && task.attempts === 0 && run.state.acceptedCommits > 0 && ownCheck) {
@@ -2447,7 +2452,7 @@ async function stepAct(run) {
2447
2452
  });
2448
2453
  run.events.emit("cycle.context", {
2449
2454
  task: task.id,
2450
- prefixBytes: ctx.system.reduce((n2, b) => n2 + b.text.length, 0),
2455
+ prefixBytes: ctx.system.reduce((n, b) => n + b.text.length, 0),
2451
2456
  stateBytes: JSON.stringify(ctx.first).length,
2452
2457
  tokens: contextBreakdown(ctx),
2453
2458
  memory: memory.stats()
@@ -2544,8 +2549,8 @@ async function stepVerify(run) {
2544
2549
  const { changes: changes2, patch, treeHash } = await workingTreeDiff(run.worktree, run.state.lastGreen);
2545
2550
  const diffStats = {
2546
2551
  files: changes2.length,
2547
- added: changes2.reduce((n2, c) => n2 + c.added, 0),
2548
- removed: changes2.reduce((n2, c) => n2 + c.removed, 0)
2552
+ added: changes2.reduce((n, c) => n + c.added, 0),
2553
+ removed: changes2.reduce((n, c) => n + c.removed, 0)
2549
2554
  };
2550
2555
  const reasons = [];
2551
2556
  const evidence = [];
@@ -2585,7 +2590,7 @@ ${c.output}`);
2585
2590
  for (const v of verdicts) if (!v.pass) reasons.push(`gate ${v.gate}: ${v.reason ?? "failed"}`);
2586
2591
  const failText = renderFailures(results, verdicts);
2587
2592
  if (failText) evidence.push(failText);
2588
- testsPassed = results.reduce((n2, r) => n2 + (r.tests?.passed ?? 0), 0) || void 0;
2593
+ testsPassed = results.reduce((n, r) => n + (r.tests?.passed ?? 0), 0) || void 0;
2589
2594
  const cheats = antiCheat({
2590
2595
  changes: changes2,
2591
2596
  patch,
@@ -2754,6 +2759,7 @@ async function stepCommit(run) {
2754
2759
  }
2755
2760
  run.state.lastProgressAt = run.clock.now();
2756
2761
  run.state.lastProgressCycle = run.state.cycle;
2762
+ run.state.recoveries = 0;
2757
2763
  await run.setPhase("record");
2758
2764
  }
2759
2765
  async function stepRollback(run) {
@@ -2917,7 +2923,7 @@ var flakyIds = (events) => {
2917
2923
  );
2918
2924
  return ids.size ? `${ids.size} (${[...ids].slice(0, 10).join(", ")})` : "none";
2919
2925
  };
2920
- var usd = (n2) => `$${n2.toFixed(2)}`;
2926
+ var usd = (n) => `$${n.toFixed(2)}`;
2921
2927
  function suggestions(events) {
2922
2928
  const seen = /* @__PURE__ */ new Set();
2923
2929
  const out = [];
@@ -2976,12 +2982,12 @@ function deltas(state) {
2976
2982
  const after = state.baseline ?? {};
2977
2983
  const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort();
2978
2984
  if (!names.length) return ["No gates were configured."];
2979
- const rows = names.map((n2) => {
2980
- const b = before[n2];
2981
- const a = after[n2];
2985
+ const rows = names.map((n) => {
2986
+ const b = before[n];
2987
+ const a = after[n];
2982
2988
  const fixed = b && a ? b.failureIds.filter((id) => !a.failureIds.includes(id)).length : 0;
2983
2989
  const tests = (g) => g?.tests ? `${g.tests.passed}/${g.tests.total}` : "-";
2984
- return `| ${n2} | ${b?.failureIds.length ?? "-"} | ${a?.failureIds.length ?? "-"} | ${fixed} | ${tests(b)} | ${tests(a)} |`;
2990
+ return `| ${n} | ${b?.failureIds.length ?? "-"} | ${a?.failureIds.length ?? "-"} | ${fixed} | ${tests(b)} | ${tests(a)} |`;
2985
2991
  });
2986
2992
  return [
2987
2993
  "Baseline is the starting commit; final is `lastGreen`.",
@@ -2998,7 +3004,7 @@ async function writeReport(store, state, plan, now) {
2998
3004
  const input = s.tokens.uncached + s.tokens.cacheWrite + s.tokens.cacheRead;
2999
3005
  const stuck = events.filter((e) => e.type === "stuck.signal");
3000
3006
  const rungs = events.filter((e) => e.type === "ladder.rung");
3001
- const parked = plan?.nodes.filter((n2) => n2.status === "parked") ?? [];
3007
+ const parked = plan?.nodes.filter((n) => n.status === "parked") ?? [];
3002
3008
  const workers = events.filter((e) => e.type === "worker.result");
3003
3009
  const assumptions = intentAssumptions(await readIntent(store));
3004
3010
  const lines = [
@@ -3049,7 +3055,7 @@ async function writeReport(store, state, plan, now) {
3049
3055
  "",
3050
3056
  `## ${REPORT_SECTIONS[6]}`,
3051
3057
  "",
3052
- ...parked.length ? parked.map((n2) => `- ${n2.id} ${n2.title}: ${n2.parkedReason ?? ""}`) : ["- Nothing parked."],
3058
+ ...parked.length ? parked.map((n) => `- ${n.id} ${n.title}: ${n.parkedReason ?? ""}`) : ["- Nothing parked."],
3053
3059
  ...state.status === "needs-human" ? [`- The run stopped for you: ${state.statusReason ?? ""}`] : [],
3054
3060
  ...suggestions(events),
3055
3061
  ...assumptions.length ? [
@@ -3239,9 +3245,9 @@ function probs(v) {
3239
3245
  if (typeof v !== "object" || v === null) return void 0;
3240
3246
  const out = {};
3241
3247
  for (const [k, x] of Object.entries(v)) {
3242
- const n2 = num(x);
3243
- if (n2 === void 0) return void 0;
3244
- out[k] = n2;
3248
+ const n = num(x);
3249
+ if (n === void 0) return void 0;
3250
+ out[k] = n;
3245
3251
  }
3246
3252
  return out;
3247
3253
  }
@@ -3976,7 +3982,7 @@ function splitDepth(plan, id) {
3976
3982
  let depth = 0;
3977
3983
  let cur = id;
3978
3984
  for (; ; ) {
3979
- const parent = plan.nodes.find((n2) => n2.splitInto.includes(cur));
3985
+ const parent = plan.nodes.find((n) => n.splitInto.includes(cur));
3980
3986
  if (!parent) return depth;
3981
3987
  depth++;
3982
3988
  cur = parent.id;
@@ -4156,7 +4162,7 @@ var Supervisor = class {
4156
4162
  async splitTask(taskId, reason) {
4157
4163
  const r = this.run;
4158
4164
  await r.savePlan();
4159
- const before = new Set(r.requirePlan().nodes.map((n2) => n2.id));
4165
+ const before = new Set(r.requirePlan().nodes.map((n) => n.id));
4160
4166
  const parentId = getNode(r.requirePlan(), taskId).parentId;
4161
4167
  try {
4162
4168
  await runPlanner(r, { kind: "split", taskId, reason });
@@ -4166,15 +4172,15 @@ var Supervisor = class {
4166
4172
  return false;
4167
4173
  }
4168
4174
  const plan = r.requirePlan();
4169
- const fresh = plan.nodes.filter((n2) => n2.type === "task" && n2.parentId === parentId && !before.has(n2.id)).map((n2) => n2.id);
4175
+ const fresh = plan.nodes.filter((n) => n.type === "task" && n.parentId === parentId && !before.has(n.id)).map((n) => n.id);
4170
4176
  if (!fresh.length) return false;
4171
4177
  const task = getNode(plan, taskId);
4172
4178
  task.splitInto = fresh;
4173
4179
  task.status = "parked";
4174
4180
  task.parkedReason = `split into ${fresh.join(", ")}`;
4175
- for (const n2 of plan.nodes) {
4176
- if (n2.dependsOn.includes(taskId) && !fresh.includes(n2.id)) {
4177
- n2.dependsOn = [...n2.dependsOn.filter((d) => d !== taskId), ...fresh];
4181
+ for (const n of plan.nodes) {
4182
+ if (n.dependsOn.includes(taskId) && !fresh.includes(n.id)) {
4183
+ n.dependsOn = [...n.dependsOn.filter((d) => d !== taskId), ...fresh];
4178
4184
  }
4179
4185
  }
4180
4186
  await r.savePlan();
@@ -4186,12 +4192,12 @@ var Supervisor = class {
4186
4192
  const r = this.run;
4187
4193
  const plan = r.requirePlan();
4188
4194
  let changed = false;
4189
- for (const n2 of plan.nodes) {
4190
- if (n2.status === "parked" && n2.splitInto.length && n2.splitInto.every((id) => getNode(plan, id).status === "done")) {
4191
- n2.status = "done";
4192
- n2.doneAtCycle = r.state.cycle;
4193
- n2.parkedReason = void 0;
4194
- r.events.emit("task.done", { task: n2.id, via: "split" });
4195
+ for (const n of plan.nodes) {
4196
+ if (n.status === "parked" && n.splitInto.length && n.splitInto.every((id) => getNode(plan, id).status === "done")) {
4197
+ n.status = "done";
4198
+ n.doneAtCycle = r.state.cycle;
4199
+ n.parkedReason = void 0;
4200
+ r.events.emit("task.done", { task: n.id, via: "split" });
4195
4201
  changed = true;
4196
4202
  }
4197
4203
  }
@@ -4325,6 +4331,7 @@ var Supervisor = class {
4325
4331
  const sinceMs = r.clock.now() - (r.state.lastProgressAt ?? r.state.startedAt);
4326
4332
  if (sinceCycles >= r.config.stuck.no_progress_cycles || sinceMs >= r.config.stuck.no_progress_hours * 36e5) {
4327
4333
  r.events.emit("stuck.signal", { signal: "no_progress", cycles: sinceCycles, ms: sinceMs });
4334
+ if (await this.recoverNoProgress(sinceCycles)) return void 0;
4328
4335
  return { status: "needs-human", reason: `no accepted commit for ${sinceCycles} cycles` };
4329
4336
  }
4330
4337
  if (r.state.noChecks && r.state.cycle >= 1)
@@ -4466,20 +4473,49 @@ ${clipDiff(diff, cfg.max_diff_chars * 2)}`
4466
4473
  r.state.idleRounds = found ? 0 : r.state.idleRounds + 1;
4467
4474
  if (!found) r.events.emit("autonomous.idle", { round, idle: r.state.idleRounds });
4468
4475
  }
4476
+ /**
4477
+ * Autonomous mode has nobody to ask when nothing gets accepted for a while: park the work in
4478
+ * progress (it is listed in the report) and let the run move on to other tasks or the next
4479
+ * improvement round. Only `max_idle_rounds` recoveries in a row; an accepted commit resets it.
4480
+ */
4481
+ async recoverNoProgress(sinceCycles) {
4482
+ const r = this.run;
4483
+ if (!r.config.autonomous.enabled) return false;
4484
+ if (r.state.recoveries >= r.config.autonomous.max_idle_rounds) return false;
4485
+ const plan = r.requirePlan();
4486
+ const stuck = plan.nodes.filter(
4487
+ (n) => n.type === "task" && (n.status === "doing" || n.id === r.state.taskId) && n.status !== "done"
4488
+ );
4489
+ for (const n of stuck) {
4490
+ n.status = "parked";
4491
+ n.parkedReason = `autonomous: no progress for ${sinceCycles} cycles; moved on`;
4492
+ }
4493
+ r.state.recoveries++;
4494
+ r.state.lastProgressCycle = r.state.cycle;
4495
+ r.state.lastProgressAt = r.clock.now();
4496
+ await r.savePlan();
4497
+ await r.save();
4498
+ r.events.emit("autonomous.recover", {
4499
+ parked: stuck.map((n) => n.id),
4500
+ recovery: r.state.recoveries,
4501
+ cycles: sinceCycles
4502
+ });
4503
+ return true;
4504
+ }
4469
4505
  /**
4470
4506
  * Autonomous mode has nobody to ask: work that can't proceed because something it needs was
4471
4507
  * parked is parked too, so the run moves on to the next improvement round. The report lists it.
4472
4508
  */
4473
4509
  async parkBlocked() {
4474
4510
  const r = this.run;
4475
- const blocked = r.requirePlan().nodes.filter((n2) => n2.status !== "done" && n2.status !== "parked");
4511
+ const blocked = r.requirePlan().nodes.filter((n) => n.status !== "done" && n.status !== "parked");
4476
4512
  if (!blocked.length) return false;
4477
- for (const n2 of blocked) {
4478
- n2.status = "parked";
4479
- n2.parkedReason = "autonomous: blocked by parked work";
4513
+ for (const n of blocked) {
4514
+ n.status = "parked";
4515
+ n.parkedReason = "autonomous: blocked by parked work";
4480
4516
  }
4481
4517
  await r.savePlan();
4482
- r.events.emit("autonomous.skipped", { nodes: blocked.map((n2) => n2.id) });
4518
+ r.events.emit("autonomous.skipped", { nodes: blocked.map((n) => n.id) });
4483
4519
  return true;
4484
4520
  }
4485
4521
  /** Milestones, rolling-wave expansion, and the end-of-plan decision. Returns a task id or an outcome. */
@@ -4515,9 +4551,9 @@ ${clipDiff(diff, cfg.max_diff_chars * 2)}`
4515
4551
  } else {
4516
4552
  m.status = "parked";
4517
4553
  m.parkedReason = "the planner could not expand it into tasks";
4518
- const released = r.requirePlan().nodes.filter((n2) => n2.dependsOn.includes(m.id)).map((n2) => {
4519
- n2.dependsOn = n2.dependsOn.filter((d) => d !== m.id);
4520
- return n2.id;
4554
+ const released = r.requirePlan().nodes.filter((n) => n.dependsOn.includes(m.id)).map((n) => {
4555
+ n.dependsOn = n.dependsOn.filter((d) => d !== m.id);
4556
+ return n.id;
4521
4557
  });
4522
4558
  if (released.length) r.events.emit("milestone.released", { parked: m.id, released });
4523
4559
  }
@@ -4527,10 +4563,10 @@ ${clipDiff(diff, cfg.max_diff_chars * 2)}`
4527
4563
  }
4528
4564
  const counts = planCounts(plan);
4529
4565
  const openMilestones = plan.nodes.filter(
4530
- (n2) => n2.type === "milestone" && n2.status !== "done" && n2.status !== "parked"
4566
+ (n) => n.type === "milestone" && n.status !== "done" && n.status !== "parked"
4531
4567
  );
4532
4568
  const auto = r.config.autonomous.enabled;
4533
- if (counts.todo === 0 && openMilestones.length === 0 && (auto || plan.nodes.every((n2) => n2.status !== "parked"))) {
4569
+ if (counts.todo === 0 && openMilestones.length === 0 && (auto || plan.nodes.every((n) => n.status !== "parked"))) {
4534
4570
  if (await this.planAudit()) return this.select();
4535
4571
  if (await this.planBeyond()) return this.select();
4536
4572
  await this.finalVerify();
@@ -4541,7 +4577,7 @@ ${clipDiff(diff, cfg.max_diff_chars * 2)}`
4541
4577
  };
4542
4578
  }
4543
4579
  if (r.config.autonomous.enabled && await this.parkBlocked()) return this.select();
4544
- const parked = plan.nodes.filter((n2) => n2.status === "parked").length;
4580
+ const parked = plan.nodes.filter((n) => n.status === "parked").length;
4545
4581
  r.events.emit("ladder.rung", { rung: "stop_and_ask", parked });
4546
4582
  return {
4547
4583
  status: "needs-human",
@@ -4934,112 +4970,14 @@ function banner(io, columns = 80, version) {
4934
4970
  return ["", mark, "", `${b.cyan("$ omnexx")}${ver}`, `> ${TAGLINE}`, ""].join("\n");
4935
4971
  }
4936
4972
 
4937
- // src/telemetry/aggregate.ts
4938
- function emptyTelemetry() {
4939
- return {
4940
- cycle: 0,
4941
- turns: 0,
4942
- tokens: { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 },
4943
- usd: 0,
4944
- toolCalls: 0,
4945
- toolErrors: 0,
4946
- commits: 0,
4947
- rejects: 0,
4948
- rollbacks: 0,
4949
- gateRuns: 0,
4950
- gatePasses: 0,
4951
- compactions: 0,
4952
- failovers: 0,
4953
- quotaOut: [],
4954
- stuck: 0,
4955
- milestonesDone: 0
4956
- };
4957
- }
4958
- var n = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
4959
- function fold(t, e) {
4960
- t.startedAt ??= e.ts;
4961
- t.lastAt = e.ts;
4962
- t.cycle = Math.max(t.cycle, e.cycle);
4963
- switch (e.type) {
4964
- case "cycle.start":
4965
- if (typeof e.task === "string") t.task = e.task;
4966
- break;
4967
- case "phase":
4968
- if (typeof e.phase === "string") t.phase = e.phase;
4969
- break;
4970
- case "turn": {
4971
- const k = e.tokens ?? {};
4972
- t.turns++;
4973
- t.tokens.input += n(k.uncached) + n(k.cacheWrite) + n(k.cacheRead);
4974
- t.tokens.cacheRead += n(k.cacheRead);
4975
- t.tokens.cacheWrite += n(k.cacheWrite);
4976
- t.tokens.output += n(k.output);
4977
- t.usd += n(e.usd);
4978
- if (typeof e.model === "string") t.model = e.model;
4979
- if (typeof e.provider === "string") t.provider = e.provider;
4980
- break;
4981
- }
4982
- case "tool.call":
4983
- t.toolCalls++;
4984
- if (e.isError) t.toolErrors++;
4985
- break;
4986
- case "verify.gates":
4987
- for (const g of Array.isArray(e.gates) ? e.gates : []) {
4988
- t.gateRuns++;
4989
- if (n(g.exitCode) === 0) t.gatePasses++;
4990
- }
4991
- break;
4992
- case "verify.result":
4993
- if (e.verdict !== "accept") t.rejects++;
4994
- break;
4995
- case "commit":
4996
- t.commits++;
4997
- if (typeof e.sha === "string") t.lastCommit = e.sha;
4998
- break;
4999
- case "rollback":
5000
- t.rollbacks++;
5001
- break;
5002
- case "context.compacted":
5003
- t.compactions++;
5004
- break;
5005
- case "run.finish":
5006
- if (typeof e.status === "string") t.status = e.status;
5007
- break;
5008
- case "provider.failover":
5009
- t.failovers++;
5010
- t.lastFailover = `${String(e.provider)}${typeof e.model === "string" ? `:${e.model}` : ""}`;
5011
- break;
5012
- case "provider.quota_exhausted":
5013
- if (typeof e.model === "string" && !t.quotaOut.includes(e.model)) t.quotaOut.push(e.model);
5014
- break;
5015
- case "route.decision":
5016
- if (typeof e.by === "string") t.routeBy = e.by;
5017
- break;
5018
- case "stuck.signal":
5019
- case "ladder.rung":
5020
- t.stuck++;
5021
- break;
5022
- case "milestone.done":
5023
- t.milestonesDone++;
5024
- break;
5025
- }
5026
- return t;
5027
- }
5028
- function cacheHitRate(t) {
5029
- return t.tokens.input ? t.tokens.cacheRead / t.tokens.input : 0;
5030
- }
5031
- function tokensPerCommit(t) {
5032
- return t.commits ? Math.round((t.tokens.input + t.tokens.output) / t.commits) : void 0;
5033
- }
5034
-
5035
4973
  // src/telemetry/humanize.ts
5036
4974
  var RANK2 = { quiet: 0, normal: 1, verbose: 2, debug: 3 };
5037
4975
  var str2 = (v) => typeof v === "string" ? v : typeof v === "number" || typeof v === "boolean" ? String(v) : v == null ? "" : JSON.stringify(v);
5038
4976
  var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
5039
- function fmtTokens(n2) {
5040
- if (n2 >= 1e6) return `${(n2 / 1e6).toFixed(1)}M`;
5041
- if (n2 >= 1e3) return `${(n2 / 1e3).toFixed(1)}k`;
5042
- return String(Math.round(n2));
4977
+ function fmtTokens(n) {
4978
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
4979
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
4980
+ return String(Math.round(n));
5043
4981
  }
5044
4982
  function fmtMs(ms) {
5045
4983
  if (ms < 1e3) return `${Math.round(ms)}ms`;
@@ -5056,9 +4994,9 @@ function toolInput(e) {
5056
4994
  return void 0;
5057
4995
  }
5058
4996
  }
5059
- function clip(s, n2) {
4997
+ function clip(s, n) {
5060
4998
  const one = s.replace(/\s+/g, " ").trim();
5061
- return one.length > n2 ? `${one.slice(0, n2 - 1)}\u2026` : one;
4999
+ return one.length > n ? `${one.slice(0, n - 1)}\u2026` : one;
5062
5000
  }
5063
5001
  function toolLine(e) {
5064
5002
  const name = str2(e.tool);
@@ -5445,7 +5383,7 @@ function debugLine(e, opts) {
5445
5383
  }
5446
5384
  function clockOf(ts, utc = false) {
5447
5385
  const d = new Date(ts);
5448
- const p = (n2) => String(n2).padStart(2, "0");
5386
+ const p = (n) => String(n).padStart(2, "0");
5449
5387
  return utc ? `${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}` : `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
5450
5388
  }
5451
5389
  function verbosityFrom(f) {
@@ -5591,10 +5529,6 @@ export {
5591
5529
  TAGLINE,
5592
5530
  brand,
5593
5531
  banner,
5594
- emptyTelemetry,
5595
- fold,
5596
- cacheHitRate,
5597
- tokensPerCommit,
5598
5532
  fmtTokens,
5599
5533
  fmtMs,
5600
5534
  humanize,
@@ -5602,4 +5536,4 @@ export {
5602
5536
  EventTail,
5603
5537
  LiveFeed
5604
5538
  };
5605
- //# sourceMappingURL=chunk-OXDXHUTX.js.map
5539
+ //# sourceMappingURL=chunk-2TKRLH7N.js.map