omnius 1.0.3 → 1.0.4

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
@@ -7852,7 +7852,6 @@ var init_nexus = __esm({
7852
7852
  * Usage: node nexus-daemon.mjs <nexus-dir> <agent-name> [agent-type]
7853
7853
  */
7854
7854
 
7855
- import { NexusClient } from 'open-agents-nexus';
7856
7855
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync, appendFileSync, watch as fsWatch } from 'node:fs';
7857
7856
  import { join } from 'node:path';
7858
7857
  import { homedir, hostname } from 'node:os';
@@ -7930,6 +7929,40 @@ const globalKeyDir = join(homedir(), '.omnius');
7930
7929
  const globalKeyPath = join(globalKeyDir, 'identity.key');
7931
7930
  const projectKeyPath = join(nexusDir, 'identity.key');
7932
7931
  const keyPath = existsSync(globalKeyPath) ? globalKeyPath : projectKeyPath;
7932
+
7933
+ function formatStartupError(err) {
7934
+ if (!err) return 'Unknown startup error';
7935
+ var msg = err && err.stack ? String(err.stack) : String(err && err.message ? err.message : err);
7936
+ return msg.replace(/\\x1B\\[[0-?]*[ -/]*[@-~]/g, '').slice(0, 4000);
7937
+ }
7938
+
7939
+ async function loadNexusClientClass() {
7940
+ try {
7941
+ var mod = await import('open-agents-nexus');
7942
+ if (!mod || !mod.NexusClient) throw new Error('open-agents-nexus did not export NexusClient');
7943
+ return mod.NexusClient;
7944
+ } catch (err) {
7945
+ var msg = 'Failed to load open-agents-nexus: ' + formatStartupError(err);
7946
+ try { appendFileSync(join(nexusDir, 'daemon.err'), 'Nexus daemon dependency load failed: ' + msg + '\\n'); } catch {}
7947
+ try {
7948
+ writeFileSync(statusFile, JSON.stringify({
7949
+ pid: process.pid,
7950
+ connected: false,
7951
+ peerId: null,
7952
+ agentName: agentName,
7953
+ agentType: agentType,
7954
+ rooms: [],
7955
+ capabilities: [],
7956
+ blockedPeers: [],
7957
+ connectedAt: null,
7958
+ error: msg,
7959
+ }, null, 2));
7960
+ } catch {}
7961
+ process.exit(1);
7962
+ }
7963
+ }
7964
+
7965
+ const NexusClient = await loadNexusClientClass();
7933
7966
  var nexusOpts = {
7934
7967
  keyStorePath: keyPath,
7935
7968
  agentName,
@@ -13188,6 +13221,21 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
13188
13221
  res((stdout || "").trim());
13189
13222
  });
13190
13223
  });
13224
+ const isNativeDataChannelError = (text) => /node-datachannel|node_datachannel\.node|datachannel\/dist/i.test(text);
13225
+ const tryRepairNodeDataChannel = async () => {
13226
+ const cmds = existsSync17(join21(this.repoRoot, "pnpm-lock.yaml")) ? ["pnpm rebuild node-datachannel 2>&1", "npm rebuild node-datachannel 2>&1"] : ["npm rebuild node-datachannel 2>&1", "pnpm rebuild node-datachannel 2>&1"];
13227
+ const failures = [];
13228
+ for (const cmd of cmds) {
13229
+ try {
13230
+ await execAsync3(cmd, { cwd: this.repoRoot, timeout: 18e4 });
13231
+ return `Repaired node-datachannel native addon with: ${cmd.replace(" 2>&1", "")}`;
13232
+ } catch (err) {
13233
+ failures.push(`${cmd.replace(" 2>&1", "")}: ${err?.message ?? String(err)}`.slice(0, 500));
13234
+ }
13235
+ }
13236
+ return `node-datachannel native addon repair failed:
13237
+ ${failures.join("\n")}`;
13238
+ };
13191
13239
  try {
13192
13240
  const nexusPkg = join21(nodeModulesDir, "open-agents-nexus", "package.json");
13193
13241
  if (existsSync17(nexusPkg)) {
@@ -13294,7 +13342,17 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
13294
13342
  errTail = (await readFile9(daemonErrPath, "utf8")).slice(-300);
13295
13343
  } catch {
13296
13344
  }
13297
- return `Nexus daemon failed to connect: ${status.error}${errTail ? "\n" + errTail : ""}`;
13345
+ const statusError = String(status.error ?? "");
13346
+ if (!args.__native_repair_attempted && isNativeDataChannelError(`${statusError}
13347
+ ${errTail}`)) {
13348
+ const repair = await tryRepairNodeDataChannel();
13349
+ if (/^Repaired /.test(repair)) {
13350
+ return this.doConnect({ ...args, __native_repair_attempted: true });
13351
+ }
13352
+ return `Nexus daemon failed to connect: ${statusError}
13353
+ ${repair}${errTail ? "\n" + errTail : ""}`;
13354
+ }
13355
+ return `Nexus daemon failed to connect: ${statusError}${errTail ? "\n" + errTail : ""}`;
13298
13356
  }
13299
13357
  if (status.connected && status.peerId) {
13300
13358
  return [
@@ -13320,6 +13378,17 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
13320
13378
  try {
13321
13379
  earlyOutput = (await readFile9(daemonLogPath, "utf8")).slice(-500);
13322
13380
  } catch {
13381
+ }
13382
+ const earlyCombined = `${earlyError}
13383
+ ${earlyOutput}`;
13384
+ if (!args.__native_repair_attempted && isNativeDataChannelError(earlyCombined)) {
13385
+ const repair = await tryRepairNodeDataChannel();
13386
+ if (/^Repaired /.test(repair)) {
13387
+ return this.doConnect({ ...args, __native_repair_attempted: true });
13388
+ }
13389
+ return `Daemon failed to start.
13390
+ ${repair}
13391
+ ${earlyError ? "\n" + earlyError : ""}${earlyOutput ? "\n" + earlyOutput : ""}`;
13323
13392
  }
13324
13393
  if (pid) {
13325
13394
  return `Daemon spawned (pid: ${pid}) but still connecting. Check status in a moment.${earlyError ? "\nStderr: " + earlyError.slice(0, 200) : ""}`;
@@ -549721,27 +549790,27 @@ var init_theme = __esm({
549721
549790
  },
549722
549791
  branding: {
549723
549792
  mode: "branding",
549724
- bg: 0,
549725
- // black
549726
- accent: 178,
549727
- // #ffae00 yellow
549728
- textPrimary: 178,
549729
- // #ffae00 yellow
549793
+ bg: -1,
549794
+ // terminal default background
549795
+ accent: 37,
549796
+ // teal
549797
+ textPrimary: 37,
549798
+ // teal
549730
549799
  textDim: 240,
549731
549800
  // grey
549732
- boxColor: 178
549733
- // #ffae00 yellow
549801
+ boxColor: 37
549802
+ // teal
549734
549803
  },
549735
549804
  custom: {
549736
549805
  mode: "custom",
549737
- bg: 0,
549738
- accent: 178,
549806
+ bg: -1,
549807
+ accent: 37,
549739
549808
  textPrimary: 252,
549740
549809
  textDim: 245,
549741
549810
  boxColor: 252
549742
549811
  }
549743
549812
  };
549744
- _config2 = { ...PRESETS.branding };
549813
+ _config2 = { ...PRESETS.system };
549745
549814
  }
549746
549815
  });
549747
549816
 
