omnexx 0.10.0 → 0.11.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.
@@ -34,7 +34,7 @@ function text(c, key) {
34
34
  return v;
35
35
  }
36
36
  async function serveChat(io, runCli, opts) {
37
- const { Session } = await import("./session-7Y5VFFFM.js");
37
+ const { Session } = await import("./session-FB6CJHQB.js");
38
38
  const session = new Session(io, runCli);
39
39
  const write = (msg) => {
40
40
  println(io.stdout, JSON.stringify(msg));
@@ -299,4 +299,4 @@ async function serveChat(io, runCli, opts) {
299
299
  export {
300
300
  serveChat
301
301
  };
302
- //# sourceMappingURL=chat-server-RZKFHVDX.js.map
302
+ //# sourceMappingURL=chat-server-U3B2GVLU.js.map
@@ -14,7 +14,7 @@ import {
14
14
  humanize,
15
15
  pickRun,
16
16
  supervisorAlive
17
- } from "./chunk-AXHJLQT4.js";
17
+ } from "./chunk-VISE5TUX.js";
18
18
  import {
19
19
  connect,
20
20
  connectFromEnv,
@@ -52,6 +52,7 @@ import {
52
52
  import {
53
53
  POOL_MODES,
54
54
  loadConfig,
55
+ parseDuration,
55
56
  readPoolMode,
56
57
  readRanking,
57
58
  writePoolMode,
@@ -68,6 +69,51 @@ import {
68
69
  discoverModels
69
70
  } from "./chunk-UX4MF6V4.js";
70
71
 
72
+ // src/tui/auto-setup.tsx
73
+ import { Box, Text } from "ink";
74
+ import { jsx, jsxs } from "react/jsx-runtime";
75
+ var AUTO_TIMES = [
76
+ { label: "30 minutes", value: "30m" },
77
+ { label: "1 hour", value: "1h" },
78
+ { label: "2 hours", value: "2h" },
79
+ { label: "4 hours", value: "4h" },
80
+ { label: "8 hours \xB7 a workday", value: "8h" },
81
+ { label: "12 hours \xB7 overnight", value: "12h" },
82
+ { label: "24 hours", value: "24h" },
83
+ { label: "custom\u2026", value: "" }
84
+ ];
85
+ function readTime(text) {
86
+ const t = text.trim().toLowerCase().replace(/\s+/g, "");
87
+ const value = /^\d+(\.\d+)?$/.test(t) ? `${t}h` : t;
88
+ try {
89
+ return parseDuration(value) >= 6e4 ? value : void 0;
90
+ } catch {
91
+ return void 0;
92
+ }
93
+ }
94
+ function timeLabel(value) {
95
+ const known = AUTO_TIMES.find((t) => t.value === value);
96
+ if (known) return known.label.split(" \xB7 ")[0] ?? value;
97
+ const m = /^(\d+(?:\.\d+)?)(m|h|d)$/.exec(value);
98
+ if (!m) return value;
99
+ const unit = { m: "minute", h: "hour", d: "day" }[m[2]];
100
+ return `${m[1] ?? ""} ${unit}${m[1] === "1" ? "" : "s"}`;
101
+ }
102
+ function AutoTimePicker({ state, width }) {
103
+ if (state.step !== "time") return null;
104
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: GREEN, paddingX: 1, width, children: [
105
+ /* @__PURE__ */ jsxs(Text, { children: [
106
+ /* @__PURE__ */ jsx(Text, { color: GREEN, bold: true, children: "autonomous run \xB7 how long should it work?" }),
107
+ /* @__PURE__ */ jsx(Text, { color: GRAY, children: " \u2191\u2193 or 1-8 \xB7 enter choose \xB7 esc cancel" })
108
+ ] }),
109
+ AUTO_TIMES.map((t, i) => /* @__PURE__ */ jsxs(Text, { inverse: i === state.cursor, children: [
110
+ /* @__PURE__ */ jsx(Text, { color: i === state.cursor ? CYAN : GRAY, children: `${String(i + 1)} ` }),
111
+ /* @__PURE__ */ jsx(Text, { children: t.label })
112
+ ] }, t.label)),
113
+ /* @__PURE__ */ jsx(Text, { color: GRAY, children: "next: what it should work on. It plans, works, checks every change, and stops at the time." })
114
+ ] });
115
+ }
116
+
71
117
  // src/tui/session.ts
72
118
  import { join as join2 } from "path";
73
119
  import { Writable } from "stream";
@@ -267,8 +313,8 @@ async function hasProvider(io) {
267
313
  }
268
314
 
269
315
  // src/tui/markdown.tsx
270
- import { Text } from "ink";
271
- import { jsx, jsxs } from "react/jsx-runtime";
316
+ import { Text as Text2 } from "ink";
317
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
272
318
  function classifyMarkdown(lines) {
273
319
  let inCode = false;
274
320
  return lines.map((l) => {
@@ -297,38 +343,38 @@ function inlineSpans(line) {
297
343
  return out;
298
344
  }
299
345
  function Inline({ line }) {
300
- return /* @__PURE__ */ jsx(Text, { children: inlineSpans(line).map(
301
- (s, i) => s.style === "code" ? /* @__PURE__ */ jsx(Text, { color: CYAN, children: s.text }, i) : s.style === "bold" ? /* @__PURE__ */ jsx(Text, { bold: true, children: s.text }, i) : /* @__PURE__ */ jsx(Text, { children: s.text }, i)
346
+ return /* @__PURE__ */ jsx2(Text2, { children: inlineSpans(line).map(
347
+ (s, i) => s.style === "code" ? /* @__PURE__ */ jsx2(Text2, { color: CYAN, children: s.text }, i) : s.style === "bold" ? /* @__PURE__ */ jsx2(Text2, { bold: true, children: s.text }, i) : /* @__PURE__ */ jsx2(Text2, { children: s.text }, i)
302
348
  ) });
303
349
  }
304
350
  function MarkdownLine({ text, md }) {
305
351
  switch (md) {
306
352
  case "fence":
307
- return /* @__PURE__ */ jsx(Text, { color: GRAY, children: text.replace(/^\s*```/, "\u2500\u2500\u2500\u2500 ").trimEnd() });
353
+ return /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: text.replace(/^\s*```/, "\u2500\u2500\u2500\u2500 ").trimEnd() });
308
354
  case "code":
309
- return /* @__PURE__ */ jsxs(Text, { children: [
310
- /* @__PURE__ */ jsx(Text, { color: GRAY, children: "\u2502 " }),
311
- /* @__PURE__ */ jsx(Text, { color: CYAN, children: text })
355
+ return /* @__PURE__ */ jsxs2(Text2, { children: [
356
+ /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: "\u2502 " }),
357
+ /* @__PURE__ */ jsx2(Text2, { color: CYAN, children: text })
312
358
  ] });
313
359
  case "heading":
314
- return /* @__PURE__ */ jsx(Text, { color: GREEN, bold: true, children: text.replace(/^#{1,6}\s/, "") });
360
+ return /* @__PURE__ */ jsx2(Text2, { color: GREEN, bold: true, children: text.replace(/^#{1,6}\s/, "") });
315
361
  case "bullet": {
316
362
  const m = /^(\s*)([-*]|\d+\.)\s(.*)$/.exec(text);
317
- return /* @__PURE__ */ jsxs(Text, { children: [
363
+ return /* @__PURE__ */ jsxs2(Text2, { children: [
318
364
  m?.[1],
319
- /* @__PURE__ */ jsx(Text, { color: GREEN, children: m?.[2] === "-" || m?.[2] === "*" ? "\u2022" : m?.[2] }),
365
+ /* @__PURE__ */ jsx2(Text2, { color: GREEN, children: m?.[2] === "-" || m?.[2] === "*" ? "\u2022" : m?.[2] }),
320
366
  " ",
321
- /* @__PURE__ */ jsx(Inline, { line: m?.[3] ?? text })
367
+ /* @__PURE__ */ jsx2(Inline, { line: m?.[3] ?? text })
322
368
  ] });
323
369
  }
324
370
  case "text":
325
- return /* @__PURE__ */ jsx(Inline, { line: text });
371
+ return /* @__PURE__ */ jsx2(Inline, { line: text });
326
372
  }
327
373
  }
328
374
 
329
375
  // src/tui/diff.tsx
330
- import { Box, Text as Text2 } from "ink";
331
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
376
+ import { Box as Box2, Text as Text3 } from "ink";
377
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
332
378
  function parseDiff(text) {
333
379
  const files = [];
334
380
  let cur;
@@ -354,30 +400,30 @@ function DiffView({ view, width }) {
354
400
  (a, f) => ({ added: a.added + f.added, removed: a.removed + f.removed }),
355
401
  { added: 0, removed: 0 }
356
402
  );
357
- return /* @__PURE__ */ jsxs2(Box, { flexDirection: "column", borderStyle: "single", borderColor: GRAY, paddingX: 1, width, children: [
358
- /* @__PURE__ */ jsxs2(Text2, { children: [
359
- /* @__PURE__ */ jsx2(Text2, { color: GREEN, bold: true, children: view.title }),
360
- /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: ` \xB7 ${view.files.length} file${view.files.length === 1 ? "" : "s"} ` }),
361
- /* @__PURE__ */ jsx2(Text2, { color: GREEN, children: `+${total.added}` }),
403
+ return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", borderStyle: "single", borderColor: GRAY, paddingX: 1, width, children: [
404
+ /* @__PURE__ */ jsxs3(Text3, { children: [
405
+ /* @__PURE__ */ jsx3(Text3, { color: GREEN, bold: true, children: view.title }),
406
+ /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: ` \xB7 ${view.files.length} file${view.files.length === 1 ? "" : "s"} ` }),
407
+ /* @__PURE__ */ jsx3(Text3, { color: GREEN, children: `+${total.added}` }),
362
408
  " ",
363
- /* @__PURE__ */ jsx2(Text2, { color: RED, children: `-${total.removed}` }),
364
- /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: " \u2191\u2193 move \xB7 enter expand \xB7 esc close" })
409
+ /* @__PURE__ */ jsx3(Text3, { color: RED, children: `-${total.removed}` }),
410
+ /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: " \u2191\u2193 move \xB7 enter expand \xB7 esc close" })
365
411
  ] }),
366
- view.files.length === 0 && /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: "no changes" }),
412
+ view.files.length === 0 && /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: "no changes" }),
367
413
  view.files.map((f, i) => {
368
414
  const open = view.open.has(i);
369
415
  const shown = f.lines.slice(0, MAX_LINES_PER_FILE);
370
- return /* @__PURE__ */ jsxs2(Box, { flexDirection: "column", children: [
371
- /* @__PURE__ */ jsxs2(Text2, { inverse: i === view.cursor, children: [
372
- /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: open ? "\u25BE " : "\u25B8 " }),
416
+ return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", children: [
417
+ /* @__PURE__ */ jsxs3(Text3, { inverse: i === view.cursor, children: [
418
+ /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: open ? "\u25BE " : "\u25B8 " }),
373
419
  f.path,
374
420
  " ",
375
- /* @__PURE__ */ jsx2(Text2, { color: GREEN, children: `+${f.added}` }),
421
+ /* @__PURE__ */ jsx3(Text3, { color: GREEN, children: `+${f.added}` }),
376
422
  " ",
377
- /* @__PURE__ */ jsx2(Text2, { color: RED, children: `-${f.removed}` })
423
+ /* @__PURE__ */ jsx3(Text3, { color: RED, children: `-${f.removed}` })
378
424
  ] }),
379
- open && shown.map((l, j) => /* @__PURE__ */ jsx2(
380
- Text2,
425
+ open && shown.map((l, j) => /* @__PURE__ */ jsx3(
426
+ Text3,
381
427
  {
382
428
  wrap: "truncate-end",
383
429
  color: l.startsWith("+") ? GREEN : l.startsWith("-") ? RED : l.startsWith("@@") ? CYAN : GRAY,
@@ -385,15 +431,15 @@ function DiffView({ view, width }) {
385
431
  },
386
432
  j
387
433
  )),
388
- open && f.lines.length > shown.length && /* @__PURE__ */ jsx2(Text2, { color: GRAY, children: ` \u2026 ${f.lines.length - shown.length} more lines` })
434
+ open && f.lines.length > shown.length && /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: ` \u2026 ${f.lines.length - shown.length} more lines` })
389
435
  ] }, f.path);
390
436
  })
391
437
  ] });
392
438
  }
393
439
 
394
440
  // src/tui/agents.tsx
395
- import { Box as Box2, Text as Text3 } from "ink";
396
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
441
+ import { Box as Box3, Text as Text4 } from "ink";
442
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
397
443
  async function loadAgents(paths, now) {
398
444
  const ids = (await listRunIds(paths)).filter((id) => !id.startsWith("chat_")).reverse();
399
445
  const rows = [];
@@ -430,25 +476,25 @@ var bar = (done, total, width = 8) => {
430
476
  };
431
477
  function AgentsView({ state, width }) {
432
478
  const live = state.rows.filter((r) => r.alive).length;
433
- return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", borderStyle: "single", borderColor: GREEN, paddingX: 1, width, children: [
434
- /* @__PURE__ */ jsxs3(Text3, { children: [
435
- /* @__PURE__ */ jsx3(Text3, { color: GREEN, bold: true, children: "agents" }),
436
- /* @__PURE__ */ jsx3(
437
- Text3,
479
+ return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", borderStyle: "single", borderColor: GREEN, paddingX: 1, width, children: [
480
+ /* @__PURE__ */ jsxs4(Text4, { children: [
481
+ /* @__PURE__ */ jsx4(Text4, { color: GREEN, bold: true, children: "agents" }),
482
+ /* @__PURE__ */ jsx4(
483
+ Text4,
438
484
  {
439
485
  color: GRAY,
440
486
  children: ` ${live} running \xB7 ${state.rows.length} total \xB7 \u2191\u2193 \xB7 enter attach \xB7 p pause/resume \xB7 s stop \xB7 esc`
441
487
  }
442
488
  )
443
489
  ] }),
444
- state.rows.length === 0 && /* @__PURE__ */ jsx3(Text3, { color: GRAY, children: "no runs yet: /run <goal> starts one" }),
445
- state.rows.map((r, i) => /* @__PURE__ */ jsxs3(Text3, { inverse: i === state.cursor, wrap: "truncate-end", children: [
446
- /* @__PURE__ */ jsx3(Text3, { color: r.alive ? GREEN : r.status === "error" ? RED : GRAY, children: r.alive ? "\u25CF " : "\u25CB " }),
447
- /* @__PURE__ */ jsx3(Text3, { color: CYAN, children: r.repo.padEnd(14).slice(0, 14) }),
448
- /* @__PURE__ */ jsx3(Text3, { children: ` ${r.alive ? r.phase.padEnd(9) : r.status.padEnd(9)} ` }),
449
- /* @__PURE__ */ jsx3(Text3, { color: GREEN, children: bar(r.done, r.tasks) }),
450
- /* @__PURE__ */ jsx3(
451
- Text3,
490
+ state.rows.length === 0 && /* @__PURE__ */ jsx4(Text4, { color: GRAY, children: "no runs yet: /run <goal> starts one" }),
491
+ state.rows.map((r, i) => /* @__PURE__ */ jsxs4(Text4, { inverse: i === state.cursor, wrap: "truncate-end", children: [
492
+ /* @__PURE__ */ jsx4(Text4, { color: r.alive ? GREEN : r.status === "error" ? RED : GRAY, children: r.alive ? "\u25CF " : "\u25CB " }),
493
+ /* @__PURE__ */ jsx4(Text4, { color: CYAN, children: r.repo.padEnd(14).slice(0, 14) }),
494
+ /* @__PURE__ */ jsx4(Text4, { children: ` ${r.alive ? r.phase.padEnd(9) : r.status.padEnd(9)} ` }),
495
+ /* @__PURE__ */ jsx4(Text4, { color: GREEN, children: bar(r.done, r.tasks) }),
496
+ /* @__PURE__ */ jsx4(
497
+ Text4,
452
498
  {
453
499
  color: GRAY,
454
500
  children: ` ${r.done}/${r.tasks} ${r.task ?? ""} $${r.usd.toFixed(2)}${r.alive && r.beatAge !== void 0 ? ` \xB7 ${fmtMs(r.beatAge)} ago` : ""} ${r.goal.slice(0, 60)}`
@@ -515,7 +561,7 @@ var SLASH = [
515
561
  { name: "diff", help: "browse what changed" },
516
562
  {
517
563
  name: "autonomous",
518
- help: "work on the repo for a set time: /autonomous 8h [goal] (default: improve it)"
564
+ help: "work on its own for a set time: pick how long, then the goal (or /autonomous 8h [goal])"
519
565
  },
520
566
  { name: "go", help: "plan mode: approve the plan and carry it out" },
521
567
  { name: "undo", help: "put the files back as they were before the last message" },
@@ -816,6 +862,10 @@ var Session = class {
816
862
  pending.resolve(yes);
817
863
  return;
818
864
  }
865
+ if (this.autoSetup && this.autoSetup.step !== "time") {
866
+ await this.autoInput(text);
867
+ return;
868
+ }
819
869
  if (!text) return;
820
870
  const awaiting = this.awaiting;
821
871
  if (awaiting) {
@@ -963,6 +1013,60 @@ var Session = class {
963
1013
  pendingKey;
964
1014
  /** The open /models ranking editor. */
965
1015
  rankView;
1016
+ /** `/autonomous` with no arguments: picking the time, then the goal. */
1017
+ autoSetup;
1018
+ openAutoSetup() {
1019
+ this.autoSetup = { step: "time", cursor: 4 };
1020
+ this.changed();
1021
+ }
1022
+ /** Keys while the time list is open. */
1023
+ autoKey(k) {
1024
+ const a = this.autoSetup;
1025
+ if (a?.step !== "time") return;
1026
+ if (k.close) {
1027
+ this.autoSetup = void 0;
1028
+ this.push("system", "autonomous run cancelled");
1029
+ } else if (k.up) a.cursor = Math.max(0, a.cursor - 1);
1030
+ else if (k.down) a.cursor = Math.min(AUTO_TIMES.length - 1, a.cursor + 1);
1031
+ else if (k.enter || k.pick !== void 0) {
1032
+ const choice = AUTO_TIMES[k.pick ?? a.cursor];
1033
+ if (!choice) return;
1034
+ const goal = a.goal === void 0 ? {} : { goal: a.goal };
1035
+ if (!choice.value) this.autoSetup = { step: "custom", ...goal };
1036
+ else if (a.goal !== void 0) void this.launchAuto(choice.value, a.goal);
1037
+ else this.autoSetup = { step: "goal", time: choice.value };
1038
+ }
1039
+ this.changed();
1040
+ }
1041
+ async launchAuto(time, goal) {
1042
+ this.autoSetup = void 0;
1043
+ this.push("system", `autonomous run for ${timeLabel(time)}`);
1044
+ try {
1045
+ await this.startRun(goal || AUTONOMOUS_DEFAULT_GOAL, ["--for", time]);
1046
+ } catch (err) {
1047
+ this.push("err", describeError(err));
1048
+ }
1049
+ }
1050
+ /** A message typed while setting up an autonomous run: the custom time, or the goal. */
1051
+ async autoInput(text) {
1052
+ const a = this.autoSetup;
1053
+ if (a?.step === "custom") {
1054
+ const time = readTime(text);
1055
+ if (!time) {
1056
+ this.push("err", `"${text}" isn't a time: try 90m, 3h, 1d or 1h30m`);
1057
+ return;
1058
+ }
1059
+ if (a.goal !== void 0) await this.launchAuto(time, a.goal);
1060
+ else {
1061
+ this.autoSetup = { step: "goal", time };
1062
+ this.changed();
1063
+ }
1064
+ return;
1065
+ }
1066
+ if (a?.step !== "goal") return;
1067
+ this.push("user", text || "(keep improving the repo)");
1068
+ await this.launchAuto(a.time, text);
1069
+ }
966
1070
  /** What choosing in the picker does: switch chat, or add to the ranking. */
967
1071
  pickFor = "chat";
968
1072
  async openRanking() {
@@ -1158,6 +1262,11 @@ var Session = class {
1158
1262
  }
1159
1263
  /** Esc: stop the agent's current turn. Returns false when nothing was running. */
1160
1264
  interrupt() {
1265
+ if (this.autoSetup) {
1266
+ this.autoSetup = void 0;
1267
+ this.push("system", "autonomous run cancelled");
1268
+ return true;
1269
+ }
1161
1270
  if (!this.code?.busy) return false;
1162
1271
  this.code.interrupt();
1163
1272
  this.react("startled");
@@ -1331,16 +1440,21 @@ var Session = class {
1331
1440
  if (rest) await this.startRun(rest);
1332
1441
  else this.setMode("run");
1333
1442
  return;
1443
+ case "auto":
1334
1444
  case "autonomous": {
1335
1445
  const [time, ...goal] = args;
1336
1446
  if (!time) {
1337
- this.push(
1338
- "system",
1339
- "usage: /autonomous <time> [goal], e.g. /autonomous 8h make it faster"
1340
- );
1447
+ this.openAutoSetup();
1448
+ return;
1449
+ }
1450
+ const valid = readTime(time);
1451
+ if (!valid) {
1452
+ this.autoSetup = { step: "time", cursor: 4, goal: rest };
1453
+ this.push("system", "pick how long it should work");
1454
+ this.changed();
1341
1455
  return;
1342
1456
  }
1343
- await this.startRun(goal.join(" ") || AUTONOMOUS_DEFAULT_GOAL, ["--for", time]);
1457
+ await this.startRun(goal.join(" ") || AUTONOMOUS_DEFAULT_GOAL, ["--for", valid]);
1344
1458
  return;
1345
1459
  }
1346
1460
  case "plan":
@@ -1627,6 +1741,8 @@ function helpText(b) {
1627
1741
  export {
1628
1742
  DiffView,
1629
1743
  AgentsView,
1744
+ timeLabel,
1745
+ AutoTimePicker,
1630
1746
  MarkdownLine,
1631
1747
  SLASH,
1632
1748
  MORE_SLASH,
@@ -1634,4 +1750,4 @@ export {
1634
1750
  Session,
1635
1751
  helpText
1636
1752
  };
1637
- //# sourceMappingURL=chunk-V46JH6SE.js.map
1753
+ //# sourceMappingURL=chunk-E6JAG5GA.js.map