open-agents-ai 0.13.3 → 0.13.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.
Files changed (2) hide show
  1. package/dist/index.js +305 -37
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4493,8 +4493,9 @@ var init_tool_creator = __esm({
4493
4493
 
4494
4494
  // packages/execution/dist/tools/skill-tools.js
4495
4495
  import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
4496
- import { join as join12, basename as basename2 } from "node:path";
4496
+ import { join as join12, basename as basename2, dirname as dirname2 } from "node:path";
4497
4497
  import { homedir as homedir4 } from "node:os";
4498
+ import { execSync as execSync8 } from "node:child_process";
4498
4499
  function getAiwgPaths() {
4499
4500
  const dataDir = join12(homedir4(), ".local", "share", "ai-writing-guide");
4500
4501
  return {
@@ -4503,9 +4504,72 @@ function getAiwgPaths() {
4503
4504
  pluginsDir: join12(dataDir, "plugins")
4504
4505
  };
4505
4506
  }
4507
+ function findAiwgPackageRoot() {
4508
+ if (_cachedAiwgPkgRoot !== void 0)
4509
+ return _cachedAiwgPkgRoot;
4510
+ try {
4511
+ const globalRoot = execSync8("npm root -g", {
4512
+ encoding: "utf-8",
4513
+ timeout: 5e3,
4514
+ stdio: ["pipe", "pipe", "pipe"]
4515
+ }).trim();
4516
+ const candidate = join12(globalRoot, "aiwg");
4517
+ if (existsSync9(join12(candidate, "package.json"))) {
4518
+ _cachedAiwgPkgRoot = candidate;
4519
+ return candidate;
4520
+ }
4521
+ } catch {
4522
+ }
4523
+ const candidates = [
4524
+ "/usr/local/lib/node_modules/aiwg",
4525
+ "/usr/lib/node_modules/aiwg",
4526
+ join12(homedir4(), ".nvm", "versions")
4527
+ // nvm — need to search deeper
4528
+ ];
4529
+ for (const c3 of candidates) {
4530
+ if (c3.includes(".nvm")) {
4531
+ if (existsSync9(c3)) {
4532
+ try {
4533
+ for (const ver of readdirSync5(join12(c3, "node"), { withFileTypes: true })) {
4534
+ if (!ver.isDirectory())
4535
+ continue;
4536
+ const nvmPath = join12(c3, "node", ver.name, "lib", "node_modules", "aiwg");
4537
+ if (existsSync9(join12(nvmPath, "package.json"))) {
4538
+ _cachedAiwgPkgRoot = nvmPath;
4539
+ return nvmPath;
4540
+ }
4541
+ }
4542
+ } catch {
4543
+ }
4544
+ }
4545
+ } else if (existsSync9(join12(c3, "package.json"))) {
4546
+ _cachedAiwgPkgRoot = c3;
4547
+ return c3;
4548
+ }
4549
+ }
4550
+ _cachedAiwgPkgRoot = null;
4551
+ return null;
4552
+ }
4506
4553
  function discoverSkills(repoRoot) {
4507
4554
  const skills = /* @__PURE__ */ new Map();
4508
4555
  const { frameworksDir, addonsDir, pluginsDir } = getAiwgPaths();
4556
+ const pkgRoot = findAiwgPackageRoot();
4557
+ if (pkgRoot) {
4558
+ const pkgFrameworks = join12(pkgRoot, "agentic", "code", "frameworks");
4559
+ if (existsSync9(pkgFrameworks)) {
4560
+ for (const fw of safeReaddir(pkgFrameworks)) {
4561
+ const skillsDir = join12(pkgFrameworks, fw, "skills");
4562
+ loadSkillsFromDir(skillsDir, `framework:${fw}`, skills);
4563
+ }
4564
+ }
4565
+ const pkgPlugins = join12(pkgRoot, "plugins");
4566
+ if (existsSync9(pkgPlugins)) {
4567
+ for (const plugin of safeReaddir(pkgPlugins)) {
4568
+ const skillsDir = join12(pkgPlugins, plugin, "skills");
4569
+ loadSkillsFromDir(skillsDir, `plugin:${plugin}`, skills);
4570
+ }
4571
+ }
4572
+ }
4509
4573
  if (existsSync9(frameworksDir)) {
4510
4574
  for (const framework of safeReaddir(frameworksDir)) {
4511
4575
  const skillsDir = join12(frameworksDir, framework, "skills");
@@ -4652,7 +4716,7 @@ function parseTriggers(filePath) {
4652
4716
  }
4653
4717
  return triggers;
4654
4718
  }
4655
- var SkillListTool, SkillExecuteTool;
4719
+ var _cachedAiwgPkgRoot, SkillListTool, SkillExecuteTool;
4656
4720
  var init_skill_tools = __esm({
4657
4721
  "packages/execution/dist/tools/skill-tools.js"() {
4658
4722
  "use strict";
@@ -8784,8 +8848,9 @@ function renderToolResult(toolName, success, output) {
8784
8848
  }
8785
8849
  const shown = lines.slice(0, maxLines);
8786
8850
  for (const line of shown) {
8787
- const trimmed = line.length > getTermWidth() - 10 ? line.slice(0, getTermWidth() - 13) + "..." : line;
8788
- process.stdout.write(` ${c2.dim("\u23BF")} ${c2.dim(trimmed)}
8851
+ const maxW = getTermWidth() - 10;
8852
+ const trimmed = line.length > maxW ? line.slice(0, maxW - 3) + "..." : line;
8853
+ process.stdout.write(` ${c2.dim("\u23BF")} ${highlightToolOutput(trimmed)}
8789
8854
  `);
8790
8855
  }
8791
8856
  if (lines.length > maxLines) {
@@ -8793,6 +8858,25 @@ function renderToolResult(toolName, success, output) {
8793
8858
  `);
8794
8859
  }
8795
8860
  }
8861
+ function highlightToolOutput(line) {
8862
+ if (line.startsWith("+") && !line.startsWith("+++"))
8863
+ return c2.green(line);
8864
+ if (line.startsWith("-") && !line.startsWith("---"))
8865
+ return c2.red(line);
8866
+ if (line.startsWith("@@"))
8867
+ return c2.cyan(line);
8868
+ if (line.startsWith("---") || line.startsWith("+++"))
8869
+ return c2.bold(line);
8870
+ if (/error/i.test(line) && !/0 error/i.test(line))
8871
+ return c2.red(line);
8872
+ if (/warning/i.test(line) && !/0 warning/i.test(line))
8873
+ return c2.yellow(line);
8874
+ if (/\bpass(ed|ing)?\b/i.test(line))
8875
+ return c2.green(line);
8876
+ if (/\bfail(ed|ing|ure)?\b/i.test(line))
8877
+ return c2.red(line);
8878
+ return c2.dim(line);
8879
+ }
8796
8880
  function renderTaskComplete(summary, turns, toolCalls, durationMs, tokens) {
8797
8881
  const duration = formatDuration2(durationMs);
8798
8882
  const tokenStr = tokens ? ` ${formatTokenCount(tokens)}` : "";
@@ -9887,10 +9971,10 @@ async function handleUpdate(subcommand, repoRoot, savePendingTaskState) {
9887
9971
  try {
9888
9972
  const { createRequire: createRequire4 } = await import("node:module");
9889
9973
  const { fileURLToPath: fileURLToPath3 } = await import("node:url");
9890
- const { dirname: dirname4, join: join26 } = await import("node:path");
9974
+ const { dirname: dirname5, join: join26 } = await import("node:path");
9891
9975
  const { existsSync: existsSync17 } = await import("node:fs");
9892
9976
  const req = createRequire4(import.meta.url);
9893
- const thisDir = dirname4(fileURLToPath3(import.meta.url));
9977
+ const thisDir = dirname5(fileURLToPath3(import.meta.url));
9894
9978
  const candidates = [
9895
9979
  join26(thisDir, "..", "package.json"),
9896
9980
  join26(thisDir, "..", "..", "package.json"),
@@ -9981,7 +10065,7 @@ var init_commands = __esm({
9981
10065
 
9982
10066
  // packages/cli/dist/tui/setup.js
9983
10067
  import * as readline from "node:readline";
9984
- import { execSync as execSync8 } from "node:child_process";
10068
+ import { execSync as execSync9 } from "node:child_process";
9985
10069
  import { existsSync as existsSync11, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "node:fs";
9986
10070
  import { join as join16 } from "node:path";
9987
10071
  import { homedir as homedir6 } from "node:os";
@@ -9991,7 +10075,7 @@ function detectSystemSpecs() {
9991
10075
  let gpuVramGB = 0;
9992
10076
  let gpuName = "";
9993
10077
  try {
9994
- const memInfo = execSync8("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
10078
+ const memInfo = execSync9("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
9995
10079
  encoding: "utf8",
9996
10080
  timeout: 5e3
9997
10081
  });
@@ -10011,7 +10095,7 @@ function detectSystemSpecs() {
10011
10095
  } catch {
10012
10096
  }
10013
10097
  try {
10014
- const nvidiaSmi = execSync8("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
10098
+ const nvidiaSmi = execSync9("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
10015
10099
  const lines = nvidiaSmi.trim().split("\n");
10016
10100
  if (lines.length > 0) {
10017
10101
  for (const line of lines) {
@@ -10073,7 +10157,7 @@ function ask(rl, question) {
10073
10157
  }
10074
10158
  function pullModelWithAutoUpdate(tag) {
10075
10159
  try {
10076
- execSync8(`ollama pull ${tag}`, {
10160
+ execSync9(`ollama pull ${tag}`, {
10077
10161
  stdio: "inherit",
10078
10162
  timeout: 36e5
10079
10163
  // 1 hour max
@@ -10090,7 +10174,7 @@ function pullModelWithAutoUpdate(tag) {
10090
10174
 
10091
10175
  `);
10092
10176
  try {
10093
- execSync8("curl -fsSL https://ollama.com/install.sh | sh", {
10177
+ execSync9("curl -fsSL https://ollama.com/install.sh | sh", {
10094
10178
  stdio: "inherit",
10095
10179
  timeout: 3e5
10096
10180
  // 5 min max for install
@@ -10101,7 +10185,7 @@ function pullModelWithAutoUpdate(tag) {
10101
10185
  process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
10102
10186
 
10103
10187
  `);
10104
- execSync8(`ollama pull ${tag}`, {
10188
+ execSync9(`ollama pull ${tag}`, {
10105
10189
  stdio: "inherit",
10106
10190
  timeout: 36e5
10107
10191
  });
@@ -10284,7 +10368,7 @@ async function doSetup(config, rl) {
10284
10368
  const modelfilePath = join16(modelDir2, `Modelfile.${customName}`);
10285
10369
  writeFileSync5(modelfilePath, modelfileContent + "\n", "utf8");
10286
10370
  process.stdout.write(` ${c2.dim("Creating model...")} `);
10287
- execSync8(`ollama create ${customName} -f ${modelfilePath}`, {
10371
+ execSync9(`ollama create ${customName} -f ${modelfilePath}`, {
10288
10372
  stdio: "pipe",
10289
10373
  timeout: 12e4
10290
10374
  });
@@ -10369,7 +10453,7 @@ var init_setup = __esm({
10369
10453
  // packages/cli/dist/tui/project-context.js
10370
10454
  import { existsSync as existsSync12, readFileSync as readFileSync10, readdirSync as readdirSync7 } from "node:fs";
10371
10455
  import { join as join17, basename as basename4 } from "node:path";
10372
- import { execSync as execSync9 } from "node:child_process";
10456
+ import { execSync as execSync10 } from "node:child_process";
10373
10457
  import { homedir as homedir7, platform, release } from "node:os";
10374
10458
  function loadProjectFiles(repoRoot) {
10375
10459
  const discovered = discoverContextFiles(repoRoot);
@@ -10400,19 +10484,19 @@ function loadProjectMap(repoRoot) {
10400
10484
  }
10401
10485
  function getGitInfo(repoRoot) {
10402
10486
  try {
10403
- execSync9("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
10487
+ execSync10("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
10404
10488
  } catch {
10405
10489
  return "";
10406
10490
  }
10407
10491
  const lines = [];
10408
10492
  try {
10409
- const branch = execSync9("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10493
+ const branch = execSync10("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10410
10494
  if (branch)
10411
10495
  lines.push(`Branch: ${branch}`);
10412
10496
  } catch {
10413
10497
  }
10414
10498
  try {
10415
- const status = execSync9("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10499
+ const status = execSync10("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10416
10500
  if (status) {
10417
10501
  const changed = status.split("\n").length;
10418
10502
  lines.push(`Working tree: ${changed} changed file(s)`);
@@ -10422,7 +10506,7 @@ function getGitInfo(repoRoot) {
10422
10506
  } catch {
10423
10507
  }
10424
10508
  try {
10425
- const log = execSync9("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10509
+ const log = execSync10("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
10426
10510
  if (log)
10427
10511
  lines.push(`Recent commits:
10428
10512
  ${log}`);
@@ -11470,7 +11554,7 @@ var init_carousel = __esm({
11470
11554
  import { existsSync as existsSync13, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readFileSync as readFileSync11, unlinkSync as unlinkSync2 } from "node:fs";
11471
11555
  import { join as join18 } from "node:path";
11472
11556
  import { homedir as homedir8, tmpdir as tmpdir2, platform as platform2 } from "node:os";
11473
- import { execSync as execSync10, spawn as nodeSpawn } from "node:child_process";
11557
+ import { execSync as execSync11, spawn as nodeSpawn } from "node:child_process";
11474
11558
  import { createRequire } from "node:module";
11475
11559
  function voiceDir() {
11476
11560
  return join18(homedir8(), ".open-agents", "voice");
@@ -11888,7 +11972,7 @@ var init_voice = __esm({
11888
11972
  }
11889
11973
  for (const player of ["paplay", "pw-play", "aplay"]) {
11890
11974
  try {
11891
- execSync10(`which ${player}`, { stdio: "pipe" });
11975
+ execSync11(`which ${player}`, { stdio: "pipe" });
11892
11976
  return [player, path];
11893
11977
  } catch {
11894
11978
  }
@@ -11939,7 +12023,7 @@ var init_voice = __esm({
11939
12023
  } catch {
11940
12024
  renderInfo("Installing ONNX runtime for voice synthesis...");
11941
12025
  try {
11942
- execSync10("npm install --no-audit --no-fund", {
12026
+ execSync11("npm install --no-audit --no-fund", {
11943
12027
  cwd: voiceDir(),
11944
12028
  stdio: "pipe",
11945
12029
  timeout: 12e4
@@ -11956,7 +12040,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
11956
12040
  } catch {
11957
12041
  renderInfo("Installing phonemizer for voice synthesis...");
11958
12042
  try {
11959
- execSync10("npm install --no-audit --no-fund", {
12043
+ execSync11("npm install --no-audit --no-fund", {
11960
12044
  cwd: voiceDir(),
11961
12045
  stdio: "pipe",
11962
12046
  timeout: 12e4
@@ -12048,9 +12132,15 @@ function fg256(code, text) {
12048
12132
  function dimText(text) {
12049
12133
  return isTTY4 ? `\x1B[2m${text}\x1B[0m` : text;
12050
12134
  }
12135
+ function italicText(text) {
12136
+ return isTTY4 ? `\x1B[3m${text}\x1B[0m` : text;
12137
+ }
12051
12138
  function dimItalic(text) {
12052
12139
  return isTTY4 ? `\x1B[2;3m${text}\x1B[0m` : text;
12053
12140
  }
12141
+ function boldText(text) {
12142
+ return isTTY4 ? `\x1B[1m${text}\x1B[0m` : text;
12143
+ }
12054
12144
  var isTTY4, PASTEL, StreamRenderer;
12055
12145
  var init_stream_renderer = __esm({
12056
12146
  "packages/cli/dist/tui/stream-renderer.js"() {
@@ -12077,8 +12167,41 @@ var init_stream_renderer = __esm({
12077
12167
  // dim grey — // comments
12078
12168
  thinking: 245,
12079
12169
  // neutral grey for thinking tokens
12080
- toolArg: 111
12170
+ toolArg: 111,
12081
12171
  // dim periwinkle for tool arg tokens
12172
+ // Markdown
12173
+ heading1: 75,
12174
+ // blue — # headings
12175
+ heading2: 117,
12176
+ // sky blue — ## headings
12177
+ heading3: 147,
12178
+ // light blue — ### headings
12179
+ inlineCode: 223,
12180
+ // light peach — `code`
12181
+ link: 111,
12182
+ // periwinkle — [link](url)
12183
+ blockquote: 245,
12184
+ // grey — > quote
12185
+ hr: 240,
12186
+ // dark grey — ---
12187
+ // Diff / patch
12188
+ diffAdded: 114,
12189
+ // mint green — + lines
12190
+ diffRemoved: 210,
12191
+ // salmon — - lines
12192
+ diffHunk: 75,
12193
+ // blue — @@ headers
12194
+ diffMeta: 222,
12195
+ // gold — --- +++ file headers
12196
+ diffContext: 245,
12197
+ // grey — context lines
12198
+ // Shell
12199
+ shellVar: 222,
12200
+ // gold — $VAR
12201
+ shellFlag: 147,
12202
+ // light blue — --flag
12203
+ shellOp: 75
12204
+ // blue — | > >>
12082
12205
  };
12083
12206
  StreamRenderer = class {
12084
12207
  lineBuffer = "";
@@ -12211,6 +12334,7 @@ var init_stream_renderer = __esm({
12211
12334
  if (!raw)
12212
12335
  return;
12213
12336
  const prefix = this.lineStarted ? "" : " \u23BF ";
12337
+ const hasNewline = text.endsWith("\n");
12214
12338
  let rendered;
12215
12339
  switch (kind) {
12216
12340
  case "thinking":
@@ -12221,15 +12345,31 @@ var init_stream_renderer = __esm({
12221
12345
  break;
12222
12346
  case "content":
12223
12347
  if (this.inCodeBlock) {
12224
- rendered = this.highlightCode(raw);
12348
+ if (this.codeLang === "diff" || this.codeLang === "patch") {
12349
+ rendered = this.highlightDiff(raw);
12350
+ } else if (this.codeLang === "bash" || this.codeLang === "sh" || this.codeLang === "shell" || this.codeLang === "zsh") {
12351
+ rendered = this.highlightShell(raw);
12352
+ } else {
12353
+ rendered = this.highlightCode(raw);
12354
+ }
12225
12355
  } else if (this.looksLikeJson(raw)) {
12226
12356
  rendered = this.highlightJson(raw, false);
12227
12357
  } else {
12228
- rendered = raw;
12358
+ const maxW = (process.stdout.columns ?? 80) - 6;
12359
+ if (raw.length > maxW) {
12360
+ const wrapped = this.wordWrap(raw, maxW);
12361
+ for (let i = 0; i < wrapped.length; i++) {
12362
+ const lp = i === 0 ? prefix : " ";
12363
+ const isLast = i === wrapped.length - 1;
12364
+ this.writeRaw(dimText(lp) + this.highlightMarkdown(wrapped[i]) + (isLast && !hasNewline ? "" : "\n"));
12365
+ }
12366
+ this.lineStarted = !hasNewline;
12367
+ return;
12368
+ }
12369
+ rendered = this.highlightMarkdown(raw);
12229
12370
  }
12230
12371
  break;
12231
12372
  }
12232
- const hasNewline = text.endsWith("\n");
12233
12373
  this.writeRaw(dimText(prefix) + rendered + (hasNewline ? "\n" : ""));
12234
12374
  this.lineStarted = !hasNewline;
12235
12375
  }
@@ -12293,10 +12433,138 @@ var init_stream_renderer = __esm({
12293
12433
  result = result.replace(/'([^']*)'/g, (_m, s) => fg256(PASTEL.string, `'${s}'`));
12294
12434
  result = result.replace(/\b(\d+\.?\d*)\b/g, (_m, n) => fg256(PASTEL.number, n));
12295
12435
  result = result.replace(/\b(true|false|null|undefined|None|True|False)\b/g, (_m, kw) => fg256(PASTEL.boolean, kw));
12296
- 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)\b/g, (_m, kw) => fg256(PASTEL.keyword, kw));
12297
- result = result.replace(/(\/\/.*$|#.*$)/gm, (_m, c3) => fg256(PASTEL.comment, c3));
12436
+ 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));
12437
+ result = result.replace(/:\s*([A-Z]\w*)/g, (_m, t) => ": " + fg256(147, t));
12438
+ result = result.replace(/(\/\/.*$|#.*$)/gm, (_m, cm) => fg256(PASTEL.comment, cm));
12439
+ return result;
12440
+ }
12441
+ // -------------------------------------------------------------------------
12442
+ // Diff / patch highlighting
12443
+ // -------------------------------------------------------------------------
12444
+ /**
12445
+ * Highlight a diff/patch line with green/red coloring.
12446
+ * Handles unified diff format, git diff, and numbered diff output.
12447
+ */
12448
+ highlightDiff(line) {
12449
+ if (/^[-]{3}\s/.test(line) || /^[+]{3}\s/.test(line)) {
12450
+ return boldText(fg256(PASTEL.diffMeta, line));
12451
+ }
12452
+ if (line.startsWith("@@")) {
12453
+ return fg256(PASTEL.diffHunk, line);
12454
+ }
12455
+ if (line.startsWith("diff ") || line.startsWith("index ")) {
12456
+ return fg256(PASTEL.diffMeta, line);
12457
+ }
12458
+ if (line.startsWith("+")) {
12459
+ return fg256(PASTEL.diffAdded, line);
12460
+ }
12461
+ if (line.startsWith("-")) {
12462
+ return fg256(PASTEL.diffRemoved, line);
12463
+ }
12464
+ if (/^\s*\d+\s*[+-]\s/.test(line)) {
12465
+ const match = line.match(/^(\s*\d+\s*)([+-])(\s.*)$/);
12466
+ if (match) {
12467
+ const num = fg256(PASTEL.diffContext, match[1]);
12468
+ const sign = match[2] === "+" ? fg256(PASTEL.diffAdded, "+") : fg256(PASTEL.diffRemoved, "-");
12469
+ const rest = match[2] === "+" ? fg256(PASTEL.diffAdded, match[3]) : fg256(PASTEL.diffRemoved, match[3]);
12470
+ return num + sign + rest;
12471
+ }
12472
+ }
12473
+ return fg256(PASTEL.diffContext, line);
12474
+ }
12475
+ // -------------------------------------------------------------------------
12476
+ // Shell / bash highlighting
12477
+ // -------------------------------------------------------------------------
12478
+ /**
12479
+ * Highlight shell/bash code with variables, flags, operators.
12480
+ */
12481
+ highlightShell(line) {
12482
+ if (/^\s*#/.test(line)) {
12483
+ return fg256(PASTEL.comment, line);
12484
+ }
12485
+ let result = line;
12486
+ result = result.replace(/"([^"]*)"/g, (_m, s) => fg256(PASTEL.string, `"${s}"`));
12487
+ result = result.replace(/'([^']*)'/g, (_m, s) => fg256(PASTEL.string, `'${s}'`));
12488
+ result = result.replace(/(\$\{[^}]+\}|\$[A-Za-z_]\w*|\$[0-9?@#*!$-])/g, (_m, v) => fg256(PASTEL.shellVar, v));
12489
+ result = result.replace(/((?:^|\s))(--?[a-zA-Z][\w-]*)/g, (_m, ws, flag) => ws + fg256(PASTEL.shellFlag, flag));
12490
+ result = result.replace(/(\|{1,2}|>{1,2}|<{1,2}|&{1,2}|;)/g, (_m, op) => fg256(PASTEL.shellOp, op));
12491
+ 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)));
12492
+ result = result.replace(/(#[^{].*$)/gm, (_m, cm) => fg256(PASTEL.comment, cm));
12298
12493
  return result;
12299
12494
  }
12495
+ // -------------------------------------------------------------------------
12496
+ // Markdown rendering (inline formatting for prose content)
12497
+ // -------------------------------------------------------------------------
12498
+ /**
12499
+ * Render a markdown line with headings, lists, blockquotes, and inline formatting.
12500
+ */
12501
+ highlightMarkdown(line) {
12502
+ const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
12503
+ if (headingMatch) {
12504
+ const level = headingMatch[1].length;
12505
+ const text = headingMatch[2];
12506
+ const colors = [PASTEL.heading1, PASTEL.heading2, PASTEL.heading3, PASTEL.heading3, 183, 183];
12507
+ return boldText(fg256(colors[level - 1] ?? 147, text));
12508
+ }
12509
+ if (/^[-*_]{3,}\s*$/.test(line)) {
12510
+ const w = (process.stdout.columns ?? 80) - 10;
12511
+ return fg256(PASTEL.hr, "\u2500".repeat(Math.min(w, 60)));
12512
+ }
12513
+ if (/^>\s?/.test(line)) {
12514
+ const content = line.replace(/^>\s?/, "");
12515
+ return fg256(PASTEL.blockquote, "\u2502 ") + italicText(fg256(PASTEL.blockquote, this.highlightInline(content)));
12516
+ }
12517
+ const ulMatch = line.match(/^(\s*)([-*+])\s+(.*)/);
12518
+ if (ulMatch) {
12519
+ return ulMatch[1] + fg256(PASTEL.blockquote, "\u2022") + " " + this.highlightInline(ulMatch[3]);
12520
+ }
12521
+ const olMatch = line.match(/^(\s*)(\d+[.)])\s+(.*)/);
12522
+ if (olMatch) {
12523
+ return olMatch[1] + fg256(PASTEL.blockquote, olMatch[2]) + " " + this.highlightInline(olMatch[3]);
12524
+ }
12525
+ return this.highlightInline(line);
12526
+ }
12527
+ /**
12528
+ * Apply inline markdown formatting: bold, italic, code, links.
12529
+ */
12530
+ highlightInline(text) {
12531
+ let result = text;
12532
+ result = result.replace(/`([^`]+)`/g, (_m, code) => fg256(PASTEL.inlineCode, code));
12533
+ result = result.replace(/\*{3}([^*]+)\*{3}/g, (_m, t) => boldText(italicText(t)));
12534
+ result = result.replace(/\*{2}([^*]+)\*{2}/g, (_m, t) => boldText(t));
12535
+ result = result.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, (_m, t) => italicText(t));
12536
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => boldText(fg256(PASTEL.link, label)) + " " + dimText(fg256(PASTEL.link, `(${url})`)));
12537
+ result = result.replace(/__([^_]+)__/g, (_m, t) => boldText(t));
12538
+ result = result.replace(/(?<!_)_([^_]+)_(?!_)/g, (_m, t) => italicText(t));
12539
+ result = result.replace(/~~([^~]+)~~/g, (_m, t) => dimText(t));
12540
+ return result;
12541
+ }
12542
+ // -------------------------------------------------------------------------
12543
+ // Word wrapping
12544
+ // -------------------------------------------------------------------------
12545
+ /**
12546
+ * Wrap plain text at word boundaries to fit within maxWidth.
12547
+ * Operates on raw text before ANSI highlighting to avoid splitting escape sequences.
12548
+ */
12549
+ wordWrap(text, maxWidth) {
12550
+ if (maxWidth <= 0)
12551
+ return [text];
12552
+ const words = text.split(/(\s+)/);
12553
+ const lines = [];
12554
+ let currentLine = "";
12555
+ for (const segment of words) {
12556
+ if (currentLine.length + segment.length > maxWidth && currentLine.trim()) {
12557
+ lines.push(currentLine.trimEnd());
12558
+ currentLine = segment.replace(/^\s+/, "");
12559
+ } else {
12560
+ currentLine += segment;
12561
+ }
12562
+ }
12563
+ if (currentLine.trim()) {
12564
+ lines.push(currentLine.trimEnd());
12565
+ }
12566
+ return lines.length > 0 ? lines : [text];
12567
+ }
12300
12568
  };
12301
12569
  }
12302
12570
  });
@@ -12419,7 +12687,7 @@ var init_edit_history = __esm({
12419
12687
  // packages/cli/dist/tui/dream-engine.js
12420
12688
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync12, existsSync as existsSync14, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
12421
12689
  import { join as join20, basename as basename5 } from "node:path";
12422
- import { execSync as execSync11 } from "node:child_process";
12690
+ import { execSync as execSync12 } from "node:child_process";
12423
12691
  function adaptTool(tool) {
12424
12692
  return {
12425
12693
  name: tool.name,
@@ -12672,7 +12940,7 @@ var init_dream_engine = __esm({
12672
12940
  }
12673
12941
  }
12674
12942
  try {
12675
- const output = execSync11(cmd, {
12943
+ const output = execSync12(cmd, {
12676
12944
  cwd: this.repoRoot,
12677
12945
  timeout: 3e4,
12678
12946
  encoding: "utf-8",
@@ -12892,17 +13160,17 @@ Dreams directory: ${this.dreamsDir}`);
12892
13160
  try {
12893
13161
  mkdirSync8(checkpointDir, { recursive: true });
12894
13162
  try {
12895
- const gitStatus = execSync11("git status --porcelain", {
13163
+ const gitStatus = execSync12("git status --porcelain", {
12896
13164
  cwd: this.repoRoot,
12897
13165
  encoding: "utf-8",
12898
13166
  timeout: 1e4
12899
13167
  });
12900
- const gitDiff = execSync11("git diff", {
13168
+ const gitDiff = execSync12("git diff", {
12901
13169
  cwd: this.repoRoot,
12902
13170
  encoding: "utf-8",
12903
13171
  timeout: 1e4
12904
13172
  });
12905
- const gitHash = execSync11("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
13173
+ const gitHash = execSync12("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
12906
13174
  cwd: this.repoRoot,
12907
13175
  encoding: "utf-8",
12908
13176
  timeout: 5e3
@@ -13312,7 +13580,7 @@ var init_status_bar = __esm({
13312
13580
  import * as readline2 from "node:readline";
13313
13581
  import { Writable } from "node:stream";
13314
13582
  import { cwd } from "node:process";
13315
- import { resolve as resolve12, join as join21, dirname as dirname2 } from "node:path";
13583
+ import { resolve as resolve12, join as join21, dirname as dirname3 } from "node:path";
13316
13584
  import { createRequire as createRequire2 } from "node:module";
13317
13585
  import { fileURLToPath } from "node:url";
13318
13586
  import { readFileSync as readFileSync13 } from "node:fs";
@@ -13321,7 +13589,7 @@ import { extname as extname5 } from "node:path";
13321
13589
  function getVersion() {
13322
13590
  try {
13323
13591
  const require2 = createRequire2(import.meta.url);
13324
- const thisDir = dirname2(fileURLToPath(import.meta.url));
13592
+ const thisDir = dirname3(fileURLToPath(import.meta.url));
13325
13593
  const candidates = [
13326
13594
  join21(thisDir, "..", "package.json"),
13327
13595
  join21(thisDir, "..", "..", "package.json"),
@@ -15127,7 +15395,7 @@ init_updater();
15127
15395
  import { parseArgs as nodeParseArgs2 } from "node:util";
15128
15396
  import { createRequire as createRequire3 } from "node:module";
15129
15397
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15130
- import { dirname as dirname3, join as join25 } from "node:path";
15398
+ import { dirname as dirname4, join as join25 } from "node:path";
15131
15399
 
15132
15400
  // packages/cli/dist/cli.js
15133
15401
  import { createInterface } from "node:readline";
@@ -15234,7 +15502,7 @@ init_output();
15234
15502
  function getVersion2() {
15235
15503
  try {
15236
15504
  const require2 = createRequire3(import.meta.url);
15237
- const pkgPath = join25(dirname3(fileURLToPath2(import.meta.url)), "..", "package.json");
15505
+ const pkgPath = join25(dirname4(fileURLToPath2(import.meta.url)), "..", "package.json");
15238
15506
  const pkg = require2(pkgPath);
15239
15507
  return pkg.version;
15240
15508
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.13.3",
3
+ "version": "0.13.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",