@@ -551291,10 +551360,10 @@ var init_render = __esm({
551291
551360
  warn: (t2) => fg256(214, t2),
551292
551361
  /** Success text — green for confirmations */
551293
551362
  ok: (t2) => fg256(78, t2),
551294
- /** Accent — yellow (178) matching header/banner */
551295
- accent: (t2) => fg256(178, t2),
551296
- /** Muted accent — dim yellow for secondary accent */
551297
- accentDim: (t2) => fg256(136, t2)
551363
+ /** Accent — teal matching header/banner */
551364
+ accent: (t2) => fg256(37, t2),
551365
+ /** Muted accent — dim teal for secondary accent */
551366
+ accentDim: (t2) => fg256(30, t2)
551298
551367
  };
551299
551368
  pastel = {
551300
551369
  pink: (t2) => fg256(218, t2),
@@ -551402,11 +551471,11 @@ var init_render = __esm({
551402
551471
  // User interaction
551403
551472
  ask_user: "Ask user"
551404
551473
  };
551405
- accent = (t2) => fg256(178, t2);
551406
- accentBright = (t2) => fg256(220, t2);
551407
- accentDim = (t2) => fg256(136, t2);
551408
- accentWarm = (t2) => fg256(214, t2);
551409
- accentSoft = (t2) => fg256(180, t2);
551474
+ accent = (t2) => fg256(37, t2);
551475
+ accentBright = (t2) => fg256(44, t2);
551476
+ accentDim = (t2) => fg256(30, t2);
551477
+ accentWarm = (t2) => fg256(43, t2);
551478
+ accentSoft = (t2) => fg256(80, t2);
551410
551479
  TOOL_COLORS = {
551411
551480
  file_read: accentSoft,
551412
551481
  file_write: accentWarm,
@@ -557646,8 +557715,8 @@ var init_braille_spinner = __esm({
557646
557715
  return (x * x * 31 + x * 17 + 59) % 97 / 97;
557647
557716
  };
557648
557717
  MOOD_RAMPS = {
557649
- neutral: [237, 94, 130, 136, 172, 172, 178, 178, 214],
557650
- // default amber→yellow
557718
+ neutral: [237, 24, 30, 36, 37, 43, 44, 50, 51],
557719
+ // default teal/cyan
557651
557720
  success: [237, 22, 28, 34, 40, 46, 47, 48, 49],
557652
557721
  // green pulse
557653
557722
  error: [237, 52, 88, 124, 160, 196, 197, 203, 209],
@@ -557658,8 +557727,8 @@ var init_braille_spinner = __esm({
557658
557727
  // purple contemplation
557659
557728
  };
557660
557729
  THEME_DEFAULT = {
557661
- ramp: [237, 94, 130, 136, 172, 172, 178, 178, 214],
557662
- // grey amber → yellow (matches header)
557730
+ ramp: [237, 24, 30, 36, 37, 43, 44, 50, 51],
557731
+ // grey -> teal/cyan
557663
557732
  speed: 2
557664
557733
  };
557665
557734
  THEME_FILE = {
@@ -557679,7 +557748,7 @@ var init_braille_spinner = __esm({
557679
557748
  speed: 4
557680
557749
  };
557681
557750
  THEME_MEMORY = {
557682
- ramp: [237, 136, 172, 178, 179, 214, 215, 220, 222],
557751
+ ramp: [237, 23, 29, 35, 36, 37, 43, 44, 50],
557683
557752
  speed: 1
557684
557753
  };
557685
557754
  THEME_SKILL = {
@@ -557691,7 +557760,7 @@ var init_braille_spinner = __esm({
557691
557760
  speed: 2
557692
557761
  };
557693
557762
  THEME_DREAM = {
557694
- ramp: [237, 94, 130, 136, 172, 178, 179, 214, 220],
557763
+ ramp: [237, 24, 30, 36, 37, 43, 44, 50, 51],
557695
557764
  speed: 1
557696
557765
  };
557697
557766
  DEFAULT_METRICS = {
@@ -558303,7 +558372,7 @@ var init_text_selection = __esm({
558303
558372
  "packages/cli/src/tui/text-selection.ts"() {
558304
558373
  "use strict";
558305
558374
  init_layout2();
558306
- SEL_BG = 178;
558375
+ SEL_BG = 37;
558307
558376
  SEL_FG = 30;
558308
558377
  SEL_START = `\x1B[${SEL_FG}m\x1B[48;5;${SEL_BG}m`;
558309
558378
  SEL_END = `\x1B[0m`;
@@ -559594,8 +559663,8 @@ var init_status_bar = __esm({
559594
559663
  const decorateMenuButton = (cmd, label) => {
559595
559664
  const isBranding = themeMode() === "branding";
559596
559665
  if (isBranding) {
559597
- const BRAND_BG = 178;
559598
- const BRAND_FG = 65;
559666
+ const BRAND_BG = 37;
559667
+ const BRAND_FG = 0;
559599
559668
  return linkify(
559600
559669
  cmd,
559601
559670
  `\x1B[38;5;${BRAND_FG}m\x1B[48;5;${BRAND_BG}m ${label} \x1B[0m${PANEL_BG_SEQ}`
@@ -561516,7 +561585,7 @@ ${CONTENT_BG_SEQ}`);
561516
561585
  if (this._contentScrollOffset > 0) {
561517
561586
  const label = " ↓ scroll to bottom ";
561518
561587
  const startCol = 3;
561519
- buf += `\x1B[${spacerRow};${startCol}H\x1B[48;5;236m\x1B[38;5;229m${label}\x1B[0m${CONTENT_BG_SEQ}`;
561588
+ buf += `\x1B[${spacerRow};${startCol}H\x1B[38;5;37m${label}\x1B[0m${CONTENT_BG_SEQ}`;
561520
561589
  this._scrollBtnRegion = {
561521
561590
  row: spacerRow,
561522
561591
  start: startCol,
@@ -564239,6 +564308,23 @@ import { promisify as promisify5 } from "node:util";
564239
564308
  import { existsSync as existsSync85, writeFileSync as writeFileSync46, readFileSync as readFileSync71, appendFileSync as appendFileSync4, mkdirSync as mkdirSync49 } from "node:fs";
564240
564309
  import { join as join102 } from "node:path";
564241
564310
  import { homedir as homedir30, platform as platform4 } from "node:os";
564311
+ function wrapText(value2, width) {
564312
+ const words = value2.split(/\s+/).filter(Boolean);
564313
+ const lines = [];
564314
+ let line = "";
564315
+ for (const word2 of words) {
564316
+ if (!line) {
564317
+ line = word2;
564318
+ } else if (Array.from(line).length + 1 + Array.from(word2).length <= width) {
564319
+ line += " " + word2;
564320
+ } else {
564321
+ lines.push(line);
564322
+ line = word2;
564323
+ }
564324
+ }
564325
+ if (line) lines.push(line);
564326
+ return lines.length > 0 ? lines : [""];
564327
+ }
564242
564328
  async function checkToolSupport(modelName, backendUrl = "http://localhost:11434") {
564243
564329
  if (_toolSupportCache.has(modelName)) return _toolSupportCache.get(modelName);
564244
564330
  try {
@@ -564459,7 +564545,7 @@ function ensureCurl() {
564459
564545
  if (hasCmd("curl")) return true;
564460
564546
  const plat = platform4();
564461
564547
  if (plat === "win32") {
564462
- process.stdout.write(` ${c3.yellow("⚠")} curl not found on Windows — install it manually.
564548
+ process.stdout.write(` ${c3.cyan("⚠")} curl not found on Windows — install it manually.
564463
564549
  `);
564464
564550
  return false;
564465
564551
  }
@@ -564483,7 +564569,7 @@ function ensureCurl() {
564483
564569
  return true;
564484
564570
  }
564485
564571
  } catch {
564486
- process.stdout.write(` ${c3.yellow("⚠")} ${s2.label} install failed, trying next...
564572
+ process.stdout.write(` ${c3.cyan("⚠")} ${s2.label} install failed, trying next...
564487
564573
  `);
564488
564574
  }
564489
564575
  }
@@ -564520,7 +564606,7 @@ function ensureZstd() {
564520
564606
  else if (hasCmd("apk")) installCmd = "apk add --no-cache zstd";
564521
564607
  if (!installCmd) {
564522
564608
  process.stdout.write(`
564523
- ${c3.yellow("⚠")} Could not detect package manager to install zstd.
564609
+ ${c3.cyan("⚠")} Could not detect package manager to install zstd.
564524
564610
  `);
564525
564611
  return false;
564526
564612
  }
@@ -564689,7 +564775,7 @@ function runElevatedCommand(command, opts = {}) {
564689
564775
  function runOllamaInstallScript() {
564690
564776
  const zstdReady = ensureZstd();
564691
564777
  if (!zstdReady) {
564692
- process.stdout.write(` ${c3.yellow("⚠")} Proceeding without zstd — install may fail if the script requires it.
564778
+ process.stdout.write(` ${c3.cyan("⚠")} Proceeding without zstd — install may fail if the script requires it.
564693
564779
  `);
564694
564780
  }
564695
564781
  const elevated = buildElevatedInstall();
@@ -564700,9 +564786,9 @@ function runOllamaInstallScript() {
564700
564786
  process.stdout.write(` ${c3.cyan("●")} Elevation: SUDO_ASKPASS (GUI password modal)
564701
564787
  `);
564702
564788
  } else {
564703
- process.stdout.write(` ${c3.yellow("⚠")} No GUI password helper available — install may stall waiting for sudo.
564789
+ process.stdout.write(` ${c3.cyan("⚠")} No GUI password helper available — install may stall waiting for sudo.
564704
564790
  `);
564705
- process.stdout.write(` ${c3.yellow("⚠")} Install one of: pkexec / zenity / kdialog / yad / ssh-askpass
564791
+ process.stdout.write(` ${c3.cyan("⚠")} Install one of: pkexec / zenity / kdialog / yad / ssh-askpass
564706
564792
  `);
564707
564793
  }
564708
564794
  const runOnce = () => {
@@ -564722,7 +564808,7 @@ function runOllamaInstallScript() {
564722
564808
  const combined = stderr + "\n" + message2;
564723
564809
  if (combined.includes("requires zstd") || combined.includes("install zstd")) {
564724
564810
  process.stdout.write(`
564725
- ${c3.yellow("⚠")} Ollama install script requires zstd. Attempting to install it...
564811
+ ${c3.cyan("⚠")} Ollama install script requires zstd. Attempting to install it...
564726
564812
  `);
564727
564813
  if (ensureZstd()) {
564728
564814
  runOnce();
@@ -564747,7 +564833,7 @@ async function autoInstallOllama(rl) {
564747
564833
  } else if (plat === "win32") {
564748
564834
  return installOllamaWindows();
564749
564835
  }
564750
- process.stdout.write(` ${c3.yellow("⚠")} Unsupported platform: ${plat}
564836
+ process.stdout.write(` ${c3.cyan("⚠")} Unsupported platform: ${plat}
564751
564837
  `);
564752
564838
  process.stdout.write(` ${c3.dim("Visit https://ollama.com to install manually.")}
564753
564839
 
@@ -564768,7 +564854,7 @@ function installOllamaLinux() {
564768
564854
  return true;
564769
564855
  }
564770
564856
  process.stdout.write(`
564771
- ${c3.yellow("⚠")} Install script ran but ollama not found on PATH.
564857
+ ${c3.cyan("⚠")} Install script ran but ollama not found on PATH.
564772
564858
  `);
564773
564859
  return false;
564774
564860
  } catch (err) {
@@ -564802,7 +564888,7 @@ async function installOllamaMac(_rl) {
564802
564888
  `);
564803
564889
  } else {
564804
564890
  process.stdout.write(`
564805
- ${c3.yellow("⚠")} Homebrew install completed but brew not found on PATH.
564891
+ ${c3.cyan("⚠")} Homebrew install completed but brew not found on PATH.
564806
564892
  `);
564807
564893
  process.stdout.write(` ${c3.dim('Try: eval "$(/opt/homebrew/bin/brew shellenv)"')}
564808
564894
 
@@ -564832,7 +564918,7 @@ async function installOllamaMac(_rl) {
564832
564918
  return true;
564833
564919
  }
564834
564920
  process.stdout.write(`
564835
- ${c3.yellow("⚠")} brew install completed but ollama not found on PATH.
564921
+ ${c3.cyan("⚠")} brew install completed but ollama not found on PATH.
564836
564922
  `);
564837
564923
  return false;
564838
564924
  } catch (err) {
@@ -564859,7 +564945,7 @@ function installOllamaWindows() {
564859
564945
  return true;
564860
564946
  }
564861
564947
  process.stdout.write(`
564862
- ${c3.yellow("⚠")} Install script ran but ollama not found on PATH.
564948
+ ${c3.cyan("⚠")} Install script ran but ollama not found on PATH.
564863
564949
  `);
564864
564950
  return false;
564865
564951
  } catch (err) {
@@ -564874,7 +564960,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
564874
564960
  if (!ollamaInstalled) {
564875
564961
  if (rl) {
564876
564962
  process.stdout.write(`
564877
- ${c3.yellow("⚠")} Ollama is not installed on this system.
564963
+ ${c3.cyan("⚠")} Ollama is not installed on this system.
564878
564964
  `);
564879
564965
  const answer = await ask(rl, ` ${c3.bold("Install Ollama now?")} (Y/n) `);
564880
564966
  if (answer.toLowerCase() === "n") {
@@ -564901,7 +564987,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
564901
564987
  const child = spawn24("ollama", ["serve"], { stdio: "ignore", detached: true });
564902
564988
  child.unref();
564903
564989
  } catch {
564904
- process.stdout.write(` ${c3.yellow("⚠")} Could not start ollama serve.
564990
+ process.stdout.write(` ${c3.cyan("⚠")} Could not start ollama serve.
564905
564991
 
564906
564992
  `);
564907
564993
  return false;
@@ -564921,7 +565007,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
564921
565007
  } catch {
564922
565008
  }
564923
565009
  }
564924
- process.stdout.write(` ${c3.yellow("⚠")} Ollama started but not responding. Try ${c3.bold("ollama serve")} manually.
565010
+ process.stdout.write(` ${c3.cyan("⚠")} Ollama started but not responding. Try ${c3.bold("ollama serve")} manually.
564925
565011
 
564926
565012
  `);
564927
565013
  return false;
@@ -564996,7 +565082,7 @@ function pullModelWithAutoUpdate(tag) {
564996
565082
  const combined = errMsg + "\n" + stderr;
564997
565083
  if (combined.includes("412") || combined.includes("newer version") || combined.includes("requires a newer version")) {
564998
565084
  process.stdout.write(`
564999
- ${c3.yellow("⚠")} Ollama needs to be updated for this model.
565085
+ ${c3.cyan("⚠")} Ollama needs to be updated for this model.
565000
565086
  `);
565001
565087
  if (!ensureCurl()) {
565002
565088
  throw new Error("curl is required to update Ollama but could not be installed.");
@@ -565124,7 +565210,7 @@ function ensurePython3() {
565124
565210
  }
565125
565211
  }
565126
565212
  }
565127
- process.stdout.write(` ${c3.yellow("⚠")} Could not install Python3 automatically. Install manually.
565213
+ process.stdout.write(` ${c3.cyan("⚠")} Could not install Python3 automatically. Install manually.
565128
565214
 
565129
565215
  `);
565130
565216
  }
@@ -565163,7 +565249,7 @@ function ensurePythonVenv() {
565163
565249
  }
565164
565250
  }
565165
565251
  }
565166
- process.stdout.write(` ${c3.yellow("⚠")} Could not install python3-venv. Install manually: sudo apt install python3-venv
565252
+ process.stdout.write(` ${c3.cyan("⚠")} Could not install python3-venv. Install manually: sudo apt install python3-venv
565167
565253
 
565168
565254
  `);
565169
565255
  }
@@ -565249,12 +565335,12 @@ async function promptForCustomEndpoint(config, rl) {
565249
565335
  }
565250
565336
  }
565251
565337
  if (!testOk) {
565252
- process.stdout.write(` ${c3.yellow("⚠")} Endpoint returned HTTP ${resp.status}
565338
+ process.stdout.write(` ${c3.cyan("⚠")} Endpoint returned HTTP ${resp.status}
565253
565339
  `);
565254
565340
  }
565255
565341
  }
565256
565342
  } catch (err) {
565257
- process.stdout.write(` ${c3.yellow("⚠")} Could not reach endpoint: ${err instanceof Error ? err.message : String(err)}
565343
+ process.stdout.write(` ${c3.cyan("⚠")} Could not reach endpoint: ${err instanceof Error ? err.message : String(err)}
565258
565344
  `);
565259
565345
  }
565260
565346
  if (!testOk) {
@@ -565292,7 +565378,7 @@ async function promptForCustomEndpoint(config, rl) {
565292
565378
  }
565293
565379
  async function doSetup(config, rl) {
565294
565380
  process.stdout.write(`
565295
- ${c3.bold(c3.cyan("omnius"))}
565381
+ ${c3.cyan(OMNIUS_FIRST_RUN_BANNER)}
565296
565382
  `);
565297
565383
  process.stdout.write(` ${c3.dim("─".repeat(60))}
565298
565384
  `);
@@ -565329,36 +565415,43 @@ async function doSetup(config, rl) {
565329
565415
  const bw = 30;
565330
565416
  const sw = 24;
565331
565417
  const boxW = 52;
565332
- const boxLine = (content, visLen) => {
565418
+ const boxLine = (content) => {
565419
+ const visLen = visibleLen(content);
565333
565420
  const pad = Math.max(0, boxW - visLen);
565334
565421
  return ` ${c3.dim("│")}${content}${" ".repeat(pad)}${c3.dim("│")}
565335
565422
  `;
565336
565423
  };
565424
+ const boxWrappedDimLine = (content, indent = " ") => {
565425
+ const lines = wrapText(content, Math.max(1, boxW - visibleLen(indent)));
565426
+ for (const line of lines) {
565427
+ process.stdout.write(boxLine(`${indent}${c3.dim(line)}`));
565428
+ }
565429
+ };
565337
565430
  const hLine = (ch) => ` ${c3.dim(ch + "─".repeat(boxW) + (ch === "┌" ? "┐" : ch === "├" ? "┤" : "┘"))}
565338
565431
  `;
565339
565432
  process.stdout.write("\n");
565340
565433
  process.stdout.write(hLine("┌"));
565341
- process.stdout.write(boxLine(` ${c3.bold("Inference Capability")}`, 22));
565434
+ process.stdout.write(boxLine(` ${c3.bold("Inference Capability")}`));
565342
565435
  process.stdout.write(hLine("├"));
565343
- process.stdout.write(boxLine(` ${c3.bold("Overall")}`, 9));
565436
+ process.stdout.write(boxLine(` ${c3.bold("Overall")}`));
565344
565437
  const overallBar = renderScoreBar(score.overall, bw);
565345
565438
  const overallLabel = `${String(score.overall).padStart(3)}/100`;
565346
- process.stdout.write(boxLine(` ${overallBar} ${c3.bold(overallLabel)}`, 2 + bw + 1 + overallLabel.length));
565347
- process.stdout.write(boxLine(` ${c3.dim(score.summary)}`, 2 + score.summary.length));
565439
+ process.stdout.write(boxLine(` ${overallBar} ${c3.bold(overallLabel)}`));
565440
+ boxWrappedDimLine(score.summary);
565348
565441
  process.stdout.write(hLine("├"));
565349
565442
  const memLabel = `${specs.totalRamGB.toFixed(0)} GB RAM` + (specs.gpuVramGB > 0 ? ` + ${specs.gpuVramGB.toFixed(0)} GB VRAM` : "");
565350
- process.stdout.write(boxLine(` ${c3.bold("Memory")} ${c3.dim(memLabel)}`, 11 + memLabel.length));
565351
- process.stdout.write(boxLine(` ${renderScoreBar(score.memory, sw)} ${String(score.memory).padStart(3)}`, 2 + sw + 1 + 3));
565352
- process.stdout.write(boxLine("", 0));
565443
+ process.stdout.write(boxLine(` ${c3.bold("Memory")} ${c3.dim(memLabel)}`));
565444
+ process.stdout.write(boxLine(` ${renderScoreBar(score.memory, sw)} ${String(score.memory).padStart(3)}`));
565445
+ process.stdout.write(boxLine(""));
565353
565446
  const gpuLabel = specs.gpuVramGB > 0 ? specs.gpuName || "NVIDIA GPU" : "CPU only";
565354
- process.stdout.write(boxLine(` ${c3.bold("Compute")} ${c3.dim(gpuLabel)}`, 11 + gpuLabel.length));
565355
- process.stdout.write(boxLine(` ${renderScoreBar(score.compute, sw)} ${String(score.compute).padStart(3)}`, 2 + sw + 1 + 3));
565356
- process.stdout.write(boxLine("", 0));
565447
+ process.stdout.write(boxLine(` ${c3.bold("Compute")} ${c3.dim(gpuLabel)}`));
565448
+ process.stdout.write(boxLine(` ${renderScoreBar(score.compute, sw)} ${String(score.compute).padStart(3)}`));
565449
+ process.stdout.write(boxLine(""));
565357
565450
  const speedLabel = specs.gpuVramGB > 0 ? "GPU accelerated" : "CPU inference";
565358
- process.stdout.write(boxLine(` ${c3.bold("Speed")} ${c3.dim(speedLabel)}`, 11 + speedLabel.length));
565359
- process.stdout.write(boxLine(` ${renderScoreBar(score.speed, sw)} ${String(score.speed).padStart(3)}`, 2 + sw + 1 + 3));
565451
+ process.stdout.write(boxLine(` ${c3.bold("Speed")} ${c3.dim(speedLabel)}`));
565452
+ process.stdout.write(boxLine(` ${renderScoreBar(score.speed, sw)} ${String(score.speed).padStart(3)}`));
565360
565453
  process.stdout.write(hLine("├"));
565361
- process.stdout.write(boxLine(` ${c3.bold("Model Compatibility")}`, 21));
565454
+ process.stdout.write(boxLine(` ${c3.bold("Model Compatibility")}`));
565362
565455
  for (const compat of score.modelCompat) {
565363
565456
  const icon = compat.fits ? c3.green("✔") : c3.red("✖");
565364
565457
  const tag = compat.fits ? compat.tag : c3.dim(compat.tag);
@@ -565372,7 +565465,7 @@ async function doSetup(config, rl) {
565372
565465
  process.stdout.write("\n");
565373
565466
  let hasPython = hasCmd("python3") || hasCmd("python");
565374
565467
  if (!hasPython) {
565375
- process.stdout.write(` ${c3.yellow("⚠")} Python3 not found (needed for vision, OCR, browser automation).
565468
+ process.stdout.write(` ${c3.cyan("⚠")} Python3 not found (needed for vision, OCR, browser automation).
565376
565469
  `);
565377
565470
  const installPy = await ask(rl, ` ${c3.bold("Install Python3?")} (Y/n) `);
565378
565471
  if (installPy.toLowerCase() !== "n") {
@@ -565383,7 +565476,7 @@ async function doSetup(config, rl) {
565383
565476
  if (hasPython) {
565384
565477
  const hasVenv = checkPythonVenv();
565385
565478
  if (!hasVenv) {
565386
- process.stdout.write(` ${c3.yellow("⚠")} Python3 venv module not found (needed for Moondream, OCR, browser automation).
565479
+ process.stdout.write(` ${c3.cyan("⚠")} Python3 venv module not found (needed for Moondream, OCR, browser automation).
565387
565480
  `);
565388
565481
  const installVenv = await ask(rl, ` ${c3.bold("Install python3-venv?")} (Y/n) `);
565389
565482
  if (installVenv.toLowerCase() !== "n") {
@@ -565396,7 +565489,7 @@ async function doSetup(config, rl) {
565396
565489
  try {
565397
565490
  models = await fetchOllamaModels(config.backendUrl);
565398
565491
  } catch {
565399
- process.stdout.write(` ${c3.yellow("⚠")} Cannot reach Ollama at ${c3.bold(config.backendUrl)}
565492
+ process.stdout.write(` ${c3.cyan("⚠")} Cannot reach Ollama at ${c3.bold(config.backendUrl)}
565400
565493
 
565401
565494
  `);
565402
565495
  const useCustom = await ask(rl, ` ${c3.bold("Use a custom inference endpoint instead?")} (Y/n) `);
@@ -565422,12 +565515,12 @@ async function doSetup(config, rl) {
565422
565515
 
565423
565516
  `);
565424
565517
  } catch {
565425
- process.stdout.write(` ${c3.yellow("⚠")} Ollama started but not responding yet. It may need a moment.
565518
+ process.stdout.write(` ${c3.cyan("⚠")} Ollama started but not responding yet. It may need a moment.
565426
565519
 
565427
565520
  `);
565428
565521
  }
565429
565522
  } catch {
565430
- process.stdout.write(` ${c3.yellow("⚠")} Could not start Ollama. Try running ${c3.bold("ollama serve")} manually.
565523
+ process.stdout.write(` ${c3.cyan("⚠")} Could not start Ollama. Try running ${c3.bold("ollama serve")} manually.
565431
565524
 
565432
565525
  `);
565433
565526
  }
@@ -565450,12 +565543,12 @@ async function doSetup(config, rl) {
565450
565543
 
565451
565544
  `);
565452
565545
  } catch {
565453
- process.stdout.write(` ${c3.yellow("⚠")} Ollama installed but not responding yet. Try ${c3.bold("ollama serve")} manually.
565546
+ process.stdout.write(` ${c3.cyan("⚠")} Ollama installed but not responding yet. Try ${c3.bold("ollama serve")} manually.
565454
565547
 
565455
565548
  `);
565456
565549
  }
565457
565550
  } catch {
565458
- process.stdout.write(` ${c3.yellow("⚠")} Ollama installed. Start it with: ${c3.bold("ollama serve")}
565551
+ process.stdout.write(` ${c3.cyan("⚠")} Ollama installed. Start it with: ${c3.bold("ollama serve")}
565459
565552
 
565460
565553
  `);
565461
565554
  }
@@ -565482,7 +565575,7 @@ async function doSetup(config, rl) {
565482
565575
  `);
565483
565576
  return currentModel.name;
565484
565577
  }
565485
- process.stdout.write(` ${c3.yellow("⚠")} Default model ${c3.bold(config.model)} is not available.
565578
+ process.stdout.write(` ${c3.cyan("⚠")} Default model ${c3.bold(config.model)} is not available.
565486
565579
 
565487
565580
  `);
565488
565581
  if (models.length > 0) {
@@ -565514,7 +565607,7 @@ async function doSetup(config, rl) {
565514
565607
  return selected.name;
565515
565608
  }
565516
565609
  } else {
565517
- process.stdout.write(` ${c3.yellow("⚠")} No models found on this system.
565610
+ process.stdout.write(` ${c3.cyan("⚠")} No models found on this system.
565518
565611
 
565519
565612
  `);
565520
565613
  }
@@ -566584,7 +566677,7 @@ export PATH="${binDir}:$PATH" # Added by omnius for nvim
566584
566677
  } catch {
566585
566678
  }
566586
566679
  }
566587
- var execAsync2, QWEN_VARIANTS, _toolSupportCache, _cloudflaredInstallPromise;
566680
+ var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE, visibleLen, QWEN_VARIANTS, _toolSupportCache, _cloudflaredInstallPromise;
566588
566681
  var init_setup = __esm({
566589
566682
  "packages/cli/src/tui/setup.ts"() {
566590
566683
  "use strict";
@@ -566594,6 +566687,17 @@ var init_setup = __esm({
566594
566687
  init_dist();
566595
566688
  init_tui_select();
566596
566689
  execAsync2 = promisify5(exec4);
566690
+ OMNIUS_FIRST_RUN_BANNER = [
566691
+ " ░▒▓██████▓▒░░▒▓██████████████▓▒░░▒▓███████▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓███████▓▒░ ",
566692
+ "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ",
566693
+ "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ",
566694
+ "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ",
566695
+ "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ",
566696
+ "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ",
566697
+ " ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░ "
566698
+ ].join("\n");
566699
+ ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g;
566700
+ visibleLen = (value2) => Array.from(value2.replace(ANSI_RE, "")).length;
566597
566701
  QWEN_VARIANTS = [
566598
566702
  { tag: "qwen3.5:0.8b", sizeGB: 1, label: "0.8B params (1.0 GB)", cloud: false },
566599
566703
  { tag: "qwen3.5:2b", sizeGB: 2.7, label: "2B params (2.7 GB)", cloud: false },
@@ -581466,7 +581570,7 @@ async function showColorMenu(ctx3) {
581466
581570
  {
581467
581571
  key: "branding",
581468
581572
  label: `Omnius Branding${currentConfig.mode === "branding" ? " (active)" : ""}`,
581469
- detail: "#ffae00 accent on black"
581573
+ detail: "Teal accent on terminal background"
581470
581574
  },
581471
581575
  {
581472
581576
  key: "custom",
@@ -587626,30 +587730,30 @@ function getNodeMnemonic() {
587626
587730
  function createDefaultBanner(version4 = "0.120.0") {
587627
587731
  const width = termCols();
587628
587732
  const rows = headerHeight();
587629
- const yellow = tuiAccent() < 0 ? -1 : tuiAccent();
587733
+ const accent2 = tuiAccent() < 0 ? -1 : tuiAccent();
587630
587734
  const bgBlack = tuiBg() < 0 ? -1 : tuiBg();
587631
587735
  const grid = [];
587632
587736
  const innerW = width - 2;
587633
587737
  const topRow = [];
587634
- topRow.push({ char: "╭", fg: yellow, bg: bgBlack, bold: false });
587738
+ topRow.push({ char: "╭", fg: accent2, bg: bgBlack, bold: false });
587635
587739
  for (let c9 = 0; c9 < innerW; c9++) {
587636
- topRow.push({ char: "─", fg: yellow, bg: bgBlack, bold: false });
587740
+ topRow.push({ char: "─", fg: accent2, bg: bgBlack, bold: false });
587637
587741
  }
587638
- topRow.push({ char: "╮", fg: yellow, bg: bgBlack, bold: false });
587742
+ topRow.push({ char: "╮", fg: accent2, bg: bgBlack, bold: false });
587639
587743
  grid.push(topRow);
587640
587744
  const midRow = [];
587641
- midRow.push({ char: "│", fg: yellow, bg: bgBlack, bold: false });
587745
+ midRow.push({ char: "│", fg: accent2, bg: bgBlack, bold: false });
587642
587746
  for (let c9 = 0; c9 < innerW; c9++) {
587643
587747
  midRow.push({ char: " ", fg: 0, bg: bgBlack, bold: false });
587644
587748
  }
587645
- midRow.push({ char: "│", fg: yellow, bg: bgBlack, bold: false });
587749
+ midRow.push({ char: "│", fg: accent2, bg: bgBlack, bold: false });
587646
587750
  grid.push(midRow);
587647
587751
  const botRow = [];
587648
- botRow.push({ char: "╰", fg: yellow, bg: bgBlack, bold: false });
587752
+ botRow.push({ char: "╰", fg: accent2, bg: bgBlack, bold: false });
587649
587753
  for (let c9 = 0; c9 < innerW; c9++) {
587650
- botRow.push({ char: "─", fg: yellow, bg: bgBlack, bold: false });
587754
+ botRow.push({ char: "─", fg: accent2, bg: bgBlack, bold: false });
587651
587755
  }
587652
- botRow.push({ char: "╯", fg: yellow, bg: bgBlack, bold: false });
587756
+ botRow.push({ char: "╯", fg: accent2, bg: bgBlack, bold: false });
587653
587757
  grid.push(botRow);
587654
587758
  return {
587655
587759
  id: "default-header",
@@ -588330,7 +588434,7 @@ var init_carousel_descriptors = __esm({
588330
588434
  },
588331
588435
  {
588332
588436
  name: "memory",
588333
- colors: [136, 172, 178, 179, 214, 215, 220, 222],
588437
+ colors: [23, 29, 35, 36, 37, 43, 44, 50],
588334
588438
  tools: ["memory_read", "memory_write"]
588335
588439
  },
588336
588440
  {
@@ -593226,7 +593330,7 @@ import { mkdirSync as mkdirSync60, existsSync as existsSync105, unlinkSync as un
593226
593330
  import { join as join120, resolve as resolve39, basename as basename22 } from "node:path";
593227
593331
  import { writeFile as writeFileAsync } from "node:fs/promises";
593228
593332
  import { createHash as createHash19, randomInt } from "node:crypto";
593229
- function parseTelegramInteractionDecision(text, forcedRoute) {
593333
+ function parseTelegramInteractionDecision(text, forcedRoute, options2 = {}) {
593230
593334
  const cleaned = stripTelegramHiddenThinking(text).replace(/```(?:json)?/gi, "").replace(/```/g, "").trim();
593231
593335
  const jsonText = cleaned.startsWith("{") ? cleaned : cleaned.match(/\{[\s\S]*\}/)?.[0] ?? "";
593232
593336
  if (!jsonText) return null;
@@ -593236,7 +593340,7 @@ function parseTelegramInteractionDecision(text, forcedRoute) {
593236
593340
  const route = forcedRoute ?? parsedRoute;
593237
593341
  if (!route) return null;
593238
593342
  const shouldReplyRaw = parsed["should_reply"] ?? parsed["shouldReply"];
593239
- const shouldReply = typeof shouldReplyRaw === "boolean" ? shouldReplyRaw : true;
593343
+ const shouldReply = typeof shouldReplyRaw === "boolean" ? shouldReplyRaw : options2.defaultShouldReply ?? true;
593240
593344
  const confidenceRaw = Number(parsed["confidence"]);
593241
593345
  const confidence = Number.isFinite(confidenceRaw) ? Math.max(0, Math.min(1, confidenceRaw)) : 0;
593242
593346
  const reason = String(parsed["reason"] ?? "live inference decision").slice(0, 240);
@@ -593299,6 +593403,41 @@ function sanitizeTelegramProgressText(text, maxLength) {
593299
593403
  const compact = stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
593300
593404
  return compact.length > maxLength ? compact.slice(0, Math.max(0, maxLength - 3)) + "..." : compact;
593301
593405
  }
593406
+ function compactTelegramVisibleText(text) {
593407
+ return stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
593408
+ }
593409
+ function isTelegramPotentialNoReplyPrefix(text) {
593410
+ const lower = compactTelegramVisibleText(text).toLowerCase();
593411
+ return Boolean(lower) && "no_reply".startsWith(lower);
593412
+ }
593413
+ function isTelegramNoReplySentinel(text) {
593414
+ const lower = compactTelegramVisibleText(text).toLowerCase();
593415
+ return lower === "no_reply" || lower.startsWith("no_reply");
593416
+ }
593417
+ function isTelegramInternalStatusText(text) {
593418
+ const compact = compactTelegramVisibleText(text);
593419
+ if (!compact) return false;
593420
+ const lower = compact.toLowerCase();
593421
+ if (isTelegramNoReplySentinel(compact)) return true;
593422
+ if (lower === "complete" || lower === "completed") return true;
593423
+ if (/^memory stage:/i.test(compact)) return true;
593424
+ if (/^\[ppr[-_\s]?skip\]/i.test(compact)) return true;
593425
+ if (/^(casual|ambient|group)\b.{0,180}\b(skipping|skipped|not directed|no action needed|no reply)\b/i.test(compact)) return true;
593426
+ if (/^no further action needed\b/i.test(compact)) return true;
593427
+ if (/^no action needed\b.{0,120}\b(task|complete|completed|done)\b/i.test(compact)) return true;
593428
+ if (/^(there'?s|there is) no active task\b/i.test(compact)) return true;
593429
+ if (/^everything'?s (done|complete|completed|wrapped up)\b/i.test(compact)) return true;
593430
+ if (/\balready (been )?(provided|answered|handled|delivered) above\b/i.test(compact)) return true;
593431
+ if (/\b(no remaining work|nothing left to do|task is complete|task has been completed)\b/i.test(compact)) return true;
593432
+ return false;
593433
+ }
593434
+ function cleanTelegramVisibleReply(text, options2 = {}) {
593435
+ const clean3 = stripTelegramHiddenThinking(text).trim();
593436
+ if (!clean3) return "";
593437
+ if (options2.suppressPotentialNoReplyPrefix && isTelegramPotentialNoReplyPrefix(clean3)) return "";
593438
+ if (isTelegramInternalStatusText(clean3)) return "";
593439
+ return clean3;
593440
+ }
593302
593441
  function truncateTelegramContext(text, maxLength) {
593303
593442
  const trimmed = text.trim();
593304
593443
  if (trimmed.length <= maxLength) return trimmed;
@@ -593419,13 +593558,13 @@ function selectTelegramFinalResponse(args) {
593419
593558
  args.streamText,
593420
593559
  args.accumulated,
593421
593560
  args.assistantText
593422
- ].map((candidate) => stripTelegramHiddenThinking(candidate || "").trim()).filter(Boolean);
593561
+ ].map((candidate) => cleanTelegramVisibleReply(candidate || "")).filter(Boolean);
593423
593562
  if (visibleCandidates.length > 0) {
593424
593563
  return visibleCandidates.reduce(
593425
593564
  (best, current) => current.length > best.length ? current : best
593426
593565
  );
593427
593566
  }
593428
- return stripTelegramHiddenThinking(args.summary || "").trim();
593567
+ return cleanTelegramVisibleReply(args.summary || "");
593429
593568
  }
593430
593569
  function formatTelegramProgressEvent(event) {
593431
593570
  if (event.type === "tool_call" && event.toolName === "task_complete") return null;
@@ -593435,23 +593574,25 @@ function formatTelegramProgressEvent(event) {
593435
593574
  }
593436
593575
  if (event.type === "tool_result") {
593437
593576
  const preview = sanitizeTelegramProgressText(event.content || "", 80);
593577
+ if (isTelegramInternalStatusText(preview)) return null;
593438
593578
  const toolName = escapeTelegramHTML(event.toolName || "tool");
593439
593579
  if (preview) return `${toolName}: ${escapeTelegramHTML(preview)}`;
593440
593580
  return event.success ? `${toolName} completed` : `${toolName} failed`;
593441
593581
  }
593442
593582
  if (event.type === "status") {
593443
593583
  const content = sanitizeTelegramProgressText(event.content || "", 120);
593584
+ if (isTelegramInternalStatusText(content)) return null;
593444
593585
  return content ? escapeTelegramHTML(content) : null;
593445
593586
  }
593446
593587
  return null;
593447
593588
  }
593448
593589
  function renderTelegramLiveProgressHTML(progressLines, accumulated) {
593449
- const draft = stripTelegramHiddenThinking(accumulated).trim();
593590
+ const draft = cleanTelegramVisibleReply(accumulated, { suppressPotentialNoReplyPrefix: true });
593450
593591
  if (draft) {
593451
593592
  const clipped = draft.length > 2e3 ? `${draft.slice(0, 1997).trimEnd()}...` : draft;
593452
593593
  return convertMarkdownToTelegramHTML(clipped);
593453
593594
  }
593454
- return progressLines.slice(-6).map((line) => line.trim()).filter(Boolean).join("\n");
593595
+ return progressLines.slice(-6).map((line) => line.trim()).filter((line) => !isTelegramInternalStatusText(line)).filter(Boolean).join("\n");
593455
593596
  }
593456
593597
  function telegramSyntheticHelpSignatures() {
593457
593598
  return [
@@ -593935,14 +594076,17 @@ RULES FOR GROUP CONTEXT:
593935
594076
  6. You may share general knowledge and helpful guidance
593936
594077
  `.trim();
593937
594078
  GROUP_REPLY_DISCRETION_PROMPT = `
593938
- REPLY DISCRETION: You are in a group chat. Only respond if:
593939
- 1. Someone @mentioned the bot directly
593940
- 2. The message is a reply to one of your previous messages
593941
- 3. The message clearly asks a question or requests help
593942
- 4. You have genuinely useful information to contribute
593943
-
593944
- If the message is casual group chatter not directed at you, use task_complete
593945
- with summary "no_reply" to silently skip without responding.
594079
+ REPLY DISCRETION: You are in a group chat. The live router has already filtered
594080
+ most ambient chatter. Continue to be selective:
594081
+ 1. Respond when someone directly addresses the bot, replies to the bot, or keeps
594082
+ an active bot-involved task moving.
594083
+ 2. Stay silent for conversation between other people, third-person commentary
594084
+ about the bot, status chatter, or questions clearly meant for someone else.
594085
+ 3. Do not reply just because you know an answer or could add color.
594086
+
594087
+ If you determine no visible reply should be sent, call task_complete with summary
594088
+ "no_reply". Never write "no_reply", "skipping", "no action needed", or a status
594089
+ explanation as assistant text.
593946
594090
  `.trim();
593947
594091
  TELEGRAM_CHAT_MODE_PROMPT = `
593948
594092
  You are Omnius replying in Telegram quick-chat mode.
@@ -593956,6 +594100,7 @@ Rules:
593956
594100
  6. Use the Telegram conversation context stream as the source of truth for who said what, recent group dynamics, and retained earlier context.
593957
594101
  7. Do not claim older chat is unavailable when the context stream contains it. If asked what you see, summarize the supplied transcript, speakers, and relationship/tone signals.
593958
594102
  8. Mirror the current sender's tone and directness while staying safe and clear.
594103
+ 9. Never send router decisions, skip explanations, memory-stage notes, task-complete summaries, or "no_reply" as chat text.
593959
594104
  `.trim();
593960
594105
  ADMIN_CHAT_PROFILE_PROMPT = `
593961
594106
  You are replying to the authenticated Telegram admin in a private DM.
@@ -593972,6 +594117,7 @@ Capabilities:
593972
594117
  Telegram response contract:
593973
594118
  - Write the actual Telegram reply as normal assistant text before completion.
593974
594119
  - task_complete is only an internal completion signal; do not put status reports, wrap-up notes, or meta-commentary there.
594120
+ - "no_reply" is an internal silent-skip sentinel only; never emit it or explain it in assistant text.
593975
594121
  - Do not summarize the fact that you answered; the visible assistant text must be the answer itself.
593976
594122
  - If you delegated long-running work, include the sub-agent id/status and what the admin should expect next.
593977
594123
  `.trim();
@@ -594637,17 +594783,17 @@ ${lines.join("\n")}`);
594637
594783
  async inferTelegramInteractionDecision(msg, toolContext) {
594638
594784
  const config = this.agentConfig;
594639
594785
  const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
594786
+ const isGroup = msg.chatType !== "private";
594640
594787
  if (!config) {
594641
594788
  return {
594642
594789
  route: forcedRoute ?? "action",
594643
- shouldReply: true,
594790
+ shouldReply: !isGroup,
594644
594791
  confidence: 0,
594645
- reason: "router inference unavailable; escalating to action path instead of using text heuristics",
594792
+ reason: isGroup ? "router inference unavailable; public group fails closed without keyword heuristics" : "router inference unavailable; private chat defaults to reply",
594646
594793
  source: "inference-unavailable"
594647
594794
  };
594648
594795
  }
594649
594796
  const sessionKey = this.sessionKeyForMessage(msg);
594650
- const isGroup = msg.chatType !== "private";
594651
594797
  const backend = new OllamaAgenticBackend(
594652
594798
  config.backendUrl,
594653
594799
  config.model,
@@ -594665,7 +594811,9 @@ ${lines.join("\n")}`);
594665
594811
  `- chat: a short conversational answer can be produced without tools.`,
594666
594812
  `- action: tools, workspace context, media processing, web lookup, delegation, or a multi-step agent loop may be needed.`,
594667
594813
  ``,
594668
- `Reply discretion: infer from the live thread, speaker relationships, direct mentions, replies, tone, and current message. Do not use static keyword rules. In private chats, should_reply is normally true. In groups, should_reply can be false only when silence is the most contextually appropriate behavior.`,
594814
+ `Reply discretion: infer from the live thread, speaker relationships, direct mentions, replies, tone, and current message. Do not use static keyword rules.`,
594815
+ `Private chats: should_reply is normally true.`,
594816
+ `Group/public chats: default should_reply to false unless the current message clearly addresses the bot, replies to the bot, continues an active bot-involved exchange, assigns the bot work, or asks for the bot's view. Ambient chatter, third-person discussion about the bot, commands meant for a human, or questions among other people are false. Do not set true just because the bot could help.`,
594669
594817
  forcedLine,
594670
594818
  ``,
594671
594819
  `Tool context: ${toolContext}`,
@@ -594696,15 +594844,17 @@ ${msg.text}`
594696
594844
  think: false
594697
594845
  });
594698
594846
  const text = result.choices[0]?.message?.content ?? "";
594699
- const parsed = parseTelegramInteractionDecision(text, forcedRoute);
594847
+ const parsed = parseTelegramInteractionDecision(text, forcedRoute, {
594848
+ defaultShouldReply: !isGroup
594849
+ });
594700
594850
  if (parsed) return parsed;
594701
594851
  } catch {
594702
594852
  }
594703
594853
  return {
594704
594854
  route: forcedRoute ?? "action",
594705
- shouldReply: true,
594855
+ shouldReply: !isGroup,
594706
594856
  confidence: 0,
594707
- reason: "router inference failed; escalating to action path instead of using text heuristics",
594857
+ reason: isGroup ? "router inference failed; public group fails closed without keyword heuristics" : "router inference failed; private chat defaults to reply",
594708
594858
  source: "inference-unavailable"
594709
594859
  };
594710
594860
  }
@@ -595096,6 +595246,20 @@ Join: ${newUrl}`);
595096
595246
  }
595097
595247
  const existing = this.subAgents.get(sessionKey);
595098
595248
  if (existing && !existing.aborted) {
595249
+ const isGroup = msg.chatType !== "private";
595250
+ if (isGroup) {
595251
+ this.recordTelegramUserMessage(msg, "ambient");
595252
+ const decision2 = await this.inferTelegramInteractionDecision(msg, existing.toolContext || toolContext);
595253
+ this.markLastTelegramUserMessageMode(msg, decision2.shouldReply ? "steering" : "ambient");
595254
+ this.subAgentViewCallbacks?.onWrite(
595255
+ existing.viewId,
595256
+ `live steering: ${decision2.shouldReply ? decision2.route : "no_reply"} (${decision2.source}, confidence ${decision2.confidence.toFixed(2)}): ${decision2.reason}`
595257
+ );
595258
+ if (!decision2.shouldReply) {
595259
+ this.maybeLogTelegramGroupSkip(msg, `live inference: no steering — ${decision2.reason}`);
595260
+ return;
595261
+ }
595262
+ }
595099
595263
  let steeringText = msg.text;
595100
595264
  if (msg.media) {
595101
595265
  const mediaContext = await this.processMedia(msg);
@@ -595106,7 +595270,11 @@ Join: ${newUrl}`);
595106
595270
  ${mediaContext}`;
595107
595271
  }
595108
595272
  }
595109
- this.recordTelegramUserMessage(msg, "steering", steeringText);
595273
+ if (isGroup) {
595274
+ this.markLastTelegramUserMessageMode(msg, "steering");
595275
+ } else {
595276
+ this.recordTelegramUserMessage(msg, "steering", steeringText);
595277
+ }
595110
595278
  if (existing.runner) {
595111
595279
  existing.runner.injectUserMessage(steeringText);
595112
595280
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "mid-conversation steering injected"));
@@ -595172,7 +595340,8 @@ ${mediaContext}`;
595172
595340
  clearInterval(subAgent.typingInterval);
595173
595341
  subAgent.typingInterval = null;
595174
595342
  }
595175
- if (result === "no_reply" || result === "") {
595343
+ const finalText = cleanTelegramVisibleReply(result || "");
595344
+ if (!finalText) {
595176
595345
  if (msg.chatType !== "private") {
595177
595346
  this.maybeLogTelegramGroupSkip(msg, "discretion: skipped reply");
595178
595347
  } else {
@@ -595186,20 +595355,10 @@ ${mediaContext}`;
595186
595355
  }
595187
595356
  return;
595188
595357
  }
595189
- const finalText = stripTelegramHiddenThinking(result || "").trim();
595190
595358
  if (subAgent.liveMessagePromise) {
595191
595359
  await subAgent.liveMessagePromise.catch(() => {
595192
595360
  });
595193
595361
  }
595194
- if (!finalText) {
595195
- if (subAgent.liveMessageId && !msg.guestQueryId) {
595196
- await this.deleteLiveMessage(msg.chatId, subAgent.liveMessageId).catch(() => {
595197
- });
595198
- }
595199
- this.subAgentViewCallbacks?.onWrite(subAgent.viewId, "completed: no model reply");
595200
- this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
595201
- return;
595202
- }
595203
595362
  this.recordTelegramAssistantMessage(msg, finalText, "action");
595204
595363
  const finalHtml = convertMarkdownToTelegramHTML(finalText);
595205
595364
  await this.sendOrEditFinalTelegramHTML(msg, finalHtml, subAgent.liveMessageId);
@@ -595280,7 +595439,7 @@ ${mediaContext}`;
595280
595439
  clearInterval(subAgent.typingInterval);
595281
595440
  subAgent.typingInterval = null;
595282
595441
  }
595283
- const finalText = stripTelegramHiddenThinking(result || "").trim();
595442
+ const finalText = cleanTelegramVisibleReply(result || "");
595284
595443
  if (subAgent.liveMessagePromise) {
595285
595444
  await subAgent.liveMessagePromise.catch(() => {
595286
595445
  });
@@ -595370,10 +595529,12 @@ ${mediaContext}`;
595370
595529
  }
595371
595530
  if (liveMessageId && !msg.guestQueryId && now - lastEditMs > 900) {
595372
595531
  lastEditMs = now;
595532
+ const html = renderTelegramLiveProgressHTML(progressLines, accumulated);
595533
+ if (!html.trim()) return;
595373
595534
  await this.editLiveMessage(
595374
595535
  msg.chatId,
595375
595536
  liveMessageId,
595376
- renderTelegramLiveProgressHTML(progressLines, accumulated)
595537
+ html
595377
595538
  ).catch(() => {
595378
595539
  });
595379
595540
  } else if (!liveMessageId && !liveMessagePromise && !msg.guestQueryId) {
@@ -595399,7 +595560,7 @@ ${mediaContext}`;
595399
595560
  clearInterval(typingInterval);
595400
595561
  typingInterval = null;
595401
595562
  }
595402
- const cleaned = stripTelegramHiddenThinking(finalText || accumulated).trim();
595563
+ const cleaned = cleanTelegramVisibleReply(finalText || accumulated);
595403
595564
  const pendingLiveMessage = liveMessagePromise;
595404
595565
  if (pendingLiveMessage) {
595405
595566
  await pendingLiveMessage.catch(() => {
@@ -595452,7 +595613,7 @@ ${mediaContext}`;
595452
595613
  isGroup ? 44 : 24
595453
595614
  );
595454
595615
  const safety = isAdminDM ? "Admin private DM. The user is trusted, but quick-chat mode still has no tool access." : isAdminGroup ? ADMIN_GROUP_PROMPT : TELEGRAM_SAFETY_PROMPT;
595455
- const groupHint = isGroup ? `Telegram group: ${msg.chatTitle || "unknown"}. Keep the reply short and relevant.` : "Telegram private chat.";
595616
+ const groupHint = isGroup ? `Telegram group: ${msg.chatTitle || "unknown"}. The live router selected this turn as reply-worthy; keep the reply short and relevant. Never output a skip decision, no_reply marker, memory-stage note, or completion status.` : "Telegram private chat.";
595456
595617
  const runtime = buildTelegramRuntimeContext(/* @__PURE__ */ new Date());
595457
595618
  const messages2 = [
595458
595619
  {
@@ -595642,7 +595803,7 @@ ${toolHint}
595642
595803
  Telegram message from @${msg.username}${chatLabel}:
595643
595804
  ${msg.text}
595644
595805
 
595645
- Respond concisely and safely.`;
595806
+ Respond concisely and safely. Send the actual chat reply, not router/status/completion commentary.`;
595646
595807
  }
595647
595808
  if (mediaContext) {
595648
595809
  userPrompt += `
@@ -595671,11 +595832,11 @@ ${creativeWorkspace}` : ""}`;
595671
595832
  buildSubAgentTools(context2, repoRoot, chatId, todoSessionId) {
595672
595833
  const taskComplete = {
595673
595834
  name: "task_complete",
595674
- description: "Internal completion signal for Telegram runs. Put the actual user-facing reply in assistant text before calling this. Use summary 'no_reply' only to silently skip responding.",
595835
+ description: "Internal completion signal for Telegram runs. Put the actual user-facing reply in assistant text before calling this. Use summary 'no_reply' only to silently skip responding; never write that sentinel as assistant text.",
595675
595836
  parameters: {
595676
595837
  type: "object",
595677
595838
  properties: {
595678
- summary: { type: "string", description: "Internal completion note, or 'no_reply' to skip when no assistant reply should be sent" }
595839
+ summary: { type: "string", description: "Internal completion note, or 'no_reply' to skip when no assistant reply should be sent. This is never shown directly to Telegram." }
595679
595840
  },
595680
595841
  required: ["summary"]
595681
595842
  },
@@ -624977,8 +625138,12 @@ This is an independent background session started from /background.`
624977
625138
  await new Promise((r3) => setTimeout(r3, 5e3));
624978
625139
  return _tryNexusConnect(attempt + 1);
624979
625140
  }
625141
+ const nexusLogPath = join136(repoRoot, ".omnius", "nexus", "daemon.err");
625142
+ const visibleOut = out.length > 1200 ? `${out.slice(0, 1200)}...` : out;
624980
625143
  writeContent(
624981
- () => renderWarning(`Nexus auto-connect failed: ${out.slice(0, 100)}`)
625144
+ () => renderWarning(`Nexus auto-connect failed:
625145
+ ${visibleOut}
625146
+ Log: ${nexusLogPath}`)
624982
625147
  );
624983
625148
  } else if (out.includes("still connecting") || out.includes("spawned")) {
624984
625149
  for (let i2 = 0; i2 < 30; i2++) {
@@ -626728,7 +626893,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
626728
626893
  },
626729
626894
  onAgentSpeech(text) {
626730
626895
  writeContent(
626731
- () => renderInfo(`\x1B[38;5;178m[agent]\x1B[0m ${text.slice(0, 120)}`)
626896
+ () => renderInfo(`\x1B[38;5;37m[agent]\x1B[0m ${text.slice(0, 120)}`)
626732
626897
  );
626733
626898
  },
626734
626899
  // Keep state changes silent
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.3",
9
+ "version": "1.0.4",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
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",