@oxgeneral/orch 0.2.3 → 0.2.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.
- package/dist/{App-KDZSTAMR.js → App-KHUT3IV7.js} +169 -71
- package/dist/{chunk-VTA74YWX.js → chunk-2KSBOAW3.js} +1 -1
- package/dist/{chunk-O5AO5QIR.js → chunk-3TGCIXJA.js} +7 -1
- package/dist/{chunk-6GFVB6EK.js → chunk-FRTKB575.js} +24 -38
- package/dist/chunk-K6DMQERQ.js +89 -0
- package/dist/{chunk-2B32FPEB.js → chunk-QTDKQYZI.js} +3 -3
- package/dist/{chunk-2B32FPEB.js.map → chunk-QTDKQYZI.js.map} +1 -1
- package/dist/{chunk-ZU6AY2VU.js → chunk-VAAOW526.js} +2 -2
- package/dist/chunk-VAAOW526.js.map +1 -0
- package/dist/chunk-ZTQ3KWXR.js +13 -0
- package/dist/chunk-ZTQ3KWXR.js.map +1 -0
- package/dist/cli.js +16 -16
- package/dist/{container-JV7TAUP5.js → container-KPH4HVAJ.js} +6 -6
- package/dist/{doctor-IO4PV4D6.js → doctor-GHRV5I2S.js} +4 -4
- package/dist/doctor-service-QEJCE5FK.js +3 -0
- package/dist/doctor-service-QEJCE5FK.js.map +1 -0
- package/dist/doctor-service-TPOMFAIG.js +2 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/{init-BE5VKWOM.js → init-EQTGQ4G2.js} +18 -2
- package/dist/{logs-IAUAS5TX.js → logs-AK255DEJ.js} +1 -1
- package/dist/orchestrator-L6QX2LJ7.js +2 -0
- package/dist/{orchestrator-TAFBYQQ5.js.map → orchestrator-L6QX2LJ7.js.map} +1 -1
- package/dist/{orchestrator-VGYKSOZJ.js → orchestrator-OMU46RCE.js} +47 -19
- package/dist/{task-5OJTXW27.js → task-35SDKXFC.js} +1 -1
- package/dist/{tui-XDJE3IUA.js → tui-AR6PVMBQ.js} +6 -1
- package/dist/{update-72GZMF65.js → update-DCCWVISK.js} +1 -1
- package/dist/update-check-4YKLGBFB.js +2 -0
- package/dist/workspace-manager-AS4TFA7R.js +3 -0
- package/dist/workspace-manager-AS4TFA7R.js.map +1 -0
- package/dist/{workspace-manager-47KI7B27.js → workspace-manager-G5EQRS72.js} +38 -2
- package/package.json +1 -1
- package/dist/chunk-E3TCKHU6.js +0 -13
- package/dist/chunk-E3TCKHU6.js.map +0 -1
- package/dist/chunk-XI4TU6VU.js +0 -50
- package/dist/chunk-ZU6AY2VU.js.map +0 -1
- package/dist/doctor-service-A34DHPKI.js +0 -2
- package/dist/doctor-service-NTWBWOM2.js +0 -2
- package/dist/doctor-service-NTWBWOM2.js.map +0 -1
- package/dist/orchestrator-TAFBYQQ5.js +0 -2
- package/dist/update-check-4RV7Z6WT.js +0 -2
- package/dist/workspace-manager-7M46ESUL.js +0 -2
- package/dist/workspace-manager-7M46ESUL.js.map +0 -1
|
@@ -3,9 +3,10 @@ import { DEFAULT_PROMPT_TEMPLATE } from './chunk-HNKJ4IF7.js';
|
|
|
3
3
|
import { DEFAULT_CONFIG } from './chunk-ED47GL3F.js';
|
|
4
4
|
import './chunk-PNE6LQRF.js';
|
|
5
5
|
import { printWarning, printSuccess, dim } from './chunk-I5WEMARW.js';
|
|
6
|
-
import { Paths, pathExists, ensureDir, writeYaml, atomicWrite } from './chunk-
|
|
7
|
-
import './chunk-
|
|
6
|
+
import { Paths, pathExists, ensureDir, writeYaml, atomicWrite } from './chunk-2KSBOAW3.js';
|
|
7
|
+
import './chunk-3TGCIXJA.js';
|
|
8
8
|
import path from 'path';
|
|
9
|
+
import fs from 'fs/promises';
|
|
9
10
|
|
|
10
11
|
// src/domain/default-agents.ts
|
|
11
12
|
var AGENT_CREATOR_ROLE = `Agent architect \u2014 designs and creates AI agents for the orchestrator via \`orch agent add\`.
|
|
@@ -124,6 +125,7 @@ async function runInit(opts = {}) {
|
|
|
124
125
|
atomicWrite(paths.defaultTemplatePath(), DEFAULT_PROMPT_TEMPLATE),
|
|
125
126
|
...defaultAgents.map((agent) => writeYaml(paths.agentPath(agent.id), agent))
|
|
126
127
|
]);
|
|
128
|
+
await ensureRootGitignore(projectRoot);
|
|
127
129
|
console.log();
|
|
128
130
|
printSuccess("initialized");
|
|
129
131
|
console.log();
|
|
@@ -138,6 +140,20 @@ async function runInit(opts = {}) {
|
|
|
138
140
|
console.log(` ${dim("\u2514\u2500\u2500")} .gitignore`);
|
|
139
141
|
console.log();
|
|
140
142
|
}
|
|
143
|
+
async function ensureRootGitignore(projectRoot) {
|
|
144
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
145
|
+
try {
|
|
146
|
+
const content = await fs.readFile(gitignorePath, "utf-8");
|
|
147
|
+
if (content.split("\n").some((line) => line.trim() === ".orchestry")) return;
|
|
148
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
149
|
+
await fs.appendFile(gitignorePath, `${separator}
|
|
150
|
+
# Orchestry state
|
|
151
|
+
.orchestry
|
|
152
|
+
`);
|
|
153
|
+
} catch {
|
|
154
|
+
await atomicWrite(gitignorePath, "# Orchestry state\n.orchestry\n");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
141
157
|
function registerInitCommand(program) {
|
|
142
158
|
program.command("init").description("Initialize .orchestry/ in the current directory").option("--name <name>", "Project name").action(async (opts) => {
|
|
143
159
|
await runInit(opts);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { printError, dim, getIcon } from './chunk-I5WEMARW.js';
|
|
3
|
-
import { InvalidArgumentsError } from './chunk-
|
|
3
|
+
import { InvalidArgumentsError } from './chunk-3TGCIXJA.js';
|
|
4
4
|
|
|
5
5
|
// src/cli/commands/logs.ts
|
|
6
6
|
function registerLogsCommand(program, container) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-L6QX2LJ7.js"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { DEFAULT_PROMPT_TEMPLATE, buildPromptContext } from './chunk-HNKJ4IF7.js';
|
|
3
3
|
import { resolveFailureStatus, isDispatchable, isTerminal, isBlocked, resolveCompletionStatus, calculateRetryDelay } from './chunk-33QNTNR6.js';
|
|
4
4
|
import { AUTONOMOUS_LABEL } from './chunk-PNE6LQRF.js';
|
|
5
|
-
import { LockConflictError, TaskAlreadyRunningError, NoAgentsError } from './chunk-
|
|
5
|
+
import { LockConflictError, WorkspaceError, TaskAlreadyRunningError, NoAgentsError } from './chunk-3TGCIXJA.js';
|
|
6
6
|
import { dirname } from 'path';
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
8
|
import { execFile } from 'child_process';
|
|
@@ -285,21 +285,40 @@ var Orchestrator = class {
|
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
/**
|
|
288
|
-
* Run a single task by ID.
|
|
288
|
+
* Run a single task by ID.
|
|
289
|
+
* If watch mode is active (lock already held), dispatches inline via stateMutex.
|
|
290
|
+
* Otherwise acquires a temporary lock for the duration of the run.
|
|
289
291
|
*/
|
|
290
292
|
async runTask(taskId) {
|
|
291
|
-
|
|
292
|
-
await this.
|
|
293
|
-
|
|
294
|
-
}
|
|
293
|
+
if (this.lockAcquired) {
|
|
294
|
+
await this.freshDispatch(() => this.dispatchTask(taskId));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
await this.withTemporaryLock(() => this.freshDispatch(() => this.dispatchTask(taskId)));
|
|
295
298
|
}
|
|
296
299
|
/**
|
|
297
|
-
* Run all dispatchable tasks.
|
|
300
|
+
* Run all dispatchable tasks.
|
|
301
|
+
* If watch mode is active (lock already held), dispatches inline via stateMutex.
|
|
302
|
+
* Otherwise acquires a temporary lock for the duration of the run.
|
|
298
303
|
*/
|
|
299
304
|
async runAll() {
|
|
300
|
-
|
|
305
|
+
if (this.lockAcquired) {
|
|
306
|
+
await this.freshDispatch(() => this.dispatchAll());
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
await this.withTemporaryLock(() => this.freshDispatch(() => this.dispatchAll()));
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Invalidate caches → loadState → run dispatch fn → saveState.
|
|
313
|
+
* Shared by runTask, runAll, and immediateDispatch.
|
|
314
|
+
*/
|
|
315
|
+
async freshDispatch(fn) {
|
|
316
|
+
await this.withStateLock(async () => {
|
|
317
|
+
this.cachedTaskStore.invalidate();
|
|
318
|
+
this.cachedAgentStore.invalidate();
|
|
301
319
|
await this.loadState();
|
|
302
|
-
await
|
|
320
|
+
await fn();
|
|
321
|
+
await this.saveState();
|
|
303
322
|
});
|
|
304
323
|
}
|
|
305
324
|
/**
|
|
@@ -539,13 +558,18 @@ var Orchestrator = class {
|
|
|
539
558
|
/**
|
|
540
559
|
* Schedule an immediate dispatch with 500ms debounce.
|
|
541
560
|
* Called on task:created to avoid waiting for the next 30s tick.
|
|
561
|
+
* Retries up to 10 times (5s) if a tick is in progress.
|
|
542
562
|
*/
|
|
543
|
-
scheduleImmediateDispatch() {
|
|
563
|
+
scheduleImmediateDispatch(retries = 0) {
|
|
544
564
|
if (this.shuttingDown) return;
|
|
545
565
|
if (this.immediateDispatchTimer) return;
|
|
546
566
|
this.immediateDispatchTimer = setTimeout(() => {
|
|
547
567
|
this.immediateDispatchTimer = null;
|
|
548
|
-
if (this.shuttingDown
|
|
568
|
+
if (this.shuttingDown) return;
|
|
569
|
+
if (this.tickInProgress) {
|
|
570
|
+
if (retries < 10) this.scheduleImmediateDispatch(retries + 1);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
549
573
|
this.immediateDispatch().catch((err) => {
|
|
550
574
|
this.deps.eventBus.emit({
|
|
551
575
|
type: "orchestrator:error",
|
|
@@ -562,14 +586,7 @@ var Orchestrator = class {
|
|
|
562
586
|
*/
|
|
563
587
|
async immediateDispatch() {
|
|
564
588
|
if (this.shuttingDown) return;
|
|
565
|
-
await this.
|
|
566
|
-
if (this.shuttingDown) return;
|
|
567
|
-
this.cachedTaskStore.invalidate();
|
|
568
|
-
this.cachedAgentStore.invalidate();
|
|
569
|
-
await this.loadState();
|
|
570
|
-
await this.dispatchAll();
|
|
571
|
-
await this.saveState();
|
|
572
|
-
});
|
|
589
|
+
await this.freshDispatch(() => this.shuttingDown ? Promise.resolve() : this.dispatchAll());
|
|
573
590
|
}
|
|
574
591
|
/**
|
|
575
592
|
* Reconcile: check PID liveness, detect stalls, process retry queue.
|
|
@@ -755,6 +772,17 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
755
772
|
try {
|
|
756
773
|
await this.dispatchTask(task.id);
|
|
757
774
|
} catch (err) {
|
|
775
|
+
if (err instanceof WorkspaceError) {
|
|
776
|
+
try {
|
|
777
|
+
const t = await this.deps.taskStore.get(task.id);
|
|
778
|
+
if (t && !isTerminal(t.status)) {
|
|
779
|
+
t.status = "failed";
|
|
780
|
+
t.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
781
|
+
await this.deps.taskStore.save(t);
|
|
782
|
+
}
|
|
783
|
+
} catch {
|
|
784
|
+
}
|
|
785
|
+
}
|
|
758
786
|
this.deps.eventBus.emit({
|
|
759
787
|
type: "orchestrator:error",
|
|
760
788
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -181,7 +181,7 @@ function registerTaskCommand(program, container) {
|
|
|
181
181
|
await container.paths.requireInit();
|
|
182
182
|
const task2 = await container.taskService.get(id);
|
|
183
183
|
if (task2.status === "in_progress") {
|
|
184
|
-
const { buildFullContainer } = await import('./container-
|
|
184
|
+
const { buildFullContainer } = await import('./container-KPH4HVAJ.js');
|
|
185
185
|
const full = await buildFullContainer(container.context);
|
|
186
186
|
await full.orchestrator.cancelTask(id);
|
|
187
187
|
} else {
|
|
@@ -8,7 +8,7 @@ function registerTuiCommand(program, container) {
|
|
|
8
8
|
const state = await container.stateStore.read();
|
|
9
9
|
const { render } = await import('ink');
|
|
10
10
|
const { createElement } = await import('react');
|
|
11
|
-
const { App } = await import('./App-
|
|
11
|
+
const { App } = await import('./App-KHUT3IV7.js');
|
|
12
12
|
const onRunTask = async (taskId) => {
|
|
13
13
|
await container.orchestrator.runTask(taskId);
|
|
14
14
|
};
|
|
@@ -151,6 +151,8 @@ function registerTuiCommand(program, container) {
|
|
|
151
151
|
const onStopWatch = async () => {
|
|
152
152
|
await container.orchestrator.stop();
|
|
153
153
|
};
|
|
154
|
+
const currentVersion = program.version() ?? "0.0.0";
|
|
155
|
+
const updateCheckPromise = import('./update-check-4YKLGBFB.js').then((m) => m.checkForUpdateSWR(currentVersion)).catch(() => null);
|
|
154
156
|
let watchStarted = false;
|
|
155
157
|
let watchError;
|
|
156
158
|
try {
|
|
@@ -159,6 +161,7 @@ function registerTuiCommand(program, container) {
|
|
|
159
161
|
} catch (err) {
|
|
160
162
|
watchError = err instanceof Error ? err.message : String(err);
|
|
161
163
|
}
|
|
164
|
+
const updateInfo = await updateCheckPromise;
|
|
162
165
|
const { waitUntilExit } = render(
|
|
163
166
|
createElement(App, {
|
|
164
167
|
projectName: container.config.project.name,
|
|
@@ -202,6 +205,8 @@ function registerTuiCommand(program, container) {
|
|
|
202
205
|
onStopWatch,
|
|
203
206
|
initialWatchActive: watchStarted,
|
|
204
207
|
watchError,
|
|
208
|
+
version: currentVersion,
|
|
209
|
+
latestVersion: updateInfo?.updateAvailable ? updateInfo.latest : void 0,
|
|
205
210
|
initialActivityFilter: container.globalConfig.tui.activity_filter,
|
|
206
211
|
onSaveActivityFilter: async (preset) => {
|
|
207
212
|
await container.globalConfigStore.set("activity_filter", preset);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {l as l$1,m,h as h$1}from'./chunk-QTDKQYZI.js';import {l}from'./chunk-VAAOW526.js';import n from'path';import h from'fs/promises';var g=class{constructor(r,e){this.projectRoot=r;this.processManager=e;}async mergeBack(r){return new Promise(e=>{let{process:o}=this.processManager.spawn("git",["merge","--no-ff",r,"-m",`Merge ${r}`],{cwd:this.projectRoot}),t="",a=2e3,c=i=>{t.length<a&&(t+=i.toString());};o.stdout?.on("data",c),o.stderr?.on("data",c),o.on("close",i=>{if(i===0){e({success:true});return}let s=t.slice(0,1e3);if(!(s.includes("CONFLICT")||s.includes("Merge conflict"))){e({success:false,conflictInfo:s});return}try{let{process:f}=this.processManager.spawn("git",["merge","--abort"],{cwd:this.projectRoot});f.on("close",()=>{e({success:!1,conflictInfo:s});}),f.on("error",()=>{e({success:!1,conflictInfo:s});});}catch{e({success:false,conflictInfo:s});}}),o.on("error",i=>{e({success:false,conflictInfo:i.message});});})}};var y=class{constructor(r,e,o){this.projectRoot=r;this.orchestryDir=e;this.processManager=o;this.mergeStrategy=new g(r,o);}mergeStrategy;gitRepoChecked=false;isGitRepo=false;async prepare(r,e,o){let t=this.resolveMode(r,e,o);switch(t!=="shared"&&await this.requireGitRepo(t),t){case "shared":return {path:this.projectRoot};case "worktree":return this.prepareWorktree(r);case "isolated":return {path:await this.prepareIsolated(r)};default:return {path:this.projectRoot}}}async requireGitRepo(r){if(!this.gitRepoChecked){try{let{process:e}=this.processManager.spawn("git",["rev-parse","--is-inside-work-tree"],{cwd:this.projectRoot}),o=await new Promise(t=>{e.on("close",t),e.on("error",()=>t(1));});this.isGitRepo=o===0;}catch{this.isGitRepo=false;}this.isGitRepo&&(this.gitRepoChecked=true);}if(!this.isGitRepo)throw new l(`workspace_mode "${r}" requires a git repository`,`Run: git init && git add -A && git commit -m "Initial commit"
|
|
2
|
+
Or set workspace_mode: shared in .orchestry/config.yml`)}async mergeBack(r){return this.mergeStrategy.mergeBack(r)}async cleanup(r){let e=n.join(this.orchestryDir,"workspaces",l$1(r));try{let{process:o}=this.processManager.spawn("git",["worktree","remove","--force",e],{cwd:this.projectRoot});await new Promise(t=>{o.on("close",()=>t()),o.on("error",()=>t());});}catch{}try{await h.rm(e,{recursive:!0,force:!0});}catch{}}validate(r,e){m(r,e);}resolveMode(r,e,o){return r.workspace_mode??e.config.workspace_mode??o.defaults.agent.workspace_mode??"worktree"}async prepareWorktree(r){let e=n.join(this.orchestryDir,"workspaces",l$1(r.id));await h$1(n.dirname(e));let o=k(r.title)||l$1(r.id),t=`orchestry/${l$1(r.id)}/${o}`,{process:a}=this.processManager.spawn("git",["worktree","add",e,"-b",t],{cwd:this.projectRoot});await new Promise((i,s)=>{a.on("close",p=>{p===0?i():s(new Error(`git worktree add failed with code ${p}`));}),a.on("error",s);});let c=n.join(e,".orchestry");return await h.rm(c,{recursive:true,force:true}).catch(()=>{}),{path:e,branch:t}}async prepareIsolated(r){let e=n.join(this.orchestryDir,"workspaces",l$1(r.id));await h$1(n.dirname(e));try{let{process:t}=this.processManager.spawn("git",["clone","--local","--no-hardlinks",".",e],{cwd:this.projectRoot});await new Promise((a,c)=>{t.on("close",i=>{i===0?a():c(new Error("git clone failed"));}),t.on("error",c);});}catch{let a=["-a",`--exclude-from=${n.join(this.orchestryDir,"workspace-exclude")}`,"./",`${e}/`],{process:c}=this.processManager.spawn("rsync",a,{cwd:this.projectRoot});await new Promise((i,s)=>{c.on("close",p=>{p===0?i():s(new Error(`rsync failed with code ${p}`));}),c.on("error",s);});}let o=n.join(e,".orchestry");return await h.rm(o,{recursive:true,force:true}).catch(()=>{}),e}};function k(l){return l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,40)}export{y as WorkspaceManager};//# sourceMappingURL=workspace-manager-AS4TFA7R.js.map
|
|
3
|
+
//# sourceMappingURL=workspace-manager-AS4TFA7R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/workspace/merge-strategy.ts","../src/infrastructure/workspace/workspace-manager.ts"],"names":["MergeStrategy","projectRoot","processManager","branch","resolve","proc","output","maxOutputLen","appendOutput","chunk","code","trimmedOutput","abortProc","err","WorkspaceManager","orchestryDir","task","agent","config","mode","WorkspaceError","taskId","workspacePath","path","sanitizeId","fs","validateWorkspacePath","ensureDir","titleSlug","sanitizeTitle","branchName","reject","worktreeOrchestry","args","clonedOrchestry","title"],"mappings":"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","file":"workspace-manager-AS4TFA7R.js","sourcesContent":["/**\n * Git merge strategy for worktree branches.\n *\n * Encapsulates `git merge --no-ff` execution and conflict handling.\n */\n\nimport type { IProcessManager } from '../process/process-manager.js';\n\nexport type MergeResult =\n | { success: true }\n | { success: false; conflictInfo: string };\n\nexport class MergeStrategy {\n constructor(\n private readonly projectRoot: string,\n private readonly processManager: IProcessManager,\n ) {}\n\n /**\n * Merge a branch into the current branch with --no-ff.\n * On conflict, aborts the merge and returns conflict info.\n */\n async mergeBack(branch: string): Promise<MergeResult> {\n return new Promise((resolve) => {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['merge', '--no-ff', branch, '-m', `Merge ${branch}`],\n { cwd: this.projectRoot },\n );\n\n let output = '';\n const maxOutputLen = 2000;\n const appendOutput = (chunk: Buffer) => {\n if (output.length < maxOutputLen) output += chunk.toString();\n };\n proc.stdout?.on('data', appendOutput);\n proc.stderr?.on('data', appendOutput);\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve({ success: true });\n return;\n }\n\n const trimmedOutput = output.slice(0, 1000);\n const isConflict = trimmedOutput.includes('CONFLICT') || trimmedOutput.includes('Merge conflict');\n\n if (!isConflict) {\n // Non-conflict failure (branch not found, hook failure, etc.) — no merge to abort\n resolve({ success: false, conflictInfo: trimmedOutput });\n return;\n }\n\n // Abort the failed merge to restore clean state\n try {\n const { process: abortProc } = this.processManager.spawn(\n 'git',\n ['merge', '--abort'],\n { cwd: this.projectRoot },\n );\n abortProc.on('close', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n abortProc.on('error', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n } catch {\n resolve({ success: false, conflictInfo: trimmedOutput });\n }\n });\n\n proc.on('error', (err) => {\n resolve({ success: false, conflictInfo: err.message });\n });\n });\n }\n}\n","/**\n * Workspace manager implementation.\n *\n * Resolves workspace path based on mode priority chain:\n * task.workspace_mode → agent.config.workspace_mode → defaults.agent.workspace_mode → 'worktree'\n */\n\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport type { Agent } from '../../domain/agent.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport type { Task, WorkspaceMode } from '../../domain/task.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { validateWorkspacePath, sanitizeId } from '../storage/paths.js';\nimport { ensureDir } from '../storage/fs-utils.js';\nimport type { IWorkspaceManager, PrepareResult } from './interface.js';\nimport { MergeStrategy, type MergeResult } from './merge-strategy.js';\nimport { WorkspaceError } from '../../domain/errors.js';\n\nexport class WorkspaceManager implements IWorkspaceManager {\n private readonly mergeStrategy: MergeStrategy;\n private gitRepoChecked = false;\n private isGitRepo = false;\n\n constructor(\n private readonly projectRoot: string,\n private readonly orchestryDir: string,\n private readonly processManager: IProcessManager,\n ) {\n this.mergeStrategy = new MergeStrategy(projectRoot, processManager);\n }\n\n async prepare(task: Task, agent: Agent, config: OrchestratorConfig): Promise<PrepareResult> {\n const mode = this.resolveMode(task, agent, config);\n\n if (mode !== 'shared') {\n await this.requireGitRepo(mode);\n }\n\n switch (mode) {\n case 'shared':\n return { path: this.projectRoot };\n\n case 'worktree':\n return this.prepareWorktree(task);\n\n case 'isolated':\n return { path: await this.prepareIsolated(task) };\n\n default:\n return { path: this.projectRoot };\n }\n }\n\n private async requireGitRepo(mode: WorkspaceMode): Promise<void> {\n if (!this.gitRepoChecked) {\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['rev-parse', '--is-inside-work-tree'],\n { cwd: this.projectRoot },\n );\n const code = await new Promise<number | null>((resolve) => {\n proc.on('close', resolve);\n proc.on('error', () => resolve(1));\n });\n this.isGitRepo = code === 0;\n } catch {\n this.isGitRepo = false;\n }\n // Only cache positive result — negative may change if user runs git init\n if (this.isGitRepo) this.gitRepoChecked = true;\n }\n\n if (!this.isGitRepo) {\n throw new WorkspaceError(\n `workspace_mode \"${mode}\" requires a git repository`,\n 'Run: git init && git add -A && git commit -m \"Initial commit\"\\n Or set workspace_mode: shared in .orchestry/config.yml',\n );\n }\n }\n\n async mergeBack(branch: string): Promise<MergeResult> {\n return this.mergeStrategy.mergeBack(branch);\n }\n\n async cleanup(taskId: string): Promise<void> {\n const workspacePath = path.join(this.orchestryDir, 'workspaces', sanitizeId(taskId));\n\n // Try git worktree remove first (cleans up .git/worktrees/ metadata)\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'remove', '--force', workspacePath],\n { cwd: this.projectRoot },\n );\n await new Promise<void>((resolve) => {\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Not a worktree or git not available — fall through to rm\n }\n\n // Remove directory regardless (handles isolated mode and worktree cleanup failures)\n try {\n await fs.rm(workspacePath, { recursive: true, force: true });\n } catch {\n // Workspace may not exist\n }\n }\n\n validate(workspacePath: string, projectRoot: string): void {\n validateWorkspacePath(workspacePath, projectRoot);\n }\n\n private resolveMode(task: Task, agent: Agent, config: OrchestratorConfig): WorkspaceMode {\n return (\n task.workspace_mode ??\n agent.config.workspace_mode ??\n config.defaults.agent.workspace_mode ??\n 'worktree'\n );\n }\n\n private async prepareWorktree(task: Task): Promise<PrepareResult> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n const titleSlug = sanitizeTitle(task.title) || sanitizeId(task.id);\n const branchName = `orchestry/${sanitizeId(task.id)}/${titleSlug}`;\n\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'add', workspacePath, '-b', branchName],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`git worktree add failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n\n // Remove .orchestry/ from worktree to prevent recursive state/workspaces\n const worktreeOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return { path: workspacePath, branch: branchName };\n }\n\n private async prepareIsolated(task: Task): Promise<string> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n // Try git clone first, fall back to rsync\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['clone', '--local', '--no-hardlinks', '.', workspacePath],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error('git clone failed'));\n });\n proc.on('error', reject);\n });\n } catch {\n // Fallback: rsync\n const excludeFile = path.join(this.orchestryDir, 'workspace-exclude');\n const args = ['-a', `--exclude-from=${excludeFile}`, './', `${workspacePath}/`];\n\n const { process: proc } = this.processManager.spawn('rsync', args, {\n cwd: this.projectRoot,\n });\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`rsync failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n }\n\n // Remove .orchestry/ to prevent recursive workspaces (covers both clone and rsync)\n const clonedOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return workspacePath;\n }\n}\n\nfunction sanitizeTitle(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40);\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-2KSBOAW3.js';
|
|
3
|
+
import { WorkspaceError } from './chunk-3TGCIXJA.js';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import fs from 'fs/promises';
|
|
6
6
|
|
|
@@ -71,8 +71,13 @@ var WorkspaceManager = class {
|
|
|
71
71
|
this.mergeStrategy = new MergeStrategy(projectRoot, processManager);
|
|
72
72
|
}
|
|
73
73
|
mergeStrategy;
|
|
74
|
+
gitRepoChecked = false;
|
|
75
|
+
isGitRepo = false;
|
|
74
76
|
async prepare(task, agent, config) {
|
|
75
77
|
const mode = this.resolveMode(task, agent, config);
|
|
78
|
+
if (mode !== "shared") {
|
|
79
|
+
await this.requireGitRepo(mode);
|
|
80
|
+
}
|
|
76
81
|
switch (mode) {
|
|
77
82
|
case "shared":
|
|
78
83
|
return { path: this.projectRoot };
|
|
@@ -84,6 +89,31 @@ var WorkspaceManager = class {
|
|
|
84
89
|
return { path: this.projectRoot };
|
|
85
90
|
}
|
|
86
91
|
}
|
|
92
|
+
async requireGitRepo(mode) {
|
|
93
|
+
if (!this.gitRepoChecked) {
|
|
94
|
+
try {
|
|
95
|
+
const { process: proc } = this.processManager.spawn(
|
|
96
|
+
"git",
|
|
97
|
+
["rev-parse", "--is-inside-work-tree"],
|
|
98
|
+
{ cwd: this.projectRoot }
|
|
99
|
+
);
|
|
100
|
+
const code = await new Promise((resolve) => {
|
|
101
|
+
proc.on("close", resolve);
|
|
102
|
+
proc.on("error", () => resolve(1));
|
|
103
|
+
});
|
|
104
|
+
this.isGitRepo = code === 0;
|
|
105
|
+
} catch {
|
|
106
|
+
this.isGitRepo = false;
|
|
107
|
+
}
|
|
108
|
+
if (this.isGitRepo) this.gitRepoChecked = true;
|
|
109
|
+
}
|
|
110
|
+
if (!this.isGitRepo) {
|
|
111
|
+
throw new WorkspaceError(
|
|
112
|
+
`workspace_mode "${mode}" requires a git repository`,
|
|
113
|
+
'Run: git init && git add -A && git commit -m "Initial commit"\n Or set workspace_mode: shared in .orchestry/config.yml'
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
87
117
|
async mergeBack(branch) {
|
|
88
118
|
return this.mergeStrategy.mergeBack(branch);
|
|
89
119
|
}
|
|
@@ -133,6 +163,9 @@ var WorkspaceManager = class {
|
|
|
133
163
|
});
|
|
134
164
|
proc.on("error", reject);
|
|
135
165
|
});
|
|
166
|
+
const worktreeOrchestry = path.join(workspacePath, ".orchestry");
|
|
167
|
+
await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {
|
|
168
|
+
});
|
|
136
169
|
return { path: workspacePath, branch: branchName };
|
|
137
170
|
}
|
|
138
171
|
async prepareIsolated(task) {
|
|
@@ -169,6 +202,9 @@ var WorkspaceManager = class {
|
|
|
169
202
|
proc.on("error", reject);
|
|
170
203
|
});
|
|
171
204
|
}
|
|
205
|
+
const clonedOrchestry = path.join(workspacePath, ".orchestry");
|
|
206
|
+
await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {
|
|
207
|
+
});
|
|
172
208
|
return workspacePath;
|
|
173
209
|
}
|
|
174
210
|
};
|
package/package.json
CHANGED
package/dist/chunk-E3TCKHU6.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {d,h,e}from'./chunk-ZU6AY2VU.js';import {a,d as d$1,c}from'./chunk-AELEEEV3.js';import {dirname}from'path';import k from'fs/promises';import {execFile}from'child_process';var J={todo:["in_progress","cancelled"],in_progress:["review","retrying","failed","cancelled"],retrying:["in_progress","failed","cancelled"],review:["done","todo","cancelled"],done:[],failed:["todo","retrying"],cancelled:["todo"]},Q=new Set(["done","failed","cancelled"]);function st(c,t){return J[c].includes(t)}function P(c){return Q.has(c)}function D(c){return c==="todo"||c==="retrying"}function G(c,t){return c.depends_on.length===0?false:c.depends_on.some(e=>{let s=t.find(a=>a.id===e);return !s||s.status!=="done"})}function A(c){return c.attempts<c.max_attempts?"retrying":"failed"}function N(c,t,e){return "review"}function F(c,t,e){let s=t*Math.pow(2,c);return Math.min(s,e)}function U(c,t){if(!c?.length||!t?.length)return false;for(let e of c)for(let s of t)if(V(e,s))return true;return false}function V(c,t){if(c===t)return true;let e=c.split("*")[0],s=t.split("*")[0];if(e.startsWith(s)||s.startsWith(e))return true;if(!e.endsWith("/")&&!s.endsWith("/")){let a=dirname(e),l=dirname(s);return a===l&&a!=="."}return false}async function C(c){let t=c+".bak",e=await H(c);if(e!==null){if(X(e))return {acquired:false,pid:e};try{await k.rename(c,t);}catch{}}try{let s=await k.open(c,"wx");return await s.writeFile(String(process.pid),"utf-8"),await s.close(),await k.unlink(t).catch(()=>{}),{acquired:!0,pid:process.pid}}catch(s){if(s.code==="EEXIST")return await k.rename(t,c).catch(()=>{}),{acquired:false,pid:await H(c)??void 0};throw s}}async function B(c){await k.unlink(c).catch(()=>{});}async function H(c){try{let t=await k.readFile(c,"utf-8"),e=parseInt(t.trim(),10);return isNaN(e)?null:e}catch{return null}}function X(c){try{return process.kill(c,0),!0}catch(t){return t.code==="EPERM"}}var R=class{constructor(t){this.inner=t;}cache=new Map;async list(t){let e=t?.status??"__all__";if(this.cache.has(e))return this.cache.get(e);let s=await this.inner.list(t);return this.cache.set(e,s),s}async get(t){return this.inner.get(t)}async save(t){await this.inner.save(t),this.cache.clear();}async delete(t){await this.inner.delete(t),this.cache.clear();}invalidate(){this.cache.clear();}},b=class{constructor(t){this.inner=t;}listCache=null;async list(){if(this.listCache)return this.listCache;let t=await this.inner.list();return this.listCache=t,t}async get(t){return this.inner.get(t)}async getByName(t){return this.inner.getByName(t)}async save(t){await this.inner.save(t),this.listCache=null;}async delete(t){await this.inner.delete(t),this.listCache=null;}invalidate(){this.listCache=null;}},x=class{constructor(t){this.inner=t;}cache=new Map;async list(t){let e=t?.status??"__all__";if(this.cache.has(e))return this.cache.get(e);let s=await this.inner.list(t);return this.cache.set(e,s),s}async get(t){return this.inner.get(t)}async save(t){await this.inner.save(t),this.cache.clear();}async delete(t){await this.inner.delete(t),this.cache.clear();}invalidate(){this.cache.clear();}};var Y={test_pass:{cmd:"npm",args:["test"]},typecheck:{cmd:"npx",args:["tsc","--noEmit"]},lint:{cmd:"npm",args:["run","lint"]}},_=class{cwd;timeoutMs;constructor(t){this.cwd=t.cwd,this.timeoutMs=t.timeout_ms??12e4;}async runAll(t){let e=[];for(let s of t){let a=await this.runCriterion(s);e.push(a);}return e}static allPassed(t){return t.length>0&&t.every(e=>e.passed)}static formatReport(t){return t.map(s=>{let a=s.passed?"\u2713":"\u2717",l=s.output.slice(0,500);return `${a} ${s.criterion}: ${s.passed?"PASSED":"FAILED"}
|
|
2
|
-
${l}`}).join(`
|
|
3
|
-
|
|
4
|
-
`)}runCriterion(t){let{cmd:e,args:s}=Y[t];return new Promise(a=>{execFile(e,s,{cwd:this.cwd,timeout:this.timeoutMs,maxBuffer:1024*1024},(l,r,i)=>{let u=(r+`
|
|
5
|
-
`+i).trim();a({criterion:t,passed:!l,output:u.slice(0,2e3)});});})}};var Z=8192,tt=4096,W=class{constructor(t){this.deps=t;this.cachedTaskStore=new R(t.taskStore),this.cachedAgentStore=new b(t.agentStore),this.cachedGoalStore=t.goalStore?new x(t.goalStore):null;}intervalId=null;shuttingDown=false;state=null;abortControllers=new Map;cachedTaskStore;cachedAgentStore;cachedGoalStore;saveStateTimer=null;saveStateDirty=false;lockAcquired=false;consecutiveTickFailures=0;maxConsecutiveTickFailures=5;maxRetryQueueSize=100;signalHandlers=[];immediateDispatchTimer=null;taskCreatedUnsub=null;tickInProgress=false;stateMutex=Promise.resolve();get isOwner(){return this.lockAcquired}withStateLock(t){let e,s=new Promise(l=>{e=l;}),a=this.stateMutex;return this.stateMutex=s,a.then(async()=>{try{return await t()}finally{e();}})}async runTask(t){await this.withTemporaryLock(async()=>{await this.loadState(),await this.dispatchTask(t);});}async runAll(){await this.withTemporaryLock(async()=>{await this.loadState(),await this.dispatchAll();});}async withTemporaryLock(t){let e=await C(this.deps.lockPath);if(!e.acquired)throw new d(e.pid);this.lockAcquired=true;try{await t();}finally{this.lockAcquired=false,await B(this.deps.lockPath);}}async startWatch(){let t=await C(this.deps.lockPath);if(!t.acquired)throw new d(t.pid);this.lockAcquired=true,await this.loadState(),this.state.pid=process.pid,this.state.started_at=new Date().toISOString(),await this.saveState(),this.registerSignalHandlers(),this.taskCreatedUnsub=this.deps.eventBus.on("task:created",()=>{this.scheduleImmediateDispatch();}),await this.tick(),this.intervalId=setInterval(()=>this.tick().then(()=>{this.consecutiveTickFailures=0;},e=>{this.consecutiveTickFailures++;let s=e instanceof Error?e.message:String(e);this.deps.eventBus.emit({type:"orchestrator:error",error:s,context:"tick",fatal:this.consecutiveTickFailures>=this.maxConsecutiveTickFailures}),this.consecutiveTickFailures>=this.maxConsecutiveTickFailures&&(this.deps.eventBus.emit({type:"orchestrator:shutdown",reason:`${this.consecutiveTickFailures} consecutive tick failures`}),this.stop().catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:"stop after consecutive tick failures",fatal:false});}));}),this.deps.config.scheduling.poll_interval_ms);}registerSignalHandlers(){let t=e=>{this.deps.eventBus.emit({type:"orchestrator:shutdown",reason:`Received ${e}`}),this.stop().catch(s=>{this.deps.eventBus.emit({type:"orchestrator:error",error:s instanceof Error?s.message:String(s),context:`stop after ${e} signal`,fatal:false});});};for(let e of ["SIGINT","SIGTERM"]){let s=()=>t(e);this.signalHandlers.push([e,s]),process.on(e,s);}}removeSignalHandlers(){for(let[t,e]of this.signalHandlers)process.removeListener(t,e);this.signalHandlers=[];}async stop(){this.shuttingDown||(this.shuttingDown=true,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.taskCreatedUnsub&&(this.taskCreatedUnsub(),this.taskCreatedUnsub=null),this.immediateDispatchTimer&&(clearTimeout(this.immediateDispatchTimer),this.immediateDispatchTimer=null),await this.flushStateLazy(),await this.withStateLock(async()=>{if(this.state){for(let[t,e]of Object.entries(this.state.running)){this.abortControllers.get(t)?.abort(),this.abortControllers.delete(t),await this.deps.processManager.killWithGrace(e.pid),await this.deps.runService.finish(e.run_id,"cancelled");let s=await this.deps.taskStore.get(t);s&&await this.deps.taskService.updateStatus(t,A(s)),await this.deps.agentService.setStatus(e.agent_id,"idle");}this.state.running={},this.state.claimed=[],this.state.pid=void 0,this.state.started_at=void 0,await this.saveState();}}),this.lockAcquired&&(await B(this.deps.lockPath),this.lockAcquired=false),this.removeSignalHandlers());}async cancelTask(t){if(!this.lockAcquired)return this.withTemporaryLock(()=>this.cancelTask(t));await this.withStateLock(async()=>{await this.loadState();let e=this.state,s=e.running[t];s&&(this.abortControllers.get(t)?.abort(),this.abortControllers.delete(t),await this.deps.processManager.killWithGrace(s.pid,3e3).catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask kill process ${s.pid} for task ${t}`,fatal:false});}),await this.deps.runService.finish(s.run_id,"cancelled").catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask finish run ${s.run_id}`,fatal:false});}),await this.deps.agentService.setStatus(s.agent_id,"idle").catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask setStatus idle for agent ${s.agent_id}`,fatal:false});}),delete e.running[t],await this.saveState()),e.retry_queue=e.retry_queue.filter(a=>a.task_id!==t);try{await this.deps.taskService.cancel(t);}catch{try{await this.deps.taskService.updateStatus(t,"cancelled");}catch{}}await this.saveState();});}async forceStopAgent(t){if(!this.lockAcquired)return this.withTemporaryLock(()=>this.forceStopAgent(t));await this.withStateLock(async()=>{await this.loadState();let e=this.state;for(let[s,a]of Object.entries(e.running))if(a.agent_id===t){this.abortControllers.get(s)?.abort(),this.abortControllers.delete(s),await this.deps.processManager.killWithGrace(a.pid,3e3),await this.deps.runService.finish(a.run_id,"cancelled");try{await this.deps.taskService.updateStatus(s,"failed");}catch{}delete e.running[s];}await this.deps.agentService.setStatus(t,"idle"),await this.saveState();});}async tick(){if(!this.shuttingDown){this.tickInProgress=true;try{await this.withStateLock(async()=>{if(this.shuttingDown)return;this.cachedTaskStore.invalidate(),this.cachedAgentStore.invalidate(),this.cachedGoalStore?.invalidate(),await this.loadState(),await this.reconcile(),await this.seedAutonomousTasks(),await this.dispatchAll();let t=await this.cachedTaskStore.list(),e=Object.keys(this.state.running).length,s=t.filter(a=>D(a.status)).length;this.deps.eventBus.emit({type:"orchestrator:tick",running:e,queued:s});});}finally{this.tickInProgress=false;}}}scheduleImmediateDispatch(){this.shuttingDown||this.immediateDispatchTimer||(this.immediateDispatchTimer=setTimeout(()=>{this.immediateDispatchTimer=null,!(this.shuttingDown||this.tickInProgress)&&this.immediateDispatch().catch(t=>{this.deps.eventBus.emit({type:"orchestrator:error",error:t instanceof Error?t.message:String(t),context:"immediate dispatch on task:created",fatal:false});});},500));}async immediateDispatch(){this.shuttingDown||await this.withStateLock(async()=>{this.shuttingDown||(this.cachedTaskStore.invalidate(),this.cachedAgentStore.invalidate(),await this.loadState(),await this.dispatchAll(),await this.saveState());});}async reconcile(){let t=this.state,e=Date.now();for(let[r,i]of Object.entries(t.running)){let u=await this.deps.taskStore.get(r);if(!u||P(u.status)){this.abortControllers.delete(r),delete t.running[r],await this.deps.agentService.setStatus(i.agent_id,"idle").catch(d=>{this.deps.eventBus.emit({type:"orchestrator:error",error:d instanceof Error?d.message:String(d),context:`reconcile setStatus idle for stale agent ${i.agent_id} (task ${r})`,fatal:false});});continue}if(!this.deps.processManager.isAlive(i.pid)){try{await this._handleRunFailure(r,i,"Process crashed unexpectedly");}catch{delete t.running[r],await this.deps.agentService.setStatus(i.agent_id,"idle").catch(d=>{this.deps.eventBus.emit({type:"orchestrator:error",error:d instanceof Error?d.message:String(d),context:`reconcile crash fallback setStatus idle for agent ${i.agent_id} (task ${r})`,fatal:false});});}continue}let o=new Date(i.last_event_at).getTime(),n=this.deps.config.defaults.agent.stall_timeout_ms;if(e-o>n){this.deps.eventBus.emit({type:"orchestrator:stall_detected",runId:i.run_id}),this.abortControllers.get(r)?.abort(),await this.deps.processManager.killWithGrace(i.pid,5e3);try{await this._handleRunFailure(r,i,"Agent stalled (no events)");}catch{delete t.running[r],await this.deps.agentService.setStatus(i.agent_id,"idle").catch(d=>{this.deps.eventBus.emit({type:"orchestrator:error",error:d instanceof Error?d.message:String(d),context:`reconcile stall fallback setStatus idle for agent ${i.agent_id} (task ${r})`,fatal:false});});}}}let s=new Set(Object.values(t.running).map(r=>r.agent_id)),a=await this.cachedAgentStore.list();for(let r of a)r.status==="running"&&!s.has(r.id)&&await this.deps.agentService.setStatus(r.id,"idle");let l=await this.cachedTaskStore.list();for(let r of l)if(r.status==="in_progress"&&!t.running[r.id]){try{await this.deps.taskService.updateStatus(r.id,"failed");}catch{r.status="failed",r.updated_at=new Date().toISOString(),await this.deps.taskStore.save(r).catch(i=>{this.deps.eventBus.emit({type:"orchestrator:error",error:i instanceof Error?i.message:String(i),context:`force-write orphaned task ${r.id}`,fatal:false});});}this.deps.eventBus.emit({type:"task:orphaned",taskId:r.id});}for(let r=t.retry_queue.length-1;r>=0;r--){let i=t.retry_queue[r];e>=new Date(i.due_at).getTime()&&(t.retry_queue.splice(r,1),await this.dispatchTask(i.task_id));}await this.saveState();}async seedAutonomousTasks(){let e=(await this.cachedAgentStore.list()).filter(i=>i.autonomous&&i.status==="idle");if(e.length===0)return;let s=await this.cachedTaskStore.list(),a$1=this.cachedGoalStore?await this.cachedGoalStore.list({status:"active"}):[],l=false,r=new Set;for(let i of e){if(s.some(h=>h.assignee===i.id&&!P(h.status)))continue;let o=a$1.find(h=>h.assignee===i.id&&!r.has(h.id))??a$1.find(h=>!h.assignee&&!r.has(h.id));o&&r.add(o.id);let n=i.role??"general assistant",d=o?`[auto] ${i.name}: ${o.title.slice(0,60)}`:`[auto] ${i.name}: ${n.slice(0,60)}`,g=o?`## GOAL (highest priority)
|
|
6
|
-
|
|
7
|
-
${o.description||o.title}
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
Agent role: ${n}`:`Autonomous work cycle. Agent role: ${n}`;try{await this.deps.taskService.create({title:d,description:g,assignee:i.id,labels:[a],priority:3}),l=!0;}catch(h){this.deps.eventBus.emit({type:"orchestrator:error",error:h instanceof Error?h.message:String(h),context:`autonomous task for agent ${i.id}`,fatal:false});}}l&&this.cachedTaskStore.invalidate();}async dispatchAll(){let t=this.state,e=this.deps.config.scheduling.max_concurrent_agents,s=Object.keys(t.running).length,a=e-s;if(a<=0)return;let l=await this.cachedTaskStore.list(),r=l.filter(o=>D(o.status)&&!G(o,l)&&!t.running[o.id]&&!t.claimed.includes(o.id)).sort((o,n)=>{let d=n.updated_at??"",g=o.updated_at??"";return d<g?-1:d>g?1:0}).slice(0,a),i=new Set,u=l.filter(o=>o.status==="in_progress"&&o.scope?.length);for(let o=0;o<r.length;o++){let n=r[o];if(!n.scope?.length)continue;let d=r.slice(0,o).filter(v=>!i.has(v.id)),g=[...u,...d],h=false;for(let v of g)if(U(n.scope,v.scope)){this.deps.eventBus.emit({type:"task:scope_overlap",taskId:n.id,overlappingTaskId:v.id,patterns:n.scope}),h=true;break}h&&i.add(n.id);}for(let o of r)if(!i.has(o.id))try{await this.dispatchTask(o.id);}catch(n){this.deps.eventBus.emit({type:"orchestrator:error",error:n instanceof Error?n.message:String(n),context:`dispatch task ${o.id}`,fatal:false});}}async dispatchTask(t){let e$1=this.state;if(e$1.running[t]){let a=e$1.running[t];throw new h(t,a.run_id,a.agent_id)}let s=await this.deps.taskService.get(t);e$1.claimed.push(t),await this.saveState();try{let a=await this.deps.agentService.findBestAgent(s);if(!a){if((await this.cachedAgentStore.list()).length===0)throw new e;this.unclaim(t),await this.saveState();return}let{path:l,branch:r}=await this.deps.workspaceManager.prepare(s,a,this.deps.config),i=this.deps.config.prompt?.template??d$1,u=await this.cachedAgentStore.list(),o=s.attempts+1,n;if(o>1){let w=await this.deps.runService.getLastFailedRunContext(s.id);w&&(n={previous_error:w.error,previous_output:w.output});}let d=this.deps.contextStore?await this.deps.contextStore.getAll():void 0,g=this.deps.messageService?await this.deps.messageService.drainMailbox(a.id,s.id):[],h=c(s,a,o,l,this.deps.config,{allAgents:u,retryContext:n,sharedContext:d,feedback:s.feedback,messages:g.length?g:void 0}),v=await this.deps.templateEngine.render(i,h),p=await this.deps.runService.create({taskId:s.id,agentId:a.id,attempt:o,prompt:v,workspacePath:l});(s.status==="failed"||s.status==="cancelled")&&(await this.deps.taskService.retry(t),s.status="todo",s.attempts=0),await this.deps.taskService.updateStatus(t,"in_progress"),await this.deps.taskService.assign(t,a.id),await this.deps.taskService.incrementAttempts(t),r&&(s.proof={...s.proof??{files_changed:[]},branch:r},s.workspace=l,await this.deps.taskStore.save(s)),await this.deps.agentService.setStatus(a.id,"running");let m=await this.deps.agentService.get(a.id);m.current_task=t,await this.deps.agentStore.save(m);let f=this.deps.adapterRegistry.require(a.adapter),S=new AbortController;this.abortControllers.set(t,S);let y=f.execute({prompt:v,workspace:l,env:{...a.config.env,ORCH_AGENT_ID:a.id,ORCH_AGENT_NAME:a.name,ORCH_TASK_ID:s.id},config:m.config,signal:S.signal}),M=y.pid,O=new Date().toISOString();await this.deps.runService.start(p.id,M),this.unclaim(t),e$1.running[t]={run_id:p.id,agent_id:a.id,task_id:t,pid:M,started_at:O,last_event_at:O},await this.saveState(),this.collectEvents(y.events,p.id,t,a.id).catch(w=>{this.deps.eventBus.emit({type:"orchestrator:error",error:w instanceof Error?w.message:String(w),context:`adapter execution for ${t}`,fatal:!1});});}catch(a){throw this.unclaim(t),await this.saveState(),a}}async collectEvents(t,e,s,a){let l,r,i,u=new Set;try{for await(let n of t){if(this.shuttingDown)break;if(n.type==="done"){n.tokens&&(l=n.tokens);let p=n.data;p&&typeof p.result=="string"&&(r=p.result);}if(n.type==="output"){let p=n.data;if(p){let m=typeof p.text=="string"?p.text:typeof p.message=="string"?p.message:void 0;m?.trim()&&(i=m);}}if(n.type==="file_change"){let p=n.data;if(p&&Array.isArray(p.paths))for(let m of p.paths)typeof m=="string"&&u.add(m);else {let m=p&&typeof p.path=="string"?p.path:typeof n.data=="string"?n.data:String(n.data);u.add(m);}}let d=et(n.timestamp)?n.timestamp:new Date().toISOString(),g=z(n.data,Z);n.data=void 0;let h={timestamp:d,type:n.type==="output"?"agent_output":n.type==="file_change"?"file_changed":n.type==="command"?"command_run":n.type==="tool_call"?"tool_call":n.type==="error"?"error":"done",data:g};await this.deps.runService.appendEvent(e,h),this.state?.running[s]&&(this.state.running[s].last_event_at=d,this.saveStateLazy());let v=z(g,tt);n.type==="output"||n.type==="tool_call"?this.deps.eventBus.emit({type:"agent:output",runId:e,agentId:a,data:v}):n.type==="file_change"?this.deps.eventBus.emit({type:"agent:file_changed",runId:e,agentId:a,path:typeof n.data=="string"?n.data:String(n.data)}):n.type==="error"&&this.deps.eventBus.emit({type:"agent:error",runId:e,agentId:a,error:v});}let o=r??i;await this.handleRunSuccess(s,e,a,l,o,[...u]);}catch(o){let n=o instanceof Error?o.message:String(o),d=this.state?.running[s];d&&await this.handleRunFailure(s,d,n);}}async handleRunSuccess(t,e,s,a,l,r){return this.withStateLock(()=>this._handleRunSuccess(t,e,s,a,l,r))}async _handleRunSuccess(t,e,s,a$1,l,r){await this.flushStateLazy(),this.abortControllers.delete(t);let i=this.state;if(!i.running[t])return;let u=await this.deps.taskStore.get(t);if(!u)return;u.proof={...u.proof,agent_summary:l?.slice(0,2e3)??u.proof?.agent_summary,files_changed:r?.length?r:u.proof?.files_changed??[]},delete u.feedback,await this.deps.taskStore.save(u);let o=await this.deps.agentStore.get(s),d=u.labels?.includes(a)||o?.config.approval_policy==="auto",g=N();await this.deps.runService.finish(e,"succeeded",a$1);let h=i.running[t],v=h?Date.now()-new Date(h.started_at).getTime():0;h&&(i.stats.total_runtime_ms+=v),delete i.running[t];let p={tasks_completed:(o?.stats.tasks_completed??0)+1,total_runs:(o?.stats.total_runs??0)+1,total_runtime_ms:(o?.stats.total_runtime_ms??0)+v};if(a$1&&(p.tokens_used=(o?.stats.tokens_used??0)+a$1.total),await this.deps.agentService.updateStats(s,p).catch(f=>{this.deps.eventBus.emit({type:"orchestrator:error",error:f instanceof Error?f.message:String(f),context:`agent stats update for ${s}`,fatal:false});}),i.stats.total_tasks_completed++,i.stats.total_runs++,a$1&&(i.stats.total_tokens.input+=a$1.input,i.stats.total_tokens.output+=a$1.output,i.stats.total_tokens.total=i.stats.total_tokens.input+i.stats.total_tokens.output),u.proof?.branch)try{let f=await this.deps.workspaceManager.mergeBack(u.proof.branch);if(f.success)this.deps.eventBus.emit({type:"workspace:merge_succeeded",taskId:t,branch:u.proof.branch}),await this.deps.workspaceManager.cleanup(t).catch(S=>{this.deps.eventBus.emit({type:"orchestrator:error",error:S instanceof Error?S.message:String(S),context:`workspace cleanup for ${t}`,fatal:!1});});else {this.deps.eventBus.emit({type:"workspace:merge_conflict",taskId:t,branch:u.proof.branch,conflictInfo:f.conflictInfo}),await this.forceTaskToReview(u,s,`MERGE CONFLICT: ${f.conflictInfo}`);return}}catch(f){let S=f instanceof Error?f.message:String(f);await this.forceTaskToReview(u,s,`MERGE ERROR: ${S}`);return}try{await this.deps.taskService.updateStatus(t,g);}catch(f){let S=f instanceof Error?f.message:String(f);this.deps.eventBus.emit({type:"orchestrator:error",error:S,context:`state machine validation failed for task ${t} -> ${g}, force-writing`,fatal:false}),u.status=g,u.updated_at=new Date().toISOString(),await this.deps.taskStore.save(u).catch(y=>{this.deps.eventBus.emit({type:"orchestrator:error",error:y instanceof Error?y.message:String(y),context:`force-write task ${t} to store failed`,fatal:false});});}await this.deps.agentService.setStatus(s,"idle").catch(f=>{this.deps.eventBus.emit({type:"orchestrator:error",error:f instanceof Error?f.message:String(f),context:`_handleRunSuccess setStatus idle for agent ${s}`,fatal:false});});let m=await this.deps.agentStore.get(s);m&&(m.current_task=void 0,await this.deps.agentStore.save(m)),u.review_criteria?.length?await this.runAutoReview(t,u.review_criteria,u.workspace??this.deps.projectRoot):d&&await this.deps.taskService.updateStatus(t,"done"),await this.saveState(),this.scheduleImmediateDispatch();}async handleRunFailure(t,e,s){return this.withStateLock(()=>this._handleRunFailure(t,e,s))}async _handleRunFailure(t,e,s){await this.flushStateLazy(),this.abortControllers.delete(t);let a=this.state,l=await this.deps.taskStore.get(t);if(!l)return;await this.deps.runService.finish(e.run_id,"failed",void 0,s),await this.deps.agentService.setStatus(e.agent_id,"idle");let r=await this.deps.agentStore.get(e.agent_id);r&&(r.current_task=void 0,await this.deps.agentStore.save(r));let i=await this.deps.agentStore.get(e.agent_id),u=Date.now()-new Date(e.started_at).getTime();await this.deps.agentService.updateStats(e.agent_id,{tasks_failed:(i?.stats.tasks_failed??0)+1,total_runs:(i?.stats.total_runs??0)+1,total_runtime_ms:(i?.stats.total_runtime_ms??0)+u});let o=A(l);if(await this.deps.taskService.updateStatus(t,o),o==="retrying"){let n=F(l.attempts-1,this.deps.config.scheduling.retry_base_delay_ms,this.deps.config.scheduling.retry_max_delay_ms);a.retry_queue.some(g=>g.task_id===t)||(a.retry_queue.length>=this.maxRetryQueueSize&&a.retry_queue.shift(),a.retry_queue.push({task_id:t,attempt:l.attempts+1,due_at:new Date(Date.now()+n).toISOString(),error:s})),this.deps.eventBus.emit({type:"run:retry",runId:e.run_id,attempt:l.attempts+1,delay_ms:n});}else a.stats.total_tasks_failed++;a.stats.total_runtime_ms+=u,delete a.running[t],a.stats.total_runs++,await this.saveState(),this.scheduleImmediateDispatch();}async runAutoReview(t,e,s){let l=await new _({cwd:s}).runAll(e),r=_.allPassed(l),i=await this.deps.taskStore.get(t);if(i&&(i.review_results=l,i.proof={...i.proof,test_results:_.formatReport(l),files_changed:i.proof?.files_changed??[]},await this.deps.taskStore.save(i),this.deps.eventBus.emit({type:"task:auto_reviewed",taskId:t,passed:r,results:l}),r))try{await this.deps.taskService.updateStatus(t,"done");}catch(u){let o=u instanceof Error?u.message:String(u);this.deps.eventBus.emit({type:"orchestrator:error",error:o,context:`auto-review transition failed for task ${t} -> done, force-writing`,fatal:false}),i.status="done",i.updated_at=new Date().toISOString(),await this.deps.taskStore.save(i).catch(n=>{this.deps.eventBus.emit({type:"orchestrator:error",error:n instanceof Error?n.message:String(n),context:`force-write task ${t} to store failed (auto-review)`,fatal:false});});}}async forceTaskToReview(t,e,s){t.proof={...t.proof,agent_summary:`${s}
|
|
11
|
-
|
|
12
|
-
${t.proof?.agent_summary??""}`.slice(0,2e3),files_changed:t.proof?.files_changed??[]},t.status="review",t.updated_at=new Date().toISOString(),await this.deps.taskStore.save(t),await this.deps.agentService.setStatus(e,"idle").catch(l=>{this.deps.eventBus.emit({type:"orchestrator:error",error:l instanceof Error?l.message:String(l),context:`forceTaskToReview setStatus idle for agent ${e}`,fatal:false});});let a=await this.deps.agentStore.get(e);a&&(a.current_task=void 0,await this.deps.agentStore.save(a)),await this.saveState();}unclaim(t){let e=this.state.claimed.indexOf(t);e!==-1&&this.state.claimed.splice(e,1);}requireOwnership(){if(!this.lockAcquired)throw new d(0)}async loadState(){this.state=await this.deps.stateStore.read();}async saveState(){this.state&&await this.deps.stateStore.write(this.state);}saveStateLazy(){this.saveStateDirty=true,!this.saveStateTimer&&(this.saveStateTimer=setTimeout(()=>{this.saveStateTimer=null,this.saveStateDirty&&(this.saveStateDirty=false,this.saveState().catch(t=>{this.deps.eventBus.emit({type:"orchestrator:error",error:t instanceof Error?t.message:String(t),context:"debounced state save",fatal:false});}));},500));}async flushStateLazy(){this.saveStateTimer&&(clearTimeout(this.saveStateTimer),this.saveStateTimer=null),this.saveStateDirty&&(this.saveStateDirty=false,await this.saveState());}};function et(c){if(typeof c!="string")return false;let t=new Date(c);return !isNaN(t.getTime())&&t.toISOString()===c}function z(c,t){let e=typeof c=="string"?c:JSON.stringify(c);return e.length>t?e.slice(0,t)+"\u2026":e}export{st as a,P as b,D as c,G as d,A as e,W as f};//# sourceMappingURL=chunk-E3TCKHU6.js.map
|
|
13
|
-
//# sourceMappingURL=chunk-E3TCKHU6.js.map
|