open-agents-ai 0.103.85 → 0.103.87

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 +317 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6726,8 +6726,8 @@ async function loadTranscribeCli() {
6726
6726
  const nvmBase = join16(homedir6(), ".nvm", "versions", "node");
6727
6727
  if (existsSync13(nvmBase)) {
6728
6728
  try {
6729
- const { readdirSync: readdirSync16 } = await import("node:fs");
6730
- for (const ver of readdirSync16(nvmBase)) {
6729
+ const { readdirSync: readdirSync17 } = await import("node:fs");
6730
+ for (const ver of readdirSync17(nvmBase)) {
6731
6731
  const tcPath = join16(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
6732
6732
  if (existsSync13(join16(tcPath, "dist", "index.js"))) {
6733
6733
  const { createRequire: createRequire4 } = await import("node:module");
@@ -22625,8 +22625,8 @@ var init_listen = __esm({
22625
22625
  const nvmBase = join34(homedir8(), ".nvm", "versions", "node");
22626
22626
  if (existsSync26(nvmBase)) {
22627
22627
  try {
22628
- const { readdirSync: readdirSync16 } = await import("node:fs");
22629
- for (const ver of readdirSync16(nvmBase)) {
22628
+ const { readdirSync: readdirSync17 } = await import("node:fs");
22629
+ for (const ver of readdirSync17(nvmBase)) {
22630
22630
  const tcPath = join34(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
22631
22631
  if (existsSync26(join34(tcPath, "dist", "index.js"))) {
22632
22632
  const { createRequire: createRequire4 } = await import("node:module");
@@ -33578,9 +33578,9 @@ function tuiSelect(opts) {
33578
33578
  const first = findSelectable(0, 1);
33579
33579
  cursor = first >= 0 ? first : 0;
33580
33580
  }
33581
- const termRows = process.stdout.rows ?? 24;
33582
- const overhead = 6;
33583
- const maxVisible = opts.maxVisible ?? Math.max(3, termRows - overhead);
33581
+ const selectChrome = 3;
33582
+ const contentArea = opts.availableRows ?? (process.stdout.rows ?? 24);
33583
+ const maxVisible = opts.maxVisible ?? Math.max(3, contentArea - selectChrome);
33584
33584
  let scrollOffset = 0;
33585
33585
  let lastRenderedLines = 0;
33586
33586
  return new Promise((resolve31) => {
@@ -33690,7 +33690,8 @@ function tuiSelect(opts) {
33690
33690
  } else {
33691
33691
  const actionHint = opts.onAction ? " \u2190/\u2192/Space toggle" : "";
33692
33692
  const deleteHint = opts.onDelete ? " Del remove" : "";
33693
- lines.push(` ${selectColors.dim("\u2191/\u2193 navigate Enter select" + actionHint + deleteHint + " Esc " + (filter ? "clear filter" : "cancel") + " Type to filter")}`);
33693
+ const customHint = opts.customKeyHint ?? "";
33694
+ lines.push(` ${selectColors.dim("\u2191/\u2193 navigate Enter select" + actionHint + deleteHint + customHint + " Esc " + (filter ? "clear filter" : "cancel") + " Type to filter")}`);
33694
33695
  }
33695
33696
  lines.push("");
33696
33697
  const output = lines.join("\n");
@@ -33858,6 +33859,23 @@ function tuiSelect(opts) {
33858
33859
  render();
33859
33860
  }
33860
33861
  } else if (seq.length === 1 && seq.charCodeAt(0) >= 32 && seq.charCodeAt(0) < 127) {
33862
+ if (opts.onCustomKey && !isSkippable(cursor) && matchSet.has(cursor)) {
33863
+ const consumed = opts.onCustomKey(items[cursor], seq, {
33864
+ done: () => render(),
33865
+ resolve: (result) => {
33866
+ cleanup();
33867
+ resolve31(result);
33868
+ },
33869
+ getInput: (prompt, prefill) => getInputFromUser(prompt, prefill),
33870
+ render: () => render(),
33871
+ updateItem: (index, updates) => {
33872
+ Object.assign(items[index], updates);
33873
+ render();
33874
+ }
33875
+ });
33876
+ if (consumed)
33877
+ return;
33878
+ }
33861
33879
  filter += seq;
33862
33880
  updateFilter();
33863
33881
  if (matchSet.size > 0) {
@@ -33869,6 +33887,72 @@ function tuiSelect(opts) {
33869
33887
  render();
33870
33888
  }
33871
33889
  }
33890
+ function getInputFromUser(prompt, prefill = "") {
33891
+ return new Promise((inputResolve) => {
33892
+ let inputBuf = prefill;
33893
+ let inputCursor = prefill.length;
33894
+ process.stdout.write("\x1B[?25h");
33895
+ function renderInput() {
33896
+ process.stdout.write(`\x1B[${lastRenderedLines}A`);
33897
+ const saveFooter = lastRenderedLines;
33898
+ for (let i = 0; i < saveFooter; i++)
33899
+ process.stdout.write("\x1B[B");
33900
+ process.stdout.write("\x1B[2A");
33901
+ process.stdout.write("\x1B[2K");
33902
+ const before = inputBuf.slice(0, inputCursor);
33903
+ const after = inputBuf.slice(inputCursor);
33904
+ process.stdout.write(` ${selectColors.cyan("\u203A")} ${selectColors.bold(prompt)} ${before}\x1B[7m${after.charAt(0) || " "}\x1B[27m${after.slice(1)}`);
33905
+ process.stdout.write("\n\x1B[2K");
33906
+ process.stdout.write(` ${selectColors.dim("Enter confirm Esc cancel")}`);
33907
+ process.stdout.write("\n");
33908
+ }
33909
+ function onInputData(chunk) {
33910
+ const s = chunk.toString("utf8");
33911
+ if (s === "\r" || s === "\n") {
33912
+ stdin.removeListener("data", onInputData);
33913
+ stdin.on("data", onData);
33914
+ process.stdout.write("\x1B[?25l");
33915
+ render();
33916
+ inputResolve(inputBuf);
33917
+ } else if (s === "\x1B" || s === "\x1B\x1B" || s === "") {
33918
+ stdin.removeListener("data", onInputData);
33919
+ stdin.on("data", onData);
33920
+ process.stdout.write("\x1B[?25l");
33921
+ render();
33922
+ inputResolve(null);
33923
+ } else if (s === "\x7F" || s === "\b") {
33924
+ if (inputCursor > 0) {
33925
+ inputBuf = inputBuf.slice(0, inputCursor - 1) + inputBuf.slice(inputCursor);
33926
+ inputCursor--;
33927
+ renderInput();
33928
+ }
33929
+ } else if (s === "\x1B[D") {
33930
+ if (inputCursor > 0) {
33931
+ inputCursor--;
33932
+ renderInput();
33933
+ }
33934
+ } else if (s === "\x1B[C") {
33935
+ if (inputCursor < inputBuf.length) {
33936
+ inputCursor++;
33937
+ renderInput();
33938
+ }
33939
+ } else if (s === "\x1B[H") {
33940
+ inputCursor = 0;
33941
+ renderInput();
33942
+ } else if (s === "\x1B[F") {
33943
+ inputCursor = inputBuf.length;
33944
+ renderInput();
33945
+ } else if (s.length === 1 && s.charCodeAt(0) >= 32 && s.charCodeAt(0) < 127) {
33946
+ inputBuf = inputBuf.slice(0, inputCursor) + s + inputBuf.slice(inputCursor);
33947
+ inputCursor++;
33948
+ renderInput();
33949
+ }
33950
+ }
33951
+ stdin.removeListener("data", onData);
33952
+ stdin.on("data", onInputData);
33953
+ renderInput();
33954
+ });
33955
+ }
33872
33956
  const onResize = () => render();
33873
33957
  process.stdout.on("resize", onResize);
33874
33958
  stdin.on("data", onData);
@@ -34363,6 +34447,10 @@ async function handleSlashCommand(input, ctx) {
34363
34447
  renderInfo(msg2);
34364
34448
  return "handled";
34365
34449
  }
34450
+ if (arg === "list" || arg === "ls" || arg === "voices") {
34451
+ await handleVoiceList(ctx);
34452
+ return "handled";
34453
+ }
34366
34454
  const msg = await ctx.voiceSetModel(arg);
34367
34455
  save({ voice: true, voiceModel: arg });
34368
34456
  renderInfo(msg + (hasLocal ? " (project-local)" : ""));
@@ -35225,7 +35313,8 @@ async function showConfigEditor(ctx) {
35225
35313
  rl: ctx.rl,
35226
35314
  skipKeys,
35227
35315
  renderRow: renderConfigRow,
35228
- onAction
35316
+ onAction,
35317
+ availableRows: ctx.availableContentRows?.()
35229
35318
  });
35230
35319
  if (result.confirmed && result.key) {
35231
35320
  const entry = entries.find((e) => e.key === result.key);
@@ -35298,7 +35387,8 @@ async function handleExposeConfig(ctx) {
35298
35387
  items,
35299
35388
  title: "Expose Configuration",
35300
35389
  rl: ctx.rl,
35301
- skipKeys
35390
+ skipKeys,
35391
+ availableRows: ctx.availableContentRows?.()
35302
35392
  });
35303
35393
  if (!result.confirmed || !result.key) {
35304
35394
  renderInfo("Expose config cancelled.");
@@ -35407,7 +35497,8 @@ async function showModelPicker(ctx, local = false) {
35407
35497
  title: "Select Model",
35408
35498
  rl: ctx.rl,
35409
35499
  // Skip header rows
35410
- skipKeys: ["__header_recent__", "__header_available__"]
35500
+ skipKeys: ["__header_recent__", "__header_available__"],
35501
+ availableRows: ctx.availableContentRows?.()
35411
35502
  });
35412
35503
  if (!result.confirmed || !result.key) {
35413
35504
  renderInfo("Model selection cancelled.");
@@ -35418,6 +35509,82 @@ async function showModelPicker(ctx, local = false) {
35418
35509
  renderError(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
35419
35510
  }
35420
35511
  }
35512
+ function formatFileSize(bytes) {
35513
+ if (bytes < 1024)
35514
+ return `${bytes}B`;
35515
+ if (bytes < 1024 * 1024)
35516
+ return `${(bytes / 1024).toFixed(0)}KB`;
35517
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
35518
+ }
35519
+ async function handleVoiceList(ctx) {
35520
+ if (!ctx.voiceListClones) {
35521
+ renderWarning("Voice clone management not available in this context.");
35522
+ return;
35523
+ }
35524
+ const clones = ctx.voiceListClones();
35525
+ if (clones.length === 0) {
35526
+ renderInfo("No clone reference voices found.");
35527
+ renderInfo("Add one with: /voice clone <audio-file>");
35528
+ renderInfo("Or generate from ONNX: /voice clone glados");
35529
+ return;
35530
+ }
35531
+ const items = clones.map((cl) => ({
35532
+ key: cl.filename,
35533
+ label: cl.name,
35534
+ detail: `${cl.filename} ${formatFileSize(cl.size)}`
35535
+ }));
35536
+ const activeFilename = clones.find((cl) => cl.isActive)?.filename;
35537
+ const result = await tuiSelect({
35538
+ items,
35539
+ activeKey: activeFilename,
35540
+ title: "Voice Clone References",
35541
+ rl: ctx.rl,
35542
+ availableRows: ctx.availableContentRows?.(),
35543
+ customKeyHint: " e rename p play",
35544
+ onDelete: (item, done) => {
35545
+ if (ctx.voiceDeleteClone?.(item.key)) {
35546
+ done(true);
35547
+ } else {
35548
+ done(false);
35549
+ }
35550
+ },
35551
+ onCustomKey: (item, key, helpers) => {
35552
+ if (key === "e" || key === "E") {
35553
+ const currentName = item.label;
35554
+ helpers.getInput("New name:", currentName).then((newName) => {
35555
+ if (newName !== null && newName.trim() && newName.trim() !== currentName) {
35556
+ ctx.voiceRenameClone?.(item.key, newName.trim());
35557
+ const idx = items.findIndex((i) => i.key === item.key);
35558
+ if (idx >= 0) {
35559
+ helpers.updateItem(idx, { label: newName.trim() });
35560
+ }
35561
+ } else {
35562
+ helpers.render();
35563
+ }
35564
+ });
35565
+ return true;
35566
+ }
35567
+ if (key === "p" || key === "P") {
35568
+ helpers.getInput("Speak text:").then((text) => {
35569
+ if (text !== null && text.trim()) {
35570
+ const prevMsg = ctx.voiceSetActiveClone?.(item.key);
35571
+ if (prevMsg)
35572
+ renderInfo(prevMsg);
35573
+ ctx.voiceSpeak?.(text.trim());
35574
+ }
35575
+ helpers.render();
35576
+ });
35577
+ return true;
35578
+ }
35579
+ return false;
35580
+ }
35581
+ });
35582
+ if (result.confirmed && result.key) {
35583
+ const msg = ctx.voiceSetActiveClone?.(result.key);
35584
+ if (msg)
35585
+ renderInfo(msg);
35586
+ }
35587
+ }
35421
35588
  async function handleEndpoint(arg, ctx, local = false) {
35422
35589
  if (!arg) {
35423
35590
  const history = loadUsageHistory("endpoint", ctx.repoRoot);
@@ -35437,6 +35604,7 @@ async function handleEndpoint(arg, ctx, local = false) {
35437
35604
  activeKey: ctx.config.backendUrl,
35438
35605
  title: "Select Endpoint",
35439
35606
  rl: ctx.rl,
35607
+ availableRows: ctx.availableContentRows?.(),
35440
35608
  onDelete: (item, done) => {
35441
35609
  deleteUsageRecord("endpoint", item.key, ctx.repoRoot);
35442
35610
  done(true);
@@ -37969,7 +38137,7 @@ var init_carousel_descriptors = __esm({
37969
38137
  });
37970
38138
 
37971
38139
  // packages/cli/dist/tui/voice.js
37972
- import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync14, readFileSync as readFileSync25, unlinkSync as unlinkSync5 } from "node:fs";
38140
+ import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync14, readFileSync as readFileSync25, unlinkSync as unlinkSync5, readdirSync as readdirSync11, renameSync, statSync as statSync10 } from "node:fs";
37973
38141
  import { join as join43 } from "node:path";
37974
38142
  import { homedir as homedir12, tmpdir as tmpdir6, platform as platform3 } from "node:os";
37975
38143
  import { execSync as execSync27, spawn as nodeSpawn } from "node:child_process";
@@ -38704,7 +38872,7 @@ var init_voice = __esm({
38704
38872
  backend: "luxtts"
38705
38873
  }
38706
38874
  };
38707
- VoiceEngine = class {
38875
+ VoiceEngine = class _VoiceEngine {
38708
38876
  enabled = false;
38709
38877
  modelId = "glados";
38710
38878
  ready = false;
@@ -38909,6 +39077,93 @@ var init_voice = __esm({
38909
39077
  this.config = prevConfig;
38910
39078
  }
38911
39079
  }
39080
+ // -------------------------------------------------------------------------
39081
+ // Clone reference management — list / delete / rename / metadata
39082
+ // -------------------------------------------------------------------------
39083
+ /** Metadata file for friendly names of clone refs */
39084
+ static cloneMetaFile() {
39085
+ return join43(luxttsCloneRefsDir(), "meta.json");
39086
+ }
39087
+ loadCloneMeta() {
39088
+ const p = _VoiceEngine.cloneMetaFile();
39089
+ if (!existsSync34(p))
39090
+ return {};
39091
+ try {
39092
+ return JSON.parse(readFileSync25(p, "utf8"));
39093
+ } catch {
39094
+ return {};
39095
+ }
39096
+ }
39097
+ saveCloneMeta(meta) {
39098
+ const dir = luxttsCloneRefsDir();
39099
+ if (!existsSync34(dir))
39100
+ mkdirSync14(dir, { recursive: true });
39101
+ writeFileSync14(_VoiceEngine.cloneMetaFile(), JSON.stringify(meta, null, 2));
39102
+ }
39103
+ /** Audio file extensions recognized as clone references */
39104
+ static AUDIO_EXTS = /* @__PURE__ */ new Set(["wav", "mp3", "ogg", "flac", "m4a", "opus", "aac"]);
39105
+ /**
39106
+ * List all clone reference audio files with metadata.
39107
+ * Returns array of { filename, path, name, size, isActive }.
39108
+ */
39109
+ listCloneRefs() {
39110
+ const dir = luxttsCloneRefsDir();
39111
+ if (!existsSync34(dir))
39112
+ return [];
39113
+ const meta = this.loadCloneMeta();
39114
+ const files = readdirSync11(dir).filter((f) => {
39115
+ const ext = f.split(".").pop()?.toLowerCase() ?? "";
39116
+ return _VoiceEngine.AUDIO_EXTS.has(ext);
39117
+ });
39118
+ return files.map((f) => {
39119
+ const p = join43(dir, f);
39120
+ let size = 0;
39121
+ try {
39122
+ size = statSync10(p).size;
39123
+ } catch {
39124
+ }
39125
+ return {
39126
+ filename: f,
39127
+ path: p,
39128
+ name: meta[f] ?? f.replace(/\.[^.]+$/, "").replace(/[-_]/g, " "),
39129
+ size,
39130
+ isActive: this.luxttsCloneRef === p
39131
+ };
39132
+ });
39133
+ }
39134
+ /** Delete a clone reference file by filename. Returns true if deleted. */
39135
+ deleteCloneRef(filename) {
39136
+ const p = join43(luxttsCloneRefsDir(), filename);
39137
+ if (!existsSync34(p))
39138
+ return false;
39139
+ try {
39140
+ unlinkSync5(p);
39141
+ const meta = this.loadCloneMeta();
39142
+ delete meta[filename];
39143
+ this.saveCloneMeta(meta);
39144
+ if (this.luxttsCloneRef === p) {
39145
+ this.luxttsCloneRef = null;
39146
+ this.autoDetectCloneRef();
39147
+ }
39148
+ return true;
39149
+ } catch {
39150
+ return false;
39151
+ }
39152
+ }
39153
+ /** Rename a clone reference's friendly name (stored in meta.json). */
39154
+ renameCloneRef(filename, newName) {
39155
+ const meta = this.loadCloneMeta();
39156
+ meta[filename] = newName;
39157
+ this.saveCloneMeta(meta);
39158
+ }
39159
+ /** Set the active clone reference by filename. */
39160
+ setActiveCloneRef(filename) {
39161
+ const p = join43(luxttsCloneRefsDir(), filename);
39162
+ if (!existsSync34(p))
39163
+ return `File not found: ${filename}`;
39164
+ this.luxttsCloneRef = p;
39165
+ return `Active clone voice set to: ${filename}`;
39166
+ }
38912
39167
  /**
38913
39168
  * Speak text asynchronously (non-blocking) at full volume.
38914
39169
  * Long text is chunked on sentence/line boundaries for reliable TTS.
@@ -40861,7 +41116,7 @@ var init_promptLoader3 = __esm({
40861
41116
  });
40862
41117
 
40863
41118
  // packages/cli/dist/tui/dream-engine.js
40864
- import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync15, readFileSync as readFileSync27, existsSync as existsSync36, cpSync, rmSync, readdirSync as readdirSync11 } from "node:fs";
41119
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync15, readFileSync as readFileSync27, existsSync as existsSync36, cpSync, rmSync, readdirSync as readdirSync12 } from "node:fs";
40865
41120
  import { join as join46, basename as basename12 } from "node:path";
40866
41121
  import { execSync as execSync28 } from "node:child_process";
40867
41122
  function loadAutoresearchMemory(repoRoot) {
@@ -42067,7 +42322,7 @@ Each proposal includes implementation entrypoints and estimated effort.
42067
42322
  /** Update the master proposal index */
42068
42323
  updateProposalIndex() {
42069
42324
  try {
42070
- const files = readdirSync11(this.dreamsDir).filter((f) => f.endsWith(".md") && f !== "PROPOSAL-INDEX.md" && f !== "dream-state.json").sort();
42325
+ const files = readdirSync12(this.dreamsDir).filter((f) => f.endsWith(".md") && f !== "PROPOSAL-INDEX.md" && f !== "dream-state.json").sort();
42071
42326
  const index = `# Dream Proposals Index
42072
42327
 
42073
42328
  **Last updated**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -42469,7 +42724,7 @@ var init_bless_engine = __esm({
42469
42724
  });
42470
42725
 
42471
42726
  // packages/cli/dist/tui/dmn-engine.js
42472
- import { existsSync as existsSync37, readFileSync as readFileSync28, writeFileSync as writeFileSync16, mkdirSync as mkdirSync17, readdirSync as readdirSync12, unlinkSync as unlinkSync6 } from "node:fs";
42727
+ import { existsSync as existsSync37, readFileSync as readFileSync28, writeFileSync as writeFileSync16, mkdirSync as mkdirSync17, readdirSync as readdirSync13, unlinkSync as unlinkSync6 } from "node:fs";
42473
42728
  import { join as join47, basename as basename13 } from "node:path";
42474
42729
  function buildDMNGatherPrompt(recentTaskSummaries, dueReminders, attentionItems, memoryTopics, capabilities, competence, reflectionBuffer) {
42475
42730
  const competenceReport = competence.length > 0 ? competence.map((c3) => {
@@ -43181,7 +43436,7 @@ OUTPUT: Call task_complete with JSON:
43181
43436
  if (!existsSync37(dir))
43182
43437
  continue;
43183
43438
  try {
43184
- const files = readdirSync12(dir).filter((f) => f.endsWith(".json"));
43439
+ const files = readdirSync13(dir).filter((f) => f.endsWith(".json"));
43185
43440
  for (const f of files) {
43186
43441
  const topic = basename13(f, ".json");
43187
43442
  if (!topics.includes(topic))
@@ -43212,7 +43467,7 @@ OUTPUT: Call task_complete with JSON:
43212
43467
  try {
43213
43468
  const filename = `cycle-${result.cycleNumber}-${Date.now()}.json`;
43214
43469
  writeFileSync16(join47(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
43215
- const files = readdirSync12(this.historyDir).filter((f) => f.startsWith("cycle-") && f.endsWith(".json")).sort();
43470
+ const files = readdirSync13(this.historyDir).filter((f) => f.startsWith("cycle-") && f.endsWith(".json")).sort();
43216
43471
  if (files.length > 50) {
43217
43472
  for (const old of files.slice(0, files.length - 50)) {
43218
43473
  try {
@@ -43229,7 +43484,7 @@ OUTPUT: Call task_complete with JSON:
43229
43484
  });
43230
43485
 
43231
43486
  // packages/cli/dist/tui/snr-engine.js
43232
- import { existsSync as existsSync38, readdirSync as readdirSync13, readFileSync as readFileSync29 } from "node:fs";
43487
+ import { existsSync as existsSync38, readdirSync as readdirSync14, readFileSync as readFileSync29 } from "node:fs";
43233
43488
  import { join as join48, basename as basename14 } from "node:path";
43234
43489
  function computeDPrime(signalScores, noiseScores) {
43235
43490
  if (signalScores.length === 0 || noiseScores.length === 0)
@@ -43477,7 +43732,7 @@ Call task_complete with the JSON array when done.`, onEvent)
43477
43732
  if (!existsSync38(dir))
43478
43733
  continue;
43479
43734
  try {
43480
- const files = readdirSync13(dir).filter((f) => f.endsWith(".json"));
43735
+ const files = readdirSync14(dir).filter((f) => f.endsWith(".json"));
43481
43736
  for (const f of files) {
43482
43737
  const topic = basename14(f, ".json");
43483
43738
  if (topics.length > 0 && !topics.includes(topic))
@@ -44050,7 +44305,7 @@ var init_tool_policy = __esm({
44050
44305
  });
44051
44306
 
44052
44307
  // packages/cli/dist/tui/telegram-bridge.js
44053
- import { mkdirSync as mkdirSync18, existsSync as existsSync39, unlinkSync as unlinkSync7, readdirSync as readdirSync14, statSync as statSync10 } from "node:fs";
44308
+ import { mkdirSync as mkdirSync18, existsSync as existsSync39, unlinkSync as unlinkSync7, readdirSync as readdirSync15, statSync as statSync11 } from "node:fs";
44054
44309
  import { join as join49, resolve as resolve27 } from "node:path";
44055
44310
  import { writeFile as writeFileAsync } from "node:fs/promises";
44056
44311
  function convertMarkdownToTelegramHTML(md) {
@@ -46128,6 +46383,20 @@ var init_status_bar = __esm({
46128
46383
  get reservedRows() {
46129
46384
  return this._currentFooterHeight;
46130
46385
  }
46386
+ /**
46387
+ * Usable content area height — the rows available for scroll content,
46388
+ * model lists, dashboards, etc. Accounts for:
46389
+ * - Header/carousel rows (scrollRegionTop)
46390
+ * - Footer rows (buffer + top separator + input lines + bottom separator + metrics)
46391
+ *
46392
+ * This is the accurate "how many rows can I draw in?" value that all
46393
+ * overlay UIs (tuiSelect, /expose dashboard, etc.) should use.
46394
+ */
46395
+ get availableContentRows() {
46396
+ const rows = process.stdout.rows ?? 24;
46397
+ const usable = rows - (this.scrollRegionTop - 1) - this._currentFooterHeight;
46398
+ return Math.max(3, usable);
46399
+ }
46131
46400
  /** Handle terminal resize — debounced to prevent separator stacking during drag */
46132
46401
  handleResize() {
46133
46402
  if (!this.active)
@@ -46799,7 +47068,7 @@ import { cwd } from "node:process";
46799
47068
  import { resolve as resolve28, join as join50, dirname as dirname18, extname as extname9 } from "node:path";
46800
47069
  import { createRequire as createRequire2 } from "node:module";
46801
47070
  import { fileURLToPath as fileURLToPath12 } from "node:url";
46802
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync17, appendFileSync as appendFileSync3, rmSync as rmSync2, readdirSync as readdirSync15, mkdirSync as mkdirSync19 } from "node:fs";
47071
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync17, appendFileSync as appendFileSync3, rmSync as rmSync2, readdirSync as readdirSync16, mkdirSync as mkdirSync19 } from "node:fs";
46803
47072
  import { existsSync as existsSync40 } from "node:fs";
46804
47073
  import { homedir as homedir13 } from "node:os";
46805
47074
  function formatTimeAgo(date) {
@@ -47039,7 +47308,7 @@ function gatherMemorySnippets(root) {
47039
47308
  if (!existsSync40(dir))
47040
47309
  continue;
47041
47310
  try {
47042
- for (const f of readdirSync15(dir).filter((f2) => f2.endsWith(".json"))) {
47311
+ for (const f of readdirSync16(dir).filter((f2) => f2.endsWith(".json"))) {
47043
47312
  const data = JSON.parse(readFileSync30(join50(dir, f), "utf-8"));
47044
47313
  for (const val of Object.values(data)) {
47045
47314
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
@@ -48338,6 +48607,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
48338
48607
  items,
48339
48608
  title: "Select one or more (Space to toggle, Enter to confirm)",
48340
48609
  rl,
48610
+ availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0,
48341
48611
  renderRow: (item, focused, _isActive) => {
48342
48612
  const isSelected = selected.has(item.key);
48343
48613
  const marker = isSelected ? c2.green("\u2611") : focused ? c2.cyan("\u2610") : c2.dim("\u2610");
@@ -48369,7 +48639,8 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
48369
48639
  const result = await tuiSelect({
48370
48640
  items,
48371
48641
  title: "Select one option",
48372
- rl
48642
+ rl,
48643
+ availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0
48373
48644
  });
48374
48645
  if (statusBar?.isActive)
48375
48646
  statusBar.endContentWrite();
@@ -48483,6 +48754,21 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
48483
48754
  async voiceGenerateCloneRef(sourceModelId) {
48484
48755
  return voiceEngine.generateCloneRef(sourceModelId);
48485
48756
  },
48757
+ voiceListClones() {
48758
+ return voiceEngine.listCloneRefs();
48759
+ },
48760
+ voiceDeleteClone(filename) {
48761
+ return voiceEngine.deleteCloneRef(filename);
48762
+ },
48763
+ voiceRenameClone(filename, newName) {
48764
+ voiceEngine.renameCloneRef(filename, newName);
48765
+ },
48766
+ voiceSetActiveClone(filename) {
48767
+ return voiceEngine.setActiveCloneRef(filename);
48768
+ },
48769
+ voiceSpeak(text) {
48770
+ voiceEngine.speak(text);
48771
+ },
48486
48772
  streamToggle() {
48487
48773
  streamEnabled = !streamEnabled;
48488
48774
  return streamEnabled;
@@ -49327,6 +49613,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
49327
49613
  }, 100);
49328
49614
  return true;
49329
49615
  },
49616
+ availableContentRows() {
49617
+ return statusBar.isActive ? statusBar.availableContentRows : Math.max(3, (process.stdout.rows ?? 24) - 6);
49618
+ },
49330
49619
  destroyProject() {
49331
49620
  const oaPath = join50(repoRoot, OA_DIR);
49332
49621
  if (existsSync40(oaPath)) {
@@ -49395,7 +49684,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
49395
49684
  ],
49396
49685
  activeKey: "restore",
49397
49686
  title: "Restore previous session context?",
49398
- rl
49687
+ rl,
49688
+ availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0
49399
49689
  });
49400
49690
  if (autoRestoreTimer)
49401
49691
  clearTimeout(autoRestoreTimer);
@@ -50426,7 +50716,7 @@ __export(index_repo_exports, {
50426
50716
  indexRepoCommand: () => indexRepoCommand
50427
50717
  });
50428
50718
  import { resolve as resolve29 } from "node:path";
50429
- import { existsSync as existsSync41, statSync as statSync11 } from "node:fs";
50719
+ import { existsSync as existsSync41, statSync as statSync12 } from "node:fs";
50430
50720
  import { cwd as cwd2 } from "node:process";
50431
50721
  async function indexRepoCommand(opts, _config) {
50432
50722
  const repoRoot = resolve29(opts.repoPath ?? cwd2());
@@ -50436,7 +50726,7 @@ async function indexRepoCommand(opts, _config) {
50436
50726
  printError(`Path does not exist: ${repoRoot}`);
50437
50727
  process.exit(1);
50438
50728
  }
50439
- const stat5 = statSync11(repoRoot);
50729
+ const stat5 = statSync12(repoRoot);
50440
50730
  if (!stat5.isDirectory()) {
50441
50731
  printError(`Path is not a directory: ${repoRoot}`);
50442
50732
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.85",
3
+ "version": "0.103.87",
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",