open-agents-ai 0.31.6 → 0.31.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,59 +1,6 @@
1
- #!/usr/bin/env node
2
- /**
3
- * index.ts Main CLI entry point for @open-agents/cli
4
- *
5
- * Routes CLI arguments to the appropriate command handler.
6
- *
7
- * Commands:
8
- * open-agents "task" implicit run
9
- * open-agents run "task" explicit run
10
- * open-agents index /path/to/repo index a repository
11
- * open-agents status show system status
12
- * open-agents config show config
13
- * open-agents config set KEY VALUE set config key
14
- * open-agents serve start vLLM server
15
- * open-agents eval run eval suite
16
- * open-agents --help help
17
- * open-agents --version version
18
- */
19
- import type { BackendType } from "./config.js";
20
- export type CommandName = "run" | "index" | "status" | "config" | "serve" | "eval" | "unknown";
21
- export interface ParsedCliArgs {
22
- command: CommandName;
23
- /** Task text for the run command */
24
- task?: string;
25
- /** Repository path (for run and index commands) */
26
- repoPath?: string;
27
- /** Config sub-command (e.g. "set", "keys") */
28
- configSubCommand?: string;
29
- /** Config key (for config set) */
30
- configKey?: string;
31
- /** Config value (for config set) */
32
- configValue?: string;
33
- /** Eval suite name */
34
- evalSuite?: string;
35
- /** vLLM server port for serve command */
36
- servePort?: number;
37
- model?: string;
38
- backendUrl?: string;
39
- backendType?: BackendType;
40
- dryRun?: boolean;
41
- verbose?: boolean;
42
- maxRetries?: number;
43
- timeoutMs?: number;
44
- offline?: boolean;
45
- /** When true, config set writes to .oa/settings.json (project-local) */
46
- local?: boolean;
47
- help?: boolean;
48
- version?: boolean;
49
- }
50
- export declare function routeCommand(command: string): CommandName;
51
- export declare function parseCliArgs(argv: string[]): ParsedCliArgs;
52
- export { createCli } from "./cli.js";
53
- export { parseArgs } from "./args.js";
54
- export type { CliOptions } from "./types.js";
55
- export { loadConfig, mergeConfig, setConfigValue, DEFAULT_CONFIG } from "./config.js";
56
- export type { AgentConfig, BackendType } from "./config.js";
57
- export { Spinner } from "./ui/spinner.js";
58
- export { printHeader, printSuccess, printError, printWarning, printInfo, printSection, printKeyValue, printBlank, printReport, formatDuration, } from "./ui/output.js";
59
- //# sourceMappingURL=index.d.ts.map
1
+ export { parseCliArgs, routeCommand } from "./types.js";
2
+ export type { ParsedCliArgs, CommandName } from "./types.js";
3
+ export { loadConfig, mergeConfig, setConfigValue, DEFAULT_CONFIG } from "./types.js";
4
+ export type { AgentConfig, BackendType } from "./types.js";
5
+ export { Spinner } from "./types.js";
6
+ export { printHeader, printSuccess, printError, printWarning, printInfo, printSection, printKeyValue, printBlank, printReport, formatDuration } from "./types.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
5
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -14997,8 +14998,13 @@ function renderSlashHelp() {
14997
14998
  ["/evaluate", "Evaluate last completed task (LLM quality scoring)"],
14998
14999
  ["/task-type", "Set task type (code, document, analysis, plan, general, auto)"],
14999
15000
  ["/stats", "Show session dashboard (metrics, tool usage, task history)"],
15000
- ["/stop", "Stop current task and save progress (alias: /pause)"],
15001
- ["/resume", "Resume a previously stopped task"],
15001
+ ["/pause", "Pause after current turn finishes (gentle halt, /resume to continue)"],
15002
+ ["/stop", "Kill current inference immediately and save state (/resume to continue)"],
15003
+ ["/resume", "Resume a paused or stopped task"],
15004
+ ["/destroy", "Remove .oa folder, kill all tasks, clear console, and exit"],
15005
+ ["/context save", "Force-save session context to .oa/context/"],
15006
+ ["/context restore", "Restore context from previous sessions into next task"],
15007
+ ["/context show", "Show saved session context status"],
15002
15008
  ["/compact", "Force context compaction now (default strategy)"],
15003
15009
  ["/compact <strategy>", "Compact with strategy: aggressive, decisions, errors, summary, structured"],
15004
15010
  ["/bruteforce", "Toggle brute-force mode (auto re-engage on turn limit)"],
@@ -15790,6 +15796,61 @@ function loadPendingTask(repoRoot) {
15790
15796
  return null;
15791
15797
  }
15792
15798
  }
