refactor: unify errand worktree paths to use agent-workdirs/<alias>/
Errands now create worktrees via ProcessManager.createWorktreesForProjects() into agent-workdirs/<alias>/<project.name>/ instead of repos/<project>/.cw-worktrees/<errandId>. This makes getAgentWorkdir + resolveAgentCwd work correctly for all agent types. Key changes: - Extract createWorktreesForProjects() from createProjectWorktrees() in ProcessManager - Add resolveAgentCwd() to ProcessManager (probes for .cw/output in subdirs) - Add projectId to SpawnAgentOptions for single-project agents (errands) - Skip auto-cleanup for errand agents (worktrees persist for merge/abandon) - Errand router uses agentManager.delete() for cleanup instead of SimpleGitWorktreeManager - Remove cwd parameter from sendUserMessage (resolves via worktreeId) - Add pruneProjectRepos() to CleanupManager for errand worktree refs
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import { spawn } from 'node:child_process';
|
||||
import { openSync, closeSync, existsSync } from 'node:fs';
|
||||
import { openSync, closeSync, existsSync, readdirSync } from 'node:fs';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import type { ProjectRepository } from '../db/repositories/project-repository.js';
|
||||
@@ -46,6 +46,36 @@ export class ProcessManager {
|
||||
return join(this.workspaceRoot, 'agent-workdirs', alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the actual working directory for an agent by probing
|
||||
* for the subdirectory that contains .cw/output/.
|
||||
*/
|
||||
resolveAgentCwd(alias: string): string {
|
||||
const base = this.getAgentWorkdir(alias);
|
||||
|
||||
// Fast path: .cw/output exists at the base level
|
||||
if (existsSync(join(base, '.cw', 'output'))) return base;
|
||||
|
||||
// Standalone agents use a workspace/ subdirectory
|
||||
const workspaceSub = join(base, 'workspace');
|
||||
if (existsSync(join(workspaceSub, '.cw'))) return workspaceSub;
|
||||
|
||||
// Initiative/errand agents may have written .cw/ inside a project
|
||||
// subdirectory (e.g. agent-workdirs/<name>/<project-name>/.cw/).
|
||||
try {
|
||||
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && entry.name !== '.cw') {
|
||||
const sub = join(base, entry.name);
|
||||
if (existsSync(join(sub, '.cw', 'output'))) return sub;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// base dir may not exist
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create worktrees for all projects linked to an initiative.
|
||||
* Returns the base agent workdir path.
|
||||
@@ -57,13 +87,11 @@ export class ProcessManager {
|
||||
branchName?: string,
|
||||
): Promise<string> {
|
||||
const projects = await this.projectRepository.findProjectsByInitiativeId(initiativeId);
|
||||
const agentWorkdir = this.getAgentWorkdir(alias);
|
||||
|
||||
log.debug({
|
||||
alias,
|
||||
initiativeId,
|
||||
projectCount: projects.length,
|
||||
agentWorkdir,
|
||||
baseBranch
|
||||
}, 'creating project worktrees');
|
||||
|
||||
@@ -74,6 +102,22 @@ export class ProcessManager {
|
||||
return this.createStandaloneWorktree(alias);
|
||||
}
|
||||
|
||||
return this.createWorktreesForProjects(alias, projects, baseBranch, branchName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create worktrees for a given list of projects under agent-workdirs/<alias>/.
|
||||
* Used by both initiative-based and single-project (errand) agents.
|
||||
* Returns the base agent workdir path.
|
||||
*/
|
||||
async createWorktreesForProjects(
|
||||
alias: string,
|
||||
projects: Array<{ name: string; url: string; id: string; defaultBranch: string }>,
|
||||
baseBranch?: string,
|
||||
branchName?: string,
|
||||
): Promise<string> {
|
||||
const agentWorkdir = this.getAgentWorkdir(alias);
|
||||
|
||||
for (const project of projects) {
|
||||
const clonePath = await ensureProjectClone(project, this.workspaceRoot);
|
||||
const worktreeManager = new SimpleGitWorktreeManager(clonePath, undefined, agentWorkdir);
|
||||
|
||||
Reference in New Issue
Block a user