@@ -54,6 +54,16 @@ type State = {
5454 dirs : Set < string >
5555}
5656
57+ type DiscoveryState = {
58+ matches : string [ ]
59+ dirs : string [ ]
60+ }
61+
62+ type ScanState = {
63+ matches : Set < string >
64+ dirs : Set < string >
65+ }
66+
5767export interface Interface {
5868 readonly get : ( name : string ) => Effect . Effect < Info | undefined >
5969 readonly all : ( ) => Effect . Effect < Info [ ] >
@@ -102,8 +112,7 @@ const add = Effect.fnUntraced(function* (state: State, match: string, bus: Bus.I
102112} )
103113
104114const scan = Effect . fnUntraced ( function * (
105- state : State ,
106- bus : Bus . Interface ,
115+ state : ScanState ,
107116 root : string ,
108117 pattern : string ,
109118 opts ?: { dot ?: boolean ; scope ?: string } ,
@@ -126,40 +135,40 @@ const scan = Effect.fnUntraced(function* (
126135 } ) ,
127136 )
128137
129- yield * Effect . forEach ( matches , ( match ) => add ( state , match , bus ) , {
130- concurrency : "unbounded" ,
131- discard : true ,
132- } )
138+ for ( const match of matches ) {
139+ state . matches . add ( match )
140+ state . dirs . add ( path . dirname ( match ) )
141+ }
133142} )
134143
135- const loadSkills = Effect . fnUntraced ( function * (
136- state : State ,
144+ const discoverSkills = Effect . fnUntraced ( function * (
137145 config : Config . Interface ,
138146 discovery : Discovery . Interface ,
139- bus : Bus . Interface ,
140147 fsys : AppFileSystem . Interface ,
141148 directory : string ,
142149 worktree : string ,
143150) {
151+ const state : ScanState = { matches : new Set ( ) , dirs : new Set ( ) }
152+
144153 if ( ! Flag . OPENCODE_DISABLE_EXTERNAL_SKILLS ) {
145154 for ( const dir of EXTERNAL_DIRS ) {
146155 const root = path . join ( Global . Path . home , dir )
147156 if ( ! ( yield * fsys . isDir ( root ) ) ) continue
148- yield * scan ( state , bus , root , EXTERNAL_SKILL_PATTERN , { dot : true , scope : "global" } )
157+ yield * scan ( state , root , EXTERNAL_SKILL_PATTERN , { dot : true , scope : "global" } )
149158 }
150159
151160 const upDirs = yield * fsys
152161 . up ( { targets : EXTERNAL_DIRS , start : directory , stop : worktree } )
153162 . pipe ( Effect . catch ( ( ) => Effect . succeed ( [ ] as string [ ] ) ) )
154163
155164 for ( const root of upDirs ) {
156- yield * scan ( state , bus , root , EXTERNAL_SKILL_PATTERN , { dot : true , scope : "project" } )
165+ yield * scan ( state , root , EXTERNAL_SKILL_PATTERN , { dot : true , scope : "project" } )
157166 }
158167 }
159168
160169 const configDirs = yield * config . directories ( )
161170 for ( const dir of configDirs ) {
162- yield * scan ( state , bus , dir , OPENCODE_SKILL_PATTERN )
171+ yield * scan ( state , dir , OPENCODE_SKILL_PATTERN )
163172 }
164173
165174 const cfg = yield * config . get ( )
@@ -171,17 +180,28 @@ const loadSkills = Effect.fnUntraced(function* (
171180 continue
172181 }
173182
174- yield * scan ( state , bus , dir , SKILL_PATTERN )
183+ yield * scan ( state , dir , SKILL_PATTERN )
175184 }
176185
177186 for ( const url of cfg . skills ?. urls ?? [ ] ) {
178187 const pulledDirs = yield * discovery . pull ( url )
179188 for ( const dir of pulledDirs ) {
180- state . dirs . add ( dir )
181- yield * scan ( state , bus , dir , SKILL_PATTERN )
189+ yield * scan ( state , dir , SKILL_PATTERN )
182190 }
183191 }
184192
193+ return {
194+ matches : Array . from ( state . matches ) ,
195+ dirs : Array . from ( state . dirs ) ,
196+ }
197+ } )
198+
199+ const loadSkills = Effect . fnUntraced ( function * ( state : State , discovered : DiscoveryState , bus : Bus . Interface ) {
200+ yield * Effect . forEach ( discovered . matches , ( match ) => add ( state , match , bus ) , {
201+ concurrency : "unbounded" ,
202+ discard : true ,
203+ } )
204+
185205 log . info ( "init" , { count : Object . keys ( state . skills ) . length } )
186206} )
187207
@@ -194,10 +214,15 @@ export const layer = Layer.effect(
194214 const config = yield * Config . Service
195215 const bus = yield * Bus . Service
196216 const fsys = yield * AppFileSystem . Service
217+ const discovered = yield * InstanceState . make (
218+ Effect . fn ( "Skill.discovery" ) ( function * ( ctx ) {
219+ return yield * discoverSkills ( config , discovery , fsys , ctx . directory , ctx . worktree )
220+ } ) ,
221+ )
197222 const state = yield * InstanceState . make (
198223 Effect . fn ( "Skill.state" ) ( function * ( ctx ) {
199224 const s : State = { skills : { } , dirs : new Set ( ) }
200- yield * loadSkills ( s , config , discovery , bus , fsys , ctx . directory , ctx . worktree )
225+ yield * loadSkills ( s , yield * InstanceState . get ( discovered ) , bus )
201226 return s
202227 } ) ,
203228 )
@@ -213,8 +238,7 @@ export const layer = Layer.effect(
213238 } )
214239
215240 const dirs = Effect . fn ( "Skill.dirs" ) ( function * ( ) {
216- const s = yield * InstanceState . get ( state )
217- return Array . from ( s . dirs )
241+ return ( yield * InstanceState . get ( discovered ) ) . dirs
218242 } )
219243
220244 const available = Effect . fn ( "Skill.available" ) ( function * ( agent ?: Agent . Info ) {
0 commit comments