open-agents-ai 0.30.2 → 0.30.4

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 +582 -106
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5425,8 +5425,8 @@ async function loadTranscribeCli() {
5425
5425
  const nvmBase = join13(homedir5(), ".nvm", "versions", "node");
5426
5426
  if (existsSync10(nvmBase)) {
5427
5427
  try {
5428
- const { readdirSync: readdirSync10 } = await import("node:fs");
5429
- for (const ver of readdirSync10(nvmBase)) {
5428
+ const { readdirSync: readdirSync11 } = await import("node:fs");
5429
+ for (const ver of readdirSync11(nvmBase)) {
5430
5430
  const tcPath = join13(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
5431
5431
  if (existsSync10(join13(tcPath, "dist", "index.js"))) {
5432
5432
  const { createRequire: createRequire4 } = await import("node:module");
@@ -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;
@@ -12408,8 +12470,8 @@ var init_listen = __esm({
12408
12470
  const nvmBase = join19(homedir6(), ".nvm", "versions", "node");
12409
12471
  if (existsSync13(nvmBase)) {
12410
12472
  try {
12411
- const { readdirSync: readdirSync10 } = await import("node:fs");
12412
- for (const ver of readdirSync10(nvmBase)) {
12473
+ const { readdirSync: readdirSync11 } = await import("node:fs");
12474
+ for (const ver of readdirSync11(nvmBase)) {
12413
12475
  const tcPath = join19(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
12414
12476
  if (existsSync13(join19(tcPath, "dist", "index.js"))) {
12415
12477
  const { createRequire: createRequire4 } = await import("node:module");
@@ -12639,10 +12701,10 @@ transcribe-cli error: ${transcribeCliError}` : "";
12639
12701
  wordTimestamps: false
12640
12702
  });
12641
12703
  if (outputDir) {
12642
- const { basename: basename9 } = await import("node:path");
12704
+ const { basename: basename10 } = await import("node:path");
12643
12705
  const transcriptDir = join19(outputDir, ".oa", "transcripts");
12644
12706
  mkdirSync5(transcriptDir, { recursive: true });
12645
- const outFile = join19(transcriptDir, `${basename9(filePath)}.txt`);
12707
+ const outFile = join19(transcriptDir, `${basename10(filePath)}.txt`);
12646
12708
  writeFileSync5(outFile, result.text, "utf-8");
12647
12709
  }
12648
12710
  return {
@@ -15489,8 +15551,24 @@ async function handleSlashCommand(input, ctx) {
15489
15551
  renderInfo(`Colors ${next ? "enabled" : "disabled"}.`);
15490
15552
  return "handled";
15491
15553
  }
15492
- case "stop":
15493
15554
  case "pause": {
15555
+ if (!ctx.hasActiveTask?.()) {
15556
+ renderWarning("No active task to pause.");
15557
+ return "handled";
15558
+ }
15559
+ if (ctx.isTaskPaused?.()) {
15560
+ renderWarning("Task is already paused. Use /resume to continue.");
15561
+ return "handled";
15562
+ }
15563
+ const paused = ctx.pauseTask?.() ?? false;
15564
+ if (paused) {
15565
+ renderInfo("Task paused. Use /resume to continue or /stop to abort.");
15566
+ } else {
15567
+ renderWarning("Could not pause the task.");
15568
+ }
15569
+ return "handled";
15570
+ }
15571
+ case "stop": {
15494
15572
  if (!ctx.hasActiveTask?.()) {
15495
15573
  renderWarning("No active task to stop.");
15496
15574
  return "handled";
@@ -15507,8 +15585,17 @@ async function handleSlashCommand(input, ctx) {
15507
15585
  return "handled";
15508
15586
  }
15509
15587
  case "resume": {
15588
+ if (ctx.isTaskPaused?.()) {
15589
+ const resumed2 = ctx.resumeInSessionTask?.() ?? false;
15590
+ if (resumed2) {
15591
+ renderInfo("Task resumed.");
15592
+ } else {
15593
+ renderWarning("Could not resume the paused task.");
15594
+ }
15595
+ return "handled";
15596
+ }
15510
15597
  if (ctx.hasActiveTask?.()) {
15511
- renderWarning("A task is already running. Stop it first with /stop.");
15598
+ renderWarning("A task is already running. Pause it first with /pause or stop with /stop.");
15512
15599
  return "handled";
15513
15600
  }
15514
15601
  const resumed = ctx.resumeTask?.() ?? false;
@@ -15676,17 +15763,17 @@ async function handleUpdate(subcommand, ctx) {
15676
15763
  try {
15677
15764
  const { createRequire: createRequire4 } = await import("node:module");
15678
15765
  const { fileURLToPath: fileURLToPath7 } = await import("node:url");
15679
- const { dirname: dirname10, join: join32 } = await import("node:path");
15680
- const { existsSync: existsSync21 } = await import("node:fs");
15766
+ const { dirname: dirname10, join: join33 } = await import("node:path");
15767
+ const { existsSync: existsSync22 } = await import("node:fs");
15681
15768
  const req = createRequire4(import.meta.url);
15682
15769
  const thisDir = dirname10(fileURLToPath7(import.meta.url));
15683
15770
  const candidates = [
15684
- join32(thisDir, "..", "package.json"),
15685
- join32(thisDir, "..", "..", "package.json"),
15686
- join32(thisDir, "..", "..", "..", "package.json")
15771
+ join33(thisDir, "..", "package.json"),
15772
+ join33(thisDir, "..", "..", "package.json"),
15773
+ join33(thisDir, "..", "..", "..", "package.json")
15687
15774
  ];
15688
15775
  for (const pkgPath of candidates) {
15689
- if (existsSync21(pkgPath)) {
15776
+ if (existsSync22(pkgPath)) {
15690
15777
  const pkg = req(pkgPath);
15691
15778
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
15692
15779
  currentVersion = pkg.version ?? "0.0.0";
@@ -16677,8 +16764,8 @@ function buildPlainRibbon(phrases, repeatWidth) {
16677
16764
  }
16678
16765
  return plain;
16679
16766
  }
16680
- function createRow(phraseIndices, speed, direction) {
16681
- const phrases = phraseIndices.map((i) => PHRASES[i % PHRASES.length]);
16767
+ function createRow(phraseIndices, speed, direction, bank) {
16768
+ const phrases = phraseIndices.map((i) => bank[i % bank.length]);
16682
16769
  return { phrases, offset: 0, speed, direction, renderedPlain: "" };
16683
16770
  }
16684
16771
  var isTTY3, PHRASES, Carousel;
@@ -16767,15 +16854,19 @@ var init_carousel = __esm({
16767
16854
  reservedRows = 4;
16768
16855
  started = false;
16769
16856
  resizeHandler = null;
16770
- constructor() {
16857
+ constructor(customPhrases) {
16771
16858
  this.width = process.stdout.columns ?? 80;
16772
- const indices0 = Array.from({ length: PHRASES.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16773
- const indices1 = Array.from({ length: PHRASES.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16774
- const indices2 = Array.from({ length: PHRASES.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16859
+ const bank = customPhrases && customPhrases.length > 0 ? customPhrases : PHRASES;
16860
+ const indices0 = Array.from({ length: bank.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16861
+ const indices1 = Array.from({ length: bank.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16862
+ const indices2 = Array.from({ length: bank.length }, (_, i) => i).sort(() => Math.random() - 0.5);
16775
16863
  this.rows = [
16776
- createRow(indices0, 2, -1),
16777
- createRow(indices1, 1, 1),
16778
- createRow(indices2, 1.5, -1)
16864
+ createRow(indices0, 0.5, -1, bank),
16865
+ // Row 1: slow left
16866
+ createRow(indices1, 1, 1, bank),
16867
+ // Row 2: medium right
16868
+ createRow(indices2, 0.7, -1, bank)
16869
+ // Row 3: medium-slow left
16779
16870
  ];
16780
16871
  this.rebuildRibbons();
16781
16872
  }
@@ -16924,26 +17015,379 @@ var init_carousel = __esm({
16924
17015
  }
16925
17016
  });
16926
17017
 
17018
+ // packages/cli/dist/tui/carousel-descriptors.js
17019
+ import { existsSync as existsSync17, readFileSync as readFileSync14, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
17020
+ import { join as join24, basename as basename7 } from "node:path";
17021
+ function loadToolProfile(repoRoot) {
17022
+ const filePath = join24(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
17023
+ try {
17024
+ if (!existsSync17(filePath))
17025
+ return null;
17026
+ return JSON.parse(readFileSync14(filePath, "utf-8"));
17027
+ } catch {
17028
+ return null;
17029
+ }
17030
+ }
17031
+ function saveToolProfile(repoRoot, profile) {
17032
+ const contextDir = join24(repoRoot, OA_DIR, "context");
17033
+ mkdirSync8(contextDir, { recursive: true });
17034
+ writeFileSync8(join24(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
17035
+ }
17036
+ function categorizeToolCall(toolName) {
17037
+ for (const cat of TOOL_CATEGORIES) {
17038
+ if (cat.tools.includes(toolName))
17039
+ return cat.name;
17040
+ }
17041
+ if (toolName.startsWith("aiwg_") || toolName.startsWith("skill_"))
17042
+ return "skill";
17043
+ if (toolName === "create_tool" || toolName === "manage_tools")
17044
+ return "toolCreate";
17045
+ return "default";
17046
+ }
17047
+ function mergeToolCalls(repoRoot, toolCalls) {
17048
+ const existing = loadToolProfile(repoRoot) ?? {
17049
+ totalCalls: 0,
17050
+ categories: {},
17051
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
17052
+ };
17053
+ for (const call of toolCalls) {
17054
+ const cat = categorizeToolCall(call.tool);
17055
+ existing.categories[cat] = (existing.categories[cat] ?? 0) + 1;
17056
+ existing.totalCalls++;
17057
+ }
17058
+ existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
17059
+ saveToolProfile(repoRoot, existing);
17060
+ return existing;
17061
+ }
17062
+ function weightedColor(profile) {
17063
+ if (!profile || profile.totalCalls === 0) {
17064
+ const defaultColors = TOOL_CATEGORIES.find((c3) => c3.name === "default").colors;
17065
+ return defaultColors[Math.floor(Math.random() * defaultColors.length)];
17066
+ }
17067
+ const entries = [];
17068
+ let totalWeight = 0;
17069
+ for (const cat of TOOL_CATEGORIES) {
17070
+ const weight = profile.categories[cat.name] ?? 0;
17071
+ if (weight > 0) {
17072
+ entries.push({ category: cat, weight });
17073
+ totalWeight += weight;
17074
+ }
17075
+ }
17076
+ if (totalWeight === 0) {
17077
+ const defaultColors = TOOL_CATEGORIES.find((c3) => c3.name === "default").colors;
17078
+ return defaultColors[Math.floor(Math.random() * defaultColors.length)];
17079
+ }
17080
+ let roll = Math.random() * totalWeight;
17081
+ let selectedCat = entries[0].category;
17082
+ for (const entry of entries) {
17083
+ roll -= entry.weight;
17084
+ if (roll <= 0) {
17085
+ selectedCat = entry.category;
17086
+ break;
17087
+ }
17088
+ }
17089
+ return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
17090
+ }
17091
+ function loadCachedDescriptors(repoRoot) {
17092
+ const filePath = join24(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
17093
+ try {
17094
+ if (!existsSync17(filePath))
17095
+ return null;
17096
+ const cached = JSON.parse(readFileSync14(filePath, "utf-8"));
17097
+ return cached.phrases.length > 0 ? cached.phrases : null;
17098
+ } catch {
17099
+ return null;
17100
+ }
17101
+ }
17102
+ function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
17103
+ const contextDir = join24(repoRoot, OA_DIR, "context");
17104
+ mkdirSync8(contextDir, { recursive: true });
17105
+ const cached = {
17106
+ phrases,
17107
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
17108
+ sourceHash
17109
+ };
17110
+ writeFileSync8(join24(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
17111
+ }
17112
+ function generateDescriptors(repoRoot) {
17113
+ const profile = loadToolProfile(repoRoot);
17114
+ const tags = [];
17115
+ extractFromPackageJson(repoRoot, tags);
17116
+ extractFromIndexMeta(repoRoot, tags);
17117
+ extractFromManifests(repoRoot, tags);
17118
+ extractFromSessions(repoRoot, tags);
17119
+ extractFromMemory(repoRoot, tags);
17120
+ extractFromToolProfile(profile, tags);
17121
+ const repoName2 = basename7(repoRoot);
17122
+ if (repoName2 && !tags.includes(repoName2)) {
17123
+ tags.push(repoName2);
17124
+ }
17125
+ const unique = [...new Set(tags.map((t) => t.toLowerCase().trim()).filter((t) => t.length > 1 && t.length < 60))];
17126
+ const phrases = unique.map((text) => ({
17127
+ text,
17128
+ color: weightedColor(profile)
17129
+ }));
17130
+ if (phrases.length < 12) {
17131
+ const fallbacks = [
17132
+ "building",
17133
+ "exploring",
17134
+ "creating",
17135
+ "refactoring",
17136
+ "testing",
17137
+ "debugging",
17138
+ "shipping",
17139
+ "iterating",
17140
+ "composing",
17141
+ "evolving",
17142
+ "crafting",
17143
+ "analyzing"
17144
+ ];
17145
+ for (const fb of fallbacks) {
17146
+ if (phrases.length >= 20)
17147
+ break;
17148
+ if (!unique.includes(fb)) {
17149
+ phrases.push({ text: fb, color: weightedColor(profile) });
17150
+ }
17151
+ }
17152
+ }
17153
+ const sourceHash = `${tags.length}-${profile?.totalCalls ?? 0}-${Date.now()}`;
17154
+ saveCachedDescriptors(repoRoot, phrases, sourceHash);
17155
+ return phrases;
17156
+ }
17157
+ function extractFromPackageJson(repoRoot, tags) {
17158
+ const pkgPath = join24(repoRoot, "package.json");
17159
+ try {
17160
+ if (!existsSync17(pkgPath))
17161
+ return;
17162
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
17163
+ if (pkg.name && typeof pkg.name === "string") {
17164
+ const parts = pkg.name.replace(/^@/, "").split("/");
17165
+ for (const p of parts)
17166
+ tags.push(p);
17167
+ }
17168
+ if (pkg.description && typeof pkg.description === "string") {
17169
+ const words = pkg.description.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !STOP_WORDS.has(w));
17170
+ tags.push(...words.slice(0, 8));
17171
+ }
17172
+ if (Array.isArray(pkg.keywords)) {
17173
+ for (const kw of pkg.keywords) {
17174
+ if (typeof kw === "string")
17175
+ tags.push(kw);
17176
+ }
17177
+ }
17178
+ } catch {
17179
+ }
17180
+ }
17181
+ function extractFromIndexMeta(repoRoot, tags) {
17182
+ const meta = readIndexMeta(repoRoot);
17183
+ if (!meta)
17184
+ return;
17185
+ for (const lang of Object.keys(meta.languages)) {
17186
+ tags.push(lang.toLowerCase());
17187
+ }
17188
+ if (meta.fileCount > 0) {
17189
+ tags.push(`${meta.fileCount} files`);
17190
+ }
17191
+ }
17192
+ function extractFromManifests(repoRoot, tags) {
17193
+ const manifestChecks = [
17194
+ { file: "package.json", tag: "node.js" },
17195
+ { file: "pyproject.toml", tag: "python" },
17196
+ { file: "Cargo.toml", tag: "rust" },
17197
+ { file: "go.mod", tag: "golang" },
17198
+ { file: "pom.xml", tag: "java" },
17199
+ { file: "Gemfile", tag: "ruby" },
17200
+ { file: "Dockerfile", tag: "docker" },
17201
+ { file: "pnpm-workspace.yaml", tag: "monorepo" },
17202
+ { file: "tsconfig.json", tag: "typescript" },
17203
+ { file: ".github/workflows", tag: "ci/cd" }
17204
+ ];
17205
+ for (const check of manifestChecks) {
17206
+ if (existsSync17(join24(repoRoot, check.file))) {
17207
+ tags.push(check.tag);
17208
+ }
17209
+ }
17210
+ }
17211
+ function extractFromSessions(repoRoot, tags) {
17212
+ try {
17213
+ const sessions = loadRecentSessions(repoRoot, 10);
17214
+ for (const session of sessions) {
17215
+ if (session.task) {
17216
+ const words = session.task.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !STOP_WORDS.has(w));
17217
+ tags.push(...words.slice(0, 4));
17218
+ }
17219
+ if (session.summary) {
17220
+ const words = session.summary.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !STOP_WORDS.has(w));
17221
+ tags.push(...words.slice(0, 3));
17222
+ }
17223
+ }
17224
+ } catch {
17225
+ }
17226
+ }
17227
+ function extractFromMemory(repoRoot, tags) {
17228
+ const memoryDir = join24(repoRoot, OA_DIR, "memory");
17229
+ try {
17230
+ if (!existsSync17(memoryDir))
17231
+ return;
17232
+ const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
17233
+ for (const file of files) {
17234
+ const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
17235
+ tags.push(topic);
17236
+ try {
17237
+ const data = JSON.parse(readFileSync14(join24(memoryDir, file), "utf-8"));
17238
+ if (data && typeof data === "object") {
17239
+ const keys = Object.keys(data).slice(0, 3);
17240
+ for (const key of keys) {
17241
+ if (typeof key === "string" && key.length > 2 && key.length < 30) {
17242
+ tags.push(key.replace(/[-_]/g, " "));
17243
+ }
17244
+ }
17245
+ }
17246
+ } catch {
17247
+ }
17248
+ }
17249
+ } catch {
17250
+ }
17251
+ }
17252
+ function extractFromToolProfile(profile, tags) {
17253
+ if (!profile)
17254
+ return;
17255
+ const sorted = Object.entries(profile.categories).sort((a, b) => b[1] - a[1]);
17256
+ for (const [cat, count] of sorted) {
17257
+ if (count > 0) {
17258
+ const label = CATEGORY_LABELS[cat] ?? cat;
17259
+ tags.push(label);
17260
+ }
17261
+ }
17262
+ }
17263
+ var TOOL_CATEGORIES, TOOL_PROFILE_FILE, DESCRIPTOR_FILE, CATEGORY_LABELS, STOP_WORDS;
17264
+ var init_carousel_descriptors = __esm({
17265
+ "packages/cli/dist/tui/carousel-descriptors.js"() {
17266
+ "use strict";
17267
+ init_oa_directory();
17268
+ TOOL_CATEGORIES = [
17269
+ {
17270
+ name: "file",
17271
+ colors: [34, 70, 71, 77, 78, 114, 150, 157],
17272
+ tools: ["file_read", "file_write", "file_edit", "file_patch", "batch_edit"]
17273
+ },
17274
+ {
17275
+ name: "shell",
17276
+ colors: [37, 73, 79, 80, 116, 117, 152, 158],
17277
+ tools: ["shell", "background_run"]
17278
+ },
17279
+ {
17280
+ name: "web",
17281
+ colors: [25, 26, 32, 33, 68, 69, 110, 153],
17282
+ tools: ["web_search", "web_fetch"]
17283
+ },
17284
+ {
17285
+ name: "search",
17286
+ colors: [60, 97, 98, 134, 135, 141, 177, 189],
17287
+ tools: ["grep_search", "find_files", "list_directory", "codebase_map", "diagnostic", "git_info"]
17288
+ },
17289
+ {
17290
+ name: "memory",
17291
+ colors: [136, 172, 178, 179, 214, 215, 220, 222],
17292
+ tools: ["memory_read", "memory_write"]
17293
+ },
17294
+ {
17295
+ name: "default",
17296
+ colors: [60, 97, 97, 141, 141, 183, 183, 189],
17297
+ tools: []
17298
+ }
17299
+ ];
17300
+ TOOL_PROFILE_FILE = "tool-profile.json";
17301
+ DESCRIPTOR_FILE = "carousel-descriptors.json";
17302
+ CATEGORY_LABELS = {
17303
+ file: "file operations",
17304
+ shell: "shell commands",
17305
+ web: "web access",
17306
+ search: "code search",
17307
+ memory: "memory management",
17308
+ skill: "skill execution",
17309
+ toolCreate: "tool creation",
17310
+ default: "general tools"
17311
+ };
17312
+ STOP_WORDS = /* @__PURE__ */ new Set([
17313
+ "the",
17314
+ "and",
17315
+ "for",
17316
+ "are",
17317
+ "but",
17318
+ "not",
17319
+ "you",
17320
+ "all",
17321
+ "can",
17322
+ "had",
17323
+ "her",
17324
+ "was",
17325
+ "one",
17326
+ "our",
17327
+ "out",
17328
+ "has",
17329
+ "have",
17330
+ "been",
17331
+ "from",
17332
+ "with",
17333
+ "they",
17334
+ "this",
17335
+ "that",
17336
+ "will",
17337
+ "each",
17338
+ "make",
17339
+ "like",
17340
+ "just",
17341
+ "over",
17342
+ "such",
17343
+ "take",
17344
+ "than",
17345
+ "them",
17346
+ "very",
17347
+ "some",
17348
+ "into",
17349
+ "most",
17350
+ "also",
17351
+ "upon",
17352
+ "what",
17353
+ "when",
17354
+ "which",
17355
+ "their",
17356
+ "said",
17357
+ "about",
17358
+ "would",
17359
+ "these",
17360
+ "other",
17361
+ "could",
17362
+ "after",
17363
+ "using",
17364
+ "used",
17365
+ "more",
17366
+ "does"
17367
+ ]);
17368
+ }
17369
+ });
17370
+
16927
17371
  // packages/cli/dist/tui/voice.js
16928
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
16929
- import { join as join24 } from "node:path";
17372
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
17373
+ import { join as join25 } from "node:path";
16930
17374
  import { homedir as homedir10, tmpdir as tmpdir4, platform as platform2 } from "node:os";
16931
17375
  import { execSync as execSync15, spawn as nodeSpawn } from "node:child_process";
16932
17376
  import { createRequire } from "node:module";
16933
17377
  function voiceDir() {
16934
- return join24(homedir10(), ".open-agents", "voice");
17378
+ return join25(homedir10(), ".open-agents", "voice");
16935
17379
  }
16936
17380
  function modelsDir() {
16937
- return join24(voiceDir(), "models");
17381
+ return join25(voiceDir(), "models");
16938
17382
  }
16939
17383
  function modelDir(id) {
16940
- return join24(modelsDir(), id);
17384
+ return join25(modelsDir(), id);
16941
17385
  }
16942
17386
  function modelOnnxPath(id) {
16943
- return join24(modelDir(id), "model.onnx");
17387
+ return join25(modelDir(id), "model.onnx");
16944
17388
  }
16945
17389
  function modelConfigPath(id) {
16946
- return join24(modelDir(id), "config.json");
17390
+ return join25(modelDir(id), "config.json");
16947
17391
  }
16948
17392
  function describeToolCall(toolName, args) {
16949
17393
  const path = args["path"];
@@ -17216,7 +17660,7 @@ var init_voice = __esm({
17216
17660
  const audioData = result["output"].data;
17217
17661
  if (audioData.length === 0)
17218
17662
  return;
17219
- const wavPath = join24(tmpdir4(), `oa-voice-${Date.now()}.wav`);
17663
+ const wavPath = join25(tmpdir4(), `oa-voice-${Date.now()}.wav`);
17220
17664
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
17221
17665
  await this.playWav(wavPath);
17222
17666
  try {
@@ -17296,7 +17740,7 @@ var init_voice = __esm({
17296
17740
  buffer.write("data", 36);
17297
17741
  buffer.writeUInt32LE(dataSize, 40);
17298
17742
  Buffer.from(int16.buffer, int16.byteOffset, int16.byteLength).copy(buffer, 44);
17299
- writeFileSync8(path, buffer);
17743
+ writeFileSync9(path, buffer);
17300
17744
  }
17301
17745
  // -------------------------------------------------------------------------
17302
17746
  // Audio playback (system default speakers)
@@ -17370,30 +17814,30 @@ var init_voice = __esm({
17370
17814
  return;
17371
17815
  const arch = process.arch;
17372
17816
  const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
17373
- mkdirSync8(voiceDir(), { recursive: true });
17374
- const pkgPath = join24(voiceDir(), "package.json");
17817
+ mkdirSync9(voiceDir(), { recursive: true });
17818
+ const pkgPath = join25(voiceDir(), "package.json");
17375
17819
  const expectedDeps = {
17376
17820
  "onnxruntime-node": "^1.21.0",
17377
17821
  "phonemizer": "^1.2.1"
17378
17822
  };
17379
- if (existsSync17(pkgPath)) {
17823
+ if (existsSync18(pkgPath)) {
17380
17824
  try {
17381
- const existing = JSON.parse(readFileSync14(pkgPath, "utf8"));
17825
+ const existing = JSON.parse(readFileSync15(pkgPath, "utf8"));
17382
17826
  if (!existing.dependencies?.["phonemizer"]) {
17383
17827
  existing.dependencies = { ...existing.dependencies, ...expectedDeps };
17384
- writeFileSync8(pkgPath, JSON.stringify(existing, null, 2));
17828
+ writeFileSync9(pkgPath, JSON.stringify(existing, null, 2));
17385
17829
  }
17386
17830
  } catch {
17387
17831
  }
17388
17832
  }
17389
- if (!existsSync17(pkgPath)) {
17390
- writeFileSync8(pkgPath, JSON.stringify({
17833
+ if (!existsSync18(pkgPath)) {
17834
+ writeFileSync9(pkgPath, JSON.stringify({
17391
17835
  name: "open-agents-voice",
17392
17836
  private: true,
17393
17837
  dependencies: expectedDeps
17394
17838
  }, null, 2));
17395
17839
  }
17396
- const voiceRequire = createRequire(join24(voiceDir(), "index.js"));
17840
+ const voiceRequire = createRequire(join25(voiceDir(), "index.js"));
17397
17841
  try {
17398
17842
  this.ort = voiceRequire("onnxruntime-node");
17399
17843
  } catch {
@@ -17447,18 +17891,18 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
17447
17891
  const dir = modelDir(id);
17448
17892
  const onnxPath = modelOnnxPath(id);
17449
17893
  const configPath = modelConfigPath(id);
17450
- if (existsSync17(onnxPath) && existsSync17(configPath))
17894
+ if (existsSync18(onnxPath) && existsSync18(configPath))
17451
17895
  return;
17452
- mkdirSync8(dir, { recursive: true });
17453
- if (!existsSync17(configPath)) {
17896
+ mkdirSync9(dir, { recursive: true });
17897
+ if (!existsSync18(configPath)) {
17454
17898
  renderInfo(`Downloading ${model.label} voice config...`);
17455
17899
  const configResp = await fetch(model.configUrl);
17456
17900
  if (!configResp.ok)
17457
17901
  throw new Error(`Failed to download config: HTTP ${configResp.status}`);
17458
17902
  const configText = await configResp.text();
17459
- writeFileSync8(configPath, configText);
17903
+ writeFileSync9(configPath, configText);
17460
17904
  }
17461
- if (!existsSync17(onnxPath)) {
17905
+ if (!existsSync18(onnxPath)) {
17462
17906
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
17463
17907
  const onnxResp = await fetch(model.onnxUrl);
17464
17908
  if (!onnxResp.ok)
@@ -17482,7 +17926,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
17482
17926
  }
17483
17927
  process.stdout.write("\r" + " ".repeat(60) + "\r");
17484
17928
  const fullBuffer = Buffer.concat(chunks);
17485
- writeFileSync8(onnxPath, fullBuffer);
17929
+ writeFileSync9(onnxPath, fullBuffer);
17486
17930
  renderInfo(`${model.label} model downloaded (${formatBytes2(fullBuffer.length)}).`);
17487
17931
  }
17488
17932
  }
@@ -17494,10 +17938,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
17494
17938
  throw new Error("ONNX runtime not loaded");
17495
17939
  const onnxPath = modelOnnxPath(this.modelId);
17496
17940
  const configPath = modelConfigPath(this.modelId);
17497
- if (!existsSync17(onnxPath) || !existsSync17(configPath)) {
17941
+ if (!existsSync18(onnxPath) || !existsSync18(configPath)) {
17498
17942
  throw new Error(`Model files not found for ${this.modelId}`);
17499
17943
  }
17500
- this.config = JSON.parse(readFileSync14(configPath, "utf8"));
17944
+ this.config = JSON.parse(readFileSync15(configPath, "utf8"));
17501
17945
  renderInfo("Loading voice model...");
17502
17946
  this.session = await this.ort.InferenceSession.create(onnxPath, {
17503
17947
  executionProviders: ["cpu"],
@@ -17997,13 +18441,13 @@ var init_stream_renderer = __esm({
17997
18441
  });
17998
18442
 
17999
18443
  // packages/cli/dist/tui/edit-history.js
18000
- import { appendFileSync, mkdirSync as mkdirSync9 } from "node:fs";
18001
- import { join as join25 } from "node:path";
18444
+ import { appendFileSync, mkdirSync as mkdirSync10 } from "node:fs";
18445
+ import { join as join26 } from "node:path";
18002
18446
  function createEditHistoryLogger(repoRoot, sessionId) {
18003
- const historyDir = join25(repoRoot, ".oa", "history");
18004
- const logPath = join25(historyDir, "edits.jsonl");
18447
+ const historyDir = join26(repoRoot, ".oa", "history");
18448
+ const logPath = join26(historyDir, "edits.jsonl");
18005
18449
  try {
18006
- mkdirSync9(historyDir, { recursive: true });
18450
+ mkdirSync10(historyDir, { recursive: true });
18007
18451
  } catch {
18008
18452
  }
18009
18453
  function logToolCall(toolName, toolArgs, success) {
@@ -18112,8 +18556,8 @@ var init_edit_history = __esm({
18112
18556
  });
18113
18557
 
18114
18558
  // packages/cli/dist/tui/dream-engine.js
18115
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync15, existsSync as existsSync18, cpSync, rmSync, readdirSync as readdirSync9 } from "node:fs";
18116
- import { join as join26, basename as basename7 } from "node:path";
18559
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync16, existsSync as existsSync19, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
18560
+ import { join as join27, basename as basename8 } from "node:path";
18117
18561
  import { execSync as execSync16 } from "node:child_process";
18118
18562
  function adaptTool(tool) {
18119
18563
  return {
@@ -18288,14 +18732,14 @@ var init_dream_engine = __esm({
18288
18732
  const content = String(args["content"] ?? "");
18289
18733
  if (!rawPath)
18290
18734
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
18291
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join26(this.dreamsDir, basename7(rawPath)) : join26(this.dreamsDir, rawPath);
18735
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join27(this.dreamsDir, basename8(rawPath)) : join27(this.dreamsDir, rawPath);
18292
18736
  if (!targetPath.startsWith(this.dreamsDir)) {
18293
18737
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
18294
18738
  }
18295
18739
  try {
18296
- const dir = join26(targetPath, "..");
18297
- mkdirSync10(dir, { recursive: true });
18298
- writeFileSync9(targetPath, content, "utf-8");
18740
+ const dir = join27(targetPath, "..");
18741
+ mkdirSync11(dir, { recursive: true });
18742
+ writeFileSync10(targetPath, content, "utf-8");
18299
18743
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
18300
18744
  } catch (err) {
18301
18745
  return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
@@ -18323,20 +18767,20 @@ var init_dream_engine = __esm({
18323
18767
  const rawPath = String(args["path"] ?? "");
18324
18768
  const oldStr = String(args["old_string"] ?? "");
18325
18769
  const newStr = String(args["new_string"] ?? "");
18326
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join26(this.dreamsDir, basename7(rawPath)) : join26(this.dreamsDir, rawPath);
18770
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join27(this.dreamsDir, basename8(rawPath)) : join27(this.dreamsDir, rawPath);
18327
18771
  if (!targetPath.startsWith(this.dreamsDir)) {
18328
18772
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
18329
18773
  }
18330
18774
  try {
18331
- if (!existsSync18(targetPath)) {
18775
+ if (!existsSync19(targetPath)) {
18332
18776
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
18333
18777
  }
18334
- let content = readFileSync15(targetPath, "utf-8");
18778
+ let content = readFileSync16(targetPath, "utf-8");
18335
18779
  if (!content.includes(oldStr)) {
18336
18780
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
18337
18781
  }
18338
18782
  content = content.replace(oldStr, newStr);
18339
- writeFileSync9(targetPath, content, "utf-8");
18783
+ writeFileSync10(targetPath, content, "utf-8");
18340
18784
  return { success: true, output: `Edited ${rawPath}`, durationMs: Date.now() - start };
18341
18785
  } catch (err) {
18342
18786
  return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
@@ -18390,7 +18834,7 @@ var init_dream_engine = __esm({
18390
18834
  constructor(config, repoRoot) {
18391
18835
  this.config = config;
18392
18836
  this.repoRoot = repoRoot;
18393
- this.dreamsDir = join26(repoRoot, ".oa", "dreams");
18837
+ this.dreamsDir = join27(repoRoot, ".oa", "dreams");
18394
18838
  this.state = {
18395
18839
  mode: "default",
18396
18840
  active: false,
@@ -18421,7 +18865,7 @@ var init_dream_engine = __esm({
18421
18865
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
18422
18866
  results: []
18423
18867
  };
18424
- mkdirSync10(this.dreamsDir, { recursive: true });
18868
+ mkdirSync11(this.dreamsDir, { recursive: true });
18425
18869
  this.saveDreamState();
18426
18870
  try {
18427
18871
  for (let cycle = 1; cycle <= totalCycles; cycle++) {
@@ -18462,8 +18906,8 @@ ${result.summary}`;
18462
18906
  if (mode !== "default" || cycle === totalCycles) {
18463
18907
  renderDreamContraction(cycle);
18464
18908
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
18465
- const summaryPath = join26(this.dreamsDir, `cycle-${cycle}-summary.md`);
18466
- writeFileSync9(summaryPath, cycleSummary, "utf-8");
18909
+ const summaryPath = join27(this.dreamsDir, `cycle-${cycle}-summary.md`);
18910
+ writeFileSync10(summaryPath, cycleSummary, "utf-8");
18467
18911
  }
18468
18912
  if (mode === "lucid" && !this.abortController.signal.aborted) {
18469
18913
  this.saveVersionCheckpoint(cycle);
@@ -18585,9 +19029,9 @@ Dreams directory: ${this.dreamsDir}`);
18585
19029
  }
18586
19030
  /** Save workspace backup for lucid mode */
18587
19031
  saveVersionCheckpoint(cycle) {
18588
- const checkpointDir = join26(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
19032
+ const checkpointDir = join27(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
18589
19033
  try {
18590
- mkdirSync10(checkpointDir, { recursive: true });
19034
+ mkdirSync11(checkpointDir, { recursive: true });
18591
19035
  try {
18592
19036
  const gitStatus = execSync16("git status --porcelain", {
18593
19037
  cwd: this.repoRoot,
@@ -18604,10 +19048,10 @@ Dreams directory: ${this.dreamsDir}`);
18604
19048
  encoding: "utf-8",
18605
19049
  timeout: 5e3
18606
19050
  }).trim();
18607
- writeFileSync9(join26(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
18608
- writeFileSync9(join26(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
18609
- writeFileSync9(join26(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
18610
- writeFileSync9(join26(checkpointDir, "checkpoint.json"), JSON.stringify({
19051
+ writeFileSync10(join27(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
19052
+ writeFileSync10(join27(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
19053
+ writeFileSync10(join27(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
19054
+ writeFileSync10(join27(checkpointDir, "checkpoint.json"), JSON.stringify({
18611
19055
  cycle,
18612
19056
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
18613
19057
  gitHash,
@@ -18615,7 +19059,7 @@ Dreams directory: ${this.dreamsDir}`);
18615
19059
  }, null, 2), "utf-8");
18616
19060
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
18617
19061
  } catch {
18618
- writeFileSync9(join26(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
19062
+ writeFileSync10(join27(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
18619
19063
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
18620
19064
  }
18621
19065
  } catch (err) {
@@ -18652,7 +19096,7 @@ Each proposal includes implementation entrypoints and estimated effort.
18652
19096
  /** Update the master proposal index */
18653
19097
  updateProposalIndex() {
18654
19098
  try {
18655
- const files = readdirSync9(this.dreamsDir).filter((f) => f.endsWith(".md") && f !== "PROPOSAL-INDEX.md" && f !== "dream-state.json").sort();
19099
+ const files = readdirSync10(this.dreamsDir).filter((f) => f.endsWith(".md") && f !== "PROPOSAL-INDEX.md" && f !== "dream-state.json").sort();
18656
19100
  const index = `# Dream Proposals Index
18657
19101
 
18658
19102
  **Last updated**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -18673,14 +19117,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
18673
19117
  ---
18674
19118
  *Auto-generated by open-agents dream engine*
18675
19119
  `;
18676
- writeFileSync9(join26(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
19120
+ writeFileSync10(join27(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
18677
19121
  } catch {
18678
19122
  }
18679
19123
  }
18680
19124
  /** Save dream state for resume/inspection */
18681
19125
  saveDreamState() {
18682
19126
  try {
18683
- writeFileSync9(join26(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
19127
+ writeFileSync10(join27(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
18684
19128
  } catch {
18685
19129
  }
18686
19130
  }
@@ -19512,22 +19956,22 @@ var init_status_bar = __esm({
19512
19956
  import * as readline2 from "node:readline";
19513
19957
  import { Writable } from "node:stream";
19514
19958
  import { cwd } from "node:process";
19515
- import { resolve as resolve16, join as join27, dirname as dirname8, extname as extname9 } from "node:path";
19959
+ import { resolve as resolve16, join as join28, dirname as dirname8, extname as extname9 } from "node:path";
19516
19960
  import { createRequire as createRequire2 } from "node:module";
19517
19961
  import { fileURLToPath as fileURLToPath5 } from "node:url";
19518
- import { readFileSync as readFileSync16 } from "node:fs";
19519
- import { existsSync as existsSync19 } from "node:fs";
19962
+ import { readFileSync as readFileSync17 } from "node:fs";
19963
+ import { existsSync as existsSync20 } from "node:fs";
19520
19964
  function getVersion() {
19521
19965
  try {
19522
19966
  const require2 = createRequire2(import.meta.url);
19523
19967
  const thisDir = dirname8(fileURLToPath5(import.meta.url));
19524
19968
  const candidates = [
19525
- join27(thisDir, "..", "package.json"),
19526
- join27(thisDir, "..", "..", "package.json"),
19527
- join27(thisDir, "..", "..", "..", "package.json")
19969
+ join28(thisDir, "..", "package.json"),
19970
+ join28(thisDir, "..", "..", "package.json"),
19971
+ join28(thisDir, "..", "..", "..", "package.json")
19528
19972
  ];
19529
19973
  for (const pkgPath of candidates) {
19530
- if (existsSync19(pkgPath)) {
19974
+ if (existsSync20(pkgPath)) {
19531
19975
  const pkg = require2(pkgPath);
19532
19976
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
19533
19977
  return pkg.version ?? "0.0.0";
@@ -19909,6 +20353,12 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
19909
20353
  } catch {
19910
20354
  }
19911
20355
  }
20356
+ if (toolSequence.length > 0) {
20357
+ try {
20358
+ mergeToolCalls(repoRoot, toolSequence);
20359
+ } catch {
20360
+ }
20361
+ }
19912
20362
  });
19913
20363
  return { runner, promise, filesTouched, get toolCallCount() {
19914
20364
  return toolSequence.length;
@@ -20004,7 +20454,12 @@ async function startInteractive(config, repoPath) {
20004
20454
  renderInfo("Use /endpoint to configure a different backend. Starting anyway...");
20005
20455
  }
20006
20456
  }
20007
- const carousel = new Carousel();
20457
+ let carouselPhrases = null;
20458
+ try {
20459
+ carouselPhrases = loadCachedDescriptors(repoRoot) ?? generateDescriptors(repoRoot);
20460
+ } catch {
20461
+ }
20462
+ const carousel = new Carousel(carouselPhrases ?? void 0);
20008
20463
  let carouselLines = 0;
20009
20464
  const version = getVersion();
20010
20465
  if (isResumed) {
@@ -20106,6 +20561,7 @@ async function startInteractive(config, repoPath) {
20106
20561
  let sudoPromptPending = false;
20107
20562
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
20108
20563
  const activePrompt = `${c2.bold(c2.white("+ "))}`;
20564
+ const pausedPrompt = `${c2.bold(c2.yellow("| "))}`;
20109
20565
  const rl = readline2.createInterface({
20110
20566
  input: process.stdin,
20111
20567
  output: process.stdout,
@@ -20139,7 +20595,7 @@ async function startInteractive(config, repoPath) {
20139
20595
  }
20140
20596
  });
20141
20597
  function showPrompt() {
20142
- const prompt = activeTask ? activePrompt : idlePrompt;
20598
+ const prompt = activeTask ? activeTask.runner.isPaused ? pausedPrompt : activePrompt : idlePrompt;
20143
20599
  rl.setPrompt(prompt);
20144
20600
  if (statusBar.isActive) {
20145
20601
  statusBar.setPromptText(prompt, 2);
@@ -20391,6 +20847,25 @@ async function startInteractive(config, repoPath) {
20391
20847
  writeContent(() => renderInfo("Task aborted."));
20392
20848
  return true;
20393
20849
  },
20850
+ pauseTask() {
20851
+ if (!activeTask)
20852
+ return false;
20853
+ activeTask.runner.pause();
20854
+ statusBar.setProcessing(false);
20855
+ showPrompt();
20856
+ return true;
20857
+ },
20858
+ resumeInSessionTask() {
20859
+ if (!activeTask || !activeTask.runner.isPaused)
20860
+ return false;
20861
+ activeTask.runner.resume();
20862
+ statusBar.setProcessing(true);
20863
+ showPrompt();
20864
+ return true;
20865
+ },
20866
+ isTaskPaused() {
20867
+ return activeTask !== null && activeTask.runner.isPaused;
20868
+ },
20394
20869
  resumeTask() {
20395
20870
  const pendingTask = loadPendingTask(repoRoot);
20396
20871
  if (!pendingTask)
@@ -20561,13 +21036,13 @@ Execute this skill now. Follow the behavioral guidance above.`;
20561
21036
  }
20562
21037
  }
20563
21038
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
20564
- const isImage = isImagePath(cleanPath) && existsSync19(resolve16(repoRoot, cleanPath));
20565
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync19(resolve16(repoRoot, cleanPath));
21039
+ const isImage = isImagePath(cleanPath) && existsSync20(resolve16(repoRoot, cleanPath));
21040
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync20(resolve16(repoRoot, cleanPath));
20566
21041
  if (activeTask) {
20567
21042
  if (isImage) {
20568
21043
  try {
20569
21044
  const imgPath = resolve16(repoRoot, cleanPath);
20570
- const imgBuffer = readFileSync16(imgPath);
21045
+ const imgBuffer = readFileSync17(imgPath);
20571
21046
  const base64 = imgBuffer.toString("base64");
20572
21047
  const ext = extname9(cleanPath).toLowerCase();
20573
21048
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -20796,6 +21271,7 @@ var init_interactive = __esm({
20796
21271
  init_oa_directory();
20797
21272
  init_render();
20798
21273
  init_carousel();
21274
+ init_carousel_descriptors();
20799
21275
  init_voice();
20800
21276
  init_stream_renderer();
20801
21277
  init_edit_history();
@@ -20837,7 +21313,7 @@ import { glob } from "glob";
20837
21313
  import ignore from "ignore";
20838
21314
  import { readFile as readFile10, stat as stat4 } from "node:fs/promises";
20839
21315
  import { createHash } from "node:crypto";
20840
- import { join as join28, relative as relative3, extname as extname10, basename as basename8 } from "node:path";
21316
+ import { join as join29, relative as relative3, extname as extname10, basename as basename9 } from "node:path";
20841
21317
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
20842
21318
  var init_codebase_indexer = __esm({
20843
21319
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -20881,7 +21357,7 @@ var init_codebase_indexer = __esm({
20881
21357
  const ig = ignore.default();
20882
21358
  if (this.config.respectGitignore) {
20883
21359
  try {
20884
- const gitignoreContent = await readFile10(join28(this.config.rootDir, ".gitignore"), "utf-8");
21360
+ const gitignoreContent = await readFile10(join29(this.config.rootDir, ".gitignore"), "utf-8");
20885
21361
  ig.add(gitignoreContent);
20886
21362
  } catch {
20887
21363
  }
@@ -20896,7 +21372,7 @@ var init_codebase_indexer = __esm({
20896
21372
  for (const relativePath of files) {
20897
21373
  if (ig.ignores(relativePath))
20898
21374
  continue;
20899
- const fullPath = join28(this.config.rootDir, relativePath);
21375
+ const fullPath = join29(this.config.rootDir, relativePath);
20900
21376
  try {
20901
21377
  const fileStat = await stat4(fullPath);
20902
21378
  if (fileStat.size > this.config.maxFileSize)
@@ -20919,7 +21395,7 @@ var init_codebase_indexer = __esm({
20919
21395
  }
20920
21396
  buildTree(files) {
20921
21397
  const root = {
20922
- name: basename8(this.config.rootDir),
21398
+ name: basename9(this.config.rootDir),
20923
21399
  path: this.config.rootDir,
20924
21400
  type: "directory",
20925
21401
  children: []
@@ -20942,7 +21418,7 @@ var init_codebase_indexer = __esm({
20942
21418
  if (!child) {
20943
21419
  child = {
20944
21420
  name: part,
20945
- path: join28(current.path, part),
21421
+ path: join29(current.path, part),
20946
21422
  type: "directory",
20947
21423
  children: []
20948
21424
  };
@@ -21017,13 +21493,13 @@ __export(index_repo_exports, {
21017
21493
  indexRepoCommand: () => indexRepoCommand
21018
21494
  });
21019
21495
  import { resolve as resolve17 } from "node:path";
21020
- import { existsSync as existsSync20, statSync as statSync7 } from "node:fs";
21496
+ import { existsSync as existsSync21, statSync as statSync7 } from "node:fs";
21021
21497
  import { cwd as cwd2 } from "node:process";
21022
21498
  async function indexRepoCommand(opts, _config) {
21023
21499
  const repoRoot = resolve17(opts.repoPath ?? cwd2());
21024
21500
  printHeader("Index Repository");
21025
21501
  printInfo(`Indexing: ${repoRoot}`);
21026
- if (!existsSync20(repoRoot)) {
21502
+ if (!existsSync21(repoRoot)) {
21027
21503
  printError(`Path does not exist: ${repoRoot}`);
21028
21504
  process.exit(1);
21029
21505
  }
@@ -21269,7 +21745,7 @@ var config_exports = {};
21269
21745
  __export(config_exports, {
21270
21746
  configCommand: () => configCommand
21271
21747
  });
21272
- import { join as join29, resolve as resolve18 } from "node:path";
21748
+ import { join as join30, resolve as resolve18 } from "node:path";
21273
21749
  import { homedir as homedir11 } from "node:os";
21274
21750
  import { cwd as cwd3 } from "node:process";
21275
21751
  function coerceForSettings(key, value) {
@@ -21322,7 +21798,7 @@ function handleShow(opts, config) {
21322
21798
  }
21323
21799
  }
21324
21800
  printSection("Config File");
21325
- printInfo(`~/.open-agents/config.json (${join29(homedir11(), ".open-agents", "config.json")})`);
21801
+ printInfo(`~/.open-agents/config.json (${join30(homedir11(), ".open-agents", "config.json")})`);
21326
21802
  printSection("Priority Chain");
21327
21803
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
21328
21804
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -21361,7 +21837,7 @@ function handleSet(opts, _config) {
21361
21837
  const coerced = coerceForSettings(key, value);
21362
21838
  saveProjectSettings(repoRoot, { [key]: coerced });
21363
21839
  printSuccess(`Project override set: ${key} = ${value}`);
21364
- printInfo(`Saved to ${join29(repoRoot, ".oa", "settings.json")}`);
21840
+ printInfo(`Saved to ${join30(repoRoot, ".oa", "settings.json")}`);
21365
21841
  printInfo("This override applies only when running in this workspace.");
21366
21842
  } catch (err) {
21367
21843
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -21579,8 +22055,8 @@ __export(eval_exports, {
21579
22055
  evalCommand: () => evalCommand
21580
22056
  });
21581
22057
  import { tmpdir as tmpdir5 } from "node:os";
21582
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
21583
- import { join as join30 } from "node:path";
22058
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
22059
+ import { join as join31 } from "node:path";
21584
22060
  async function evalCommand(opts, config) {
21585
22061
  const suiteName = opts.suite ?? "basic";
21586
22062
  const suite = SUITES[suiteName];
@@ -21701,9 +22177,9 @@ async function evalCommand(opts, config) {
21701
22177
  process.exit(failed > 0 ? 1 : 0);
21702
22178
  }
21703
22179
  function createTempEvalRepo() {
21704
- const dir = join30(tmpdir5(), `open-agents-eval-${Date.now()}`);
21705
- mkdirSync11(dir, { recursive: true });
21706
- writeFileSync10(join30(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
22180
+ const dir = join31(tmpdir5(), `open-agents-eval-${Date.now()}`);
22181
+ mkdirSync12(dir, { recursive: true });
22182
+ writeFileSync11(join31(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
21707
22183
  return dir;
21708
22184
  }
21709
22185
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -21763,7 +22239,7 @@ init_updater();
21763
22239
  import { parseArgs as nodeParseArgs2 } from "node:util";
21764
22240
  import { createRequire as createRequire3 } from "node:module";
21765
22241
  import { fileURLToPath as fileURLToPath6 } from "node:url";
21766
- import { dirname as dirname9, join as join31 } from "node:path";
22242
+ import { dirname as dirname9, join as join32 } from "node:path";
21767
22243
 
21768
22244
  // packages/cli/dist/cli.js
21769
22245
  import { createInterface } from "node:readline";
@@ -21870,7 +22346,7 @@ init_output();
21870
22346
  function getVersion2() {
21871
22347
  try {
21872
22348
  const require2 = createRequire3(import.meta.url);
21873
- const pkgPath = join31(dirname9(fileURLToPath6(import.meta.url)), "..", "package.json");
22349
+ const pkgPath = join32(dirname9(fileURLToPath6(import.meta.url)), "..", "package.json");
21874
22350
  const pkg = require2(pkgPath);
21875
22351
  return pkg.version;
21876
22352
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.30.2",
3
+ "version": "0.30.4",
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",