omnius 1.0.324 → 1.0.326

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
@@ -160050,7 +160050,7 @@ var require_constants5 = __commonJS({
160050
160050
  writable: false,
160051
160051
  configurable: false
160052
160052
  };
160053
- var states = {
160053
+ var states2 = {
160054
160054
  CONNECTING: 0,
160055
160055
  OPEN: 1,
160056
160056
  CLOSING: 2,
@@ -160086,7 +160086,7 @@ var require_constants5 = __commonJS({
160086
160086
  uid,
160087
160087
  sentCloseFrameState,
160088
160088
  staticPropertyDescriptors,
160089
- states,
160089
+ states: states2,
160090
160090
  opcodes,
160091
160091
  maxUnsigned16Bit,
160092
160092
  parserStates,
@@ -160100,21 +160100,21 @@ var require_constants5 = __commonJS({
160100
160100
  var require_util7 = __commonJS({
160101
160101
  "../node_modules/undici/lib/web/websocket/util.js"(exports, module) {
160102
160102
  "use strict";
160103
- var { states, opcodes } = require_constants5();
160103
+ var { states: states2, opcodes } = require_constants5();
160104
160104
  var { isUtf8 } = __require("node:buffer");
160105
160105
  var { removeHTTPWhitespace } = require_data_url();
160106
160106
  var { collectASequenceOfCodePointsFast } = require_infra();
160107
160107
  function isConnecting(readyState) {
160108
- return readyState === states.CONNECTING;
160108
+ return readyState === states2.CONNECTING;
160109
160109
  }
160110
160110
  function isEstablished(readyState) {
160111
- return readyState === states.OPEN;
160111
+ return readyState === states2.OPEN;
160112
160112
  }
160113
160113
  function isClosing(readyState) {
160114
- return readyState === states.CLOSING;
160114
+ return readyState === states2.CLOSING;
160115
160115
  }
160116
160116
  function isClosed(readyState) {
160117
- return readyState === states.CLOSED;
160117
+ return readyState === states2.CLOSED;
160118
160118
  }
160119
160119
  function fireEvent(e2, target, eventFactory = (type, init2) => new Event(type, init2), eventInitDict = {}) {
160120
160120
  const event = eventFactory(e2, eventInitDict);
@@ -160382,7 +160382,7 @@ var require_frame = __commonJS({
160382
160382
  var require_connection = __commonJS({
160383
160383
  "../node_modules/undici/lib/web/websocket/connection.js"(exports, module) {
160384
160384
  "use strict";
160385
- var { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require_constants5();
160385
+ var { uid, states: states2, sentCloseFrameState, emptyBuffer, opcodes } = require_constants5();
160386
160386
  var { parseExtensions, isClosed, isClosing, isEstablished, isConnecting, validateCloseCodeAndReason } = require_util7();
160387
160387
  var { makeRequest } = require_request2();
160388
160388
  var { fetching } = require_fetch();
@@ -160489,7 +160489,7 @@ var require_connection = __commonJS({
160489
160489
  if (isClosed(object.readyState) || isClosing(object.readyState)) {
160490
160490
  } else if (!isEstablished(object.readyState)) {
160491
160491
  failWebsocketConnection(object);
160492
- object.readyState = states.CLOSING;
160492
+ object.readyState = states2.CLOSING;
160493
160493
  } else if (!object.closeState.has(sentCloseFrameState.SENT) && !object.closeState.has(sentCloseFrameState.RECEIVED)) {
160494
160494
  const frame = new WebsocketFrameSend();
160495
160495
  if (reason.length !== 0 && code8 === null) {
@@ -160510,9 +160510,9 @@ var require_connection = __commonJS({
160510
160510
  }
160511
160511
  object.socket.write(frame.createFrame(opcodes.CLOSE));
160512
160512
  object.closeState.add(sentCloseFrameState.SENT);
160513
- object.readyState = states.CLOSING;
160513
+ object.readyState = states2.CLOSING;
160514
160514
  } else {
160515
- object.readyState = states.CLOSING;
160515
+ object.readyState = states2.CLOSING;
160516
160516
  }
160517
160517
  }
160518
160518
  function failWebsocketConnection(handler, code8, reason, cause) {
@@ -160633,7 +160633,7 @@ var require_receiver = __commonJS({
160633
160633
  "use strict";
160634
160634
  var { Writable } = __require("node:stream");
160635
160635
  var assert = __require("node:assert");
160636
- var { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require_constants5();
160636
+ var { parserStates, opcodes, states: states2, emptyBuffer, sentCloseFrameState } = require_constants5();
160637
160637
  var {
160638
160638
  isValidStatusCode,
160639
160639
  isValidOpcode,
@@ -160921,7 +160921,7 @@ var require_receiver = __commonJS({
160921
160921
  this.#handler.socket.write(closeFrame.createFrame(opcodes.CLOSE));
160922
160922
  this.#handler.closeState.add(sentCloseFrameState.SENT);
160923
160923
  }
160924
- this.#handler.readyState = states.CLOSING;
160924
+ this.#handler.readyState = states2.CLOSING;
160925
160925
  this.#handler.closeState.add(sentCloseFrameState.RECEIVED);
160926
160926
  return false;
160927
160927
  } else if (opcode === opcodes.PING) {
@@ -161040,7 +161040,7 @@ var require_websocket = __commonJS({
161040
161040
  var { webidl } = require_webidl();
161041
161041
  var { URLSerializer } = require_data_url();
161042
161042
  var { environmentSettingsObject } = require_util4();
161043
- var { staticPropertyDescriptors, states, sentCloseFrameState, sendHints, opcodes } = require_constants5();
161043
+ var { staticPropertyDescriptors, states: states2, sentCloseFrameState, sendHints, opcodes } = require_constants5();
161044
161044
  var {
161045
161045
  isConnecting,
161046
161046
  isEstablished,
@@ -161093,7 +161093,7 @@ var require_websocket = __commonJS({
161093
161093
  }
161094
161094
  },
161095
161095
  onSocketError: (err) => {
161096
- this.#handler.readyState = states.CLOSING;
161096
+ this.#handler.readyState = states2.CLOSING;
161097
161097
  if (channels.socketError.hasSubscribers) {
161098
161098
  channels.socketError.publish(err);
161099
161099
  }
@@ -161116,7 +161116,7 @@ var require_websocket = __commonJS({
161116
161116
  });
161117
161117
  }
161118
161118
  },
161119
- readyState: states.CONNECTING,
161119
+ readyState: states2.CONNECTING,
161120
161120
  socket: null,
161121
161121
  closeState: /* @__PURE__ */ new Set(),
161122
161122
  controller: null,
@@ -161327,7 +161327,7 @@ var require_websocket = __commonJS({
161327
161327
  parser2.on("error", (err) => this.#handler.onParserError(err));
161328
161328
  this.#parser = parser2;
161329
161329
  this.#sendQueue = new SendQueue(response.socket);
161330
- this.#handler.readyState = states.OPEN;
161330
+ this.#handler.readyState = states2.OPEN;
161331
161331
  const extensions = response.headersList.get("sec-websocket-extensions");
161332
161332
  if (extensions !== null) {
161333
161333
  this.#extensions = extensions;
@@ -161353,7 +161353,7 @@ var require_websocket = __commonJS({
161353
161353
  }
161354
161354
  }
161355
161355
  #onMessage(type, data) {
161356
- if (this.#handler.readyState !== states.OPEN) {
161356
+ if (this.#handler.readyState !== states2.OPEN) {
161357
161357
  return;
161358
161358
  }
161359
161359
  let dataForEvent;
@@ -161392,7 +161392,7 @@ var require_websocket = __commonJS({
161392
161392
  code8 = result.code ?? 1005;
161393
161393
  reason = result.reason;
161394
161394
  }
161395
- this.#handler.readyState = states.CLOSED;
161395
+ this.#handler.readyState = states2.CLOSED;
161396
161396
  if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
161397
161397
  code8 = 1006;
161398
161398
  fireEvent("error", this, (type, init2) => new ErrorEvent2(type, init2), {
@@ -161433,10 +161433,10 @@ var require_websocket = __commonJS({
161433
161433
  };
161434
161434
  var { ping: ping2 } = WebSocket6;
161435
161435
  Reflect.deleteProperty(WebSocket6, "ping");
161436
- WebSocket6.CONNECTING = WebSocket6.prototype.CONNECTING = states.CONNECTING;
161437
- WebSocket6.OPEN = WebSocket6.prototype.OPEN = states.OPEN;
161438
- WebSocket6.CLOSING = WebSocket6.prototype.CLOSING = states.CLOSING;
161439
- WebSocket6.CLOSED = WebSocket6.prototype.CLOSED = states.CLOSED;
161436
+ WebSocket6.CONNECTING = WebSocket6.prototype.CONNECTING = states2.CONNECTING;
161437
+ WebSocket6.OPEN = WebSocket6.prototype.OPEN = states2.OPEN;
161438
+ WebSocket6.CLOSING = WebSocket6.prototype.CLOSING = states2.CLOSING;
161439
+ WebSocket6.CLOSED = WebSocket6.prototype.CLOSED = states2.CLOSED;
161440
161440
  Object.defineProperties(WebSocket6.prototype, {
161441
161441
  CONNECTING: staticPropertyDescriptors,
161442
161442
  OPEN: staticPropertyDescriptors,
@@ -161602,7 +161602,7 @@ var require_websocketstream = __commonJS({
161602
161602
  "use strict";
161603
161603
  var { createDeferredPromise: createDeferredPromise2 } = require_promise();
161604
161604
  var { environmentSettingsObject } = require_util4();
161605
- var { states, opcodes, sentCloseFrameState } = require_constants5();
161605
+ var { states: states2, opcodes, sentCloseFrameState } = require_constants5();
161606
161606
  var { webidl } = require_webidl();
161607
161607
  var { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require_util7();
161608
161608
  var { establishWebSocketConnection, failWebsocketConnection, closeWebSocketConnection } = require_connection();
@@ -161646,7 +161646,7 @@ var require_websocketstream = __commonJS({
161646
161646
  }
161647
161647
  },
161648
161648
  onSocketError: (err) => {
161649
- this.#handler.readyState = states.CLOSING;
161649
+ this.#handler.readyState = states2.CLOSING;
161650
161650
  if (channels.socketError.hasSubscribers) {
161651
161651
  channels.socketError.publish(err);
161652
161652
  }
@@ -161657,7 +161657,7 @@ var require_websocketstream = __commonJS({
161657
161657
  },
161658
161658
  onPong: () => {
161659
161659
  },
161660
- readyState: states.CONNECTING,
161660
+ readyState: states2.CONNECTING,
161661
161661
  socket: null,
161662
161662
  closeState: /* @__PURE__ */ new Set(),
161663
161663
  controller: null,
@@ -161699,7 +161699,7 @@ var require_websocketstream = __commonJS({
161699
161699
  signal.addEventListener("abort", () => {
161700
161700
  if (!isEstablished(this.#handler.readyState)) {
161701
161701
  failWebsocketConnection(this.#handler);
161702
- this.#handler.readyState = states.CLOSING;
161702
+ this.#handler.readyState = states2.CLOSING;
161703
161703
  this.#openedPromise.reject(signal.reason);
161704
161704
  this.#closedPromise.reject(signal.reason);
161705
161705
  this.#handshakeAborted = true;
@@ -161770,7 +161770,7 @@ var require_websocketstream = __commonJS({
161770
161770
  parser2.on("drain", () => this.#handler.onParserDrain());
161771
161771
  parser2.on("error", (err) => this.#handler.onParserError(err));
161772
161772
  this.#parser = parser2;
161773
- this.#handler.readyState = states.OPEN;
161773
+ this.#handler.readyState = states2.OPEN;
161774
161774
  const extensions = parsedExtensions ?? "";
161775
161775
  const protocol = response.headersList.get("sec-websocket-protocol") ?? "";
161776
161776
  const readable = new ReadableStream({
@@ -161801,7 +161801,7 @@ var require_websocketstream = __commonJS({
161801
161801
  }
161802
161802
  /** @type {import('../websocket').Handler['onMessage']} */
161803
161803
  #onMessage(type, data) {
161804
- if (this.#handler.readyState !== states.OPEN) {
161804
+ if (this.#handler.readyState !== states2.OPEN) {
161805
161805
  return;
161806
161806
  }
161807
161807
  let chunk;
@@ -161820,7 +161820,7 @@ var require_websocketstream = __commonJS({
161820
161820
  /** @type {import('../websocket').Handler['onSocketClose']} */
161821
161821
  #onSocketClose() {
161822
161822
  const wasClean = this.#handler.closeState.has(sentCloseFrameState.SENT) && this.#handler.closeState.has(sentCloseFrameState.RECEIVED);
161823
- this.#handler.readyState = states.CLOSED;
161823
+ this.#handler.readyState = states2.CLOSED;
161824
161824
  if (this.#handshakeAborted) {
161825
161825
  return;
161826
161826
  }
@@ -552312,7 +552312,10 @@ function detectProvider(url) {
552312
552312
  modelsPath: isLocal ? "/v1/models" : "/v1/models"
552313
552313
  };
552314
552314
  }
552315
- var PROVIDERS;
552315
+ function listProviderPresets() {
552316
+ return PROVIDER_PRESETS.map((p2) => ({ ...p2 }));
552317
+ }
552318
+ var PROVIDERS, PROVIDER_PRESETS;
552316
552319
  var init_normalizeUrl = __esm({
552317
552320
  "packages/backend-vllm/dist/normalizeUrl.js"() {
552318
552321
  "use strict";
@@ -552384,6 +552387,28 @@ var init_normalizeUrl = __esm({
552384
552387
  info: { id: "vllm", label: "vLLM (local)", local: true, authRequired: false, modelsPath: "/v1/models" }
552385
552388
  }
552386
552389
  ];
552390
+ PROVIDER_PRESETS = [
552391
+ // --- Local runtimes ---
552392
+ { id: "ollama", label: "Ollama (local)", local: true, authRequired: false, modelsPath: "/api/tags", defaultUrl: "http://127.0.0.1:11434", description: "Local Ollama runtime on port 11434." },
552393
+ { id: "lmstudio", label: "LM Studio (local)", local: true, authRequired: false, modelsPath: "/v1/models", defaultUrl: "http://127.0.0.1:1234/v1", description: "Local OpenAI-compatible server on port 1234." },
552394
+ { id: "vllm", label: "vLLM (local)", local: true, authRequired: false, modelsPath: "/v1/models", defaultUrl: "http://127.0.0.1:8000/v1", description: "Self-hosted OpenAI-compatible vLLM endpoint." },
552395
+ // --- Cloud providers ---
552396
+ { id: "openai", label: "OpenAI", local: false, authRequired: true, keyPrefix: "sk-", modelsPath: "/v1/models", defaultUrl: "https://api.openai.com/v1", apiKeyUrl: "https://platform.openai.com/api-keys", description: "OpenAI API models." },
552397
+ { id: "anthropic", label: "Anthropic (Claude)", local: false, authRequired: true, keyPrefix: "sk-ant-", modelsPath: "/v1/models", defaultUrl: "https://api.anthropic.com/v1", apiKeyUrl: "https://console.anthropic.com/settings/keys", description: "Claude via the Anthropic API." },
552398
+ { id: "openrouter", label: "OpenRouter", local: false, authRequired: true, keyPrefix: "sk-or-", modelsPath: "/v1/models", defaultUrl: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", description: "Routing across many hosted models." },
552399
+ { id: "groq", label: "Groq", local: false, authRequired: true, keyPrefix: "gsk_", modelsPath: "/v1/models", defaultUrl: "https://api.groq.com/openai/v1", apiKeyUrl: "https://console.groq.com/keys", description: "Groq OpenAI-compatible inference." },
552400
+ { id: "chutes", label: "Chutes AI", local: false, authRequired: true, keyPrefix: "cpk_", modelsPath: "/v1/models", defaultUrl: "https://llm.chutes.ai/v1", apiKeyUrl: "https://chutes.ai/app/api", description: "Chutes OpenAI-compatible endpoint." },
552401
+ { id: "deepinfra", label: "DeepInfra", local: false, authRequired: true, modelsPath: "/v1/models", defaultUrl: "https://api.deepinfra.com/v1/openai", apiKeyUrl: "https://deepinfra.com/dash/api_keys", description: "DeepInfra hosted models." },
552402
+ { id: "together", label: "Together AI", local: false, authRequired: true, modelsPath: "/v1/models", defaultUrl: "https://api.together.xyz/v1", apiKeyUrl: "https://api.together.xyz/settings/api-keys", description: "Together OpenAI-compatible inference." },
552403
+ { id: "fireworks", label: "Fireworks AI", local: false, authRequired: true, keyPrefix: "fw_", modelsPath: "/v1/models", defaultUrl: "https://api.fireworks.ai/inference/v1", apiKeyUrl: "https://fireworks.ai/account/api-keys", description: "Fireworks OpenAI-compatible inference." },
552404
+ { id: "mistral", label: "Mistral AI", local: false, authRequired: true, modelsPath: "/v1/models", defaultUrl: "https://api.mistral.ai/v1", apiKeyUrl: "https://console.mistral.ai/api-keys", description: "Mistral hosted models." },
552405
+ { id: "cerebras", label: "Cerebras", local: false, authRequired: true, keyPrefix: "csk-", modelsPath: "/v1/models", defaultUrl: "https://api.cerebras.ai/v1", apiKeyUrl: "https://cloud.cerebras.ai/platform", description: "Cerebras OpenAI-compatible inference." },
552406
+ { id: "sambanova", label: "SambaNova", local: false, authRequired: true, modelsPath: "/v1/models", defaultUrl: "https://api.sambanova.ai/v1", apiKeyUrl: "https://cloud.sambanova.ai/apis", description: "SambaNova OpenAI-compatible inference." },
552407
+ { id: "nvidia", label: "NVIDIA NIM", local: false, authRequired: true, keyPrefix: "nvapi-", modelsPath: "/v1/models", defaultUrl: "https://integrate.api.nvidia.com/v1", apiKeyUrl: "https://build.nvidia.com", description: "NVIDIA-hosted NIM models." },
552408
+ { id: "hyperbolic", label: "Hyperbolic", local: false, authRequired: true, modelsPath: "/v1/models", defaultUrl: "https://api.hyperbolic.xyz/v1", apiKeyUrl: "https://app.hyperbolic.xyz/settings", description: "Hyperbolic OpenAI-compatible inference." },
552409
+ // --- Catch-all ---
552410
+ { id: "custom", label: "Custom endpoint", local: false, authRequired: false, modelsPath: "/v1/models", description: "Any OpenAI-compatible endpoint — enter a URL." }
552411
+ ];
552387
552412
  }
552388
552413
  });
552389
552414
 
@@ -563637,11 +563662,11 @@ var init_streaming_executor = __esm({
563637
563662
  }
563638
563663
  /** Get the current state of all tool calls */
563639
563664
  getStates() {
563640
- const states = /* @__PURE__ */ new Map();
563665
+ const states2 = /* @__PURE__ */ new Map();
563641
563666
  for (const [id, entry] of this.tools) {
563642
- states.set(id, entry.state);
563667
+ states2.set(id, entry.state);
563643
563668
  }
563644
- return states;
563669
+ return states2;
563645
563670
  }
563646
563671
  /** Get count of tools in each state */
563647
563672
  getCounts() {
@@ -596660,10 +596685,61 @@ var init_secret_redactor = __esm({
596660
596685
  }
596661
596686
  });
596662
596687
 
596688
+ // packages/cli/src/tui/tool-collapse-store.ts
596689
+ function isCollapsibleBlock(id) {
596690
+ return states.has(id);
596691
+ }
596692
+ function ensureCollapsible(id) {
596693
+ let s2 = states.get(id);
596694
+ if (s2 === void 0) {
596695
+ s2 = globalDefault;
596696
+ states.set(id, s2);
596697
+ }
596698
+ return s2;
596699
+ }
596700
+ function getCollapseState(id) {
596701
+ return states.get(id) ?? globalDefault;
596702
+ }
596703
+ function setCollapseState(id, state) {
596704
+ states.set(id, state);
596705
+ }
596706
+ function toggleTitle(id) {
596707
+ const cur = getCollapseState(id);
596708
+ setCollapseState(id, cur === "collapsed" ? "preview" : "collapsed");
596709
+ }
596710
+ function toggleMore(id) {
596711
+ const cur = getCollapseState(id);
596712
+ setCollapseState(id, cur === "expanded" ? "preview" : "expanded");
596713
+ }
596714
+ function toggleAll() {
596715
+ let anyOpen = false;
596716
+ for (const s2 of states.values()) {
596717
+ if (s2 !== "collapsed") {
596718
+ anyOpen = true;
596719
+ break;
596720
+ }
596721
+ }
596722
+ const next = anyOpen ? "collapsed" : "preview";
596723
+ for (const id of states.keys()) states.set(id, next);
596724
+ globalDefault = next;
596725
+ }
596726
+ var PREVIEW_ROWS, READ_MORE_LABEL, READ_LESS_LABEL, globalDefault, states;
596727
+ var init_tool_collapse_store = __esm({
596728
+ "packages/cli/src/tui/tool-collapse-store.ts"() {
596729
+ "use strict";
596730
+ PREVIEW_ROWS = 8;
596731
+ READ_MORE_LABEL = "read more…";
596732
+ READ_LESS_LABEL = "read less";
596733
+ globalDefault = "preview";
596734
+ states = /* @__PURE__ */ new Map();
596735
+ }
596736
+ });
596737
+
596663
596738
  // packages/cli/src/tui/render.ts
596664
596739
  var render_exports = {};
596665
596740
  __export(render_exports, {
596666
596741
  SLASH_COMMANDS: () => SLASH_COMMANDS2,
596742
+ applyCollapseToBox: () => applyCollapseToBox,
596667
596743
  breakTelegramCoalesce: () => breakTelegramCoalesce,
596668
596744
  c: () => c3,
596669
596745
  charWidth: () => charWidth2,
@@ -597088,6 +597164,52 @@ function buildToolBottom(width, colorCode) {
597088
597164
  const border = toolColorSeq(colorCode);
597089
597165
  return `${border}${BOX_BL2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_BR2}${toolResetSeq()}`;
597090
597166
  }
597167
+ function dimSeqOrEmpty() {
597168
+ return _colorsEnabled && stdoutIsTTY() ? "\x1B[2m" : "";
597169
+ }
597170
+ function underlineSeqOrEmpty() {
597171
+ return _colorsEnabled && stdoutIsTTY() ? "\x1B[4m" : "";
597172
+ }
597173
+ function collapsedBarLine(desc) {
597174
+ const seq = toolColorSeq(desc.colorCode);
597175
+ const reset = toolResetSeq();
597176
+ const dim = dimSeqOrEmpty();
597177
+ const title = sanitizeToolBoxContent(desc.title);
597178
+ const metrics2 = desc.metrics ? ` ${dim}${sanitizeToolBoxContent(desc.metrics)}${reset}` : "";
597179
+ return `${seq}▸ ${title}${reset}${metrics2}`;
597180
+ }
597181
+ function affordanceRowText(label, hiddenRows) {
597182
+ const ul = underlineSeqOrEmpty();
597183
+ const dim = dimSeqOrEmpty();
597184
+ const reset = toolResetSeq();
597185
+ const suffix = hiddenRows && hiddenRows > 0 ? `${dim} (${hiddenRows} more line${hiddenRows === 1 ? "" : "s"})${reset}` : "";
597186
+ return `${ul}${label}${reset}${suffix}`;
597187
+ }
597188
+ function applyCollapseToBox(fullLines, opts) {
597189
+ if (fullLines.length === 0) return fullLines;
597190
+ if (opts.state === "collapsed") return [collapsedBarLine(opts.desc)];
597191
+ if (fullLines.length < 4) return fullLines;
597192
+ const w = Math.max(40, opts.width);
597193
+ const head = fullLines.slice(0, 2);
597194
+ const bottom = fullLines[fullLines.length - 1];
597195
+ const body = fullLines.slice(2, fullLines.length - 1);
597196
+ if (body.length <= PREVIEW_ROWS) return fullLines;
597197
+ if (opts.state === "preview") {
597198
+ const shown = body.slice(0, PREVIEW_ROWS);
597199
+ const moreRow = buildToolContentRow(
597200
+ affordanceRowText(READ_MORE_LABEL, body.length - PREVIEW_ROWS),
597201
+ w,
597202
+ opts.desc.colorCode
597203
+ );
597204
+ return [...head, ...shown, moreRow, bottom];
597205
+ }
597206
+ const lessRow = buildToolContentRow(
597207
+ affordanceRowText(READ_LESS_LABEL),
597208
+ w,
597209
+ opts.desc.colorCode
597210
+ );
597211
+ return [...head, ...body, lessRow, bottom];
597212
+ }
597091
597213
  function buildToolContentRow(content, width, colorCode) {
597092
597214
  const border = toolColorSeq(colorCode);
597093
597215
  const reset = toolResetSeq();
@@ -597330,12 +597452,24 @@ function buildToolBoxLines(data, width) {
597330
597452
  lines.push(buildToolBottom(w, data.colorCode));
597331
597453
  return lines;
597332
597454
  }
597333
- function renderToolDynamicBlock(kind, render2, opts) {
597455
+ function renderToolDynamicBlock(kind, render2, opts, collapse) {
597334
597456
  const redir = _contentWriteHook?.redirect?.();
597335
597457
  const host = opts.host !== void 0 ? opts.host : _contentWriteHook?.dynamicBlockHost?.();
597336
597458
  if (!redir && host) {
597337
597459
  const id = `${kind}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
597338
- host.registerDynamicBlock(id, render2);
597460
+ if (collapse) {
597461
+ ensureCollapsible(id);
597462
+ host.registerDynamicBlock(
597463
+ id,
597464
+ (width) => applyCollapseToBox(render2(width), {
597465
+ state: getCollapseState(id),
597466
+ desc: collapse,
597467
+ width
597468
+ })
597469
+ );
597470
+ } else {
597471
+ host.registerDynamicBlock(id, render2);
597472
+ }
597339
597473
  host.appendDynamicBlock(id);
597340
597474
  return;
597341
597475
  }
@@ -597800,10 +597934,32 @@ function renderToolLine(content, isLast = false) {
597800
597934
  process.stdout.write(`${lines.join("\n")}
597801
597935
  `);
597802
597936
  }
597937
+ function toolResultCollapseDescriptor(toolName, success, output, opts) {
597938
+ const label = TOOL_LABELS[toolName] ?? toolName;
597939
+ const status = success ? "✔" : "✖";
597940
+ const rawLines = output.split("\n").filter((line) => line.trim()).length;
597941
+ const metrics2 = [
597942
+ success ? "ok" : "failed",
597943
+ rawLines > 0 ? `${rawLines} line${rawLines === 1 ? "" : "s"}` : "",
597944
+ output.length > 0 ? `${output.length.toLocaleString()} chars` : "",
597945
+ opts.durationMs && opts.durationMs > 0 ? formatDuration4(opts.durationMs) : ""
597946
+ ].filter(Boolean).join(" · ");
597947
+ return {
597948
+ title: `${status} ${label}`,
597949
+ metrics: metrics2,
597950
+ colorCode: success ? toolColorCode(toolName) : TOOL_ERROR_COLOR_CODE
597951
+ };
597952
+ }
597803
597953
  function renderToolResult(toolName, success, output, verboseOrOpts) {
597804
597954
  breakTelegramCoalesce();
597805
597955
  const opts = normalizeToolOpts(verboseOrOpts);
597806
597956
  const frozenOutput = getSecretRedactor().redactText(String(output ?? ""));
597957
+ const collapseDesc = toolResultCollapseDescriptor(
597958
+ toolName,
597959
+ success,
597960
+ frozenOutput,
597961
+ opts
597962
+ );
597807
597963
  if (_pendingToolCall && _pendingToolCall.toolName === toolName) {
597808
597964
  const pending2 = _pendingToolCall;
597809
597965
  _pendingToolCall = null;
@@ -597817,7 +597973,8 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
597817
597973
  { ...opts, verbose: pending2.verbose ?? opts.verbose },
597818
597974
  width
597819
597975
  ),
597820
- opts
597976
+ opts,
597977
+ collapseDesc
597821
597978
  );
597822
597979
  return;
597823
597980
  }
@@ -597825,7 +597982,8 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
597825
597982
  renderToolDynamicBlock(
597826
597983
  "tool-result",
597827
597984
  (width) => buildToolResultBoxLines(toolName, success, frozenOutput, opts, width),
597828
- opts
597985
+ opts,
597986
+ collapseDesc
597829
597987
  );
597830
597988
  }
597831
597989
  function renderBoxedBlock(opts) {
@@ -598248,6 +598406,7 @@ var init_render = __esm({
598248
598406
  init_syntax_highlight();
598249
598407
  init_model_picker();
598250
598408
  init_secret_redactor();
598409
+ init_tool_collapse_store();
598251
598410
  c3 = {
598252
598411
  bold: (t2) => ansi2("1", t2),
598253
598412
  dim: (t2) => stdoutIsTTY() ? `${dimFg()}${t2}\x1B[0m` : t2,
@@ -607576,6 +607735,7 @@ var init_status_bar = __esm({
607576
607735
  init_overlay_lock();
607577
607736
  init_dist5();
607578
607737
  init_theme();
607738
+ init_tool_collapse_store();
607579
607739
  init_layout2();
607580
607740
  EXPERT_TOOL_BASELINES = {
607581
607741
  file_read: 12,
@@ -607807,6 +607967,11 @@ var init_status_bar = __esm({
607807
607967
  _contentScrollOffset = 0;
607808
607968
  // 0 = live (bottom), >0 = scrolled back
607809
607969
  _contentMaxLines = 1e4;
607970
+ // Snapshot of the most recent content paint, used to map a mouse-click screen
607971
+ // row back to the reflowed line (and thus its dynamic-block id) for click
607972
+ // hit-testing on collapsible tool boxes. Refreshed on every repaintContent().
607973
+ _lastPaintReflow = null;
607974
+ _lastPaintStartIdx = 0;
607810
607975
  /**
607811
607976
  * Dynamic content blocks — width-aware regions that re-render themselves
607812
607977
  * when the terminal resizes. The renderer registered here is called from
@@ -609513,6 +609678,55 @@ var init_status_bar = __esm({
609513
609678
  get textSelection() {
609514
609679
  return this._textSelection;
609515
609680
  }
609681
+ /**
609682
+ * Map a screen row to the collapsible tool box painted there (if any). Uses
609683
+ * the snapshot captured during the last repaintContent(): screen row r shows
609684
+ * reflowedLines[startIdx + (r - scrollRegionTop)]. All reflowed rows of a
609685
+ * dynamic block share the sentinel's bufferIdx, so we can recover the block
609686
+ * id and the row's offset within the block.
609687
+ */
609688
+ hitTestContentBlock(screenRow) {
609689
+ const reflow = this._lastPaintReflow;
609690
+ if (!reflow) return null;
609691
+ const rel = screenRow - this.scrollRegionTop;
609692
+ if (rel < 0) return null;
609693
+ const idx = this._lastPaintStartIdx + rel;
609694
+ const entry = reflow[idx];
609695
+ if (!entry) return null;
609696
+ const src2 = this._contentLines[entry.bufferIdx];
609697
+ if (!src2 || !src2.startsWith(this.DYNAMIC_BLOCK_MARK_PREFIX) || !src2.endsWith(this.DYNAMIC_BLOCK_MARK_SUFFIX)) {
609698
+ return null;
609699
+ }
609700
+ const id = src2.slice(
609701
+ this.DYNAMIC_BLOCK_MARK_PREFIX.length,
609702
+ src2.length - this.DYNAMIC_BLOCK_MARK_SUFFIX.length
609703
+ );
609704
+ let first2 = idx;
609705
+ while (first2 > 0 && reflow[first2 - 1]?.bufferIdx === entry.bufferIdx) {
609706
+ first2--;
609707
+ }
609708
+ return { id, offset: idx - first2, lineText: entry.line };
609709
+ }
609710
+ /**
609711
+ * Handle a click inside a collapsible tool box. Title row (offset 0) toggles
609712
+ * collapsed↔preview; a "read more…/read less" row toggles preview↔expanded;
609713
+ * other body rows are left alone so text selection still works. Returns true
609714
+ * when the click was consumed.
609715
+ */
609716
+ handleContentBlockClick(screenRow) {
609717
+ const hit = this.hitTestContentBlock(screenRow);
609718
+ if (!hit || !isCollapsibleBlock(hit.id)) return false;
609719
+ const plain = stripAnsi(hit.lineText);
609720
+ if (plain.includes(READ_MORE_LABEL) || plain.includes(READ_LESS_LABEL)) {
609721
+ toggleMore(hit.id);
609722
+ } else if (hit.offset === 0) {
609723
+ toggleTitle(hit.id);
609724
+ } else {
609725
+ return false;
609726
+ }
609727
+ this.refreshDynamicBlocks();
609728
+ return true;
609729
+ }
609516
609730
  /**
609517
609731
  * Handle a mouse pointer event (press/drag/release).
609518
609732
  * Called by MouseFilterStream's pointer handler.
@@ -609522,6 +609736,9 @@ var init_status_bar = __esm({
609522
609736
  handlePointerEvent(type, col, row) {
609523
609737
  if (!this.active) return;
609524
609738
  const w = termCols();
609739
+ if (type === "press" && row >= this.scrollRegionTop) {
609740
+ if (this.handleContentBlockClick(row)) return;
609741
+ }
609525
609742
  if (type === "press" && this._suggestions.length > 0) {
609526
609743
  if (this.suggestClickAt(row)) return;
609527
609744
  }
@@ -610174,6 +610391,20 @@ ${CONTENT_BG_SEQ}`);
610174
610391
  this.repaintContent();
610175
610392
  this.renderFooterAndPositionInput();
610176
610393
  }
610394
+ /**
610395
+ * Flicker-free in-place repaint of the content area (and thus any dynamic
610396
+ * blocks within it). Unlike refreshDisplay(), this does NOT blank the area
610397
+ * first via fillContentArea() — repaintContent() uses synchronized output
610398
+ * (\x1B[?2026h) and a per-row \x1B[2K clear, so a live block that updates
610399
+ * many times per second (e.g. the shell timer) refreshes without the whole
610400
+ * TUI flashing. Implements the DynamicBlockHost.refreshDynamicBlocks contract.
610401
+ */
610402
+ refreshDynamicBlocks() {
610403
+ if (!this.active) return;
610404
+ if (this._contentScrollOffset > 0 || this._mouseSelecting) return;
610405
+ if (isOverlayActive() || this._suspendContentLayer) return;
610406
+ this.repaintContent();
610407
+ }
610177
610408
  clearStreamingRepaintTimer() {
610178
610409
  if (!this._streamingRepaintTimer) return;
610179
610410
  clearTimeout(this._streamingRepaintTimer);
@@ -610552,6 +610783,8 @@ ${CONTENT_BG_SEQ}`);
610552
610783
  if (this._contentScrollOffset === 0) this._autoScroll = true;
610553
610784
  }
610554
610785
  const startIdx = Math.max(0, totalLines - h - this._contentScrollOffset);
610786
+ this._lastPaintReflow = reflowedLines;
610787
+ this._lastPaintStartIdx = startIdx;
610555
610788
  const headerSafeFloor = layout().headerBottom + 1;
610556
610789
  let buf = "\x1B[?2026h";
610557
610790
  buf += "\x1B7";
@@ -628720,7 +628953,7 @@ __export(commands_exports, {
628720
628953
  registerSlashCommand: () => registerSlashCommand
628721
628954
  });
628722
628955
  import * as nodeOs from "node:os";
628723
- import { execSync as nodeExecSync } from "node:child_process";
628956
+ import { execSync as nodeExecSync, spawn as nodeSpawn2 } from "node:child_process";
628724
628957
  import { createHash as createHash35 } from "node:crypto";
628725
628958
  import {
628726
628959
  existsSync as existsSync127,
@@ -639831,6 +640064,87 @@ async function handleVoiceList(ctx3, focusFilename) {
639831
640064
  if (msg) renderInfo(msg);
639832
640065
  }
639833
640066
  }
640067
+ function openUrlInBrowser(url) {
640068
+ if (process.env["OMNIUS_NO_BROWSER"] === "1") return false;
640069
+ if (!/^https?:\/\//i.test(url)) return false;
640070
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
640071
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
640072
+ try {
640073
+ const child = nodeSpawn2(cmd, args, { stdio: "ignore", detached: true });
640074
+ child.on("error", () => {
640075
+ });
640076
+ child.unref();
640077
+ return true;
640078
+ } catch {
640079
+ return false;
640080
+ }
640081
+ }
640082
+ function clickableLink(url, text2 = url) {
640083
+ if (!process.stdout.isTTY) return text2;
640084
+ return `\x1B]8;;${url}\x07${text2}\x1B]8;;\x07`;
640085
+ }
640086
+ async function browseProviderPresets(ctx3, local) {
640087
+ const presets = listProviderPresets();
640088
+ const byKey = new Map(presets.map((p2) => [p2.id, p2]));
640089
+ const items = presets.map((p2) => ({
640090
+ key: p2.id,
640091
+ label: p2.local ? `${c3.green("●")} ${p2.label}` : p2.label,
640092
+ detail: [
640093
+ p2.defaultUrl || "enter a custom URL",
640094
+ p2.authRequired ? "API key required" : p2.local ? "local · no key" : "no key",
640095
+ p2.description || ""
640096
+ ].filter(Boolean).join(" · ")
640097
+ }));
640098
+ let pending2 = null;
640099
+ const result = await tuiSelect({
640100
+ items,
640101
+ title: "Add inference provider",
640102
+ rl: ctx3.rl,
640103
+ availableRows: ctx3.availableContentRows?.(),
640104
+ onEnter: (item, { getInput, resolve: resolve71 }) => {
640105
+ const preset = byKey.get(item.key);
640106
+ if (!preset) return false;
640107
+ void (async () => {
640108
+ let url2 = preset.defaultUrl ?? "";
640109
+ if (!url2) {
640110
+ const typed = await getInput("Endpoint URL", "https://");
640111
+ if (!typed || !typed.trim()) {
640112
+ resolve71({ confirmed: false, key: item.key, index: -1 });
640113
+ return;
640114
+ }
640115
+ url2 = typed.trim();
640116
+ }
640117
+ let key2 = "";
640118
+ if (preset.authRequired || !preset.local) {
640119
+ let promptLabel = "API key";
640120
+ if (preset.apiKeyUrl) {
640121
+ const opened = openUrlInBrowser(preset.apiKeyUrl);
640122
+ promptLabel = opened ? `API key (opened ${preset.apiKeyUrl} in browser)` : `API key (get one: ${preset.apiKeyUrl})`;
640123
+ }
640124
+ const entered = await getInput(
640125
+ preset.authRequired ? promptLabel : `${promptLabel} (optional)`,
640126
+ ""
640127
+ );
640128
+ key2 = (entered ?? "").trim();
640129
+ }
640130
+ pending2 = { url: url2, key: key2 };
640131
+ resolve71({ confirmed: true, key: "__apply__", index: -1 });
640132
+ })();
640133
+ return true;
640134
+ }
640135
+ });
640136
+ if (!result.confirmed || result.key !== "__apply__" || !pending2) {
640137
+ renderInfo("Provider selection cancelled.");
640138
+ return;
640139
+ }
640140
+ const { url, key } = pending2;
640141
+ const keyUrl = presets.find((p2) => p2.defaultUrl === url)?.apiKeyUrl;
640142
+ if (keyUrl) {
640143
+ process.stdout.write(` ${c3.dim("API key page:")} ${clickableLink(keyUrl)}
640144
+ `);
640145
+ }
640146
+ await handleEndpoint(key ? `${url} --auth ${key}` : url, ctx3, local);
640147
+ }
639834
640148
  async function handleEndpoint(arg, ctx3, local = false) {
639835
640149
  if (!arg) {
639836
640150
  const history = loadUsageHistory("endpoint", ctx3.repoRoot);
@@ -639845,6 +640159,11 @@ async function handleEndpoint(arg, ctx3, local = false) {
639845
640159
  detail: `${provider2} ${uses}${auth}`
639846
640160
  };
639847
640161
  });
640162
+ items.push({
640163
+ key: "__providers__",
640164
+ label: `${c3.cyan("◈")} Add from provider list`,
640165
+ detail: "Pick OpenAI, Anthropic, Groq, Ollama… and enter a key"
640166
+ });
639848
640167
  items.push({
639849
640168
  key: "__add__",
639850
640169
  label: `${c3.green("+")} Add endpoint`,
@@ -639886,9 +640205,17 @@ async function handleEndpoint(arg, ctx3, local = false) {
639886
640205
  resolve71({ confirmed: true, key: "__sponsor__", index: -1 });
639887
640206
  return true;
639888
640207
  }
640208
+ if (item.key === "__providers__") {
640209
+ resolve71({ confirmed: true, key: "__providers__", index: -1 });
640210
+ return true;
640211
+ }
639889
640212
  return false;
639890
640213
  }
639891
640214
  });
640215
+ if (result.confirmed && result.key === "__providers__") {
640216
+ await browseProviderPresets(ctx3, local);
640217
+ return;
640218
+ }
639892
640219
  if (result.confirmed && result.key === "__add__" && addedEndpoint) {
639893
640220
  await handleEndpoint(addedEndpoint, ctx3, local);
639894
640221
  return;
@@ -639914,6 +640241,11 @@ async function handleEndpoint(arg, ctx3, local = false) {
639914
640241
  label: `${currentProvider.label} — ${ctx3.config.backendUrl}`,
639915
640242
  detail: `${ctx3.config.backendType} ${ctx3.config.apiKey ? "Auth: Bearer token set" : "No auth"}`
639916
640243
  },
640244
+ {
640245
+ key: "__providers__",
640246
+ label: `${c3.cyan("◈")} Add from provider list`,
640247
+ detail: "Pick OpenAI, Anthropic, Groq, Ollama… and enter a key"
640248
+ },
639917
640249
  {
639918
640250
  key: "__add__",
639919
640251
  label: `${c3.green("+")} Add endpoint`,
@@ -639946,10 +640278,16 @@ async function handleEndpoint(arg, ctx3, local = false) {
639946
640278
  resolve71({ confirmed: true, key: "__sponsor__", index: -1 });
639947
640279
  return true;
639948
640280
  }
640281
+ if (item.key === "__providers__") {
640282
+ resolve71({ confirmed: true, key: "__providers__", index: -1 });
640283
+ return true;
640284
+ }
639949
640285
  return false;
639950
640286
  }
639951
640287
  });
639952
- if (noHistResult.confirmed && noHistResult.key === "__add__" && addedUrl) {
640288
+ if (noHistResult.confirmed && noHistResult.key === "__providers__") {
640289
+ await browseProviderPresets(ctx3, local);
640290
+ } else if (noHistResult.confirmed && noHistResult.key === "__add__" && addedUrl) {
639953
640291
  await handleEndpoint(addedUrl, ctx3, local);
639954
640292
  } else if (noHistResult.confirmed && noHistResult.key === "__sponsor__") {
639955
640293
  await handleSponsoredEndpoint(ctx3, local);
@@ -639999,6 +640337,10 @@ async function handleEndpoint(arg, ctx3, local = false) {
639999
640337
  await handleSponsoredEndpoint(ctx3, local);
640000
640338
  return;
640001
640339
  }
640340
+ if (arg === "providers" || arg === "list" || arg === "browse") {
640341
+ await browseProviderPresets(ctx3, local);
640342
+ return;
640343
+ }
640002
640344
  if (arg.startsWith("add ")) {
640003
640345
  const addArg = arg.slice(4).replace(/\u2014/g, "--").replace(/\u2013/g, "--");
640004
640346
  const addParts = addArg.split(/\s+/);
@@ -653287,8 +653629,8 @@ var init_telegram_stats_menu = __esm({
653287
653629
  INACTIVITY_TIMEOUT_MS2 = 6e4;
653288
653630
  COUNTDOWN_SECONDS2 = 10;
653289
653631
  StatsMenuTimerManager = class {
653290
- constructor(states, callbacks, getSnapshot) {
653291
- this.states = states;
653632
+ constructor(states2, callbacks, getSnapshot) {
653633
+ this.states = states2;
653292
653634
  this.callbacks = callbacks;
653293
653635
  this.getSnapshot = getSnapshot;
653294
653636
  }
@@ -668271,9 +668613,9 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668271
668613
  }
668272
668614
  createTelegramGenerativeProgressBridge(chatId, msg) {
668273
668615
  if (chatId === void 0) return void 0;
668274
- const states = /* @__PURE__ */ new Map();
668616
+ const states2 = /* @__PURE__ */ new Map();
668275
668617
  const stateFor = (toolName) => {
668276
- let state = states.get(toolName);
668618
+ let state = states2.get(toolName);
668277
668619
  if (!state) {
668278
668620
  state = {
668279
668621
  messageId: null,
@@ -668281,7 +668623,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668281
668623
  queuedHtml: null,
668282
668624
  lastRenderedAt: 0
668283
668625
  };
668284
- states.set(toolName, state);
668626
+ states2.set(toolName, state);
668285
668627
  }
668286
668628
  return state;
668287
668629
  };
@@ -668354,7 +668696,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668354
668696
  },
668355
668697
  complete: (toolName, result) => {
668356
668698
  if (!generationKindForToolName(toolName)) return;
668357
- const state = states.get(toolName);
668699
+ const state = states2.get(toolName);
668358
668700
  if (!state && result.success) return;
668359
668701
  const html = completeHtml(toolName, result);
668360
668702
  if (!html) return;
@@ -675739,6 +676081,10 @@ function finishShellLiveBlock(state, success) {
675739
676081
  }
675740
676082
  state.status = success ? "ok" : "failed";
675741
676083
  }
676084
+ function shellLiveBlockFingerprint(state) {
676085
+ const sec = Math.floor(Math.max(0, Date.now() - state.startedAt) / 1e3);
676086
+ return `${state.status}|${state.lines.length}|${state.currentLine.length}|${sec}`;
676087
+ }
675742
676088
  function buildShellLiveBlockLines(state, width) {
675743
676089
  const w = Math.max(36, width);
675744
676090
  const inner = Math.max(1, w - 4);
@@ -677779,6 +678125,10 @@ var init_direct_input = __esm({
677779
678125
  this._deleteWordLeft();
677780
678126
  return;
677781
678127
  case 21:
678128
+ if (this.line.length === 0) {
678129
+ this.emit("ctrl-u");
678130
+ return;
678131
+ }
677782
678132
  this.line = this.line.slice(this.cursor);
677783
678133
  this.cursor = 0;
677784
678134
  return;
@@ -681497,20 +681847,20 @@ async function handleNexusStatus(ctx3) {
681497
681847
  join163(process.cwd(), ".omnius", "nexus-peer-state.json"),
681498
681848
  join163(homedir56(), ".omnius", "nexus-peer-cache.json")
681499
681849
  ];
681500
- const states = [];
681850
+ const states2 = [];
681501
681851
  for (const p2 of statePaths) {
681502
681852
  if (!existsSync151(p2)) continue;
681503
681853
  try {
681504
681854
  const raw = readFileSync123(p2, "utf-8");
681505
- states.push({ source: p2, data: JSON.parse(raw) });
681855
+ states2.push({ source: p2, data: JSON.parse(raw) });
681506
681856
  } catch (e2) {
681507
- states.push({ source: p2, error: String(e2) });
681857
+ states2.push({ source: p2, error: String(e2) });
681508
681858
  }
681509
681859
  }
681510
681860
  const config = loadConfig();
681511
681861
  sendJson2(res, 200, {
681512
- connected: states.length > 0,
681513
- peer_cache_files: states,
681862
+ connected: states2.length > 0,
681863
+ peer_cache_files: states2,
681514
681864
  agent_name: loadAgentName(),
681515
681865
  backend_url: config.backendUrl
681516
681866
  });
@@ -684700,6 +685050,100 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
684700
685050
  border-color: var(--color-border-strong);
684701
685051
  }
684702
685052
 
685053
+ .settings-provider-module-grid {
685054
+ display: grid;
685055
+ grid-template-columns: repeat(auto-fit, minmax(156px, 1fr));
685056
+ gap: 10px;
685057
+ }
685058
+ .settings-provider-module {
685059
+ min-height: 118px;
685060
+ border: 1px solid var(--color-border);
685061
+ border-radius: 8px;
685062
+ background: var(--color-bg-input);
685063
+ color: var(--color-fg);
685064
+ display: grid;
685065
+ align-content: center;
685066
+ justify-items: center;
685067
+ gap: 7px;
685068
+ padding: 12px;
685069
+ text-align: center;
685070
+ font: inherit;
685071
+ cursor: pointer;
685072
+ }
685073
+ .settings-provider-module:hover {
685074
+ background: var(--color-bg-hover);
685075
+ border-color: var(--color-border-strong);
685076
+ }
685077
+ .settings-provider-module.active {
685078
+ border-color: var(--color-brand);
685079
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-brand) 45%, transparent);
685080
+ }
685081
+ .settings-provider-brand {
685082
+ width: 34px;
685083
+ height: 34px;
685084
+ border-radius: 8px;
685085
+ border: 1px solid var(--color-border);
685086
+ background: var(--color-bg);
685087
+ display: inline-grid;
685088
+ place-items: center;
685089
+ overflow: hidden;
685090
+ color: var(--color-brand);
685091
+ font-weight: 700;
685092
+ }
685093
+ .settings-provider-brand img {
685094
+ width: 22px;
685095
+ height: 22px;
685096
+ object-fit: contain;
685097
+ }
685098
+ .settings-provider-module strong {
685099
+ font-size: 0.78rem;
685100
+ font-weight: 700;
685101
+ max-width: 100%;
685102
+ overflow-wrap: anywhere;
685103
+ }
685104
+ .settings-provider-module small {
685105
+ color: var(--color-fg-muted);
685106
+ font-size: 0.68rem;
685107
+ line-height: 1.25;
685108
+ }
685109
+ .settings-provider-setup {
685110
+ border: 1px solid var(--color-border);
685111
+ border-radius: 8px;
685112
+ background: var(--color-bg-elevated);
685113
+ padding: 12px;
685114
+ display: grid;
685115
+ gap: 10px;
685116
+ }
685117
+ .settings-provider-setup-head {
685118
+ display: grid;
685119
+ grid-template-columns: auto minmax(0, 1fr);
685120
+ gap: 10px;
685121
+ align-items: center;
685122
+ }
685123
+ .settings-provider-setup-head strong {
685124
+ display: block;
685125
+ font-size: 0.82rem;
685126
+ }
685127
+ .settings-provider-setup-head small,
685128
+ .settings-provider-meta {
685129
+ color: var(--color-fg-muted);
685130
+ font-size: 0.7rem;
685131
+ }
685132
+ .settings-provider-actions {
685133
+ display: flex;
685134
+ gap: 8px;
685135
+ align-items: center;
685136
+ flex-wrap: wrap;
685137
+ }
685138
+ .settings-provider-link {
685139
+ color: var(--color-brand);
685140
+ border: 1px solid var(--color-border);
685141
+ border-radius: var(--radius-sm);
685142
+ padding: 4px 8px;
685143
+ text-decoration: none;
685144
+ font-size: 0.7rem;
685145
+ }
685146
+
684703
685147
  /* Settings models list rows */
684704
685148
  #settings-models-list .row,
684705
685149
  #mm-list .row {
@@ -685399,8 +685843,8 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
685399
685843
  </label>
685400
685844
  </section>
685401
685845
  <section class="settings-pane" id="settings-pane-connections" role="tabpanel" hidden>
685402
- <h4>Backend</h4>
685403
- <p style="font-size:0.74rem;color:var(--color-fg-muted);margin:6px 0 12px">Loaded from /v1/config edits POST /v1/config/endpoint.</p>
685846
+ <h4>Inference providers</h4>
685847
+ <p style="font-size:0.74rem;color:var(--color-fg-muted);margin:6px 0 12px">Choose a provider module, add auth when needed, then save it to the daemon endpoint.</p>
685404
685848
  <div id="settings-connections-host">
685405
685849
  <button onclick="loadSettingsConnections()" style="font-size:0.74rem">load current</button>
685406
685850
  </div>
@@ -692234,32 +692678,21 @@ async function loadSettingsConnections() {
692234
692678
  '</div>';
692235
692679
  // Stash history globally so click handlers can resolve index → record.
692236
692680
  window.__omniusEndpointHistory = history;
692681
+ const activeProviderId = settingsProviderIdForUrl(ep);
692682
+ const selectedProviderId = settingsProviderById(window.__omniusSelectedProviderModule)
692683
+ ? window.__omniusSelectedProviderModule
692684
+ : (activeProviderId || 'ollama');
692685
+ window.__omniusSelectedProviderModule = selectedProviderId;
692237
692686
  host.innerHTML =
692238
692687
  '<div style="display:flex;flex-direction:column;gap:14px">' +
692239
- // Quick presets — one-click apply for the common defaults so the
692240
- // user doesn't have to type or even pick a backend type. Selecting
692241
- // a preset fills the URL + backend type fields below; clicking
692242
- // "Apply preset" saves directly without further input.
692243
692688
  '<div>' +
692244
- '<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Quick preset</label>' +
692245
- '<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">' +
692246
- '<select id="settings-conn-preset" style="flex:1;min-width:240px;background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-fg);padding:6px 10px;border-radius:var(--radius-sm);font-size:0.78rem">' +
692247
- '<option value="">— select preset —</option>' +
692248
- '<option value="ollama">Ollama (http://127.0.0.1:11434)</option>' +
692249
- '<option value="ollama-lan">Ollama on LAN (http://0.0.0.0:11434)</option>' +
692250
- '<option value="vllm">vLLM (http://127.0.0.1:8000/v1)</option>' +
692251
- '<option value="lmstudio">LM Studio (http://127.0.0.1:1234/v1)</option>' +
692252
- '<option value="openai">OpenAI (https://api.openai.com/v1)</option>' +
692253
- '<option value="anthropic">Anthropic (https://api.anthropic.com/v1)</option>' +
692254
- '<option value="chutes">Chutes (https://llm.chutes.ai/v1)</option>' +
692255
- '<option value="groq">Groq (https://api.groq.com/openai/v1)</option>' +
692256
- '<option value="deepinfra">DeepInfra (https://api.deepinfra.com/v1/openai)</option>' +
692257
- '</select>' +
692258
- '<button class="omnius-btn-secondary" type="button" onclick="applyEndpointPreset(true)" style="background:var(--color-accent);color:var(--color-accent-fg);border-color:var(--color-accent)">apply preset</button>' +
692259
- '<button class="omnius-btn-secondary" type="button" onclick="applyEndpointPreset(false)" title="fill the fields below without saving">load to form</button>' +
692689
+ '<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px">' +
692690
+ '<label style="display:block;font-size:0.78rem;font-weight:500">Provider modules</label>' +
692691
+ '<span style="font-size:0.68rem;color:var(--color-fg-muted)">' + escapeHtml(settingsProviderGroupSummary()) + '</span>' +
692260
692692
  '</div>' +
692261
- '<p style="font-size:0.7rem;color:var(--color-fg-muted);margin:4px 0 0">Pick a preset and click <b>apply preset</b> to switch backends instantly. <b>load to form</b> just populates the fields below for further editing.</p>' +
692693
+ renderSettingsProviderModules(selectedProviderId, ep) +
692262
692694
  '</div>' +
692695
+ '<div id="settings-provider-setup" class="settings-provider-setup">' + renderSettingsProviderSetup(selectedProviderId) + '</div>' +
692263
692696
  '<div>' +
692264
692697
  '<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Endpoint history</label>' +
692265
692698
  histHTML +
@@ -692300,17 +692733,142 @@ async function loadSettingsConnections() {
692300
692733
  // Map preset key → { url, backendType, requiresAuth, label }. Used by
692301
692734
  // applyEndpointPreset() below to populate the URL + type fields with one
692302
692735
  // click, optionally saving immediately.
692303
- const _OMNIUS_ENDPOINT_PRESETS = {
692304
- 'ollama': { url: 'http://127.0.0.1:11434', backendType: 'ollama' },
692305
- 'ollama-lan': { url: 'http://0.0.0.0:11434', backendType: 'ollama' },
692306
- 'vllm': { url: 'http://127.0.0.1:8000/v1', backendType: 'vllm' },
692307
- 'lmstudio': { url: 'http://127.0.0.1:1234/v1', backendType: 'vllm' },
692308
- 'openai': { url: 'https://api.openai.com/v1', backendType: 'vllm', requiresAuth: true },
692309
- 'anthropic': { url: 'https://api.anthropic.com/v1', backendType: 'vllm', requiresAuth: true },
692310
- 'chutes': { url: 'https://llm.chutes.ai/v1', backendType: 'vllm', requiresAuth: true },
692311
- 'groq': { url: 'https://api.groq.com/openai/v1', backendType: 'vllm', requiresAuth: true },
692312
- 'deepinfra': { url: 'https://api.deepinfra.com/v1/openai', backendType: 'vllm', requiresAuth: true },
692313
- };
692736
+ const _OMNIUS_ENDPOINT_PROVIDERS = [
692737
+ { id: 'ollama', label: 'Ollama', group: 'Local models', domain: 'ollama.com', url: 'http://127.0.0.1:11434', backendType: 'ollama', local: true, description: 'Local Ollama runtime on port 11434.', docsUrl: 'https://docs.ollama.com/api' },
692738
+ { id: 'lmstudio', label: 'LM Studio', group: 'Local models', domain: 'lmstudio.ai', url: 'http://127.0.0.1:1234/v1', backendType: 'vllm', local: true, description: 'Local OpenAI-compatible server on port 1234.', docsUrl: 'https://lmstudio.ai/docs' },
692739
+ { id: 'vllm', label: 'vLLM', group: 'Local models', domain: 'docs.vllm.ai', url: 'http://127.0.0.1:8000/v1', backendType: 'vllm', local: true, description: 'Self-hosted OpenAI-compatible vLLM endpoint.', docsUrl: 'https://docs.vllm.ai' },
692740
+ { id: 'openai', label: 'OpenAI', group: 'Cloud providers', domain: 'openai.com', url: 'https://api.openai.com/v1', backendType: 'vllm', requiresAuth: true, description: 'OpenAI API-compatible models.', apiKeyUrl: 'https://platform.openai.com/api-keys', docsUrl: 'https://platform.openai.com/docs/api-reference/authentication' },
692741
+ { id: 'anthropic', label: 'Anthropic', group: 'Cloud providers', domain: 'anthropic.com', url: 'https://api.anthropic.com/v1', backendType: 'vllm', requiresAuth: true, description: 'Claude via Anthropic API.', apiKeyUrl: 'https://console.anthropic.com/settings/keys', docsUrl: 'https://docs.anthropic.com/en/api/overview' },
692742
+ { id: 'openrouter', label: 'OpenRouter', group: 'Cloud providers', domain: 'openrouter.ai', url: 'https://openrouter.ai/api/v1', backendType: 'vllm', requiresAuth: true, description: 'OpenAI-compatible routing across many hosted models.', apiKeyUrl: 'https://openrouter.ai/keys', docsUrl: 'https://openrouter.ai/docs' },
692743
+ { id: 'chutes', label: 'Chutes', group: 'Cloud providers', domain: 'chutes.ai', url: 'https://llm.chutes.ai/v1', backendType: 'vllm', requiresAuth: true, description: 'Chutes OpenAI-compatible model endpoint.', apiKeyUrl: 'https://chutes.ai/app/api', docsUrl: 'https://docs.chutes.ai' },
692744
+ { id: 'groq', label: 'Groq', group: 'Cloud providers', domain: 'groq.com', url: 'https://api.groq.com/openai/v1', backendType: 'vllm', requiresAuth: true, description: 'Groq OpenAI-compatible inference.', apiKeyUrl: 'https://console.groq.com/keys', docsUrl: 'https://console.groq.com/docs' },
692745
+ { id: 'deepinfra', label: 'DeepInfra', group: 'Cloud providers', domain: 'deepinfra.com', url: 'https://api.deepinfra.com/v1/openai', backendType: 'vllm', requiresAuth: true, description: 'DeepInfra OpenAI-compatible hosted models.', apiKeyUrl: 'https://deepinfra.com/dash/api_keys', docsUrl: 'https://deepinfra.com/docs/openai_api' },
692746
+ { id: 'together', label: 'Together AI', group: 'Cloud providers', domain: 'together.ai', url: 'https://api.together.xyz/v1', backendType: 'vllm', requiresAuth: true, description: 'Together OpenAI-compatible inference.', apiKeyUrl: 'https://api.together.xyz/settings/api-keys', docsUrl: 'https://docs.together.ai/docs/openai-api-compatibility' },
692747
+ { id: 'fireworks', label: 'Fireworks', group: 'Cloud providers', domain: 'fireworks.ai', url: 'https://api.fireworks.ai/inference/v1', backendType: 'vllm', requiresAuth: true, description: 'Fireworks OpenAI-compatible inference.', apiKeyUrl: 'https://fireworks.ai/account/api-keys', docsUrl: 'https://docs.fireworks.ai' },
692748
+ { id: 'mistral', label: 'Mistral', group: 'Cloud providers', domain: 'mistral.ai', url: 'https://api.mistral.ai/v1', backendType: 'vllm', requiresAuth: true, description: 'Mistral hosted model endpoint.', apiKeyUrl: 'https://console.mistral.ai/api-keys', docsUrl: 'https://docs.mistral.ai' },
692749
+ { id: 'cerebras', label: 'Cerebras', group: 'Cloud providers', domain: 'cerebras.ai', url: 'https://api.cerebras.ai/v1', backendType: 'vllm', requiresAuth: true, description: 'Cerebras OpenAI-compatible inference.', apiKeyUrl: 'https://cloud.cerebras.ai/platform', docsUrl: 'https://inference-docs.cerebras.ai' },
692750
+ { id: 'sambanova', label: 'SambaNova', group: 'Cloud providers', domain: 'sambanova.ai', url: 'https://api.sambanova.ai/v1', backendType: 'vllm', requiresAuth: true, description: 'SambaNova OpenAI-compatible inference.', apiKeyUrl: 'https://cloud.sambanova.ai/apis', docsUrl: 'https://docs.sambanova.ai' },
692751
+ { id: 'nvidia', label: 'NVIDIA NIM', group: 'Cloud providers', domain: 'nvidia.com', url: 'https://integrate.api.nvidia.com/v1', backendType: 'vllm', requiresAuth: true, description: 'NVIDIA-hosted NIM models.', apiKeyUrl: 'https://build.nvidia.com', docsUrl: 'https://docs.api.nvidia.com/nim' },
692752
+ { id: 'hyperbolic', label: 'Hyperbolic', group: 'Cloud providers', domain: 'hyperbolic.xyz', url: 'https://api.hyperbolic.xyz/v1', backendType: 'vllm', requiresAuth: true, description: 'Hyperbolic OpenAI-compatible inference.', apiKeyUrl: 'https://app.hyperbolic.xyz/settings', docsUrl: 'https://docs.hyperbolic.xyz' },
692753
+ { id: 'custom', label: 'Custom', group: 'Custom endpoint', domain: '', url: '', backendType: 'vllm', requiresAuth: false, description: 'Any OpenAI-compatible endpoint.' },
692754
+ ];
692755
+ const _OMNIUS_ENDPOINT_PRESETS = Object.fromEntries(_OMNIUS_ENDPOINT_PROVIDERS.map(p => [p.id, p]));
692756
+
692757
+ function settingsProviderById(id) {
692758
+ return _OMNIUS_ENDPOINT_PROVIDERS.find(p => p.id === id) || null;
692759
+ }
692760
+
692761
+ function settingsProviderIdForUrl(url) {
692762
+ const u = String(url || '').toLowerCase();
692763
+ if (!u) return '';
692764
+ if (u.includes('11434') || u.includes('ollama')) return 'ollama';
692765
+ if (u.includes('1234') || u.includes('lmstudio')) return 'lmstudio';
692766
+ if (u.includes('8000') || u.includes('vllm')) return 'vllm';
692767
+ if (u.includes('api.openai.com')) return 'openai';
692768
+ if (u.includes('api.anthropic.com')) return 'anthropic';
692769
+ if (u.includes('openrouter.ai')) return 'openrouter';
692770
+ if (u.includes('chutes.ai')) return 'chutes';
692771
+ if (u.includes('api.groq.com')) return 'groq';
692772
+ if (u.includes('api.deepinfra.com')) return 'deepinfra';
692773
+ if (u.includes('api.together.xyz')) return 'together';
692774
+ if (u.includes('api.fireworks.ai')) return 'fireworks';
692775
+ if (u.includes('api.mistral.ai')) return 'mistral';
692776
+ if (u.includes('api.cerebras.ai')) return 'cerebras';
692777
+ if (u.includes('api.sambanova.ai')) return 'sambanova';
692778
+ if (u.includes('integrate.api.nvidia.com')) return 'nvidia';
692779
+ if (u.includes('api.hyperbolic.xyz')) return 'hyperbolic';
692780
+ return 'custom';
692781
+ }
692782
+
692783
+ function settingsProviderGroupSummary() {
692784
+ const groups = [];
692785
+ for (const p of _OMNIUS_ENDPOINT_PROVIDERS) {
692786
+ if (!groups.includes(p.group)) groups.push(p.group);
692787
+ }
692788
+ return groups.join(' / ');
692789
+ }
692790
+
692791
+ function settingsProviderIcon(provider) {
692792
+ const initial = escapeHtml(String(provider.label || '?').trim().charAt(0).toUpperCase() || '?');
692793
+ if (!provider.domain) return '<span class="settings-provider-brand"><span>' + initial + '</span></span>';
692794
+ const src = 'https://www.google.com/s2/favicons?domain=' + encodeURIComponent(provider.domain) + '&sz=64';
692795
+ return '<span class="settings-provider-brand"><img src="' + escapeHtml(src) + '" alt="" onerror="this.hidden=true;this.nextElementSibling.hidden=false"><span hidden>' + initial + '</span></span>';
692796
+ }
692797
+
692798
+ function renderSettingsProviderModules(selectedId, currentUrl) {
692799
+ const activeId = settingsProviderIdForUrl(currentUrl);
692800
+ return '<div class="settings-provider-module-grid">' + _OMNIUS_ENDPOINT_PROVIDERS.map(provider => {
692801
+ const selected = provider.id === selectedId;
692802
+ const active = provider.id === activeId;
692803
+ const cls = 'settings-provider-module' + (selected ? ' active' : '');
692804
+ const safeId = escapeHtml(provider.id);
692805
+ const meta = provider.group + (active ? ' - active' : (provider.requiresAuth ? ' - API key' : ''));
692806
+ return '<button type="button" class="' + cls + '" data-provider-id="' + safeId + '" onclick="selectSettingsProviderModule(\\'' + safeId + '\\', false)">' +
692807
+ settingsProviderIcon(provider) +
692808
+ '<strong>' + escapeHtml(provider.label) + '</strong>' +
692809
+ '<small>' + escapeHtml(meta) + '</small>' +
692810
+ '</button>';
692811
+ }).join('') + '</div>';
692812
+ }
692813
+
692814
+ function renderSettingsProviderSetup(providerId) {
692815
+ const provider = settingsProviderById(providerId) || settingsProviderById('custom');
692816
+ if (!provider) return '';
692817
+ const endpoint = provider.url || 'custom URL';
692818
+ const auth = provider.requiresAuth ? 'API key required' : (provider.local ? 'Local endpoint' : 'Auth optional');
692819
+ const links = [
692820
+ provider.apiKeyUrl ? '<a class="settings-provider-link" href="' + escapeHtml(provider.apiKeyUrl) + '" target="_blank" rel="noopener noreferrer">key</a>' : '',
692821
+ provider.docsUrl ? '<a class="settings-provider-link" href="' + escapeHtml(provider.docsUrl) + '" target="_blank" rel="noopener noreferrer">docs</a>' : '',
692822
+ ].filter(Boolean).join('');
692823
+ return '<div class="settings-provider-setup-head">' +
692824
+ settingsProviderIcon(provider) +
692825
+ '<div><strong>' + escapeHtml(provider.label) + '</strong><small>' + escapeHtml(provider.description || provider.group) + '</small></div>' +
692826
+ '</div>' +
692827
+ '<div class="settings-provider-meta">Endpoint <code>' + escapeHtml(endpoint) + '</code> · ' + escapeHtml(auth) + '</div>' +
692828
+ '<div class="settings-provider-actions">' +
692829
+ '<button class="omnius-btn-secondary" type="button" onclick="selectSettingsProviderModule(\\'' + escapeHtml(provider.id) + '\\', true)" style="background:var(--color-accent);color:var(--color-accent-fg);border-color:var(--color-accent)">use provider</button>' +
692830
+ '<button class="omnius-btn-secondary" type="button" onclick="selectSettingsProviderModule(\\'' + escapeHtml(provider.id) + '\\', false)">load to form</button>' +
692831
+ '<button class="omnius-btn-secondary" type="button" onclick="testSettingsConnections()">test</button>' +
692832
+ links +
692833
+ '</div>';
692834
+ }
692835
+
692836
+ function updateSettingsProviderSetup(providerId) {
692837
+ const host = document.getElementById('settings-provider-setup');
692838
+ if (host) host.innerHTML = renderSettingsProviderSetup(providerId);
692839
+ document.querySelectorAll('.settings-provider-module').forEach(btn => {
692840
+ btn.classList.toggle('active', btn.getAttribute('data-provider-id') === providerId);
692841
+ });
692842
+ }
692843
+
692844
+ async function selectSettingsProviderModule(providerId, apply) {
692845
+ const provider = settingsProviderById(providerId);
692846
+ if (!provider) return;
692847
+ window.__omniusSelectedProviderModule = provider.id;
692848
+ updateSettingsProviderSetup(provider.id);
692849
+ const inp = document.getElementById('settings-conn-endpoint');
692850
+ const bt = document.getElementById('settings-conn-backend-type');
692851
+ const auth = document.getElementById('settings-conn-auth');
692852
+ const status = document.getElementById('settings-conn-status');
692853
+ if (inp && provider.url) inp.value = provider.url;
692854
+ if (bt && provider.backendType) bt.value = provider.backendType;
692855
+ if (status) {
692856
+ status.textContent = provider.url ? (provider.label + ' loaded') : 'enter a custom endpoint URL below';
692857
+ status.style.color = 'var(--color-fg-muted)';
692858
+ }
692859
+ if (!apply) return;
692860
+ if (!provider.url && inp && !String(inp.value || '').trim()) {
692861
+ if (status) { status.textContent = 'enter a custom endpoint URL first'; status.style.color = 'var(--color-warning)'; }
692862
+ return;
692863
+ }
692864
+ if (provider.requiresAuth && (!auth || !auth.value) && !window.__omniusAuthAlreadySet) {
692865
+ if (status) { status.textContent = provider.label + ' requires an auth key'; status.style.color = 'var(--color-warning)'; }
692866
+ return;
692867
+ }
692868
+ await saveSettingsConnections();
692869
+ }
692870
+ window.selectSettingsProviderModule = selectSettingsProviderModule;
692871
+ window.updateSettingsProviderSetup = updateSettingsProviderSetup;
692314
692872
 
692315
692873
  // One-click endpoint switcher. apply=true saves directly (no typing
692316
692874
  // needed). apply=false just fills the URL/backend-type fields so the
@@ -692431,7 +692989,7 @@ function autoDetectBackendType(url) {
692431
692989
  let detected = 'unknown';
692432
692990
  if (u.includes('11434') || u.includes('ollama')) detected = 'ollama';
692433
692991
  else if (u.startsWith('peer://')) detected = 'nexus';
692434
- else if (u.includes('vllm') || u.includes('openai.com') || u.includes('api.anthropic.com') || u.includes('chutes') || u.includes('groq') || u.includes('deepinfra') || u.includes('/v1')) detected = 'vllm';
692992
+ else if (u.includes('vllm') || u.includes('lmstudio') || u.includes('openai.com') || u.includes('api.anthropic.com') || u.includes('openrouter') || u.includes('chutes') || u.includes('groq') || u.includes('deepinfra') || u.includes('together') || u.includes('fireworks') || u.includes('mistral') || u.includes('cerebras') || u.includes('sambanova') || u.includes('nvidia') || u.includes('hyperbolic') || u.includes('/v1')) detected = 'vllm';
692435
692993
  if (sel.value === '' || sel.value === 'unknown') sel.value = detected;
692436
692994
  }
692437
692995
 
@@ -707598,15 +708156,21 @@ ${entry.fullContent}`
707598
708156
  );
707599
708157
  };
707600
708158
  let liveShellBlock = null;
708159
+ const liveShellFingerprint = () => liveShellBlock ? shellLiveBlockFingerprint(liveShellBlock.state) : "";
708160
+ let lastLiveShellPaint = "";
707601
708161
  const scheduleLiveShellRepaint = () => {
707602
708162
  if (!liveShellBlock || liveShellBlock.repaintTimer || !statusBar?.isActive)
707603
708163
  return;
707604
708164
  liveShellBlock.repaintTimer = setTimeout(() => {
707605
708165
  if (!liveShellBlock) return;
707606
708166
  liveShellBlock.repaintTimer = null;
707607
- if (statusBar?.isActive) statusBar.refreshDisplay();
708167
+ const fp = liveShellFingerprint();
708168
+ if (fp !== lastLiveShellPaint) {
708169
+ lastLiveShellPaint = fp;
708170
+ if (statusBar?.isActive) statusBar.refreshDynamicBlocks();
708171
+ }
707608
708172
  if (liveShellBlock.state.status === "running") scheduleLiveShellRepaint();
707609
- }, 33);
708173
+ }, 120);
707610
708174
  liveShellBlock.repaintTimer.unref?.();
707611
708175
  };
707612
708176
  let gpuRecoveryBlock = null;
@@ -707764,6 +708328,7 @@ ${entry.fullContent}`
707764
708328
  const state = createShellLiveBlockState(command);
707765
708329
  const id = `shell-live-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
707766
708330
  liveShellBlock = { id, state, repaintTimer: null };
708331
+ lastLiveShellPaint = "";
707767
708332
  liveShellStatusBar.registerDynamicBlock(
707768
708333
  id,
707769
708334
  (width) => buildShellLiveBlockLines(state, width)
@@ -714318,6 +714883,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
714318
714883
  process.stderr.write(c3.red("Clipboard paste failed\n"));
714319
714884
  }
714320
714885
  });
714886
+ rl.on("ctrl-u", () => {
714887
+ try {
714888
+ toggleAll();
714889
+ statusBar?.refreshDynamicBlocks();
714890
+ } catch {
714891
+ }
714892
+ });
714321
714893
  rl.on("close", () => {
714322
714894
  if (interactiveExiting) return;
714323
714895
  interactiveExiting = true;
@@ -714910,6 +715482,7 @@ var init_interactive = __esm({
714910
715482
  init_platforms();
714911
715483
  init_status_bar();
714912
715484
  init_shell_live_block();
715485
+ init_tool_collapse_store();
714913
715486
  init_daemon_registry();
714914
715487
  init_dist9();
714915
715488
  init_overlay_lock();
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.324",
3
+ "version": "1.0.326",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.324",
9
+ "version": "1.0.326",
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.324",
3
+ "version": "1.0.326",
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",