@@ -186,6 +186,49 @@ async function readRefsDir(root: string, relDir: string): Promise<RefFile[]> {
186186 return refs ;
187187}
188188
189+ // ── OpenSpec integration ──
190+
191+ /** Read OpenSpec context if openspec/ exists. Returns null if not present. */
192+ export async function readOpenSpecContext ( root : string ) : Promise < string | null > {
193+ const openspecDir = path . join ( root , "openspec" ) ;
194+ try {
195+ await readdir ( openspecDir ) ;
196+ } catch {
197+ return null ;
198+ }
199+
200+ const parts : string [ ] = [ ] ;
201+
202+ // Read project.md (global context)
203+ try {
204+ const projectMd = await readFile ( path . join ( openspecDir , "project.md" ) , "utf8" ) ;
205+ parts . push ( "### Project Context\n\n" + projectMd ) ;
206+ } catch {
207+ // no project.md
208+ }
209+
210+ // Read all specs/*/spec.md (behavioral requirements)
211+ const specsDir = path . join ( openspecDir , "specs" ) ;
212+ let capabilities : string [ ] ;
213+ try {
214+ capabilities = await readdir ( specsDir ) ;
215+ } catch {
216+ capabilities = [ ] ;
217+ }
218+
219+ for ( const cap of capabilities . toSorted ( ) ) {
220+ try {
221+ const specPath = path . join ( specsDir , cap , "spec.md" ) ;
222+ const content = await readFile ( specPath , "utf8" ) ;
223+ parts . push ( `### ${ cap } \n\n${ content } ` ) ;
224+ } catch {
225+ // skip non-directories or missing spec.md
226+ }
227+ }
228+
229+ return parts . length > 0 ? parts . join ( "\n\n---\n\n" ) : null ;
230+ }
231+
189232// ── Docs ──
190233
191234/** 读取节点的模块化文档 nodes/<nodeId>/docs.md,不存在返回 null */
0 commit comments