refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt standard monorepo conventions (apps/ for runnable apps, packages/ for reusable libraries). Update all config files, shared package imports, test fixtures, and documentation to reflect new paths. Key fixes: - Update workspace config to ["apps/*", "packages/*"] - Update tsconfig.json rootDir/include for apps/server/ - Add apps/web/** to vitest exclude list - Update drizzle.config.ts schema path - Fix ensure-schema.ts migration path detection (3 levels up in dev, 2 levels up in dist) - Fix tests/integration/cli-server.test.ts import paths - Update packages/shared imports to apps/server/ paths - Update all docs/ files with new paths
This commit is contained in:
108
apps/server/agent/lifecycle/cleanup-strategy.ts
Normal file
108
apps/server/agent/lifecycle/cleanup-strategy.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* CleanupStrategy — Centralized cleanup logic based on debug mode and agent state.
|
||||
*
|
||||
* Determines when and how to clean up agent workdirs and resources.
|
||||
* Supports archive mode for debugging vs. immediate cleanup for production.
|
||||
*/
|
||||
|
||||
import { createModuleLogger } from '../../logger/index.js';
|
||||
import type { CleanupManager } from '../cleanup-manager.js';
|
||||
|
||||
const log = createModuleLogger('cleanup-strategy');
|
||||
|
||||
export type CleanupAction = 'remove' | 'archive' | 'preserve';
|
||||
|
||||
export interface AgentInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
status: string;
|
||||
initiativeId?: string | null;
|
||||
worktreeId: string;
|
||||
}
|
||||
|
||||
export interface CleanupStrategy {
|
||||
shouldCleanup(agent: AgentInfo, isDebugMode: boolean): Promise<CleanupAction>;
|
||||
executeCleanup(agent: AgentInfo, action: CleanupAction): Promise<void>;
|
||||
}
|
||||
|
||||
export class DefaultCleanupStrategy implements CleanupStrategy {
|
||||
constructor(private cleanupManager: CleanupManager) {}
|
||||
|
||||
/**
|
||||
* Determine what cleanup action should be taken for an agent.
|
||||
* Considers agent status and debug mode setting.
|
||||
*/
|
||||
async shouldCleanup(agent: AgentInfo, isDebugMode: boolean): Promise<CleanupAction> {
|
||||
log.debug({
|
||||
agentId: agent.id,
|
||||
name: agent.name,
|
||||
status: agent.status,
|
||||
isDebugMode
|
||||
}, 'evaluating cleanup action for agent');
|
||||
|
||||
// Never cleanup agents waiting for user input
|
||||
if (agent.status === 'waiting_for_input') {
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'preserving agent waiting for input');
|
||||
return 'preserve';
|
||||
}
|
||||
|
||||
// Never cleanup running agents
|
||||
if (agent.status === 'running') {
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'preserving running agent');
|
||||
return 'preserve';
|
||||
}
|
||||
|
||||
// For completed/idle/crashed agents, decide based on debug mode
|
||||
if (agent.status === 'idle' || agent.status === 'completed' || agent.status === 'crashed') {
|
||||
if (isDebugMode) {
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'archiving agent in debug mode');
|
||||
return 'archive';
|
||||
} else {
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'removing agent in production mode');
|
||||
return 'remove';
|
||||
}
|
||||
}
|
||||
|
||||
// For stopped agents, clean up immediately regardless of debug mode
|
||||
if (agent.status === 'stopped') {
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'removing stopped agent');
|
||||
return 'remove';
|
||||
}
|
||||
|
||||
// Default to preserve for any unrecognized status
|
||||
log.debug({ agentId: agent.id, status: agent.status }, 'preserving agent with unrecognized status');
|
||||
return 'preserve';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the determined cleanup action.
|
||||
*/
|
||||
async executeCleanup(agent: AgentInfo, action: CleanupAction): Promise<void> {
|
||||
log.debug({
|
||||
agentId: agent.id,
|
||||
name: agent.name,
|
||||
action
|
||||
}, 'executing cleanup action');
|
||||
|
||||
switch (action) {
|
||||
case 'remove':
|
||||
await this.cleanupManager.removeAgentWorktrees(agent.name, agent.initiativeId ?? null);
|
||||
await this.cleanupManager.removeAgentBranches(agent.name, agent.initiativeId ?? null);
|
||||
await this.cleanupManager.removeAgentLogs(agent.id);
|
||||
log.info({ agentId: agent.id, name: agent.name }, 'agent workdir and resources removed');
|
||||
break;
|
||||
|
||||
case 'archive':
|
||||
await this.cleanupManager.archiveForDebug(agent.worktreeId, agent.id);
|
||||
log.info({ agentId: agent.id, name: agent.name }, 'agent workdir archived for debugging');
|
||||
break;
|
||||
|
||||
case 'preserve':
|
||||
log.debug({ agentId: agent.id, name: agent.name }, 'agent workdir preserved');
|
||||
break;
|
||||
|
||||
default:
|
||||
log.warn({ agentId: agent.id, action }, 'unknown cleanup action, preserving by default');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user