open-agents-ai 0.187.39 → 0.187.40

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 (2) hide show
  1. package/dist/index.js +110 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -299641,6 +299641,69 @@ var init_status_bar = __esm({
299641
299641
  _streamStartTime = 0;
299642
299642
  /** Current package version (shown in metrics row, rightmost) */
299643
299643
  _version = "";
299644
+ // ── Header Panel System ──────────────────────────────────────────────
299645
+ // Extensible dual-state (N-state) header: the content row inside the
299646
+ // ╭│╰ box cycles between registered panels via arrow buttons.
299647
+ // Page 0 = "main" (version + menu buttons) — always registered.
299648
+ // Page 1 = "agents" (agent tabs, voice, nexus) — registered on demand.
299649
+ // Future pages added via registerHeaderPanel().
299650
+ /** Registered header panels. Each has a unique id and a render function. */
299651
+ _headerPanels = [];
299652
+ /** Index of the currently visible panel (0 = main) */
299653
+ _headerPanelIndex = 0;
299654
+ /** Register a header panel. Returns its index. */
299655
+ registerHeaderPanel(id, render) {
299656
+ const existing = this._headerPanels.findIndex((p2) => p2.id === id);
299657
+ if (existing >= 0) {
299658
+ this._headerPanels[existing] = { id, render };
299659
+ return existing;
299660
+ }
299661
+ this._headerPanels.push({ id, render });
299662
+ return this._headerPanels.length - 1;
299663
+ }
299664
+ /** Switch to the next header panel (wraps around) */
299665
+ nextHeaderPanel() {
299666
+ if (this._headerPanels.length <= 1)
299667
+ return;
299668
+ this._headerPanelIndex = (this._headerPanelIndex + 1) % this._headerPanels.length;
299669
+ this.refreshHeaderContent();
299670
+ }
299671
+ /** Switch to the previous header panel (wraps around) */
299672
+ prevHeaderPanel() {
299673
+ if (this._headerPanels.length <= 1)
299674
+ return;
299675
+ this._headerPanelIndex = (this._headerPanelIndex - 1 + this._headerPanels.length) % this._headerPanels.length;
299676
+ this.refreshHeaderContent();
299677
+ }
299678
+ /** Get current panel id */
299679
+ get currentHeaderPanel() {
299680
+ return this._headerPanels[this._headerPanelIndex]?.id ?? "main";
299681
+ }
299682
+ /** Render the current header panel content onto terminal row 2 (inside box) */
299683
+ refreshHeaderContent() {
299684
+ if (!this.active)
299685
+ return;
299686
+ const w = process.stdout.columns ?? 80;
299687
+ const innerW = w - 2;
299688
+ const panel = this._headerPanels[this._headerPanelIndex];
299689
+ if (!panel)
299690
+ return;
299691
+ const content = panel.render(innerW);
299692
+ const hasMultiple = this._headerPanels.length > 1;
299693
+ const leftArrow = hasMultiple ? `\x1B]8;;oa-cmd:header-prev\x07\x1B[38;5;${TEXT_DIM}m${this._headerPanelIndex > 0 ? "\u25C0" : " "}\x1B]8;;\x07` : " ";
299694
+ const rightArrow = hasMultiple ? `\x1B]8;;oa-cmd:header-next\x07\x1B[38;5;${TEXT_DIM}m${this._headerPanelIndex < this._headerPanels.length - 1 ? "\u25B6" : " "}\x1B]8;;\x07` : " ";
299695
+ let buf = "\x1B7";
299696
+ buf += `\x1B[2;1H\x1B[48;5;0m\x1B[2K`;
299697
+ buf += `${BOX_FG}\u2502${RESET}\x1B[48;5;0m`;
299698
+ buf += leftArrow;
299699
+ buf += `\x1B[38;5;${TEXT_PRIMARY}m\x1B[48;5;0m`;
299700
+ buf += content;
299701
+ buf += `\x1B[2;${w - 1}H`;
299702
+ buf += rightArrow;
299703
+ buf += `${BOX_FG}\u2502${RESET}`;
299704
+ buf += "\x1B8";
299705
+ this.termWrite(buf);
299706
+ }
299644
299707
  /**
299645
299708
  * Provide a callback that returns readline's current input state.
299646
299709
  * StatusBar uses this to render typed text and position the cursor
@@ -300188,6 +300251,39 @@ var init_status_bar = __esm({
300188
300251
  activate(scrollRegionTop) {
300189
300252
  this.scrollRegionTop = scrollRegionTop ?? 1;
300190
300253
  this.active = true;
300254
+ if (this._headerPanels.length === 0) {
300255
+ this.registerHeaderPanel("main", (innerW) => {
300256
+ const verText = ` OA v${this._version}`;
300257
+ const btnLabels = [" help ", " voice ", " model ", " cohere "];
300258
+ const btnText = btnLabels.join(" ");
300259
+ const gap = Math.max(1, innerW - verText.length - btnText.length - 4);
300260
+ let out = `\x1B[1;38;5;${TEXT_PRIMARY}m${verText}`;
300261
+ out += `\x1B[38;5;${TEXT_DIM}m${" ".repeat(gap)}`;
300262
+ for (const btn of btnLabels) {
300263
+ out += `\x1B]8;;oa-cmd:${btn.trim()}\x07\x1B[38;5;${TEXT_DIM}m${btn}\x1B]8;;\x07 `;
300264
+ }
300265
+ return out;
300266
+ });
300267
+ this.registerHeaderPanel("systems", (_innerW) => {
300268
+ let out = "";
300269
+ if (this._agentViews.size > 1) {
300270
+ for (const view of this._agentViews.values()) {
300271
+ if (view.id === "main" && this._activeViewId === "main")
300272
+ continue;
300273
+ const icon = view.status === "running" ? "\u25CF" : view.status === "completed" ? "\u2713" : view.status === "failed" ? "\u2717" : "\u25CB";
300274
+ const isActive = view.id === this._activeViewId;
300275
+ const fg2 = isActive ? 252 : 245;
300276
+ out += `\x1B]8;;oa-view:${view.id}\x07\x1B[38;5;${fg2}m ${view.label} ${icon} \x1B]8;;\x07 `;
300277
+ }
300278
+ } else {
300279
+ out += `\x1B[38;5;${TEXT_DIM}m no sub-agents `;
300280
+ }
300281
+ out += `\x1B[38;5;${TEXT_DIM}m\u2502 `;
300282
+ out += `\x1B]8;;oa-cmd:voice\x07\x1B[38;5;${TEXT_DIM}m voice \x1B]8;;\x07 `;
300283
+ out += `\x1B]8;;oa-cmd:nexus\x07\x1B[38;5;${TEXT_DIM}m nexus \x1B]8;;\x07`;
300284
+ return out;
300285
+ });
300286
+ }
300191
300287
  if (!this._agentViews.has("main")) {
300192
300288
  this._agentViews.set("main", {
300193
300289
  id: "main",
@@ -300205,6 +300301,7 @@ var init_status_bar = __esm({
300205
300301
  this.applyScrollRegion();
300206
300302
  this.fillContentArea();
300207
300303
  this.renderFooterAndPositionInput();
300304
+ this.refreshHeaderContent();
300208
300305
  this.hookStdin();
300209
300306
  if (!this._metricsCollector.isActive) {
300210
300307
  this.startLocalMetrics();
@@ -300458,6 +300555,14 @@ var init_status_bar = __esm({
300458
300555
  if (row < this.scrollRegionTop) {
300459
300556
  const cmd = hitTestHeaderButton(row, col, w);
300460
300557
  if (type === "press" && cmd) {
300558
+ if (cmd === "header-prev") {
300559
+ this.prevHeaderPanel();
300560
+ return;
300561
+ }
300562
+ if (cmd === "header-next") {
300563
+ this.nextHeaderPanel();
300564
+ return;
300565
+ }
300461
300566
  setPressedButton(cmd);
300462
300567
  setHoveredButton(null);
300463
300568
  this.renderHeaderButtons();
@@ -300609,45 +300714,14 @@ var init_status_bar = __esm({
300609
300714
  return this._agentViews.size > 1;
300610
300715
  }
300611
300716
  // ── Agent Tab Bar (WO-NA2) ───────────────────────────────────
300612
- /** Render the agent tab bar in the HEADER area (row 2, right-aligned).
300613
- * Moved from footer to header so agents are visible alongside version info. */
300717
+ /** Refresh agent tabs in header delegates to the header panel system.
300718
+ * If currently on the "systems" panel, re-render to show updated agent list. */
300614
300719
  renderAgentTabs() {
300615
- if (!this.active || !this.hasSubAgents)
300720
+ if (!this.active)
300616
300721
  return;
300617
- const w = process.stdout.columns ?? 80;
300618
- const headerContentRow = 2;
300619
- const tabs = [];
300620
- let totalLen = 0;
300621
- for (const view of this._agentViews.values()) {
300622
- const isActive = view.id === this._activeViewId;
300623
- if (view.id === "main" && this._activeViewId === "main")
300624
- continue;
300625
- const icon = view.status === "running" ? "\u25CF" : (
300626
- // ●
300627
- view.status === "completed" ? "\u2713" : (
300628
- // ✓
300629
- view.status === "failed" ? "\u2717" : (
300630
- // ✗
300631
- view.status === "paused" ? "\u25CB" : "?"
300632
- )
300633
- )
300634
- );
300635
- const label = ` ${view.label} ${icon} `;
300636
- const bg = isActive ? 235 : 0;
300637
- const fg2 = isActive ? 252 : 245;
300638
- const tabStr = `\x1B]8;;oa-view:${view.id}\x07\x1B[38;5;${fg2}m\x1B[48;5;${bg}m${label}\x1B[0m\x1B[48;5;0m\x1B]8;;\x07`;
300639
- tabs.push(tabStr);
300640
- totalLen += label.length + 1;
300641
- if (totalLen >= Math.floor(w * 0.4))
300642
- break;
300722
+ if (this.currentHeaderPanel === "systems") {
300723
+ this.refreshHeaderContent();
300643
300724
  }
300644
- if (tabs.length === 0)
300645
- return;
300646
- const startCol = Math.max(2, w - totalLen - 2);
300647
- let buf = `\x1B[${headerContentRow};${startCol}H\x1B[48;5;0m`;
300648
- buf += tabs.join(" ");
300649
- buf += RESET;
300650
- this.termWrite(buf);
300651
300725
  }
300652
300726
  /** Hit-test the tab bar for click events. Returns view ID or null. */
300653
300727
  hitTestTabBar(col) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.39",
3
+ "version": "0.187.40",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",