feat(backends): multi-backend intelligence layer — LLM + Agent backends, persona-loading agents, honest CLI commands
Add IntelligenceBackend abstraction with two categories: - LLMBackend (OllamaLocal, OllamaCloud): CI runs tool loop, provides tools, constructs prompts - AgentBackend (Opencode): agent runs own tool loop, CI serializes request Refactor all 18 agents from hardcoded stubs to persona loaders that delegate to the active backend or fail honestly when no backend is available. Refactor OrchestratorAgent.executeStage() from monolithic switch to agent delegation via STAGE_AGENT_MAP for intelligent stages (research, plan, execute, verify), with mechanical stages (specify, clarify, complete) staying inline. Wire CLI commands with --backend flag and auto-detection (opencode → ollama-local → ollama-cloud). Harden rollback/ship with real git operations. No command returns fake success.
This commit is contained in:
+33
-1
@@ -1,3 +1,6 @@
|
||||
import { IntelligenceBackend, BackendRequest, BackendResult, BackendUnavailableError, emptyBackendResult } from "../backends/types.js";
|
||||
import { AgentName, AutonomyLevel } from "../types/config.js";
|
||||
|
||||
export interface AgentResult {
|
||||
success: boolean;
|
||||
output: string;
|
||||
@@ -14,14 +17,43 @@ export interface AgentContext {
|
||||
stage: string;
|
||||
specification: string;
|
||||
config_path: string;
|
||||
backend?: IntelligenceBackend;
|
||||
}
|
||||
|
||||
export function backendResultToAgentResult(result: BackendResult): AgentResult {
|
||||
return {
|
||||
success: result.success,
|
||||
output: result.output,
|
||||
artifacts_created: result.artifacts.map((a) => a.path),
|
||||
decisions: result.decisions.length,
|
||||
escalations: result.escalations.length,
|
||||
duration_ms: 0,
|
||||
error: result.error,
|
||||
};
|
||||
}
|
||||
|
||||
export abstract class BaseAgent {
|
||||
abstract readonly name: string;
|
||||
abstract readonly name: AgentName;
|
||||
abstract readonly description: string;
|
||||
abstract readonly workflow: string;
|
||||
|
||||
abstract execute(context: AgentContext): Promise<AgentResult>;
|
||||
|
||||
protected async executeViaBackend(context: AgentContext, task: string): Promise<AgentResult> {
|
||||
if (!context.backend) {
|
||||
throw new BackendUnavailableError("none", this.name);
|
||||
}
|
||||
const request: BackendRequest = {
|
||||
persona: this.name,
|
||||
workflow: this.workflow,
|
||||
task,
|
||||
context,
|
||||
autonomy: "full",
|
||||
};
|
||||
const result = await context.backend.execute(request);
|
||||
return backendResultToAgentResult(result);
|
||||
}
|
||||
|
||||
protected log(message: string): void {
|
||||
console.log(`[${this.name}] ${message}`);
|
||||
}
|
||||
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class ChallengerAgent extends BaseAgent {
|
||||
readonly name = "challenger";
|
||||
readonly description = "Stress-tests plans with binding verdicts. Only escalates when confidence < 0.60.";
|
||||
readonly workflow = "plan";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Challenging plan...");
|
||||
const start = Date.now();
|
||||
this.log("Challenging plan...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Stress-test the plan for phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Plan challenge complete — verdict: proceed",
|
||||
success: false,
|
||||
output: "Plan challenge requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class CodeReviewerAgent extends BaseAgent {
|
||||
readonly name = "code-reviewer";
|
||||
readonly description = "Multi-persona code review. Auto-applies P0 fixes. Flags P1+ for post-hoc review.";
|
||||
readonly workflow = "review";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Running code review...");
|
||||
const start = Date.now();
|
||||
this.log("Running code review...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Perform multi-persona code review for phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Code review complete — P0 fixes applied, P1+ flagged for review",
|
||||
artifacts_created: ["CODE-REVIEW.md"],
|
||||
success: false,
|
||||
output: "Code review requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
+13
-4
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class DebuggerAgent extends BaseAgent {
|
||||
readonly name = "debugger";
|
||||
readonly description = "Autonomous debugging. Auto-fixes when root cause confidence > 0.60, escalates otherwise.";
|
||||
readonly workflow = "debug";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Running autonomous debug...");
|
||||
const start = Date.now();
|
||||
this.log("Running autonomous debug...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Debug the following issue: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Debug complete — issue identified and resolved",
|
||||
artifacts_created: ["DEBUG.md"],
|
||||
success: false,
|
||||
output: "Debugging requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class DocVerifierAgent extends BaseAgent {
|
||||
readonly name = "doc-verifier";
|
||||
readonly description = "Verifies documentation matches live codebase.";
|
||||
readonly workflow = "verify";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Verifying documentation...");
|
||||
const start = Date.now();
|
||||
this.log("Verifying documentation...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Verify documentation matches codebase for phase ${context.phase}.`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Documentation verification complete",
|
||||
success: false,
|
||||
output: "Documentation verification requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class DocWriterAgent extends BaseAgent {
|
||||
readonly name = "doc-writer";
|
||||
readonly description = "Autonomous documentation writer. No behavioral changes from Learnship.";
|
||||
readonly workflow = "execute";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Writing documentation...");
|
||||
const start = Date.now();
|
||||
this.log("Writing documentation...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Write documentation for phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Documentation written",
|
||||
artifacts_created: ["DOCS.md"],
|
||||
success: false,
|
||||
output: "Documentation writing requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class ExecutorAgent extends BaseAgent {
|
||||
readonly name = "executor";
|
||||
readonly description = "Executes plan tasks autonomously. Never pauses for checkpoints.";
|
||||
readonly workflow = "execute";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Executing tasks...");
|
||||
const start = Date.now();
|
||||
this.log("Executing tasks...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Execute implementation for stage ${context.stage}, phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Tasks executed",
|
||||
success: false,
|
||||
output: "Execution requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class IdeationAgent extends BaseAgent {
|
||||
readonly name = "ideation-agent";
|
||||
readonly description = "Generates improvement ideas. Output feeds directly into planning pipeline.";
|
||||
readonly workflow = "research";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Generating improvement ideas...");
|
||||
const start = Date.now();
|
||||
this.log("Generating improvement ideas...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Generate improvement ideas for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Ideation complete",
|
||||
artifacts_created: ["IDEAS.md"],
|
||||
success: false,
|
||||
output: "Ideation requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export { BaseAgent } from "./base.js";
|
||||
export { BaseAgent, AgentContext, AgentResult, backendResultToAgentResult } from "./base.js";
|
||||
export { OrchestratorAgent } from "./orchestrator.js";
|
||||
export { PlannerAgent } from "./planner.js";
|
||||
export { ExecutorAgent } from "./executor.js";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { GitContext, ProjectState } from "../core/git-context.js";
|
||||
import { GitBranch } from "../core/git-branch.js";
|
||||
import { CiFiles } from "../core/ci-files.js";
|
||||
import { CommitBuilder } from "../core/commit-builder.js";
|
||||
import { CIConfig } from "../types/config.js";
|
||||
import { CIConfig, AgentName } from "../types/config.js";
|
||||
import {
|
||||
PipelineState,
|
||||
PipelineStage,
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
} from "../types/pipeline.js";
|
||||
import { Specification, parseSpecification } from "../types/specification.js";
|
||||
import { loadConfig, saveConfig, isCIInitialized, initCI } from "../core/config.js";
|
||||
import { getAgent } from "./index.js";
|
||||
import { IntelligenceBackend, BackendUnavailableError } from "../backends/types.js";
|
||||
|
||||
export interface GitAgentContext extends AgentContext {
|
||||
gitContext: GitContext;
|
||||
@@ -26,8 +28,9 @@ export interface GitAgentContext extends AgentContext {
|
||||
}
|
||||
|
||||
export class OrchestratorAgent extends BaseAgent {
|
||||
readonly name = "orchestrator";
|
||||
readonly name: AgentName = "orchestrator";
|
||||
readonly description = "Top-level autonomous controller that coordinates the full CI pipeline";
|
||||
readonly workflow = "run";
|
||||
|
||||
private config: CIConfig;
|
||||
private pipelineState: PipelineState | null = null;
|
||||
@@ -39,6 +42,13 @@ export class OrchestratorAgent extends BaseAgent {
|
||||
private currentMilestone: string;
|
||||
private phaseResults: PhaseResult[] = [];
|
||||
|
||||
private static readonly STAGE_AGENT_MAP: Partial<Record<PipelineStage, AgentName>> = {
|
||||
research: "researcher",
|
||||
plan: "planner",
|
||||
execute: "executor",
|
||||
verify: "verifier",
|
||||
};
|
||||
|
||||
constructor(config?: CIConfig) {
|
||||
super();
|
||||
this.config = config || loadConfig(process.cwd());
|
||||
@@ -149,6 +159,32 @@ export class OrchestratorAgent extends BaseAgent {
|
||||
context: AgentContext
|
||||
): Promise<PhaseResult> {
|
||||
const stageStart = Date.now();
|
||||
const agentName = OrchestratorAgent.STAGE_AGENT_MAP[stage];
|
||||
|
||||
if (agentName && context.backend) {
|
||||
this.log(`Delegating ${stage} to ${agentName} agent via backend...`);
|
||||
try {
|
||||
const agent = getAgent(agentName);
|
||||
const result = await agent.execute(context);
|
||||
return {
|
||||
phase: this.pipelineState!.current_phase,
|
||||
stage,
|
||||
success: result.success,
|
||||
artifacts_created: Array.isArray(result.artifacts_created) ? result.artifacts_created : [],
|
||||
decisions_made: result.decisions,
|
||||
escalations_raised: result.escalations,
|
||||
duration_ms: Date.now() - stageStart,
|
||||
error: result.error,
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof BackendUnavailableError) {
|
||||
this.warn(`Backend unavailable for ${stage}, falling back to mechanical execution`);
|
||||
} else {
|
||||
this.warn(`Agent ${agentName} failed for ${stage}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let decisionsMade = 0;
|
||||
let escalationsRaised = 0;
|
||||
const artifactsCreated: string[] = [];
|
||||
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class PhaseResearcherAgent extends BaseAgent {
|
||||
readonly name = "phase-researcher";
|
||||
readonly description = "Researches how to implement a specific phase well.";
|
||||
readonly workflow = "research";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Researching phase implementation...");
|
||||
const start = Date.now();
|
||||
this.log("Researching phase implementation...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Research how to implement phase ${context.phase} well. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Phase research complete",
|
||||
artifacts_created: ["RESEARCH.md"],
|
||||
success: false,
|
||||
output: "Phase research requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class PlanCheckerAgent extends BaseAgent {
|
||||
readonly name = "plan-checker";
|
||||
readonly description = "Verifies plan quality. On ISSUES FOUND, triggers automatic plan revision (up to 3 iterations).";
|
||||
readonly workflow = "plan";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Checking plan quality...");
|
||||
const start = Date.now();
|
||||
this.log("Checking plan quality...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Verify plan quality for phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Plan check passed",
|
||||
success: false,
|
||||
output: "Plan checking requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
-5
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class PlannerAgent extends BaseAgent {
|
||||
readonly name = "planner";
|
||||
readonly description = "Creates phase plans with tasks. Never sets autonomous:false — decomposes into verifiable subtasks.";
|
||||
readonly workflow = "plan";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Creating phase plan...");
|
||||
const start = Date.now();
|
||||
this.log("Creating phase plan...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Create a phase plan for stage ${context.stage}, phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Plan created with verifiable subtasks",
|
||||
artifacts_created: ["PLAN.md"],
|
||||
decisions: 1,
|
||||
success: false,
|
||||
output: "Planning requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class ProjectResearcherAgent extends BaseAgent {
|
||||
readonly name = "project-researcher";
|
||||
readonly description = "Researches the domain ecosystem for a new project.";
|
||||
readonly workflow = "research";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Researching project domain ecosystem...");
|
||||
const start = Date.now();
|
||||
this.log("Researching project domain ecosystem...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Research the domain ecosystem for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Project research complete",
|
||||
artifacts_created: ["RESEARCH.md"],
|
||||
success: false,
|
||||
output: "Project research requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class ResearchSynthesizerAgent extends BaseAgent {
|
||||
readonly name = "research-synthesizer";
|
||||
readonly description = "Synthesizes research files into a cohesive summary for roadmap creation.";
|
||||
readonly workflow = "research";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Synthesizing research...");
|
||||
const start = Date.now();
|
||||
this.log("Synthesizing research...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Synthesize research findings into a summary for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Research synthesis complete",
|
||||
artifacts_created: ["SUMMARY.md"],
|
||||
success: false,
|
||||
output: "Research synthesis requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class ResearcherAgent extends BaseAgent {
|
||||
readonly name = "researcher";
|
||||
readonly description = "Researches project domain. Logs assumptions instead of asking for validation.";
|
||||
readonly workflow = "research";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Researching domain...");
|
||||
const start = Date.now();
|
||||
this.log("Researching domain...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Research the domain for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Research complete",
|
||||
artifacts_created: ["RESEARCH.md"],
|
||||
decisions: 1,
|
||||
success: false,
|
||||
output: "Research requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class RoadmapperAgent extends BaseAgent {
|
||||
readonly name = "roadmapper";
|
||||
readonly description = "Creates and maintains project roadmaps.";
|
||||
readonly workflow = "plan";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Creating roadmap...");
|
||||
const start = Date.now();
|
||||
this.log("Creating roadmap...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Create project roadmap for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Roadmap created",
|
||||
artifacts_created: ["ROADMAP.md"],
|
||||
decisions: 1,
|
||||
success: false,
|
||||
output: "Roadmap creation requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class SecurityAuditorAgent extends BaseAgent {
|
||||
readonly name = "security-auditor";
|
||||
readonly description = "Auto-dispositions threats: low=accept, medium=mitigate, high=escalate.";
|
||||
readonly workflow = "verify";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Running security audit...");
|
||||
const start = Date.now();
|
||||
this.log("Running security audit...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Perform security audit for phase ${context.phase}. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Security audit complete",
|
||||
artifacts_created: ["SECURITY.md"],
|
||||
decisions: 1,
|
||||
success: false,
|
||||
output: "Security auditing requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class SolutionWriterAgent extends BaseAgent {
|
||||
readonly name = "solution-writer";
|
||||
readonly description = "Produces structured solution documents for .planning/solutions/.";
|
||||
readonly workflow = "execute";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Writing solution document...");
|
||||
const start = Date.now();
|
||||
this.log("Writing solution document...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Write a structured solution document for: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Solution document written",
|
||||
artifacts_created: ["SOLUTION.md"],
|
||||
success: false,
|
||||
output: "Solution writing requires an intelligence backend.",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
+13
-4
@@ -3,17 +3,26 @@ import { BaseAgent, AgentContext, AgentResult } from "./base.js";
|
||||
export class VerifierAgent extends BaseAgent {
|
||||
readonly name = "verifier";
|
||||
readonly description = "Verifies phase outputs. Generates automated tests instead of requesting human UAT.";
|
||||
readonly workflow = "verify";
|
||||
|
||||
async execute(context: AgentContext): Promise<AgentResult> {
|
||||
this.log("Verifying phase output...");
|
||||
const start = Date.now();
|
||||
this.log("Verifying phase output...");
|
||||
if (context.backend) {
|
||||
const result = await this.executeViaBackend(
|
||||
context,
|
||||
`Verify phase ${context.phase} output. Specification: ${context.specification}`
|
||||
);
|
||||
return { ...result, duration_ms: Date.now() - start };
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: "Verification complete — all checks passed",
|
||||
artifacts_created: ["VERIFICATION.md"],
|
||||
success: false,
|
||||
output: "Verification requires an intelligence backend. Configure one with: ci init --backend",
|
||||
artifacts_created: [],
|
||||
decisions: 0,
|
||||
escalations: 0,
|
||||
duration_ms: Date.now() - start,
|
||||
error: "No intelligence backend available",
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user