feat: enhance workflow and testing infrastructure

- Introduced ExecutionMode type for project execution modes (parallel, sequential).
- Updated SetupOpts to use ExecutionMode instead of string literals.
- Enhanced workflow states to include a new "In Review" state with appropriate transitions.
- Implemented TestHarness for end-to-end testing, including command interception and workspace setup.
- Created TestProvider for in-memory issue tracking during tests.
- Refactored project registration and setup tools to utilize ExecutionMode.
- Updated various tools to ensure compatibility with new workflow and execution modes.
- Added new dependencies: cockatiel for resilience and zod for schema validation.
This commit is contained in:
Lauren ten Hoor
2026-02-16 13:27:14 +08:00
parent a359ffed34
commit 371e760d94
37 changed files with 2444 additions and 263 deletions

View File

@@ -14,7 +14,8 @@ import YAML from "yaml";
import { ROLE_REGISTRY } from "../roles/registry.js";
import { DEFAULT_WORKFLOW, type WorkflowConfig } from "../workflow.js";
import { mergeConfig } from "./merge.js";
import type { DevClawConfig, ResolvedConfig, ResolvedRoleConfig, RoleOverride } from "./types.js";
import type { DevClawConfig, ResolvedConfig, ResolvedRoleConfig, ResolvedTimeouts, RoleOverride } from "./types.js";
import { validateConfig, validateWorkflowIntegrity } from "./schema.js";
import { DATA_DIR } from "../setup/migrate-layout.js";
/**
@@ -140,20 +141,42 @@ function resolve(config: DevClawConfig): ResolvedConfig {
states: { ...DEFAULT_WORKFLOW.states, ...config.workflow?.states },
};
return { roles, workflow };
// Validate structural integrity (cross-references between states)
const integrityErrors = validateWorkflowIntegrity(workflow);
if (integrityErrors.length > 0) {
throw new Error(`Workflow config integrity errors:\n - ${integrityErrors.join("\n - ")}`);
}
const timeouts: ResolvedTimeouts = {
gitPullMs: config.timeouts?.gitPullMs ?? 30_000,
gatewayMs: config.timeouts?.gatewayMs ?? 15_000,
sessionPatchMs: config.timeouts?.sessionPatchMs ?? 30_000,
dispatchMs: config.timeouts?.dispatchMs ?? 600_000,
staleWorkerHours: config.timeouts?.staleWorkerHours ?? 2,
};
return { roles, workflow, timeouts };
}
// ---------------------------------------------------------------------------
// File reading helpers
// ---------------------------------------------------------------------------
/** Read workflow.yaml (new primary config file). */
/** Read workflow.yaml (new primary config file). Validates structure via Zod. */
async function readWorkflowFile(dir: string): Promise<DevClawConfig | null> {
try {
const content = await fs.readFile(path.join(dir, "workflow.yaml"), "utf-8");
return YAML.parse(content) as DevClawConfig;
} catch { /* not found */ }
return null;
const parsed = YAML.parse(content);
if (parsed) validateConfig(parsed);
return parsed as DevClawConfig;
} catch (err: any) {
if (err?.code === "ENOENT") return null;
// Re-throw validation errors with file context
if (err?.name === "ZodError") {
throw new Error(`Invalid workflow.yaml in ${dir}: ${err.message}`);
}
return null;
}
}
/** Read config.yaml (old name, fallback for unmigrated workspaces). */