@@ -8,13 +8,30 @@ import { parseModulefile, parseFlowList } from '../../tools/lib/parse-modulefile
88
99const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
1010const ROOT = resolve ( __dirname , '..' , '..' ) ;
11- const MODULES_DIR = join ( ROOT , '.opencode' , 'modules' ) ;
12- const INSTALLED_PATH = join ( MODULES_DIR , 'installed.json' ) ;
11+
12+ // Harness target: 'opencode' (default) or 'pi' (--pi flag)
13+ // Controls where module files are installed and where installed.json lives.
14+ let HARNESS = 'opencode' ;
15+ let MODULES_DIR = join ( ROOT , '.opencode' , 'modules' ) ;
16+ let INSTALLED_PATH = join ( MODULES_DIR , 'installed.json' ) ;
17+ let HARNESS_TARGET = '.opencode' ;
1318const OPENCODE_JSON = join ( ROOT , 'opencode.json' ) ;
1419
20+ function setHarness ( mode ) {
21+ HARNESS = mode ;
22+ if ( mode === 'pi' ) {
23+ MODULES_DIR = join ( ROOT , '.agents' , 'modules' ) ;
24+ HARNESS_TARGET = '.agents' ;
25+ } else {
26+ MODULES_DIR = join ( ROOT , '.opencode' , 'modules' ) ;
27+ HARNESS_TARGET = '.opencode' ;
28+ }
29+ INSTALLED_PATH = join ( MODULES_DIR , 'installed.json' ) ;
30+ }
31+
1532// ββ Logging ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1633
17- const LOG_PREFIXES = { ADD : 'ADD' , DEL : 'DEL' , SKIP : 'SKIP' , KEEP : 'KEEP' , WARN : 'WARN' , ERR : 'ERR' , OK : 'OK' } ;
34+ const LOG_PREFIXES = { ADD : 'ADD' , DEL : 'DEL' , SKIP : 'SKIP' , KEEP : 'KEEP' , WARN : 'WARN' , ERR : 'ERR' , OK : 'OK' , SAME : 'SAME' , UPDATE : 'UPDATE' } ;
1835
1936function log ( prefix , msg ) {
2037 const p = ( LOG_PREFIXES [ prefix ] || prefix ) . padEnd ( 5 ) ;
@@ -163,7 +180,7 @@ function cmdAdd(args) {
163180 continue ;
164181 }
165182
166- walkAndCopy ( entryPath , join ( ROOT , '.opencode' , entry ) , addedFiles , force ) ;
183+ walkAndCopy ( entryPath , join ( ROOT , HARNESS_TARGET , entry ) , addedFiles , force ) ;
167184 }
168185
169186 // Handle MCP fragments
@@ -178,6 +195,13 @@ function cmdAdd(args) {
178195 log ( 'WARN' , `MCP fragment '${ mcpFile } ' is not valid JSON β skipped` ) ;
179196 continue ;
180197 }
198+ // MCP fragments are only merged into opencode.json (OpenCode harness).
199+ // Pi harness manages MCP separately β skip with a warning.
200+ if ( HARNESS === 'pi' ) {
201+ log ( 'WARN' , `MCP fragment '${ mcpFile } ' β Pi harness does not merge MCP via installer (skipped)` ) ;
202+ summary . mcpSkipped ++ ;
203+ continue ;
204+ }
181205 const ocfg = readJSON ( OPENCODE_JSON ) || { } ;
182206 if ( ! ocfg . mcp ) ocfg . mcp = { } ;
183207 let merged = false ;
@@ -245,14 +269,14 @@ function walkAndCopy(srcDir, destDir, fileList, force = false) {
245269 copyFileSync ( srcPath , destPath ) ;
246270 log ( 'UPDATE' , `${ toForward ( relative ( MODULES_DIR , srcPath ) ) } β ${ toForward ( relative ( ROOT , destPath ) ) } ` ) ;
247271 }
248- fileList . push ( toForward ( relative ( join ( ROOT , '.opencode' ) , destPath ) ) ) ;
272+ fileList . push ( toForward ( relative ( join ( ROOT , HARNESS_TARGET ) , destPath ) ) ) ;
249273 } else {
250274 log ( 'SKIP' , `${ toForward ( relative ( MODULES_DIR , srcPath ) ) } β ${ toForward ( relative ( ROOT , destPath ) ) } ` ) ;
251275 }
252276 } else {
253277 copyFileSync ( srcPath , destPath ) ;
254278 log ( 'ADD' , `${ toForward ( relative ( MODULES_DIR , srcPath ) ) } β ${ toForward ( relative ( ROOT , destPath ) ) } ` ) ;
255- fileList . push ( toForward ( relative ( join ( ROOT , '.opencode' ) , destPath ) ) ) ;
279+ fileList . push ( toForward ( relative ( join ( ROOT , HARNESS_TARGET ) , destPath ) ) ) ;
256280 }
257281 }
258282 }
@@ -304,7 +328,7 @@ function cmdRemove(name) {
304328
305329 // Remove tracked files
306330 for ( const f of files ) {
307- const installedPath = join ( ROOT , '.opencode' , f ) ;
331+ const installedPath = join ( ROOT , HARNESS_TARGET , f ) ;
308332 const sourcePath = join ( MODULES_DIR , name , f ) ;
309333
310334 if ( ! existsSync ( installedPath ) ) {
@@ -332,8 +356,8 @@ function cmdRemove(name) {
332356 // Clean up empty parent directories
333357 const parentDirs = new Set ( ) ;
334358 for ( const f of files ) {
335- let dir = dirname ( join ( ROOT , '.opencode' , f ) ) ;
336- while ( dir . startsWith ( join ( ROOT , '.opencode' ) ) ) {
359+ let dir = dirname ( join ( ROOT , HARNESS_TARGET , f ) ) ;
360+ while ( dir . startsWith ( join ( ROOT , HARNESS_TARGET ) ) ) {
337361 parentDirs . add ( dir ) ;
338362 dir = dirname ( dir ) ;
339363 }
@@ -349,8 +373,8 @@ function cmdRemove(name) {
349373 } catch { /* skip */ }
350374 }
351375
352- // Remove MCP servers from opencode.json
353- if ( mcpServers . length > 0 ) {
376+ // Remove MCP servers from opencode.json (OpenCode-only)
377+ if ( mcpServers . length > 0 && HARNESS !== 'pi' ) {
354378 const ocfg = readJSON ( OPENCODE_JSON ) ;
355379 if ( ocfg && ocfg . mcp ) {
356380 for ( const serverName of mcpServers ) {
@@ -386,7 +410,7 @@ function runValidation() {
386410 return ;
387411 }
388412 log ( 'OK' , 'Running post-install validation...' ) ;
389- const result = spawnSync ( 'node' , [ validatePath ] , { cwd : ROOT , stdio : 'inherit' , shell : true } ) ;
413+ const result = spawnSync ( 'node' , [ validatePath ] , { cwd : ROOT , stdio : 'inherit' } ) ;
390414 if ( result . status !== 0 ) {
391415 log ( 'WARN' , `Validation exited with code ${ result . status } β fix issues if needed` ) ;
392416 } else {
@@ -398,12 +422,24 @@ function runValidation() {
398422
399423function main ( ) {
400424 const args = process . argv . slice ( 2 ) ;
425+
426+ // Parse --pi flag (can appear anywhere in args)
427+ const piIndex = args . indexOf ( '--pi' ) ;
428+ if ( piIndex !== - 1 ) {
429+ setHarness ( 'pi' ) ;
430+ args . splice ( piIndex , 1 ) ;
431+ }
432+
401433 if ( args . length === 0 ) {
434+ const scriptPath = HARNESS === 'pi' ? '.agents/modules/install.mjs' : '.opencode/modules/install.mjs' ;
402435 console . log ( 'Usage:' ) ;
403- console . log ( ' node .opencode/modules/install.mjs list' ) ;
404- console . log ( ' node .opencode/modules/install.mjs info <name>' ) ;
405- console . log ( ' node .opencode/modules/install.mjs add <name...>' ) ;
406- console . log ( ' node .opencode/modules/install.mjs remove <name>' ) ;
436+ console . log ( ` node ${ scriptPath } list [--pi]` ) ;
437+ console . log ( ` node ${ scriptPath } info <name> [--pi]` ) ;
438+ console . log ( ` node ${ scriptPath } add <name...> [--pi]` ) ;
439+ console . log ( ` node ${ scriptPath } remove <name> [--pi]` ) ;
440+ console . log ( '' ) ;
441+ console . log ( 'Options:' ) ;
442+ console . log ( ' --pi Install to .agents/ instead of .opencode/ (Pi harness)' ) ;
407443 process . exit ( 0 ) ;
408444 }
409445
0 commit comments