open-agents-ai 0.14.9 → 0.15.1

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 +295 -190
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -232,7 +232,6 @@ var init_output = __esm({
232
232
  });
233
233
 
234
234
  // packages/cli/dist/updater.js
235
- import { execSync } from "node:child_process";
236
235
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
237
236
  import { join as join2 } from "node:path";
238
237
  import { homedir as homedir2 } from "node:os";
@@ -297,50 +296,6 @@ async function checkForUpdate(currentVersion, forceCheck = false) {
297
296
  latestVersion: latest
298
297
  };
299
298
  }
300
- function performUpdate() {
301
- try {
302
- execSync(`npm cache clean --force ${PACKAGE_NAME} 2>/dev/null; npm install -g ${PACKAGE_NAME}@latest --force`, {
303
- stdio: "inherit",
304
- timeout: 12e4,
305
- shell: "/bin/bash"
306
- });
307
- try {
308
- const installed = execSync(`npm list -g ${PACKAGE_NAME} --depth=0 --json`, {
309
- encoding: "utf-8",
310
- stdio: ["pipe", "pipe", "pipe"],
311
- timeout: 1e4
312
- });
313
- const parsed = JSON.parse(installed);
314
- const ver = parsed?.dependencies?.[PACKAGE_NAME]?.version;
315
- if (ver) {
316
- console.log(` Verified: ${PACKAGE_NAME}@${ver} installed globally.`);
317
- }
318
- } catch {
319
- }
320
- return true;
321
- } catch {
322
- return false;
323
- }
324
- }
325
- function performSilentUpdate() {
326
- try {
327
- execSync(`npm install -g ${PACKAGE_NAME}@latest --prefer-online`, {
328
- stdio: "pipe",
329
- timeout: 12e4
330
- });
331
- return true;
332
- } catch {
333
- return false;
334
- }
335
- }
336
- function restartProcess() {
337
- const args = process.argv.slice(1);
338
- try {
339
- execSync([process.execPath, ...args].map((a) => `"${a}"`).join(" "), { stdio: "inherit", timeout: 0 });
340
- } catch {
341
- }
342
- process.exit(0);
343
- }
344
299
  function formatUpdateBanner(info) {
345
300
  return `
346
301
  Update available: v${info.currentVersion} \u2192 v${info.latestVersion}
@@ -2122,7 +2077,7 @@ var init_list_directory = __esm({
2122
2077
  });
2123
2078
 
2124
2079
  // packages/execution/dist/tools/aiwg-setup.js
2125
- import { execSync as execSync2 } from "node:child_process";
2080
+ import { execSync } from "node:child_process";
2126
2081
  var AiwgSetupTool;
2127
2082
  var init_aiwg_setup = __esm({
2128
2083
  "packages/execution/dist/tools/aiwg-setup.js"() {
@@ -2161,7 +2116,7 @@ var init_aiwg_setup = __esm({
2161
2116
  };
2162
2117
  }
2163
2118
  try {
2164
- const output = execSync2(`aiwg use ${framework}`, {
2119
+ const output = execSync(`aiwg use ${framework}`, {
2165
2120
  cwd: projectDir,
2166
2121
  encoding: "utf8",
2167
2122
  timeout: 6e4,
@@ -2185,7 +2140,7 @@ ${output}`,
2185
2140
  }
