@@ -29,11 +29,59 @@ import { defaultOrchestrator } from "../../frameworks/framework.registry.js";
2929import { guessedRootNotice , resolveRoot } from "../../core/helpers/resolve-root.helper.js" ;
3030import type { IProjectContext } from "../../contracts/interfaces/core/project-context.interface.js" ;
3131import type { IScanOutcome } from "../../contracts/interfaces/cli/scan-outcome.interface.js" ;
32+ import { hasFlag } from "../../core/helpers/argv.helper.js" ;
33+ import { StableIdService } from "../../core/state/stable-id.service.js" ;
34+ import { ShadowStateWriterService , type IShadowWriteDiagnostic } from "../../core/state/shadow-state-writer.service.js" ;
35+
36+ export interface IScanOptions {
37+ readonly shadow ?: boolean ;
38+ readonly stateDatabasePath ?: string ;
39+ }
40+
41+ async function writeShadowSnapshot ( root : string , framework : string , routes : ReadonlyArray < { method : string ; uri : string } > , path ?: string ) : Promise < IShadowWriteDiagnostic > {
42+ const [ { SnapshotTransactionService } , { SqliteProjectRepository } , { SqliteSnapshotRepository } , { openStateDatabase } ] = await Promise . all ( [
43+ import ( "../../core/state/snapshot-transaction.service.js" ) ,
44+ import ( "../../core/state/sqlite/sqlite-project.repository.js" ) ,
45+ import ( "../../core/state/sqlite/sqlite-snapshot.repository.js" ) ,
46+ import ( "../../core/state/sqlite/sqlite-connection.adapter.js" ) ,
47+ ] ) ;
48+ const ids = new StableIdService ( ) ;
49+ const capturedAt = new Date ( ) . toISOString ( ) ;
50+ const projectId = ids . project ( root ) ;
51+ const snapshot = {
52+ projectId,
53+ snapshotId : ids . snapshot ( `${ root } \0${ capturedAt } ` ) ,
54+ status : "building" as const ,
55+ revision : Date . now ( ) ,
56+ capturedAt,
57+ diagnostics : [ ] ,
58+ metadata : { framework, routeCount : routes . length } ,
59+ services : [ {
60+ serviceId : ids . service ( `${ root } \0${ framework } ` ) ,
61+ name : framework ,
62+ operations : routes . map ( ( route ) => ( {
63+ operationId : ids . operation ( `${ framework } \0${ route . method } \0${ route . uri } ` ) ,
64+ method : route . method ,
65+ path : route . uri ,
66+ } ) ) ,
67+ } ] ,
68+ } ;
69+ const connection = openStateDatabase ( path ) ;
70+ try {
71+ const snapshots = new SqliteSnapshotRepository ( connection . database as never ) ;
72+ const projects = new SqliteProjectRepository ( connection . database as never ) ;
73+ const transactions = new SnapshotTransactionService ( connection . database as never , snapshots ) ;
74+ return new ShadowStateWriterService ( transactions , projects ) . write ( snapshot , root , true ) ;
75+ } finally {
76+ connection . close ( ) ;
77+ }
78+ }
3279
3380/** Scans the project and returns what was found, printing it along the way. */
3481export async function runScan (
3582 argv : string [ ] = process . argv . slice ( 2 ) ,
3683 context ?: IProjectContext ,
84+ options : IScanOptions = { } ,
3785) : Promise < IScanOutcome > {
3886 const root = context ?. projectRoot ?? resolveRoot ( { argv } ) . root ;
3987
@@ -85,6 +133,16 @@ export async function runScan(
85133 console . log ( ` ${ r . method . padEnd ( 6 ) } ${ r . uri } ${ tags } ${ desc } ` ) ;
86134 }
87135
136+ if ( options . shadow ?? hasFlag ( argv , "--shadow" ) ) {
137+ try {
138+ const shadow = await writeShadowSnapshot ( root , match . framework , routes , options . stateDatabasePath ) ;
139+ if ( ! shadow . ok ) console . error ( `⚠ Shadow state write failed: ${ shadow . error } ` ) ;
140+ else console . log ( "✔ Shadow state snapshot persisted (legacy remains authoritative)" ) ;
141+ } catch ( error ) {
142+ console . error ( `⚠ Shadow state unavailable: ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
143+ }
144+ }
145+
88146 return {
89147 code : 0 ,
90148 root,
0 commit comments