orcastrator 0.2.6 → 0.2.7

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.
@@ -62,7 +62,7 @@ export async function loadConfig(configPath) {
62
62
  const configCandidate = "default" in importedModule ? importedModule.default : importedModule;
63
63
  return coerceConfig(configCandidate);
64
64
  }
65
- const TOP_LEVEL_SCALARS = ["runsDir", "sessionLogs", "maxRetries", "anthropicApiKey", "openaiApiKey"];
65
+ const TOP_LEVEL_SCALARS = ["runsDir", "sessionLogs", "maxRetries", "anthropicApiKey", "openaiApiKey", "executor"];
66
66
  export function mergeConfigs(...configs) {
67
67
  const presentConfigs = configs.filter((config) => config !== undefined);
68
68
  if (presentConfigs.length === 0) {
@@ -1,12 +1,14 @@
1
1
  import path from "node:path";
2
2
  import { promises as fs } from "node:fs";
3
- import { executeTask } from "../agents/claude/session.js";
3
+ import * as claudeAgent from "../agents/claude/session.js";
4
+ import { createCodexSession } from "../agents/codex/session.js";
4
5
  import { loadSkills } from "../utils/skill-loader.js";
5
6
  import { getRunnable, validateDAG } from "./dependency-graph.js";
6
7
  import { shouldRetry } from "./retry-policy.js";
7
- let executeTaskImpl = executeTask;
8
+ // Non-null only when set by tests — null means "use real executor logic"
9
+ let testExecuteTaskOverride = null;
8
10
  export function setExecuteTaskForTests(fn) {
9
- executeTaskImpl = fn ?? executeTask;
11
+ testExecuteTaskOverride = fn;
10
12
  }
11
13
  function toErrorMessage(error) {
12
14
  if (error instanceof Error) {
@@ -94,10 +96,34 @@ async function writeSessionSummary(store, runId, sessionLogsDir) {
94
96
  }
95
97
  export async function runTaskRunner(options) {
96
98
  const emitHook = options.emitHook ?? defaultEmitHook;
97
- const executeTaskFn = options.executeTask ?? executeTaskImpl;
98
99
  const { runId, store, config } = options;
99
100
  const skills = await loadSkills(config);
100
101
  const taskSystemContext = skills.length === 0 ? undefined : formatSkillsSection(skills);
102
+ // Test mocks bypass all executor logic entirely — no real sessions created.
103
+ const mockFn = options.executeTask ?? testExecuteTaskOverride;
104
+ // Build real executor (Codex persistent session or Claude stateless fallback).
105
+ // Only runs in production — skipped completely when a mock is active.
106
+ let codexSession;
107
+ let executeTaskFn;
108
+ if (mockFn) {
109
+ executeTaskFn = mockFn;
110
+ }
111
+ else {
112
+ const executor = config?.executor ?? "codex";
113
+ if (executor === "codex") {
114
+ try {
115
+ codexSession = await createCodexSession(process.cwd(), config);
116
+ executeTaskFn = (task, taskRunId, _cfg, systemContext) => codexSession.executeTask(task, taskRunId, systemContext);
117
+ }
118
+ catch (sessionError) {
119
+ console.warn(`[orca] Codex session init failed, falling back to Claude: ${toErrorMessage(sessionError)}`);
120
+ executeTaskFn = claudeAgent.executeTask;
121
+ }
122
+ }
123
+ else {
124
+ executeTaskFn = claudeAgent.executeTask;
125
+ }
126
+ }
101
127
  let run = await store.getRun(runId);
102
128
  if (!run) {
103
129
  throw new Error(`Run not found: ${runId}`);
@@ -320,4 +346,14 @@ export async function runTaskRunner(options) {
320
346
  await writeSessionSummary(store, runId, config?.sessionLogs);
321
347
  throw error;
322
348
  }
349
+ finally {
350
+ if (codexSession) {
351
+ try {
352
+ await codexSession.disconnect();
353
+ }
354
+ catch {
355
+ // Best-effort cleanup — don't mask the real error.
356
+ }
357
+ }
358
+ }
323
359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orcastrator",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "orca": "dist/cli/index.js"