open-agents-ai 0.30.3 → 0.30.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -105,7 +105,7 @@ var init_config = __esm({
105
105
  "packages/cli/dist/config.js"() {
106
106
  "use strict";
107
107
  DEFAULT_CONFIG = Object.freeze({
108
- backendUrl: "http://localhost:11434",
108
+ backendUrl: "http://127.0.0.1:11434",
109
109
  model: "qwen3.5:latest",
110
110
  backendType: "ollama",
111
111
  apiKey: "",
@@ -6757,7 +6757,7 @@ Coordinates are normalized (0-1). Multiply by image width/height for pixel value
6757
6757
  }
6758
6758
  }
6759
6759
  async tryOllamaVision(buffer, filename, action, prompt, length, start) {
6760
- const ollamaHost = process.env["OLLAMA_HOST"] || "http://localhost:11434";
6760
+ const ollamaHost = process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
6761
6761
  const envModel = process.env["OLLAMA_VISION_MODEL"];
6762
6762
  const model = envModel || (this._activeModelHasVision && this._activeModel ? this._activeModel : "moondream");
6763
6763
  const imageBase64 = buffer.toString("base64");
@@ -7079,7 +7079,7 @@ var init_desktop_click = __esm({
7079
7079
  }
7080
7080
  if (!visionWorked) {
7081
7081
  try {
7082
- const ollamaHost = process.env["OLLAMA_HOST"] || "http://localhost:11434";
7082
+ const ollamaHost = process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
7083
7083
  const envModel = process.env["OLLAMA_VISION_MODEL"];
7084
7084
  const ollamaModel = envModel || (this._activeModelHasVision && this._activeModel ? this._activeModel : "moondream");
7085
7085
  const imageBase64 = readFileSync11(screenshotPath).toString("base64");
@@ -7253,7 +7253,7 @@ ${caption}`);
7253
7253
  }
7254
7254
  if (!visionWorked) {
7255
7255
  try {
7256
- const ollamaHost = process.env["OLLAMA_HOST"] || "http://localhost:11434";
7256
+ const ollamaHost = process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
7257
7257
  const envModel = process.env["OLLAMA_VISION_MODEL"];
7258
7258
  const ollamaModel = envModel || (this._activeModelHasVision && this._activeModel ? this._activeModel : "moondream");
7259
7259
  const imageBase64 = imageBuffer.toString("base64");
@@ -10343,6 +10343,8 @@ Rules:
10343
10343
  handlers = [];
10344
10344
  pendingUserMessages = [];
10345
10345
  aborted = false;
10346
+ _paused = false;
10347
+ _pauseResolve = null;
10346
10348
  _sudoPassword = null;
10347
10349
  _sudoResolve = null;
10348
10350
  constructor(backend, options) {
@@ -10388,6 +10390,50 @@ Rules:
10388
10390
  /** Abort the current task run */
10389
10391
  abort() {
10390
10392
  this.aborted = true;
10393
+ if (this._pauseResolve) {
10394
+ this._pauseResolve();
10395
+ this._pauseResolve = null;
10396
+ }
10397
+ }
10398
+ /**
10399
+ * Pause the current task gracefully. The run loop will suspend at the next
10400
+ * turn boundary (between tool calls / model requests) without destroying state.
10401
+ * Call resume() to continue.
10402
+ */
10403
+ pause() {
10404
+ if (!this._paused) {
10405
+ this._paused = true;
10406
+ this.emit({ type: "compaction", content: "Task paused by user.", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10407
+ }
10408
+ }
10409
+ /**
10410
+ * Resume a paused task. The run loop continues from where it left off.
10411
+ */
10412
+ resume() {
10413
+ if (this._paused) {
10414
+ this._paused = false;
10415
+ this.emit({ type: "compaction", content: "Task resumed by user.", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10416
+ if (this._pauseResolve) {
10417
+ this._pauseResolve();
10418
+ this._pauseResolve = null;
10419
+ }
10420
+ }
10421
+ }
10422
+ /** Whether the runner is currently paused */
10423
+ get isPaused() {
10424
+ return this._paused;
10425
+ }
10426
+ /**
10427
+ * If paused, block until resume() or abort() is called.
10428
+ * Returns true if the loop should continue, false if aborted while paused.
10429
+ */
10430
+ async waitIfPaused() {
10431
+ if (!this._paused)
10432
+ return true;
10433
+ await new Promise((resolve19) => {
10434
+ this._pauseResolve = resolve19;
10435
+ });
10436
+ return !this.aborted;
10391
10437
  }
10392
10438
  emit(event) {
10393
10439
  for (const handler of this.handlers) {
@@ -10440,6 +10486,8 @@ Respond with your assessment, then take action.`;
10440
10486
  let selfEvalCount = 0;
10441
10487
  const toolCallLog = [];
10442
10488
  this.aborted = false;
10489
+ this._paused = false;
10490
+ this._pauseResolve = null;
10443
10491
  this.pendingUserMessages.length = 0;
10444
10492
  const basePrompt = getSystemPromptForTier(this.options.modelTier);
10445
10493
  const systemPrompt = this.options.dynamicContext ? `${basePrompt}
@@ -10461,6 +10509,13 @@ TASK: ${task}` : task }
10461
10509
  let summary = "";
10462
10510
  let bruteForceCycle = 0;
10463
10511
  for (let turn = 0; turn < this.options.maxTurns; turn++) {
10512
+ if (this._paused) {
10513
+ const shouldContinue = await this.waitIfPaused();
10514
+ if (!shouldContinue) {
10515
+ this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10516
+ break;
10517
+ }
10518
+ }
10464
10519
  if (this.aborted) {
10465
10520
  this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10466
10521
  break;
@@ -10717,6 +10772,13 @@ You have ${this.options.maxTurns} more turns. Continue making progress. Call tas
10717
10772
  messages.push(...compacted);
10718
10773
  }
10719
10774
  for (let turn = 0; turn < this.options.maxTurns; turn++) {
10775
+ if (this._paused) {
10776
+ const shouldContinue = await this.waitIfPaused();
10777
+ if (!shouldContinue) {
10778
+ this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10779
+ break;
10780
+ }
10781
+ }
10720
10782
  if (this.aborted) {
10721
10783
  this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10722
10784
  break;
@@ -12061,8 +12123,8 @@ function isTranscribablePath(path) {
12061
12123
  return isAudioPath(path) || isVideoPath(path);
12062
12124
  }
12063
12125
  function findMicCaptureCommand() {
12064
- const platform3 = process.platform;
12065
- if (platform3 === "linux") {
12126
+ const platform4 = process.platform;
12127
+ if (platform4 === "linux") {
12066
12128
  try {
12067
12129
  execSync12("which arecord", { stdio: "pipe" });
12068
12130
  return {
@@ -12072,7 +12134,7 @@ function findMicCaptureCommand() {
12072
12134
  } catch {
12073
12135
  }
12074
12136
  }
12075
- if (platform3 === "darwin") {
12137
+ if (platform4 === "darwin") {
12076
12138
  try {
12077
12139
  execSync12("which sox", { stdio: "pipe" });
12078
12140
  return {
@@ -12084,7 +12146,7 @@ function findMicCaptureCommand() {
12084
12146
  }
12085
12147
  try {
12086
12148
  execSync12("which ffmpeg", { stdio: "pipe" });
12087
- if (platform3 === "linux") {
12149
+ if (platform4 === "linux") {
12088
12150
  return {
12089
12151
  cmd: "ffmpeg",
12090
12152
  args: [
@@ -12103,7 +12165,7 @@ function findMicCaptureCommand() {
12103
12165
  "pipe:1"
12104
12166
  ]
12105
12167
  };
12106
- } else if (platform3 === "darwin") {
12168
+ } else if (platform4 === "darwin") {
12107
12169
  return {
12108
12170
  cmd: "ffmpeg",
12109
12171
  args: [
@@ -14272,10 +14334,10 @@ var init_oa_directory = __esm({
14272
14334
 
14273
14335
  // packages/cli/dist/tui/setup.js
14274
14336
  import * as readline from "node:readline";
14275
- import { execSync as execSync13 } from "node:child_process";
14337
+ import { execSync as execSync13, spawn as spawn8 } from "node:child_process";
14276
14338
  import { existsSync as existsSync15, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
14277
14339
  import { join as join22 } from "node:path";
14278
- import { homedir as homedir8 } from "node:os";
14340
+ import { homedir as homedir8, platform } from "node:os";
14279
14341
  function detectSystemSpecs() {
14280
14342
  let totalRamGB = 0;
14281
14343
  let availableRamGB = 0;
@@ -14362,6 +14424,148 @@ function ask(rl, question) {
14362
14424
  rl.question(question, (answer) => resolve19(answer.trim()));
14363
14425
  });
14364
14426
  }
14427
+ async function autoInstallOllama(rl) {
14428
+ const plat = platform();
14429
+ if (plat === "linux") {
14430
+ return installOllamaLinux();
14431
+ } else if (plat === "darwin") {
14432
+ return await installOllamaMac(rl);
14433
+ } else if (plat === "win32") {
14434
+ return installOllamaWindows();
14435
+ }
14436
+ process.stdout.write(` ${c2.yellow("\u26A0")} Unsupported platform: ${plat}
14437
+ `);
14438
+ process.stdout.write(` ${c2.dim("Visit https://ollama.com to install manually.")}
14439
+
14440
+ `);
14441
+ return false;
14442
+ }
14443
+ function installOllamaLinux() {
14444
+ process.stdout.write(`
14445
+ ${c2.cyan("\u25CF")} Installing Ollama via official install script...
14446
+
14447
+ `);
14448
+ try {
14449
+ execSync13("curl -fsSL https://ollama.com/install.sh | sh", {
14450
+ stdio: "inherit",
14451
+ timeout: 3e5
14452
+ });
14453
+ if (hasCmd("ollama")) {
14454
+ process.stdout.write(`
14455
+ ${c2.green("\u2714")} Ollama installed successfully.
14456
+ `);
14457
+ return true;
14458
+ }
14459
+ process.stdout.write(`
14460
+ ${c2.yellow("\u26A0")} Install script ran but ollama not found on PATH.
14461
+ `);
14462
+ return false;
14463
+ } catch (err) {
14464
+ process.stdout.write(`
14465
+ ${c2.red("\u2716")} Ollama install failed: ${err instanceof Error ? err.message : String(err)}
14466
+ `);
14467
+ return false;
14468
+ }
14469
+ }
14470
+ async function installOllamaMac(rl) {
14471
+ if (!hasCmd("brew")) {
14472
+ process.stdout.write(`
14473
+ ${c2.yellow("\u26A0")} Homebrew is not installed (needed for Ollama on macOS).
14474
+
14475
+ `);
14476
+ const installBrew = await ask(rl, ` ${c2.bold("Install Homebrew?")} (Y/n) `);
14477
+ if (installBrew.toLowerCase() === "n") {
14478
+ process.stdout.write(` ${c2.dim("Skipping Homebrew install.")}
14479
+
14480
+ `);
14481
+ return false;
14482
+ }
14483
+ process.stdout.write(`
14484
+ ${c2.cyan("\u25CF")} Installing Homebrew...
14485
+
14486
+ `);
14487
+ try {
14488
+ execSync13('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
14489
+ if (!hasCmd("brew")) {
14490
+ try {
14491
+ const brewPrefix = existsSync15("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
14492
+ process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
14493
+ } catch {
14494
+ }
14495
+ }
14496
+ if (hasCmd("brew")) {
14497
+ process.stdout.write(`
14498
+ ${c2.green("\u2714")} Homebrew installed.
14499
+ `);
14500
+ } else {
14501
+ process.stdout.write(`
14502
+ ${c2.yellow("\u26A0")} Homebrew install completed but brew not found on PATH.
14503
+ `);
14504
+ process.stdout.write(` ${c2.dim('Try: eval "$(/opt/homebrew/bin/brew shellenv)"')}
14505
+
14506
+ `);
14507
+ return false;
14508
+ }
14509
+ } catch (err) {
14510
+ process.stdout.write(`
14511
+ ${c2.red("\u2716")} Homebrew install failed: ${err instanceof Error ? err.message : String(err)}
14512
+ `);
14513
+ return false;
14514
+ }
14515
+ }
14516
+ process.stdout.write(`
14517
+ ${c2.cyan("\u25CF")} Installing Ollama via Homebrew...
14518
+
14519
+ `);
14520
+ try {
14521
+ execSync13("brew install ollama", {
14522
+ stdio: "inherit",
14523
+ timeout: 3e5
14524
+ });
14525
+ if (hasCmd("ollama")) {
14526
+ process.stdout.write(`
14527
+ ${c2.green("\u2714")} Ollama installed successfully.
14528
+ `);
14529
+ return true;
14530
+ }
14531
+ process.stdout.write(`
14532
+ ${c2.yellow("\u26A0")} brew install completed but ollama not found on PATH.
14533
+ `);
14534
+ return false;
14535
+ } catch (err) {
14536
+ process.stdout.write(`
14537
+ ${c2.red("\u2716")} Ollama install failed: ${err instanceof Error ? err.message : String(err)}
14538
+ `);
14539
+ return false;
14540
+ }
14541
+ }
14542
+ function installOllamaWindows() {
14543
+ process.stdout.write(`
14544
+ ${c2.cyan("\u25CF")} Installing Ollama via PowerShell...
14545
+
14546
+ `);
14547
+ try {
14548
+ execSync13('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
14549
+ stdio: "inherit",
14550
+ timeout: 3e5
14551
+ });
14552
+ if (hasCmd("ollama")) {
14553
+ process.stdout.write(`
14554
+ ${c2.green("\u2714")} Ollama installed successfully.
14555
+ `);
14556
+ return true;
14557
+ }
14558
+ process.stdout.write(`
14559
+ ${c2.yellow("\u26A0")} Install script ran but ollama not found on PATH.
14560
+ `);
14561
+ return false;
14562
+ } catch (err) {
14563
+ process.stdout.write(`
14564
+ ${c2.red("\u2716")} Ollama install failed: ${err instanceof Error ? err.message : String(err)}
14565
+ `);
14566
+ return false;
14567
+ }
14568
+ }
14365
14569
  function pullModelWithAutoUpdate(tag) {
14366
14570
  try {
14367
14571
  execSync13(`ollama pull ${tag}`, {
@@ -14562,32 +14766,81 @@ async function doSetup(config, rl) {
14562
14766
  process.stdout.write(` ${c2.yellow("\u26A0")} Cannot reach Ollama at ${c2.bold(config.backendUrl)}
14563
14767
 
14564
14768
  `);
14565
- const useWithout = await ask(rl, ` ${c2.bold("Use without Ollama?")} (y/n) `);
14566
- if (useWithout.toLowerCase() === "y" || useWithout.toLowerCase() === "yes") {
14567
- const endpointResult = await promptForCustomEndpoint(config, rl);
14568
- if (endpointResult) {
14569
- return endpointResult;
14769
+ const ollamaInstalled = hasCmd("ollama");
14770
+ if (ollamaInstalled) {
14771
+ process.stdout.write(` ${c2.cyan("\u25CF")} Ollama is installed but not running.
14772
+
14773
+ `);
14774
+ const startOllama = await ask(rl, ` ${c2.bold("Start Ollama now?")} (Y/n) `);
14775
+ if (startOllama.toLowerCase() !== "n") {
14776
+ process.stdout.write(`
14777
+ ${c2.cyan("\u25CF")} Starting ollama serve in background...
14778
+ `);
14779
+ try {
14780
+ const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
14781
+ child.unref();
14782
+ await new Promise((resolve19) => setTimeout(resolve19, 3e3));
14783
+ try {
14784
+ models = await fetchOllamaModels(config.backendUrl);
14785
+ process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
14786
+
14787
+ `);
14788
+ } catch {
14789
+ process.stdout.write(` ${c2.yellow("\u26A0")} Ollama started but not responding yet. It may need a moment.
14790
+
14791
+ `);
14792
+ }
14793
+ } catch {
14794
+ process.stdout.write(` ${c2.yellow("\u26A0")} Could not start Ollama. Try running ${c2.bold("ollama serve")} manually.
14795
+
14796
+ `);
14797
+ }
14570
14798
  }
14571
- usingCustomEndpoint = true;
14572
14799
  } else {
14573
- process.stdout.write(`
14574
- ${c2.cyan("\u25CF")} Install Ollama: ${c2.bold(c2.cyan("https://ollama.com"))}
14800
+ const installOllama = await ask(rl, ` ${c2.bold("Install Ollama?")} (Y/n) `);
14801
+ if (installOllama.toLowerCase() !== "n") {
14802
+ const installed = await autoInstallOllama(rl);
14803
+ if (installed) {
14804
+ process.stdout.write(`
14805
+ ${c2.cyan("\u25CF")} Starting ollama serve...
14575
14806
  `);
14576
- process.stdout.write(` ${c2.dim("Linux:")} curl -fsSL https://ollama.com/install.sh | sh
14807
+ try {
14808
+ const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
14809
+ child.unref();
14810
+ await new Promise((resolve19) => setTimeout(resolve19, 3e3));
14811
+ try {
14812
+ models = await fetchOllamaModels(config.backendUrl);
14813
+ process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
14814
+
14577
14815
  `);
14578
- process.stdout.write(` ${c2.dim("macOS:")} brew install ollama
14816
+ } catch {
14817
+ process.stdout.write(` ${c2.yellow("\u26A0")} Ollama installed but not responding yet. Try ${c2.bold("ollama serve")} manually.
14818
+
14579
14819
  `);
14580
- process.stdout.write(` ${c2.dim("Then:")} ollama serve
14820
+ }
14821
+ } catch {
14822
+ process.stdout.write(` ${c2.yellow("\u26A0")} Ollama installed. Start it with: ${c2.bold("ollama serve")}
14581
14823
 
14582
14824
  `);
14583
- const startAnyway = await ask(rl, ` ${c2.bold("Start anyway?")} (y/n) `);
14584
- if (startAnyway.toLowerCase() !== "y" && startAnyway.toLowerCase() !== "yes") {
14585
- process.stdout.write(`
14586
- ${c2.dim("You can always configure an endpoint later with /endpoint")}
14825
+ }
14826
+ }
14827
+ }
14828
+ if (models.length === 0) {
14829
+ const useCustom = await ask(rl, ` ${c2.bold("Use a custom inference endpoint instead?")} (y/n) `);
14830
+ if (useCustom.toLowerCase() === "y" || useCustom.toLowerCase() === "yes") {
14831
+ const endpointResult = await promptForCustomEndpoint(config, rl);
14832
+ if (endpointResult) {
14833
+ return endpointResult;
14834
+ }
14835
+ usingCustomEndpoint = true;
14836
+ } else {
14837
+ process.stdout.write(`
14838
+ ${c2.dim("You can configure an endpoint later with /endpoint")}
14587
14839
 
14588
14840
  `);
14841
+ return config.model;
14842
+ }
14589
14843
  }
14590
- return config.model;
14591
14844
  }
14592
14845
  }
14593
14846
  if (usingCustomEndpoint) {
@@ -15489,8 +15742,24 @@ async function handleSlashCommand(input, ctx) {
15489
15742
  renderInfo(`Colors ${next ? "enabled" : "disabled"}.`);
15490
15743
  return "handled";
15491
15744
  }
15492
- case "stop":
15493
15745
  case "pause": {
15746
+ if (!ctx.hasActiveTask?.()) {
15747
+ renderWarning("No active task to pause.");
15748
+ return "handled";
15749
+ }
15750
+ if (ctx.isTaskPaused?.()) {
15751
+ renderWarning("Task is already paused. Use /resume to continue.");
15752
+ return "handled";
15753
+ }
15754
+ const paused = ctx.pauseTask?.() ?? false;
15755
+ if (paused) {
15756
+ renderInfo("Task paused. Use /resume to continue or /stop to abort.");
15757
+ } else {
15758
+ renderWarning("Could not pause the task.");
15759
+ }
15760
+ return "handled";
15761
+ }
15762
+ case "stop": {
15494
15763
  if (!ctx.hasActiveTask?.()) {
15495
15764
  renderWarning("No active task to stop.");
15496
15765
  return "handled";
@@ -15507,8 +15776,17 @@ async function handleSlashCommand(input, ctx) {
15507
15776
  return "handled";
15508
15777
  }
15509
15778
  case "resume": {
15779
+ if (ctx.isTaskPaused?.()) {
15780
+ const resumed2 = ctx.resumeInSessionTask?.() ?? false;
15781
+ if (resumed2) {
15782
+ renderInfo("Task resumed.");
15783
+ } else {
15784
+ renderWarning("Could not resume the paused task.");
15785
+ }
15786
+ return "handled";
15787
+ }
15510
15788
  if (ctx.hasActiveTask?.()) {
15511
- renderWarning("A task is already running. Stop it first with /stop.");
15789
+ renderWarning("A task is already running. Pause it first with /pause or stop with /stop.");
15512
15790
  return "handled";
15513
15791
  }
15514
15792
  const resumed = ctx.resumeTask?.() ?? false;
@@ -15570,7 +15848,7 @@ async function handleEndpoint(arg, ctx, local = false) {
15570
15848
  process.stdout.write(`
15571
15849
  ${c2.dim("Usage: /endpoint <url> [--auth <token>]")}
15572
15850
  `);
15573
- process.stdout.write(` ${c2.dim(" /endpoint http://localhost:11434 Ollama")}
15851
+ process.stdout.write(` ${c2.dim(" /endpoint http://127.0.0.1:11434 Ollama")}
15574
15852
  `);
15575
15853
  process.stdout.write(` ${c2.dim(" /endpoint https://llm.chutes.ai --auth cpk_... Chutes AI")}
15576
15854
  `);
@@ -15803,7 +16081,7 @@ var init_commands = __esm({
15803
16081
  import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync as readdirSync8 } from "node:fs";
15804
16082
  import { join as join23, basename as basename6 } from "node:path";
15805
16083
  import { execSync as execSync14 } from "node:child_process";
15806
- import { homedir as homedir9, platform, release } from "node:os";
16084
+ import { homedir as homedir9, platform as platform2, release } from "node:os";
15807
16085
  function getModelTier(modelName) {
15808
16086
  const m = modelName.toLowerCase();
15809
16087
  const sizeMatch = m.match(/\b(\d+)b\b/);
@@ -15943,7 +16221,7 @@ function getEnvironment(repoRoot) {
15943
16221
  const lines = [
15944
16222
  `Working directory: ${repoRoot}`,
15945
16223
  `Date: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
15946
- `Platform: ${platform()} ${release()}`,
16224
+ `Platform: ${platform2()} ${release()}`,
15947
16225
  `Node: ${process.version}`
15948
16226
  ];
15949
16227
  return lines.join("\n");
@@ -17284,7 +17562,7 @@ var init_carousel_descriptors = __esm({
17284
17562
  // packages/cli/dist/tui/voice.js
17285
17563
  import { existsSync as existsSync18, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
17286
17564
  import { join as join25 } from "node:path";
17287
- import { homedir as homedir10, tmpdir as tmpdir4, platform as platform2 } from "node:os";
17565
+ import { homedir as homedir10, tmpdir as tmpdir4, platform as platform3 } from "node:os";
17288
17566
  import { execSync as execSync15, spawn as nodeSpawn } from "node:child_process";
17289
17567
  import { createRequire } from "node:module";
17290
17568
  function voiceDir() {
@@ -17691,7 +17969,7 @@ var init_voice = __esm({
17691
17969
  });
17692
17970
  }
17693
17971
  getPlayCommand(path) {
17694
- const os = platform2();
17972
+ const os = platform3();
17695
17973
  if (os === "darwin")
17696
17974
  return ["afplay", path];
17697
17975
  if (os === "win32") {
@@ -20474,6 +20752,7 @@ async function startInteractive(config, repoPath) {
20474
20752
  let sudoPromptPending = false;
20475
20753
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
20476
20754
  const activePrompt = `${c2.bold(c2.white("+ "))}`;
20755
+ const pausedPrompt = `${c2.bold(c2.yellow("| "))}`;
20477
20756
  const rl = readline2.createInterface({
20478
20757
  input: process.stdin,
20479
20758
  output: process.stdout,
@@ -20507,7 +20786,7 @@ async function startInteractive(config, repoPath) {
20507
20786
  }
20508
20787
  });
20509
20788
  function showPrompt() {
20510
- const prompt = activeTask ? activePrompt : idlePrompt;
20789
+ const prompt = activeTask ? activeTask.runner.isPaused ? pausedPrompt : activePrompt : idlePrompt;
20511
20790
  rl.setPrompt(prompt);
20512
20791
  if (statusBar.isActive) {
20513
20792
  statusBar.setPromptText(prompt, 2);
@@ -20759,6 +21038,25 @@ async function startInteractive(config, repoPath) {
20759
21038
  writeContent(() => renderInfo("Task aborted."));
20760
21039
  return true;
20761
21040
  },
21041
+ pauseTask() {
21042
+ if (!activeTask)
21043
+ return false;
21044
+ activeTask.runner.pause();
21045
+ statusBar.setProcessing(false);
21046
+ showPrompt();
21047
+ return true;
21048
+ },
21049
+ resumeInSessionTask() {
21050
+ if (!activeTask || !activeTask.runner.isPaused)
21051
+ return false;
21052
+ activeTask.runner.resume();
21053
+ statusBar.setProcessing(true);
21054
+ showPrompt();
21055
+ return true;
21056
+ },
21057
+ isTaskPaused() {
21058
+ return activeTask !== null && activeTask.runner.isPaused;
21059
+ },
20762
21060
  resumeTask() {
20763
21061
  const pendingTask = loadPendingTask(repoRoot);
20764
21062
  if (!pendingTask)
@@ -21790,7 +22088,7 @@ var serve_exports = {};
21790
22088
  __export(serve_exports, {
21791
22089
  serveCommand: () => serveCommand
21792
22090
  });
21793
- import { spawn as spawn8 } from "node:child_process";
22091
+ import { spawn as spawn9 } from "node:child_process";
21794
22092
  async function serveCommand(opts, config) {
21795
22093
  const backendType = config.backendType;
21796
22094
  if (backendType === "ollama") {
@@ -21883,7 +22181,7 @@ async function serveVllm(opts, config) {
21883
22181
  }
21884
22182
  async function runVllmServer(args, verbose) {
21885
22183
  return new Promise((resolve19, reject) => {
21886
- const child = spawn8("python", args, {
22184
+ const child = spawn9("python", args, {
21887
22185
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
21888
22186
  env: { ...process.env }
21889
22187
  });
package/dist/launcher.cjs CHANGED
@@ -198,10 +198,26 @@ if (nodeVersion < 18) {
198
198
  }
199
199
  console.log("");
200
200
  console.log(" ┌─────────────────────────────────────────────────┐");
201
- console.log(" │ Done! Open a new terminal, then run: oa │");
201
+ console.log(" │ Done! Launching open-agents... │");
202
202
  console.log(" └─────────────────────────────────────────────────┘");
203
203
  console.log("");
204
204
  rl.close();
205
+
206
+ // Auto-source shell config and re-exec oa — no "open a new terminal" needed
207
+ var rcFile = shell.indexOf("zsh") !== -1 ? "~/.zshrc" : "~/.bashrc";
208
+ var relaunchCmd = 'export NVM_DIR="' + nvmDir + '" && ' +
209
+ '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
210
+ "source " + rcFile + " 2>/dev/null; " +
211
+ "exec oa";
212
+ try {
213
+ childProcess.execSync(shell + " -c '" + relaunchCmd + "'", {
214
+ stdio: "inherit",
215
+ env: process.env,
216
+ });
217
+ } catch (e) {
218
+ // Fallback: tell user to open new terminal only if re-exec fails
219
+ console.log("\n If oa didn't launch, run: source " + rcFile + " && oa\n");
220
+ }
205
221
  process.exit(0);
206
222
  });
207
223
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.30.3",
3
+ "version": "0.30.5",
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",