omnius 1.0.865 → 1.0.866

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.
Files changed (25) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/tui/native/worker.js +402 -172
  3. package/docs/DISCOVERY.json +538 -0
  4. package/docs/DISCOVERY.md +15 -0
  5. package/docs/work-orders/2026-10-16-browser-instrument-dashboard.md +17 -0
  6. package/docs/work-orders/2026-10-16-interface-delivery.md +6 -0
  7. package/docs/work-orders/evidence/browser-controls-deployment-20261016.json +28 -0
  8. package/docs/work-orders/evidence/browser-controls-package-verification-20261016.json +68 -0
  9. package/docs/work-orders/evidence/instrument-package-install-20261016-updated.json +45 -6
  10. package/docs/work-orders/evidence/instrument-sessions-narrow-60x20.png +0 -0
  11. package/docs/work-orders/evidence/instrument-sessions-restored-120x36.png +0 -0
  12. package/docs/work-orders/evidence/native-session-lifecycle-verification-20261016.json +79 -0
  13. package/docs/work-orders/evidence/native-session-regression-verification-20261016.json +65 -0
  14. package/docs/work-orders/evidence/native-session-widget-verification-20261016.json +60 -0
  15. package/docs/work-orders/evidence/native-sessions-installed-pty-20261016.json +2608 -0
  16. package/docs/work-orders/evidence/native-sessions-production-pty-20261016.json +3348 -0
  17. package/docs/work-orders/evidence/native-sessions-production-vte-20261016.json +2032 -0
  18. package/docs/work-orders/evidence/session-tabs-installation-20261016.json +37 -0
  19. package/docs/work-orders/evidence/session-tabs-package-verification-20261016.json +50 -0
  20. package/docs/work-orders/evidence/web-sidebar-send-dark-desktop-20261016.png +0 -0
  21. package/docs/work-orders/evidence/web-sidebar-send-light-phone-20261016.png +0 -0
  22. package/docs/work-orders/evidence/web-sidebar-send-repair-20261016.json +163 -0
  23. package/docs/work-orders/instrument-tui.md +34 -4
  24. package/npm-shrinkwrap.json +15 -15
  25. package/package.json +1 -1
@@ -2,19 +2,18 @@
2
2
  import { createWriteStream } from "node:fs";
3
3
  import { createInterface } from "node:readline";
4
4
  import { PassThrough } from "node:stream";
5
- import { CliRenderEvents as CliRenderEvents6, NativeSession, RGBA as RGBA3, createCliRenderer } from "@opentui/core";
5
+ import { CliRenderEvents as CliRenderEvents7, NativeSession, RGBA as RGBA3, createCliRenderer } from "@opentui/core";
6
6
 
7
7
  // packages/cli/src/tui/native/components/frontend.ts
