open-agents-ai 0.11.0 → 0.11.2

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 +185 -92
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -302,6 +302,17 @@ function performUpdate() {
302
302
  return false;
303
303
  }
304
304
  }
305
+ function performSilentUpdate() {
306
+ try {
307
+ execSync(`npm install -g ${PACKAGE_NAME}@latest`, {
308
+ stdio: "pipe",
309
+ timeout: 12e4
310
+ });
311
+ return true;
312
+ } catch {
313
+ return false;
314
+ }
315
+ }
305
316
  function restartProcess() {
306
317
  const args = process.argv.slice(1);
307
318
  try {
@@ -1854,15 +1865,26 @@ var init_memory_read = __esm({
1854
1865
  durationMs: performance.now() - start
1855
1866
  };
1856
1867
  }
1868
+ const entry = entries[key];
1869
+ const artifactTag = entry?.artifactId ? ` [artifact: ${entry.artifactId}]` : "";
1857
1870
  return {
1858
1871
  success: true,
1859
- output: JSON.stringify(entries[key], null, 2),
1872
+ output: JSON.stringify(entry, null, 2) + artifactTag,
1860
1873
  durationMs: performance.now() - start
1861
1874
  };
1862
1875
  }
1876
+ const keys = Object.keys(entries);
1877
+ const summary = keys.map((k) => {
1878
+ const e = entries[k];
1879
+ const aid = e?.artifactId ? ` [${e.artifactId}]` : "";
1880
+ return ` ${k}${aid}`;
1881
+ }).join("\n");
1863
1882
  return {
1864
1883
  success: true,
1865
- output: JSON.stringify(entries, null, 2),
1884
+ output: `Topic: ${topic} (${keys.length} entries)
1885
+ ${summary}
1886
+
1887
+ ${JSON.stringify(entries, null, 2)}`,
1866
1888
  durationMs: performance.now() - start
1867
1889
  };
1868
1890
  } catch (error) {
@@ -1881,6 +1903,7 @@ var init_memory_read = __esm({
1881
1903
  // packages/execution/dist/tools/memory-write.js
1882
1904
  import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir2 } from "node:fs/promises";
1883
1905
  import { resolve as resolve7, join as join4 } from "node:path";
1906
+ import { randomBytes } from "node:crypto";
1884
1907
  var MemoryWriteTool;
1885
1908
  var init_memory_write = __esm({
1886
1909
  "packages/execution/dist/tools/memory-write.js"() {
@@ -1927,15 +1950,32 @@ var init_memory_write = __esm({
1927
1950
  entries = JSON.parse(raw);
1928
1951
  } catch {
1929
1952
  }
1953
+ const artifactId = `mem-${randomBytes(6).toString("hex")}`;
1930
1954
  entries[key] = {
1931
1955
  value,
1932
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1956
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1957
+ artifactId
1933
1958
  };
1934
1959
  await writeFile3(topicFile, JSON.stringify(entries, null, 2), "utf-8");
1935
1960
  }
1961
+ const provenanceDir = resolve7(this.workingDir, ".oa", "provenance");
1962
+ try {
1963
+ await mkdir2(provenanceDir, { recursive: true });
1964
+ const provRecord = {
1965
+ type: "memory_write",
1966
+ topic,
1967
+ key,
1968
+ artifactId: `mem-${randomBytes(6).toString("hex")}`,
1969
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1970
+ source: "agent"
1971
+ };
1972
+ const provFile = join4(provenanceDir, `${Date.now()}-memory-write.json`);
1973
+ await writeFile3(provFile, JSON.stringify(provRecord, null, 2), "utf-8");
1974
+ } catch {
1975
+ }
1936
1976
  return {
1937
1977
  success: true,
1938
- output: `Stored memory: ${topic}.${key}`,
1978
+ output: `Stored memory: ${topic}.${key} [artifact: mem-${Date.now().toString(36)}]`,
1939
1979
  durationMs: performance.now() - start
1940
1980
  };
1941
1981
  } catch (error) {
@@ -8632,8 +8672,30 @@ var init_project_context = __esm({
8632
8672
  function fg(code, text) {
8633
8673
  return isTTY3 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
8634
8674
  }
8675
+ function displayWidth(str) {
8676
+ let w = 0;
8677
+ for (const ch of str) {
8678
+ const cp = ch.codePointAt(0);
8679
+ if (cp >= 4352 && cp <= 4447 || // Hangul Jamo
8680
+ cp >= 11904 && cp <= 12350 || // CJK Radicals, Kangxi, CJK Symbols
8681
+ cp >= 12352 && cp <= 13247 || // Hiragana, Katakana, CJK Compat
8682
+ cp >= 13312 && cp <= 19903 || // CJK Ext A
8683
+ cp >= 19968 && cp <= 42191 || // CJK Unified, Yi
8684
+ cp >= 44032 && cp <= 55215 || // Hangul Syllables
8685
+ cp >= 63744 && cp <= 64255 || // CJK Compat Ideographs
8686
+ cp >= 65072 && cp <= 65135 || // CJK Compat Forms
8687
+ cp >= 65281 && cp <= 65376 || // Fullwidth Forms
8688
+ cp >= 65504 && cp <= 65510 || // Fullwidth Signs
8689
+ cp >= 131072 && cp <= 195103) {
8690
+ w += 2;
8691
+ } else {
8692
+ w += 1;
8693
+ }
8694
+ }
8695
+ return w;
8696
+ }
8635
8697
  function buildPlainRibbon(phrases, repeatWidth) {
8636
- const separator = " \xB7 ";
8698
+ const separator = " : ";
8637
8699
  let plain = "";
8638
8700
  while (plain.length < repeatWidth * 3) {
8639
8701
  for (const p of phrases) {
@@ -8669,70 +8731,67 @@ var init_carousel = __esm({
8669
8731
  { text: "imagine freely", color: 219 },
8670
8732
  { text: "liberate creativity", color: 111 },
8671
8733
  // Spanish
8672
- { text: "libertad de informaci\xF3n", color: 214 },
8734
+ { text: "libertad de informacion", color: 214 },
8673
8735
  { text: "crear libremente", color: 208 },
8674
- { text: "c\xF3digo abierto", color: 220 },
8675
- { text: "s\xE9 creativo", color: 226 },
8676
- { text: "imaginaci\xF3n sin l\xEDmites", color: 215 },
8736
+ { text: "codigo abierto", color: 220 },
8737
+ { text: "se creativo", color: 226 },
8738
+ { text: "imaginacion sin limites", color: 215 },
8677
8739
  // French
8678
- { text: "cr\xE9er librement", color: 171 },
8679
- { text: "libert\xE9 d'expression", color: 177 },
8740
+ { text: "creer librement", color: 171 },
8741
+ { text: "liberte d'expression", color: 177 },
8680
8742
  { text: "source ouverte", color: 141 },
8681
8743
  { text: "imaginer sans contrainte", color: 183 },
8682
8744
  // German
8683
8745
  { text: "Freiheit der Muster", color: 77 },
8684
8746
  { text: "frei erschaffen", color: 78 },
8685
8747
  { text: "offene Quelle", color: 114 },
8686
- { text: "grenzenlose Kreativit\xE4t", color: 150 },
8748
+ { text: "grenzenlose Kreativitat", color: 150 },
8687
8749
  // Japanese
8688
- { text: "\u81EA\u7531\u306B\u5275\u9020\u3059\u308B", color: 204 },
8689
- { text: "\u958B\u6E90\u306E\u7CBE\u795E", color: 210 },
8690
- { text: "\u5236\u7D04\u306A\u304D\u60F3\u50CF\u529B", color: 203 },
8691
- { text: "\u77E5\u8B58\u3092\u5171\u6709\u3059\u308B", color: 209 },
8750
+ { text: "jiyuu ni souzou suru", color: 204 },
8751
+ { text: "kaigen no seishin", color: 210 },
8752
+ { text: "seiyaku naki souzouryoku", color: 203 },
8753
+ { text: "chishiki wo kyouyuu", color: 209 },
8692
8754
  // Korean
8693
- { text: "\uC790\uC720\uB85C\uC6B4 \uCC3D\uC791", color: 105 },
8694
- { text: "\uC624\uD508\uC18C\uC2A4 \uC815\uC2E0", color: 99 },
8695
- { text: "\uC601\uAC10\uC744 \uB098\uB204\uB2E4", color: 135 },
8696
- // Chinese
8697
- { text: "\u958B\u6E90\u81EA\u7531", color: 167 },
8698
- { text: "\u81EA\u7531\u5275\u4F5C", color: 173 },
8699
- { text: "\u77E5\u8B58\u5171\u4EAB", color: 161 },
8700
- { text: "\u7121\u9650\u60F3\u50CF", color: 131 },
8755
+ { text: "jayuroun changjak", color: 105 },
8756
+ { text: "opeunsoseu jeongsin", color: 99 },
8757
+ { text: "yeonggam eul nanuda", color: 135 },
8701
8758
  // Russian
8702
- { text: "\u0441\u0432\u043E\u0431\u043E\u0434\u0430 \u0442\u0432\u043E\u0440\u0447\u0435\u0441\u0442\u0432\u0430", color: 73 },
8703
- { text: "\u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0439 \u0438\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u043A\u043E\u0434", color: 67 },
8704
- { text: "\u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0439 \u0441\u0432\u043E\u0431\u043E\u0434\u043D\u043E", color: 109 },
8759
+ { text: "svoboda tvorchestva", color: 73 },
8760
+ { text: "otkrytyy iskhodnyy kod", color: 67 },
8761
+ { text: "sozdavay svobodno", color: 109 },
8705
8762
  // Portuguese
8706
8763
  { text: "liberdade de criar", color: 179 },
8707
- { text: "c\xF3digo aberto", color: 185 },
8708
- { text: "imagina\xE7\xE3o sem fronteiras", color: 186 },
8764
+ { text: "codigo aberto", color: 185 },
8765
+ { text: "imaginacao sem fronteiras", color: 186 },
8709
8766
  // Italian
8710
8767
  { text: "creare liberamente", color: 144 },
8711
- { text: "libert\xE0 di espressione", color: 180 },
8712
- // Hindi
8713
- { text: "\u0916\u0941\u0932\u0940 \u0938\u094B\u091A", color: 198 },
8714
- { text: "\u092E\u0941\u0915\u094D\u0924 \u0930\u091A\u0928\u093E", color: 199 },
8715
- // Arabic
8716
- { text: "\u062D\u0631\u064A\u0629 \u0627\u0644\u0625\u0628\u062F\u0627\u0639", color: 222 },
8717
- { text: "\u0645\u0635\u062F\u0631 \u0645\u0641\u062A\u0648\u062D", color: 228 },
8768
+ { text: "liberta di espressione", color: 180 },
8718
8769
  // Turkish
8719
- { text: "\xF6zg\xFCrce yarat", color: 156 },
8720
- { text: "a\xE7\u0131k kaynak", color: 192 },
8770
+ { text: "ozgurce yarat", color: 156 },
8771
+ { text: "acik kaynak", color: 192 },
8721
8772
  // Swedish
8722
8773
  { text: "skapa fritt", color: 116 },
8723
- { text: "\xF6ppen k\xE4llkod", color: 122 },
8774
+ { text: "oppen kallkod", color: 122 },
8724
8775
  // Dutch
8725
- { text: "vrij cre\xEBren", color: 152 },
8776
+ { text: "vrij creeren", color: 152 },
8726
8777
  // Polish
8727
- { text: "tw\xF3rz swobodnie", color: 188 },
8778
+ { text: "tworz swobodnie", color: 188 },
8728
8779
  // Greek
8729
- { text: "\u03B4\u03B7\u03BC\u03B9\u03BF\u03CD\u03C1\u03B3\u03B7\u03C3\u03B5 \u03B5\u03BB\u03B5\u03CD\u03B8\u03B5\u03C1\u03B1", color: 75 }
8780
+ { text: "dimiourgia elefthera", color: 75 },
8781
+ // Hindi
8782
+ { text: "khuli soch", color: 198 },
8783
+ { text: "mukt rachna", color: 199 },
8784
+ // Arabic
8785
+ { text: "hurriyat al-ibdaa", color: 222 },
8786
+ { text: "masdar maftuh", color: 228 }
8730
8787
  ];
8731
8788
  Carousel = class {
8732
8789
  rows;
8733
8790
  timer = null;
8734
8791
  width;
8735
8792
  lineCount = 3;
8793
+ /** Total rows reserved at top: 3 carousel + 1 blank separator */
8794
+ reservedRows = 4;
8736
8795
  started = false;
8737
8796
  resizeHandler = null;
8738
8797
  constructor() {
@@ -8742,11 +8801,8 @@ var init_carousel = __esm({
8742
8801
  const indices2 = Array.from({ length: PHRASES.length }, (_, i) => i).sort(() => Math.random() - 0.5);
8743
8802
  this.rows = [
8744
8803
  createRow(indices0, 2, -1),
8745
- // fast left
8746
8804
  createRow(indices1, 1, 1),
8747
- // medium right
8748
8805
  createRow(indices2, 1.5, -1)
8749
- // slow-medium left
8750
8806
  ];
8751
8807
  this.rebuildRibbons();
8752
8808
  }
@@ -8757,13 +8813,8 @@ var init_carousel = __esm({
8757
8813
  }
8758
8814
  /**
8759
8815
  * Start the animation.
8760
- *
8761
- * 1. Writes 3 empty lines to reserve space
8762
- * 2. Sets DECSTBM scroll region to row 4+ (everything below carousel)
8763
- * 3. Moves cursor into the scroll region
8764
- * 4. Starts animation timer that writes ONLY to rows 1-3
8765
- *
8766
- * The cursor never leaves the scroll region, so readline works perfectly.
8816
+ * Reserves rows 1-3 for carousel, row 4 as blank separator.
8817
+ * Sets scroll region to row 5+ for all content/readline.
8767
8818
  */
8768
8819
  start() {
8769
8820
  if (!isTTY3)
@@ -8771,17 +8822,17 @@ var init_carousel = __esm({
8771
8822
  this.started = true;
8772
8823
  const termRows = process.stdout.rows ?? 24;
8773
8824
  process.stdout.write("\x1B[1;1H");
8774
- for (let i = 0; i < this.lineCount; i++) {
8825
+ for (let i = 0; i < this.reservedRows; i++) {
8775
8826
  process.stdout.write("\x1B[2K\n");
8776
8827
  }
8777
- process.stdout.write(`\x1B[${this.lineCount + 1};${termRows}r`);
8778
- process.stdout.write(`\x1B[${this.lineCount + 1};1H`);
8828
+ process.stdout.write(`\x1B[${this.reservedRows + 1};${termRows}r`);
8829
+ process.stdout.write(`\x1B[${this.reservedRows + 1};1H`);
8779
8830
  this.resizeHandler = () => {
8780
8831
  this.width = process.stdout.columns ?? 80;
8781
8832
  const newRows = process.stdout.rows ?? 24;
8782
8833
  this.rebuildRibbons();
8783
8834
  if (this.started) {
8784
- process.stdout.write(`\x1B[${this.lineCount + 1};${newRows}r`);
8835
+ process.stdout.write(`\x1B[${this.reservedRows + 1};${newRows}r`);
8785
8836
  }
8786
8837
  };
8787
8838
  process.stdout.on("resize", this.resizeHandler);
@@ -8795,40 +8846,41 @@ var init_carousel = __esm({
8795
8846
  }
8796
8847
  this.renderFrame();
8797
8848
  }, 66);
8798
- return this.lineCount;
8849
+ return this.reservedRows;
8799
8850
  }
8800
8851
  /**
8801
- * Render one animation frame.
8802
- *
8803
- * Uses save/restore cursor (DECSC/DECRC) to briefly visit rows 1-3,
8804
- * then return. Because the scroll region is set to row 4+, the cursor
8805
- * restore puts it back exactly where readline expects it.
8852
+ * Render one animation frame into rows 1-3 only.
8853
+ * Row 4 is left blank as a separator.
8806
8854
  */
8807
8855
  renderFrame() {
8808
8856
  if (!isTTY3)
8809
8857
  return;
8810
8858
  let buf = "\x1B7";
8859
+ buf += "\x1B[?7l";
8811
8860
  for (let i = 0; i < this.rows.length; i++) {
8812
8861
  const line = this.extractWindow(this.rows[i]);
8813
8862
  buf += `\x1B[${i + 1};1H\x1B[2K${line}`;
8814
8863
  }
8864
+ buf += `\x1B[4;1H\x1B[2K`;
8865
+ buf += "\x1B[?7h";
8815
8866
  buf += "\x1B8";
8816
8867
  process.stdout.write(buf);
8817
8868
  }
8818
8869
  /**
8819
8870
  * Extract a terminal-width colored window from a scrolling ribbon.
8871
+ * Uses column-aware width to prevent CJK/fullwidth character overflow.
8820
8872
  */
8821
8873
  extractWindow(row) {
8822
- const w = this.width;
8874
+ const maxCols = this.width;
8823
8875
  const plain = row.renderedPlain;
8824
8876
  if (!plain)
8825
8877
  return "";
8826
8878
  let start = Math.floor(Math.abs(row.offset)) % plain.length;
8827
8879
  if (start < 0)
8828
8880
  start += plain.length;
8829
- const separator = " \xB7 ";
8881
+ const separator = " : ";
8830
8882
  let coloredLine = "";
8831
- let charCount = 0;
8883
+ let colCount = 0;
8832
8884
  let charInPhrase = 0;
8833
8885
  let skipChars = start;
8834
8886
  const phrases = row.phrases;
@@ -8843,20 +8895,25 @@ var init_carousel = __esm({
8843
8895
  skipChars -= fullText.length;
8844
8896
  fullIdx++;
8845
8897
  }
8846
- while (charCount < w) {
8898
+ while (colCount < maxCols) {
8847
8899
  const p = phrases[fullIdx % phrases.length];
8848
8900
  const fullText = p.text + separator;
8849
8901
  const remaining = fullText.slice(charInPhrase);
8850
8902
  for (const ch of remaining) {
8851
- if (charCount >= w)
8903
+ const chWidth = displayWidth(ch);
8904
+ if (colCount + chWidth > maxCols) {
8905
+ if (colCount < maxCols)
8906
+ coloredLine += " ";
8907
+ colCount = maxCols;
8852
8908
  break;
8909
+ }
8853
8910
  const inPhrase = charInPhrase < p.text.length;
8854
8911
  if (inPhrase) {
8855
8912
  coloredLine += fg(p.color, ch);
8856
8913
  } else {
8857
8914
  coloredLine += `\x1B[2m${ch}\x1B[0m`;
8858
8915
  }
8859
- charCount++;
8916
+ colCount += chWidth;
8860
8917
  charInPhrase++;
8861
8918
  }
8862
8919
  fullIdx++;
@@ -8865,7 +8922,7 @@ var init_carousel = __esm({
8865
8922
  return coloredLine;
8866
8923
  }
8867
8924
  /**
8868
- * Stop the animation, clear the carousel lines, and reset scroll region.
8925
+ * Stop the animation, clear rows 1-4, reset scroll region.
8869
8926
  */
8870
8927
  stop() {
8871
8928
  if (this.timer) {
@@ -8879,7 +8936,7 @@ var init_carousel = __esm({
8879
8936
  if (!isTTY3 || !this.started)
8880
8937
  return;
8881
8938
  let buf = "\x1B7";
8882
- for (let i = 0; i < this.lineCount; i++) {
8939
+ for (let i = 0; i < this.reservedRows; i++) {
8883
8940
  buf += `\x1B[${i + 1};1H\x1B[2K`;
8884
8941
  }
8885
8942
  buf += "\x1B[r";
@@ -8887,7 +8944,6 @@ var init_carousel = __esm({
8887
8944
  process.stdout.write(buf);
8888
8945
  this.started = false;
8889
8946
  }
8890
- /** Check if carousel is running */
8891
8947
  get isRunning() {
8892
8948
  return this.timer !== null;
8893
8949
  }
@@ -9666,6 +9722,10 @@ function startTask(task, config, repoRoot, voice) {
9666
9722
  }
9667
9723
  async function startInteractive(config, repoPath) {
9668
9724
  const repoRoot = resolve11(repoPath ?? cwd());
9725
+ const isResumed = !!process.env.__OA_RESUMED;
9726
+ if (isResumed) {
9727
+ delete process.env.__OA_RESUMED;
9728
+ }
9669
9729
  initOaDirectory(repoRoot);
9670
9730
  const savedSettings = resolveSettings(repoRoot);
9671
9731
  if (savedSettings.model)
@@ -9679,30 +9739,37 @@ async function startInteractive(config, repoPath) {
9679
9739
  config = { ...config, apiKey: savedSettings.apiKey };
9680
9740
  if (savedSettings.verbose !== void 0)
9681
9741
  config = { ...config, verbose: savedSettings.verbose };
9682
- const needsSetup = isFirstRun() || !await isModelAvailable(config);
9683
- if (needsSetup && config.backendType === "ollama") {
9684
- const setupModel = await runSetupWizard(config);
9685
- if (setupModel === null) {
9686
- process.exit(0);
9742
+ if (!isResumed) {
9743
+ const needsSetup = isFirstRun() || !await isModelAvailable(config);
9744
+ if (needsSetup && config.backendType === "ollama") {
9745
+ const setupModel = await runSetupWizard(config);
9746
+ if (setupModel === null) {
9747
+ process.exit(0);
9748
+ }
9749
+ config = { ...config, model: setupModel };
9687
9750
  }
9688
- config = { ...config, model: setupModel };
9689
9751
  }
9690
- try {
9691
- const healthUrl = config.backendType === "ollama" ? `${config.backendUrl}/api/tags` : `${config.backendUrl}/v1/models`;
9692
- const resp = await fetch(healthUrl, { signal: AbortSignal.timeout(1e4) });
9693
- if (!resp.ok)
9694
- throw new Error(`HTTP ${resp.status}`);
9695
- } catch {
9696
- renderError(`Cannot reach ${config.backendType} at ${config.backendUrl}`);
9697
- if (config.backendType === "ollama") {
9698
- renderInfo("Start Ollama with: ollama serve");
9752
+ if (!isResumed) {
9753
+ try {
9754
+ const healthUrl = config.backendType === "ollama" ? `${config.backendUrl}/api/tags` : `${config.backendUrl}/v1/models`;
9755
+ const resp = await fetch(healthUrl, { signal: AbortSignal.timeout(1e4) });
9756
+ if (!resp.ok)
9757
+ throw new Error(`HTTP ${resp.status}`);
9758
+ } catch {
9759
+ renderError(`Cannot reach ${config.backendType} at ${config.backendUrl}`);
9760
+ if (config.backendType === "ollama") {
9761
+ renderInfo("Start Ollama with: ollama serve");
9762
+ }
9763
+ renderInfo("Use /endpoint to configure a different backend.");
9764
+ process.exit(1);
9699
9765
  }
9700
- renderInfo("Use /endpoint to configure a different backend.");
9701
- process.exit(1);
9702
9766
  }
9703
9767
  process.stdout.write("\x1B[2J\x1B[H");
9704
9768
  const carousel = new Carousel();
9705
- const carouselLines = carousel.start();
9769
+ let carouselLines = 0;
9770
+ if (!isResumed) {
9771
+ carouselLines = carousel.start();
9772
+ }
9706
9773
  const version = getVersion();
9707
9774
  renderRichHeader({
9708
9775
  model: config.model,
@@ -9710,6 +9777,10 @@ async function startInteractive(config, repoPath) {
9710
9777
  workspace: repoRoot,
9711
9778
  carouselLines
9712
9779
  });
9780
+ if (isResumed) {
9781
+ renderInfo(`Auto-updated to v${version} \u2014 session resumed.
9782
+ `);
9783
+ }
9713
9784
  const voiceEngine = new VoiceEngine();
9714
9785
  if (savedSettings.voice) {
9715
9786
  voiceEngine.toggle().catch(() => {
@@ -9722,7 +9793,7 @@ async function startInteractive(config, repoPath) {
9722
9793
  let currentConfig = { ...config };
9723
9794
  let activeTask = null;
9724
9795
  let messageQueue = [];
9725
- let carouselRetired = false;
9796
+ let carouselRetired = isResumed;
9726
9797
  const idlePrompt = `${c2.bold(c2.blue("> "))}`;
9727
9798
  const activePrompt = `${c2.dim(c2.cyan("+ "))}`;
9728
9799
  const rl = readline2.createInterface({
@@ -9735,8 +9806,9 @@ async function startInteractive(config, repoPath) {
9735
9806
  process.stdout.on("resize", () => {
9736
9807
  if (!carouselRetired) {
9737
9808
  const termRows = process.stdout.rows ?? 24;
9738
- process.stdout.write(`\x1B[${carouselLines + 1};${termRows}r`);
9739
- process.stdout.write(`\x1B[${carouselLines + 1};1H\x1B[J`);
9809
+ const scrollStart = carousel.reservedRows + 1;
9810
+ process.stdout.write(`\x1B[${scrollStart};${termRows}r`);
9811
+ process.stdout.write(`\x1B[${scrollStart};1H\x1B[J`);
9740
9812
  renderRichHeader({
9741
9813
  model: currentConfig.model,
9742
9814
  version,
@@ -9863,6 +9935,26 @@ ${c2.dim("Goodbye!")}
9863
9935
  } finally {
9864
9936
  activeTask = null;
9865
9937
  }
9938
+ try {
9939
+ const updateInfo = await checkForUpdate(version);
9940
+ if (updateInfo) {
9941
+ renderInfo(`Update available: v${version} \u2192 v${updateInfo.latestVersion}. Installing...`);
9942
+ const ok = performSilentUpdate();
9943
+ if (ok) {
9944
+ renderInfo(`Updated to v${updateInfo.latestVersion}. Reloading...
9945
+ `);
9946
+ process.env.__OA_RESUMED = "1";
9947
+ if (carousel.isRunning)
9948
+ carousel.stop();
9949
+ voiceEngine.dispose();
9950
+ rl.close();
9951
+ restartProcess();
9952
+ } else {
9953
+ renderWarning("Auto-update failed. Use /update to retry manually.");
9954
+ }
9955
+ }
9956
+ } catch {
9957
+ }
9866
9958
  showPrompt();
9867
9959
  });
9868
9960
  rl.on("close", () => {
@@ -9922,6 +10014,7 @@ var init_interactive = __esm({
9922
10014
  "use strict";
9923
10015
  init_dist5();
9924
10016
  init_dist2();
10017
+ init_updater();
9925
10018
  init_commands();
9926
10019
  init_setup();
9927
10020
  init_project_context();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
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",