@@ -27,6 +27,7 @@ import { sleep } from "./error-handler.ts";
2727import type { ProviderRouter } from "../providers/router.ts" ;
2828import type { ToolRegistry } from "../tools/registry.ts" ;
2929import type { ToolContext } from "../tools/types.ts" ;
30+ import type { GenomeManifest } from "../genome/manifest.ts" ;
3031
3132/* ── Vision interface (inline until vision.ts exists) ──────────── */
3233
@@ -176,6 +177,7 @@ export class AutopilotLoop {
176177 private config ! : AutopilotConfig ;
177178 private lastScanHash = "" ;
178179 private focusState : FocusState = "unknown" ;
180+ private genome : GenomeManifest | null = null ;
179181
180182 /* ── Public API ────────────────────────────────────────────── */
181183
@@ -193,6 +195,14 @@ export class AutopilotLoop {
193195 this . queue = new WorkQueue ( config . toolContext . cwd ) ;
194196 await this . queue . load ( ) ;
195197
198+ // Load genome if available — enhances agent context and enables auto-evolution
199+ try {
200+ const { loadManifest } = await import ( "../genome/manifest.ts" ) ;
201+ this . genome = await loadManifest ( config . toolContext . cwd ) ;
202+ } catch {
203+ this . genome = null ;
204+ }
205+
196206 config . onProgress ?.( { type : "started" , goal : vision . goal } ) ;
197207
198208 await this . runLoop ( ) ;
@@ -263,13 +273,22 @@ export class AutopilotLoop {
263273 break ;
264274 }
265275
266- // Step 3: Re-assess vision (every 5 ticks)
276+ // Step 3: Re-assess vision (every 5 ticks) + genome evolution
267277 if ( this . tickNumber % 5 === 0 ) {
268278 const complete = await this . assessVision ( ) ;
269279 if ( complete ) {
280+ // If genome exists, end generation and advance before wrapping up
281+ if ( this . genome ) {
282+ await this . advanceGeneration ( ) ;
283+ }
270284 this . wrapUpRequested = true ;
271285 continue ; // Next iteration will handle wrap-up
272286 }
287+
288+ // Evaluate genome fitness periodically (every 10 ticks)
289+ if ( this . genome && this . tickNumber % 10 === 0 ) {
290+ await this . evaluateGenomeFitness ( ) ;
291+ }
273292 }
274293
275294 // Step 4: Scan for new work (every 3 ticks)
@@ -639,10 +658,27 @@ Reply with JSON only: {"focusAreas": ["..."], "assessment": "...", "isComplete":
639658 itemDescription : item . title ,
640659 } ) ;
641660
661+ // Build context with genome sections if available
662+ let genomeContext = "" ;
663+ if ( this . genome ) {
664+ try {
665+ const { retrieveSections, formatGenomeForPrompt } = await import ( "../genome/retriever.ts" ) ;
666+ const sections = await retrieveSections (
667+ this . config . toolContext . cwd ,
668+ `${ item . title } ${ item . description } ` ,
669+ 4000 ,
670+ ) ;
671+ genomeContext = formatGenomeForPrompt ( sections ) ;
672+ } catch {
673+ // Genome retrieval failed — continue without
674+ }
675+ }
676+
642677 const contextPrompt = [
643678 `## Vision` ,
644679 `Goal: ${ this . vision . goal } ` ,
645680 `Focus areas: ${ this . vision . focusAreas . join ( ", " ) || "none" } ` ,
681+ genomeContext ? `\n${ genomeContext } ` : "" ,
646682 `` ,
647683 `## Task` ,
648684 `${ item . title } : ${ item . description } ` ,
@@ -791,6 +827,23 @@ Reply with JSON only: {"focusAreas": ["..."], "assessment": "...", "isComplete":
791827 if ( this . vision . progress . length > 50 ) {
792828 this . vision . progress = this . vision . progress . slice ( - 50 ) ;
793829 }
830+
831+ // Propose genome progress update if genome exists
832+ if ( this . genome ) {
833+ try {
834+ const { proposeUpdate } = await import ( "../genome/scribe.ts" ) ;
835+ await proposeUpdate ( this . config . toolContext . cwd , {
836+ agentId : "autopilot" ,
837+ section : "knowledge/discoveries.md" ,
838+ operation : "append" ,
839+ content : `- [${ new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] } ] Tick ${ this . tickNumber } : ${ this . itemsCompleted } completed, ${ this . itemsFailed } failed` ,
840+ rationale : "Autopilot progress update" ,
841+ generation : this . genome . generation . number ,
842+ } ) ;
843+ } catch {
844+ // Genome proposal failed — not critical
845+ }
846+ }
794847 }
795848
796849 // Notify user if terminal unfocused
@@ -805,6 +858,64 @@ Reply with JSON only: {"focusAreas": ["..."], "assessment": "...", "isComplete":
805858 }
806859 }
807860
861+ /* ── Genome integration ──────────────────────────────────────── */
862+
863+ /**
864+ * Evaluate genome fitness and consolidate pending proposals.
865+ */
866+ private async evaluateGenomeFitness ( ) : Promise < void > {
867+ try {
868+ const { evaluateGeneration, formatGenerationReport } = await import ( "../genome/generations.ts" ) ;
869+ const { consolidateProposals } = await import ( "../genome/scribe.ts" ) ;
870+ const cwd = this . config . toolContext . cwd ;
871+
872+ // First consolidate any pending proposals
873+ await consolidateProposals ( cwd , this . config . router ) ;
874+
875+ // Then evaluate fitness
876+ const report = await evaluateGeneration ( cwd , this . config . router ) ;
877+
878+ this . config . onProgress ?.( {
879+ type : "notification" ,
880+ title : "Genome Fitness" ,
881+ body : `Gen ${ report . generation } : ${ ( report . fitness . milestoneProgress * 100 ) . toFixed ( 0 ) } % milestone, ${ report . mutations } mutations` ,
882+ } ) ;
883+ } catch {
884+ // Genome evaluation failed — not critical
885+ }
886+ }
887+
888+ /**
889+ * End the current generation and start the next one.
890+ */
891+ private async advanceGeneration ( ) : Promise < void > {
892+ try {
893+ const { endGeneration, startGeneration } = await import ( "../genome/generations.ts" ) ;
894+ const { loadManifest } = await import ( "../genome/manifest.ts" ) ;
895+ const { readSection } = await import ( "../genome/manifest.ts" ) ;
896+ const cwd = this . config . toolContext . cwd ;
897+
898+ await endGeneration ( cwd ) ;
899+
900+ // Check backlog for next milestone
901+ const backlog = await readSection ( cwd , "milestones/backlog.md" ) ;
902+ const nextMilestone = backlog
903+ ? extractFirstMilestone ( backlog )
904+ : "Continue development" ;
905+
906+ const genNum = await startGeneration ( cwd , nextMilestone ) ;
907+ this . genome = await loadManifest ( cwd ) ;
908+
909+ this . config . onProgress ?.( {
910+ type : "notification" ,
911+ title : "Generation Advanced" ,
912+ body : `Generation ${ genNum } : ${ nextMilestone } ` ,
913+ } ) ;
914+ } catch {
915+ // Generation advance failed — not critical
916+ }
917+ }
918+
808919 /* ── Step 10: Abortable sleep ──────────────────────────────── */
809920
810921 private async abortableSleep ( ms : number ) : Promise < void > {
@@ -833,3 +944,17 @@ export function createAutopilotLoop(): AutopilotLoop {
833944 _instance = new AutopilotLoop ( ) ;
834945 return _instance ;
835946}
947+
948+ /**
949+ * Extract the first milestone from a backlog markdown file.
950+ * Looks for the first ## heading or first bullet point.
951+ */
952+ function extractFirstMilestone ( backlog : string ) : string {
953+ for ( const line of backlog . split ( "\n" ) ) {
954+ const heading = line . match ( / ^ # # \s + ( .+ ) / ) ;
955+ if ( heading ) return heading [ 1 ] ! . trim ( ) ;
956+ const bullet = line . match ( / ^ [ - * ] \s + ( .+ ) / ) ;
957+ if ( bullet ) return bullet [ 1 ] ! . trim ( ) ;
958+ }
959+ return "Continue development" ;
960+ }
0 commit comments