omnius 1.0.323 → 1.0.325

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
  }
@@ -563637,11 +563637,11 @@ var init_streaming_executor = __esm({
563637
563637
  }
563638
563638
  /** Get the current state of all tool calls */
563639
563639
  getStates() {
563640
- const states = /* @__PURE__ */ new Map();
563640
+ const states2 = /* @__PURE__ */ new Map();
563641
563641
  for (const [id, entry] of this.tools) {
563642
- states.set(id, entry.state);
563642
+ states2.set(id, entry.state);
563643
563643
  }
563644
- return states;
563644
+ return states2;
563645
563645
  }
563646
563646
  /** Get count of tools in each state */
563647
563647
  getCounts() {
@@ -595348,6 +595348,23 @@ __export(task_complete_box_exports, {
595348
595348
  renderSessionHistoryBox: () => renderSessionHistoryBox,
595349
595349
  renderTaskCompleteBox: () => renderTaskCompleteBox
595350
595350
  });
595351
+ function refreshBoxPalette() {
595352
+ if (themeMode() === "system") {
595353
+ GREEN = DEFAULT_FG;
595354
+ FG_BORDER = DEFAULT_FG;
595355
+ FG_TITLE = DEFAULT_BOLD_FG;
595356
+ FG_METRIC = DEFAULT_FG;
595357
+ FG_LABEL = DEFAULT_FG;
595358
+ return;
595359
+ }
595360
+ const accent = tuiAccent();
595361
+ const borderColor = accent >= 0 ? accent : TASK_COMPLETE_GREEN_256;
595362
+ GREEN = `\x1B[38;5;${borderColor}m`;
595363
+ FG_BORDER = `\x1B[38;5;${borderColor}m`;
595364
+ FG_TITLE = `\x1B[1;38;5;${borderColor}m`;
595365
+ FG_METRIC = "\x1B[38;5;222m";
595366
+ FG_LABEL = "\x1B[38;5;147m";
595367
+ }
595351
595368
  function deriveTitle(task) {
595352
595369
  if (!task || !task.trim()) return "Task Complete";
595353
595370
  const source = task.replace(/^[\s\S]*?\n---\s*\n\s*NEW TASK:\s*/i, "").replace(/^NEW TASK:\s*/i, "").replace(/<task-handoff>[\s\S]*?<\/task-handoff>/gi, " ").replace(/<session-recap>[\s\S]*?<\/session-recap>/gi, " ").replace(/^\[task_(?:boundary|summary)\][\s\S]*?(?=\n\n|$)/gim, " ");
@@ -595540,6 +595557,7 @@ function buildLabeledFooterLines(label, items, width) {
595540
595557
  return lines;
595541
595558
  }
595542
595559
  function buildBoxLines(data, width) {
595560
+ refreshBoxPalette();
595543
595561
  const w = Math.max(40, width);
595544
595562
  const title = deriveTitle(data.task);
595545
595563
  const metrics2 = buildMetricsChip(data);
@@ -595579,6 +595597,7 @@ function buildBoxLines(data, width) {
595579
595597
  return lines;
595580
595598
  }
595581
595599
  function buildSessionHistoryBoxLines(data, width) {
595600
+ refreshBoxPalette();
595582
595601
  const w = Math.max(40, width);
595583
595602
  const title = deriveTitle(data.title || "Session History");
595584
595603
  const metrics2 = buildSessionHistoryMetricsChip(data);
@@ -595710,11 +595729,12 @@ function detectProvenanceAnchors(toolOutputs) {
595710
595729
  }
595711
595730
  return [...out].slice(0, 16);
595712
595731
  }
595713
- var BOX_TL, BOX_TR, BOX_BL, BOX_BR, BOX_H, BOX_V, BOX_TJ_L, BOX_TJ_R, RESET, TASK_COMPLETE_GREEN_256, GREEN, FG_BORDER, FG_TITLE, FG_METRIC, FG_LABEL;
595732
+ var BOX_TL, BOX_TR, BOX_BL, BOX_BR, BOX_H, BOX_V, BOX_TJ_L, BOX_TJ_R, RESET, TASK_COMPLETE_GREEN_256, DEFAULT_FG, DEFAULT_BOLD_FG, GREEN, FG_BORDER, FG_TITLE, FG_METRIC, FG_LABEL;
595714
595733
  var init_task_complete_box = __esm({
595715
595734
  "packages/cli/src/tui/task-complete-box.ts"() {
595716
595735
  "use strict";
595717
595736
  init_text_selection();
595737
+ init_theme();
595718
595738
  BOX_TL = "╭";
595719
595739
  BOX_TR = "╮";
595720
595740
  BOX_BL = "╰";
@@ -595725,6 +595745,8 @@ var init_task_complete_box = __esm({
595725
595745
  BOX_TJ_R = "┤";
595726
595746
  RESET = "\x1B[0m";
595727
595747
  TASK_COMPLETE_GREEN_256 = 154;
595748
+ DEFAULT_FG = "\x1B[39m";
595749
+ DEFAULT_BOLD_FG = "\x1B[1;39m";
595728
595750
  GREEN = `\x1B[38;5;${TASK_COMPLETE_GREEN_256}m`;
595729
595751
  FG_BORDER = `\x1B[38;5;${TASK_COMPLETE_GREEN_256}m`;
595730
595752
  FG_TITLE = `\x1B[1;38;5;${TASK_COMPLETE_GREEN_256}m`;
@@ -596638,10 +596660,61 @@ var init_secret_redactor = __esm({
596638
596660
  }
596639
596661
  });
596640
596662
 
596663
+ // packages/cli/src/tui/tool-collapse-store.ts
596664
+ function isCollapsibleBlock(id) {
596665
+ return states.has(id);
596666
+ }
596667
+ function ensureCollapsible(id) {
596668
+ let s2 = states.get(id);
596669
+ if (s2 === void 0) {
596670
+ s2 = globalDefault;
596671
+ states.set(id, s2);
596672
+ }
596673
+ return s2;
596674
+ }
596675
+ function getCollapseState(id) {
596676
+ return states.get(id) ?? globalDefault;
596677
+ }
596678
+ function setCollapseState(id, state) {
596679
+ states.set(id, state);
596680
+ }
596681
+ function toggleTitle(id) {
596682
+ const cur = getCollapseState(id);
596683
+ setCollapseState(id, cur === "collapsed" ? "preview" : "collapsed");
596684
+ }
596685
+ function toggleMore(id) {
596686
+ const cur = getCollapseState(id);
596687
+ setCollapseState(id, cur === "expanded" ? "preview" : "expanded");
596688
+ }
596689
+ function toggleAll() {
596690
+ let anyOpen = false;
596691
+ for (const s2 of states.values()) {
596692
+ if (s2 !== "collapsed") {
596693
+ anyOpen = true;
596694
+ break;
596695
+ }
596696
+ }
596697
+ const next = anyOpen ? "collapsed" : "preview";
596698
+ for (const id of states.keys()) states.set(id, next);
596699
+ globalDefault = next;
596700
+ }
596701
+ var PREVIEW_ROWS, READ_MORE_LABEL, READ_LESS_LABEL, globalDefault, states;
596702
+ var init_tool_collapse_store = __esm({
596703
+ "packages/cli/src/tui/tool-collapse-store.ts"() {
596704
+ "use strict";
596705
+ PREVIEW_ROWS = 8;
596706
+ READ_MORE_LABEL = "read more…";
596707
+ READ_LESS_LABEL = "read less";
596708
+ globalDefault = "preview";
596709
+ states = /* @__PURE__ */ new Map();
596710
+ }
596711
+ });
596712
+
596641
596713
  // packages/cli/src/tui/render.ts
596642
596714
  var render_exports = {};
596643
596715
  __export(render_exports, {
596644
596716
  SLASH_COMMANDS: () => SLASH_COMMANDS2,
596717
+ applyCollapseToBox: () => applyCollapseToBox,
596645
596718
  breakTelegramCoalesce: () => breakTelegramCoalesce,
596646
596719
  c: () => c3,
596647
596720
  charWidth: () => charWidth2,
@@ -597066,6 +597139,52 @@ function buildToolBottom(width, colorCode) {
597066
597139
  const border = toolColorSeq(colorCode);
597067
597140
  return `${border}${BOX_BL2}${BOX_H2.repeat(Math.max(0, width - 2))}${BOX_BR2}${toolResetSeq()}`;
597068
597141
  }
597142
+ function dimSeqOrEmpty() {
597143
+ return _colorsEnabled && stdoutIsTTY() ? "\x1B[2m" : "";
597144
+ }
597145
+ function underlineSeqOrEmpty() {
597146
+ return _colorsEnabled && stdoutIsTTY() ? "\x1B[4m" : "";
597147
+ }
597148
+ function collapsedBarLine(desc) {
597149
+ const seq = toolColorSeq(desc.colorCode);
597150
+ const reset = toolResetSeq();
597151
+ const dim = dimSeqOrEmpty();
597152
+ const title = sanitizeToolBoxContent(desc.title);
597153
+ const metrics2 = desc.metrics ? ` ${dim}${sanitizeToolBoxContent(desc.metrics)}${reset}` : "";
597154
+ return `${seq}▸ ${title}${reset}${metrics2}`;
597155
+ }
597156
+ function affordanceRowText(label, hiddenRows) {
597157
+ const ul = underlineSeqOrEmpty();
597158
+ const dim = dimSeqOrEmpty();
597159
+ const reset = toolResetSeq();
597160
+ const suffix = hiddenRows && hiddenRows > 0 ? `${dim} (${hiddenRows} more line${hiddenRows === 1 ? "" : "s"})${reset}` : "";
597161
+ return `${ul}${label}${reset}${suffix}`;
597162
+ }
597163
+ function applyCollapseToBox(fullLines, opts) {
597164
+ if (fullLines.length === 0) return fullLines;
597165
+ if (opts.state === "collapsed") return [collapsedBarLine(opts.desc)];
597166
+ if (fullLines.length < 4) return fullLines;
597167
+ const w = Math.max(40, opts.width);
597168
+ const head = fullLines.slice(0, 2);
597169
+ const bottom = fullLines[fullLines.length - 1];
597170
+ const body = fullLines.slice(2, fullLines.length - 1);
597171
+ if (body.length <= PREVIEW_ROWS) return fullLines;
597172
+ if (opts.state === "preview") {
597173
+ const shown = body.slice(0, PREVIEW_ROWS);
597174
+ const moreRow = buildToolContentRow(
597175
+ affordanceRowText(READ_MORE_LABEL, body.length - PREVIEW_ROWS),
597176
+ w,
597177
+ opts.desc.colorCode
597178
+ );
597179
+ return [...head, ...shown, moreRow, bottom];
597180
+ }
597181
+ const lessRow = buildToolContentRow(
597182
+ affordanceRowText(READ_LESS_LABEL),
597183
+ w,
597184
+ opts.desc.colorCode
597185
+ );
597186
+ return [...head, ...body, lessRow, bottom];
597187
+ }
597069
597188
  function buildToolContentRow(content, width, colorCode) {
597070
597189
  const border = toolColorSeq(colorCode);
597071
597190
  const reset = toolResetSeq();
@@ -597308,12 +597427,24 @@ function buildToolBoxLines(data, width) {
597308
597427
  lines.push(buildToolBottom(w, data.colorCode));
597309
597428
  return lines;
597310
597429
  }
597311
- function renderToolDynamicBlock(kind, render2, opts) {
597430
+ function renderToolDynamicBlock(kind, render2, opts, collapse) {
597312
597431
  const redir = _contentWriteHook?.redirect?.();
597313
597432
  const host = opts.host !== void 0 ? opts.host : _contentWriteHook?.dynamicBlockHost?.();
597314
597433
  if (!redir && host) {
597315
597434
  const id = `${kind}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
597316
- host.registerDynamicBlock(id, render2);
597435
+ if (collapse) {
597436
+ ensureCollapsible(id);
597437
+ host.registerDynamicBlock(
597438
+ id,
597439
+ (width) => applyCollapseToBox(render2(width), {
597440
+ state: getCollapseState(id),
597441
+ desc: collapse,
597442
+ width
597443
+ })
597444
+ );
597445
+ } else {
597446
+ host.registerDynamicBlock(id, render2);
597447
+ }
597317
597448
  host.appendDynamicBlock(id);
597318
597449
  return;
597319
597450
  }
@@ -597778,10 +597909,32 @@ function renderToolLine(content, isLast = false) {
597778
597909
  process.stdout.write(`${lines.join("\n")}
597779
597910
  `);
597780
597911
  }
597912
+ function toolResultCollapseDescriptor(toolName, success, output, opts) {
597913
+ const label = TOOL_LABELS[toolName] ?? toolName;
597914
+ const status = success ? "✔" : "✖";
597915
+ const rawLines = output.split("\n").filter((line) => line.trim()).length;
597916
+ const metrics2 = [
597917
+ success ? "ok" : "failed",
597918
+ rawLines > 0 ? `${rawLines} line${rawLines === 1 ? "" : "s"}` : "",
597919
+ output.length > 0 ? `${output.length.toLocaleString()} chars` : "",
597920
+ opts.durationMs && opts.durationMs > 0 ? formatDuration4(opts.durationMs) : ""
597921
+ ].filter(Boolean).join(" · ");
597922
+ return {
597923
+ title: `${status} ${label}`,
597924
+ metrics: metrics2,
597925
+ colorCode: success ? toolColorCode(toolName) : TOOL_ERROR_COLOR_CODE
597926
+ };
597927
+ }
597781
597928
  function renderToolResult(toolName, success, output, verboseOrOpts) {
597782
597929
  breakTelegramCoalesce();
597783
597930
  const opts = normalizeToolOpts(verboseOrOpts);
597784
597931
  const frozenOutput = getSecretRedactor().redactText(String(output ?? ""));
597932
+ const collapseDesc = toolResultCollapseDescriptor(
597933
+ toolName,
597934
+ success,
597935
+ frozenOutput,
597936
+ opts
597937
+ );
597785
597938
  if (_pendingToolCall && _pendingToolCall.toolName === toolName) {
597786
597939
  const pending2 = _pendingToolCall;
597787
597940
  _pendingToolCall = null;
@@ -597795,7 +597948,8 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
597795
597948
  { ...opts, verbose: pending2.verbose ?? opts.verbose },
597796
597949
  width
597797
597950
  ),
597798
- opts
597951
+ opts,
597952
+ collapseDesc
597799
597953
  );
597800
597954
  return;
597801
597955
  }
@@ -597803,7 +597957,8 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
597803
597957
  renderToolDynamicBlock(
597804
597958
  "tool-result",
597805
597959
  (width) => buildToolResultBoxLines(toolName, success, frozenOutput, opts, width),
597806
- opts
597960
+ opts,
597961
+ collapseDesc
597807
597962
  );
597808
597963
  }
597809
597964
  function renderBoxedBlock(opts) {
@@ -598226,6 +598381,7 @@ var init_render = __esm({
598226
598381
  init_syntax_highlight();
598227
598382
  init_model_picker();
598228
598383
  init_secret_redactor();
598384
+ init_tool_collapse_store();
598229
598385
  c3 = {
598230
598386
  bold: (t2) => ansi2("1", t2),
598231
598387
  dim: (t2) => stdoutIsTTY() ? `${dimFg()}${t2}\x1B[0m` : t2,
@@ -605735,6 +605891,31 @@ function getLastTaskSummary(repoRoot) {
605735
605891
  const clean5 = text2.replace(/^\[.*?\]\s*/, "").replace(/\s+/g, " ").trim();
605736
605892
  return clean5.length > 40 ? clean5.slice(0, 37) + "..." : clean5;
605737
605893
  }
605894
+ function cleanSessionHistoryDisplayLine(line) {
605895
+ return String(line || "").replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/^[>❯▹∙•*+\-\s]+/, "").replace(/^\[.*?\]\s*/, "").replace(/^(?:User|Assistant|You|Open Agent|Omnius)\s*:\s*/i, "").replace(/\s+/g, " ").trim();
605896
+ }
605897
+ function isNoisySessionHistoryLine(line) {
605898
+ const clean5 = cleanSessionHistoryDisplayLine(line || "");
605899
+ if (!clean5) return true;
605900
+ return /^(?:Previous session found|REST API:|Nexus P2P network connected|No context to restore|Starting fresh|Use \/endpoint|Knowledge graph:|Zettelkasten:|Episodes captured:|Current OMNIUS_HOST:|Loaded TUI session|General session$|Chat tui:sess|i\s+)/i.test(clean5);
605901
+ }
605902
+ function firstMeaningfulSessionHistoryLine(lines) {
605903
+ for (const line of lines) {
605904
+ const clean5 = cleanSessionHistoryDisplayLine(line);
605905
+ if (!isNoisySessionHistoryLine(clean5)) return clean5;
605906
+ }
605907
+ return "";
605908
+ }
605909
+ function sanitizeSessionHistoryEntry(repoRoot, entry) {
605910
+ if (!isNoisySessionHistoryLine(entry.name) && !isNoisySessionHistoryLine(entry.description)) return entry;
605911
+ const lines = loadSessionHistory(repoRoot, entry.id) || [];
605912
+ const fallback = firstMeaningfulSessionHistoryLine(lines);
605913
+ return {
605914
+ ...entry,
605915
+ name: isNoisySessionHistoryLine(entry.name) ? fallback ? fallback.length > 40 ? fallback.slice(0, 37) + "..." : fallback : entry.name : entry.name,
605916
+ description: isNoisySessionHistoryLine(entry.description) ? fallback || entry.description : entry.description
605917
+ };
605918
+ }
605738
605919
  function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
605739
605920
  const sessDir = join125(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
605740
605921
  mkdirSync66(sessDir, { recursive: true });
@@ -605782,7 +605963,7 @@ function listSessions(repoRoot) {
605782
605963
  try {
605783
605964
  if (!existsSync110(indexPath)) return [];
605784
605965
  const index = JSON.parse(readFileSync89(indexPath, "utf-8"));
605785
- return index.sort((a2, b) => b.updatedAt.localeCompare(a2.updatedAt));
605966
+ return index.map((entry) => sanitizeSessionHistoryEntry(repoRoot, entry)).sort((a2, b) => b.updatedAt.localeCompare(a2.updatedAt));
605786
605967
  } catch {
605787
605968
  return [];
605788
605969
  }
@@ -605813,12 +605994,9 @@ function deleteSession(repoRoot, sessionId) {
605813
605994
  }
605814
605995
  }
605815
605996
  function generateSessionName(lines) {
605816
- for (const line of lines.slice(0, 30)) {
605817
- const clean5 = line.trim();
605818
- if (clean5.length > 10 && !clean5.startsWith("i ") && !clean5.startsWith(" ")) {
605819
- const phrase = clean5.replace(/^[>❯▹]\s*/, "").slice(0, 40);
605820
- return phrase.length > 37 ? phrase.slice(0, 37) + "..." : phrase;
605821
- }
605997
+ const phrase = firstMeaningfulSessionHistoryLine(lines.slice(0, 80));
605998
+ if (phrase.length > 10) {
605999
+ return phrase.length > 40 ? phrase.slice(0, 37) + "..." : phrase;
605822
606000
  }
605823
606001
  return `Session ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
605824
606002
  }
@@ -605836,7 +606014,9 @@ function generateSessionDescription(lines) {
605836
606014
  }
605837
606015
  if (topics.length >= 3) break;
605838
606016
  }
605839
- return topics.length > 0 ? topics.join(", ") : "General session";
606017
+ if (topics.length > 0) return topics.join(", ");
606018
+ const fallback = firstMeaningfulSessionHistoryLine(lines.slice(0, 120));
606019
+ return fallback || "General session";
605840
606020
  }
605841
606021
  function detectManifests(repoRoot) {
605842
606022
  const manifests = [];
@@ -607403,6 +607583,25 @@ __export(status_bar_exports, {
607403
607583
  unlockFooterRedraws: () => unlockFooterRedraws
607404
607584
  });
607405
607585
  import { readFileSync as readFileSync91 } from "node:fs";
607586
+ function headerButtonGlyphFg() {
607587
+ const a2 = tuiAccent();
607588
+ return a2 < 0 ? "\x1B[39m" : `\x1B[38;5;${a2}m`;
607589
+ }
607590
+ function headerButtonBg() {
607591
+ const a2 = tuiAccent();
607592
+ return a2 < 0 ? "\x1B[7m" : `\x1B[48;5;${a2}m`;
607593
+ }
607594
+ function headerButtonFg() {
607595
+ const a2 = tuiAccent();
607596
+ return a2 < 0 ? "" : `\x1B[38;5;${contrastTextColor(a2)}m`;
607597
+ }
607598
+ function headerAccentBoldFg() {
607599
+ const a2 = tuiAccent();
607600
+ return a2 < 0 ? "\x1B[1;39m" : `\x1B[1;38;5;${a2}m`;
607601
+ }
607602
+ function headerTelegramFg() {
607603
+ return themeMode() === "system" ? "\x1B[39m" : "\x1B[38;5;45m";
607604
+ }
607406
607605
  function stripSubAgentPrefix(label) {
607407
607606
  const stripped = label.replace(/^\s*sub[-\s]?agents?\b[\s:_–—-]*/i, "").trim();
607408
607607
  return stripped.length > 0 ? stripped : label.trim();
@@ -607460,6 +607659,11 @@ function refreshThemeVars() {
607460
607659
  BOX_FG = tuiBoxFg();
607461
607660
  TEXT_PRIMARY = tuiTextPrimary() < 0 ? 252 : tuiTextPrimary();
607462
607661
  TEXT_DIM = tuiTextDim();
607662
+ HEADER_BUTTON_GLYPH_FG = headerButtonGlyphFg();
607663
+ HEADER_BUTTON_BG = headerButtonBg();
607664
+ HEADER_BUTTON_FG = headerButtonFg();
607665
+ HEADER_ACCENT_BOLD_FG = headerAccentBoldFg();
607666
+ HEADER_TELEGRAM_FG = headerTelegramFg();
607463
607667
  }
607464
607668
  function sanitizeSponsorHeaderText(value2, max = SPONSOR_HEADER_LABEL_MAX) {
607465
607669
  const cleaned = stripAnsi(String(value2 ?? "")).replace(/[\x00-\x1F\x7F]/g, " ").replace(/\s+/g, " ").trim();
@@ -607494,7 +607698,7 @@ function setTerminalTitle(task, version4) {
607494
607698
  process.stdout.write(data);
607495
607699
  }
607496
607700
  }
607497
- var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, CODE_READ_CHARS_PER_SEC, PROSE_READ_CHARS_PER_SEC, MIN_CONTENT_FOR_READING, CODE_CONTENT_TOOLS, PROSE_CONTENT_TOOLS, HumanSpeedTracker, PANEL_BG_SEQ, CONTENT_BG_SEQ, BOX_FG, TEXT_PRIMARY, TEXT_DIM, NO_SUB_AGENTS_HEADER_LABEL, HEADER_ACCENT_GREEN, HEADER_ACCENT_BOLD_FG, HEADER_BUTTON_BG, HEADER_BUTTON_FG, BOX_TL3, BOX_TR3, BOX_BL3, BOX_BR3, BOX_H3, BOX_V3, _globalFooterLock, RESET4, CURSOR_BLINK_BLOCK, _isWindows, SPONSOR_HEADER_LABEL_MAX, _termTitleWriter, StatusBar;
607701
+ var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, CODE_READ_CHARS_PER_SEC, PROSE_READ_CHARS_PER_SEC, MIN_CONTENT_FOR_READING, CODE_CONTENT_TOOLS, PROSE_CONTENT_TOOLS, HumanSpeedTracker, PANEL_BG_SEQ, CONTENT_BG_SEQ, BOX_FG, TEXT_PRIMARY, TEXT_DIM, NO_SUB_AGENTS_HEADER_LABEL, HEADER_BUTTON_GLYPH_FG, HEADER_BUTTON_BG, HEADER_BUTTON_FG, HEADER_ACCENT_BOLD_FG, HEADER_TELEGRAM_FG, BOX_TL3, BOX_TR3, BOX_BL3, BOX_BR3, BOX_H3, BOX_V3, _globalFooterLock, RESET4, CURSOR_BLINK_BLOCK, _isWindows, SPONSOR_HEADER_LABEL_MAX, _termTitleWriter, StatusBar;
607498
607702
  var init_status_bar = __esm({
607499
607703
  "packages/cli/src/tui/status-bar.ts"() {
607500
607704
  "use strict";
@@ -607506,6 +607710,7 @@ var init_status_bar = __esm({
607506
607710
  init_overlay_lock();
607507
607711
  init_dist5();
607508
607712
  init_theme();
607713
+ init_tool_collapse_store();
607509
607714
  init_layout2();
607510
607715
  EXPERT_TOOL_BASELINES = {
607511
607716
  file_read: 12,
@@ -607674,10 +607879,11 @@ var init_status_bar = __esm({
607674
607879
  TEXT_PRIMARY = tuiTextPrimary() < 0 ? 252 : tuiTextPrimary();
607675
607880
  TEXT_DIM = tuiTextDim();
607676
607881
  NO_SUB_AGENTS_HEADER_LABEL = " no agents ";
607677
- HEADER_ACCENT_GREEN = 154;
607678
- HEADER_ACCENT_BOLD_FG = `\x1B[1;38;5;${HEADER_ACCENT_GREEN}m`;
607679
- HEADER_BUTTON_BG = `\x1B[48;5;${HEADER_ACCENT_GREEN}m`;
607680
- HEADER_BUTTON_FG = "\x1B[38;5;0m";
607882
+ HEADER_BUTTON_GLYPH_FG = headerButtonGlyphFg();
607883
+ HEADER_BUTTON_BG = headerButtonBg();
607884
+ HEADER_BUTTON_FG = headerButtonFg();
607885
+ HEADER_ACCENT_BOLD_FG = headerAccentBoldFg();
607886
+ HEADER_TELEGRAM_FG = headerTelegramFg();
607681
607887
  BOX_TL3 = "╭";
607682
607888
  BOX_TR3 = "╮";
607683
607889
  BOX_BL3 = "╰";
@@ -607736,6 +607942,11 @@ var init_status_bar = __esm({
607736
607942
  _contentScrollOffset = 0;
607737
607943
  // 0 = live (bottom), >0 = scrolled back
607738
607944
  _contentMaxLines = 1e4;
607945
+ // Snapshot of the most recent content paint, used to map a mouse-click screen
607946
+ // row back to the reflowed line (and thus its dynamic-block id) for click
607947
+ // hit-testing on collapsible tool boxes. Refreshed on every repaintContent().
607948
+ _lastPaintReflow = null;
607949
+ _lastPaintStartIdx = 0;
607739
607950
  /**
607740
607951
  * Dynamic content blocks — width-aware regions that re-render themselves
607741
607952
  * when the terminal resizes. The renderer registered here is called from
@@ -608148,7 +608359,7 @@ var init_status_bar = __esm({
608148
608359
  return fg2;
608149
608360
  };
608150
608361
  const decorateMenuButton = (cmd, label) => {
608151
- return `\x1B[38;5;${HEADER_ACCENT_GREEN}m🭁\x1B[0m${HEADER_BUTTON_FG}${HEADER_BUTTON_BG}${label}\x1B[0m${PANEL_BG_SEQ}\x1B[38;5;${HEADER_ACCENT_GREEN}m🭝\x1B[0m${PANEL_BG_SEQ}`;
608362
+ return `${HEADER_BUTTON_GLYPH_FG}🭁\x1B[0m${HEADER_BUTTON_BG}${HEADER_BUTTON_FG}${label}\x1B[0m${PANEL_BG_SEQ}${HEADER_BUTTON_GLYPH_FG}🭝\x1B[0m${PANEL_BG_SEQ}`;
608152
608363
  };
608153
608364
  const decorateAgentButton = (content, color, active) => {
608154
608365
  const bg = `\x1B[48;5;${color}m`;
@@ -608282,7 +608493,7 @@ var init_status_bar = __esm({
608282
608493
  sysItems.push({
608283
608494
  render: () => renderBtn(
608284
608495
  "telegram",
608285
- `\x1B[38;5;45m${telegramDot}${telegramLabel}\x1B[0m`
608496
+ `${HEADER_TELEGRAM_FG}${telegramDot}${telegramLabel}\x1B[0m`
608286
608497
  ) + " ",
608287
608498
  w: telegramLabel.length + 2
608288
608499
  });
@@ -609442,6 +609653,55 @@ var init_status_bar = __esm({
609442
609653
  get textSelection() {
609443
609654
  return this._textSelection;
609444
609655
  }
609656
+ /**
609657
+ * Map a screen row to the collapsible tool box painted there (if any). Uses
609658
+ * the snapshot captured during the last repaintContent(): screen row r shows
609659
+ * reflowedLines[startIdx + (r - scrollRegionTop)]. All reflowed rows of a
609660
+ * dynamic block share the sentinel's bufferIdx, so we can recover the block
609661
+ * id and the row's offset within the block.
609662
+ */
609663
+ hitTestContentBlock(screenRow) {
609664
+ const reflow = this._lastPaintReflow;
609665
+ if (!reflow) return null;
609666
+ const rel = screenRow - this.scrollRegionTop;
609667
+ if (rel < 0) return null;
609668
+ const idx = this._lastPaintStartIdx + rel;
609669
+ const entry = reflow[idx];
609670
+ if (!entry) return null;
609671
+ const src2 = this._contentLines[entry.bufferIdx];
609672
+ if (!src2 || !src2.startsWith(this.DYNAMIC_BLOCK_MARK_PREFIX) || !src2.endsWith(this.DYNAMIC_BLOCK_MARK_SUFFIX)) {
609673
+ return null;
609674
+ }
609675
+ const id = src2.slice(
609676
+ this.DYNAMIC_BLOCK_MARK_PREFIX.length,
609677
+ src2.length - this.DYNAMIC_BLOCK_MARK_SUFFIX.length
609678
+ );
609679
+ let first2 = idx;
609680
+ while (first2 > 0 && reflow[first2 - 1]?.bufferIdx === entry.bufferIdx) {
609681
+ first2--;
609682
+ }
609683
+ return { id, offset: idx - first2, lineText: entry.line };
609684
+ }
609685
+ /**
609686
+ * Handle a click inside a collapsible tool box. Title row (offset 0) toggles
609687
+ * collapsed↔preview; a "read more…/read less" row toggles preview↔expanded;
609688
+ * other body rows are left alone so text selection still works. Returns true
609689
+ * when the click was consumed.
609690
+ */
609691
+ handleContentBlockClick(screenRow) {
609692
+ const hit = this.hitTestContentBlock(screenRow);
609693
+ if (!hit || !isCollapsibleBlock(hit.id)) return false;
609694
+ const plain = stripAnsi(hit.lineText);
609695
+ if (plain.includes(READ_MORE_LABEL) || plain.includes(READ_LESS_LABEL)) {
609696
+ toggleMore(hit.id);
609697
+ } else if (hit.offset === 0) {
609698
+ toggleTitle(hit.id);
609699
+ } else {
609700
+ return false;
609701
+ }
609702
+ this.refreshDynamicBlocks();
609703
+ return true;
609704
+ }
609445
609705
  /**
609446
609706
  * Handle a mouse pointer event (press/drag/release).
609447
609707
  * Called by MouseFilterStream's pointer handler.
@@ -609451,6 +609711,9 @@ var init_status_bar = __esm({
609451
609711
  handlePointerEvent(type, col, row) {
609452
609712
  if (!this.active) return;
609453
609713
  const w = termCols();
609714
+ if (type === "press" && row >= this.scrollRegionTop) {
609715
+ if (this.handleContentBlockClick(row)) return;
609716
+ }
609454
609717
  if (type === "press" && this._suggestions.length > 0) {
609455
609718
  if (this.suggestClickAt(row)) return;
609456
609719
  }
@@ -610103,6 +610366,20 @@ ${CONTENT_BG_SEQ}`);
610103
610366
  this.repaintContent();
610104
610367
  this.renderFooterAndPositionInput();
610105
610368
  }
610369
+ /**
610370
+ * Flicker-free in-place repaint of the content area (and thus any dynamic
610371
+ * blocks within it). Unlike refreshDisplay(), this does NOT blank the area
610372
+ * first via fillContentArea() — repaintContent() uses synchronized output
610373
+ * (\x1B[?2026h) and a per-row \x1B[2K clear, so a live block that updates
610374
+ * many times per second (e.g. the shell timer) refreshes without the whole
610375
+ * TUI flashing. Implements the DynamicBlockHost.refreshDynamicBlocks contract.
610376
+ */
610377
+ refreshDynamicBlocks() {
610378
+ if (!this.active) return;
610379
+ if (this._contentScrollOffset > 0 || this._mouseSelecting) return;
610380
+ if (isOverlayActive() || this._suspendContentLayer) return;
610381
+ this.repaintContent();
610382
+ }
610106
610383
  clearStreamingRepaintTimer() {
610107
610384
  if (!this._streamingRepaintTimer) return;
610108
610385
  clearTimeout(this._streamingRepaintTimer);
@@ -610481,6 +610758,8 @@ ${CONTENT_BG_SEQ}`);
610481
610758
  if (this._contentScrollOffset === 0) this._autoScroll = true;
610482
610759
  }
610483
610760
  const startIdx = Math.max(0, totalLines - h - this._contentScrollOffset);
610761
+ this._lastPaintReflow = reflowedLines;
610762
+ this._lastPaintStartIdx = startIdx;
610484
610763
  const headerSafeFloor = layout().headerBottom + 1;
610485
610764
  let buf = "\x1B[?2026h";
610486
610765
  buf += "\x1B7";
@@ -610719,8 +610998,8 @@ ${CONTENT_BG_SEQ}`);
610719
610998
  const label = `✈ tg${suffix}`;
610720
610999
  const compact3 = `✈${suffix}`;
610721
611000
  sections.push({
610722
- expanded: `\x1B[38;5;45m${label}\x1B[0m`,
610723
- compact: `\x1B[38;5;45m${compact3}\x1B[0m`,
611001
+ expanded: `${HEADER_TELEGRAM_FG}${label}\x1B[0m`,
611002
+ compact: `${HEADER_TELEGRAM_FG}${compact3}\x1B[0m`,
610724
611003
  expandedW: 2 + 3 + suffix.length,
610725
611004
  compactW: 2 + suffix.length,
610726
611005
  empty: false,
@@ -645238,22 +645517,51 @@ function normalizeRoot(root) {
645238
645517
  }
645239
645518
  }
645240
645519
  function stripAnsi5(text2) {
645241
- return String(text2 || "").replace(/\[[0-9;]*[a-zA-Z]/g, "");
645520
+ return String(text2 || "").replace(/\u001b\[[0-9;]*[a-zA-Z]/g, "");
645521
+ }
645522
+ function cleanSessionDisplayLine(line) {
645523
+ return stripAnsi5(line).replace(/^[>❯▹∙•*+\-\s]+/, "").replace(/^(?:User|Assistant|You|Open Agent|Omnius)\s*:\s*/i, "").replace(/\s+/g, " ").trim();
645524
+ }
645525
+ function isNoisySessionDisplayLine(line) {
645526
+ const clean5 = cleanSessionDisplayLine(line || "");
645527
+ if (!clean5) return true;
645528
+ return /^(?:Previous session found|REST API:|Nexus P2P network connected|No context to restore|Starting fresh|Use \/endpoint|Knowledge graph:|Zettelkasten:|Episodes captured:|Current OMNIUS_HOST:|Loaded TUI session|General session$|Chat tui:sess|\[Imported TUI session transcript\]|Title:|Description:|Project root:|i\s+)/i.test(clean5);
645529
+ }
645530
+ function bestSessionDisplayLine(text2) {
645531
+ const lines = stripAnsi5(text2).split(/\r?\n/);
645532
+ for (const line of lines) {
645533
+ const clean5 = cleanSessionDisplayLine(line);
645534
+ if (!isNoisySessionDisplayLine(clean5)) return clean5;
645535
+ }
645536
+ const fallback = stripAnsi5(text2).replace(/\s+/g, " ").trim();
645537
+ return isNoisySessionDisplayLine(fallback) ? "" : fallback;
645242
645538
  }
645243
645539
  function makeTitle(text2) {
645244
- const clean5 = stripAnsi5(text2).replace(/\s+/g, " ").trim();
645540
+ const clean5 = bestSessionDisplayLine(text2);
645245
645541
  if (!clean5) return "Chat session";
645246
- return clean5.length > 72 ? `${clean5.slice(0, 69)}...` : clean5;
645542
+ return clean5.length > 72 ? clean5.slice(0, 69) + "..." : clean5;
645247
645543
  }
645248
645544
  function makePreview(text2) {
645249
- const clean5 = stripAnsi5(text2).replace(/\s+/g, " ").trim();
645250
- return clean5.length > 160 ? `${clean5.slice(0, 157)}...` : clean5;
645545
+ const clean5 = bestSessionDisplayLine(text2);
645546
+ return clean5.length > 160 ? clean5.slice(0, 157) + "..." : clean5;
645251
645547
  }
645252
645548
  function normalizeLoadedSession(parsed) {
645253
645549
  if (!parsed.source) parsed.source = "web";
645254
645550
  if (parsed.projectRoot) parsed.projectRoot = normalizeRoot(parsed.projectRoot);
645551
+ if (parsed.title && isNoisySessionDisplayLine(parsed.title)) parsed.title = void 0;
645552
+ if (parsed.preview && isNoisySessionDisplayLine(parsed.preview)) parsed.preview = "";
645553
+ const importedContext = (parsed.messages || []).find(
645554
+ (m2) => m2.role === "system" && m2.content.startsWith("[Imported TUI session transcript]")
645555
+ )?.content;
645556
+ if ((parsed.source === "tui" || parsed.id?.startsWith("tui:")) && importedContext) {
645557
+ const importedPreview = makePreview(importedContext);
645558
+ if (!parsed.preview && importedPreview) parsed.preview = importedPreview;
645559
+ if (!parsed.title && importedPreview) parsed.title = makeTitle(importedPreview);
645560
+ }
645255
645561
  if (!parsed.preview) {
645256
- const last2 = [...parsed.messages || []].reverse().find((m2) => m2.role === "user" || m2.role === "assistant");
645562
+ const last2 = [...parsed.messages || []].reverse().find(
645563
+ (m2) => (m2.role === "user" || m2.role === "assistant") && !isNoisySessionDisplayLine(m2.content)
645564
+ );
645257
645565
  parsed.preview = last2 ? makePreview(last2.content) : "";
645258
645566
  }
645259
645567
  if (!parsed.title && parsed.preview) parsed.title = makeTitle(parsed.preview);
@@ -645426,9 +645734,10 @@ function getSession2(sessionId, model, cwd4) {
645426
645734
  function importTranscriptSession(opts) {
645427
645735
  const projectRoot = normalizeRoot(opts.projectRoot) ?? process.cwd();
645428
645736
  const id = opts.id;
645429
- const title = opts.title || makeTitle(opts.description || id);
645430
- const preview = makePreview(opts.description || opts.transcriptLines.slice(-8).join(" "));
645431
645737
  const transcript = opts.transcriptLines.map(stripAnsi5).join("\n").trim();
645738
+ const metadataSource = [opts.title, opts.description, transcript].filter(Boolean).join("\n");
645739
+ const title = makeTitle(metadataSource || id);
645740
+ const preview = makePreview([opts.description, transcript].filter(Boolean).join("\n") || title);
645432
645741
  const cappedTranscript = transcript.length > 32e3 ? `[earlier transcript truncated: ${transcript.length - 32e3} chars]
645433
645742
  ` + transcript.slice(-32e3) : transcript;
645434
645743
  const importedContext = [
@@ -653186,8 +653495,8 @@ var init_telegram_stats_menu = __esm({
653186
653495
  INACTIVITY_TIMEOUT_MS2 = 6e4;
653187
653496
  COUNTDOWN_SECONDS2 = 10;
653188
653497
  StatsMenuTimerManager = class {
653189
- constructor(states, callbacks, getSnapshot) {
653190
- this.states = states;
653498
+ constructor(states2, callbacks, getSnapshot) {
653499
+ this.states = states2;
653191
653500
  this.callbacks = callbacks;
653192
653501
  this.getSnapshot = getSnapshot;
653193
653502
  }
@@ -668170,9 +668479,9 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668170
668479
  }
668171
668480
  createTelegramGenerativeProgressBridge(chatId, msg) {
668172
668481
  if (chatId === void 0) return void 0;
668173
- const states = /* @__PURE__ */ new Map();
668482
+ const states2 = /* @__PURE__ */ new Map();
668174
668483
  const stateFor = (toolName) => {
668175
- let state = states.get(toolName);
668484
+ let state = states2.get(toolName);
668176
668485
  if (!state) {
668177
668486
  state = {
668178
668487
  messageId: null,
@@ -668180,7 +668489,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668180
668489
  queuedHtml: null,
668181
668490
  lastRenderedAt: 0
668182
668491
  };
668183
- states.set(toolName, state);
668492
+ states2.set(toolName, state);
668184
668493
  }
668185
668494
  return state;
668186
668495
  };
@@ -668253,7 +668562,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
668253
668562
  },
668254
668563
  complete: (toolName, result) => {
668255
668564
  if (!generationKindForToolName(toolName)) return;
668256
- const state = states.get(toolName);
668565
+ const state = states2.get(toolName);
668257
668566
  if (!state && result.success) return;
668258
668567
  const html = completeHtml(toolName, result);
668259
668568
  if (!html) return;
@@ -675638,6 +675947,10 @@ function finishShellLiveBlock(state, success) {
675638
675947
  }
675639
675948
  state.status = success ? "ok" : "failed";
675640
675949
  }
675950
+ function shellLiveBlockFingerprint(state) {
675951
+ const sec = Math.floor(Math.max(0, Date.now() - state.startedAt) / 1e3);
675952
+ return `${state.status}|${state.lines.length}|${state.currentLine.length}|${sec}`;
675953
+ }
675641
675954
  function buildShellLiveBlockLines(state, width) {
675642
675955
  const w = Math.max(36, width);
675643
675956
  const inner = Math.max(1, w - 4);
@@ -677678,6 +677991,10 @@ var init_direct_input = __esm({
677678
677991
  this._deleteWordLeft();
677679
677992
  return;
677680
677993
  case 21:
677994
+ if (this.line.length === 0) {
677995
+ this.emit("ctrl-u");
677996
+ return;
677997
+ }
677681
677998
  this.line = this.line.slice(this.cursor);
677682
677999
  this.cursor = 0;
677683
678000
  return;
@@ -681396,20 +681713,20 @@ async function handleNexusStatus(ctx3) {
681396
681713
  join163(process.cwd(), ".omnius", "nexus-peer-state.json"),
681397
681714
  join163(homedir56(), ".omnius", "nexus-peer-cache.json")
681398
681715
  ];
681399
- const states = [];
681716
+ const states2 = [];
681400
681717
  for (const p2 of statePaths) {
681401
681718
  if (!existsSync151(p2)) continue;
681402
681719
  try {
681403
681720
  const raw = readFileSync123(p2, "utf-8");
681404
- states.push({ source: p2, data: JSON.parse(raw) });
681721
+ states2.push({ source: p2, data: JSON.parse(raw) });
681405
681722
  } catch (e2) {
681406
- states.push({ source: p2, error: String(e2) });
681723
+ states2.push({ source: p2, error: String(e2) });
681407
681724
  }
681408
681725
  }
681409
681726
  const config = loadConfig();
681410
681727
  sendJson2(res, 200, {
681411
- connected: states.length > 0,
681412
- peer_cache_files: states,
681728
+ connected: states2.length > 0,
681729
+ peer_cache_files: states2,
681413
681730
  agent_name: loadAgentName(),
681414
681731
  backend_url: config.backendUrl
681415
681732
  });
@@ -684599,6 +684916,100 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
684599
684916
  border-color: var(--color-border-strong);
684600
684917
  }
684601
684918
 
684919
+ .settings-provider-module-grid {
684920
+ display: grid;
684921
+ grid-template-columns: repeat(auto-fit, minmax(156px, 1fr));
684922
+ gap: 10px;
684923
+ }
684924
+ .settings-provider-module {
684925
+ min-height: 118px;
684926
+ border: 1px solid var(--color-border);
684927
+ border-radius: 8px;
684928
+ background: var(--color-bg-input);
684929
+ color: var(--color-fg);
684930
+ display: grid;
684931
+ align-content: center;
684932
+ justify-items: center;
684933
+ gap: 7px;
684934
+ padding: 12px;
684935
+ text-align: center;
684936
+ font: inherit;
684937
+ cursor: pointer;
684938
+ }
684939
+ .settings-provider-module:hover {
684940
+ background: var(--color-bg-hover);
684941
+ border-color: var(--color-border-strong);
684942
+ }
684943
+ .settings-provider-module.active {
684944
+ border-color: var(--color-brand);
684945
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-brand) 45%, transparent);
684946
+ }
684947
+ .settings-provider-brand {
684948
+ width: 34px;
684949
+ height: 34px;
684950
+ border-radius: 8px;
684951
+ border: 1px solid var(--color-border);
684952
+ background: var(--color-bg);
684953
+ display: inline-grid;
684954
+ place-items: center;
684955
+ overflow: hidden;
684956
+ color: var(--color-brand);
684957
+ font-weight: 700;
684958
+ }
684959
+ .settings-provider-brand img {
684960
+ width: 22px;
684961
+ height: 22px;
684962
+ object-fit: contain;
684963
+ }
684964
+ .settings-provider-module strong {
684965
+ font-size: 0.78rem;
684966
+ font-weight: 700;
684967
+ max-width: 100%;
684968
+ overflow-wrap: anywhere;
684969
+ }
684970
+ .settings-provider-module small {
684971
+ color: var(--color-fg-muted);
684972
+ font-size: 0.68rem;
684973
+ line-height: 1.25;
684974
+ }
684975
+ .settings-provider-setup {
684976
+ border: 1px solid var(--color-border);
684977
+ border-radius: 8px;
684978
+ background: var(--color-bg-elevated);
684979
+ padding: 12px;
684980
+ display: grid;
684981
+ gap: 10px;
684982
+ }
684983
+ .settings-provider-setup-head {
684984
+ display: grid;
684985
+ grid-template-columns: auto minmax(0, 1fr);
684986
+ gap: 10px;
684987
+ align-items: center;
684988
+ }
684989
+ .settings-provider-setup-head strong {
684990
+ display: block;
684991
+ font-size: 0.82rem;
684992
+ }
684993
+ .settings-provider-setup-head small,
684994
+ .settings-provider-meta {
684995
+ color: var(--color-fg-muted);
684996
+ font-size: 0.7rem;
684997
+ }
684998
+ .settings-provider-actions {
684999
+ display: flex;
685000
+ gap: 8px;
685001
+ align-items: center;
685002
+ flex-wrap: wrap;
685003
+ }
685004
+ .settings-provider-link {
685005
+ color: var(--color-brand);
685006
+ border: 1px solid var(--color-border);
685007
+ border-radius: var(--radius-sm);
685008
+ padding: 4px 8px;
685009
+ text-decoration: none;
685010
+ font-size: 0.7rem;
685011
+ }
685012
+
684602
685013
  /* Settings models list rows */
684603
685014
  #settings-models-list .row,
684604
685015
  #mm-list .row {
@@ -685298,8 +685709,8 @@ body { display:flex; flex-direction:column; height:100vh; margin:0; overflow:hid
685298
685709
  </label>
685299
685710
  </section>
685300
685711
  <section class="settings-pane" id="settings-pane-connections" role="tabpanel" hidden>
685301
- <h4>Backend</h4>
685302
- <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>
685712
+ <h4>Inference providers</h4>
685713
+ <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>
685303
685714
  <div id="settings-connections-host">
685304
685715
  <button onclick="loadSettingsConnections()" style="font-size:0.74rem">load current</button>
685305
685716
  </div>
@@ -685535,6 +685946,44 @@ async function loadServerPrefs() {
685535
685946
  } catch { return null; }
685536
685947
  }
685537
685948
 
685949
+ function isNoisyChatSessionText(text) {
685950
+ const clean = String(text || '').replace(/\\s+/g, ' ').trim();
685951
+ if (!clean) return true;
685952
+ const t = clean.replace(/^[>❯▹∙•\\-\\s]+/, '');
685953
+ return /^(Previous session found|REST API:|Nexus P2P network connected|No context to restore|Starting fresh|Use \\/endpoint|General session$|Loaded TUI session|Chat tui:sess)/i.test(t);
685954
+ }
685955
+
685956
+ function isGenericChatTitle(id, title) {
685957
+ const t = String(title || '').trim();
685958
+ if (!t) return true;
685959
+ if (isNoisyChatSessionText(t)) return true;
685960
+ if (t === 'Chat ' + String(id || '').slice(0, 8)) return true;
685961
+ return /^Chat tui:sess/i.test(t);
685962
+ }
685963
+
685964
+ function sessionDisplayTitle(id, session) {
685965
+ const s = session || {};
685966
+ for (const candidate of [s.title, s.name, s.preview]) {
685967
+ if (!isGenericChatTitle(id, candidate)) return String(candidate).trim();
685968
+ }
685969
+ if (Array.isArray(s.messages)) {
685970
+ for (let i = s.messages.length - 1; i >= 0; i--) {
685971
+ const msg = s.messages[i];
685972
+ const content = msg && typeof msg.content === 'string' ? msg.content : '';
685973
+ if (!isGenericChatTitle(id, content)) return content.replace(/\\s+/g, ' ').trim().slice(0, 72);
685974
+ }
685975
+ }
685976
+ return String(id || '').startsWith('tui:') ? 'TUI session ' + String(id).slice(4, 16) : 'Chat ' + String(id || '').slice(0, 8);
685977
+ }
685978
+
685979
+ function sessionDisplayPreview(session) {
685980
+ const s = session || {};
685981
+ for (const candidate of [s.preview, s.title, s.name]) {
685982
+ if (!isNoisyChatSessionText(candidate)) return String(candidate).trim();
685983
+ }
685984
+ return '';
685985
+ }
685986
+
685538
685987
  async function loadServerChatSessions() {
685539
685988
  const root = $currentProject.get()?.root || '';
685540
685989
  if (!root) return;
@@ -685547,16 +685996,24 @@ async function loadServerChatSessions() {
685547
685996
  for (const sess of (data.sessions || [])) {
685548
685997
  if (!sess || !sess.id) continue;
685549
685998
  const existing = merged[sess.id] || {};
685999
+ const serverTitle = sess.title || sess.preview || '';
686000
+ const existingTitle = existing.title || existing.name || '';
686001
+ const title = !isGenericChatTitle(sess.id, existingTitle)
686002
+ ? existingTitle
686003
+ : (!isGenericChatTitle(sess.id, serverTitle) ? serverTitle : sessionDisplayTitle(sess.id, sess));
686004
+ const preview = !isNoisyChatSessionText(existing.preview)
686005
+ ? existing.preview
686006
+ : (!isNoisyChatSessionText(sess.preview) ? sess.preview : sessionDisplayPreview(sess));
685550
686007
  merged[sess.id] = {
685551
686008
  ...existing,
685552
686009
  id: sess.id,
685553
- title: existing.title || sess.title || sess.preview || ('Chat ' + String(sess.id).slice(0, 8)),
685554
- name: existing.name || sess.title || sess.preview || ('Chat ' + String(sess.id).slice(0, 8)),
685555
- preview: existing.preview || sess.preview || sess.title || '',
686010
+ title,
686011
+ name: !isGenericChatTitle(sess.id, existing.name) ? existing.name : title,
686012
+ preview,
685556
686013
  model: existing.model || sess.model || '',
685557
686014
  source: sess.source || existing.source || 'web',
685558
686015
  projectRoot: sess.projectRoot || root,
685559
- updatedAt: existing.updatedAt || sess.lastActivity || sess.updatedAt || '',
686016
+ updatedAt: sess.lastActivity || sess.updatedAt || existing.updatedAt || '',
685560
686017
  messages: existing.messages || [],
685561
686018
  };
685562
686019
  }
@@ -686085,6 +686542,7 @@ function addMessage(role, content) {
686085
686542
  }
686086
686543
  if (role === 'assistant' || (role === 'user' && looksLikeMarkdown(content))) {
686087
686544
  host.innerHTML = renderMarkdown(content);
686545
+ appendArtifactsForText(host, content);
686088
686546
  } else {
686089
686547
  host.textContent = content;
686090
686548
  }
@@ -686380,6 +686838,7 @@ function renderToolCallEvent(parent, chunkLike) {
686380
686838
  argsDiv.appendChild(row);
686381
686839
  }
686382
686840
  }
686841
+ appendArtifactControls(argsDiv, extractArtifactsFromValue(a));
686383
686842
  details.appendChild(argsDiv);
686384
686843
  }
686385
686844
  parent.appendChild(details);
@@ -686396,6 +686855,7 @@ function renderToolResultEvent(parent, chunkLike) {
686396
686855
  : 'background:var(--color-bg-elevated);color:var(--color-fg-muted);';
686397
686856
  resultEl.style.cssText = errStyle + 'padding:4px 8px 4px 18px;margin:0 0 2px 0;font-size:0.65rem';
686398
686857
  appendExpandableContent(resultEl, chunkLike.output || '', { truncateAt: 150, baseStyle: 'color:inherit;' });
686858
+ appendArtifactControls(resultEl, extractArtifactsFromValue(chunkLike));
686399
686859
  parent.appendChild(resultEl);
686400
686860
  return resultEl;
686401
686861
  }
@@ -686751,6 +687211,7 @@ async function sendMessage() {
686751
687211
  fullContent += summaryText;
686752
687212
  }
686753
687213
  contentDiv.innerHTML = renderMarkdown(fullContent);
687214
+ appendArtifactsForText(contentDiv, fullContent);
686754
687215
  hideStreamingIndicator(msgDiv);
686755
687216
  maybeAutoScroll();
686756
687217
  }
@@ -686862,6 +687323,7 @@ async function sendMessage() {
686862
687323
  argsDiv.appendChild(row);
686863
687324
  }
686864
687325
  }
687326
+ appendArtifactControls(argsDiv, extractArtifactsFromValue(a));
686865
687327
  details.appendChild(argsDiv);
686866
687328
  }
686867
687329
  toolsContainer.appendChild(details);
@@ -686874,10 +687336,8 @@ async function sendMessage() {
686874
687336
  // 150 chars. The button sits underneath the result block.
686875
687337
  if (chunk.type === 'tool_result') {
686876
687338
  if (isInternalChatTool(chunk.tool || '')) continue;
686877
- const resultEl = document.createElement('div');
686878
- resultEl.style.cssText = 'background:var(--color-bg-elevated);padding:4px 8px 4px 18px;margin:0 0 2px 0;color:var(--color-fg-muted);font-size:0.65rem';
686879
- appendExpandableContent(resultEl, chunk.output || '', { truncateAt: 150, baseStyle: 'color:var(--color-fg-muted);' });
686880
- toolsContainer.appendChild(resultEl);
687339
+ renderToolResultEvent(toolsContainer, chunk);
687340
+ maybeAutoScroll();
686881
687341
  continue;
686882
687342
  }
686883
687343
 
@@ -686893,6 +687353,7 @@ async function sendMessage() {
686893
687353
  hideStreamingIndicator(msgDiv);
686894
687354
  fullContent += delta;
686895
687355
  contentDiv.innerHTML = renderMarkdown(fullContent);
687356
+ appendArtifactsForText(contentDiv, fullContent);
686896
687357
  try { _highlightCodeBlocks(contentDiv); } catch {}
686897
687358
  maybeAutoScroll();
686898
687359
  }
@@ -686916,6 +687377,7 @@ async function sendMessage() {
686916
687377
 
686917
687378
  // Final render: content + collapsible tools + metadata
686918
687379
  contentDiv.innerHTML = renderMarkdown(fullContent);
687380
+ appendArtifactsForText(contentDiv, fullContent);
686919
687381
  // OWUI-3: streaming complete — drop the pulsing dot.
686920
687382
  hideStreamingIndicator(msgDiv);
686921
687383
  try { _highlightCodeBlocks(contentDiv); } catch {}
@@ -688828,12 +689290,20 @@ async function loadJobs() {
688828
689290
  function saveSessions() {
688829
689291
  const saved = loadScopedSessions();
688830
689292
  if (chatSessionId) {
689293
+ const existing = saved[chatSessionId] || (($chatSessions.get && $chatSessions.get()) || {})[chatSessionId] || {};
689294
+ const preview = messages.slice(-1)[0]?.content?.slice(0, 50) || sessionDisplayPreview(existing) || 'empty';
689295
+ const title = !isGenericChatTitle(chatSessionId, existing.title || existing.name)
689296
+ ? (existing.title || existing.name)
689297
+ : sessionDisplayTitle(chatSessionId, { ...existing, preview, messages });
688831
689298
  saved[chatSessionId] = {
689299
+ ...existing,
688832
689300
  id: chatSessionId,
689301
+ title,
689302
+ name: !isGenericChatTitle(chatSessionId, existing.name) ? existing.name : title,
688833
689303
  messages: messages,
688834
689304
  model: modelSelect.value,
688835
689305
  updatedAt: new Date().toISOString(),
688836
- preview: messages.slice(-1)[0]?.content?.slice(0, 50) || 'empty',
689306
+ preview,
688837
689307
  };
688838
689308
  }
688839
689309
  saveScopedSessions(saved);
@@ -688859,7 +689329,7 @@ function updateSessionSelect() {
688859
689329
  for (const [id, s] of entries) {
688860
689330
  const opt = document.createElement('option');
688861
689331
  opt.value = id;
688862
- opt.textContent = (s.preview || 'session').slice(0, 40);
689332
+ opt.textContent = sessionDisplayTitle(id, s).slice(0, 40);
688863
689333
  if (id === chatSessionId) opt.selected = true;
688864
689334
  sel.appendChild(opt);
688865
689335
  }
@@ -689668,6 +690138,255 @@ function rawFileUrl(path) {
689668
690138
  return '/v1/files/raw?path=' + encodeURIComponent(path);
689669
690139
  }
689670
690140
 
690141
+ function cleanArtifactPathCandidate(value) {
690142
+ let s = String(value || '').trim();
690143
+ s = s.replace(/^["'(<]+/, '').replace(/[)"'>,.;:]+$/, '');
690144
+ return s;
690145
+ }
690146
+
690147
+ function isPreviewableArtifactInfo(info) {
690148
+ return info && (info.kind === 'audio' || info.kind === 'video' || info.kind === 'image' || info.kind === 'pdf' || isTextPreviewable(info));
690149
+ }
690150
+
690151
+ function mediaUrlForStoredPath(path) {
690152
+ const normalized = String(path || '').split(String.fromCharCode(92)).join('/');
690153
+ const marker = '/.omnius/media/';
690154
+ const idx = normalized.indexOf(marker);
690155
+ if (idx < 0) return null;
690156
+ const rest = normalized.slice(idx + marker.length);
690157
+ const parts = rest.split('/').filter(Boolean);
690158
+ if (parts.length < 2) return null;
690159
+ const group = parts[0];
690160
+ const name = parts[parts.length - 1];
690161
+ const kind = group === 'images' ? 'image'
690162
+ : group === 'videos' ? 'video'
690163
+ : group === 'audio' ? 'audio'
690164
+ : group === 'music' ? 'music'
690165
+ : null;
690166
+ if (!kind || !name) return null;
690167
+ return '/v1/media/file?kind=' + encodeURIComponent(kind) + '&name=' + encodeURIComponent(name);
690168
+ }
690169
+
690170
+ function artifactFromPath(path, hint) {
690171
+ const clean = cleanArtifactPathCandidate(path);
690172
+ if (!clean) return null;
690173
+ const info = fileInfoFor(null, clean);
690174
+ if (info.kind === 'binary' || info.kind === 'archive') return null;
690175
+ const mediaUrl = mediaUrlForStoredPath(clean);
690176
+ return {
690177
+ path: clean,
690178
+ url: mediaUrl || rawFileUrl(clean),
690179
+ name: baseNameForPath(clean),
690180
+ kind: hint || info.kind,
690181
+ mime: info.mime,
690182
+ info,
690183
+ };
690184
+ }
690185
+
690186
+ function artifactFromUrl(url, hint) {
690187
+ const clean = cleanArtifactPathCandidate(url);
690188
+ if (!clean) return null;
690189
+ if (!/^\\/v1\\/media\\/file\\?/.test(clean) && !/^\\/v1\\/files\\/raw\\?/.test(clean) && !/^https?:\\/\\//i.test(clean)) return null;
690190
+ let name = clean;
690191
+ let kind = hint || '';
690192
+ let path = '';
690193
+ try {
690194
+ const u = new URL(clean, window.location.origin);
690195
+ path = u.searchParams.get('path') || '';
690196
+ name = u.searchParams.get('name') || (path ? baseNameForPath(path) : '') || baseNameForPath(u.pathname) || clean;
690197
+ kind = kind || u.searchParams.get('kind') || '';
690198
+ if (kind === 'music') kind = 'audio';
690199
+ } catch {}
690200
+ const info = fileInfoFor({ name, kind }, path || name);
690201
+ return { path, url: clean, name, kind: kind || info.kind, mime: info.mime, info };
690202
+ }
690203
+
690204
+ function uniqueArtifacts(items) {
690205
+ const seen = new Set();
690206
+ const out = [];
690207
+ for (const item of items || []) {
690208
+ if (!item) continue;
690209
+ const key = (item.url || '') + '|' + (item.path || '');
690210
+ if (!key.trim() || seen.has(key)) continue;
690211
+ seen.add(key);
690212
+ out.push(item);
690213
+ }
690214
+ return out;
690215
+ }
690216
+
690217
+ function extractArtifactsFromText(text) {
690218
+ const raw = String(text || '');
690219
+ if (!raw.trim()) return [];
690220
+ const out = [];
690221
+
690222
+ const urlRe = /\\/v1\\/(?:media\\/file|files\\/raw)\\?[^\\s"'<>]+/g;
690223
+ for (const match of raw.matchAll(urlRe)) {
690224
+ out.push(artifactFromUrl(match[0]));
690225
+ }
690226
+
690227
+ const pathRe = /(?:~|\\/|[A-Za-z]:[\\\\/])[^\\s"'<>]+/g;
690228
+ for (const match of raw.matchAll(pathRe)) {
690229
+ const candidate = cleanArtifactPathCandidate(match[0]);
690230
+ if (/^\\/v1\\/(?:media\\/file|files\\/raw)\\?/i.test(candidate)) continue;
690231
+ const info = fileInfoFor(null, candidate);
690232
+ if (isPreviewableArtifactInfo(info)) out.push(artifactFromPath(candidate));
690233
+ }
690234
+
690235
+ const trimmed = raw.trim();
690236
+ if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
690237
+ try {
690238
+ out.push(...extractArtifactsFromValue(JSON.parse(trimmed)));
690239
+ } catch {}
690240
+ }
690241
+
690242
+ return uniqueArtifacts(out);
690243
+ }
690244
+
690245
+ function extractArtifactsFromValue(value) {
690246
+ const out = [];
690247
+ const walk = (v, key) => {
690248
+ if (v == null) return;
690249
+ if (typeof v === 'string') {
690250
+ const lowerKey = String(key || '').toLowerCase();
690251
+ if (/^(path|file|filename|output|url|href|src|artifact|download)$/.test(lowerKey)) {
690252
+ out.push(artifactFromUrl(v) || artifactFromPath(v));
690253
+ }
690254
+ out.push(...extractArtifactsFromText(v));
690255
+ return;
690256
+ }
690257
+ if (Array.isArray(v)) {
690258
+ for (const item of v.slice(0, 20)) walk(item, key);
690259
+ return;
690260
+ }
690261
+ if (typeof v === 'object') {
690262
+ const obj = v;
690263
+ const kind = typeof obj.kind === 'string' ? obj.kind : '';
690264
+ const direct = obj.url || obj.href || obj.src || obj.path || obj.output || obj.file || obj.filename;
690265
+ if (typeof direct === 'string') out.push(artifactFromUrl(direct, kind) || artifactFromPath(direct, kind));
690266
+ for (const [k, child] of Object.entries(obj).slice(0, 30)) walk(child, k);
690267
+ }
690268
+ };
690269
+ walk(value, '');
690270
+ return uniqueArtifacts(out);
690271
+ }
690272
+
690273
+ async function downloadArtifact(artifact) {
690274
+ const url = artifact.url || (artifact.path ? rawFileUrl(artifact.path) : '');
690275
+ if (!url) return;
690276
+ try {
690277
+ const r = await fetch(url, { headers: headers() });
690278
+ if (!r.ok) throw new Error('HTTP ' + r.status);
690279
+ const blob = await r.blob();
690280
+ const href = URL.createObjectURL(blob);
690281
+ const a = document.createElement('a');
690282
+ a.href = href;
690283
+ a.download = artifact.name || baseNameForPath(artifact.path || url) || 'artifact';
690284
+ document.body.appendChild(a);
690285
+ a.click();
690286
+ a.remove();
690287
+ setTimeout(() => URL.revokeObjectURL(href), 5000);
690288
+ } catch (e) {
690289
+ const s = document.getElementById('status');
690290
+ if (s) {
690291
+ const old = s.textContent;
690292
+ s.textContent = 'download failed: ' + (e && e.message ? e.message : String(e));
690293
+ setTimeout(() => { s.textContent = old; }, 2500);
690294
+ }
690295
+ }
690296
+ }
690297
+
690298
+ function previewArtifact(artifact) {
690299
+ if (artifact.path) {
690300
+ previewFile(artifact.path);
690301
+ return;
690302
+ }
690303
+ const info = artifact.info || fileInfoFor({ name: artifact.name, kind: artifact.kind }, artifact.name || artifact.url);
690304
+ const shell = createFilePreviewShell(artifact.name || artifact.url, info);
690305
+ const src = artifact.url;
690306
+ const openLink = shell.card.querySelector('a');
690307
+ if (openLink) openLink.href = src;
690308
+ if (info.kind === 'audio') {
690309
+ const audio = document.createElement('audio');
690310
+ audio.controls = true;
690311
+ audio.preload = 'metadata';
690312
+ audio.src = src;
690313
+ audio.style.cssText = 'width:min(680px,82vw);display:block';
690314
+ shell.body.appendChild(audio);
690315
+ } else if (info.kind === 'video') {
690316
+ const video = document.createElement('video');
690317
+ video.controls = true;
690318
+ video.preload = 'metadata';
690319
+ video.src = src;
690320
+ video.style.cssText = 'max-width:86vw;max-height:76vh;background:#000;display:block';
690321
+ shell.body.appendChild(video);
690322
+ } else if (info.kind === 'image') {
690323
+ const img = document.createElement('img');
690324
+ img.src = src;
690325
+ img.alt = artifact.name || 'artifact';
690326
+ img.style.cssText = 'max-width:86vw;max-height:76vh;object-fit:contain;display:block';
690327
+ shell.body.appendChild(img);
690328
+ } else {
690329
+ const link = document.createElement('a');
690330
+ link.href = src;
690331
+ link.target = '_blank';
690332
+ link.rel = 'noopener noreferrer';
690333
+ link.textContent = 'open artifact';
690334
+ link.style.cssText = 'color:var(--color-brand);border:1px solid var(--color-border);border-radius:3px;padding:6px 10px;text-decoration:none';
690335
+ shell.body.appendChild(link);
690336
+ }
690337
+ document.body.appendChild(shell.modal);
690338
+ }
690339
+
690340
+ function appendArtifactControls(parent, artifacts) {
690341
+ const items = uniqueArtifacts(artifacts);
690342
+ if (!parent || items.length === 0) return null;
690343
+ const wrap = document.createElement('div');
690344
+ wrap.className = 'artifact-controls';
690345
+ wrap.style.cssText = 'display:flex;flex-direction:column;gap:6px;margin:6px 0 2px 0';
690346
+ for (const artifact of items) {
690347
+ const info = artifact.info || fileInfoFor({ name: artifact.name, kind: artifact.kind }, artifact.path || artifact.name || artifact.url);
690348
+ const row = document.createElement('div');
690349
+ row.style.cssText = 'display:flex;align-items:center;gap:8px;min-width:0;background:var(--color-bg);border:1px solid var(--color-border);border-left:2px solid var(--color-brand);border-radius:4px;padding:6px 8px;color:var(--color-fg);font-size:0.68rem';
690350
+ const label = document.createElement('span');
690351
+ label.textContent = (info.icon || '◇') + ' ' + (artifact.name || baseNameForPath(artifact.path || artifact.url || 'artifact'));
690352
+ label.title = artifact.path || artifact.url || '';
690353
+ label.style.cssText = 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1';
690354
+ row.appendChild(label);
690355
+
690356
+ if (info.kind === 'audio') {
690357
+ const audio = document.createElement('audio');
690358
+ audio.controls = true;
690359
+ audio.preload = 'metadata';
690360
+ audio.src = artifact.url || rawFileUrl(artifact.path);
690361
+ audio.style.cssText = 'width:min(320px,40vw);height:28px;flex:0 1 320px';
690362
+ row.appendChild(audio);
690363
+ } else if (isPreviewableArtifactInfo(info)) {
690364
+ const view = document.createElement('button');
690365
+ view.type = 'button';
690366
+ view.textContent = 'view';
690367
+ view.title = 'View ' + info.label;
690368
+ view.style.cssText = 'background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-brand);border-radius:3px;padding:3px 8px;cursor:pointer;font:inherit;font-size:0.64rem;flex-shrink:0';
690369
+ view.onclick = (e) => { e.stopPropagation(); previewArtifact(artifact); };
690370
+ row.appendChild(view);
690371
+ }
690372
+
690373
+ const download = document.createElement('button');
690374
+ download.type = 'button';
690375
+ download.textContent = 'download';
690376
+ download.title = 'Download ' + (artifact.name || 'artifact');
690377
+ download.style.cssText = 'background:var(--color-bg-input);border:1px solid var(--color-border);color:var(--color-brand);border-radius:3px;padding:3px 8px;cursor:pointer;font:inherit;font-size:0.64rem;flex-shrink:0';
690378
+ download.onclick = (e) => { e.stopPropagation(); downloadArtifact(artifact); };
690379
+ row.appendChild(download);
690380
+ wrap.appendChild(row);
690381
+ }
690382
+ parent.appendChild(wrap);
690383
+ return wrap;
690384
+ }
690385
+
690386
+ function appendArtifactsForText(parent, text) {
690387
+ return appendArtifactControls(parent, extractArtifactsFromText(text));
690388
+ }
690389
+
689671
690390
  function appendFileKindBadge(row, info) {
689672
690391
  if (!info || info.kind === 'text') return;
689673
690392
  const badge = document.createElement('span');
@@ -690446,7 +691165,9 @@ async function restoreChatSession() {
690446
691165
  messages: messages,
690447
691166
  model: data.model || modelSelect.value,
690448
691167
  updatedAt: data.updated_at || data.updatedAt || new Date().toISOString(),
690449
- preview: messages.slice(-1)[0]?.content?.slice(0, 50) || 'empty',
691168
+ title: data.title || (($chatSessions.get && $chatSessions.get()) || {})[data.id]?.title || sessionDisplayTitle(data.id, { messages }),
691169
+ name: data.title || (($chatSessions.get && $chatSessions.get()) || {})[data.id]?.name || sessionDisplayTitle(data.id, { messages }),
691170
+ preview: data.preview || messages.slice(-1)[0]?.content?.slice(0, 50) || 'empty',
690450
691171
  };
690451
691172
  saveScopedSessions(saved);
690452
691173
  $chatSessions.set({ ...(($chatSessions.get && $chatSessions.get()) || {}), ...saved });
@@ -691633,7 +692354,7 @@ function _renderSidebarChats(filter) {
691633
692354
 
691634
692355
  const renderRow = (id) => {
691635
692356
  const s = sessions[id] || {};
691636
- const title = (s.title || s.name || ('Chat ' + String(id).slice(0, 8))).toString();
692357
+ const title = sessionDisplayTitle(id, s).toString();
691637
692358
  const cls = 'sb-chat' + (id === activeId ? ' active' : '');
691638
692359
  const safeId = String(id).replace(/'/g, "\\\\'");
691639
692360
  const safeTitle = title.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
@@ -691823,32 +692544,21 @@ async function loadSettingsConnections() {
691823
692544
  '</div>';
691824
692545
  // Stash history globally so click handlers can resolve index → record.
691825
692546
  window.__omniusEndpointHistory = history;
692547
+ const activeProviderId = settingsProviderIdForUrl(ep);
692548
+ const selectedProviderId = settingsProviderById(window.__omniusSelectedProviderModule)
692549
+ ? window.__omniusSelectedProviderModule
692550
+ : (activeProviderId || 'ollama');
692551
+ window.__omniusSelectedProviderModule = selectedProviderId;
691826
692552
  host.innerHTML =
691827
692553
  '<div style="display:flex;flex-direction:column;gap:14px">' +
691828
- // Quick presets — one-click apply for the common defaults so the
691829
- // user doesn't have to type or even pick a backend type. Selecting
691830
- // a preset fills the URL + backend type fields below; clicking
691831
- // "Apply preset" saves directly without further input.
691832
692554
  '<div>' +
691833
- '<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Quick preset</label>' +
691834
- '<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">' +
691835
- '<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">' +
691836
- '<option value="">— select preset —</option>' +
691837
- '<option value="ollama">Ollama (http://127.0.0.1:11434)</option>' +
691838
- '<option value="ollama-lan">Ollama on LAN (http://0.0.0.0:11434)</option>' +
691839
- '<option value="vllm">vLLM (http://127.0.0.1:8000/v1)</option>' +
691840
- '<option value="lmstudio">LM Studio (http://127.0.0.1:1234/v1)</option>' +
691841
- '<option value="openai">OpenAI (https://api.openai.com/v1)</option>' +
691842
- '<option value="anthropic">Anthropic (https://api.anthropic.com/v1)</option>' +
691843
- '<option value="chutes">Chutes (https://llm.chutes.ai/v1)</option>' +
691844
- '<option value="groq">Groq (https://api.groq.com/openai/v1)</option>' +
691845
- '<option value="deepinfra">DeepInfra (https://api.deepinfra.com/v1/openai)</option>' +
691846
- '</select>' +
691847
- '<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>' +
691848
- '<button class="omnius-btn-secondary" type="button" onclick="applyEndpointPreset(false)" title="fill the fields below without saving">load to form</button>' +
692555
+ '<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px">' +
692556
+ '<label style="display:block;font-size:0.78rem;font-weight:500">Provider modules</label>' +
692557
+ '<span style="font-size:0.68rem;color:var(--color-fg-muted)">' + escapeHtml(settingsProviderGroupSummary()) + '</span>' +
691849
692558
  '</div>' +
691850
- '<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>' +
692559
+ renderSettingsProviderModules(selectedProviderId, ep) +
691851
692560
  '</div>' +
692561
+ '<div id="settings-provider-setup" class="settings-provider-setup">' + renderSettingsProviderSetup(selectedProviderId) + '</div>' +
691852
692562
  '<div>' +
691853
692563
  '<label style="display:block;font-size:0.78rem;font-weight:500;margin-bottom:6px">Endpoint history</label>' +
691854
692564
  histHTML +
@@ -691889,17 +692599,142 @@ async function loadSettingsConnections() {
691889
692599
  // Map preset key → { url, backendType, requiresAuth, label }. Used by
691890
692600
  // applyEndpointPreset() below to populate the URL + type fields with one
691891
692601
  // click, optionally saving immediately.
691892
- const _OMNIUS_ENDPOINT_PRESETS = {
691893
- 'ollama': { url: 'http://127.0.0.1:11434', backendType: 'ollama' },
691894
- 'ollama-lan': { url: 'http://0.0.0.0:11434', backendType: 'ollama' },
691895
- 'vllm': { url: 'http://127.0.0.1:8000/v1', backendType: 'vllm' },
691896
- 'lmstudio': { url: 'http://127.0.0.1:1234/v1', backendType: 'vllm' },
691897
- 'openai': { url: 'https://api.openai.com/v1', backendType: 'vllm', requiresAuth: true },
691898
- 'anthropic': { url: 'https://api.anthropic.com/v1', backendType: 'vllm', requiresAuth: true },
691899
- 'chutes': { url: 'https://llm.chutes.ai/v1', backendType: 'vllm', requiresAuth: true },
691900
- 'groq': { url: 'https://api.groq.com/openai/v1', backendType: 'vllm', requiresAuth: true },
691901
- 'deepinfra': { url: 'https://api.deepinfra.com/v1/openai', backendType: 'vllm', requiresAuth: true },
691902
- };
692602
+ const _OMNIUS_ENDPOINT_PROVIDERS = [
692603
+ { 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' },
692604
+ { 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' },
692605
+ { 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' },
692606
+ { 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' },
692607
+ { 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' },
692608
+ { 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' },
692609
+ { 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' },
692610
+ { 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' },
692611
+ { 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' },
692612
+ { 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' },
692613
+ { 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' },
692614
+ { 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' },
692615
+ { 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' },
692616
+ { 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' },
692617
+ { 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' },
692618
+ { 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' },
692619
+ { id: 'custom', label: 'Custom', group: 'Custom endpoint', domain: '', url: '', backendType: 'vllm', requiresAuth: false, description: 'Any OpenAI-compatible endpoint.' },
692620
+ ];
692621
+ const _OMNIUS_ENDPOINT_PRESETS = Object.fromEntries(_OMNIUS_ENDPOINT_PROVIDERS.map(p => [p.id, p]));
692622
+
692623
+ function settingsProviderById(id) {
692624
+ return _OMNIUS_ENDPOINT_PROVIDERS.find(p => p.id === id) || null;
692625
+ }
692626
+
692627
+ function settingsProviderIdForUrl(url) {
692628
+ const u = String(url || '').toLowerCase();
692629
+ if (!u) return '';
692630
+ if (u.includes('11434') || u.includes('ollama')) return 'ollama';
692631
+ if (u.includes('1234') || u.includes('lmstudio')) return 'lmstudio';
692632
+ if (u.includes('8000') || u.includes('vllm')) return 'vllm';
692633
+ if (u.includes('api.openai.com')) return 'openai';
692634
+ if (u.includes('api.anthropic.com')) return 'anthropic';
692635
+ if (u.includes('openrouter.ai')) return 'openrouter';
692636
+ if (u.includes('chutes.ai')) return 'chutes';
692637
+ if (u.includes('api.groq.com')) return 'groq';
692638
+ if (u.includes('api.deepinfra.com')) return 'deepinfra';
692639
+ if (u.includes('api.together.xyz')) return 'together';
692640
+ if (u.includes('api.fireworks.ai')) return 'fireworks';
692641
+ if (u.includes('api.mistral.ai')) return 'mistral';
692642
+ if (u.includes('api.cerebras.ai')) return 'cerebras';
692643
+ if (u.includes('api.sambanova.ai')) return 'sambanova';
692644
+ if (u.includes('integrate.api.nvidia.com')) return 'nvidia';
692645
+ if (u.includes('api.hyperbolic.xyz')) return 'hyperbolic';
692646
+ return 'custom';
692647
+ }
692648
+
692649
+ function settingsProviderGroupSummary() {
692650
+ const groups = [];
692651
+ for (const p of _OMNIUS_ENDPOINT_PROVIDERS) {
692652
+ if (!groups.includes(p.group)) groups.push(p.group);
692653
+ }
692654
+ return groups.join(' / ');
692655
+ }
692656
+
692657
+ function settingsProviderIcon(provider) {
692658
+ const initial = escapeHtml(String(provider.label || '?').trim().charAt(0).toUpperCase() || '?');
692659
+ if (!provider.domain) return '<span class="settings-provider-brand"><span>' + initial + '</span></span>';
692660
+ const src = 'https://www.google.com/s2/favicons?domain=' + encodeURIComponent(provider.domain) + '&sz=64';
692661
+ return '<span class="settings-provider-brand"><img src="' + escapeHtml(src) + '" alt="" onerror="this.hidden=true;this.nextElementSibling.hidden=false"><span hidden>' + initial + '</span></span>';
692662
+ }
692663
+
692664
+ function renderSettingsProviderModules(selectedId, currentUrl) {
692665
+ const activeId = settingsProviderIdForUrl(currentUrl);
692666
+ return '<div class="settings-provider-module-grid">' + _OMNIUS_ENDPOINT_PROVIDERS.map(provider => {
692667
+ const selected = provider.id === selectedId;
692668
+ const active = provider.id === activeId;
692669
+ const cls = 'settings-provider-module' + (selected ? ' active' : '');
692670
+ const safeId = escapeHtml(provider.id);
692671
+ const meta = provider.group + (active ? ' - active' : (provider.requiresAuth ? ' - API key' : ''));
692672
+ return '<button type="button" class="' + cls + '" data-provider-id="' + safeId + '" onclick="selectSettingsProviderModule(\\'' + safeId + '\\', false)">' +
692673
+ settingsProviderIcon(provider) +
692674
+ '<strong>' + escapeHtml(provider.label) + '</strong>' +
692675
+ '<small>' + escapeHtml(meta) + '</small>' +
692676
+ '</button>';
692677
+ }).join('') + '</div>';
692678
+ }
692679
+
692680
+ function renderSettingsProviderSetup(providerId) {
692681
+ const provider = settingsProviderById(providerId) || settingsProviderById('custom');
692682
+ if (!provider) return '';
692683
+ const endpoint = provider.url || 'custom URL';
692684
+ const auth = provider.requiresAuth ? 'API key required' : (provider.local ? 'Local endpoint' : 'Auth optional');
692685
+ const links = [
692686
+ provider.apiKeyUrl ? '<a class="settings-provider-link" href="' + escapeHtml(provider.apiKeyUrl) + '" target="_blank" rel="noopener noreferrer">key</a>' : '',
692687
+ provider.docsUrl ? '<a class="settings-provider-link" href="' + escapeHtml(provider.docsUrl) + '" target="_blank" rel="noopener noreferrer">docs</a>' : '',
692688
+ ].filter(Boolean).join('');
692689
+ return '<div class="settings-provider-setup-head">' +
692690
+ settingsProviderIcon(provider) +
692691
+ '<div><strong>' + escapeHtml(provider.label) + '</strong><small>' + escapeHtml(provider.description || provider.group) + '</small></div>' +
692692
+ '</div>' +
692693
+ '<div class="settings-provider-meta">Endpoint <code>' + escapeHtml(endpoint) + '</code> · ' + escapeHtml(auth) + '</div>' +
692694
+ '<div class="settings-provider-actions">' +
692695
+ '<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>' +
692696
+ '<button class="omnius-btn-secondary" type="button" onclick="selectSettingsProviderModule(\\'' + escapeHtml(provider.id) + '\\', false)">load to form</button>' +
692697
+ '<button class="omnius-btn-secondary" type="button" onclick="testSettingsConnections()">test</button>' +
692698
+ links +
692699
+ '</div>';
692700
+ }
692701
+
692702
+ function updateSettingsProviderSetup(providerId) {
692703
+ const host = document.getElementById('settings-provider-setup');
692704
+ if (host) host.innerHTML = renderSettingsProviderSetup(providerId);
692705
+ document.querySelectorAll('.settings-provider-module').forEach(btn => {
692706
+ btn.classList.toggle('active', btn.getAttribute('data-provider-id') === providerId);
692707
+ });
692708
+ }
692709
+
692710
+ async function selectSettingsProviderModule(providerId, apply) {
692711
+ const provider = settingsProviderById(providerId);
692712
+ if (!provider) return;
692713
+ window.__omniusSelectedProviderModule = provider.id;
692714
+ updateSettingsProviderSetup(provider.id);
692715
+ const inp = document.getElementById('settings-conn-endpoint');
692716
+ const bt = document.getElementById('settings-conn-backend-type');
692717
+ const auth = document.getElementById('settings-conn-auth');
692718
+ const status = document.getElementById('settings-conn-status');
692719
+ if (inp && provider.url) inp.value = provider.url;
692720
+ if (bt && provider.backendType) bt.value = provider.backendType;
692721
+ if (status) {
692722
+ status.textContent = provider.url ? (provider.label + ' loaded') : 'enter a custom endpoint URL below';
692723
+ status.style.color = 'var(--color-fg-muted)';
692724
+ }
692725
+ if (!apply) return;
692726
+ if (!provider.url && inp && !String(inp.value || '').trim()) {
692727
+ if (status) { status.textContent = 'enter a custom endpoint URL first'; status.style.color = 'var(--color-warning)'; }
692728
+ return;
692729
+ }
692730
+ if (provider.requiresAuth && (!auth || !auth.value) && !window.__omniusAuthAlreadySet) {
692731
+ if (status) { status.textContent = provider.label + ' requires an auth key'; status.style.color = 'var(--color-warning)'; }
692732
+ return;
692733
+ }
692734
+ await saveSettingsConnections();
692735
+ }
692736
+ window.selectSettingsProviderModule = selectSettingsProviderModule;
692737
+ window.updateSettingsProviderSetup = updateSettingsProviderSetup;
691903
692738
 
691904
692739
  // One-click endpoint switcher. apply=true saves directly (no typing
691905
692740
  // needed). apply=false just fills the URL/backend-type fields so the
@@ -692020,7 +692855,7 @@ function autoDetectBackendType(url) {
692020
692855
  let detected = 'unknown';
692021
692856
  if (u.includes('11434') || u.includes('ollama')) detected = 'ollama';
692022
692857
  else if (u.startsWith('peer://')) detected = 'nexus';
692023
- 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';
692858
+ 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';
692024
692859
  if (sel.value === '' || sel.value === 'unknown') sel.value = detected;
692025
692860
  }
692026
692861
 
@@ -701804,6 +702639,10 @@ ${historyLines}
701804
702639
  jsonResponse(res, 200, {
701805
702640
  id: session.id,
701806
702641
  model: session.model,
702642
+ title: session.title ?? null,
702643
+ preview: session.preview ?? null,
702644
+ source: session.source ?? "web",
702645
+ projectRoot: session.projectRoot ?? null,
701807
702646
  messages: publicMessages,
701808
702647
  message_count: publicMessages.length,
701809
702648
  tokens_in: session.tokensIn,
@@ -707183,15 +708022,21 @@ ${entry.fullContent}`
707183
708022
  );
707184
708023
  };
707185
708024
  let liveShellBlock = null;
708025
+ const liveShellFingerprint = () => liveShellBlock ? shellLiveBlockFingerprint(liveShellBlock.state) : "";
708026
+ let lastLiveShellPaint = "";
707186
708027
  const scheduleLiveShellRepaint = () => {
707187
708028
  if (!liveShellBlock || liveShellBlock.repaintTimer || !statusBar?.isActive)
707188
708029
  return;
707189
708030
  liveShellBlock.repaintTimer = setTimeout(() => {
707190
708031
  if (!liveShellBlock) return;
707191
708032
  liveShellBlock.repaintTimer = null;
707192
- if (statusBar?.isActive) statusBar.refreshDisplay();
708033
+ const fp = liveShellFingerprint();
708034
+ if (fp !== lastLiveShellPaint) {
708035
+ lastLiveShellPaint = fp;
708036
+ if (statusBar?.isActive) statusBar.refreshDynamicBlocks();
708037
+ }
707193
708038
  if (liveShellBlock.state.status === "running") scheduleLiveShellRepaint();
707194
- }, 33);
708039
+ }, 120);
707195
708040
  liveShellBlock.repaintTimer.unref?.();
707196
708041
  };
707197
708042
  let gpuRecoveryBlock = null;
@@ -707349,6 +708194,7 @@ ${entry.fullContent}`
707349
708194
  const state = createShellLiveBlockState(command);
707350
708195
  const id = `shell-live-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
707351
708196
  liveShellBlock = { id, state, repaintTimer: null };
708197
+ lastLiveShellPaint = "";
707352
708198
  liveShellStatusBar.registerDynamicBlock(
707353
708199
  id,
707354
708200
  (width) => buildShellLiveBlockLines(state, width)
@@ -713903,6 +714749,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
713903
714749
  process.stderr.write(c3.red("Clipboard paste failed\n"));
713904
714750
  }
713905
714751
  });
714752
+ rl.on("ctrl-u", () => {
714753
+ try {
714754
+ toggleAll();
714755
+ statusBar?.refreshDynamicBlocks();
714756
+ } catch {
714757
+ }
714758
+ });
713906
714759
  rl.on("close", () => {
713907
714760
  if (interactiveExiting) return;
713908
714761
  interactiveExiting = true;
@@ -714495,6 +715348,7 @@ var init_interactive = __esm({
714495
715348
  init_platforms();
714496
715349
  init_status_bar();
714497
715350
  init_shell_live_block();
715351
+ init_tool_collapse_store();
714498
715352
  init_daemon_registry();
714499
715353
  init_dist9();
714500
715354
  init_overlay_lock();