2186
2141
  isAiwgInstalled() {
2187
2142
  try {
2188
- execSync2("aiwg --version", {
2143
+ execSync("aiwg --version", {
2189
2144
  encoding: "utf8",
2190
2145
  timeout: 5e3,
2191
2146
  stdio: ["pipe", "pipe", "pipe"]
@@ -2200,7 +2155,7 @@ ${output}`,
2200
2155
  });
2201
2156
 
2202
2157
  // packages/execution/dist/tools/aiwg-health.js
2203
- import { execSync as execSync3 } from "node:child_process";
2158
+ import { execSync as execSync2 } from "node:child_process";
2204
2159
  import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
2205
2160
  import { join as join6 } from "node:path";
2206
2161
  var AiwgHealthTool;
@@ -2280,7 +2235,7 @@ var init_aiwg_health = __esm({
2280
2235
  }
2281
2236
  if (this.isAiwgInstalled()) {
2282
2237
  try {
2283
- const runtimeInfo = execSync3("aiwg runtime-info 2>/dev/null", {
2238
+ const runtimeInfo = execSync2("aiwg runtime-info 2>/dev/null", {
2284
2239
  cwd: projectDir,
2285
2240
  encoding: "utf8",
2286
2241
  timeout: 15e3
@@ -2401,7 +2356,7 @@ var init_aiwg_health = __esm({
2401
2356
  }
2402
2357
  isAiwgInstalled() {
2403
2358
  try {
2404
- execSync3("aiwg --version", { encoding: "utf8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] });
2359
+ execSync2("aiwg --version", { encoding: "utf8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] });
2405
2360
  return true;
2406
2361
  } catch {
2407
2362
  return false;
@@ -2412,7 +2367,7 @@ var init_aiwg_health = __esm({
2412
2367
  });
2413
2368
 
2414
2369
  // packages/execution/dist/tools/aiwg-workflow.js
2415
- import { execSync as execSync4 } from "node:child_process";
2370
+ import { execSync as execSync3 } from "node:child_process";
2416
2371
  var AiwgWorkflowTool;
2417
2372
  var init_aiwg_workflow = __esm({
2418
2373
  "packages/execution/dist/tools/aiwg-workflow.js"() {
@@ -2460,7 +2415,7 @@ var init_aiwg_workflow = __esm({
2460
2415
  }
2461
2416
  const sanitized = command.replace(/[;&|`$()]/g, "");
2462
2417
  try {
2463
- const output = execSync4(`aiwg ${sanitized}`, {
2418
+ const output = execSync3(`aiwg ${sanitized}`, {
2464
2419
  cwd: projectDir,
2465
2420
  encoding: "utf8",
2466
2421
  timeout: 12e4,
@@ -2486,7 +2441,7 @@ var init_aiwg_workflow = __esm({
2486
2441
  }
2487
2442
  isAiwgInstalled() {
2488
2443
  try {
2489
- execSync4("aiwg --version", { encoding: "utf8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] });
2444
+ execSync3("aiwg --version", { encoding: "utf8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] });
2490
2445
  return true;
2491
2446
  } catch {
2492
2447
  return false;
@@ -3083,7 +3038,7 @@ var init_codebase_map = __esm({
3083
3038
  });
3084
3039
 
3085
3040
  // packages/execution/dist/tools/diagnostic.js
3086
- import { execSync as execSync5 } from "node:child_process";
3041
+ import { execSync as execSync4 } from "node:child_process";
3087
3042
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
3088
3043
  import { join as join8 } from "node:path";
3089
3044
  var DiagnosticTool;
@@ -3198,7 +3153,7 @@ var init_diagnostic = __esm({
3198
3153
  runStep(step, command, cwd4) {
3199
3154
  const start = performance.now();
3200
3155
  try {
3201
- const output = execSync5(command, {
3156
+ const output = execSync4(command, {
3202
3157
  cwd: cwd4,
3203
3158
  encoding: "utf8",
3204
3159
  timeout: 12e4,
@@ -3228,7 +3183,7 @@ ${err.stderr ?? ""}`.trim(),
3228
3183
  });
3229
3184
 
3230
3185
  // packages/execution/dist/tools/git-info.js
3231
- import { execSync as execSync6 } from "node:child_process";
3186
+ import { execSync as execSync5 } from "node:child_process";
3232
3187
  import { existsSync as existsSync6 } from "node:fs";
3233
3188
  import { join as join9 } from "node:path";
3234
3189
  var GitInfoTool;
@@ -3344,7 +3299,7 @@ var init_git_info = __esm({
3344
3299
  }
3345
3300
  git(cwd4, cmd) {
3346
3301
  try {
3347
- return execSync6(`git ${cmd}`, {
3302
+ return execSync5(`git ${cmd}`, {
3348
3303
  cwd: cwd4,
3349
3304
  encoding: "utf8",
3350
3305
  timeout: 1e4,
@@ -3649,7 +3604,7 @@ Exit code: ${task.exitCode ?? "N/A"}`,
3649
3604
  // packages/execution/dist/tools/image.js
3650
3605
  import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
3651
3606
  import { resolve as resolve11, extname as extname2, basename } from "node:path";
3652
- import { execSync as execSync7 } from "node:child_process";
3607
+ import { execSync as execSync6 } from "node:child_process";
3653
3608
  import { tmpdir } from "node:os";
3654
3609
  import { join as join10 } from "node:path";
3655
3610
  function isImagePath(path) {
@@ -3676,7 +3631,7 @@ function getMimeType(filePath) {
3676
3631
  }
3677
3632
  function getImageDimensions(filePath) {
3678
3633
  try {
3679
- const out = execSync7(`identify -format "%w %h" ${JSON.stringify(filePath)}`, {
3634
+ const out = execSync6(`identify -format "%w %h" ${JSON.stringify(filePath)}`, {
3680
3635
  encoding: "utf8",
3681
3636
  stdio: ["pipe", "pipe", "pipe"],
3682
3637
  timeout: 5e3
@@ -3687,7 +3642,7 @@ function getImageDimensions(filePath) {
3687
3642
  } catch {
3688
3643
  }
3689
3644
  try {
3690
- const out = execSync7(`file ${JSON.stringify(filePath)}`, {
3645
+ const out = execSync6(`file ${JSON.stringify(filePath)}`, {
3691
3646
  encoding: "utf8",
3692
3647
  stdio: ["pipe", "pipe", "pipe"],
3693
3648
  timeout: 5e3
@@ -3701,7 +3656,7 @@ function getImageDimensions(filePath) {
3701
3656
  }
3702
3657
  function hasTesseract() {
3703
3658
  try {
3704
- execSync7("tesseract --version", { stdio: "pipe", timeout: 5e3 });
3659
+ execSync6("tesseract --version", { stdio: "pipe", timeout: 5e3 });
3705
3660
  return true;
3706
3661
  } catch {
3707
3662
  return false;
@@ -3709,7 +3664,7 @@ function hasTesseract() {
3709
3664
  }
3710
3665
  function runOCR(filePath) {
3711
3666
  try {
3712
- return execSync7(`tesseract ${JSON.stringify(filePath)} stdout 2>/dev/null`, {
3667
+ return execSync6(`tesseract ${JSON.stringify(filePath)} stdout 2>/dev/null`, {
3713
3668
  encoding: "utf8",
3714
3669
  stdio: ["pipe", "pipe", "pipe"],
3715
3670
  timeout: 3e4
@@ -3842,7 +3797,7 @@ ${ocrText}`);
3842
3797
  };
3843
3798
  }
3844
3799
  try {
3845
- execSync7(cmd, { stdio: "pipe", timeout: 1e4 });
3800
+ execSync6(cmd, { stdio: "pipe", timeout: 1e4 });
3846
3801
  } catch (err) {
3847
3802
  return {
3848
3803
  success: false,
@@ -3890,7 +3845,7 @@ ${ocrText}`);
3890
3845
  if (plat === "linux") {
3891
3846
  for (const tool of ["scrot", "gnome-screenshot", "import"]) {
3892
3847
  try {
3893
- execSync7(`which ${tool}`, { stdio: "pipe" });
3848
+ execSync6(`which ${tool}`, { stdio: "pipe" });
3894
3849
  if (tool === "scrot") {
3895
3850
  if (region === "active")
3896
3851
  return `scrot -u ${out}`;
@@ -3967,14 +3922,14 @@ ${ocrText}`);
3967
3922
  if (x != null && y != null && w != null && h != null) {
3968
3923
  const croppedPath = join10(tmpdir(), `oa-ocr-crop-${Date.now()}.png`);
3969
3924
  try {
3970
- execSync7(`convert ${JSON.stringify(fullPath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
3925
+ execSync6(`convert ${JSON.stringify(fullPath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
3971
3926
  inputPath = croppedPath;
3972
3927
  } catch {
3973
3928
  }
3974
3929
  }
3975
3930
  }
3976
3931
  try {
3977
- const text = execSync7(`tesseract ${JSON.stringify(inputPath)} stdout -l ${language} --psm ${psm} 2>/dev/null`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }).trim();
3932
+ const text = execSync6(`tesseract ${JSON.stringify(inputPath)} stdout -l ${language} --psm ${psm} 2>/dev/null`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }).trim();
3978
3933
  if (!text) {
3979
3934
  return { success: true, output: "(no text detected in image)", durationMs: Date.now() - start };
3980
3935
  }
@@ -4509,7 +4464,7 @@ var init_tool_creator = __esm({
4509
4464
  import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
4510
4465
  import { join as join12, basename as basename2, dirname as dirname2 } from "node:path";
4511
4466
  import { homedir as homedir4 } from "node:os";
4512
- import { execSync as execSync8 } from "node:child_process";
4467
+ import { execSync as execSync7 } from "node:child_process";
4513
4468
  function getAiwgPaths() {
4514
4469
  const dataDir = join12(homedir4(), ".local", "share", "ai-writing-guide");
4515
4470
  return {
@@ -4522,7 +4477,7 @@ function findAiwgPackageRoot() {
4522
4477
  if (_cachedAiwgPkgRoot !== void 0)
4523
4478
  return _cachedAiwgPkgRoot;
4524
4479
  try {
4525
- const globalRoot = execSync8("npm root -g", {
4480
+ const globalRoot = execSync7("npm root -g", {
4526
4481
  encoding: "utf-8",
4527
4482
  timeout: 5e3,
4528
4483
  stdio: ["pipe", "pipe", "pipe"]
@@ -4858,7 +4813,7 @@ ${content}`,
4858
4813
  import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync9, unlinkSync } from "node:fs";
4859
4814
  import { join as join13, basename as basename3, extname as extname3, resolve as resolve12 } from "node:path";
4860
4815
  import { homedir as homedir5 } from "node:os";
4861
- import { execSync as execSync9, spawn as spawn4 } from "node:child_process";
4816
+ import { execSync as execSync8, spawn as spawn4 } from "node:child_process";
4862
4817
  function isTranscribable(path) {
4863
4818
  const ext = extname3(path).toLowerCase();
4864
4819
  return AUDIO_EXTS.has(ext) || VIDEO_EXTS.has(ext);
@@ -4868,7 +4823,7 @@ async function loadTranscribeCli() {
4868
4823
  return _tcModule;
4869
4824
  _tcChecked = true;
4870
4825
  try {
4871
- const globalRoot = execSync9("npm root -g", {
4826
+ const globalRoot = execSync8("npm root -g", {
4872
4827
  encoding: "utf-8",
4873
4828
  timeout: 5e3,
4874
4829
  stdio: ["pipe", "pipe", "pipe"]
@@ -5033,7 +4988,7 @@ var init_transcribe_tool = __esm({
5033
4988
  const args = [filePath, "-m", model, "-f", "txt"];
5034
4989
  if (diarize)
5035
4990
  args.push("--diarize");
5036
- const output = execSync9(`transcribe-cli ${args.join(" ")}`, {
4991
+ const output = execSync8(`transcribe-cli ${args.join(" ")}`, {
5037
4992
  encoding: "utf-8",
5038
4993
  timeout: 3e5,
5039
4994
  // 5 min max
@@ -5100,12 +5055,12 @@ var init_transcribe_tool = __esm({
5100
5055
  const tmpFile = join13(tmpDir, `download-${Date.now()}${ext}`);
5101
5056
  try {
5102
5057
  try {
5103
- execSync9(`curl -sL -o "${tmpFile}" "${url}"`, {
5058
+ execSync8(`curl -sL -o "${tmpFile}" "${url}"`, {
5104
5059
  timeout: 12e4,
5105
5060
  stdio: ["pipe", "pipe", "pipe"]
5106
5061
  });
5107
5062
  } catch {
5108
- execSync9(`wget -q -O "${tmpFile}" "${url}"`, {
5063
+ execSync8(`wget -q -O "${tmpFile}" "${url}"`, {
5109
5064
  timeout: 12e4,
5110
5065
  stdio: ["pipe", "pipe", "pipe"]
5111
5066
  });
@@ -7908,6 +7863,21 @@ var init_agenticRunner = __esm({
7908
7863
  - task_stop: Kill a running background task
7909
7864
  - sub_agent: Delegate a sub-task to an independent agent with its own context
7910
7865
 
7866
+ IMPORTANT \u2014 True Parallelism:
7867
+ When you issue MULTIPLE tool calls in a SINGLE response, read-only tools (file_read, grep_search,
7868
+ find_files, list_directory, web_fetch, web_search, memory_read, task_status, task_output) execute
7869
+ IN PARALLEL automatically. Use this to dramatically speed up exploration \u2014 call 3-5 file_reads or
7870
+ greps at once instead of one at a time.
7871
+
7872
+ For sub-agents: use background=true and launch MULTIPLE sub_agent calls in one response to run
7873
+ them concurrently against the backend. Each sub-agent gets its own independent context window and
7874
+ makes its own API requests. Check results with task_status/task_output when done.
7875
+
7876
+ PARALLEL SUB-AGENT PATTERN (preferred for independent tasks):
7877
+ 1. Call sub_agent({task: "task A", background: true}) AND sub_agent({task: "task B", background: true}) in ONE response
7878
+ 2. Both sub-agents run simultaneously against the backend
7879
+ 3. Use task_status() to poll, then task_output() to read results
7880
+
7911
7881
  ## Skills (AIWG)
7912
7882
 
7913
7883
  - skill_list: Discover available skills \u2014 shows descriptions and trigger patterns. Use filter param to search.
@@ -8245,9 +8215,23 @@ Integrate this guidance into your current approach. Continue working on the task
8245
8215
  function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
8246
8216
  }))
8247
8217
  });
8248
- for (const tc of msg.toolCalls) {
8218
+ const PARALLEL_SAFE = /* @__PURE__ */ new Set([
8219
+ "file_read",
8220
+ "grep_search",
8221
+ "find_files",
8222
+ "list_directory",
8223
+ "web_fetch",
8224
+ "web_search",
8225
+ "memory_read",
8226
+ "task_status",
8227
+ "task_output",
8228
+ "image_read",
8229
+ "screenshot",
8230
+ "ocr"
8231
+ ]);
8232
+ const executeSingle = async (tc) => {
8249
8233
  if (this.aborted)
8250
- break;
8234
+ return null;
8251
8235
  toolCallCount++;
8252
8236
  const argsKey = Object.keys(tc.arguments ?? {}).sort().join(",");
8253
8237
  toolCallLog.push({ name: tc.name, argsKey });
@@ -8281,8 +8265,39 @@ ${result.output}`;
8281
8265
  turn,
8282
8266
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
8283
8267
  });
8284
- const toolMsg = this.buildToolMessage(output, tc.id);
8285
- messages.push(toolMsg);
8268
+ return { tc, output };
8269
+ };
8270
+ const parallelBatch = [];
8271
+ const sequentialBatch = [];
8272
+ for (const tc of msg.toolCalls) {
8273
+ const isBackgroundSubAgent = tc.name === "sub_agent" && Boolean(tc.arguments?.["background"]);
8274
+ if (PARALLEL_SAFE.has(tc.name) || isBackgroundSubAgent) {
8275
+ parallelBatch.push(tc);
8276
+ } else {
8277
+ sequentialBatch.push(tc);
8278
+ }
8279
+ }
8280
+ if (parallelBatch.length > 1) {
8281
+ const results = await Promise.allSettled(parallelBatch.map((tc) => executeSingle(tc)));
8282
+ for (const settled of results) {
8283
+ if (settled.status === "fulfilled" && settled.value) {
8284
+ const toolMsg = this.buildToolMessage(settled.value.output, settled.value.tc.id);
8285
+ messages.push(toolMsg);
8286
+ }
8287
+ }
8288
+ } else if (parallelBatch.length === 1) {
8289
+ const r = await executeSingle(parallelBatch[0]);
8290
+ if (r) {
8291
+ messages.push(this.buildToolMessage(r.output, r.tc.id));
8292
+ }
8293
+ }
8294
+ for (const tc of sequentialBatch) {
8295
+ if (this.aborted)
8296
+ break;
8297
+ const r = await executeSingle(tc);
8298
+ if (r) {
8299
+ messages.push(this.buildToolMessage(r.output, r.tc.id));
8300
+ }
8286
8301
  if (tc.name === "task_complete") {
8287
8302
  completed = true;
8288
8303
  summary = tc.arguments.summary || "";
@@ -9051,7 +9066,7 @@ var init_dist5 = __esm({
9051
9066
  });
9052
9067
 
9053
9068
  // packages/cli/dist/tui/listen.js
9054
- import { spawn as spawn5, execSync as execSync10 } from "node:child_process";
9069
+ import { spawn as spawn5, execSync as execSync9 } from "node:child_process";
9055
9070
  import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
9056
9071
  import { join as join16 } from "node:path";
9057
9072
  import { homedir as homedir6 } from "node:os";
@@ -9071,7 +9086,7 @@ function findMicCaptureCommand() {
9071
9086
  const platform3 = process.platform;
9072
9087
  if (platform3 === "linux") {
9073
9088
  try {
9074
- execSync10("which arecord", { stdio: "pipe" });
9089
+ execSync9("which arecord", { stdio: "pipe" });
9075
9090
  return {
9076
9091
  cmd: "arecord",
9077
9092
  args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
@@ -9081,7 +9096,7 @@ function findMicCaptureCommand() {
9081
9096
  }
9082
9097
  if (platform3 === "darwin") {
9083
9098
  try {
9084
- execSync10("which sox", { stdio: "pipe" });
9099
+ execSync9("which sox", { stdio: "pipe" });
9085
9100
  return {
9086
9101
  cmd: "sox",
9087
9102
  args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
@@ -9090,7 +9105,7 @@ function findMicCaptureCommand() {
9090
9105
  }
9091
9106
  }
9092
9107
  try {
9093
- execSync10("which ffmpeg", { stdio: "pipe" });
9108
+ execSync9("which ffmpeg", { stdio: "pipe" });
9094
9109
  if (platform3 === "linux") {
9095
9110
  return {
9096
9111
  cmd: "ffmpeg",
@@ -9139,7 +9154,7 @@ function ensureTranscribeCliBackground() {
9139
9154
  return;
9140
9155
  _bgInstallPromise = (async () => {
9141
9156
  try {
9142
- const globalRoot = execSync10("npm root -g", {
9157
+ const globalRoot = execSync9("npm root -g", {
9143
9158
  encoding: "utf-8",
9144
9159
  timeout: 5e3,
9145
9160
  stdio: ["pipe", "pipe", "pipe"]
@@ -9246,7 +9261,7 @@ var init_listen = __esm({
9246
9261
  }
9247
9262
  if (!this.transcribeCliAvailable) {
9248
9263
  try {
9249
- execSync10("which transcribe-cli", { stdio: "pipe" });
9264
+ execSync9("which transcribe-cli", { stdio: "pipe" });
9250
9265
  this.transcribeCliAvailable = true;
9251
9266
  } catch {
9252
9267
  this.transcribeCliAvailable = false;
@@ -9263,7 +9278,7 @@ var init_listen = __esm({
9263
9278
  } catch {
9264
9279
  }
9265
9280
  try {
9266
- const globalRoot = execSync10("npm root -g", {
9281
+ const globalRoot = execSync9("npm root -g", {
9267
9282
  encoding: "utf-8",
9268
9283
  timeout: 5e3,
9269
9284
  stdio: ["pipe", "pipe", "pipe"]
@@ -9314,7 +9329,7 @@ var init_listen = __esm({
9314
9329
  if (!tc) {
9315
9330
  this.emit("info", "Installing transcribe-cli...");
9316
9331
  try {
9317
- execSync10("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
9332
+ execSync9("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
9318
9333
  this.transcribeCliAvailable = null;
9319
9334
  tc = await this.loadTranscribeCli();
9320
9335
  } catch {
@@ -9451,7 +9466,7 @@ var init_listen = __esm({
9451
9466
  }
9452
9467
  if (!tc) {
9453
9468
  try {
9454
- execSync10("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
9469
+ execSync9("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
9455
9470
  this.transcribeCliAvailable = null;
9456
9471
  tc = await this.loadTranscribeCli();
9457
9472
  } catch {
@@ -9588,6 +9603,21 @@ var init_model_picker = __esm({
9588
9603
  function ansi2(code, text) {
9589
9604
  return isTTY2 ? `\x1B[${code}m${text}\x1B[0m` : text;
9590
9605
  }
9606
+ function fg256(code, text) {
9607
+ return isTTY2 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
9608
+ }
9609
+ function setEmojisEnabled(enabled) {
9610
+ _emojisEnabled = enabled;
9611
+ }
9612
+ function getEmojisEnabled() {
9613
+ return _emojisEnabled;
9614
+ }
9615
+ function setColorsEnabled(enabled) {
9616
+ _colorsEnabled = enabled;
9617
+ }
9618
+ function getColorsEnabled() {
9619
+ return _colorsEnabled;
9620
+ }
9591
9621
  function getTermWidth() {
9592
9622
  return process.stdout.columns ?? 80;
9593
9623
  }
@@ -9623,12 +9653,14 @@ function renderToolCallStart(toolName, args) {
9623
9653
  const icon = TOOL_ICONS[toolName] ?? "\u{1F527}";
9624
9654
  const label = TOOL_LABELS[toolName] ?? toolName;
9625
9655
  const argsSummary = formatToolArgs(toolName, args);
9656
+ const colorFn = _colorsEnabled ? TOOL_COLORS[toolName] ?? c2.dim : (t) => t;
9657
+ const emojiPrefix = _emojisEnabled ? `${icon} ` : "";
9626
9658
  process.stdout.write(`
9627
- ${c2.dim("\u23BF")} ${icon} ${c2.bold(label)}${argsSummary ? c2.dim(": ") + argsSummary : ""}
9659
+ ${c2.dim("\u23BF")} ${emojiPrefix}${colorFn(c2.bold(label))}${argsSummary ? c2.dim(": ") + argsSummary : ""}
9628
9660
  `);
9629
9661
  }
9630
9662
  function renderToolResult(toolName, success, output) {
9631
- const icon = success ? c2.green("\u2714") : c2.red("\u2716");
9663
+ const icon = success ? _emojisEnabled ? c2.green("\u2714") : c2.green("+") : _emojisEnabled ? c2.red("\u2716") : c2.red("x");
9632
9664
  const maxLines = 8;
9633
9665
  const lines = output.split("\n").filter((l) => l.trim());
9634
9666
  if (lines.length === 0) {
@@ -9712,20 +9744,23 @@ function setContentWriteHook(hook) {
9712
9744
  }
9713
9745
  function renderError(message) {
9714
9746
  _contentWriteHook?.begin();
9747
+ const icon = _emojisEnabled ? c2.red("\u2716") : c2.red("E");
9715
9748
  process.stdout.write(`
9716
- ${c2.red("\u2716")} ${message}
9749
+ ${icon} ${message}
9717
9750
  `);
9718
9751
  _contentWriteHook?.end();
9719
9752
  }
9720
9753
  function renderInfo(message) {
9721
9754
  _contentWriteHook?.begin();
9722
- process.stdout.write(`${c2.cyan("\u2139")} ${message}
9755
+ const icon = _emojisEnabled ? c2.cyan("\u2139") : c2.cyan("i");
9756
+ process.stdout.write(`${icon} ${message}
9723
9757
  `);
9724
9758
  _contentWriteHook?.end();
9725
9759
  }
9726
9760
  function renderWarning(message) {
9727
9761
  _contentWriteHook?.begin();
9728
- process.stdout.write(`${c2.yellow("\u26A0")} ${message}
9762
+ const icon = _emojisEnabled ? c2.yellow("\u26A0") : c2.yellow("!");
9763
+ process.stdout.write(`${icon} ${message}
9729
9764
  `);
9730
9765
  _contentWriteHook?.end();
9731
9766
  }
@@ -9966,7 +10001,7 @@ function formatDuration2(ms) {
9966
10001
  const secs = Math.floor(totalSecs % 60);
9967
10002
  return `${mins}m ${secs}s`;
9968
10003
  }
9969
- var isTTY2, c2, TOOL_ICONS, TOOL_LABELS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
10004
+ var isTTY2, c2, pastel, _emojisEnabled, _colorsEnabled, TOOL_ICONS, TOOL_LABELS, TOOL_COLORS, _contentWriteHook, HINTS, TOOL_NAMES, COMMAND_NAMES;
9970
10005
  var init_render = __esm({
9971
10006
  "packages/cli/dist/tui/render.js"() {
9972
10007
  "use strict";
@@ -9985,6 +10020,20 @@ var init_render = __esm({
9985
10020
  bgBlue: (t) => ansi2("44", t),
9986
10021
  bgGreen: (t) => ansi2("42", t)
9987
10022
  };
10023
+ pastel = {
10024
+ pink: (t) => fg256(218, t),
10025
+ peach: (t) => fg256(216, t),
10026
+ lavender: (t) => fg256(183, t),
10027
+ mint: (t) => fg256(158, t),
10028
+ sky: (t) => fg256(117, t),
10029
+ coral: (t) => fg256(209, t),
10030
+ lilac: (t) => fg256(177, t),
10031
+ sage: (t) => fg256(151, t),
10032
+ butter: (t) => fg256(229, t),
10033
+ ice: (t) => fg256(153, t)
10034
+ };
10035
+ _emojisEnabled = true;
10036
+ _colorsEnabled = true;
9988
10037
  TOOL_ICONS = {
9989
10038
  file_read: "\u{1F4C4}",
9990
10039
  file_write: "\u{1F4DD}",
@@ -10053,6 +10102,37 @@ var init_render = __esm({
10053
10102
  transcribe_file: "Transcribe",
10054
10103
  transcribe_url: "Transcribe URL"
10055
10104
  };
10105
+ TOOL_COLORS = {
10106
+ file_read: pastel.sky,
10107
+ file_write: pastel.peach,
10108
+ file_edit: pastel.coral,
10109
+ shell: pastel.mint,
10110
+ grep_search: pastel.lavender,
10111
+ find_files: pastel.lilac,
10112
+ list_directory: pastel.sage,
10113
+ web_search: pastel.ice,
10114
+ web_fetch: pastel.ice,
10115
+ memory_read: pastel.butter,
10116
+ memory_write: pastel.butter,
10117
+ task_complete: pastel.mint,
10118
+ aiwg_setup: pastel.pink,
10119
+ aiwg_health: pastel.pink,
10120
+ aiwg_workflow: pastel.pink,
10121
+ batch_edit: pastel.coral,
10122
+ codebase_map: pastel.lilac,
10123
+ diagnostic: pastel.peach,
10124
+ git_info: pastel.sage,
10125
+ background_run: pastel.lavender,
10126
+ task_status: pastel.lavender,
10127
+ task_output: pastel.lavender,
10128
+ task_stop: pastel.lavender,
10129
+ sub_agent: pastel.sky,
10130
+ image_read: pastel.pink,
10131
+ screenshot: pastel.pink,
10132
+ ocr: pastel.pink,
10133
+ transcribe_file: pastel.peach,
10134
+ transcribe_url: pastel.peach
10135
+ };
10056
10136
  _contentWriteHook = null;
10057
10137
  HINTS = [
10058
10138
  "Use /voice to enable TTS voice feedback while the agent works",
@@ -10534,7 +10614,7 @@ async function handleSlashCommand(input, ctx) {
10534
10614
  return "handled";
10535
10615
  case "update":
10536
10616
  case "upgrade":
10537
- await handleUpdate(arg, ctx.repoRoot, ctx.savePendingTaskState);
10617
+ await handleUpdate(arg, ctx.repoRoot);
10538
10618
  return "handled";
10539
10619
  case "voice": {
10540
10620
  const save = hasLocal ? ctx.saveLocalSettings.bind(ctx) : ctx.saveSettings.bind(ctx);
@@ -10679,6 +10759,26 @@ async function handleSlashCommand(input, ctx) {
10679
10759
  renderInfo(`Brute-force mode: ${isOn ? "on" : "off"}${hasLocal ? " (project-local)" : ""}` + (isOn ? " \u2014 agent will auto re-engage when turn limit is hit, reassess and try creative strategies" : ""));
10680
10760
  return "handled";
10681
10761
  }
10762
+ case "emojis":
10763
+ case "emoji": {
10764
+ const current = ctx.getEmojis?.() ?? true;
10765
+ const next = !current;
10766
+ ctx.setEmojis?.(next);
10767
+ const save = hasLocal ? ctx.saveLocalSettings.bind(ctx) : ctx.saveSettings.bind(ctx);
10768
+ save({ emojis: next });
10769
+ renderInfo(`Emojis ${next ? "enabled" : "disabled"}.`);
10770
+ return "handled";
10771
+ }
10772
+ case "colors":
10773
+ case "color": {
10774
+ const current = ctx.getColors?.() ?? true;
10775
+ const next = !current;
10776
+ ctx.setColors?.(next);
10777
+ const save = hasLocal ? ctx.saveLocalSettings.bind(ctx) : ctx.saveSettings.bind(ctx);
10778
+ save({ colors: next });
10779
+ renderInfo(`Colors ${next ? "enabled" : "disabled"}.`);
10780
+ return "handled";
10781
+ }
10682
10782
  default: {
10683
10783
  const skills = discoverSkills(ctx.repoRoot);
10684
10784
  const skill = skills.find((s) => s.name === cmd || s.name === cmd.replace(/_/g, "-"));
@@ -10804,7 +10904,7 @@ async function handleEndpoint(arg, ctx, local = false) {
10804
10904
  }
10805
10905
  process.stdout.write("\n");
10806
10906
  }
10807
- async function handleUpdate(subcommand, repoRoot, savePendingTaskState) {
10907
+ async function handleUpdate(subcommand, repoRoot) {
10808
10908
  if (subcommand === "auto") {
10809
10909
  const settings = { updateMode: "auto" };
10810
10910
  saveProjectSettings(repoRoot, settings);
@@ -10855,26 +10955,17 @@ async function handleUpdate(subcommand, repoRoot, savePendingTaskState) {
10855
10955
  }
10856
10956
  process.stdout.write(` ${c2.yellow("\u26A0")} Update available: v${info.currentVersion} \u2192 v${c2.bold(c2.green(info.latestVersion))}
10857
10957
  `);
10858
- process.stdout.write(` ${c2.cyan("\u25CF")} Installing update...
10958
+ process.stdout.write(` ${c2.cyan("\u25CF")} Installing in background...
10859
10959
 
10860
10960
  `);
10861
- const success = performUpdate();
10862
- if (!success) {
10863
- renderError("Update failed. Try manually: npm i -g open-agents-ai");
10864
- return;
10865
- }
10866
- if (savePendingTaskState) {
10867
- try {
10868
- savePendingTaskState();
10869
- } catch {
10961
+ const { exec } = await import("node:child_process");
10962
+ exec(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { timeout: 18e4 }, (err) => {
10963
+ if (err) {
10964
+ renderWarning("Update install failed. Try manually: npm i -g open-agents-ai");
10965
+ } else {
10966
+ renderInfo(`${c2.green("\u2714")} Updated to v${info.latestVersion}. Takes effect next session.`);
10870
10967
  }
10871
- }
10872
- process.env.__OA_RESUMED = "1";
10873
- process.stdout.write(`
10874
- ${c2.green("\u2714")} Updated to v${info.latestVersion}. Restarting...
10875
-
10876
- `);
10877
- restartProcess();
10968
+ });
10878
10969
  }
10879
10970
  async function switchModel(query, ctx, local = false) {
10880
10971
  try {
@@ -10917,7 +11008,7 @@ var init_commands = __esm({
10917
11008
 
10918
11009
  // packages/cli/dist/tui/setup.js
10919
11010
  import * as readline from "node:readline";
10920
- import { execSync as execSync11 } from "node:child_process";
11011
+ import { execSync as execSync10 } from "node:child_process";
10921
11012
  import { existsSync as existsSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
10922
11013
  import { join as join18 } from "node:path";
10923
11014
  import { homedir as homedir8 } from "node:os";
@@ -10927,7 +11018,7 @@ function detectSystemSpecs() {
10927
11018
  let gpuVramGB = 0;
10928
11019
  let gpuName = "";
10929
11020
  try {
10930
- const memInfo = execSync11("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
11021
+ const memInfo = execSync10("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
10931
11022
  encoding: "utf8",
10932
11023
  timeout: 5e3
10933
11024
  });
@@ -10947,7 +11038,7 @@ function detectSystemSpecs() {
10947
11038
  } catch {
10948
11039
  }
10949
11040
  try {
10950
- const nvidiaSmi = execSync11("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
11041
+ const nvidiaSmi = execSync10("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
10951
11042
  const lines = nvidiaSmi.trim().split("\n");
10952
11043
  if (lines.length > 0) {
10953
11044
  for (const line of lines) {
@@ -11009,7 +11100,7 @@ function ask(rl, question) {
11009
11100
  }
11010
11101
  function pullModelWithAutoUpdate(tag) {
11011
11102
  try {
11012
- execSync11(`ollama pull ${tag}`, {
11103
+ execSync10(`ollama pull ${tag}`, {
11013
11104
  stdio: "inherit",
11014
11105
  timeout: 36e5
11015
11106
  // 1 hour max
@@ -11026,7 +11117,7 @@ function pullModelWithAutoUpdate(tag) {
11026
11117
 
11027
11118
  `);
11028
11119
  try {
11029
- execSync11("curl -fsSL https://ollama.com/install.sh | sh", {
11120
+ execSync10("curl -fsSL https://ollama.com/install.sh | sh", {
11030
11121
  stdio: "inherit",
11031
11122
  timeout: 3e5
11032
11123
  // 5 min max for install
@@ -11037,7 +11128,7 @@ function pullModelWithAutoUpdate(tag) {
11037
11128
  process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
11038
11129
 
11039
11130
  `);
11040
- execSync11(`ollama pull ${tag}`, {
11131
+ execSync10(`ollama pull ${tag}`, {
11041
11132
  stdio: "inherit",
11042
11133
  timeout: 36e5
11043
11134
  });
@@ -11220,7 +11311,7 @@ async function doSetup(config, rl) {
11220
11311
  const modelfilePath = join18(modelDir2, `Modelfile.${customName}`);
11221
11312
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
11222
11313
  process.stdout.write(` ${c2.dim("Creating model...")} `);
11223
- execSync11(`ollama create ${customName} -f ${modelfilePath}`, {
11314
+ execSync10(`ollama create ${customName} -f ${modelfilePath}`, {
11224
11315
  stdio: "pipe",
11225
11316
  timeout: 12e4
11226
11317
  });
@@ -11305,7 +11396,7 @@ var init_setup = __esm({
11305
11396
  // packages/cli/dist/tui/project-context.js
11306
11397
  import { existsSync as existsSync14, readFileSync as readFileSync11, readdirSync as readdirSync7 } from "node:fs";
11307
11398
  import { join as join19, basename as basename5 } from "node:path";
11308
- import { execSync as execSync12 } from "node:child_process";
11399
+ import { execSync as execSync11 } from "node:child_process";
11309
11400
  import { homedir as homedir9, platform, release } from "node:os";
11310
11401
  function loadProjectFiles(repoRoot) {
11311
11402
  const discovered = discoverContextFiles(repoRoot);
@@ -11336,19 +11427,19 @@ function loadProjectMap(repoRoot) {
11336
11427
  }
11337
11428
  function getGitInfo(repoRoot) {
11338
11429
  try {
11339
- execSync12("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
11430
+ execSync11("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
11340
11431
  } catch {
11341
11432
  return "";
11342
11433
  }
11343
11434
  const lines = [];
11344
11435
  try {
11345
- const branch = execSync12("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11436
+ const branch = execSync11("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11346
11437
  if (branch)
11347
11438
  lines.push(`Branch: ${branch}`);
11348
11439
  } catch {
11349
11440
  }
11350
11441
  try {
11351
- const status = execSync12("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11442
+ const status = execSync11("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11352
11443
  if (status) {
11353
11444
  const changed = status.split("\n").length;
11354
11445
  lines.push(`Working tree: ${changed} changed file(s)`);
@@ -11358,7 +11449,7 @@ function getGitInfo(repoRoot) {
11358
11449
  } catch {
11359
11450
  }
11360
11451
  try {
11361
- const log = execSync12("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11452
+ const log = execSync11("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
11362
11453
  if (log)
11363
11454
  lines.push(`Recent commits:
11364
11455
  ${log}`);
@@ -12406,7 +12497,7 @@ var init_carousel = __esm({
12406
12497
  import { existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync12, unlinkSync as unlinkSync3 } from "node:fs";
12407
12498
  import { join as join20 } from "node:path";
12408
12499
  import { homedir as homedir10, tmpdir as tmpdir2, platform as platform2 } from "node:os";
12409
- import { execSync as execSync13, spawn as nodeSpawn } from "node:child_process";
12500
+ import { execSync as execSync12, spawn as nodeSpawn } from "node:child_process";
12410
12501
  import { createRequire } from "node:module";
12411
12502
  function voiceDir() {
12412
12503
  return join20(homedir10(), ".open-agents", "voice");
@@ -12824,7 +12915,7 @@ var init_voice = __esm({
12824
12915
  }
12825
12916
  for (const player of ["paplay", "pw-play", "aplay"]) {
12826
12917
  try {
12827
- execSync13(`which ${player}`, { stdio: "pipe" });
12918
+ execSync12(`which ${player}`, { stdio: "pipe" });
12828
12919
  return [player, path];
12829
12920
  } catch {
12830
12921
  }
@@ -12875,7 +12966,7 @@ var init_voice = __esm({
12875
12966
  } catch {
12876
12967
  renderInfo("Installing ONNX runtime for voice synthesis...");
12877
12968
  try {
12878
- execSync13("npm install --no-audit --no-fund", {
12969
+ execSync12("npm install --no-audit --no-fund", {
12879
12970
  cwd: voiceDir(),
12880
12971
  stdio: "pipe",
12881
12972
  timeout: 12e4
@@ -12892,7 +12983,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
12892
12983
  } catch {
12893
12984
  renderInfo("Installing phonemizer for voice synthesis...");
12894
12985
  try {
12895
- execSync13("npm install --no-audit --no-fund", {
12986
+ execSync12("npm install --no-audit --no-fund", {
12896
12987
  cwd: voiceDir(),
12897
12988
  stdio: "pipe",
12898
12989
  timeout: 12e4
@@ -12978,7 +13069,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
12978
13069
  });
12979
13070
 
12980
13071
  // packages/cli/dist/tui/stream-renderer.js
12981
- function fg256(code, text) {
13072
+ function fg2562(code, text) {
12982
13073
  return isTTY4 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
12983
13074
  }
12984
13075
  function dimText(text) {
@@ -13268,12 +13359,12 @@ var init_stream_renderer = __esm({
13268
13359
  const colorKey = dim ? PASTEL.toolArg : PASTEL.key;
13269
13360
  const colorStr = dim ? PASTEL.toolArg : PASTEL.string;
13270
13361
  let result = line;
13271
- result = result.replace(/"([^"]*)"(\s*:)/g, (_m, key, colon) => fg256(colorKey, `"${key}"`) + fg256(PASTEL.colon, colon));
13272
- result = result.replace(/(:\s*)"([^"]*)"/g, (_m, prefix, val) => fg256(PASTEL.colon, prefix) + fg256(colorStr, `"${val}"`));
13273
- result = result.replace(/(:\s*)(\d+\.?\d*)/g, (_m, prefix, num) => fg256(PASTEL.colon, prefix) + fg256(PASTEL.number, num));
13274
- result = result.replace(/(:\s*)(true|false)/g, (_m, prefix, bool) => fg256(PASTEL.colon, prefix) + fg256(PASTEL.boolean, bool));
13275
- result = result.replace(/(:\s*)(null)/g, (_m, prefix, n) => fg256(PASTEL.colon, prefix) + fg256(PASTEL.null, n));
13276
- result = result.replace(/([{}[\]])/g, (_m, b) => fg256(PASTEL.bracket, b));
13362
+ result = result.replace(/"([^"]*)"(\s*:)/g, (_m, key, colon) => fg2562(colorKey, `"${key}"`) + fg2562(PASTEL.colon, colon));
13363
+ result = result.replace(/(:\s*)"([^"]*)"/g, (_m, prefix, val) => fg2562(PASTEL.colon, prefix) + fg2562(colorStr, `"${val}"`));
13364
+ result = result.replace(/(:\s*)(\d+\.?\d*)/g, (_m, prefix, num) => fg2562(PASTEL.colon, prefix) + fg2562(PASTEL.number, num));
13365
+ result = result.replace(/(:\s*)(true|false)/g, (_m, prefix, bool) => fg2562(PASTEL.colon, prefix) + fg2562(PASTEL.boolean, bool));
13366
+ result = result.replace(/(:\s*)(null)/g, (_m, prefix, n) => fg2562(PASTEL.colon, prefix) + fg2562(PASTEL.null, n));
13367
+ result = result.replace(/([{}[\]])/g, (_m, b) => fg2562(PASTEL.bracket, b));
13277
13368
  return dim ? dimText(result) : result;
13278
13369
  }
13279
13370
  /**
@@ -13281,13 +13372,13 @@ var init_stream_renderer = __esm({
13281
13372
  */
13282
13373
  highlightCode(line) {
13283
13374
  let result = line;
13284
- result = result.replace(/"([^"]*)"/g, (_m, s) => fg256(PASTEL.string, `"${s}"`));
13285
- result = result.replace(/'([^']*)'/g, (_m, s) => fg256(PASTEL.string, `'${s}'`));
13286
- result = result.replace(/\b(\d+\.?\d*)\b/g, (_m, n) => fg256(PASTEL.number, n));
13287
- result = result.replace(/\b(true|false|null|undefined|None|True|False)\b/g, (_m, kw) => fg256(PASTEL.boolean, kw));
13288
- result = result.replace(/\b(function|const|let|var|return|if|else|for|while|import|export|from|class|async|await|def|self|try|catch|finally|throw|new|typeof|instanceof|type|interface|enum|struct|impl|fn|pub|mod|use|match|trait|where|mut|ref|move|yield|switch|case|default|break|continue|do|in|of|extends|implements|super|this|static|abstract|override|readonly|declare|namespace|package|func|go|chan|select|defer|range|map)\b/g, (_m, kw) => fg256(PASTEL.keyword, kw));
13289
- result = result.replace(/:\s*([A-Z]\w*)/g, (_m, t) => ": " + fg256(147, t));
13290
- result = result.replace(/(\/\/.*$|#.*$)/gm, (_m, cm) => fg256(PASTEL.comment, cm));
13375
+ result = result.replace(/"([^"]*)"/g, (_m, s) => fg2562(PASTEL.string, `"${s}"`));
13376
+ result = result.replace(/'([^']*)'/g, (_m, s) => fg2562(PASTEL.string, `'${s}'`));
13377
+ result = result.replace(/\b(\d+\.?\d*)\b/g, (_m, n) => fg2562(PASTEL.number, n));
13378
+ result = result.replace(/\b(true|false|null|undefined|None|True|False)\b/g, (_m, kw) => fg2562(PASTEL.boolean, kw));
13379
+ result = result.replace(/\b(function|const|let|var|return|if|else|for|while|import|export|from|class|async|await|def|self|try|catch|finally|throw|new|typeof|instanceof|type|interface|enum|struct|impl|fn|pub|mod|use|match|trait|where|mut|ref|move|yield|switch|case|default|break|continue|do|in|of|extends|implements|super|this|static|abstract|override|readonly|declare|namespace|package|func|go|chan|select|defer|range|map)\b/g, (_m, kw) => fg2562(PASTEL.keyword, kw));
13380
+ result = result.replace(/:\s*([A-Z]\w*)/g, (_m, t) => ": " + fg2562(147, t));
13381
+ result = result.replace(/(\/\/.*$|#.*$)/gm, (_m, cm) => fg2562(PASTEL.comment, cm));
13291
13382
  return result;
13292
13383
  }
13293
13384
  // -------------------------------------------------------------------------
@@ -13299,30 +13390,30 @@ var init_stream_renderer = __esm({
13299
13390
  */
13300
13391
  highlightDiff(line) {
13301
13392
  if (/^[-]{3}\s/.test(line) || /^[+]{3}\s/.test(line)) {
13302
- return boldText(fg256(PASTEL.diffMeta, line));
13393
+ return boldText(fg2562(PASTEL.diffMeta, line));
13303
13394
  }
13304
13395
  if (line.startsWith("@@")) {
13305
- return fg256(PASTEL.diffHunk, line);
13396
+ return fg2562(PASTEL.diffHunk, line);
13306
13397
  }
13307
13398
  if (line.startsWith("diff ") || line.startsWith("index ")) {
13308
- return fg256(PASTEL.diffMeta, line);
13399
+ return fg2562(PASTEL.diffMeta, line);
13309
13400
  }
13310
13401
  if (line.startsWith("+")) {
13311
- return fg256(PASTEL.diffAdded, line);
13402
+ return fg2562(PASTEL.diffAdded, line);
13312
13403
  }
13313
13404
  if (line.startsWith("-")) {
13314
- return fg256(PASTEL.diffRemoved, line);
13405
+ return fg2562(PASTEL.diffRemoved, line);
13315
13406
  }
13316
13407
  if (/^\s*\d+\s*[+-]\s/.test(line)) {
13317
13408
  const match = line.match(/^(\s*\d+\s*)([+-])(\s.*)$/);
13318
13409
  if (match) {
13319
- const num = fg256(PASTEL.diffContext, match[1]);
13320
- const sign = match[2] === "+" ? fg256(PASTEL.diffAdded, "+") : fg256(PASTEL.diffRemoved, "-");
13321
- const rest = match[2] === "+" ? fg256(PASTEL.diffAdded, match[3]) : fg256(PASTEL.diffRemoved, match[3]);
13410
+ const num = fg2562(PASTEL.diffContext, match[1]);
13411
+ const sign = match[2] === "+" ? fg2562(PASTEL.diffAdded, "+") : fg2562(PASTEL.diffRemoved, "-");
13412
+ const rest = match[2] === "+" ? fg2562(PASTEL.diffAdded, match[3]) : fg2562(PASTEL.diffRemoved, match[3]);
13322
13413
  return num + sign + rest;
13323
13414
  }
13324
13415
  }
13325
- return fg256(PASTEL.diffContext, line);
13416
+ return fg2562(PASTEL.diffContext, line);
13326
13417
  }
13327
13418
  // -------------------------------------------------------------------------
13328
13419
  // Shell / bash highlighting
@@ -13332,16 +13423,16 @@ var init_stream_renderer = __esm({
13332
13423
  */
13333
13424
  highlightShell(line) {
13334
13425
  if (/^\s*#/.test(line)) {
13335
- return fg256(PASTEL.comment, line);
13426
+ return fg2562(PASTEL.comment, line);
13336
13427
  }
13337
13428
  let result = line;
13338
- result = result.replace(/"([^"]*)"/g, (_m, s) => fg256(PASTEL.string, `"${s}"`));
13339
- result = result.replace(/'([^']*)'/g, (_m, s) => fg256(PASTEL.string, `'${s}'`));
13340
- result = result.replace(/(\$\{[^}]+\}|\$[A-Za-z_]\w*|\$[0-9?@#*!$-])/g, (_m, v) => fg256(PASTEL.shellVar, v));
13341
- result = result.replace(/((?:^|\s))(--?[a-zA-Z][\w-]*)/g, (_m, ws, flag) => ws + fg256(PASTEL.shellFlag, flag));
13342
- result = result.replace(/(\|{1,2}|>{1,2}|<{1,2}|&{1,2}|;)/g, (_m, op) => fg256(PASTEL.shellOp, op));
13343
- result = result.replace(/^(\s*)(npm|npx|node|pnpm|yarn|git|docker|kubectl|curl|wget|cat|grep|find|ls|cd|cp|mv|rm|mkdir|chmod|chown|echo|printf|sed|awk|sort|uniq|head|tail|wc|tar|gzip|make|cargo|go|pip|python|python3|ruby|gem|brew|apt|yum|dnf|pacman|sudo|ssh|scp|rsync|man)\b/, (_m, ws, cmd) => ws + boldText(fg256(PASTEL.keyword, cmd)));
13344
- result = result.replace(/(#[^{].*$)/gm, (_m, cm) => fg256(PASTEL.comment, cm));
13429
+ result = result.replace(/"([^"]*)"/g, (_m, s) => fg2562(PASTEL.string, `"${s}"`));
13430
+ result = result.replace(/'([^']*)'/g, (_m, s) => fg2562(PASTEL.string, `'${s}'`));
13431
+ result = result.replace(/(\$\{[^}]+\}|\$[A-Za-z_]\w*|\$[0-9?@#*!$-])/g, (_m, v) => fg2562(PASTEL.shellVar, v));
13432
+ result = result.replace(/((?:^|\s))(--?[a-zA-Z][\w-]*)/g, (_m, ws, flag) => ws + fg2562(PASTEL.shellFlag, flag));
13433
+ result = result.replace(/(\|{1,2}|>{1,2}|<{1,2}|&{1,2}|;)/g, (_m, op) => fg2562(PASTEL.shellOp, op));
13434
+ result = result.replace(/^(\s*)(npm|npx|node|pnpm|yarn|git|docker|kubectl|curl|wget|cat|grep|find|ls|cd|cp|mv|rm|mkdir|chmod|chown|echo|printf|sed|awk|sort|uniq|head|tail|wc|tar|gzip|make|cargo|go|pip|python|python3|ruby|gem|brew|apt|yum|dnf|pacman|sudo|ssh|scp|rsync|man)\b/, (_m, ws, cmd) => ws + boldText(fg2562(PASTEL.keyword, cmd)));
13435
+ result = result.replace(/(#[^{].*$)/gm, (_m, cm) => fg2562(PASTEL.comment, cm));
13345
13436
  return result;
13346
13437
  }
13347
13438
  // -------------------------------------------------------------------------
@@ -13356,23 +13447,23 @@ var init_stream_renderer = __esm({
13356
13447
  const level = headingMatch[1].length;
13357
13448
  const text = headingMatch[2];
13358
13449
  const colors = [PASTEL.heading1, PASTEL.heading2, PASTEL.heading3, PASTEL.heading3, 183, 183];
13359
- return boldText(fg256(colors[level - 1] ?? 147, text));
13450
+ return boldText(fg2562(colors[level - 1] ?? 147, text));
13360
13451
  }
13361
13452
  if (/^[-*_]{3,}\s*$/.test(line)) {
13362
13453
  const w = (process.stdout.columns ?? 80) - 10;
13363
- return fg256(PASTEL.hr, "\u2500".repeat(Math.min(w, 60)));
13454
+ return fg2562(PASTEL.hr, "\u2500".repeat(Math.min(w, 60)));
13364
13455
  }
13365
13456
  if (/^>\s?/.test(line)) {
13366
13457
  const content = line.replace(/^>\s?/, "");
13367
- return fg256(PASTEL.blockquote, "\u2502 ") + italicText(fg256(PASTEL.blockquote, this.highlightInline(content)));
13458
+ return fg2562(PASTEL.blockquote, "\u2502 ") + italicText(fg2562(PASTEL.blockquote, this.highlightInline(content)));
13368
13459
  }
13369
13460
  const ulMatch = line.match(/^(\s*)([-*+])\s+(.*)/);
13370
13461
  if (ulMatch) {
13371
- return ulMatch[1] + fg256(PASTEL.blockquote, "\u2022") + " " + this.highlightInline(ulMatch[3]);
13462
+ return ulMatch[1] + fg2562(PASTEL.blockquote, "\u2022") + " " + this.highlightInline(ulMatch[3]);
13372
13463
  }
13373
13464
  const olMatch = line.match(/^(\s*)(\d+[.)])\s+(.*)/);
13374
13465
  if (olMatch) {
13375
- return olMatch[1] + fg256(PASTEL.blockquote, olMatch[2]) + " " + this.highlightInline(olMatch[3]);
13466
+ return olMatch[1] + fg2562(PASTEL.blockquote, olMatch[2]) + " " + this.highlightInline(olMatch[3]);
13376
13467
  }
13377
13468
  return this.highlightInline(line);
13378
13469
  }
@@ -13381,11 +13472,11 @@ var init_stream_renderer = __esm({
13381
13472
  */
13382
13473
  highlightInline(text) {
13383
13474
  let result = text;
13384
- result = result.replace(/`([^`]+)`/g, (_m, code) => fg256(PASTEL.inlineCode, code));
13475
+ result = result.replace(/`([^`]+)`/g, (_m, code) => fg2562(PASTEL.inlineCode, code));
13385
13476
  result = result.replace(/\*{3}([^*]+)\*{3}/g, (_m, t) => boldText(italicText(t)));
13386
13477
  result = result.replace(/\*{2}([^*]+)\*{2}/g, (_m, t) => boldText(t));
13387
13478
  result = result.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, (_m, t) => italicText(t));
13388
- result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => boldText(fg256(PASTEL.link, label)) + " " + dimText(fg256(PASTEL.link, `(${url})`)));
13479
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => boldText(fg2562(PASTEL.link, label)) + " " + dimText(fg2562(PASTEL.link, `(${url})`)));
13389
13480
  result = result.replace(/__([^_]+)__/g, (_m, t) => boldText(t));
13390
13481
  result = result.replace(/(?<!_)_([^_]+)_(?!_)/g, (_m, t) => italicText(t));
13391
13482
  result = result.replace(/~~([^~]+)~~/g, (_m, t) => dimText(t));
@@ -13539,7 +13630,7 @@ var init_edit_history = __esm({
13539
13630
  // packages/cli/dist/tui/dream-engine.js
13540
13631
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync13, existsSync as existsSync16, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
13541
13632
  import { join as join22, basename as basename6 } from "node:path";
13542
- import { execSync as execSync14 } from "node:child_process";
13633
+ import { execSync as execSync13 } from "node:child_process";
13543
13634
  function adaptTool(tool) {
13544
13635
  return {
13545
13636
  name: tool.name,
@@ -13792,7 +13883,7 @@ var init_dream_engine = __esm({
13792
13883
  }
13793
13884
  }
13794
13885
  try {
13795
- const output = execSync14(cmd, {
13886
+ const output = execSync13(cmd, {
13796
13887
  cwd: this.repoRoot,
13797
13888
  timeout: 3e4,
13798
13889
  encoding: "utf-8",
@@ -14012,17 +14103,17 @@ Dreams directory: ${this.dreamsDir}`);
14012
14103
  try {
14013
14104
  mkdirSync10(checkpointDir, { recursive: true });
14014
14105
  try {
14015
- const gitStatus = execSync14("git status --porcelain", {
14106
+ const gitStatus = execSync13("git status --porcelain", {
14016
14107
  cwd: this.repoRoot,
14017
14108
  encoding: "utf-8",
14018
14109
  timeout: 1e4
14019
14110
  });
14020
- const gitDiff = execSync14("git diff", {
14111
+ const gitDiff = execSync13("git diff", {
14021
14112
  cwd: this.repoRoot,
14022
14113
  encoding: "utf-8",
14023
14114
  timeout: 1e4
14024
14115
  });
14025
- const gitHash = execSync14("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
14116
+ const gitHash = execSync13("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
14026
14117
  cwd: this.repoRoot,
14027
14118
  encoding: "utf-8",
14028
14119
  timeout: 5e3
@@ -14153,6 +14244,8 @@ var init_status_bar = __esm({
14153
14244
  _recording = false;
14154
14245
  /** Countdown seconds for auto-mode silence timeout (0 = not counting down) */
14155
14246
  _countdown = 0;
14247
+ _recBlink = true;
14248
+ _recBlinkTimer = null;
14156
14249
  /**
14157
14250
  * Provide a callback that returns readline's current input state.
14158
14251
  * StatusBar uses this to render typed text and position the cursor
@@ -14164,8 +14257,21 @@ var init_status_bar = __esm({
14164
14257
  /** Set recording indicator state (blinking red ●) */
14165
14258
  setRecording(active) {
14166
14259
  this._recording = active;
14167
- if (!active)
14260
+ if (active) {
14261
+ this._recBlink = true;
14262
+ this._recBlinkTimer = setInterval(() => {
14263
+ this._recBlink = !this._recBlink;
14264
+ if (this.active)
14265
+ this.renderFooterPreserveCursor();
14266
+ }, 500);
14267
+ } else {
14268
+ if (this._recBlinkTimer) {
14269
+ clearInterval(this._recBlinkTimer);
14270
+ this._recBlinkTimer = null;
14271
+ }
14272
+ this._recBlink = true;
14168
14273
  this._countdown = 0;
14274
+ }
14169
14275
  if (this.active)
14170
14276
  this.renderFooterPreserveCursor();
14171
14277
  }
@@ -14325,7 +14431,7 @@ var init_status_bar = __esm({
14325
14431
  const ctxLabel = c2.blue("Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
14326
14432
  let recordingLabel = "";
14327
14433
  if (this._recording) {
14328
- const dot = c2.red("\u25CF");
14434
+ const dot = this._recBlink ? c2.red("\u25CF") : " ";
14329
14435
  const countdown = this._countdown > 0 ? c2.dim(` ${this._countdown}s`) : "";
14330
14436
  recordingLabel = pipe + dot + c2.red(" REC") + countdown;
14331
14437
  }
@@ -14562,7 +14668,7 @@ function buildTools(repoRoot, config) {
14562
14668
  function createSubAgentTool(config, repoRoot) {
14563
14669
  return {
14564
14670
  name: "sub_agent",
14565
- description: "Delegate a sub-task to an independent agent with its own context window. The sub-agent has access to all tools and works autonomously until completion. Use for: parallel exploration, independent sub-tasks, different approaches. Set background=true to run without blocking (check results via task_status/task_output).",
14671
+ description: "Delegate a sub-task to an independent agent with its own context window. Each sub-agent creates an independent backend connection, enabling TRUE PARALLEL inference when the backend supports concurrent requests (Ollama with OLLAMA_NUM_PARALLEL > 1). BEST PRACTICE: Launch multiple sub_agent calls with background=true in ONE response to maximize parallelism. Check results via task_status/task_output.",
14566
14672
  parameters: {
14567
14673
  type: "object",
14568
14674
  properties: {
@@ -14845,6 +14951,10 @@ async function startInteractive(config, repoPath) {
14845
14951
  config = { ...config, dbPath: savedSettings.dbPath };
14846
14952
  let streamEnabled = savedSettings.stream ?? false;
14847
14953
  let bruteForceEnabled = savedSettings.bruteforce ?? false;
14954
+ if (savedSettings.emojis !== void 0)
14955
+ setEmojisEnabled(savedSettings.emojis);
14956
+ if (savedSettings.colors !== void 0)
14957
+ setColorsEnabled(savedSettings.colors);
14848
14958
  if (!isResumed) {
14849
14959
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
14850
14960
  if (needsSetup && config.backendType === "ollama") {
@@ -15127,7 +15237,11 @@ async function startInteractive(config, repoPath) {
15127
15237
  const text = await engine.stop();
15128
15238
  statusBar.setRecording(false);
15129
15239
  return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
15130
- }
15240
+ },
15241
+ getEmojis: () => getEmojisEnabled(),
15242
+ setEmojis: (enabled) => setEmojisEnabled(enabled),
15243
+ getColors: () => getColorsEnabled(),
15244
+ setColors: (enabled) => setColorsEnabled(enabled)
15131
15245
  };
15132
15246
  showPrompt();
15133
15247
  if (isResumed) {
@@ -15330,21 +15444,12 @@ Summarize or analyze this transcription as appropriate.`;
15330
15444
  try {
15331
15445
  const updateInfo = await checkForUpdate(version);
15332
15446
  if (updateInfo) {
15333
- writeContent(() => renderInfo(`Update available: v${version} \u2192 v${updateInfo.latestVersion}. Installing...`));
15334
- const ok = performSilentUpdate();
15335
- if (ok) {
15336
- writeContent(() => renderInfo(`Updated to v${updateInfo.latestVersion}. Reloading...
15337
- `));
15338
- process.env.__OA_RESUMED = "1";
15339
- statusBar.deactivate();
15340
- if (carousel.isRunning)
15341
- carousel.stop();
15342
- voiceEngine.dispose();
15343
- rl.close();
15344
- restartProcess();
15345
- } else {
15346
- writeContent(() => renderWarning("Auto-update failed. Use /update to retry manually."));
15347
- }
15447
+ const { exec } = await import("node:child_process");
15448
+ exec(`npm install -g open-agents-ai@latest --prefer-online`, { timeout: 18e4 }, (err) => {
15449
+ if (!err) {
15450
+ writeContent(() => renderInfo(`Updated to v${updateInfo.latestVersion} in background. Takes effect next session.`));
15451
+ }
15452
+ });
15348
15453
  }
15349
15454
  } catch {
15350
15455
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.14.9",
3
+ "version": "0.15.1",
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",