15799
+ function saveSessionContext(repoRoot, entry) {
15800
+ const contextDir = join24(repoRoot, OA_DIR, "context");
15801
+ mkdirSync6(contextDir, { recursive: true });
15802
+ const filePath = join24(contextDir, CONTEXT_SAVE_FILE);
15803
+ let ctx;
15804
+ try {
15805
+ if (existsSync18(filePath)) {
15806
+ ctx = JSON.parse(readFileSync13(filePath, "utf-8"));
15807
+ } else {
15808
+ ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
15809
+ }
15810
+ } catch {
15811
+ ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
15812
+ }
15813
+ ctx.entries.push(entry);
15814
+ if (ctx.entries.length > ctx.maxEntries) {
15815
+ ctx.entries = ctx.entries.slice(-ctx.maxEntries);
15816
+ }
15817
+ ctx.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
15818
+ writeFileSync6(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
15819
+ }
15820
+ function loadSessionContext(repoRoot) {
15821
+ const filePath = join24(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
15822
+ try {
15823
+ if (!existsSync18(filePath))
15824
+ return null;
15825
+ return JSON.parse(readFileSync13(filePath, "utf-8"));
15826
+ } catch {
15827
+ return null;
15828
+ }
15829
+ }
15830
+ function buildContextRestorePrompt(repoRoot) {
15831
+ const ctx = loadSessionContext(repoRoot);
15832
+ if (!ctx || ctx.entries.length === 0)
15833
+ return null;
15834
+ const lines = [
15835
+ "[RESTORED SESSION CONTEXT] Previous session history for this project:",
15836
+ ""
15837
+ ];
15838
+ const recentEntries = ctx.entries.slice(-10);
15839
+ for (const entry of recentEntries) {
15840
+ const status = entry.completed ? "COMPLETED" : "INCOMPLETE";
15841
+ const date = new Date(entry.savedAt).toLocaleString();
15842
+ lines.push(`[${status}] ${date} \u2014 ${entry.task.slice(0, 200)}`);
15843
+ if (entry.summary) {
15844
+ lines.push(` Summary: ${entry.summary.slice(0, 300)}`);
15845
+ }
15846
+ if (entry.filesModified.length > 0) {
15847
+ lines.push(` Files: ${entry.filesModified.slice(0, 10).join(", ")}`);
15848
+ }
15849
+ lines.push("");
15850
+ }
15851
+ lines.push("Use this context to understand what has been done previously. Do not repeat completed work.");
15852
+ return lines.join("\n");
15853
+ }
15793
15854
  function detectManifests(repoRoot) {
15794
15855
  const manifests = [];
15795
15856
  const checks = [
@@ -15883,7 +15944,7 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
15883
15944
  }
15884
15945
  return result;
15885
15946
  }
15886
- var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, SKIP_DIRS;
15947
+ var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SKIP_DIRS;
15887
15948
  var init_oa_directory = __esm({
15888
15949
  "packages/cli/dist/tui/oa-directory.js"() {
15889
15950
  "use strict";
@@ -15900,6 +15961,8 @@ var init_oa_directory = __esm({
15900
15961
  "AGENTS.md"
15901
15962
  ];
15902
15963
  PENDING_TASK_FILE = "pending-task.json";
15964
+ CONTEXT_SAVE_FILE = "session-context.json";
15965
+ MAX_CONTEXT_ENTRIES = 20;
15903
15966
  SKIP_DIRS = /* @__PURE__ */ new Set([
15904
15967
  "node_modules",
15905
15968
  ".git",
@@ -17450,7 +17513,7 @@ async function handleSlashCommand(input, ctx) {
17450
17513
  }
17451
17514
  const paused = ctx.pauseTask?.() ?? false;
17452
17515
  if (paused) {
17453
- renderInfo("Task paused. Use /resume to continue or /stop to abort.");
17516
+ renderInfo("Task paused (current turn will finish, then halt). Use /resume to continue or /stop to kill.");
17454
17517
  } else {
17455
17518
  renderWarning("Could not pause the task.");
17456
17519
  }
@@ -17464,9 +17527,9 @@ async function handleSlashCommand(input, ctx) {
17464
17527
  const saved = ctx.savePendingTaskState?.() ?? false;
17465
17528
  const aborted = ctx.abortTask?.() ?? false;
17466
17529
  if (saved && aborted) {
17467
- renderInfo("Task stopped and saved. Use /resume to continue later.");
17530
+ renderInfo("Task killed and state saved. Use /resume to continue later.");
17468
17531
  } else if (aborted) {
17469
- renderWarning("Task stopped but state could not be saved.");
17532
+ renderWarning("Task killed but state could not be saved.");
17470
17533
  } else {
17471
17534
  renderWarning("Could not stop the task.");
17472
17535
  }
@@ -17492,6 +17555,60 @@ async function handleSlashCommand(input, ctx) {
17492
17555
  }
17493
17556
  return "handled";
17494
17557
  }
17558
+ case "destroy": {
17559
+ if (ctx.hasActiveTask?.()) {
17560
+ ctx.abortTask?.();
17561
+ }
17562
+ ctx.destroyProject?.();
17563
+ return "exit";
17564
+ }
17565
+ case "context": {
17566
+ const subCmd = arg?.toLowerCase().split(/\s+/)[0] || "";
17567
+ switch (subCmd) {
17568
+ case "save": {
17569
+ const ok = ctx.contextSave?.() ?? false;
17570
+ if (ok) {
17571
+ renderInfo("Session context saved to .oa/context/. Will auto-restore on next /context restore.");
17572
+ } else {
17573
+ renderWarning("Could not save session context.");
17574
+ }
17575
+ break;
17576
+ }
17577
+ case "restore": {
17578
+ if (ctx.hasActiveTask?.()) {
17579
+ renderWarning("Cannot restore context while a task is running.");
17580
+ break;
17581
+ }
17582
+ const prompt = ctx.contextRestore?.();
17583
+ if (prompt) {
17584
+ const info = ctx.contextShow?.();
17585
+ renderInfo(`Context restored from ${info?.entries ?? 0} saved session(s). Will be injected into your next task.`);
17586
+ ctx.setRestoredContext?.(prompt);
17587
+ } else {
17588
+ renderWarning("No saved session context found. Complete a task first, or use /context save.");
17589
+ }
17590
+ break;
17591
+ }
17592
+ case "show":
17593
+ case "status": {
17594
+ const info = ctx.contextShow?.();
17595
+ if (info && info.entries > 0) {
17596
+ renderInfo(`Session context: ${info.entries} entries saved. Last saved: ${info.lastSaved ? new Date(info.lastSaved).toLocaleString() : "unknown"}`);
17597
+ } else {
17598
+ renderInfo("No session context saved yet. Context auto-saves on task completion.");
17599
+ }
17600
+ break;
17601
+ }
17602
+ default:
17603
+ renderInfo("Usage: /context save | /context restore | /context show");
17604
+ renderInfo(" save \u2014 Force-save current session context");
17605
+ renderInfo(" restore \u2014 Load previous session context into next task");
17606
+ renderInfo(" show \u2014 Show saved context status");
17607
+ renderInfo("Context auto-saves on every task completion.");
17608
+ break;
17609
+ }
17610
+ return "handled";
17611
+ }
17495
17612
  case "compact":
17496
17613
  case "gc": {
17497
17614
  if (!ctx.hasActiveTask?.()) {
@@ -21271,7 +21388,7 @@ var init_status_bar = __esm({
21271
21388
  completionTokens: 0,
21272
21389
  totalTokens: 0,
21273
21390
  estimatedContextTokens: 0,
21274
- contextWindowSize: 131072
21391
+ contextWindowSize: 0
21275
21392
  };
21276
21393
  active = false;
21277
21394
  scrollRegionTop = 1;
@@ -21596,9 +21713,14 @@ var init_status_bar = __esm({
21596
21713
  const tokOutLabel = pastel2(151, "Out: ") + c2.bold(tokOut);
21597
21714
  const ctxUsed = m.estimatedContextTokens;
21598
21715
  const ctxTotal = m.contextWindowSize;
21599
- const ctxPct = ctxTotal > 0 ? Math.max(0, Math.min(100, Math.round((1 - ctxUsed / ctxTotal) * 100))) : 100;
21600
- const ctxColor = ctxPct > 50 ? c2.green : ctxPct > 20 ? c2.yellow : c2.red;
21601
- const ctxLabel = pastel2(153, "Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
21716
+ let ctxLabel;
21717
+ if (ctxTotal <= 0) {
21718
+ ctxLabel = pastel2(153, "Ctx: ") + c2.dim("--");
21719
+ } else {
21720
+ const ctxPct = Math.max(0, Math.min(100, Math.round((1 - ctxUsed / ctxTotal) * 100)));
21721
+ const ctxColor = ctxPct > 50 ? c2.green : ctxPct > 20 ? c2.yellow : c2.red;
21722
+ ctxLabel = pastel2(153, "Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
21723
+ }
21602
21724
  let costLabel = "";
21603
21725
  if (m.hasPricing && m.estimatedCost !== void 0) {
21604
21726
  const costStr = m.estimatedCost < 0.01 ? `$${m.estimatedCost.toFixed(4)}` : m.estimatedCost < 1 ? `$${m.estimatedCost.toFixed(3)}` : `$${m.estimatedCost.toFixed(2)}`;
@@ -21900,7 +22022,7 @@ import { cwd } from "node:process";
21900
22022
  import { resolve as resolve19, join as join31, dirname as dirname10, extname as extname9 } from "node:path";
21901
22023
  import { createRequire as createRequire2 } from "node:module";
21902
22024
  import { fileURLToPath as fileURLToPath7 } from "node:url";
21903
- import { readFileSync as readFileSync18 } from "node:fs";
22025
+ import { readFileSync as readFileSync18, rmSync as rmSync2 } from "node:fs";
21904
22026
  import { existsSync as existsSync24 } from "node:fs";
21905
22027
  function getVersion() {
21906
22028
  try {
@@ -22325,6 +22447,18 @@ ${entry.fullContent}`
22325
22447
  });
22326
22448
  } catch {
22327
22449
  }
22450
+ try {
22451
+ saveSessionContext(repoRoot, {
22452
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
22453
+ task: task.slice(0, 500),
22454
+ summary: result.summary.slice(0, 500),
22455
+ filesModified: Array.from(filesTouched).slice(0, 30),
22456
+ toolCalls: result.toolCalls,
22457
+ completed: result.completed,
22458
+ model: config.model
22459
+ });
22460
+ } catch {
22461
+ }
22328
22462
  if (taskStores?.taskMemoryStore) {
22329
22463
  try {
22330
22464
  taskStores.taskMemoryStore.insert({
@@ -22556,6 +22690,7 @@ async function startInteractive(config, repoPath) {
22556
22690
  let currentTaskType;
22557
22691
  let sessionFilesTouched = [];
22558
22692
  let sessionToolCallCount = 0;
22693
+ let restoredSessionContext = null;
22559
22694
  let sessionSudoPassword = null;
22560
22695
  let sudoPromptPending = false;
22561
22696
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
@@ -22933,6 +23068,50 @@ async function startInteractive(config, repoPath) {
22933
23068
  rl.emit("line", resumeContext);
22934
23069
  }, 100);
22935
23070
  return true;
23071
+ },
23072
+ destroyProject() {
23073
+ const oaPath = join31(repoRoot, OA_DIR);
23074
+ if (existsSync24(oaPath)) {
23075
+ try {
23076
+ rmSync2(oaPath, { recursive: true, force: true });
23077
+ writeContent(() => renderInfo(`Removed ${OA_DIR}/ directory.`));
23078
+ } catch (err) {
23079
+ writeContent(() => renderWarning(`Could not remove ${OA_DIR}/: ${err instanceof Error ? err.message : String(err)}`));
23080
+ }
23081
+ } else {
23082
+ writeContent(() => renderInfo(`No ${OA_DIR}/ directory found.`));
23083
+ }
23084
+ process.stdout.write("\x1Bc");
23085
+ },
23086
+ contextSave() {
23087
+ try {
23088
+ const entry = {
23089
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
23090
+ task: lastSubmittedPrompt || "(manual save)",
23091
+ summary: `Manual context save. ${sessionToolCallCount} tool calls, ${sessionFilesTouched.length} files modified.`,
23092
+ filesModified: [...sessionFilesTouched],
23093
+ toolCalls: sessionToolCallCount,
23094
+ completed: false,
23095
+ model: currentConfig.model
23096
+ };
23097
+ saveSessionContext(repoRoot, entry);
23098
+ return true;
23099
+ } catch {
23100
+ return false;
23101
+ }
23102
+ },
23103
+ contextRestore() {
23104
+ return buildContextRestorePrompt(repoRoot);
23105
+ },
23106
+ setRestoredContext(ctx) {
23107
+ restoredSessionContext = ctx;
23108
+ },
23109
+ contextShow() {
23110
+ const ctx = loadSessionContext(repoRoot);
23111
+ if (!ctx || ctx.entries.length === 0) {
23112
+ return { entries: 0, lastSaved: null };
23113
+ }
23114
+ return { entries: ctx.entries.length, lastSaved: ctx.updatedAt };
22936
23115
  }
22937
23116
  };
22938
23117
  showPrompt();
@@ -23162,9 +23341,18 @@ Summarize or analyze this transcription as appropriate.`;
23162
23341
  const displayText = isImage ? `[Image: ${cleanPath}]` : inputLineCount > 1 ? `[pasted ${inputLineCount} lines]` : fullInput;
23163
23342
  writeContent(() => renderUserMessage(displayText));
23164
23343
  lastSubmittedPrompt = fullInput;
23344
+ let taskInput = fullInput;
23345
+ if (restoredSessionContext) {
23346
+ taskInput = `${restoredSessionContext}
23347
+
23348
+ ---
23349
+
23350
+ NEW TASK: ${fullInput}`;
23351
+ restoredSessionContext = null;
23352
+ }
23165
23353
  try {
23166
23354
  statusBar.setProcessing(true);
23167
- const task = startTask(fullInput, currentConfig, repoRoot, voiceEngine, {
23355
+ const task = startTask(taskInput, currentConfig, repoRoot, voiceEngine, {
23168
23356
  enabled: streamEnabled,
23169
23357
  renderer: streamRenderer
23170
23358
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.31.6",
3
+ "version": "0.31.8",
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",