open-agents-ai 0.8.0 → 0.9.0

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 (3) hide show
  1. package/README.md +23 -0
  2. package/dist/index.js +463 -113
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -221,6 +221,29 @@ Create a `.open-agents.md` file in your project root to give the agent project-s
221
221
 
222
222
  Context files are merged from parent → child directories, so you can set global defaults at `~/.open-agents.md` and override per-project.
223
223
 
224
+ ### `.oa/` Project Directory
225
+
226
+ Each project gets a `.oa/` directory (similar to `.claude/` for Claude Code) that persists artifacts across sessions:
227
+
228
+ ```
229
+ .oa/
230
+ ├── config.json # Per-project configuration overrides
231
+ ├── memory/ # Persistent memory store
232
+ │ └── {topic}.json # Topic-based key-value memories
233
+ ├── index/ # Cached codebase index
234
+ │ ├── repo-profile.json # Repository metadata
235
+ │ ├── file-summaries.json # Per-file purpose, exports, domain, risk
236
+ │ ├── symbols.json # Symbol table cache
237
+ │ ├── graph.json # Import/dependency graph
238
+ │ └── meta.json # Index metadata (timestamp, hash)
239
+ ├── context/ # Auto-generated project context
240
+ │ └── project-map.md # Generated overview for system prompt
241
+ └── history/ # Session history
242
+ └── {session-id}.json # Per-session task log
243
+ ```
244
+
245
+ The agent auto-discovers `AGENTS.md`, `OA.md`, `CLAUDE.md`, and `README.md` from the project root and parent directories, injecting them into the system prompt for project-specific awareness.
246
+
224
247
  ### Smart Context Compaction
225
248
 
226
249
  When conversations exceed the context window, the agent compacts older messages while preserving:
