@@ -6,6 +6,7 @@ import { detectOpenCodeInstallations } from "./opencode-detect";
66import {
77 describeOpenCodeInstallations ,
88 getAvailableModels ,
9+ getOpenCodeCommandInvocation ,
910 getOpenCodeVersion ,
1011 OPENCODE_VERSION_PROBE_TIMEOUT_MS ,
1112} from "./opencode-helpers" ;
@@ -14,9 +15,15 @@ import {
1415// #196 follow-up: a stock CLI not on PATH must still enumerate). POSIX-only:
1516// the test writes an executable shell stub, which CI runs on Linux/macOS.
1617const isPosix = process . platform !== "win32" ;
18+ const originalComSpec = process . env . ComSpec ;
19+ const originalPathExpansionProbe = process . env . MC_OPENCODE_TEST_PATH ;
1720const tempDirs : string [ ] = [ ] ;
1821
1922afterEach ( ( ) => {
23+ if ( originalComSpec === undefined ) delete process . env . ComSpec ;
24+ else process . env . ComSpec = originalComSpec ;
25+ if ( originalPathExpansionProbe === undefined ) delete process . env . MC_OPENCODE_TEST_PATH ;
26+ else process . env . MC_OPENCODE_TEST_PATH = originalPathExpansionProbe ;
2027 for ( const dir of tempDirs . splice ( 0 ) ) rmSync ( dir , { recursive : true , force : true } ) ;
2128} ) ;
2229
@@ -39,6 +46,86 @@ function fakeHomeOpencode(body: string): { home: string; bin: string } {
3946 return { home, bin } ;
4047}
4148
49+ function fakeOpenCodeCommandShim ( ) : string {
50+ const dir = mkdtempSync ( join ( tmpdir ( ) , "mc %MC_OPENCODE_TEST_PATH% & shim " ) ) ;
51+ tempDirs . push ( dir ) ;
52+ const shim = join ( dir , "opencode.cmd" ) ;
53+
54+ if ( process . platform === "win32" ) {
55+ writeFileSync (
56+ shim ,
57+ [
58+ "@echo off" ,
59+ 'if "%~1"=="--version" (' ,
60+ " echo 1.18.7" ,
61+ ') else if "%~1"=="models" (' ,
62+ " echo anthropic/claude-opus-4-8" ,
63+ " echo openai/gpt-5.5" ,
64+ ")" ,
65+ ] . join ( "\r\n" ) ,
66+ ) ;
67+ } else {
68+ const comSpec = join ( dir , "fake-cmd" ) ;
69+ writeFileSync (
70+ comSpec ,
71+ '#!/bin/sh\ncase "$5" in\n *--version*) echo "1.18.7" ;;\n *models*) printf "anthropic/claude-opus-4-8\\nopenai/gpt-5.5\\n" ;;\nesac\n' ,
72+ ) ;
73+ chmodSync ( comSpec , 0o755 ) ;
74+ process . env . ComSpec = comSpec ;
75+ }
76+
77+ return shim ;
78+ }
79+
80+ describe ( "OpenCode command execution" , ( ) => {
81+ it ( "routes cmd and bat shims through ComSpec" , ( ) => {
82+ process . env . ComSpec = "custom-cmd.exe" ;
83+
84+ expect ( getOpenCodeCommandInvocation ( "C:\\npm\\opencode.CMD" , [ "--version" ] ) ) . toEqual ( {
85+ command : "custom-cmd.exe" ,
86+ args : [
87+ "/d" ,
88+ "/s" ,
89+ "/v:off" ,
90+ "/c" ,
91+ '""%MAGIC_CONTEXT_OPENCODE_BINARY%" "--version""' ,
92+ ] ,
93+ env : { MAGIC_CONTEXT_OPENCODE_BINARY : "C:\\npm\\opencode.CMD" } ,
94+ windowsVerbatimArguments : true ,
95+ } ) ;
96+ expect ( getOpenCodeCommandInvocation ( "C:\\npm\\opencode.bat" , [ "models" ] ) ) . toEqual ( {
97+ command : "custom-cmd.exe" ,
98+ args : [
99+ "/d" ,
100+ "/s" ,
101+ "/v:off" ,
102+ "/c" ,
103+ '""%MAGIC_CONTEXT_OPENCODE_BINARY%" "models""' ,
104+ ] ,
105+ env : { MAGIC_CONTEXT_OPENCODE_BINARY : "C:\\npm\\opencode.bat" } ,
106+ windowsVerbatimArguments : true ,
107+ } ) ;
108+ } ) ;
109+
110+ it ( "invokes native executables directly" , ( ) => {
111+ expect ( getOpenCodeCommandInvocation ( "/usr/local/bin/opencode" , [ "--version" ] ) ) . toEqual ( {
112+ command : "/usr/local/bin/opencode" ,
113+ args : [ "--version" ] ,
114+ } ) ;
115+ } ) ;
116+
117+ it ( "executes a cmd shim for version and model probes" , ( ) => {
118+ process . env . MC_OPENCODE_TEST_PATH = "expanded-to-the-wrong-path" ;
119+ const shim = fakeOpenCodeCommandShim ( ) ;
120+
121+ expect ( getOpenCodeVersion ( shim ) ) . toBe ( "1.18.7" ) ;
122+ expect ( getAvailableModels ( shim ) ) . toEqual ( [
123+ "anthropic/claude-opus-4-8" ,
124+ "openai/gpt-5.5" ,
125+ ] ) ;
126+ } ) ;
127+ } ) ;
128+
42129describe . if ( isPosix ) ( "opencode helpers with a resolved binary path" , ( ) => {
43130 it ( "getAvailableModels invokes the given absolute binary" , ( ) => {
44131 const bin = fakeOpencode (
0 commit comments