@@ -22,8 +22,8 @@ pub use remote::{
2222 RemoteSourceState , SecretValue , SkilldRemote , Sleeper , ThreadSleeper , TokenProvider ,
2323} ;
2424use skilld_core:: {
25- AGENT_TARGETS , AgentTargetId , DomainError , GlobalTargetPath , InstallMode , InstallRequest ,
26- InstallScope , InstallSource , LockedSource , VERSION , select_target_ids,
25+ AGENT_TARGETS , AgentTargetId , DomainError , GlobalTargetPath , InstallMode , InstallOperation ,
26+ InstallRequest , InstallScope , InstallSource , LockedSource , VERSION , select_target_ids,
2727} ;
2828
2929#[ derive( Debug , Parser ) ]
@@ -112,9 +112,11 @@ pub trait Host {
112112 "Agent target selection is unavailable on this host" ,
113113 ) ) ;
114114 }
115- let source = request
116- . source
117- . ok_or_else ( || CommandError :: unsupported_host ( "lockfile restore is unavailable" ) ) ?;
115+ let InstallOperation :: Install ( source) = request. operation else {
116+ return Err ( CommandError :: unsupported_host (
117+ "lockfile restore is unavailable" ,
118+ ) ) ;
119+ } ;
118120 self . install ( source, request. scope ) . map ( |name| vec ! [ name] )
119121 }
120122
@@ -345,19 +347,24 @@ fn dispatch<H: Host>(command: Command, host: &H) -> Result<Vec<String>, CommandE
345347 direct,
346348 } => {
347349 let scope = scope ( global) ;
348- let source = source
349- . map ( |source| InstallSource :: parse ( & source) )
350- . map ( |source| match ( direct, source) {
350+ let operation = match source {
351+ Some ( source) => match ( direct, InstallSource :: parse ( & source) ) {
351352 ( true , InstallSource :: Remote ( source) ) => {
352- Ok ( InstallSource :: DirectRemote ( source) )
353+ InstallOperation :: Install ( InstallSource :: DirectRemote ( source) )
353354 }
354- ( true , _) => Err ( CommandError :: input (
355- "--direct needs an explicit public GitHub Repository selector" ,
356- ) ) ,
357- ( false , source) => Ok ( source) ,
358- } )
359- . transpose ( ) ?;
360- if source == Some ( InstallSource :: BundledSkilld ) && scope != InstallScope :: Global {
355+ ( true , _) => {
356+ return Err ( CommandError :: input (
357+ "--direct needs an explicit public GitHub Repository selector" ,
358+ ) ) ;
359+ }
360+ ( false , source) => InstallOperation :: Install ( source) ,
361+ } ,
362+ None if direct => InstallOperation :: DirectRestore ,
363+ None => InstallOperation :: Restore ,
364+ } ;
365+ if operation == InstallOperation :: Install ( InstallSource :: BundledSkilld )
366+ && scope != InstallScope :: Global
367+ {
361368 return Err ( CommandError :: input (
362369 "install the skilld-maintained Skill with --global" ,
363370 ) ) ;
@@ -372,7 +379,7 @@ fn dispatch<H: Host>(command: Command, host: &H) -> Result<Vec<String>, CommandE
372379 . transpose ( )
373380 . map_err ( CommandError :: domain) ?;
374381 let names = host. install_request ( InstallRequest {
375- source ,
382+ operation ,
376383 scope,
377384 targets,
378385 mode,
@@ -749,8 +756,13 @@ impl LocalHost {
749756 Ok ( name. to_string ( ) )
750757 }
751758
752- fn restore ( & self , request : & InstallRequest ) -> Result < Vec < String > , CommandError > {
753- let ( targets, known) = self . select_installs ( request) ?;
759+ fn restore ( & self , request : & InstallRequest , direct : bool ) -> Result < Vec < String > , CommandError > {
760+ let ( targets, known) = if request. targets . is_empty ( ) {
761+ ( None , self . known_targets ( request. scope ) ?)
762+ } else {
763+ let ( targets, known) = self . select_installs ( request) ?;
764+ ( Some ( targets) , known)
765+ } ;
754766 let store = self . store ( request. scope ) ;
755767 let names = store. list ( & known) . map_err ( CommandError :: store) ?;
756768 if names. is_empty ( ) {
@@ -769,24 +781,46 @@ impl LocalHost {
769781 let view = store
770782 . view ( & skill_name, & known)
771783 . map_err ( CommandError :: store) ?;
772- let restored_targets = targets
773- . iter ( )
774- . map ( |target| {
775- let mode = if request. mode . is_some ( ) {
776- target. mode
777- } else {
778- view. skill
779- . targets
784+ let restored_targets = if let Some ( targets) = & targets {
785+ targets
786+ . iter ( )
787+ . map ( |target| {
788+ let mode = if request. mode . is_some ( ) {
789+ target. mode
790+ } else {
791+ view. skill
792+ . targets
793+ . iter ( )
794+ . find ( |locked| locked. agent == target. target . agent )
795+ . map_or ( target. mode , |locked| locked. mode )
796+ } ;
797+ TargetInstall {
798+ target : target. target . clone ( ) ,
799+ mode,
800+ }
801+ } )
802+ . collect :: < Vec < _ > > ( )
803+ } else {
804+ view. skill
805+ . targets
806+ . iter ( )
807+ . map ( |locked| {
808+ known
780809 . iter ( )
781- . find ( |locked| locked. agent == target. target . agent )
782- . map_or ( target. mode , |locked| locked. mode )
783- } ;
784- TargetInstall {
785- target : target. target . clone ( ) ,
786- mode,
787- }
788- } )
789- . collect :: < Vec < _ > > ( ) ;
810+ . find ( |target| target. agent == locked. agent )
811+ . cloned ( )
812+ . map ( |target| TargetInstall {
813+ target,
814+ mode : request. mode . unwrap_or ( locked. mode ) ,
815+ } )
816+ . ok_or_else ( || {
817+ CommandError :: domain ( DomainError :: InvalidTarget (
818+ locked. agent . to_string ( ) ,
819+ ) )
820+ } )
821+ } )
822+ . collect :: < Result < Vec < _ > , _ > > ( ) ?
823+ } ;
790824 match view. skill . source {
791825 LockedSource :: Local { path } => {
792826 let ( source, locked_source) =
@@ -805,17 +839,18 @@ impl LocalHost {
805839 LockedSource :: Remote {
806840 source, commit_sha, ..
807841 } => {
808- if !matches ! (
809- view. skill. source_status,
810- skilld_core:: SourceStatus :: Verified { .. }
811- ) {
812- return Err ( CommandError {
813- code : "UNVERIFIED_SOURCE" ,
814- message :
815- "restore an unverified Skill with an explicit --direct install"
816- . to_owned ( ) ,
817- } ) ;
818- }
842+ let direct = match view. skill . source_status {
843+ skilld_core:: SourceStatus :: Verified { .. } => false ,
844+ skilld_core:: SourceStatus :: Unverified { .. } if direct => true ,
845+ _ => {
846+ return Err ( CommandError {
847+ code : "UNVERIFIED_SOURCE" ,
848+ message :
849+ "run skilld install --direct to restore an unverified Skill"
850+ . to_owned ( ) ,
851+ } ) ;
852+ }
853+ } ;
819854 let selector = skilld_core:: RemoteSelector :: parse ( & source)
820855 . map_err ( CommandError :: remote) ?;
821856 let mut exact_source = selector. source ( ) . clone ( ) ;
@@ -830,7 +865,7 @@ impl LocalHost {
830865 } ;
831866 let prepared = self
832867 . remote_provider ( ) ?
833- . prepare ( & exact, false )
868+ . prepare ( & exact, direct )
834869 . map_err ( CommandError :: remote) ?;
835870 let staged = materialize_remote ( & prepared. files ) ?;
836871 store
@@ -858,7 +893,7 @@ impl Host for LocalHost {
858893
859894 fn install ( & self , source : InstallSource , scope : InstallScope ) -> Result < String , CommandError > {
860895 self . install_request ( InstallRequest {
861- source : Some ( source) ,
896+ operation : InstallOperation :: Install ( source) ,
862897 scope,
863898 targets : vec ! [ ] ,
864899 mode : None ,
@@ -869,8 +904,10 @@ impl Host for LocalHost {
869904 }
870905
871906 fn install_request ( & self , request : InstallRequest ) -> Result < Vec < String > , CommandError > {
872- let Some ( source) = request. source . clone ( ) else {
873- return self . restore ( & request) ;
907+ let source = match request. operation . clone ( ) {
908+ InstallOperation :: Restore => return self . restore ( & request, false ) ,
909+ InstallOperation :: DirectRestore => return self . restore ( & request, true ) ,
910+ InstallOperation :: Install ( source) => source,
874911 } ;
875912 let ( targets, known) = self . select_installs ( & request) ?;
876913 match source {
@@ -1291,7 +1328,10 @@ mod tests {
12911328 }
12921329
12931330 fn install_request ( & self , request : InstallRequest ) -> Result < Vec < String > , CommandError > {
1294- assert_eq ! ( request. source, Some ( InstallSource :: BundledSkilld ) ) ;
1331+ assert_eq ! (
1332+ request. operation,
1333+ InstallOperation :: Install ( InstallSource :: BundledSkilld )
1334+ ) ;
12951335 assert_eq ! ( request. scope, InstallScope :: Global ) ;
12961336 assert_eq ! ( request. targets, [ AgentTargetId :: Codex ] ) ;
12971337 Ok ( vec ! [ "skilld" . to_owned( ) ] )
0 commit comments