@@ -7,6 +7,7 @@ import { readSourceCatalogFile } from "./workspace/source-catalog.js";
77import { runWalnutBootstrapCli } from "./providers/walnut/cli.js" ;
88import { runArtifactProviderCli } from "./artifacts/registry/artifact-provider-cli.js" ;
99import { createBundledAgentCustomizationCollector } from "./customization-collector.js" ;
10+ import { loadArtifactProviderModules } from "./artifacts/registry/artifact-provider-modules.js" ;
1011
1112const HELP = `harness-studio — local studio for harness runs and compare evidence
1213
@@ -39,6 +40,9 @@ Options:
3940 Prebuilt Canvas SDK media directory
4041 --provider-state <dir>
4142 Studio-private external provider activation state
43+ --artifact-provider-module <specifier>
44+ Repeatable operator-provisioned module exporting
45+ createArtifactProvider() (executes trusted local code)
4246 --walnut-cache <dir> Studio-owned Walnut cache root
4347 --source-catalog <file>
4448 JSON catalog of bounded switchable Studio inputs
@@ -99,6 +103,7 @@ interface ParsedArgs {
99103 canvasSdkRoot ?: string ;
100104 canvasSdkMedia ?: string ;
101105 providerState ?: string ;
106+ artifactProviderModules : string [ ] ;
102107 walnutCache ?: string ;
103108 sourceCatalog ?: string ;
104109 port : number ;
@@ -111,7 +116,14 @@ interface ParsedArgs {
111116}
112117
113118export function parseHarnessStudioArgs ( argv : string [ ] ) : ParsedArgs {
114- const parsed : ParsedArgs = { port : 3311 , host : "127.0.0.1" , allowRemote : false , help : false , acpArgs : [ ] } ;
119+ const parsed : ParsedArgs = {
120+ port : 3311 ,
121+ host : "127.0.0.1" ,
122+ allowRemote : false ,
123+ help : false ,
124+ acpArgs : [ ] ,
125+ artifactProviderModules : [ ] ,
126+ } ;
115127 for ( let index = 0 ; index < argv . length ; index += 1 ) {
116128 const arg = argv [ index ] ;
117129 const takeValue = ( ) : string | undefined = > {
@@ -176,6 +188,12 @@ export function parseHarnessStudioArgs(argv: string[]): ParsedArgs {
176188 case "--provider-state" :
177189 parsed . providerState = takeValue ( ) ;
178190 break ;
191+ case "--artifact-provider-module" : {
192+ const value = takeValue ( ) ;
193+ if ( value === undefined ) parsed . error = "--artifact-provider-module requires a package name or filesystem path." ;
194+ else parsed . artifactProviderModules . push ( value ) ;
195+ break ;
196+ }
179197 case "--walnut-cache" :
180198 parsed . walnutCache = takeValue ( ) ;
181199 break ;
@@ -243,6 +261,16 @@ export async function runHarnessStudioCli(argv: string[], io: HarnessStudioCliIo
243261 // Skills are conventionally declared relative to their `.harness` file (see
244262 // examples/*.harness), so loading one without a flag still delivers them.
245263 const sourceRoot = resolveHarnessStudioSourceRoot ( parsed . harness , parsed . sourceRoot ) ;
264+ let artifactProviders ;
265+ try {
266+ artifactProviders = await loadArtifactProviderModules (
267+ parsed . artifactProviderModules ,
268+ resolve ( parsed . cwd ?? process . cwd ( ) ) ,
269+ ) ;
270+ } catch ( error ) {
271+ io . stderr ( `${ error instanceof Error ? error . message : String ( error ) } \n` ) ;
272+ return 2 ;
273+ }
246274 const started = await startHarnessStudioServer ( {
247275 appDir : defaultAppDir ( ) ,
248276 port : parsed . port ,
@@ -269,6 +297,7 @@ export async function runHarnessStudioCli(argv: string[], io: HarnessStudioCliIo
269297 ...( parsed . canvasSdkRoot !== undefined ? { canvasSdkRoot : resolve ( parsed . canvasSdkRoot ) } : { } ) ,
270298 ...( parsed . canvasSdkMedia !== undefined ? { canvasSdkMedia : resolve ( parsed . canvasSdkMedia ) } : { } ) ,
271299 ...( parsed . providerState !== undefined ? { artifactProviderStateRoot : resolve ( parsed . providerState ) } : { } ) ,
300+ ...( artifactProviders . length > 0 ? { artifactProviders } : { } ) ,
272301 ...( parsed . walnutCache !== undefined ? { walnutCacheRoot : resolve ( parsed . walnutCache ) } : { } ) ,
273302 ...( sourceCatalog . length > 0 ? { sourceCatalog } : { } ) ,
274303 ...( parsed . cwd !== undefined ? { cwd : parsed . cwd } : { } ) ,
0 commit comments