feat: implement CI (Continuous Intelligence) autonomous engineering harness
Implements the full PRD for CI - a fully autonomous AI-driven software engineering harness derived from Learnship's architecture. Core components: - CI Orchestrator agent with autonomous pipeline (SPECIFY → CLARIFY → RESEARCH → PLAN → EXECUTE → VERIFY → COMPLETE) - Decision Engine with confidence thresholds (high/medium/low) - Clarify Phase with question budget and default acceptance - Escalation Protocol with timeout auto-proceed - Audit Trail system (.ci/audit/) for post-hoc review - Error Recovery with retry, plan revision, and rollback 18 agents (all Learnship agents + Orchestrator): - Autonomous behavioral modifications per PRD §7.1 - Agent registry with factory pattern 11 CLI commands: - ci init, ci run, ci quick, ci debug, ci verify - ci review, ci status, ci audit, ci clarify - ci rollback, ci ship 4-layer verification system: - Structural, Behavioral, Security, Code Quality 3 autonomy levels: full, supervised, guided Compatible with Learnship artifact schemas (.planning/)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
export interface ClarifyQuestion {
|
||||
id: string;
|
||||
question: string;
|
||||
context: string;
|
||||
default_answer: string;
|
||||
rationale: string;
|
||||
impact: "critical" | "high" | "medium" | "low";
|
||||
category: string;
|
||||
answered: boolean;
|
||||
answer?: string;
|
||||
agent_interpretation?: string;
|
||||
}
|
||||
|
||||
export interface ClarifyResult {
|
||||
questions: ClarifyQuestion[];
|
||||
total_questions: number;
|
||||
answered_questions: number;
|
||||
unanswered_defaults_accepted: number;
|
||||
completed_at: string;
|
||||
}
|
||||
|
||||
export function createClarifyQuestion(
|
||||
params: Omit<ClarifyQuestion, "id" | "answered">
|
||||
): ClarifyQuestion {
|
||||
return {
|
||||
...params,
|
||||
id: `Q-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
answered: false,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
export type AutonomyLevel = "full" | "supervised" | "guided";
|
||||
|
||||
export type ModelProfile = "quality" | "speed" | "balanced";
|
||||
|
||||
export type BranchingStrategy = "phase" | "feature" | "trunk";
|
||||
|
||||
export type PhaseName = "research" | "plan" | "execute" | "verify" | "complete";
|
||||
|
||||
export type AgentName =
|
||||
| "orchestrator"
|
||||
| "planner"
|
||||
| "executor"
|
||||
| "verifier"
|
||||
| "researcher"
|
||||
| "phase-researcher"
|
||||
| "challenger"
|
||||
| "security-auditor"
|
||||
| "debugger"
|
||||
| "doc-writer"
|
||||
| "doc-verifier"
|
||||
| "code-reviewer"
|
||||
| "ideation-agent"
|
||||
| "roadmapper"
|
||||
| "plan-checker"
|
||||
| "project-researcher"
|
||||
| "research-synthesizer"
|
||||
| "solution-writer";
|
||||
|
||||
export interface AutonomyConfig {
|
||||
level: AutonomyLevel;
|
||||
escalation_hooks: string[];
|
||||
clarify_budget: number;
|
||||
decision_confidence_threshold: number;
|
||||
max_revision_iterations: number;
|
||||
max_verification_retries: number;
|
||||
escalation_timeout_ms: number;
|
||||
}
|
||||
|
||||
export interface ParallelizationConfig {
|
||||
enabled: boolean;
|
||||
max_concurrent_agents: number;
|
||||
min_plans_for_parallel: number;
|
||||
}
|
||||
|
||||
export interface VerificationConfig {
|
||||
automated_only: boolean;
|
||||
escalate_visual: boolean;
|
||||
escalate_external_integration: boolean;
|
||||
test_first: boolean;
|
||||
}
|
||||
|
||||
export interface SecurityConfig {
|
||||
auto_accept_low_severity: boolean;
|
||||
auto_mitigate_medium_severity: boolean;
|
||||
escalate_high_severity: boolean;
|
||||
}
|
||||
|
||||
export interface GitConfig {
|
||||
branching_strategy: BranchingStrategy;
|
||||
auto_commit: boolean;
|
||||
auto_push: boolean;
|
||||
}
|
||||
|
||||
export interface CIConfig {
|
||||
autonomy: AutonomyConfig;
|
||||
model_profile: ModelProfile;
|
||||
parallelization: ParallelizationConfig;
|
||||
verification: VerificationConfig;
|
||||
security: SecurityConfig;
|
||||
git: GitConfig;
|
||||
}
|
||||
|
||||
export const DEFAULT_CI_CONFIG: CIConfig = {
|
||||
autonomy: {
|
||||
level: "full",
|
||||
escalation_hooks: ["deploy", "delete_data", "merge_to_main"],
|
||||
clarify_budget: 10,
|
||||
decision_confidence_threshold: 0.6,
|
||||
max_revision_iterations: 3,
|
||||
max_verification_retries: 2,
|
||||
escalation_timeout_ms: 300000,
|
||||
},
|
||||
model_profile: "quality",
|
||||
parallelization: {
|
||||
enabled: true,
|
||||
max_concurrent_agents: 5,
|
||||
min_plans_for_parallel: 2,
|
||||
},
|
||||
verification: {
|
||||
automated_only: true,
|
||||
escalate_visual: true,
|
||||
escalate_external_integration: true,
|
||||
test_first: false,
|
||||
},
|
||||
security: {
|
||||
auto_accept_low_severity: true,
|
||||
auto_mitigate_medium_severity: true,
|
||||
escalate_high_severity: true,
|
||||
},
|
||||
git: {
|
||||
branching_strategy: "phase",
|
||||
auto_commit: true,
|
||||
auto_push: false,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
export type ConfidenceLevel = "high" | "medium" | "low";
|
||||
|
||||
export type DecisionCategory =
|
||||
| "implementation_approach"
|
||||
| "technology_choice"
|
||||
| "architecture"
|
||||
| "scope"
|
||||
| "verification"
|
||||
| "security"
|
||||
| "deployment"
|
||||
| "general";
|
||||
|
||||
export interface Decision {
|
||||
id: string;
|
||||
timestamp: string;
|
||||
decision: string;
|
||||
rationale: string;
|
||||
confidence: number;
|
||||
category: DecisionCategory;
|
||||
alternatives_considered: Alternative[];
|
||||
learnship_equivalent: string;
|
||||
human_override: string | null;
|
||||
phase?: string;
|
||||
task?: string;
|
||||
}
|
||||
|
||||
export interface Alternative {
|
||||
option: string;
|
||||
rejected_reason: string;
|
||||
}
|
||||
|
||||
export function confidenceToLevel(confidence: number): ConfidenceLevel {
|
||||
if (confidence > 0.85) return "high";
|
||||
if (confidence >= 0.6) return "medium";
|
||||
return "low";
|
||||
}
|
||||
|
||||
export function shouldEscalate(
|
||||
confidence: number,
|
||||
threshold: number
|
||||
): boolean {
|
||||
return confidence < threshold;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
export type EscalationType =
|
||||
| "irreversible_action"
|
||||
| "verification_failure"
|
||||
| "low_confidence_decision"
|
||||
| "security_escalation"
|
||||
| "specification_ambiguity";
|
||||
|
||||
export type EscalationResolution =
|
||||
| "approved"
|
||||
| "rejected"
|
||||
| "modified"
|
||||
| "pending"
|
||||
| "timeout_auto_proceed";
|
||||
|
||||
export interface EscalationOption {
|
||||
id: string;
|
||||
label: string;
|
||||
description: string;
|
||||
recommended: boolean;
|
||||
}
|
||||
|
||||
export interface Escalation {
|
||||
id: string;
|
||||
timestamp: string;
|
||||
type: EscalationType;
|
||||
phase: string;
|
||||
plan?: string;
|
||||
task?: string;
|
||||
description: string;
|
||||
context: string;
|
||||
options: EscalationOption[];
|
||||
default_option_id: string;
|
||||
resolution: EscalationResolution;
|
||||
resolved_at?: string;
|
||||
resolution_detail?: string;
|
||||
audit_file: string;
|
||||
}
|
||||
|
||||
export interface EscalationResult {
|
||||
escalation: Escalation;
|
||||
chosen_option_id: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export const ESCALATION_TYPES: Record<EscalationType, string> = {
|
||||
irreversible_action: "Irreversible Action",
|
||||
verification_failure: "Verification Failure",
|
||||
low_confidence_decision: "Low Confidence Decision",
|
||||
security_escalation: "Security Escalation",
|
||||
specification_ambiguity: "Specification Ambiguity",
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./config.js";
|
||||
export * from "./decisions.js";
|
||||
export * from "./escalation.js";
|
||||
export * from "./pipeline.js";
|
||||
export * from "./clarify.js";
|
||||
export * from "./specification.js";
|
||||
@@ -0,0 +1,92 @@
|
||||
import { AgentName, PhaseName } from "./config.js";
|
||||
|
||||
export type PipelineStage =
|
||||
| "specify"
|
||||
| "clarify"
|
||||
| "research"
|
||||
| "plan"
|
||||
| "execute"
|
||||
| "verify"
|
||||
| "complete";
|
||||
|
||||
export interface PipelineState {
|
||||
project_path: string;
|
||||
current_stage: PipelineStage;
|
||||
current_phase: number;
|
||||
phases_completed: number[];
|
||||
specification_loaded: boolean;
|
||||
clarify_completed: boolean;
|
||||
research_completed: boolean;
|
||||
plan_completed: boolean;
|
||||
execute_completed: boolean;
|
||||
verify_completed: boolean;
|
||||
errors: PipelineError[];
|
||||
started_at: string;
|
||||
last_updated: string;
|
||||
}
|
||||
|
||||
export interface PipelineError {
|
||||
stage: PipelineStage;
|
||||
phase: number;
|
||||
message: string;
|
||||
timestamp: string;
|
||||
retry_count: number;
|
||||
resolved: boolean;
|
||||
}
|
||||
|
||||
export interface PhaseResult {
|
||||
phase: number;
|
||||
stage: PipelineStage;
|
||||
success: boolean;
|
||||
artifacts_created: string[];
|
||||
decisions_made: number;
|
||||
escalations_raised: number;
|
||||
duration_ms: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface OrchestratorResult {
|
||||
success: boolean;
|
||||
pipeline_state: PipelineState;
|
||||
phase_results: PhaseResult[];
|
||||
total_decisions: number;
|
||||
total_escalations: number;
|
||||
total_duration_ms: number;
|
||||
completion_report: string;
|
||||
}
|
||||
|
||||
export const STAGE_ORDER: PipelineStage[] = [
|
||||
"specify",
|
||||
"clarify",
|
||||
"research",
|
||||
"plan",
|
||||
"execute",
|
||||
"verify",
|
||||
"complete",
|
||||
];
|
||||
|
||||
export function getNextStage(current: PipelineStage): PipelineStage | null {
|
||||
const idx = STAGE_ORDER.indexOf(current);
|
||||
if (idx < 0 || idx >= STAGE_ORDER.length - 1) return null;
|
||||
return STAGE_ORDER[idx + 1];
|
||||
}
|
||||
|
||||
export function createInitialPipelineState(
|
||||
project_path: string
|
||||
): PipelineState {
|
||||
return {
|
||||
project_path,
|
||||
current_stage: "specify",
|
||||
current_phase: 0,
|
||||
phases_completed: [],
|
||||
specification_loaded: false,
|
||||
clarify_completed: false,
|
||||
research_completed: false,
|
||||
plan_completed: false,
|
||||
execute_completed: false,
|
||||
verify_completed: false,
|
||||
errors: [],
|
||||
started_at: new Date().toISOString(),
|
||||
last_updated: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export interface Specification {
|
||||
title: string;
|
||||
objective: string;
|
||||
requirements: string[];
|
||||
constraints: string[];
|
||||
out_of_scope: string[];
|
||||
raw_content: string;
|
||||
source: "inline" | "file" | "clarify";
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export function parseSpecification(content: string, source: "inline" | "file" | "clarify" = "inline"): Specification {
|
||||
const lines = content.split("\n");
|
||||
let title = "";
|
||||
let objective = "";
|
||||
const requirements: string[] = [];
|
||||
const constraints: string[] = [];
|
||||
const outOfScope: string[] = [];
|
||||
|
||||
let currentSection: "objective" | "requirements" | "constraints" | "out_of_scope" | null = null;
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith("# ")) {
|
||||
if (!title) title = trimmed.slice(2);
|
||||
} else if (trimmed.startsWith("## Objective")) {
|
||||
currentSection = "objective";
|
||||
} else if (trimmed.startsWith("## Requirements")) {
|
||||
currentSection = "requirements";
|
||||
} else if (trimmed.startsWith("## Constraints")) {
|
||||
currentSection = "constraints";
|
||||
} else if (trimmed.startsWith("## Out of Scope")) {
|
||||
currentSection = "out_of_scope";
|
||||
} else if (trimmed.startsWith("- ") && currentSection) {
|
||||
const item = trimmed.slice(2);
|
||||
if (currentSection === "objective") objective = (objective ? objective + " " : "") + item;
|
||||
else if (currentSection === "requirements") requirements.push(item);
|
||||
else if (currentSection === "constraints") constraints.push(item);
|
||||
else if (currentSection === "out_of_scope") outOfScope.push(item);
|
||||
} else if (trimmed && currentSection === "objective") {
|
||||
objective = (objective ? objective + " " : "") + trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
if (!title) title = "Untitled Project";
|
||||
if (!objective) objective = content.slice(0, 200);
|
||||
|
||||
return {
|
||||
title,
|
||||
objective,
|
||||
requirements,
|
||||
constraints,
|
||||
out_of_scope: outOfScope,
|
||||
raw_content: content,
|
||||
source,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user