package/dist/index.js CHANGED
@@ -1827,12 +1827,18 @@ var init_memory_read = __esm({
1827
1827
  const key = args["key"];
1828
1828
  const start = performance.now();
1829
1829
  try {
1830
- const memoryDir = resolve6(this.workingDir, ".open-agents", "memory");
1831
- const topicFile = join3(memoryDir, `${topic}.json`);
1832
- let raw;
1833
- try {
1834
- raw = await readFile3(topicFile, "utf-8");
1835
- } catch {
1830
+ const oaMemDir = resolve6(this.workingDir, ".oa", "memory");
1831
+ const legacyMemDir = resolve6(this.workingDir, ".open-agents", "memory");
1832
+ let raw = null;
1833
+ for (const memoryDir of [oaMemDir, legacyMemDir]) {
1834
+ const topicFile = join3(memoryDir, `${topic}.json`);
1835
+ try {
1836
+ raw = await readFile3(topicFile, "utf-8");
1837
+ break;
1838
+ } catch {
1839
+ }
1840
+ }
1841
+ if (raw === null) {
1836
1842
  return {
1837
1843
  success: true,
1838
1844
  output: "(no memories found)",
@@ -1910,20 +1916,23 @@ var init_memory_write = __esm({
1910
1916
  const value = args["value"];
1911
1917
  const start = performance.now();
1912
1918
  try {
1913
- const memoryDir = resolve7(this.workingDir, ".open-agents", "memory");
1914
- await mkdir2(memoryDir, { recursive: true });
1915
- const topicFile = join4(memoryDir, `${topic}.json`);
1916
- let entries = {};
1917
- try {
1918
- const raw = await readFile4(topicFile, "utf-8");
1919
- entries = JSON.parse(raw);
1920
- } catch {
1919
+ const oaMemDir = resolve7(this.workingDir, ".oa", "memory");
1920
+ const legacyMemDir = resolve7(this.workingDir, ".open-agents", "memory");
1921
+ for (const memoryDir of [oaMemDir, legacyMemDir]) {
1922
+ await mkdir2(memoryDir, { recursive: true });
1923
+ const topicFile = join4(memoryDir, `${topic}.json`);
1924
+ let entries = {};
1925
+ try {
1926
+ const raw = await readFile4(topicFile, "utf-8");
1927
+ entries = JSON.parse(raw);
1928
+ } catch {
1929
+ }
1930
+ entries[key] = {
1931
+ value,
1932
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1933
+ };
1934
+ await writeFile3(topicFile, JSON.stringify(entries, null, 2), "utf-8");
1921
1935
  }
1922
- entries[key] = {
1923
- value,
1924
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1925
- };
1926
- await writeFile3(topicFile, JSON.stringify(entries, null, 2), "utf-8");
1927
1936
  return {
1928
1937
  success: true,
1929
1938
  output: `Stored memory: ${topic}.${key}`,
@@ -6463,6 +6472,18 @@ Use screenshot to capture visual state for debugging UI issues.
6463
6472
  - Keep tool calls focused \u2014 read only what you need
6464
6473
  - You MUST call task_complete when the task is done
6465
6474
 
6475
+ ## Project Awareness
6476
+
6477
+ Your system prompt is dynamically enriched with project context. Before each task:
6478
+ - AGENTS.md, OA.md, CLAUDE.md, and README.md are auto-discovered and loaded
6479
+ - The .oa/ directory stores per-project artifacts (memory, index, session history)
6480
+ - Git state (branch, dirty files, recent commits) is injected
6481
+ - Persistent memories from previous sessions are loaded
6482
+ - Recent session history shows what was worked on before
6483
+
6484
+ When working in a new project, use codebase_map first to orient yourself.
6485
+ Store important discoveries with memory_write for future sessions.
6486
+
6466
6487
  ## Self-Learning
6467
6488
 
6468
6489
  When you encounter an unfamiliar API, language feature, or runtime behavior:
@@ -6689,7 +6710,7 @@ ${result.output}`;
6689
6710
  });
6690
6711
  if (/task.?complete|all tests pass/i.test(content)) {
6691
6712
  completed = true;
6692
- summary = content.slice(0, 200);
6713
+ summary = content;
6693
6714
  break;
6694
6715
  }
6695
6716
  messages.push({
@@ -7061,8 +7082,11 @@ function renderTaskComplete(summary, turns, toolCalls, durationMs) {
7061
7082
  ${c2.green("\u2714")} ${c2.bold("Task completed")} ${c2.dim(`(${turns} turns, ${toolCalls} tool calls, ${duration})`)}
7062
7083
  `);
7063
7084
  if (summary) {
7064
- process.stdout.write(` ${summary}
7085
+ const lines = summary.split("\n");
7086
+ for (const line of lines) {
7087
+ process.stdout.write(` ${line}
7065
7088
  `);
7089
+ }
7066
7090
  }
7067
7091
  process.stdout.write("\n");
7068
7092
  }
@@ -7519,17 +7543,17 @@ async function handleUpdate() {
7519
7543
  try {
7520
7544
  const { createRequire: createRequire3 } = await import("node:module");
7521
7545
  const { fileURLToPath: fileURLToPath2 } = await import("node:url");
7522
- const { dirname: dirname4, join: join20 } = await import("node:path");
7523
- const { existsSync: existsSync13 } = await import("node:fs");
7546
+ const { dirname: dirname4, join: join21 } = await import("node:path");
7547
+ const { existsSync: existsSync14 } = await import("node:fs");
7524
7548
  const req = createRequire3(import.meta.url);
7525
7549
  const thisDir = dirname4(fileURLToPath2(import.meta.url));
7526
7550
  const candidates = [
7527
- join20(thisDir, "..", "package.json"),
7528
- join20(thisDir, "..", "..", "package.json"),
7529
- join20(thisDir, "..", "..", "..", "package.json")
7551
+ join21(thisDir, "..", "package.json"),
7552
+ join21(thisDir, "..", "..", "package.json"),
7553
+ join21(thisDir, "..", "..", "..", "package.json")
7530
7554
  ];
7531
7555
  for (const pkgPath of candidates) {
7532
- if (existsSync13(pkgPath)) {
7556
+ if (existsSync14(pkgPath)) {
7533
7557
  const pkg = req(pkgPath);
7534
7558
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
7535
7559
  currentVersion = pkg.version ?? "0.0.0";
@@ -7981,40 +8005,326 @@ var init_setup = __esm({
7981
8005
  }
7982
8006
  });
7983
8007
 
7984
- // packages/cli/dist/tui/project-context.js
7985
- import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "node:fs";
7986
- import { join as join14, basename as basename2 } from "node:path";
7987
- import { execSync as execSync9 } from "node:child_process";
7988
- import { homedir as homedir4, platform, release } from "node:os";
7989
- function loadProjectFiles(repoRoot) {
7990
- const sections = [];
8008
+ // packages/cli/dist/tui/oa-directory.js
8009
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync4, statSync as statSync5 } from "node:fs";
8010
+ import { join as join14, relative as relative2, basename as basename2, extname as extname4 } from "node:path";
8011
+ function initOaDirectory(repoRoot) {
8012
+ const oaPath = join14(repoRoot, OA_DIR);
8013
+ for (const sub of SUBDIRS) {
8014
+ mkdirSync4(join14(oaPath, sub), { recursive: true });
8015
+ }
8016
+ return oaPath;
8017
+ }
8018
+ function hasOaDirectory(repoRoot) {
8019
+ return existsSync9(join14(repoRoot, OA_DIR, "index"));
8020
+ }
8021
+ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
8022
+ const found = [];
8023
+ const seen = /* @__PURE__ */ new Set();
7991
8024
  let dir = repoRoot;
7992
8025
  const visited = /* @__PURE__ */ new Set();
7993
8026
  while (dir && !visited.has(dir)) {
7994
8027
  visited.add(dir);
7995
- for (const name of CONTEXT_FILE_NAMES) {
8028
+ for (const name of CONTEXT_FILES) {
7996
8029
  const filePath = join14(dir, name);
7997
- if (existsSync9(filePath)) {
8030
+ const normalizedName = name.toLowerCase();
8031
+ if (existsSync9(filePath) && !seen.has(filePath)) {
8032
+ seen.add(filePath);
7998
8033
  try {
7999
- const content = readFileSync7(filePath, "utf-8").trim();
8000
- if (content) {
8001
- const relativePath = dir === repoRoot ? name : `${dir}/${name}`;
8002
- sections.push(`# Project Context (${relativePath})
8003
-
8004
- ${content}`);
8034
+ let content = readFileSync7(filePath, "utf-8");
8035
+ if (content.length > maxContentLen) {
8036
+ content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
8005
8037
  }
8038
+ const type = normalizedName.includes("agents") ? "agents" : normalizedName === "oa.md" || normalizedName === ".open-agents.md" ? "oa" : normalizedName.includes("claude") ? "claude" : normalizedName.includes("readme") ? "readme" : normalizedName.includes("architect") ? "architecture" : normalizedName.includes("contribut") ? "contributing" : "other";
8039
+ found.push({
8040
+ path: relative2(repoRoot, filePath) || name,
8041
+ content,
8042
+ type
8043
+ });
8006
8044
  } catch {
8007
8045
  }
8008
8046
  }
8009
8047
  }
8048
+ const projectMap = join14(dir, OA_DIR, "context", "project-map.md");
8049
+ if (existsSync9(projectMap) && !seen.has(projectMap)) {
8050
+ seen.add(projectMap);
8051
+ try {
8052
+ let content = readFileSync7(projectMap, "utf-8");
8053
+ if (content.length > maxContentLen) {
8054
+ content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
8055
+ }
8056
+ found.push({
8057
+ path: relative2(repoRoot, projectMap),
8058
+ content,
8059
+ type: "oa"
8060
+ });
8061
+ } catch {
8062
+ }
8063
+ }
8010
8064
  const parent = join14(dir, "..");
8011
8065
  if (parent === dir)
8012
8066
  break;
8013
8067
  dir = parent;
8014
8068
  }
8015
- sections.reverse();
8069
+ const priority = {
8070
+ agents: 0,
8071
+ oa: 1,
8072
+ claude: 2,
8073
+ architecture: 3,
8074
+ contributing: 4,
8075
+ readme: 5,
8076
+ other: 6
8077
+ };
8078
+ found.sort((a, b) => (priority[a.type] ?? 6) - (priority[b.type] ?? 6));
8079
+ return found;
8080
+ }
8081
+ function readIndexMeta(repoRoot) {
8082
+ const metaPath = join14(repoRoot, OA_DIR, "index", "meta.json");
8083
+ try {
8084
+ return JSON.parse(readFileSync7(metaPath, "utf-8"));
8085
+ } catch {
8086
+ return null;
8087
+ }
8088
+ }
8089
+ function generateProjectMap(repoRoot) {
8090
+ const sections = [];
8091
+ const repoName2 = basename2(repoRoot);
8092
+ sections.push(`# Project Map: ${repoName2}
8093
+ `);
8094
+ sections.push(`> Auto-generated by open-agents. Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
8095
+ `);
8096
+ const manifests = detectManifests(repoRoot);
8097
+ if (manifests.length > 0) {
8098
+ sections.push(`## Project Type
8099
+ `);
8100
+ for (const m of manifests) {
8101
+ sections.push(`- ${m.type}: \`${m.file}\``);
8102
+ if (m.name)
8103
+ sections[sections.length - 1] += ` (${m.name})`;
8104
+ }
8105
+ sections.push("");
8106
+ }
8107
+ const tree = buildDirTree(repoRoot, 2);
8108
+ if (tree) {
8109
+ sections.push(`## Directory Structure
8110
+
8111
+ \`\`\`
8112
+ ${tree}\`\`\`
8113
+ `);
8114
+ }
8115
+ const keyFiles = findKeyFiles(repoRoot);
8116
+ if (keyFiles.length > 0) {
8117
+ sections.push(`## Key Files
8118
+ `);
8119
+ for (const f of keyFiles) {
8120
+ sections.push(`- \`${f.path}\` \u2014 ${f.description}`);
8121
+ }
8122
+ sections.push("");
8123
+ }
8124
+ const meta = readIndexMeta(repoRoot);
8125
+ if (meta && Object.keys(meta.languages).length > 0) {
8126
+ sections.push(`## Languages
8127
+ `);
8128
+ const sorted = Object.entries(meta.languages).sort((a, b) => b[1] - a[1]);
8129
+ for (const [lang, count] of sorted.slice(0, 8)) {
8130
+ sections.push(`- ${lang}: ${count} files`);
8131
+ }
8132
+ sections.push("");
8133
+ }
8134
+ const content = sections.join("\n");
8135
+ const contextDir = join14(repoRoot, OA_DIR, "context");
8136
+ mkdirSync4(contextDir, { recursive: true });
8137
+ writeFileSync4(join14(contextDir, "project-map.md"), content, "utf-8");
8138
+ return content;
8139
+ }
8140
+ function saveSession(repoRoot, session) {
8141
+ const historyDir = join14(repoRoot, OA_DIR, "history");
8142
+ mkdirSync4(historyDir, { recursive: true });
8143
+ writeFileSync4(join14(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
8144
+ }
8145
+ function loadRecentSessions(repoRoot, limit = 5) {
8146
+ const historyDir = join14(repoRoot, OA_DIR, "history");
8147
+ if (!existsSync9(historyDir))
8148
+ return [];
8149
+ try {
8150
+ const files = readdirSync4(historyDir).filter((f) => f.endsWith(".json")).map((f) => {
8151
+ const stat3 = statSync5(join14(historyDir, f));
8152
+ return { file: f, mtime: stat3.mtimeMs };
8153
+ }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
8154
+ return files.map((f) => {
8155
+ try {
8156
+ return JSON.parse(readFileSync7(join14(historyDir, f.file), "utf-8"));
8157
+ } catch {
8158
+ return null;
8159
+ }
8160
+ }).filter((s) => s !== null);
8161
+ } catch {
8162
+ return [];
8163
+ }
8164
+ }
8165
+ function detectManifests(repoRoot) {
8166
+ const manifests = [];
8167
+ const checks = [
8168
+ { file: "package.json", type: "Node.js", nameField: "name" },
8169
+ { file: "pyproject.toml", type: "Python" },
8170
+ { file: "Cargo.toml", type: "Rust" },
8171
+ { file: "go.mod", type: "Go" },
8172
+ { file: "pom.xml", type: "Java (Maven)" },
8173
+ { file: "build.gradle", type: "Java (Gradle)" },
8174
+ { file: "Gemfile", type: "Ruby" },
8175
+ { file: "composer.json", type: "PHP" },
8176
+ { file: "pnpm-workspace.yaml", type: "pnpm Monorepo" },
8177
+ { file: "lerna.json", type: "Lerna Monorepo" },
8178
+ { file: "Dockerfile", type: "Docker" },
8179
+ { file: "docker-compose.yml", type: "Docker Compose" },
8180
+ { file: "docker-compose.yaml", type: "Docker Compose" }
8181
+ ];
8182
+ for (const check of checks) {
8183
+ const filePath = join14(repoRoot, check.file);
8184
+ if (existsSync9(filePath)) {
8185
+ let name;
8186
+ if (check.nameField) {
8187
+ try {
8188
+ const data = JSON.parse(readFileSync7(filePath, "utf-8"));
8189
+ name = data[check.nameField];
8190
+ } catch {
8191
+ }
8192
+ }
8193
+ manifests.push({ file: check.file, type: check.type, name });
8194
+ }
8195
+ }
8196
+ return manifests;
8197
+ }
8198
+ function findKeyFiles(repoRoot) {
8199
+ const keyFiles = [];
8200
+ const checks = [
8201
+ { pattern: "package.json", description: "Node.js project manifest" },
8202
+ { pattern: "tsconfig.json", description: "TypeScript configuration" },
8203
+ { pattern: ".eslintrc.json", description: "ESLint configuration" },
8204
+ { pattern: ".prettierrc", description: "Prettier configuration" },
8205
+ { pattern: "vitest.config.ts", description: "Vitest test config" },
8206
+ { pattern: "jest.config.js", description: "Jest test config" },
8207
+ { pattern: "Makefile", description: "Build automation" },
8208
+ { pattern: ".github/workflows", description: "GitHub Actions CI/CD" },
8209
+ { pattern: ".gitlab-ci.yml", description: "GitLab CI/CD" },
8210
+ { pattern: "Dockerfile", description: "Container definition" },
8211
+ { pattern: ".env.example", description: "Environment template" },
8212
+ { pattern: "AGENTS.md", description: "Agent instructions" },
8213
+ { pattern: "OA.md", description: "Open Agents context" },
8214
+ { pattern: "CLAUDE.md", description: "Claude Code context" }
8215
+ ];
8216
+ for (const check of checks) {
8217
+ if (existsSync9(join14(repoRoot, check.pattern))) {
8218
+ keyFiles.push({ path: check.pattern, description: check.description });
8219
+ }
8220
+ }
8221
+ return keyFiles;
8222
+ }
8223
+ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
8224
+ if (depth > maxDepth)
8225
+ return "";
8226
+ let result = "";
8227
+ try {
8228
+ const entries = readdirSync4(root, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") || e.name === ".github").filter((e) => !SKIP_DIRS.has(e.name)).sort((a, b) => {
8229
+ if (a.isDirectory() && !b.isDirectory())
8230
+ return -1;
8231
+ if (!a.isDirectory() && b.isDirectory())
8232
+ return 1;
8233
+ return a.name.localeCompare(b.name);
8234
+ });
8235
+ for (let i = 0; i < entries.length; i++) {
8236
+ const entry = entries[i];
8237
+ const isLast = i === entries.length - 1;
8238
+ const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
8239
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
8240
+ if (entry.isDirectory()) {
8241
+ let fileCount = 0;
8242
+ try {
8243
+ fileCount = readdirSync4(join14(root, entry.name)).filter((f) => !f.startsWith(".")).length;
8244
+ } catch {
8245
+ }
8246
+ result += `${prefix}${connector}${entry.name}/ (${fileCount})
8247
+ `;
8248
+ result += buildDirTree(join14(root, entry.name), maxDepth, childPrefix, depth + 1);
8249
+ } else if (depth < maxDepth) {
8250
+ result += `${prefix}${connector}${entry.name}
8251
+ `;
8252
+ }
8253
+ }
8254
+ } catch {
8255
+ }
8256
+ return result;
8257
+ }
8258
+ var OA_DIR, SUBDIRS, CONTEXT_FILES, SKIP_DIRS;
8259
+ var init_oa_directory = __esm({
8260
+ "packages/cli/dist/tui/oa-directory.js"() {
8261
+ "use strict";
8262
+ OA_DIR = ".oa";
8263
+ SUBDIRS = ["memory", "index", "context", "history"];
8264
+ CONTEXT_FILES = [
8265
+ "AGENTS.md",
8266
+ "OA.md",
8267
+ ".open-agents.md",
8268
+ "CLAUDE.md",
8269
+ "README.md",
8270
+ "ARCHITECTURE.md",
8271
+ "CONTRIBUTING.md",
8272
+ "AGENTS.md"
8273
+ ];
8274
+ SKIP_DIRS = /* @__PURE__ */ new Set([
8275
+ "node_modules",
8276
+ ".git",
8277
+ "dist",
8278
+ "build",
8279
+ ".next",
8280
+ "__pycache__",
8281
+ ".venv",
8282
+ "venv",
8283
+ "coverage",
8284
+ ".nyc_output",
8285
+ ".oa",
8286
+ ".open-agents",
8287
+ ".claude",
8288
+ "vendor",
8289
+ "target",
8290
+ ".idea",
8291
+ ".vscode"
8292
+ ]);
8293
+ }
8294
+ });
8295
+
8296
+ // packages/cli/dist/tui/project-context.js
8297
+ import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync as readdirSync5 } from "node:fs";
8298
+ import { join as join15, basename as basename3 } from "node:path";
8299
+ import { execSync as execSync9 } from "node:child_process";
8300
+ import { homedir as homedir4, platform, release } from "node:os";
8301
+ function loadProjectFiles(repoRoot) {
8302
+ const discovered = discoverContextFiles(repoRoot);
8303
+ if (discovered.length === 0)
8304
+ return "";
8305
+ const sections = [];
8306
+ for (const ctx of discovered) {
8307
+ const header = ctx.type === "agents" ? "Agent Instructions" : ctx.type === "oa" ? "Open Agents Context" : ctx.type === "claude" ? "Project Instructions" : ctx.type === "architecture" ? "Architecture" : ctx.type === "contributing" ? "Contributing Guidelines" : ctx.type === "readme" ? "Project Overview" : "Additional Context";
8308
+ sections.push(`# ${header} (${ctx.path})
8309
+
8310
+ ${ctx.content}`);
8311
+ }
8016
8312
  return sections.join("\n\n---\n\n");
8017
8313
  }
8314
+ function loadProjectMap(repoRoot) {
8315
+ if (!hasOaDirectory(repoRoot)) {
8316
+ initOaDirectory(repoRoot);
8317
+ }
8318
+ const mapPath = join15(repoRoot, OA_DIR, "context", "project-map.md");
8319
+ if (existsSync10(mapPath)) {
8320
+ try {
8321
+ const content = readFileSync8(mapPath, "utf-8");
8322
+ return content;
8323
+ } catch {
8324
+ }
8325
+ }
8326
+ return generateProjectMap(repoRoot);
8327
+ }
8018
8328
  function getGitInfo(repoRoot) {
8019
8329
  try {
8020
8330
  execSync9("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
@@ -8049,29 +8359,33 @@ ${log}`);
8049
8359
  }
8050
8360
  function loadMemoryContext(repoRoot) {
8051
8361
  const sections = [];
8052
- const projectMemDir = join14(repoRoot, ".open-agents", "memory");
8053
- const projectEntries = loadMemoryDir(projectMemDir, "project");
8054
- if (projectEntries)
8055
- sections.push(projectEntries);
8056
- const globalMemDir = join14(homedir4(), ".open-agents", "memory");
8057
- if (globalMemDir !== projectMemDir) {
8058
- const globalEntries = loadMemoryDir(globalMemDir, "global");
8059
- if (globalEntries)
8060
- sections.push(globalEntries);
8061
- }
8362
+ const oaMemDir = join15(repoRoot, OA_DIR, "memory");
8363
+ const oaEntries = loadMemoryDir(oaMemDir, "project");
8364
+ if (oaEntries)
8365
+ sections.push(oaEntries);
8366
+ const legacyMemDir = join15(repoRoot, ".open-agents", "memory");
8367
+ if (legacyMemDir !== oaMemDir && existsSync10(legacyMemDir)) {
8368
+ const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
8369
+ if (legacyEntries)
8370
+ sections.push(legacyEntries);
8371
+ }
8372
+ const globalMemDir = join15(homedir4(), ".open-agents", "memory");
8373
+ const globalEntries = loadMemoryDir(globalMemDir, "global");
8374
+ if (globalEntries)
8375
+ sections.push(globalEntries);
8062
8376
  return sections.join("\n\n");
8063
8377
  }
8064
8378
  function loadMemoryDir(memDir, scope) {
8065
- if (!existsSync9(memDir))
8379
+ if (!existsSync10(memDir))
8066
8380
  return "";
8067
8381
  const lines = [];
8068
8382
  try {
8069
- const files = readdirSync4(memDir).filter((f) => f.endsWith(".json"));
8383
+ const files = readdirSync5(memDir).filter((f) => f.endsWith(".json"));
8070
8384
  for (const file of files.slice(0, 10)) {
8071
8385
  try {
8072
- const raw = readFileSync7(join14(memDir, file), "utf-8");
8386
+ const raw = readFileSync8(join15(memDir, file), "utf-8");
8073
8387
  const entries = JSON.parse(raw);
8074
- const topic = basename2(file, ".json");
8388
+ const topic = basename3(file, ".json");
8075
8389
  const keys = Object.keys(entries);
8076
8390
  if (keys.length === 0)
8077
8391
  continue;
@@ -8089,6 +8403,21 @@ function loadMemoryDir(memDir, scope) {
8089
8403
  }
8090
8404
  return lines.join("\n");
8091
8405
  }
8406
+ function loadSessionHistory(repoRoot) {
8407
+ const sessions = loadRecentSessions(repoRoot, 5);
8408
+ if (sessions.length === 0)
8409
+ return "";
8410
+ const lines = ["Recent tasks in this project:"];
8411
+ for (const s of sessions) {
8412
+ const status = s.completed ? "completed" : "incomplete";
8413
+ const date = s.startedAt.split("T")[0];
8414
+ lines.push(`- [${date}] ${s.task.slice(0, 80)} (${status}, ${s.turns} turns)`);
8415
+ if (s.summary) {
8416
+ lines.push(` Summary: ${s.summary.slice(0, 120)}`);
8417
+ }
8418
+ }
8419
+ return lines.join("\n");
8420
+ }
8092
8421
  function getEnvironment(repoRoot) {
8093
8422
  const lines = [
8094
8423
  `Working directory: ${repoRoot}`,
@@ -8101,8 +8430,10 @@ function getEnvironment(repoRoot) {
8101
8430
  function buildProjectContext(repoRoot) {
8102
8431
  return {
8103
8432
  projectInstructions: loadProjectFiles(repoRoot),
8433
+ projectMap: loadProjectMap(repoRoot),
8104
8434
  gitInfo: getGitInfo(repoRoot),
8105
8435
  memoryContext: loadMemoryContext(repoRoot),
8436
+ sessionHistory: loadSessionHistory(repoRoot),
8106
8437
  environment: getEnvironment(repoRoot)
8107
8438
  };
8108
8439
  }
@@ -8117,6 +8448,11 @@ ${ctx.environment}`);
8117
8448
  sections.push(`## Git State
8118
8449
 
8119
8450
  ${ctx.gitInfo}`);
8451
+ }
8452
+ if (ctx.projectMap) {
8453
+ sections.push(`## Project Map
8454
+
8455
+ ${ctx.projectMap}`);
8120
8456
  }
8121
8457
  if (ctx.projectInstructions) {
8122
8458
  sections.push(ctx.projectInstructions);
@@ -8127,36 +8463,35 @@ ${ctx.gitInfo}`);
8127
8463
  ${ctx.memoryContext}
8128
8464
 
8129
8465
  Use this context to avoid re-learning known patterns. Update with memory_write if you discover new insights.`);
8466
+ }
8467
+ if (ctx.sessionHistory) {
8468
+ sections.push(`## Session History
8469
+
8470
+ ${ctx.sessionHistory}`);
8130
8471
  }
8131
8472
  return sections.join("\n\n");
8132
8473
  }
8133
- var CONTEXT_FILE_NAMES;
8134
8474
  var init_project_context = __esm({
8135
8475
  "packages/cli/dist/tui/project-context.js"() {
8136
8476
  "use strict";
8137
- CONTEXT_FILE_NAMES = [
8138
- ".open-agents.md",
8139
- "AGENTS.md",
8140
- ".open-agents/context.md",
8141
- ".open-agents/instructions.md"
8142
- ];
8477
+ init_oa_directory();
8143
8478
  }
8144
8479
  });
8145
8480
 
8146
8481
  // packages/cli/dist/tui/voice.js
8147
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync8, unlinkSync } from "node:fs";
8148
- import { join as join15 } from "node:path";
8482
+ import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readFileSync as readFileSync9, unlinkSync } from "node:fs";
8483
+ import { join as join16 } from "node:path";
8149
8484
  import { homedir as homedir5, tmpdir as tmpdir2, platform as platform2 } from "node:os";
8150
8485
  import { execSync as execSync10, spawn as nodeSpawn } from "node:child_process";
8151
8486
  import { createRequire } from "node:module";
8152
8487
  function modelDir(id) {
8153
- return join15(MODELS_DIR, id);
8488
+ return join16(MODELS_DIR, id);
8154
8489
  }
8155
8490
  function modelOnnxPath(id) {
8156
- return join15(modelDir(id), "model.onnx");
8491
+ return join16(modelDir(id), "model.onnx");
8157
8492
  }
8158
8493
  function modelConfigPath(id) {
8159
- return join15(modelDir(id), "config.json");
8494
+ return join16(modelDir(id), "config.json");
8160
8495
  }
8161
8496
  function describeToolCall(toolName, args) {
8162
8497
  const path = args["path"];
@@ -8265,8 +8600,8 @@ var init_voice = __esm({
8265
8600
  configUrl: "https://raw.githubusercontent.com/robit-man/combine_overwatch_onnx/main/overwatch.onnx.json"
8266
8601
  }
8267
8602
  };
8268
- VOICE_DIR = join15(homedir5(), ".open-agents", "voice");
8269
- MODELS_DIR = join15(VOICE_DIR, "models");
8603
+ VOICE_DIR = join16(homedir5(), ".open-agents", "voice");
8604
+ MODELS_DIR = join16(VOICE_DIR, "models");
8270
8605
  VoiceEngine = class {
8271
8606
  enabled = false;
8272
8607
  modelId = "glados";
@@ -8386,7 +8721,7 @@ var init_voice = __esm({
8386
8721
  const audioData = result["output"].data;
8387
8722
  if (audioData.length === 0)
8388
8723
  return;
8389
- const wavPath = join15(tmpdir2(), `oa-voice-${Date.now()}.wav`);
8724
+ const wavPath = join16(tmpdir2(), `oa-voice-${Date.now()}.wav`);
8390
8725
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
8391
8726
  await this.playWav(wavPath);
8392
8727
  try {
@@ -8466,7 +8801,7 @@ var init_voice = __esm({
8466
8801
  buffer.write("data", 36);
8467
8802
  buffer.writeUInt32LE(dataSize, 40);
8468
8803
  Buffer.from(int16.buffer, int16.byteOffset, int16.byteLength).copy(buffer, 44);
8469
- writeFileSync4(path, buffer);
8804
+ writeFileSync5(path, buffer);
8470
8805
  }
8471
8806
  // -------------------------------------------------------------------------
8472
8807
  // Audio playback (system default speakers)
@@ -8533,30 +8868,30 @@ var init_voice = __esm({
8533
8868
  async ensureRuntime() {
8534
8869
  if (this.ort)
8535
8870
  return;
8536
- mkdirSync4(VOICE_DIR, { recursive: true });
8537
- const pkgPath = join15(VOICE_DIR, "package.json");
8871
+ mkdirSync5(VOICE_DIR, { recursive: true });
8872
+ const pkgPath = join16(VOICE_DIR, "package.json");
8538
8873
  const expectedDeps = {
8539
8874
  "onnxruntime-node": "^1.21.0",
8540
8875
  "phonemizer": "^1.2.1"
8541
8876
  };
8542
- if (existsSync10(pkgPath)) {
8877
+ if (existsSync11(pkgPath)) {
8543
8878
  try {
8544
- const existing = JSON.parse(readFileSync8(pkgPath, "utf8"));
8879
+ const existing = JSON.parse(readFileSync9(pkgPath, "utf8"));
8545
8880
  if (!existing.dependencies?.["phonemizer"]) {
8546
8881
  existing.dependencies = { ...existing.dependencies, ...expectedDeps };
8547
- writeFileSync4(pkgPath, JSON.stringify(existing, null, 2));
8882
+ writeFileSync5(pkgPath, JSON.stringify(existing, null, 2));
8548
8883
  }
8549
8884
  } catch {
8550
8885
  }
8551
8886
  }
8552
- if (!existsSync10(pkgPath)) {
8553
- writeFileSync4(pkgPath, JSON.stringify({
8887
+ if (!existsSync11(pkgPath)) {
8888
+ writeFileSync5(pkgPath, JSON.stringify({
8554
8889
  name: "open-agents-voice",
8555
8890
  private: true,
8556
8891
  dependencies: expectedDeps
8557
8892
  }, null, 2));
8558
8893
  }
8559
- const voiceRequire = createRequire(join15(VOICE_DIR, "index.js"));
8894
+ const voiceRequire = createRequire(join16(VOICE_DIR, "index.js"));
8560
8895
  try {
8561
8896
  this.ort = voiceRequire("onnxruntime-node");
8562
8897
  } catch {
@@ -8602,18 +8937,18 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
8602
8937
  const dir = modelDir(id);
8603
8938
  const onnxPath = modelOnnxPath(id);
8604
8939
  const configPath = modelConfigPath(id);
8605
- if (existsSync10(onnxPath) && existsSync10(configPath))
8940
+ if (existsSync11(onnxPath) && existsSync11(configPath))
8606
8941
  return;
8607
- mkdirSync4(dir, { recursive: true });
8608
- if (!existsSync10(configPath)) {
8942
+ mkdirSync5(dir, { recursive: true });
8943
+ if (!existsSync11(configPath)) {
8609
8944
  renderInfo(`Downloading ${model.label} voice config...`);
8610
8945
  const configResp = await fetch(model.configUrl);
8611
8946
  if (!configResp.ok)
8612
8947
  throw new Error(`Failed to download config: HTTP ${configResp.status}`);
8613
8948
  const configText = await configResp.text();
8614
- writeFileSync4(configPath, configText);
8949
+ writeFileSync5(configPath, configText);
8615
8950
  }
8616
- if (!existsSync10(onnxPath)) {
8951
+ if (!existsSync11(onnxPath)) {
8617
8952
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
8618
8953
  const onnxResp = await fetch(model.onnxUrl);
8619
8954
  if (!onnxResp.ok)
@@ -8637,7 +8972,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
8637
8972
  }
8638
8973
  process.stdout.write("\r" + " ".repeat(60) + "\r");
8639
8974
  const fullBuffer = Buffer.concat(chunks);
8640
- writeFileSync4(onnxPath, fullBuffer);
8975
+ writeFileSync5(onnxPath, fullBuffer);
8641
8976
  renderInfo(`${model.label} model downloaded (${formatBytes2(fullBuffer.length)}).`);
8642
8977
  }
8643
8978
  }
@@ -8649,10 +8984,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
8649
8984
  throw new Error("ONNX runtime not loaded");
8650
8985
  const onnxPath = modelOnnxPath(this.modelId);
8651
8986
  const configPath = modelConfigPath(this.modelId);
8652
- if (!existsSync10(onnxPath) || !existsSync10(configPath)) {
8987
+ if (!existsSync11(onnxPath) || !existsSync11(configPath)) {
8653
8988
  throw new Error(`Model files not found for ${this.modelId}`);
8654
8989
  }
8655
- this.config = JSON.parse(readFileSync8(configPath, "utf8"));
8990
+ this.config = JSON.parse(readFileSync9(configPath, "utf8"));
8656
8991
  renderInfo("Loading voice model...");
8657
8992
  this.session = await this.ort.InferenceSession.create(onnxPath, {
8658
8993
  executionProviders: ["cpu"],
@@ -8668,9 +9003,9 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
8668
9003
  import * as readline2 from "node:readline";
8669
9004
  import { cwd } from "node:process";
8670
9005
  import { resolve as resolve11 } from "node:path";
8671
- import { readFileSync as readFileSync9 } from "node:fs";
8672
- import { existsSync as existsSync11 } from "node:fs";
8673
- import { extname as extname4 } from "node:path";
9006
+ import { readFileSync as readFileSync10 } from "node:fs";
9007
+ import { existsSync as existsSync12 } from "node:fs";
9008
+ import { extname as extname5 } from "node:path";
8674
9009
  function adaptTool(tool) {
8675
9010
  return {
8676
9011
  name: tool.name,
@@ -8859,12 +9194,26 @@ function startTask(task, config, repoRoot, voice) {
8859
9194
  break;
8860
9195
  }
8861
9196
  });
9197
+ const sessionId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
8862
9198
  const promise = runner.run(task, `Working directory: ${repoRoot}`).then((result) => {
8863
9199
  if (result.completed) {
8864
9200
  renderTaskComplete(result.summary, result.turns, result.toolCalls, result.durationMs);
8865
9201
  } else {
8866
9202
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs);
8867
9203
  }
9204
+ try {
9205
+ saveSession(repoRoot, {
9206
+ id: sessionId,
9207
+ startedAt: new Date(Date.now() - result.durationMs).toISOString(),
9208
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
9209
+ task,
9210
+ turns: result.turns,
9211
+ toolCalls: result.toolCalls,
9212
+ completed: result.completed,
9213
+ summary: result.summary.slice(0, 500)
9214
+ });
9215
+ } catch {
9216
+ }
8868
9217
  });
8869
9218
  return { runner, promise };
8870
9219
  }
@@ -8968,14 +9317,14 @@ ${c2.dim("Goodbye!")}
8968
9317
  }
8969
9318
  }
8970
9319
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
8971
- const isImage = isImagePath(cleanPath) && existsSync11(resolve11(repoRoot, cleanPath));
9320
+ const isImage = isImagePath(cleanPath) && existsSync12(resolve11(repoRoot, cleanPath));
8972
9321
  if (activeTask) {
8973
9322
  if (isImage) {
8974
9323
  try {
8975
9324
  const imgPath = resolve11(repoRoot, cleanPath);
8976
- const imgBuffer = readFileSync9(imgPath);
9325
+ const imgBuffer = readFileSync10(imgPath);
8977
9326
  const base64 = imgBuffer.toString("base64");
8978
- const ext = extname4(cleanPath).toLowerCase();
9327
+ const ext = extname5(cleanPath).toLowerCase();
8979
9328
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
8980
9329
  activeTask.runner.injectImage(base64, mime, `User shared image: ${cleanPath}`);
8981
9330
  renderUserInterrupt(`[Image: ${cleanPath}]`);
@@ -9071,6 +9420,7 @@ var init_interactive = __esm({
9071
9420
  init_commands();
9072
9421
  init_setup();
9073
9422
  init_project_context();
9423
+ init_oa_directory();
9074
9424
  init_render();
9075
9425
  init_voice();
9076
9426
  taskManager = new BackgroundTaskManager();
@@ -9108,7 +9458,7 @@ import { glob } from "glob";
9108
9458
  import ignore from "ignore";
9109
9459
  import { readFile as readFile8, stat as stat2 } from "node:fs/promises";
9110
9460
  import { createHash } from "node:crypto";
9111
- import { join as join16, relative as relative2, extname as extname5, basename as basename3 } from "node:path";
9461
+ import { join as join17, relative as relative3, extname as extname6, basename as basename4 } from "node:path";
9112
9462
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
9113
9463
  var init_codebase_indexer = __esm({
9114
9464
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -9152,7 +9502,7 @@ var init_codebase_indexer = __esm({
9152
9502
  const ig = ignore.default();
9153
9503
  if (this.config.respectGitignore) {
9154
9504
  try {
9155
- const gitignoreContent = await readFile8(join16(this.config.rootDir, ".gitignore"), "utf-8");
9505
+ const gitignoreContent = await readFile8(join17(this.config.rootDir, ".gitignore"), "utf-8");
9156
9506
  ig.add(gitignoreContent);
9157
9507
  } catch {
9158
9508
  }
@@ -9167,14 +9517,14 @@ var init_codebase_indexer = __esm({
9167
9517
  for (const relativePath of files) {
9168
9518
  if (ig.ignores(relativePath))
9169
9519
  continue;
9170
- const fullPath = join16(this.config.rootDir, relativePath);
9520
+ const fullPath = join17(this.config.rootDir, relativePath);
9171
9521
  try {
9172
9522
  const fileStat = await stat2(fullPath);
9173
9523
  if (fileStat.size > this.config.maxFileSize)
9174
9524
  continue;
9175
9525
  const content = await readFile8(fullPath);
9176
9526
  const hash = createHash("sha256").update(content).digest("hex");
9177
- const ext = extname5(relativePath);
9527
+ const ext = extname6(relativePath);
9178
9528
  indexed.push({
9179
9529
  path: fullPath,
9180
9530
  relativePath,
@@ -9190,7 +9540,7 @@ var init_codebase_indexer = __esm({
9190
9540
  }
9191
9541
  buildTree(files) {
9192
9542
  const root = {
9193
- name: basename3(this.config.rootDir),
9543
+ name: basename4(this.config.rootDir),
9194
9544
  path: this.config.rootDir,
9195
9545
  type: "directory",
9196
9546
  children: []
@@ -9213,7 +9563,7 @@ var init_codebase_indexer = __esm({
9213
9563
  if (!child) {
9214
9564
  child = {
9215
9565
  name: part,
9216
- path: join16(current.path, part),
9566
+ path: join17(current.path, part),
9217
9567
  type: "directory",
9218
9568
  children: []
9219
9569
  };
@@ -9288,17 +9638,17 @@ __export(index_repo_exports, {
9288
9638
  indexRepoCommand: () => indexRepoCommand
9289
9639
  });
9290
9640
  import { resolve as resolve12 } from "node:path";
9291
- import { existsSync as existsSync12, statSync as statSync5 } from "node:fs";
9641
+ import { existsSync as existsSync13, statSync as statSync6 } from "node:fs";
9292
9642
  import { cwd as cwd2 } from "node:process";
9293
9643
  async function indexRepoCommand(opts, _config) {
9294
9644
  const repoRoot = resolve12(opts.repoPath ?? cwd2());
9295
9645
  printHeader("Index Repository");
9296
9646
  printInfo(`Indexing: ${repoRoot}`);
9297
- if (!existsSync12(repoRoot)) {
9647
+ if (!existsSync13(repoRoot)) {
9298
9648
  printError(`Path does not exist: ${repoRoot}`);
9299
9649
  process.exit(1);
9300
9650
  }
9301
- const stat3 = statSync5(repoRoot);
9651
+ const stat3 = statSync6(repoRoot);
9302
9652
  if (!stat3.isDirectory()) {
9303
9653
  printError(`Path is not a directory: ${repoRoot}`);
9304
9654
  process.exit(1);
@@ -9540,7 +9890,7 @@ var config_exports = {};
9540
9890
  __export(config_exports, {
9541
9891
  configCommand: () => configCommand
9542
9892
  });
9543
- import { join as join17 } from "node:path";
9893
+ import { join as join18 } from "node:path";
9544
9894
  import { homedir as homedir6 } from "node:os";
9545
9895
  async function configCommand(opts, config) {
9546
9896
  if (opts.subCommand === "set") {
@@ -9563,7 +9913,7 @@ function handleShow(opts, config) {
9563
9913
  printKeyValue("verbose", String(config.verbose), 2);
9564
9914
  printKeyValue("dbPath", config.dbPath, 2);
9565
9915
  printSection("Config File");
9566
- printInfo(`~/.open-agents/config.json (${join17(homedir6(), ".open-agents", "config.json")})`);
9916
+ printInfo(`~/.open-agents/config.json (${join18(homedir6(), ".open-agents", "config.json")})`);
9567
9917
  printSection("Environment Variables");
9568
9918
  printInfo("OPEN_AGENTS_BACKEND_URL \u2014 override backendUrl");
9569
9919
  printInfo("OPEN_AGENTS_MODEL \u2014 override model");
@@ -9795,8 +10145,8 @@ __export(eval_exports, {
9795
10145
  evalCommand: () => evalCommand
9796
10146
  });
9797
10147
  import { tmpdir as tmpdir3 } from "node:os";
9798
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
9799
- import { join as join18 } from "node:path";
10148
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
10149
+ import { join as join19 } from "node:path";
9800
10150
  async function evalCommand(opts, config) {
9801
10151
  const suiteName = opts.suite ?? "basic";
9802
10152
  const suite = SUITES[suiteName];
@@ -9917,9 +10267,9 @@ async function evalCommand(opts, config) {
9917
10267
  process.exit(failed > 0 ? 1 : 0);
9918
10268
  }
9919
10269
  function createTempEvalRepo() {
9920
- const dir = join18(tmpdir3(), `open-agents-eval-${Date.now()}`);
9921
- mkdirSync5(dir, { recursive: true });
9922
- writeFileSync5(join18(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
10270
+ const dir = join19(tmpdir3(), `open-agents-eval-${Date.now()}`);
10271
+ mkdirSync6(dir, { recursive: true });
10272
+ writeFileSync6(join19(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
9923
10273
  return dir;
9924
10274
  }
9925
10275
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -9979,7 +10329,7 @@ init_updater();
9979
10329
  import { parseArgs as nodeParseArgs2 } from "node:util";
9980
10330
  import { createRequire as createRequire2 } from "node:module";
9981
10331
  import { fileURLToPath } from "node:url";
9982
- import { dirname as dirname3, join as join19 } from "node:path";
10332
+ import { dirname as dirname3, join as join20 } from "node:path";
9983
10333
 
9984
10334
  // packages/cli/dist/cli.js
9985
10335
  import { createInterface } from "node:readline";
@@ -10086,7 +10436,7 @@ init_output();
10086
10436
  function getVersion() {
10087
10437
  try {
10088
10438
  const require2 = createRequire2(import.meta.url);
10089
- const pkgPath = join19(dirname3(fileURLToPath(import.meta.url)), "..", "package.json");
10439
+ const pkgPath = join20(dirname3(fileURLToPath(import.meta.url)), "..", "package.json");
10090
10440
  const pkg = require2(pkgPath);
10091
10441
  return pkg.version;
10092
10442
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — Claude Code-style TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",