omnius 1.0.266 → 1.0.268

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.
package/dist/index.js CHANGED
@@ -557292,7 +557292,7 @@ var init_ollama_pool = __esm({
557292
557292
  elasticSpawnCap(gpus) {
557293
557293
  return this.config.maxSpawnedInstances > 0 ? this.config.maxSpawnedInstances : Math.max(0, gpus.length - 1);
557294
557294
  }
557295
- async getGpusForPlacement(maxAgeMs = 3e3) {
557295
+ async getGpusForPlacement(maxAgeMs = 3e4) {
557296
557296
  const now2 = Date.now();
557297
557297
  if (this.gpuCache && now2 - this.gpuCache.takenAtMs <= maxAgeMs) {
557298
557298
  return this.gpuCache.gpus;
@@ -557366,7 +557366,12 @@ var init_ollama_pool = __esm({
557366
557366
  }
557367
557367
  const gpuUuid = gpu?.uuid || null;
557368
557368
  const gpuIndex = gpu?.index ?? null;
557369
- const { proc, ready } = await this.spawner({ port, gpuUuid, gpuIndex, config: this.config });
557369
+ const { proc, ready } = await this.spawner({
557370
+ port,
557371
+ gpuUuid,
557372
+ gpuIndex,
557373
+ config: this.config
557374
+ });
557370
557375
  try {
557371
557376
  await ready;
557372
557377
  } catch (err) {
@@ -562511,6 +562516,8 @@ var init_streaming_executor = __esm({
562511
562516
  insertionOrder = [];
562512
562517
  config;
562513
562518
  executeFn = null;
562519
+ /** Resolver for notification-based wait (delay-1: replaces 1ms spin loop) */
562520
+ _notifyResolve = null;
562514
562521
  constructor(config) {
562515
562522
  this.config = {
562516
562523
  maxConcurrent: config?.maxConcurrent ?? 5,
@@ -562588,6 +562595,18 @@ var init_streaming_executor = __esm({
562588
562595
  }
562589
562596
  return results;
562590
562597
  }
562598
+ /** Signal the notification promise (wake waitAll if sleeping) */
562599
+ _signalChange() {
562600
+ const r2 = this._notifyResolve;
562601
+ this._notifyResolve = null;
562602
+ r2?.();
562603
+ }
562604
+ /** Create a new notification promise for waitAll to await */
562605
+ _waitForChange() {
562606
+ return new Promise((resolve70) => {
562607
+ this._notifyResolve = resolve70;
562608
+ });
562609
+ }
562591
562610
  /**
562592
562611
  * Wait for all queued/executing tools to complete.
562593
562612
  */
@@ -562603,7 +562622,7 @@ var init_streaming_executor = __esm({
562603
562622
  this.processQueue();
562604
562623
  } else {
562605
562624
  this.processQueue();
562606
- await new Promise((r2) => setTimeout(r2, 1));
562625
+ await this._waitForChange();
562607
562626
  }
562608
562627
  }
562609
562628
  }
@@ -562740,6 +562759,7 @@ var init_streaming_executor = __esm({
562740
562759
  break;
562741
562760
  }
562742
562761
  }
562762
+ this._signalChange();
562743
562763
  }
562744
562764
  startExecution(entry) {
562745
562765
  entry.state = "executing";
@@ -563908,7 +563928,11 @@ function captureToolchainVersions() {
563908
563928
  const out = {};
563909
563929
  for (const probe of TOOLCHAIN_PROBES) {
563910
563930
  try {
563911
- const v = execSync47(probe.cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 1500 }).trim();
563931
+ const v = execSync47(probe.cmd, {
563932
+ encoding: "utf8",
563933
+ stdio: ["ignore", "pipe", "ignore"],
563934
+ timeout: 500
563935
+ }).trim();
563912
563936
  out[probe.name] = v.split(/\r?\n/)[0].slice(0, 200);
563913
563937
  } catch {
563914
563938
  out[probe.name] = null;
@@ -563929,7 +563953,10 @@ function freeDiskBytes(path12 = "/tmp") {
563929
563953
  const st = statSync35(path12);
563930
563954
  if (!st.isDirectory())
563931
563955
  return -1;
563932
- const out = execSync47(`df -P -k ${JSON.stringify(path12)} | tail -1`, { encoding: "utf8", timeout: 1500 });
563956
+ const out = execSync47(`df -P -k ${JSON.stringify(path12)} | tail -1`, {
563957
+ encoding: "utf8",
563958
+ timeout: 500
563959
+ });
563933
563960
  const cols = out.trim().split(/\s+/);
563934
563961
  const availKb = parseInt(cols[3] ?? "0", 10);
563935
563962
  if (!Number.isFinite(availKb))
@@ -581407,21 +581434,30 @@ var init_cascadeBackend = __esm({
581407
581434
  } catch (err) {
581408
581435
  this.consecutiveFailures++;
581409
581436
  if (this.isTransientError(err) && this.consecutiveFailures >= this.maxFailures) {
581410
- const nextIdx = this.findNextAvailableEndpoint();
581411
- if (nextIdx !== null && nextIdx !== this.activeIndex) {
581437
+ const candidates = this.endpoints.filter((_ep, i2) => i2 !== this.activeIndex && _ep.modelAvailable !== false);
581438
+ if (candidates.length > 0) {
581412
581439
  const from3 = this.endpoints[this.activeIndex];
581413
- const to = this.endpoints[nextIdx];
581414
581440
  const reason = `${this.consecutiveFailures} consecutive failures: ${err instanceof Error ? err.message : String(err)}`;
581415
- this.activeIndex = nextIdx;
581416
- this.consecutiveFailures = 0;
581417
- this.onSwitch?.(from3, to, reason);
581418
- const newBackend = this.getActiveBackend();
581441
+ const promises = candidates.map((ep) => {
581442
+ const bk = this.backends.get(ep.url);
581443
+ return bk.chatCompletion(request).then((result) => ({ result, from: ep }));
581444
+ });
581419
581445
  try {
581420
- const result = await newBackend.chatCompletion(request);
581446
+ const { result, from: from4 } = await Promise.race(promises);
581447
+ const winnerIdx = this.endpoints.indexOf(from4);
581448
+ if (winnerIdx >= 0) {
581449
+ this.activeIndex = winnerIdx;
581450
+ this.onSwitch?.(from4, from4, reason);
581451
+ }
581452
+ this.consecutiveFailures = 0;
581421
581453
  return result;
581422
- } catch (cascadeErr) {
581423
- this.consecutiveFailures++;
581424
- throw cascadeErr;
581454
+ } catch {
581455
+ this.consecutiveFailures += candidates.length;
581456
+ throw err;
581457
+ } finally {
581458
+ for (const p2 of promises)
581459
+ p2.catch(() => {
581460
+ });
581425
581461
  }
581426
581462
  }
581427
581463
  }
@@ -581636,7 +581672,7 @@ function createSteeringIngress(input) {
581636
581672
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
581637
581673
  };
581638
581674
  }
581639
- async function interpretSteeringIngress(backend, ingress, timeoutMs = 15e3) {
581675
+ async function interpretSteeringIngress(backend, ingress, timeoutMs = 8e3) {
581640
581676
  const first2 = await backend.chatCompletion({
581641
581677
  messages: [
581642
581678
  {
@@ -594350,6 +594386,175 @@ var init_task_complete_box = __esm({
594350
594386
  }
594351
594387
  });
594352
594388
 
594389
+ // packages/cli/src/tui/syntax-highlight.ts
594390
+ var syntax_highlight_exports = {};
594391
+ __export(syntax_highlight_exports, {
594392
+ detectLanguage: () => detectLanguage2,
594393
+ getHighlightStatus: () => getHighlightStatus,
594394
+ highlightBlock: () => highlightBlock,
594395
+ highlightCode: () => highlightCode,
594396
+ isAvailable: () => isAvailable,
594397
+ prewarm: () => prewarm
594398
+ });
594399
+ function highlightingDisabled() {
594400
+ return !isTTY2 || noColorEnv || disableEnv;
594401
+ }
594402
+ async function loadHighlighter() {
594403
+ if (_state.attempted) return _state.fn;
594404
+ _state.attempted = true;
594405
+ if (highlightingDisabled()) {
594406
+ _state.reason = !isTTY2 ? "non-tty" : noColorEnv ? "NO_COLOR set" : "OMNIUS_TUI_HIGHLIGHT=0";
594407
+ return null;
594408
+ }
594409
+ try {
594410
+ const { createRequire: createRequire10 } = await import("node:module");
594411
+ const req3 = createRequire10(import.meta.url);
594412
+ let resolved = null;
594413
+ try {
594414
+ resolved = req3.resolve("cli-highlight");
594415
+ } catch {
594416
+ _state.reason = "cli-highlight not installed";
594417
+ return null;
594418
+ }
594419
+ const mod3 = await import(resolved).catch(() => null);
594420
+ if (!mod3) {
594421
+ _state.reason = "cli-highlight failed to load";
594422
+ return null;
594423
+ }
594424
+ const m2 = mod3;
594425
+ const candidate = m2.highlight ?? m2.default ?? null;
594426
+ if (typeof candidate !== "function") {
594427
+ _state.reason = "cli-highlight export shape unrecognized";
594428
+ return null;
594429
+ }
594430
+ _state.fn = candidate;
594431
+ return candidate;
594432
+ } catch (err) {
594433
+ _state.reason = `import threw: ${err?.message ?? String(err)}`;
594434
+ return null;
594435
+ }
594436
+ }
594437
+ function loadHighlighterSync() {
594438
+ if (highlightingDisabled()) return null;
594439
+ return _state.fn;
594440
+ }
594441
+ async function prewarm() {
594442
+ await loadHighlighter();
594443
+ }
594444
+ function isAvailable() {
594445
+ if (highlightingDisabled()) return false;
594446
+ return _state.attempted && _state.fn !== null;
594447
+ }
594448
+ function getHighlightStatus() {
594449
+ return {
594450
+ available: isAvailable(),
594451
+ attempted: _state.attempted,
594452
+ reason: _state.reason,
594453
+ isTTY: isTTY2,
594454
+ noColor: noColorEnv,
594455
+ disabledByEnv: disableEnv
594456
+ };
594457
+ }
594458
+ function highlightCode(code8, language) {
594459
+ if (!code8) return code8;
594460
+ const fn = loadHighlighterSync();
594461
+ if (!fn) return code8;
594462
+ const lang = (language ?? detectLanguage2(code8) ?? "").trim();
594463
+ try {
594464
+ if (lang) {
594465
+ return fn(code8, { language: lang, ignoreIllegals: true });
594466
+ }
594467
+ return fn(code8, { ignoreIllegals: true });
594468
+ } catch {
594469
+ return code8;
594470
+ }
594471
+ }
594472
+ function detectLanguage2(text2) {
594473
+ if (!text2) return null;
594474
+ const trimmed = text2.trimStart();
594475
+ const shebang = trimmed.match(/^#!\s*\/[^\n]+/);
594476
+ if (shebang) {
594477
+ const sb = shebang[0];
594478
+ if (/python/.test(sb)) return "python";
594479
+ if (/(?:^|[\s/])(?:bash|sh|zsh)\b/.test(sb)) return "bash";
594480
+ if (/node/.test(sb)) return "javascript";
594481
+ if (/ruby/.test(sb)) return "ruby";
594482
+ if (/perl/.test(sb)) return "perl";
594483
+ }
594484
+ if (/^[\s\n]*[{[]/.test(trimmed)) {
594485
+ try {
594486
+ JSON.parse(trimmed);
594487
+ return "json";
594488
+ } catch {
594489
+ }
594490
+ }
594491
+ if (/^[-a-zA-Z_][\w-]*:\s/.test(trimmed) && /\n[-a-zA-Z_][\w-]*:\s/.test(trimmed)) {
594492
+ return "yaml";
594493
+ }
594494
+ if (/^(?:async def |def |class |import |from )/.test(trimmed) && /(?::\s*$|->|self\b)/m.test(trimmed)) {
594495
+ return "python";
594496
+ }
594497
+ if (/^(?:import |export |const |let |var |function |class |interface |type |async )/.test(trimmed)) {
594498
+ if (/(:\s*(?:string|number|boolean|any|unknown|void)\b|\binterface\b|\btype\s+\w+\s*=)/.test(trimmed)) {
594499
+ return "typescript";
594500
+ }
594501
+ return "javascript";
594502
+ }
594503
+ if (/(?:^|\n)\s*(?:fn |use |let mut |impl |struct |enum |trait )/.test(trimmed)) {
594504
+ return "rust";
594505
+ }
594506
+ if (/(?:^package \w+|\nfunc \w+\s*\()/.test(trimmed)) {
594507
+ return "go";
594508
+ }
594509
+ if (/^\s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i.test(trimmed)) {
594510
+ return "sql";
594511
+ }
594512
+ if (/^[\s\n]*<(?:!DOCTYPE|html|\?xml|\w+)/i.test(trimmed)) {
594513
+ return "html";
594514
+ }
594515
+ if (/^(?:---|\+\+\+|@@|diff )/.test(trimmed)) {
594516
+ return "diff";
594517
+ }
594518
+ if (/^\s*(?:\$\s|sudo |apt |brew |npm |pnpm |yarn |git |docker |kubectl |curl |wget )/.test(trimmed)) {
594519
+ return "bash";
594520
+ }
594521
+ return null;
594522
+ }
594523
+ function highlightBlock(code8, language) {
594524
+ if (!code8) return [""];
594525
+ const fn = loadHighlighterSync();
594526
+ if (!fn) return code8.split("\n");
594527
+ const lang = (language ?? detectLanguage2(code8) ?? "").trim();
594528
+ try {
594529
+ const out = lang ? fn(code8, { language: lang, ignoreIllegals: true }) : fn(code8, { ignoreIllegals: true });
594530
+ const lines = out.split("\n");
594531
+ const inputLines = code8.split("\n");
594532
+ if (lines.length === inputLines.length) return lines;
594533
+ if (lines.length < inputLines.length) {
594534
+ while (lines.length < inputLines.length) lines.push("");
594535
+ } else {
594536
+ lines.length = inputLines.length;
594537
+ }
594538
+ return lines;
594539
+ } catch {
594540
+ return code8.split("\n");
594541
+ }
594542
+ }
594543
+ var isTTY2, noColorEnv, disableEnv, _state;
594544
+ var init_syntax_highlight = __esm({
594545
+ "packages/cli/src/tui/syntax-highlight.ts"() {
594546
+ "use strict";
594547
+ isTTY2 = process.stdout?.isTTY ?? false;
594548
+ noColorEnv = process.env["NO_COLOR"] !== void 0 && process.env["NO_COLOR"] !== "";
594549
+ disableEnv = process.env["OMNIUS_TUI_HIGHLIGHT"] === "0";
594550
+ _state = {
594551
+ attempted: false,
594552
+ fn: null,
594553
+ reason: ""
594554
+ };
594555
+ }
594556
+ });
594557
+
594353
594558
  // packages/cli/src/tui/model-picker.ts
594354
594559
  import { totalmem as totalmem4 } from "node:os";
594355
594560
  function isImageGenModel(name10, family) {
@@ -596058,10 +596263,29 @@ function diffBodyLines(output, verbose) {
596058
596263
  for (const line of lines.slice(0, maxLines)) {
596059
596264
  const m2 = line.match(DIFF_LINE_RE);
596060
596265
  if (m2) {
596061
- const colored = m2[1] === "+" ? c3.green(line) : c3.red(line);
596266
+ const marker = m2[1];
596267
+ const codeStart = m2.index + m2[0].length;
596268
+ const prefix = line.slice(0, codeStart);
596269
+ const code8 = line.slice(codeStart);
596270
+ let hlCode = code8;
596271
+ if (isAvailable() && code8.trim()) {
596272
+ const hl = highlightCode(code8);
596273
+ if (hl !== code8) hlCode = hl;
596274
+ }
596275
+ const colorSeq = marker === "+" ? "\x1B[32m" : "\x1B[31m";
596276
+ const resetRe = /\x1B\[0m/g;
596277
+ const adjusted = hlCode.replace(resetRe, `\x1B[0m${colorSeq}`);
596278
+ const colored = `${colorSeq}${prefix}${adjusted}\x1B[0m`;
596062
596279
  body.push({ text: colored, mode: "truncate", kind: "plain" });
596063
596280
  } else {
596064
- body.push({ text: line, mode: "wrap", kind: "dim" });
596281
+ let formatted = line;
596282
+ if (isAvailable() && line.trim()) {
596283
+ const hl = highlightCode(line);
596284
+ formatted = hl !== line ? hl : c3.dim(line);
596285
+ } else {
596286
+ formatted = c3.dim(line);
596287
+ }
596288
+ body.push({ text: formatted, mode: "wrap", kind: "plain" });
596065
596289
  }
596066
596290
  }
596067
596291
  if (lines.length > maxLines) {
@@ -596081,11 +596305,16 @@ function codePreviewLines(output, maxLines) {
596081
596305
  const shown = lines.slice(start2, start2 + maxLines);
596082
596306
  if (shown.length === 0)
596083
596307
  return [{ text: "(empty file)", mode: "wrap", kind: "dim" }];
596084
- const body = shown.map((line) => ({
596085
- text: line,
596308
+ let hlLines = null;
596309
+ if (isAvailable()) {
596310
+ const codeBlock = shown.join("\n");
596311
+ const hl = highlightBlock(codeBlock);
596312
+ if (hl.length === shown.length) hlLines = hl;
596313
+ }
596314
+ const body = shown.map((line, i2) => ({
596315
+ text: hlLines ? hlLines[i2] ?? line : line,
596086
596316
  mode: "truncate",
596087
596317
  kind: "plain"
596088
- // show content in default terminal color, not dim
596089
596318
  }));
596090
596319
  const remaining = lines.length - start2 - shown.length;
596091
596320
  if (remaining > 0) {
@@ -596580,6 +596809,7 @@ var init_render = __esm({
596580
596809
  init_config();
596581
596810
  init_text_selection();
596582
596811
  init_task_complete_box();
596812
+ init_syntax_highlight();
596583
596813
  init_model_picker();
596584
596814
  init_secret_redactor();
596585
596815
  c3 = {
@@ -606213,7 +606443,10 @@ var init_status_bar = __esm({
606213
606443
  const sentinel = `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
606214
606444
  this._contentLines.push(sentinel);
606215
606445
  if (this._contentLines.length > this._contentMaxLines) {
606216
- this._contentLines.splice(0, this._contentLines.length - this._contentMaxLines);
606446
+ this._contentLines.splice(
606447
+ 0,
606448
+ this._contentLines.length - this._contentMaxLines
606449
+ );
606217
606450
  this.clampContentScrollOffset();
606218
606451
  }
606219
606452
  if (this._autoScroll && !this._mouseSelecting)
@@ -606346,8 +606579,13 @@ var init_status_bar = __esm({
606346
606579
  ];
606347
606580
  const model = this.summarizeHeaderModelName();
606348
606581
  const transport = this.summarizeHeaderTransport();
606349
- if (model) parts.push({ text: ` ${model} `, width: stripAnsi(` ${model} `).length });
606350
- if (transport) parts.push({ text: ` ${transport} `, width: stripAnsi(` ${transport} `).length });
606582
+ if (model)
606583
+ parts.push({ text: ` ${model} `, width: stripAnsi(` ${model} `).length });
606584
+ if (transport)
606585
+ parts.push({
606586
+ text: ` ${transport} `,
606587
+ width: stripAnsi(` ${transport} `).length
606588
+ });
606351
606589
  if (this._updateLatest) {
606352
606590
  const last2 = parts[parts.length - 1];
606353
606591
  if (last2) {
@@ -606566,7 +606804,10 @@ var init_status_bar = __esm({
606566
606804
  const telegramDot = this._telegramStatus.active ? "●" : "○";
606567
606805
  const telegramLabel = this._telegramStatus.activeSubAgents > 0 ? ` ✈ tg ${this._telegramStatus.activeSubAgents} ` : " ✈ tg ";
606568
606806
  sysItems.push({
606569
- render: () => renderBtn("telegram", `\x1B[38;5;45m${telegramDot}${telegramLabel}\x1B[0m`) + " ",
606807
+ render: () => renderBtn(
606808
+ "telegram",
606809
+ `\x1B[38;5;45m${telegramDot}${telegramLabel}\x1B[0m`
606810
+ ) + " ",
606570
606811
  w: telegramLabel.length + 2
606571
606812
  });
606572
606813
  const nexusDot = this._nexusStatus === "connected" || this._nexusStatus === "connecting" ? "●" : "○";
@@ -607094,7 +607335,9 @@ var init_status_bar = __esm({
607094
607335
  Promise.resolve().then(() => (init_dist8(), dist_exports3)).then(({ getOllamaPool: getOllamaPool2, resolveDefaultPoolConfig: resolveDefaultPoolConfig2 }) => {
607095
607336
  try {
607096
607337
  const config = resolveDefaultPoolConfig2();
607097
- const pool3 = getOllamaPool2({ baseInstanceUrl: config.baseInstanceUrl });
607338
+ const pool3 = getOllamaPool2({
607339
+ baseInstanceUrl: config.baseInstanceUrl
607340
+ });
607098
607341
  broker.setOllamaAffinityProvider((modelName) => {
607099
607342
  try {
607100
607343
  const status = pool3.status?.();
@@ -607670,7 +607913,10 @@ var init_status_bar = __esm({
607670
607913
  if (!this._mouseTrackingEnabled) return;
607671
607914
  this._mouseTrackingEnabled = false;
607672
607915
  if (process.stdout.isTTY) {
607673
- this._trueStdoutWrite.call(process.stdout, "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l");
607916
+ this._trueStdoutWrite.call(
607917
+ process.stdout,
607918
+ "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l"
607919
+ );
607674
607920
  }
607675
607921
  }
607676
607922
  /** Re-apply the current mouse preference after overlays, password prompts, or redraws. */
@@ -608474,10 +608720,7 @@ ${CONTENT_BG_SEQ}`);
608474
608720
  reflowContentLine(line, width) {
608475
608721
  const visible = stripAnsi(line);
608476
608722
  if (visible.length <= width) return [line];
608477
- const continuationIndent = this.hangingIndentForVisibleLine(
608478
- visible,
608479
- width
608480
- );
608723
+ const continuationIndent = this.hangingIndentForVisibleLine(visible, width);
608481
608724
  const ranges = this.visibleWrapRanges(
608482
608725
  visible,
608483
608726
  width,
@@ -608650,46 +608893,28 @@ ${CONTENT_BG_SEQ}`);
608650
608893
  (line) => line.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\]?[^\x07]*\x07/g, "")
608651
608894
  );
608652
608895
  const text2 = stripped.join("\n");
608653
- const clipboardCmds = [
608654
- ["wl-copy", text2],
608655
- ["xclip", ["-selection", "clipboard"], "-i"],
608656
- ["xsel", "--clipboard", "--input"]
608657
- ];
608658
- let success = false;
608659
- for (const [cmd, ...args] of clipboardCmds) {
608896
+ if (text2.length === 0) return;
608897
+ const ok3 = copyText(text2);
608898
+ if (!ok3) {
608660
608899
  try {
608661
- const { execSync: execSync63 } = __require("child_process");
608662
- const child = __require("child_process").spawn(cmd, args, {
608663
- stdio: ["pipe", "pipe", "pipe"]
608664
- });
608665
- if (child.stdin) {
608666
- child.stdin.write(text2);
608667
- child.stdin.end();
608668
- }
608669
- child.on("close", (code8) => {
608670
- if (code8 === 0) success = true;
608671
- });
608672
- setTimeout(() => {
608673
- if (!success) {
608674
- try {
608675
- child.kill();
608676
- } catch {
608677
- }
608678
- }
608679
- }, 500);
608680
- break;
608900
+ const fs11 = __require("fs");
608901
+ const os9 = __require("os");
608902
+ const tmpPath = __require("path").join(
608903
+ os9.tmpdir(),
608904
+ "omnius-session-copy.txt"
608905
+ );
608906
+ fs11.writeFileSync(tmpPath, text2, "utf-8");
608907
+ process.stderr.write(
608908
+ `\x1B[38;5;208mClipboard unavailable session saved to ${tmpPath}\x1B[0m
608909
+ `
608910
+ );
608681
608911
  } catch {
608682
- continue;
608912
+ process.stderr.write(
608913
+ `\x1B[38;5;196mFailed to save session to clipboard or temp file.\x1B[0m
608914
+ `
608915
+ );
608683
608916
  }
608684
608917
  }
608685
- if (!success) {
608686
- const fs11 = __require("fs");
608687
- const os9 = __require("os");
608688
- const tmpPath = __require("path").join(os9.tmpdir(), "omnius-session-copy.txt");
608689
- fs11.writeFileSync(tmpPath, text2, "utf-8");
608690
- process.stderr.write(`\x1B[38;5;208mClipboard unavailable — session saved to ${tmpPath}\x1B[0m
608691
- `);
608692
- }
608693
608918
  }
608694
608919
  /**
608695
608920
  * WO-TASK-02 — sync the tasks panel "pager" scope flag with the current
@@ -608757,7 +608982,10 @@ ${CONTENT_BG_SEQ}`);
608757
608982
  end: startCol + label.length - 1
608758
608983
  };
608759
608984
  const copyLabel = " ⎘ copy session ";
608760
- const copyCol = Math.max(startCol + label.length + 2, w - copyLabel.length);
608985
+ const copyCol = Math.max(
608986
+ startCol + label.length + 2,
608987
+ w - copyLabel.length
608988
+ );
608761
608989
  if (copyCol + copyLabel.length <= w) {
608762
608990
  buf += `\x1B[${spacerRow};${copyCol}H\x1B[38;5;141m${copyLabel}\x1B[0m${CONTENT_BG_SEQ}`;
608763
608991
  this._copyBtnRegion = {
@@ -609268,7 +609496,10 @@ ${CONTENT_BG_SEQ}`);
609268
609496
  if (!this.inputStateProvider) return 1;
609269
609497
  const availWidth = this.inputTextWidth(termWidth);
609270
609498
  const { line } = this.inputStateProvider();
609271
- return Math.max(1, this.wrapPlainInputText(line, availWidth).rawLines.length);
609499
+ return Math.max(
609500
+ 1,
609501
+ this.wrapPlainInputText(line, availWidth).rawLines.length
609502
+ );
609272
609503
  }
609273
609504
  /** Update _currentFooterHeight based on current input + suggestions. Returns true if height changed. */
609274
609505
  updateFooterHeight(termWidth) {
@@ -609344,10 +609575,16 @@ ${CONTENT_BG_SEQ}`);
609344
609575
  cursorRow: 0,
609345
609576
  // Align with bordered input layout: col1 is │, content starts at col2.
609346
609577
  // Keep this consistent with the wrapped path (+2) and positionAtInput().
609347
- cursorCol: Math.min(Math.max(1, termWidth - 1), this.promptWidth + cursorPos + 2)
609578
+ cursorCol: Math.min(
609579
+ Math.max(1, termWidth - 1),
609580
+ this.promptWidth + cursorPos + 2
609581
+ )
609348
609582
  };
609349
609583
  }
609350
- const { rawLines, charPositions } = this.wrapPlainInputText(fullLine, availWidth);
609584
+ const { rawLines, charPositions } = this.wrapPlainInputText(
609585
+ fullLine,
609586
+ availWidth
609587
+ );
609351
609588
  let cursorLineIdx = rawLines.length - 1;
609352
609589
  let cursorColInLine = cursorPos;
609353
609590
  for (let i2 = 0; i2 < charPositions.length; i2++) {
@@ -609366,7 +609603,10 @@ ${CONTENT_BG_SEQ}`);
609366
609603
  lines,
609367
609604
  cursorRow: cursorLineIdx,
609368
609605
  // +2 accounts for the left box border (│ at col 1) and the column after it
609369
- cursorCol: Math.min(Math.max(1, termWidth - 1), this.promptWidth + cursorColInLine + 2)
609606
+ cursorCol: Math.min(
609607
+ Math.max(1, termWidth - 1),
609608
+ this.promptWidth + cursorColInLine + 2
609609
+ )
609370
609610
  };
609371
609611
  }
609372
609612
  /** Set the DECSTBM scroll region to exclude the dynamic footer rows */
@@ -609543,7 +609783,8 @@ ${CONTENT_BG_SEQ}`);
609543
609783
  * If footer height changed, also updates DECSTBM and redraws full footer.
609544
609784
  */
609545
609785
  renderInputRowDuringStream(force = false) {
609546
- if (!this.active || this._resizing && !force || !this.inputStateProvider) return;
609786
+ if (!this.active || this._resizing && !force || !this.inputStateProvider)
609787
+ return;
609547
609788
  const rows = termRows();
609548
609789
  const w = getTermWidth();
609549
609790
  const oldFooterHeight = this._currentFooterHeight;
@@ -609992,7 +610233,11 @@ ${CONTENT_BG_SEQ}`);
609992
610233
  totalToolCalls: this._toolCalls,
609993
610234
  successfulToolCalls: this._successfulToolCalls,
609994
610235
  failedToolCalls: this._failedToolCalls,
609995
- toolCallBreakdown: this._toolCallBreakdown.map((t2) => ({ name: t2.name, count: t2.count, avgDurationMs: 0 })),
610236
+ toolCallBreakdown: this._toolCallBreakdown.map((t2) => ({
610237
+ name: t2.name,
610238
+ count: t2.count,
610239
+ avgDurationMs: 0
610240
+ })),
609996
610241
  contextWindowSize: m2.contextWindowSize,
609997
610242
  estimatedContextTokens: m2.estimatedContextTokens,
609998
610243
  peakContextTokens: m2.estimatedContextTokens,
@@ -610013,10 +610258,10 @@ ${CONTENT_BG_SEQ}`);
610013
610258
  // packages/cli/src/tui/tui-select.ts
610014
610259
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
610015
610260
  function ansi3(code8, text2) {
610016
- return isTTY2 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
610261
+ return isTTY3 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
610017
610262
  }
610018
610263
  function fg2563(code8, text2) {
610019
- return isTTY2 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
610264
+ return isTTY3 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
610020
610265
  }
610021
610266
  function stripAnsi3(s2) {
610022
610267
  return s2.replace(/\x1B\[[0-9;]*m/g, "");
@@ -610669,14 +610914,14 @@ ${tuiBgSeq()}`);
610669
610914
  }
610670
610915
  });
610671
610916
  }
610672
- var isTTY2, MENU_ACTIVE_GREEN_256, selectColors, nonInteractiveSelectSurface;
610917
+ var isTTY3, MENU_ACTIVE_GREEN_256, selectColors, nonInteractiveSelectSurface;
610673
610918
  var init_tui_select = __esm({
610674
610919
  "packages/cli/src/tui/tui-select.ts"() {
610675
610920
  "use strict";
610676
610921
  init_overlay_lock();
610677
610922
  init_theme();
610678
610923
  init_layout2();
610679
- isTTY2 = process.stdout.isTTY ?? false;
610924
+ isTTY3 = process.stdout.isTTY ?? false;
610680
610925
  MENU_ACTIVE_GREEN_256 = 154;
610681
610926
  selectColors = {
610682
610927
  blue: (t2) => fg2563(39, t2),
@@ -616152,7 +616397,7 @@ var init_format = __esm({
616152
616397
  import { existsSync as existsSync116 } from "node:fs";
616153
616398
  import { extname as extname17, resolve as resolve55 } from "node:path";
616154
616399
  function ansi4(code8, text2) {
616155
- return isTTY3 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
616400
+ return isTTY4 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
616156
616401
  }
616157
616402
  function stripAnsi4(s2) {
616158
616403
  return s2.replace(/\x1B\[[0-9;]*m/g, "");
@@ -616323,13 +616568,13 @@ function showDropPanel(opts) {
616323
616568
  render2();
616324
616569
  });
616325
616570
  }
616326
- var isTTY3, dc;
616571
+ var isTTY4, dc;
616327
616572
  var init_drop_panel = __esm({
616328
616573
  "packages/cli/src/tui/drop-panel.ts"() {
616329
616574
  "use strict";
616330
616575
  init_overlay_lock();
616331
616576
  init_layout2();
616332
- isTTY3 = process.stdout.isTTY ?? false;
616577
+ isTTY4 = process.stdout.isTTY ?? false;
616333
616578
  dc = {
616334
616579
  bold: (t2) => ansi4("1", t2),
616335
616580
  dim: (t2) => ansi4("38;5;250", t2),
@@ -618628,17 +618873,17 @@ import { tmpdir as tmpdir20 } from "node:os";
618628
618873
  import { join as join131 } from "node:path";
618629
618874
  import { execSync as execSync54 } from "node:child_process";
618630
618875
  function isNeovimActive() {
618631
- return _state !== null && !_state.cleanedUp;
618876
+ return _state2 !== null && !_state2.cleanedUp;
618632
618877
  }
618633
618878
  function isNeovimFocused() {
618634
- return _state?.focused ?? false;
618879
+ return _state2?.focused ?? false;
618635
618880
  }
618636
618881
  function refocusNeovim() {
618637
- if (!_state || _state.cleanedUp || _state.focused) return;
618638
- toggleFocus(_state);
618882
+ if (!_state2 || _state2.cleanedUp || _state2.focused) return;
618883
+ toggleFocus(_state2);
618639
618884
  }
618640
618885
  async function startNeovimMode(opts) {
618641
- if (_state && !_state.cleanedUp) {
618886
+ if (_state2 && !_state2.cleanedUp) {
618642
618887
  return "Neovim mode is already active. Use /neovim to exit first.";
618643
618888
  }
618644
618889
  let nvimPath;
@@ -618679,7 +618924,7 @@ async function startNeovimMode(opts) {
618679
618924
  const ptyCols = opts.cols;
618680
618925
  const topOffset = opts.topOffset ?? 0;
618681
618926
  const ptyRows = Math.max(5, opts.contentRows);
618682
- if (isTTY4) {
618927
+ if (isTTY5) {
618683
618928
  const L = layout();
618684
618929
  const bottomBound = L.contentBottom;
618685
618930
  process.stdout.write(
@@ -618728,7 +618973,7 @@ async function startNeovimMode(opts) {
618728
618973
  installedFilteredListeners: [],
618729
618974
  cleanedUp: false
618730
618975
  };
618731
- _state = state;
618976
+ _state2 = state;
618732
618977
  const toolbarBtns = [];
618733
618978
  {
618734
618979
  const btns = [
@@ -618748,7 +618993,7 @@ async function startNeovimMode(opts) {
618748
618993
  }
618749
618994
  }
618750
618995
  function renderToolbar() {
618751
- if (!isTTY4) return;
618996
+ if (!isTTY5) return;
618752
618997
  const L = layout();
618753
618998
  const hdrRow = L.headerContent;
618754
618999
  const fg2 = 252;
@@ -618809,7 +619054,7 @@ async function startNeovimMode(opts) {
618809
619054
  stdin.setRawMode(true);
618810
619055
  }
618811
619056
  stdin.resume();
618812
- if (isTTY4) {
619057
+ if (isTTY5) {
618813
619058
  process.stdout.write("\x1B[?1002h\x1B[?1006h");
618814
619059
  }
618815
619060
  state.stdinHandler = (data) => {
@@ -618876,12 +619121,12 @@ async function startNeovimMode(opts) {
618876
619121
  return null;
618877
619122
  }
618878
619123
  function stopNeovimMode() {
618879
- if (!_state || _state.cleanedUp) return Promise.resolve();
619124
+ if (!_state2 || _state2.cleanedUp) return Promise.resolve();
618880
619125
  try {
618881
- _state.pty?.write("\x1B:qa!\r");
619126
+ _state2.pty?.write("\x1B:qa!\r");
618882
619127
  } catch {
618883
619128
  }
618884
- const s2 = _state;
619129
+ const s2 = _state2;
618885
619130
  return new Promise((resolve70) => {
618886
619131
  setTimeout(() => {
618887
619132
  if (s2 && !s2.cleanedUp) {
@@ -618892,18 +619137,18 @@ function stopNeovimMode() {
618892
619137
  });
618893
619138
  }
618894
619139
  function writeToNeovimOutput(text2) {
618895
- if (!_state || _state.cleanedUp || !_state.nvim || !_state.outputChanId) return;
619140
+ if (!_state2 || _state2.cleanedUp || !_state2.nvim || !_state2.outputChanId) return;
618896
619141
  const normalized = text2.replace(/(?<!\r)\n/g, "\r\n");
618897
- _state.nvim.request("nvim_chan_send", [_state.outputChanId, normalized]).catch(() => {
619142
+ _state2.nvim.request("nvim_chan_send", [_state2.outputChanId, normalized]).catch(() => {
618898
619143
  });
618899
619144
  }
618900
619145
  async function notifyNeovimFileChange(filePath) {
618901
- if (!_state || _state.cleanedUp || !_state.nvim) return;
619146
+ if (!_state2 || _state2.cleanedUp || !_state2.nvim) return;
618902
619147
  try {
618903
- await _state.nvim.command("checktime");
619148
+ await _state2.nvim.command("checktime");
618904
619149
  if (filePath) {
618905
619150
  const escaped = filePath.replace(/'/g, "''");
618906
- await _state.nvim.command(
619151
+ await _state2.nvim.command(
618907
619152
  `if bufexists('${escaped}') | execute 'buffer ' . bufnr('${escaped}') | endif`
618908
619153
  );
618909
619154
  }
@@ -618911,10 +619156,10 @@ async function notifyNeovimFileChange(filePath) {
618911
619156
  }
618912
619157
  }
618913
619158
  function resizeNeovim(cols, contentRows) {
618914
- if (!_state || _state.cleanedUp || !_state.pty) return;
619159
+ if (!_state2 || _state2.cleanedUp || !_state2.pty) return;
618915
619160
  const rows = Math.max(5, contentRows);
618916
619161
  try {
618917
- _state.pty.resize(cols, rows);
619162
+ _state2.pty.resize(cols, rows);
618918
619163
  } catch {
618919
619164
  }
618920
619165
  }
@@ -619089,7 +619334,7 @@ function doCleanup(state) {
619089
619334
  } catch {
619090
619335
  }
619091
619336
  }
619092
- _state = null;
619337
+ _state2 = null;
619093
619338
  process.stdout.write(
619094
619339
  `\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?1004l\x1B[?2004l\x1B[1;${termRows()}r`
619095
619340
  // reset scroll region to full terminal
@@ -619108,16 +619353,16 @@ function doCleanup(state) {
619108
619353
  }
619109
619354
  state.opts.onExit?.();
619110
619355
  }
619111
- var isTTY4, PTY_MODE_ENABLE_RE, STDIN_MOUSE_FOCUS_RE, _state;
619356
+ var isTTY5, PTY_MODE_ENABLE_RE, STDIN_MOUSE_FOCUS_RE, _state2;
619112
619357
  var init_neovim_mode = __esm({
619113
619358
  "packages/cli/src/tui/neovim-mode.ts"() {
619114
619359
  "use strict";
619115
619360
  init_setup();
619116
619361
  init_layout2();
619117
- isTTY4 = process.stdout.isTTY ?? false;
619362
+ isTTY5 = process.stdout.isTTY ?? false;
619118
619363
  PTY_MODE_ENABLE_RE = /\x1B\[\?(?:1004|2004)h/g;
619119
619364
  STDIN_MOUSE_FOCUS_RE = /\x1B\[<[\d;]+[Mm]|\x1B\[M[\s\S]{3}|\x1B\[[IO]|\x1BO[ABCD]/g;
619120
- _state = null;
619365
+ _state2 = null;
619121
619366
  }
619122
619367
  });
619123
619368
 
@@ -644051,7 +644296,7 @@ function setCarouselWriter(writer) {
644051
644296
  chromeWrite2 = writer;
644052
644297
  }
644053
644298
  function fg(code8, text2) {
644054
- return isTTY5 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
644299
+ return isTTY6 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
644055
644300
  }
644056
644301
  function displayWidth(str) {
644057
644302
  let w = 0;
@@ -644089,12 +644334,12 @@ function createRow(phraseIndices, speed, direction, bank2) {
644089
644334
  const phrases = phraseIndices.map((i2) => bank2[i2 % bank2.length]);
644090
644335
  return { phrases, offset: 0, speed, direction, renderedPlain: "" };
644091
644336
  }
644092
- var isTTY5, chromeWrite2, PHRASES, Carousel;
644337
+ var isTTY6, chromeWrite2, PHRASES, Carousel;
644093
644338
  var init_carousel = __esm({
644094
644339
  "packages/cli/src/tui/carousel.ts"() {
644095
644340
  "use strict";
644096
644341
  init_layout2();
644097
- isTTY5 = process.stdout.isTTY ?? false;
644342
+ isTTY6 = process.stdout.isTTY ?? false;
644098
644343
  chromeWrite2 = ((data) => {
644099
644344
  process.stdout.write(data);
644100
644345
  });
@@ -644206,7 +644451,7 @@ var init_carousel = __esm({
644206
644451
  * Sets scroll region to row 5+ for all content/readline.
644207
644452
  */
644208
644453
  start() {
644209
- if (!isTTY5) return 0;
644454
+ if (!isTTY6) return 0;
644210
644455
  this.started = true;
644211
644456
  setHeaderHeight(this.reservedRows);
644212
644457
  const L = layout();
@@ -644238,7 +644483,7 @@ var init_carousel = __esm({
644238
644483
  * Row 4 is left blank as a separator.
644239
644484
  */
644240
644485
  renderFrame() {
644241
- if (!isTTY5) return;
644486
+ if (!isTTY6) return;
644242
644487
  const L = layout();
644243
644488
  let buf = "\x1B7";
644244
644489
  buf += "\x1B[?7l";
@@ -644315,7 +644560,7 @@ var init_carousel = __esm({
644315
644560
  process.stdout.removeListener("resize", this.resizeHandler);
644316
644561
  this.resizeHandler = null;
644317
644562
  }
644318
- if (!isTTY5 || !this.started) return;
644563
+ if (!isTTY6 || !this.started) return;
644319
644564
  const L = layout();
644320
644565
  let buf = "\x1B7";
644321
644566
  for (let i2 = 0; i2 < this.reservedRows; i2++) {
@@ -644551,13 +644796,13 @@ function createAnimatedBanner(id, name10, frameBuilders, frameDurationMs, author
644551
644796
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
644552
644797
  };
644553
644798
  }
644554
- var isTTY6, chromeWrite3, MNEMONIC_ADJECTIVES, MNEMONIC_NOUNS, BannerRenderer;
644799
+ var isTTY7, chromeWrite3, MNEMONIC_ADJECTIVES, MNEMONIC_NOUNS, BannerRenderer;
644555
644800
  var init_banner = __esm({
644556
644801
  "packages/cli/src/tui/banner.ts"() {
644557
644802
  "use strict";
644558
644803
  init_theme();
644559
644804
  init_layout2();
644560
- isTTY6 = process.stdout.isTTY ?? false;
644805
+ isTTY7 = process.stdout.isTTY ?? false;
644561
644806
  chromeWrite3 = ((data) => {
644562
644807
  process.stdout.write(data);
644563
644808
  });
@@ -644719,7 +644964,7 @@ var init_banner = __esm({
644719
644964
  * Returns the number of rows reserved (3 banner + 1 separator = 4).
644720
644965
  */
644721
644966
  start() {
644722
- if (!isTTY6 || !this.currentDesign) return 0;
644967
+ if (!isTTY7 || !this.currentDesign) return 0;
644723
644968
  this.renderCurrentFrame();
644724
644969
  this._resizeHandler = () => {
644725
644970
  setTermSize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
@@ -644760,7 +645005,7 @@ var init_banner = __esm({
644760
645005
  }
644761
645006
  /** Render the current frame into the top 3 rows (public for refresh callbacks) */
644762
645007
  renderCurrentFrame() {
644763
- if (!isTTY6 || !this.currentDesign) return;
645008
+ if (!isTTY7 || !this.currentDesign) return;
644764
645009
  const frame = this.currentDesign.frames[this.currentFrame];
644765
645010
  if (!frame) return;
644766
645011
  this.width = termCols();
@@ -645164,175 +645409,6 @@ var init_carousel_descriptors = __esm({
645164
645409
  }
645165
645410
  });
645166
645411
 
645167
- // packages/cli/src/tui/syntax-highlight.ts
645168
- var syntax_highlight_exports = {};
645169
- __export(syntax_highlight_exports, {
645170
- detectLanguage: () => detectLanguage2,
645171
- getHighlightStatus: () => getHighlightStatus,
645172
- highlightBlock: () => highlightBlock,
645173
- highlightCode: () => highlightCode,
645174
- isAvailable: () => isAvailable,
645175
- prewarm: () => prewarm
645176
- });
645177
- function highlightingDisabled() {
645178
- return !isTTY7 || noColorEnv || disableEnv;
645179
- }
645180
- async function loadHighlighter() {
645181
- if (_state2.attempted) return _state2.fn;
645182
- _state2.attempted = true;
645183
- if (highlightingDisabled()) {
645184
- _state2.reason = !isTTY7 ? "non-tty" : noColorEnv ? "NO_COLOR set" : "OMNIUS_TUI_HIGHLIGHT=0";
645185
- return null;
645186
- }
645187
- try {
645188
- const { createRequire: createRequire10 } = await import("node:module");
645189
- const req3 = createRequire10(import.meta.url);
645190
- let resolved = null;
645191
- try {
645192
- resolved = req3.resolve("cli-highlight");
645193
- } catch {
645194
- _state2.reason = "cli-highlight not installed";
645195
- return null;
645196
- }
645197
- const mod3 = await import(resolved).catch(() => null);
645198
- if (!mod3) {
645199
- _state2.reason = "cli-highlight failed to load";
645200
- return null;
645201
- }
645202
- const m2 = mod3;
645203
- const candidate = m2.highlight ?? m2.default ?? null;
645204
- if (typeof candidate !== "function") {
645205
- _state2.reason = "cli-highlight export shape unrecognized";
645206
- return null;
645207
- }
645208
- _state2.fn = candidate;
645209
- return candidate;
645210
- } catch (err) {
645211
- _state2.reason = `import threw: ${err?.message ?? String(err)}`;
645212
- return null;
645213
- }
645214
- }
645215
- function loadHighlighterSync() {
645216
- if (highlightingDisabled()) return null;
645217
- return _state2.fn;
645218
- }
645219
- async function prewarm() {
645220
- await loadHighlighter();
645221
- }
645222
- function isAvailable() {
645223
- if (highlightingDisabled()) return false;
645224
- return _state2.attempted && _state2.fn !== null;
645225
- }
645226
- function getHighlightStatus() {
645227
- return {
645228
- available: isAvailable(),
645229
- attempted: _state2.attempted,
645230
- reason: _state2.reason,
645231
- isTTY: isTTY7,
645232
- noColor: noColorEnv,
645233
- disabledByEnv: disableEnv
645234
- };
645235
- }
645236
- function highlightCode(code8, language) {
645237
- if (!code8) return code8;
645238
- const fn = loadHighlighterSync();
645239
- if (!fn) return code8;
645240
- const lang = (language ?? detectLanguage2(code8) ?? "").trim();
645241
- try {
645242
- if (lang) {
645243
- return fn(code8, { language: lang, ignoreIllegals: true });
645244
- }
645245
- return fn(code8, { ignoreIllegals: true });
645246
- } catch {
645247
- return code8;
645248
- }
645249
- }
645250
- function detectLanguage2(text2) {
645251
- if (!text2) return null;
645252
- const trimmed = text2.trimStart();
645253
- const shebang = trimmed.match(/^#!\s*\/[^\n]+/);
645254
- if (shebang) {
645255
- const sb = shebang[0];
645256
- if (/python/.test(sb)) return "python";
645257
- if (/(?:^|[\s/])(?:bash|sh|zsh)\b/.test(sb)) return "bash";
645258
- if (/node/.test(sb)) return "javascript";
645259
- if (/ruby/.test(sb)) return "ruby";
645260
- if (/perl/.test(sb)) return "perl";
645261
- }
645262
- if (/^[\s\n]*[{[]/.test(trimmed)) {
645263
- try {
645264
- JSON.parse(trimmed);
645265
- return "json";
645266
- } catch {
645267
- }
645268
- }
645269
- if (/^[-a-zA-Z_][\w-]*:\s/.test(trimmed) && /\n[-a-zA-Z_][\w-]*:\s/.test(trimmed)) {
645270
- return "yaml";
645271
- }
645272
- if (/^(?:async def |def |class |import |from )/.test(trimmed) && /(?::\s*$|->|self\b)/m.test(trimmed)) {
645273
- return "python";
645274
- }
645275
- if (/^(?:import |export |const |let |var |function |class |interface |type |async )/.test(trimmed)) {
645276
- if (/(:\s*(?:string|number|boolean|any|unknown|void)\b|\binterface\b|\btype\s+\w+\s*=)/.test(trimmed)) {
645277
- return "typescript";
645278
- }
645279
- return "javascript";
645280
- }
645281
- if (/(?:^|\n)\s*(?:fn |use |let mut |impl |struct |enum |trait )/.test(trimmed)) {
645282
- return "rust";
645283
- }
645284
- if (/(?:^package \w+|\nfunc \w+\s*\()/.test(trimmed)) {
645285
- return "go";
645286
- }
645287
- if (/^\s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i.test(trimmed)) {
645288
- return "sql";
645289
- }
645290
- if (/^[\s\n]*<(?:!DOCTYPE|html|\?xml|\w+)/i.test(trimmed)) {
645291
- return "html";
645292
- }
645293
- if (/^(?:---|\+\+\+|@@|diff )/.test(trimmed)) {
645294
- return "diff";
645295
- }
645296
- if (/^\s*(?:\$\s|sudo |apt |brew |npm |pnpm |yarn |git |docker |kubectl |curl |wget )/.test(trimmed)) {
645297
- return "bash";
645298
- }
645299
- return null;
645300
- }
645301
- function highlightBlock(code8, language) {
645302
- if (!code8) return [""];
645303
- const fn = loadHighlighterSync();
645304
- if (!fn) return code8.split("\n");
645305
- const lang = (language ?? detectLanguage2(code8) ?? "").trim();
645306
- try {
645307
- const out = lang ? fn(code8, { language: lang, ignoreIllegals: true }) : fn(code8, { ignoreIllegals: true });
645308
- const lines = out.split("\n");
645309
- const inputLines = code8.split("\n");
645310
- if (lines.length === inputLines.length) return lines;
645311
- if (lines.length < inputLines.length) {
645312
- while (lines.length < inputLines.length) lines.push("");
645313
- } else {
645314
- lines.length = inputLines.length;
645315
- }
645316
- return lines;
645317
- } catch {
645318
- return code8.split("\n");
645319
- }
645320
- }
645321
- var isTTY7, noColorEnv, disableEnv, _state2;
645322
- var init_syntax_highlight = __esm({
645323
- "packages/cli/src/tui/syntax-highlight.ts"() {
645324
- "use strict";
645325
- isTTY7 = process.stdout?.isTTY ?? false;
645326
- noColorEnv = process.env["NO_COLOR"] !== void 0 && process.env["NO_COLOR"] !== "";
645327
- disableEnv = process.env["OMNIUS_TUI_HIGHLIGHT"] === "0";
645328
- _state2 = {
645329
- attempted: false,
645330
- fn: null,
645331
- reason: ""
645332
- };
645333
- }
645334
- });
645335
-
645336
645412
  // packages/cli/src/tui/stream-renderer.ts
645337
645413
  function fg2564(code8, text2) {
645338
645414
  return isTTY8 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
@@ -704310,28 +704386,32 @@ ${entry.fullContent}`
704310
704386
  }
704311
704387
  if (lm.intervention) {
704312
704388
  contentWrite(() => {
704313
- const lines = [`⚠ ${lm.intervention}`];
704314
- if (lm.details && showAdversary) {
704315
- const det = String(lm.details);
704316
- lines.push(...det.split("\n").filter(Boolean));
704317
- }
704318
- renderBoxedBlock({
704319
- title: "Adversary",
704320
- lines,
704321
- kind: "plain"
704322
- });
704389
+ renderWarning(`Adversary: ${lm.intervention}`);
704323
704390
  });
704324
704391
  } else if (lm.details && showAdversary) {
704325
704392
  contentWrite(() => {
704326
- renderBoxedBlock({
704327
- title: "Adversary",
704328
- lines: String(lm.details).split("\n").filter(Boolean),
704329
- kind: "dim"
704330
- });
704393
+ renderInfo(
704394
+ `Adversary details: ${String(lm.details).split("\n").filter(Boolean).join(" | ")}`
704395
+ );
704331
704396
  });
704332
704397
  }
704333
704398
  }
704334
704399
  break;
704400
+ case "adversary_reaction":
704401
+ if (event.adversary) {
704402
+ const adv = event.adversary;
704403
+ const conf = adv.confidence != null ? ` (${Math.round(adv.confidence * 100)}%)` : "";
704404
+ const text2 = adv.shortText + conf;
704405
+ contentWrite(() => {
704406
+ renderWarning(`Adversary ${adv.class}: ${text2}`);
704407
+ });
704408
+ if (adv.details) {
704409
+ adversaryBuffer.push(adv.details);
704410
+ if (adversaryBuffer.length > 50)
704411
+ adversaryBuffer.splice(0, adversaryBuffer.length - 50);
704412
+ }
704413
+ }
704414
+ break;
704335
704415
  }
704336
704416
  });
704337
704417
  try {
@@ -0,0 +1,230 @@
1
+ # Unnecessary Causes of Delays Between Agent Actions
2
+
3
+ Analysis of `packages/orchestrator/src/` (95 files) — identified delay sources ranked by impact.
4
+
5
+ ---
6
+
7
+ ## HIGH IMPACT
8
+
9
+ ### 1. `streaming-executor.ts:171-192` — `waitAll()` busy-poll loop
10
+
11
+ ```typescript
12
+ async waitAll(): Promise<void> {
13
+ while (true) {
14
+ const pending = Array.from(this.tools.values()).filter(
15
+ e => e.state === "queued" || e.state === "executing"
16
+ );
17
+ if (pending.length === 0) break;
18
+ const executing = pending.filter(e => e.promise);
19
+ if (executing.length > 0) {
20
+ await Promise.allSettled(executing.map(e => e.promise!));
21
+ this.processQueue();
22
+ } else {
23
+ this.processQueue();
24
+ await new Promise(r => setTimeout(r, 1)); // ← 1ms spin loop
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ **Problem:** When tools are queued but none have started (no `promise`), the loop spins with 1ms `setTimeout` between `processQueue()` calls. Each iteration costs at least 1ms of wall-clock delay. With many queued-but-blocked tools, this adds up.
31
+
32
+ **Fix:** Replace with Promise-based notification (event emitter or `AbortController`-based wait) so the loop yields until a tool completes or a new tool is enqueued.
33
+
34
+ ---
35
+
36
+ ### 2. `ollama-pool.ts:850-869` — Instance readiness probe loop
37
+
38
+ ```typescript
39
+ await new Promise((r) => setTimeout(r, 500)); // ← 500ms between probes
40
+ ```
41
+
42
+ **Problem:** When spawning a new Ollama instance, the code polls `/api/version` every **500ms** with a 2-second abort timeout. This adds **500-2000ms** of delay per new model instance. If the pool is empty and a model isn't loaded, every first request pays this cost.
43
+
44
+ **Fix:** Use exponential backoff (100ms → 200ms → 400ms) or a readiness event emitter instead of fixed polling.
45
+
46
+ ---
47
+
48
+ ### 3. `cascadeBackend.ts:105-156` — Sequential fallback chain
49
+
50
+ ```typescript
51
+ const result = await backend.chatCompletion(request);
52
+ // On failure → try newBackend.chatCompletion(request);
53
+ // On failure → try primaryBackend.chatCompletion({ timeoutMs: 10_000 });
54
+ ```
55
+
56
+ **Problem:** The cascade backend tries multiple backends in sequence. Each failure triggers a retry on the next backend. If the first backend is slow to fail (not crash), the full timeout (10s+) is paid before the fallback activates.
57
+
58
+ **Fix:** Start all backends simultaneously with `Promise.race()` and cancel losers on first success.
59
+
60
+ ---
61
+
62
+ ## MEDIUM IMPACT
63
+
64
+ ### 4. `ollama-pool.ts:1190` — Unbounded slot waiter queue
65
+
66
+ ```typescript
67
+ await new Promise<void>((resolve) => this.slotWaiters.push(resolve));
68
+ ```
69
+
70
+ **Problem:** When all GPU slots are occupied, new requests queue as promises in `slotWaiters`. They only resolve when a slot frees up — but there's no timeout or progress feedback. Under heavy load, this can stall indefinitely.
71
+
72
+ **Fix:** Add a configurable timeout (e.g., 30s) and reject with a clear "no GPU available" error.
73
+
74
+ ---
75
+
76
+ ### 5. `ollama-pool.ts:1336` — GPU detection on every acquire
77
+
78
+ ```typescript
79
+ const rawGpus = await this.gpuDetector();
80
+ ```
81
+
82
+ **Problem:** GPU detection runs on every placement decision. If `gpuDetector()` calls `nvidia-smi` or similar system commands, this adds **10-100ms** per request.
83
+
84
+ **Fix:** Cache GPU detection results with a TTL (e.g., 30s). GPU topology rarely changes at runtime.
85
+
86
+ ---
87
+
88
+ ### 6. `tool-batching.ts:247-253` — Forced serial execution of non-concurrent tools
89
+
90
+ ```typescript
91
+ for (const call of batch.calls) {
92
+ results.push(await executeFn(call));
93
+ }
94
+ ```
95
+
96
+ **Problem:** Write/shell tools are forced to run serially. If the agent produces 3+ write tools in one turn, they queue sequentially. No parallelism for independent writes.
97
+
98
+ **Fix:** Add a write-conflict analyzer (e.g., file-level locking) to allow parallel writes to different files.
99
+
100
+ ---
101
+
102
+ ### 7. `steeringIntake.ts:97` — 15s steering timeout
103
+
104
+ ```typescript
105
+ timeoutMs = 15_000,
106
+ ```
107
+
108
+ **Problem:** Steering intake has a 15-second timeout. If the model is slow or the prompt is large, this adds a full 15s delay before the steering response arrives.
109
+
110
+ **Fix:** Reduce to 5-8s for steering (which is advisory, not critical) or make it non-blocking with a best-effort result.
111
+
112
+ ---
113
+
114
+ ### 8. `verifierRunner.ts:161` — 60s test timeout
115
+
116
+ ```typescript
117
+ timeout: 60_000,
118
+ ```
119
+
120
+ **Problem:** Test execution has a 60-second timeout. If tests hang or are slow, this blocks the entire agent loop.
121
+
122
+ **Fix:** Add a per-test timeout and a total timeout with early termination on repeated failures.
123
+
124
+ ---
125
+
126
+ ## LOW-MEDIUM IMPACT
127
+
128
+ ### 9. `ollama-pool.ts:1236,1257` — VRAM estimation per model
129
+
130
+ ```typescript
131
+ const vramNeededMB = await this.estimateModelVramMB(model);
132
+ ```
133
+
134
+ **Problem:** VRAM estimation runs before every spawn/placement. If it involves model metadata lookups or API calls, this adds latency.
135
+
136
+ **Fix:** Cache VRAM estimates keyed by model name with a TTL.
137
+
138
+ ---
139
+
140
+ ### 10. `streaming-executor.ts:21-26` — `stableValueKey` deep serialization
141
+
142
+ ```typescript
143
+ function stableValueKey(value: unknown): string {
144
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
145
+ if (Array.isArray(value)) return `[${value.map(stableValueKey).join(",")}]`;
146
+ const record = value as Record<string, unknown>;
147
+ return `{${Object.keys(record).sort().map((key) => ...).join(",")}}`;
148
+ }
149
+ ```
150
+
151
+ **Problem:** Deep serialization of tool arguments for deduplication. For large args (e.g., file contents), this adds O(n) serialization cost per tool call.
152
+
153
+ **Fix:** Add a size cap (e.g., 10KB) — if the value exceeds it, use a hash instead of deep serialization.
154
+
155
+ ---
156
+
157
+ ### 11. `streaming-executor.ts:263-291` — Duplicate detection overhead
158
+
159
+ ```typescript
160
+ private findPriorEquivalent(entry: StreamingToolEntry): StreamingToolEntry | null
161
+ private cloneDuplicateResult(entry: StreamingToolEntry): boolean
162
+ private mirrorPriorEquivalent(entry: StreamingToolEntry): boolean
163
+ ```
164
+
165
+ **Problem:** Every tool call is checked against all prior calls for equivalence. This is O(n²) in the number of tools per turn.
166
+
167
+ **Fix:** Use a hash-based index (tool name + arg hash) for O(1) lookup instead of linear scan.
168
+
169
+ ---
170
+
171
+ ### 12. `ollama-pool.ts:1697` — Stale process cleanup timer
172
+
173
+ ```typescript
174
+ const handle = setTimeout(async () => {
175
+ const { cleanupStaleOllamaProcesses } = await import("./ollama-pool-cleanup.js");
176
+ const report = await cleanupStaleOllamaProcesses({ ... });
177
+ }, ...);
178
+ ```
179
+
180
+ **Problem:** Cleanup runs as a deferred `setTimeout` — adds latency before stale processes are actually cleaned up.
181
+
182
+ **Fix:** Run cleanup eagerly when a slot is freed, not on a timer.
183
+
184
+ ---
185
+
186
+ ### 13. `ollama-pool.ts:298,304` — `execSync` with 3s timeout
187
+
188
+ ```typescript
189
+ { encoding: "utf8", timeout: 3_000 },
190
+ ```
191
+
192
+ **Problem:** Synchronous child processes block the event loop. If the command takes the full 3s, the entire process stalls.
193
+
194
+ **Fix:** Use `execFile` with `Promise` wrapper or `spawn` with timeout signal.
195
+
196
+ ---
197
+
198
+ ### 14. `preflightSnapshot.ts:284,311` — Multiple 1.5s probe timeouts
199
+
200
+ ```typescript
201
+ timeout: 1500
202
+ ```
203
+
204
+ **Problem:** Preflight checks run multiple probes, each with 1.5s timeout. If multiple probes fail, this adds 3-6s of startup delay.
205
+
206
+ **Fix:** Run probes in parallel with `Promise.allSettled()` and use the first success.
207
+
208
+ ---
209
+
210
+ ### 15. `tool-batching.ts:212-240` — Concurrency limit on reads
211
+
212
+ ```typescript
213
+ export async function withConcurrencyLimit<T>(...) {
214
+ // Uses a limiter to cap parallel reads
215
+ }
216
+ ```
217
+
218
+ **Problem:** Concurrent-safe tools (reads) are limited by a concurrency cap. If the limit is too low, parallel reads are serialized unnecessarily.
219
+
220
+ **Fix:** Make the concurrency limit configurable and increase the default (e.g., from 2 to 8).
221
+
222
+ ---
223
+
224
+ ## Summary: Top 3 Fixes for Immediate Impact
225
+
226
+ | Priority | File | Change | Expected Savings |
227
+ |----------|------|--------|------------------|
228
+ | 1 | `streaming-executor.ts` | Replace 1ms spin loop with Promise notification | Eliminates busy-poll latency entirely |
229
+ | 2 | `ollama-pool.ts` | Cache GPU detection with 30s TTL | Eliminates 10-100ms per request |
230
+ | 3 | `cascadeBackend.ts` | Parallelize backend fallbacks with `Promise.race()` | Eliminates cascading timeout accumulation |
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.266",
3
+ "version": "1.0.268",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.266",
9
+ "version": "1.0.268",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.266",
3
+ "version": "1.0.268",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",