8
8
  import {
9
- BoxRenderable as BoxRenderable6,
10
- CliRenderEvents as CliRenderEvents4,
9
+ BoxRenderable as BoxRenderable7,
10
+ CliRenderEvents as CliRenderEvents5,
11
11
  EmbeddedTerminalRenderable as EmbeddedTerminalRenderable2,
12
- ScrollBoxRenderable as ScrollBoxRenderable4,
12
+ ScrollBoxRenderable as ScrollBoxRenderable5,
13
13
  SyntaxStyle as SyntaxStyle2,
14
- TabSelectRenderable,
15
14
  TextareaRenderable as TextareaRenderable2,
16
- TextRenderable as TextRenderable5,
17
- TextAttributes as TextAttributes7,
15
+ TextRenderable as TextRenderable6,
16
+ TextAttributes as TextAttributes8,
18
17
  createClipboard,
19
18
  createHostClipboard,
20
19
  createRendererClipboardAdapter
@@ -799,49 +798,51 @@ function drawDotRail(buffer, x, y, length, horizontal, progress, colors) {
799
798
  function styleNativeScrollbars(scroll, colors) {
800
799
  for (const bar of [scroll.horizontalScrollBar, scroll.verticalScrollBar]) {
801
800
  bar.showArrows = false;
802
- const slider = bar.slider;
803
- slider.foregroundColor = colors.foreground;
804
- slider.backgroundColor = colors.background;
805
- slider.renderAfter = (buffer) => {
806
- const horizontal = slider.orientation === "horizontal";
807
- drawDotRail(
808
- buffer,
809
- slider.x,
810
- slider.y,
811
- horizontal ? slider.width : slider.height,
812
- horizontal,
813
- slider.max > slider.min ? (slider.value - slider.min) / (slider.max - slider.min) : 0,
814
- colors
815
- );
816
- };
817
- let dragging = false;
818
- const seek = (event) => {
819
- const horizontal = slider.orientation === "horizontal";
820
- const length = horizontal ? slider.width : slider.height;
821
- const offset = horizontal ? event.x - slider.x : event.y - slider.y;
822
- const progress = length > 1 ? Math.max(0, Math.min(1, offset / (length - 1))) : 0;
823
- slider.value = slider.min + progress * (slider.max - slider.min);
824
- event.preventDefault();
825
- event.stopPropagation();
826
- };
827
- slider.onMouseDown = (event) => {
828
- if (event.button === 0) {
829
- dragging = true;
830
- seek(event);
831
- }
832
- };
833
- slider.onMouseDrag = (event) => {
834
- if (dragging) seek(event);
835
- };
836
- slider.onMouseUp = (event) => {
837
- if (dragging) seek(event);
838
- dragging = false;
839
- };
840
- slider.onMouseDragEnd = () => {
841
- dragging = false;
842
- };
801
+ styleNativeSlider(bar.slider, colors);
843
802
  }
844
803
  }
804
+ function styleNativeSlider(slider, colors) {
805
+ slider.foregroundColor = colors.foreground;
806
+ slider.backgroundColor = colors.background;
807
+ slider.renderAfter = (buffer) => {
808
+ const horizontal = slider.orientation === "horizontal";
809
+ drawDotRail(
810
+ buffer,
811
+ slider.x,
812
+ slider.y,
813
+ horizontal ? slider.width : slider.height,
814
+ horizontal,
815
+ slider.max > slider.min ? (slider.value - slider.min) / (slider.max - slider.min) : 0,
816
+ colors
817
+ );
818
+ };
819
+ let dragging = false;
820
+ const seek = (event) => {
821
+ const horizontal = slider.orientation === "horizontal";
822
+ const length = horizontal ? slider.width : slider.height;
823
+ const offset = horizontal ? event.x - slider.x : event.y - slider.y;
824
+ const progress = length > 1 ? Math.max(0, Math.min(1, offset / (length - 1))) : 0;
825
+ slider.value = slider.min + progress * (slider.max - slider.min);
826
+ event.preventDefault();
827
+ event.stopPropagation();
828
+ };
829
+ slider.onMouseDown = (event) => {
830
+ if (event.button === 0) {
831
+ dragging = true;
832
+ seek(event);
833
+ }
834
+ };
835
+ slider.onMouseDrag = (event) => {
836
+ if (dragging) seek(event);
837
+ };
838
+ slider.onMouseUp = (event) => {
839
+ if (dragging) seek(event);
840
+ dragging = false;
841
+ };
842
+ slider.onMouseDragEnd = () => {
843
+ dragging = false;
844
+ };
845
+ }
845
846
 
846
847
  // packages/cli/src/tui/native/components/select.ts
847
848
  var NativeSelectRenderable = class extends SelectRenderable {
@@ -1781,12 +1782,19 @@ function terminalCellWidth(value) {
1781
1782
 
1782
1783
  // packages/cli/src/tui/native/components/instrument-format.ts
1783
1784
  var graphemes2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1784
- function formatSignalDivider(width) {
1785
+ function formatSignalDivider(width, geometry = { direction: "top" }) {
1785
1786
  const cells = Math.max(0, Math.floor(width));
1786
- if (cells < 32) return "─".repeat(cells);
1787
- const plateau = Math.min(12, Math.max(6, Math.floor(cells / 8)));
1788
- const left = Math.floor((cells - plateau - 2) / 2);
1789
- return "▁".repeat(left) + "╱" + "▔".repeat(plateau) + "╲" + "▁".repeat(cells - left - plateau - 2);
1787
+ if (cells < 8) return "─".repeat(cells);
1788
+ const buffer = Math.max(1, Math.floor(geometry.buffer ?? 2));
1789
+ const requestedRight = geometry.direction === "bottom" && geometry.sidebarColumn !== void 0 ? geometry.sidebarColumn : (geometry.rightTextStart ?? cells) - buffer - 1;
1790
+ const right = Math.max(4, Math.min(cells - 2, Math.floor(requestedRight)));
1791
+ const requestedLeft = Math.floor(geometry.leftTextEnd ?? 0) + buffer;
1792
+ if (geometry.direction === "top" && requestedLeft > right - 2) return "─".repeat(cells);
1793
+ const left = Math.max(1, Math.min(right - 2, requestedLeft));
1794
+ const outside = geometry.direction === "top" ? "▁" : "▔";
1795
+ const inside = geometry.direction === "top" ? "▔" : "▁";
1796
+ const fall = geometry.direction === "top" ? "╱" : "╲", rise = geometry.direction === "top" ? "╲" : "╱";
1797
+ return outside.repeat(left) + fall + inside.repeat(right - left - 1) + rise + outside.repeat(cells - right - 1);
1790
1798
  }
1791
1799
  function fitInstrumentText(value, cells, marker = "~") {
1792
1800
  const text = stripTerminalSequences(normalizeTerminalLine(value));
@@ -4206,6 +4214,180 @@ var NativeSelectionMenu = class {
4206
4214
  }
4207
4215
  };
4208
4216
 
4217
+ // packages/cli/src/tui/native/components/tab-strip.ts
4218
+ import { BoxRenderable as BoxRenderable6, CliRenderEvents as CliRenderEvents4, ScrollBoxRenderable as ScrollBoxRenderable4, SliderRenderable, TextAttributes as TextAttributes7, TextRenderable as TextRenderable5 } from "@opentui/core";
4219
+ var NativeTabStrip = class extends BoxRenderable6 {
4220
+ constructor(renderer2, options) {
4221
+ super(renderer2, {
4222
+ id: options.id,
4223
+ height: 1,
4224
+ minHeight: 1,
4225
+ maxHeight: 1,
4226
+ minWidth: 0,
4227
+ flexGrow: 1,
4228
+ flexShrink: 1,
4229
+ flexDirection: "row",
4230
+ shouldFill: false
4231
+ });
4232
+ this.renderer = renderer2;
4233
+ this.options = options;
4234
+ this.colors = options.colors;
4235
+ this.scroll = new ScrollBoxRenderable4(renderer2, {
4236
+ id: `${options.id}:scroll`,
4237
+ height: 1,
4238
+ minHeight: 1,
4239
+ maxHeight: 1,
4240
+ minWidth: 0,
4241
+ flexGrow: 1,
4242
+ flexShrink: 1,
4243
+ scrollX: true,
4244
+ scrollY: false,
4245
+ viewportCulling: true,
4246
+ viewportOptions: { height: 1, minHeight: 1, maxHeight: 1 },
4247
+ contentOptions: { flexDirection: "row", gap: 1 },
4248
+ horizontalScrollbarOptions: { visible: false },
4249
+ verticalScrollbarOptions: { visible: false }
4250
+ });
4251
+ this.scroll.focusable = false;
4252
+ this.scroll.horizontalScrollBar.visible = this.scroll.verticalScrollBar.visible = false;
4253
+ styleNativeScrollbars(this.scroll, this.colors);
4254
+ this.add(this.scroll);
4255
+ this.rail = new SliderRenderable(renderer2, {
4256
+ id: `${options.id}:rail`,
4257
+ orientation: "horizontal",
4258
+ width: 5,
4259
+ minWidth: 5,
4260
+ height: 1,
4261
+ flexShrink: 0,
4262
+ visible: false,
4263
+ min: 0,
4264
+ max: 0,
4265
+ value: 0,
4266
+ onChange: (value) => {
4267
+ if (!this.syncing) this.scroll.scrollLeft = value;
4268
+ }
4269
+ });
4270
+ this.rail.focusable = false;
4271
+ this.add(this.rail);
4272
+ styleNativeSlider(this.rail, this.colors);
4273
+ renderer2.on(CliRenderEvents4.FRAME, this.syncScroll);
4274
+ }
4275
+ renderer;
4276
+ options;
4277
+ scroll;
4278
+ rail;
4279
+ buttons = /* @__PURE__ */ new Map();
4280
+ activeId;
4281
+ signature = "";
4282
+ syncing = false;
4283
+ reveal;
4284
+ colors;
4285
+ naturalWidth = 0;
4286
+ update(items, activeId, busy = false) {
4287
+ const signature = JSON.stringify([items, activeId, busy]);
4288
+ if (signature === this.signature) return;
4289
+ this.signature = signature;
4290
+ const ids = new Set(items.map((item) => item.id));
4291
+ for (const [id, entry] of this.buttons) if (!ids.has(id)) {
4292
+ entry.button.destroy();
4293
+ this.buttons.delete(id);
4294
+ }
4295
+ for (const [index, action] of items.entries()) {
4296
+ let entry = this.buttons.get(action.id);
4297
+ if (!entry) {
4298
+ const button = new TextRenderable5(this.renderer, {
4299
+ id: `${this.options.prefix}:${action.id}`,
4300
+ content: "",
4301
+ height: 1,
4302
+ flexShrink: 0,
4303
+ wrapMode: "none",
4304
+ selectable: false,
4305
+ fg: this.colors.foreground,
4306
+ bg: this.colors.background,
4307
+ onMouseDown: (event) => {
4308
+ if (event.button === 0) {
4309
+ button.focus();
4310
+ if (!entry.blocked) this.options.activate(action.id);
4311
+ }
4312
+ event.preventDefault();
4313
+ event.stopPropagation();
4314
+ },
4315
+ onKeyDown: (key) => this.handleKey(entry, key)
4316
+ });
4317
+ entry = { action, active: false, blocked: false, button };
4318
+ this.buttons.set(action.id, entry);
4319
+ button.on("focused", () => {
4320
+ this.style(entry);
4321
+ this.scroll.scrollChildIntoView(button.id);
4322
+ this.reveal = button.id;
4323
+ });
4324
+ button.on("blurred", () => this.style(entry));
4325
+ }
4326
+ entry.action = action;
4327
+ entry.active = action.id === activeId;
4328
+ entry.blocked = busy || Boolean(action.disabled);
4329
+ entry.button.focusable = entry.active || !entry.blocked;
4330
+ const label = plainText(action.label);
4331
+ const content = entry.active ? `⟋⟋ ${label} ⟍⟍` : ` ${label} `;
4332
+ if (entry.button.plainText !== content) entry.button.content = content;
4333
+ this.style(entry);
4334
+ if (this.scroll.getChildren()[index] !== entry.button) this.scroll.add(entry.button, index);
4335
+ }
4336
+ this.naturalWidth = Array.from(this.buttons.values()).reduce((width, entry) => width + terminalCellWidth(entry.button.plainText), 0) + Math.max(0, items.length - 1);
4337
+ const focused = this.renderer.currentFocusedRenderable;
4338
+ if (focused && !focused.focusable && Array.from(this.buttons.values()).some((entry) => entry.button === focused)) this.buttons.get(activeId)?.button.focus();
4339
+ if (activeId !== this.activeId) this.reveal = `${this.options.prefix}:${activeId}`;
4340
+ this.activeId = activeId;
4341
+ this.renderer.requestRender();
4342
+ }
4343
+ style(entry) {
4344
+ entry.button.attributes = (entry.active ? TextAttributes7.BOLD | TextAttributes7.UNDERLINE : entry.blocked ? TextAttributes7.DIM : 0) | (entry.button.focused ? TextAttributes7.INVERSE : 0);
4345
+ }
4346
+ handleKey(entry, key) {
4347
+ if (key.eventType === "release") return;
4348
+ if (key.name === "return" || key.sequence === " ") {
4349
+ if (!entry.blocked) this.options.activate(entry.action.id);
4350
+ } else if (["left", "right", "home", "end"].includes(key.name)) {
4351
+ const targets = this.scroll.getChildren().filter((button) => button.focusable);
4352
+ const index = targets.indexOf(entry.button);
4353
+ const next = key.name === "home" ? 0 : key.name === "end" ? targets.length - 1 : (index + (key.name === "left" ? -1 : 1) + targets.length) % targets.length;
4354
+ targets[next]?.focus();
4355
+ } else return;
4356
+ key.preventDefault();
4357
+ key.stopPropagation();
4358
+ }
4359
+ syncScroll = () => {
4360
+ if (!this.visible || this.width < 1) return;
4361
+ const overflow = this.naturalWidth > this.width;
4362
+ if (this.rail.visible !== overflow) {
4363
+ this.rail.visible = overflow;
4364
+ this.renderer.requestRender();
4365
+ }
4366
+ if (this.reveal) {
4367
+ this.scroll.scrollChildIntoView(this.reveal);
4368
+ this.reveal = void 0;
4369
+ }
4370
+ this.syncing = true;
4371
+ this.rail.max = Math.max(0, this.scroll.scrollWidth - this.scroll.viewport.width);
4372
+ this.rail.viewPortSize = this.scroll.viewport.width;
4373
+ this.rail.value = this.scroll.scrollLeft;
4374
+ this.syncing = false;
4375
+ };
4376
+ applyTheme(colors) {
4377
+ this.colors = colors;
4378
+ for (const { button } of this.buttons.values()) {
4379
+ button.fg = colors.foreground;
4380
+ button.bg = colors.background;
4381
+ }
4382
+ styleNativeScrollbars(this.scroll, colors);
4383
+ styleNativeSlider(this.rail, colors);
4384
+ }
4385
+ destroySelf() {
4386
+ this.renderer.off(CliRenderEvents4.FRAME, this.syncScroll);
4387
+ super.destroySelf();
4388
+ }
4389
+ };
4390
+
4209
4391
  // packages/cli/src/tui/native/components/frontend.ts
4210
4392
  var initialTheme = { mode: "system", bg: -1, accent: -1, textPrimary: -1, textDim: -1, boxColor: -1 };
4211
4393
  var NativeFrontend = class {
@@ -4219,7 +4401,7 @@ var NativeFrontend = class {
4219
4401
  this.selectionMenu = new NativeSelectionMenu(renderer2, colors, (text) => {
4220
4402
  void this.copy(text);
4221
4403
  }, () => this.restoreFocus());
4222
- this.root = new BoxRenderable6(renderer2, {
4404
+ this.root = new BoxRenderable7(renderer2, {
4223
4405
  id: "omnius-native",
4224
4406
  width: "100%",
4225
4407
  height: "100%",
@@ -4227,7 +4409,7 @@ var NativeFrontend = class {
4227
4409
  backgroundColor: colors.background
4228
4410
  });
4229
4411
  renderer2.root.add(this.root);
4230
- this.header = new BoxRenderable6(renderer2, {
4412
+ this.header = new BoxRenderable7(renderer2, {
4231
4413
  id: "omnius-header",
4232
4414
  width: "100%",
4233
4415
  minWidth: 0,
@@ -4240,17 +4422,21 @@ var NativeFrontend = class {
4240
4422
  this.root.add(this.header);
4241
4423
  this.header.renderAfter = (buffer) => {
4242
4424
  if (this.header.height > 0) buffer.drawText(
4243
- formatSignalDivider(this.header.width),
4425
+ formatSignalDivider(this.header.width, {
4426
+ direction: "top",
4427
+ leftTextEnd: this.identity.x - this.header.x + Math.min(this.identity.width, terminalCellWidth(this.identity.plainText)),
4428
+ rightTextStart: Math.min(this.detailButton.x, this.headerActions.visible ? this.headerActions.x : this.detailButton.x) - this.header.x
4429
+ }),
4244
4430
  this.header.x,
4245
4431
  this.header.y + this.header.height - 1,
4246
4432
  this.context.colors.foreground,
4247
4433
  this.context.colors.background,
4248
- TextAttributes7.DIM
4434
+ TextAttributes8.DIM
4249
4435
  );
4250
4436
  };
4251
- const headerRow = new BoxRenderable6(renderer2, { id: "omnius-header-row", width: "100%", minWidth: 0, minHeight: 1, flexDirection: "row", gap: 1 });
4437
+ const headerRow = new BoxRenderable7(renderer2, { id: "omnius-header-row", width: "100%", minWidth: 0, minHeight: 1, flexDirection: "row", gap: 1 });
4252
4438
  this.header.add(headerRow);
4253
- this.identity = new TextRenderable5(renderer2, {
4439
+ this.identity = new TextRenderable6(renderer2, {
4254
4440
  id: "omnius-identity",
4255
4441
  content: "Omnius",
4256
4442
  fg: colors.foreground,
@@ -4260,7 +4446,7 @@ var NativeFrontend = class {
4260
4446
  truncate: true,
4261
4447
  minWidth: 18,
4262
4448
  selectable: false,
4263
- attributes: TextAttributes7.BOLD,
4449
+ attributes: TextAttributes8.BOLD,
4264
4450
  onMouseDown: (event) => {
4265
4451
  if (event.button === 0) {
4266
4452
  this.toggleHeaderPanel();
@@ -4275,7 +4461,7 @@ var NativeFrontend = class {
4275
4461
  }
4276
4462
  });
4277
4463
  headerRow.add(this.identity);
4278
- this.headerActions = new ScrollBoxRenderable4(renderer2, {
4464
+ this.headerActions = new ScrollBoxRenderable5(renderer2, {
4279
4465
  id: "omnius-header-actions",
4280
4466
  flexGrow: 0,
4281
4467
  flexShrink: 1,
@@ -4288,16 +4474,16 @@ var NativeFrontend = class {
4288
4474
  verticalScrollbarOptions: { visible: false }
4289
4475
  });
4290
4476
  headerRow.add(this.headerActions);
4291
- this.headerPanel = new TextRenderable5(renderer2, { id: "omnius-header-panel", content: "", width: "100%", wrapMode: "word", visible: false });
4477
+ this.headerPanel = new TextRenderable6(renderer2, { id: "omnius-header-panel", content: "", width: "100%", wrapMode: "word", visible: false });
4292
4478
  this.header.add(this.headerPanel);
4293
- this.detailButton = new TextRenderable5(renderer2, {
4479
+ this.detailButton = new TextRenderable6(renderer2, {
4294
4480
  id: "omnius-details-toggle",
4295
4481
  content: "+ DETAILS",
4296
4482
  height: 1,
4297
4483
  width: 9,
4298
4484
  flexShrink: 0,
4299
4485
  fg: colors.foreground,
4300
- attributes: TextAttributes7.DIM,
4486
+ attributes: TextAttributes8.DIM,
4301
4487
  selectable: false,
4302
4488
  onMouseDown: (event) => {
4303
4489
  if (event.button === 0) {
@@ -4317,60 +4503,67 @@ var NativeFrontend = class {
4317
4503
  for (const control of [this.identity, this.detailButton]) {
4318
4504
  const attributes = control.attributes;
4319
4505
  control.on("focused", () => {
4320
- control.attributes = attributes | TextAttributes7.INVERSE;
4506
+ control.attributes = attributes | TextAttributes8.INVERSE;
4321
4507
  });
4322
4508
  control.on("blurred", () => {
4323
4509
  control.attributes = attributes;
4324
4510
  });
4325
4511
  }
4326
- this.routeWarning = new TextRenderable5(renderer2, { id: "omnius-route-warning", content: "", width: "100%", wrapMode: "word", fg: colors.warning, attributes: TextAttributes7.BOLD | TextAttributes7.UNDERLINE, visible: false, flexShrink: 0 });
4327
- this.root.add(this.routeWarning);
4328
- this.tabs = new TabSelectRenderable(renderer2, {
4329
- id: "omnius-agent-tabs",
4512
+ this.sessionRow = new BoxRenderable7(renderer2, {
4513
+ id: "omnius-sessions-row",
4330
4514
  width: "100%",
4331
- height: 2,
4332
- showDescription: false,
4333
- showUnderline: true,
4334
- showScrollArrows: false,
4335
- tabWidth: 18,
4336
- wrapSelection: true,
4337
- visible: false,
4338
- backgroundColor: colors.background,
4339
- focusedBackgroundColor: colors.background,
4340
- textColor: colors.dim,
4341
- selectedTextColor: colors.foreground,
4342
- selectedBackgroundColor: colors.selection,
4515
+ height: 1,
4516
+ minWidth: 0,
4517
+ flexShrink: 0,
4518
+ flexDirection: "row",
4519
+ gap: 1,
4520
+ visible: false
4521
+ });
4522
+ this.header.add(this.sessionRow);
4523
+ this.sessions = new NativeTabStrip(renderer2, {
4524
+ id: "omnius-session-tabs",
4525
+ prefix: "session",
4526
+ colors,
4527
+ activate: (id) => this.emitAction("session", id)
4528
+ });
4529
+ this.sessionRow.add(this.sessions);
4530
+ this.newSession = new TextRenderable6(renderer2, {
4531
+ id: "omnius-session-new",
4532
+ content: "+ NEW",
4533
+ width: 5,
4534
+ height: 1,
4535
+ flexShrink: 0,
4536
+ selectable: false,
4537
+ fg: colors.foreground,
4538
+ bg: colors.background,
4343
4539
  onMouseDown: (event) => {
4344
- if (event.button !== 0) return;
4345
- const count = Math.max(1, Math.floor(this.tabs.width / this.tabs.getTabWidth()));
4346
- const start = Math.max(0, Math.min(this.tabs.getSelectedIndex() - Math.floor(count / 2), this.tabs.options.length - count));
4347
- this.tabs.setSelectedIndex(start + Math.floor((event.x - this.tabs.x) / this.tabs.getTabWidth()));
4540
+ if (event.button === 0 && !this.state?.sessions?.busy) this.emitAction("session-new");
4541
+ event.preventDefault();
4348
4542
  event.stopPropagation();
4543
+ },
4544
+ onKeyDown: (key) => {
4545
+ if (key.eventType !== "release" && (key.name === "return" || key.sequence === " ")) {
4546
+ if (!this.state?.sessions?.busy) this.emitAction("session-new");
4547
+ key.preventDefault();
4548
+ key.stopPropagation();
4549
+ }
4349
4550
  }
4350
4551
  });
4351
- this.tabs.on("selectionChanged", () => {
4352
- if (this.changing) return;
4353
- const selected = this.tabs.getSelectedOption();
4354
- if (selected) this.emitAction("view", String(selected.value));
4355
- this.editor.focus();
4356
- });
4357
- this.tabs.renderAfter = (buffer) => {
4358
- if (this.tabs.height < 2) return;
4359
- const colors2 = this.context.colors;
4360
- const tabWidth = Math.min(this.tabs.getTabWidth(), this.tabs.width);
4361
- const count = Math.max(1, Math.floor(this.tabs.width / Math.max(1, tabWidth)));
4362
- const selected = this.tabs.getSelectedIndex();
4363
- const start = Math.max(0, Math.min(selected - Math.floor(count / 2), this.tabs.options.length - count));
4364
- buffer.fillRect(0, 1, this.tabs.width, 1, colors2.background);
4365
- buffer.drawText("─".repeat(Math.max(0, tabWidth)), (selected - start) * tabWidth, 1, colors2.foreground, colors2.background, TextAttributes7.DIM);
4552
+ this.newSession.focusable = true;
4553
+ const styleNew = () => {
4554
+ this.newSession.attributes = (this.state?.sessions?.busy ? TextAttributes8.DIM : 0) | (this.newSession.focused ? TextAttributes8.INVERSE : 0);
4366
4555
  };
4367
- this.root.add(this.tabs);
4368
- this.taskPane = new BoxRenderable6(renderer2, { id: "omnius-tasks", width: "100%", flexDirection: "column", maxHeight: 6, flexShrink: 0, overflow: "hidden", visible: false });
4556
+ this.newSession.on("focused", styleNew);
4557
+ this.newSession.on("blurred", styleNew);
4558
+ this.sessionRow.add(this.newSession);
4559
+ this.routeWarning = new TextRenderable6(renderer2, { id: "omnius-route-warning", content: "", width: "100%", wrapMode: "word", fg: colors.warning, attributes: TextAttributes8.BOLD | TextAttributes8.UNDERLINE, visible: false, flexShrink: 0 });
4560
+ this.root.add(this.routeWarning);
4561
+ this.taskPane = new BoxRenderable7(renderer2, { id: "omnius-tasks", width: "100%", flexDirection: "column", maxHeight: 6, flexShrink: 0, overflow: "hidden", visible: false });
4369
4562
  this.tasks = new NativeBlockList(this.context, this.taskPane);
4370
4563
  this.root.add(this.taskPane);
4371
- this.body = new BoxRenderable6(renderer2, { id: "omnius-body", width: "100%", flexDirection: "row", flexGrow: 1, minHeight: 1 });
4564
+ this.body = new BoxRenderable7(renderer2, { id: "omnius-body", width: "100%", flexDirection: "row", flexGrow: 1, minHeight: 1 });
4372
4565
  this.root.add(this.body);
4373
- this.scroll = new ScrollBoxRenderable4(renderer2, {
4566
+ this.scroll = new ScrollBoxRenderable5(renderer2, {
4374
4567
  id: "omnius-conversation",
4375
4568
  flexGrow: 1,
4376
4569
  flexShrink: 1,
@@ -4443,7 +4636,7 @@ var NativeFrontend = class {
4443
4636
  this.root.onMouseUp = (event) => this.instrumentDivider.handleRelease(event);
4444
4637
  this.instruments = new InstrumentRail(renderer2, { colors, onInspectAgent: (id) => this.emitAction("view", id), onAction: (command2) => this.emitAction(command2) });
4445
4638
  this.body.add(this.instruments);
4446
- this.embeddedPane = new BoxRenderable6(renderer2, {
4639
+ this.embeddedPane = new BoxRenderable7(renderer2, {
4447
4640
  id: "omnius-editor-pane",
4448
4641
  width: "50%",
4449
4642
  flexShrink: 0,
@@ -4454,7 +4647,7 @@ var NativeFrontend = class {
4454
4647
  visible: false
4455
4648
  });
4456
4649
  this.body.add(this.embeddedPane);
4457
- this.liveButton = new TextRenderable5(renderer2, {
4650
+ this.liveButton = new TextRenderable6(renderer2, {
4458
4651
  id: "omnius-live-button",
4459
4652
  content: "↓ Live",
4460
4653
  width: "100%",
@@ -4477,7 +4670,7 @@ var NativeFrontend = class {
4477
4670
  });
4478
4671
  this.liveButton.focusable = true;
4479
4672
  this.root.add(this.liveButton);
4480
- this.queue = new TextRenderable5(renderer2, { id: "omnius-steering-queue", content: "", width: "100%", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, visible: false, flexShrink: 0 });
4673
+ this.queue = new TextRenderable6(renderer2, { id: "omnius-steering-queue", content: "", width: "100%", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, visible: false, flexShrink: 0 });
4481
4674
  this.root.add(this.queue);
4482
4675
  this.suggestions = new NativeSelectRenderable(renderer2, {
4483
4676
  id: "omnius-suggestions",
@@ -4496,31 +4689,49 @@ var NativeFrontend = class {
4496
4689
  this.suggestions.onActivate = () => this.acceptSuggestion();
4497
4690
  this.suggestions.on("itemSelected", () => this.acceptSuggestion());
4498
4691
  this.root.add(this.suggestions);
4499
- this.status = new BoxRenderable6(renderer2, { id: "omnius-live-status", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2, visible: false });
4692
+ this.status = new BoxRenderable7(renderer2, { id: "omnius-live-status", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2, visible: false });
4500
4693
  this.root.add(this.status);
4501
- this.footer = new BoxRenderable6(renderer2, {
4694
+ this.footer = new BoxRenderable7(renderer2, {
4502
4695
  id: "omnius-input-box",
4503
4696
  width: "100%",
4504
4697
  flexShrink: 0,
4505
- border: ["top"],
4506
- borderStyle: "single",
4698
+ border: [],
4507
4699
  borderColor: colors.border,
4508
4700
  flexDirection: "column"
4509
4701
  });
4510
4702
  this.root.add(this.footer);
4511
- this.footer.renderAfter = (buffer) => {
4512
- if (this.footer.height > 0) buffer.drawText(
4513
- formatSignalDivider(this.footer.width),
4514
- this.footer.x,
4515
- this.footer.y,
4516
- this.context.colors.foreground,
4517
- this.context.colors.background,
4518
- TextAttributes7.DIM
4519
- );
4703
+ this.footerRule = new BoxRenderable7(renderer2, {
4704
+ id: "omnius-input-rule",
4705
+ width: "100%",
4706
+ height: 1,
4707
+ minHeight: 1,
4708
+ maxHeight: 1,
4709
+ flexShrink: 0,
4710
+ flexDirection: "row",
4711
+ paddingLeft: 2,
4712
+ shouldFill: false
4713
+ });
4714
+ this.footer.add(this.footerRule);
4715
+ this.tabs = new NativeTabStrip(renderer2, {
4716
+ id: "omnius-agent-tabs",
4717
+ prefix: "agent",
4718
+ colors,
4719
+ activate: (id) => this.emitAction("view", id)
4720
+ });
4721
+ this.tabs.flexGrow = 0;
4722
+ this.tabs.flexShrink = 0;
4723
+ this.tabs.visible = false;
4724
+ this.footerRule.add(this.tabs);
4725
+ this.footerRule.renderBefore = (buffer) => {
4726
+ buffer.drawText(formatSignalDivider(this.footerRule.width, {
4727
+ direction: "bottom",
4728
+ leftTextEnd: this.tabs.visible ? this.tabs.x - this.footerRule.x + this.tabs.width : 0,
4729
+ sidebarColumn: this.instrumentDivider.visible && this.instruments.visible ? this.instrumentDivider.x - this.footerRule.x : void 0
4730
+ }), this.footerRule.x, this.footerRule.y, this.context.colors.foreground, this.context.colors.background, TextAttributes8.DIM);
4520
4731
  };
4521
- const inputRow = new BoxRenderable6(renderer2, { id: "omnius-input-row", width: "100%", flexDirection: "row", gap: 1 });
4732
+ const inputRow = new BoxRenderable7(renderer2, { id: "omnius-input-row", width: "100%", flexDirection: "row", gap: 1 });
4522
4733
  this.footer.add(inputRow);
4523
- this.prompt = new TextRenderable5(renderer2, { id: "omnius-prompt", content: "❯", fg: colors.accent, wrapMode: "none", selectable: false, flexShrink: 0 });
4734
+ this.prompt = new TextRenderable6(renderer2, { id: "omnius-prompt", content: "❯", fg: colors.accent, wrapMode: "none", selectable: false, flexShrink: 0 });
4524
4735
  inputRow.add(this.prompt);
4525
4736
  this.editor = new TextareaRenderable2(renderer2, {
4526
4737
  id: "omnius-input",
@@ -4540,14 +4751,14 @@ var NativeFrontend = class {
4540
4751
  onCursorChange: () => this.editorChanged(),
4541
4752
  onSubmit: () => this.submit()
4542
4753
  });
4543
- this.vimMode = new TextRenderable5(renderer2, {
4754
+ this.vimMode = new TextRenderable6(renderer2, {
4544
4755
  id: "omnius-vim-mode",
4545
4756
  content: "INSERT",
4546
4757
  height: 1,
4547
4758
  maxWidth: 12,
4548
4759
  flexShrink: 0,
4549
4760
  fg: colors.foreground,
4550
- attributes: TextAttributes7.DIM,
4761
+ attributes: TextAttributes8.DIM,
4551
4762
  wrapMode: "none",
4552
4763
  truncate: true,
4553
4764
  visible: false,
@@ -4561,42 +4772,42 @@ var NativeFrontend = class {
4561
4772
  this.renderer.requestRender();
4562
4773
  });
4563
4774
  inputRow.add(this.editor);
4564
- this.enhance = new BoxRenderable6(renderer2, { id: "omnius-enhance", flexDirection: "row", gap: 1, flexShrink: 0, visible: false });
4775
+ this.enhance = new BoxRenderable7(renderer2, { id: "omnius-enhance", flexDirection: "row", gap: 1, flexShrink: 0, visible: false });
4565
4776
  inputRow.add(this.enhance);
4566
- this.activity = new TextRenderable5(renderer2, { id: "omnius-activity", content: "", flexGrow: 1, minWidth: 0, height: 1, wrapMode: "none", truncate: true, visible: false, fg: colors.accent });
4777
+ this.activity = new TextRenderable6(renderer2, { id: "omnius-activity", content: "", flexGrow: 1, minWidth: 0, height: 1, wrapMode: "none", truncate: true, visible: false, fg: colors.accent });
4567
4778
  this.status.add(this.activity);
4568
- this.media = new BoxRenderable6(renderer2, { id: "omnius-media", height: 1, minWidth: 0, flexShrink: 1, flexDirection: "row", gap: 1, visible: false });
4569
- this.mediaText = new TextRenderable5(renderer2, { id: "omnius-media-text", content: "", flexGrow: 1, minWidth: 0, wrapMode: "none", truncate: true, fg: colors.accent });
4779
+ this.media = new BoxRenderable7(renderer2, { id: "omnius-media", height: 1, minWidth: 0, flexShrink: 1, flexDirection: "row", gap: 1, visible: false });
4780
+ this.mediaText = new TextRenderable6(renderer2, { id: "omnius-media-text", content: "", flexGrow: 1, minWidth: 0, wrapMode: "none", truncate: true, fg: colors.accent });
4570
4781
  this.media.add(this.mediaText);
4571
- this.micTrack = new TextRenderable5(renderer2, { id: "omnius-mic-meter", width: 12, height: 1, flexShrink: 0, fg: colors.foreground, visible: false });
4782
+ this.micTrack = new TextRenderable6(renderer2, { id: "omnius-mic-meter", width: 12, height: 1, flexShrink: 0, fg: colors.foreground, visible: false });
4572
4783
  this.media.add(this.micTrack);
4573
4784
  this.status.add(this.media);
4574
- this.copyFeedback = new TextRenderable5(renderer2, {
4785
+ this.copyFeedback = new TextRenderable6(renderer2, {
4575
4786
  id: "omnius-copy-feedback",
4576
4787
  content: "",
4577
4788
  height: 1,
4578
4789
  flexShrink: 0,
4579
4790
  fg: colors.foreground,
4580
- attributes: TextAttributes7.DIM,
4791
+ attributes: TextAttributes8.DIM,
4581
4792
  selectable: false,
4582
4793
  visible: false
4583
4794
  });
4584
4795
  this.status.add(this.copyFeedback);
4585
- this.metricsRow = new BoxRenderable6(renderer2, { id: "omnius-metrics-row", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 1 });
4586
- this.keyHints = new TextRenderable5(renderer2, { id: "omnius-key-hints", content: "F1 HELP TAB FOCUS", height: 1, flexShrink: 0, attributes: TextAttributes7.DIM, fg: colors.foreground, selectable: false });
4796
+ this.metricsRow = new BoxRenderable7(renderer2, { id: "omnius-metrics-row", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 1 });
4797
+ this.keyHints = new TextRenderable6(renderer2, { id: "omnius-key-hints", content: "F1 HELP TAB FOCUS", height: 1, flexShrink: 0, attributes: TextAttributes8.DIM, fg: colors.foreground, selectable: false });
4587
4798
  this.metricsRow.add(this.keyHints);
4588
- this.metricsStartActions = new BoxRenderable6(renderer2, { id: "omnius-metrics-start-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
4799
+ this.metricsStartActions = new BoxRenderable7(renderer2, { id: "omnius-metrics-start-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
4589
4800
  this.metricsRow.add(this.metricsStartActions);
4590
- this.metrics = new TextRenderable5(renderer2, { id: "omnius-metrics", content: "", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, flexShrink: 1, flexGrow: 1, minWidth: 0 });
4801
+ this.metrics = new TextRenderable6(renderer2, { id: "omnius-metrics", content: "", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, flexShrink: 1, flexGrow: 1, minWidth: 0 });
4591
4802
  this.metricsRow.add(this.metrics);
4592
- this.metricsEndActions = new BoxRenderable6(renderer2, { id: "omnius-metrics-end-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
4803
+ this.metricsEndActions = new BoxRenderable7(renderer2, { id: "omnius-metrics-end-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
4593
4804
  this.metricsRow.add(this.metricsEndActions);
4594
4805
  this.root.add(this.metricsRow);
4595
4806
  this.modals = new NativeModalStack(this.context, () => this.restoreFocus());
4596
4807
  renderer2.keyInput.on("keypress", this.onKey);
4597
4808
  renderer2.keyInput.on("paste", this.onPaste);
4598
- renderer2.on(CliRenderEvents4.FRAME, this.onFrame);
4599
- renderer2.on(CliRenderEvents4.RESIZE, this.onResize);
4809
+ renderer2.on(CliRenderEvents5.FRAME, this.onFrame);
4810
+ renderer2.on(CliRenderEvents5.RESIZE, this.onResize);
4600
4811
  this.applyTheme(initialTheme);
4601
4812
  this.editor.focus();
4602
4813
  }
@@ -4616,6 +4827,9 @@ var NativeFrontend = class {
4616
4827
  headerPanel;
4617
4828
  routeWarning;
4618
4829
  tabs;
4830
+ sessionRow;
4831
+ sessions;
4832
+ newSession;
4619
4833
  taskPane;
4620
4834
  tasks;
4621
4835
  body;
@@ -4627,6 +4841,7 @@ var NativeFrontend = class {
4627
4841
  queue;
4628
4842
  suggestions;
4629
4843
  footer;
4844
+ footerRule;
4630
4845
  prompt;
4631
4846
  vimMode;
4632
4847
  enhance;
@@ -4646,7 +4861,6 @@ var NativeFrontend = class {
4646
4861
  state;
4647
4862
  themeSignature = "";
4648
4863
  headerSignature = "";
4649
- tabsSignature = "";
4650
4864
  suggestionSignature = "";
4651
4865
  metricsActionsSignature = "";
4652
4866
  changing = false;
@@ -4674,8 +4888,8 @@ var NativeFrontend = class {
4674
4888
  selectionArmed = false;
4675
4889
  update(state, patch) {
4676
4890
  const inputWasEnabled = this.state?.input.enabled;
4677
- const previousView = this.state ? `${this.state.activeViewId}:${this.state.presentation ?? "stack"}` : void 0;
4678
- const currentView = `${state.activeViewId}:${state.presentation ?? "stack"}`;
4891
+ const previousView = this.state ? `${this.state.sessions?.activeId ?? ""}:${this.state.activeViewId}:${this.state.presentation ?? "stack"}` : void 0;
4892
+ const currentView = `${state.sessions?.activeId ?? ""}:${state.activeViewId}:${state.presentation ?? "stack"}`;
4679
4893
  const viewChanged = previousView !== void 0 && previousView !== currentView;
4680
4894
  if (viewChanged) {
4681
4895
  this.viewScroll.set(previousView, { top: this.scroll.scrollTop, live: this.offset === 0 });
@@ -4701,14 +4915,13 @@ var NativeFrontend = class {
4701
4915
  }
4702
4916
  this.routeWarning.content = state.routeWarning ? `! ${state.routeWarning}` : "";
4703
4917
  this.routeWarning.visible = Boolean(state.routeWarning);
4704
- const tabsSignature = JSON.stringify(state.tabs);
4705
- if (tabsSignature !== this.tabsSignature) {
4706
- this.tabsSignature = tabsSignature;
4707
- this.tabs.setOptions(state.tabs.map((tab) => ({ name: fitInstrumentText(plainText(tab.label), this.tabs.getTabWidth() - 2), description: "", value: tab.id })));
4708
- }
4709
- this.tabs.visible = state.tabs.length > 1;
4710
- const activeTab = state.tabs.findIndex((tab) => tab.id === state.activeViewId);
4711
- if (activeTab >= 0 && activeTab !== this.tabs.getSelectedIndex()) this.tabs.setSelectedIndex(activeTab);
4918
+ this.tabs.update(state.tabs, state.activeViewId);
4919
+ this.tabs.visible = state.tabs.some((tab) => tab.id !== "main");
4920
+ this.sessionRow.visible = Boolean(state.sessions);
4921
+ this.sessions.update(state.sessions?.items ?? [], state.sessions?.activeId ?? "", state.sessions?.busy);
4922
+ this.newSession.focusable = !state.sessions?.busy;
4923
+ if (state.sessions?.busy && this.newSession.focused) this.getRenderable(`session:${state.sessions.activeId}`)?.focus();
4924
+ this.newSession.attributes = state.sessions?.busy ? TextAttributes8.DIM : this.newSession.focused ? TextAttributes8.INVERSE : 0;
4712
4925
  this.tasks.replace(state.tasks);
4713
4926
  this.taskPane.visible = state.tasks.length > 0;
4714
4927
  if (patch) {
@@ -4730,7 +4943,7 @@ var NativeFrontend = class {
4730
4943
  this.prompt.content = styledText(state.prompt.trimEnd() || "❯");
4731
4944
  if (!this.editorInitialized) {
4732
4945
  this.editor.setText(state.input.text);
4733
- this.editor.cursorOffset = Math.max(0, Math.min(state.input.text.length, state.input.cursor));
4946
+ this.placeInputCursor(state.input.text, state.input.cursor);
4734
4947
  this.editorInitialized = true;
4735
4948
  }
4736
4949
  this.editor.focusable = state.input.enabled && !this.paused;
@@ -4739,6 +4952,7 @@ var NativeFrontend = class {
4739
4952
  this.metrics.visible = state.metricsVisible;
4740
4953
  this.instruments.update(state);
4741
4954
  this.layoutInstruments();
4955
+ this.layoutTabStrips();
4742
4956
  const metricsActions = JSON.stringify(state.metricsActions ?? []);
4743
4957
  if (metricsActions !== this.metricsActionsSignature) {
4744
4958
  this.metricsActionsSignature = metricsActions;
@@ -4761,8 +4975,8 @@ var NativeFrontend = class {
4761
4975
  for (const child of [...parent.getChildren()]) child.destroy();
4762
4976
  for (const action of actions) {
4763
4977
  const colors = this.context.colors;
4764
- const attributes = action.disabled ? TextAttributes7.DIM : action.active ? TextAttributes7.BOLD | TextAttributes7.UNDERLINE : 0;
4765
- const button = new TextRenderable5(this.renderer, {
4978
+ const attributes = action.disabled ? TextAttributes8.DIM : action.active ? TextAttributes8.BOLD | TextAttributes8.UNDERLINE : 0;
4979
+ const button = new TextRenderable6(this.renderer, {
4766
4980
  id: `${prefix}:${action.id}`,
4767
4981
  content: styledText(action.label),
4768
4982
  flexShrink: 0,
@@ -4785,16 +4999,16 @@ var NativeFrontend = class {
4785
4999
  button.focusable = !action.disabled;
4786
5000
  if (!action.disabled) {
4787
5001
  button.on("focused", () => {
4788
- button.attributes = attributes | TextAttributes7.INVERSE;
5002
+ button.attributes = attributes | TextAttributes8.INVERSE;
4789
5003
  });
4790
5004
  button.on("blurred", () => {
4791
5005
  button.attributes = attributes;
4792
5006
  });
4793
5007
  button.onMouseOver = () => {
4794
- button.attributes = attributes | TextAttributes7.UNDERLINE | (button.focused ? TextAttributes7.INVERSE : 0);
5008
+ button.attributes = attributes | TextAttributes8.UNDERLINE | (button.focused ? TextAttributes8.INVERSE : 0);
4795
5009
  };
4796
5010
  button.onMouseOut = () => {
4797
- button.attributes = attributes | (button.focused ? TextAttributes7.INVERSE : 0);
5011
+ button.attributes = attributes | (button.focused ? TextAttributes8.INVERSE : 0);
4798
5012
  };
4799
5013
  }
4800
5014
  parent.add(button);
@@ -4856,10 +5070,10 @@ var NativeFrontend = class {
4856
5070
  this.editor.backgroundColor = this.editor.focusedBackgroundColor = colors.background;
4857
5071
  this.editor.textColor = this.editor.focusedTextColor = colors.foreground;
4858
5072
  this.editor.editorView.setSelectionColors(void 0, void 0);
4859
- this.tabs.backgroundColor = this.tabs.focusedBackgroundColor = colors.background;
4860
- this.tabs.textColor = colors.dim;
4861
- this.tabs.selectedTextColor = colors.foreground;
4862
- this.tabs.selectedBackgroundColor = colors.selection;
5073
+ this.tabs.applyTheme(colors);
5074
+ this.sessions.applyTheme(colors);
5075
+ this.newSession.fg = colors.foreground;
5076
+ this.newSession.bg = colors.background;
4863
5077
  this.suggestions.backgroundColor = this.suggestions.focusedBackgroundColor = colors.background;
4864
5078
  this.suggestions.textColor = colors.dim;
4865
5079
  this.suggestions.selectedTextColor = colors.foreground;
@@ -4971,6 +5185,7 @@ var NativeFrontend = class {
4971
5185
  }
4972
5186
  const height = Math.max(1, Math.min(8, this.editor.editorView.getTotalVirtualLineCount(), this.renderer.terminalHeight - 8));
4973
5187
  if (height !== this.editor.height) this.editor.height = height;
5188
+ this.layoutTabStrips();
4974
5189
  const offset = this.offset;
4975
5190
  if (offset === 0) this.newEntries = 0;
4976
5191
  this.liveButton.visible = offset > 0;
@@ -4985,8 +5200,16 @@ var NativeFrontend = class {
4985
5200
  };
4986
5201
  onResize = () => {
4987
5202
  this.layoutInstruments();
5203
+ this.layoutTabStrips();
4988
5204
  this.emit({ type: "resize", columns: this.renderer.terminalWidth, rows: this.renderer.terminalHeight });
4989
5205
  };
5206
+ layoutTabStrips() {
5207
+ const width = this.renderer.terminalWidth;
5208
+ const junction = this.instrumentDivider.visible && this.instruments.visible ? this.instrumentDivider.x : width - 3;
5209
+ const available = Math.max(0, junction - 6);
5210
+ const desired = Math.min(this.tabs.naturalWidth, available);
5211
+ if (this.tabs.width !== desired) this.tabs.width = desired;
5212
+ }
4990
5213
  editorChanged() {
4991
5214
  if (!this.editor || this.changing || this.destroyed || this.inputEventPending) return;
4992
5215
  this.inputEventPending = true;
@@ -5000,7 +5223,7 @@ var NativeFrontend = class {
5000
5223
  }
5001
5224
  flushLatestInput() {
5002
5225
  const text = this.editor.plainText;
5003
- const cursor = this.editor.cursorOffset;
5226
+ const cursor = this.inputCursor();
5004
5227
  if (text === this.lastInput && cursor === this.lastCursor) return;
5005
5228
  this.lastInput = text;
5006
5229
  this.lastCursor = cursor;
@@ -5043,10 +5266,17 @@ var NativeFrontend = class {
5043
5266
  }
5044
5267
  setInput(text, cursor = text.length) {
5045
5268
  this.editor.replaceText(text);
5046
- this.editor.cursorOffset = Math.max(0, Math.min(text.length, cursor));
5269
+ this.placeInputCursor(text, cursor);
5047
5270
  this.editorInitialized = true;
5048
5271
  this.editorChanged();
5049
5272
  }
5273
+ inputCursor() {
5274
+ return this.editor.getTextRange(0, this.editor.cursorOffset).length;
5275
+ }
5276
+ placeInputCursor(text, cursor) {
5277
+ const index = Math.max(0, Math.min(text.length, cursor));
5278
+ this.editor.cursorOffset = this.editor.editBuffer.measureText(text.slice(0, index));
5279
+ }
5050
5280
  shortcut(name, key) {
5051
5281
  this.flushLatestInput();
5052
5282
  this.emit({ type: "shortcut", name });
@@ -5214,7 +5444,7 @@ var NativeFrontend = class {
5214
5444
  const targets = [];
5215
5445
  const visit = (node) => {
5216
5446
  if (!node.visible) return;
5217
- if (node.focusable && node !== this.scroll && !(node instanceof ScrollBoxRenderable4) && node.height > 0 && node.width > 0) targets.push(node);
5447
+ if (node.focusable && node !== this.scroll && !(node instanceof ScrollBoxRenderable5) && node.height > 0 && node.width > 0) targets.push(node);
5218
5448
  for (const child of node.getChildren()) visit(child);
5219
5449
  };
5220
5450
  visit(this.root);
@@ -5296,7 +5526,7 @@ var NativeFrontend = class {
5296
5526
  break;
5297
5527
  }
5298
5528
  case "input":
5299
- if (command2.expectedText !== void 0 && command2.expectedText !== this.editor.plainText || command2.expectedCursor !== void 0 && command2.expectedCursor !== this.editor.cursorOffset) {
5529
+ if (command2.expectedText !== void 0 && command2.expectedText !== this.editor.plainText || command2.expectedCursor !== void 0 && command2.expectedCursor !== this.inputCursor()) {
5300
5530
  this.flushLatestInput();
5301
5531
  } else this.setInput(command2.text, command2.cursor);
5302
5532
  break;
@@ -5406,8 +5636,8 @@ var NativeFrontend = class {
5406
5636
  this.disposeSelectionContrast();
5407
5637
  this.renderer.keyInput.off("keypress", this.onKey);
5408
5638
  this.renderer.keyInput.off("paste", this.onPaste);
5409
- this.renderer.off(CliRenderEvents4.FRAME, this.onFrame);
5410
- this.renderer.off(CliRenderEvents4.RESIZE, this.onResize);
5639
+ this.renderer.off(CliRenderEvents5.FRAME, this.onFrame);
5640
+ this.renderer.off(CliRenderEvents5.RESIZE, this.onResize);
5411
5641
  this.modals.destroy();
5412
5642
  this.content.destroy();
5413
5643
  this.tasks.destroy();
@@ -5418,7 +5648,7 @@ var NativeFrontend = class {
5418
5648
  };
5419
5649
 
5420
5650
  // packages/cli/src/tui/native/components/cursor.ts
5421
- import { CliRenderEvents as CliRenderEvents5 } from "@opentui/core";
5651
+ import { CliRenderEvents as CliRenderEvents6 } from "@opentui/core";
5422
5652
  function installTerminalCursorDefaults(renderer2, session) {
5423
5653
  const reset = new TextEncoder().encode("\x1B]112\x07");
5424
5654
  let disposed = false;
@@ -5468,11 +5698,11 @@ function installTerminalCursorDefaults(renderer2, session) {
5468
5698
  const dispose = () => {
5469
5699
  if (disposed) return;
5470
5700
  disposed = true;
5471
- renderer2.off(CliRenderEvents5.FRAME, afterFrame);
5472
- renderer2.off(CliRenderEvents5.DESTROY, dispose);
5701
+ renderer2.off(CliRenderEvents6.FRAME, afterFrame);
5702
+ renderer2.off(CliRenderEvents6.DESTROY, dispose);
5473
5703
  };
5474
- renderer2.on(CliRenderEvents5.FRAME, afterFrame);
5475
- renderer2.once(CliRenderEvents5.DESTROY, dispose);
5704
+ renderer2.on(CliRenderEvents6.FRAME, afterFrame);
5705
+ renderer2.once(CliRenderEvents6.DESTROY, dispose);
5476
5706
  return { restore, dispose };
5477
5707
  }
5478
5708
 
@@ -5548,10 +5778,10 @@ try {
5548
5778
  maxFps: 60,
5549
5779
  clearOnShutdown: false
5550
5780
  });
5551
- renderer.on(CliRenderEvents6.RENDER_ERROR, (event) => {
5781
+ renderer.on(CliRenderEvents7.RENDER_ERROR, (event) => {
5552
5782
  void fail(event.error);
5553
5783
  });
5554
- renderer.on(CliRenderEvents6.HANDLER_ERROR, (event) => {
5784
+ renderer.on(CliRenderEvents7.HANDLER_ERROR, (event) => {
5555
5785
  void fail(event.error);
5556
5786
  });
5557
5787
  renderer.on("error", (event) => {