@@ -154,6 +154,30 @@ describe("parseModelsCliOutput", () => {
154154 NodeAssert . equal ( model . id , "qwen/qwen3-coder" ) ;
155155 NodeAssert . equal ( model . providerID , "openrouter" ) ;
156156 } ) ;
157+
158+ it ( "strips OSC title escapes from model slugs (opencode CLI leak)" , ( ) => {
159+ const stdout = [
160+ "\x1b]0;t3code: ready\x07opencode/big-pickle" ,
161+ JSON . stringify ( { id : "big-pickle" , providerID : "opencode" , name : "Big Pickle" } ) ,
162+ "\x1b]0;tmp: ready\x07anthropic/claude-sonnet-4-5" ,
163+ JSON . stringify ( { id : "claude-sonnet-4-5" , providerID : "anthropic" , name : "Sonnet" } ) ,
164+ ] . join ( "\n" ) ;
165+
166+ const result = parseModelsCliOutput ( stdout ) ;
167+ NodeAssert . equal ( result . providers . size , 2 ) ;
168+ NodeAssert . ok ( result . providers . get ( "opencode" ) ! . models [ "big-pickle" ] ) ;
169+ NodeAssert . ok ( result . providers . get ( "anthropic" ) ! . models [ "claude-sonnet-4-5" ] ) ;
170+ } ) ;
171+
172+ it ( "strips ANSI escapes from model slugs" , ( ) => {
173+ const stdout = [
174+ "\x1b[33mopencode/gpt-5.4\x1b[0m" ,
175+ JSON . stringify ( { id : "gpt-5.4" , providerID : "opencode" , name : "GPT-5.4" } ) ,
176+ ] . join ( "\n" ) ;
177+
178+ const result = parseModelsCliOutput ( stdout ) ;
179+ NodeAssert . ok ( result . providers . get ( "opencode" ) ! . models [ "gpt-5.4" ] ) ;
180+ } ) ;
157181} ) ;
158182
159183describe ( "parseAgentListCliOutput" , ( ) => {
@@ -255,9 +279,47 @@ describe("parseAgentListCliOutput", () => {
255279 NodeAssert . equal ( result [ 0 ] ! . hidden , true ) ;
256280 NodeAssert . equal ( result [ 1 ] ! . hidden , false ) ;
257281 } ) ;
282+
283+ it ( "strips OSC title escapes leaked by opencode CLI" , ( ) => {
284+ // opencode <=1.18 writes `ESC ]0;<cwd>: ready BEL` to stdout for every
285+ // non-help command — even when stdout is a pipe. Without stripping, the
286+ // agent name becomes `ESC]0;...BELbuild` and later fails with
287+ // `Agent not found: "ESC]0;...build"`.
288+ const stdout = [
289+ "\x1b]0;t3code: ready\x07build (primary)" ,
290+ " " + JSON . stringify ( [ { permission : "*" , action : "allow" , pattern : "*" } ] ) ,
291+ "\x1b]0;tmp: ready\x07explore (subagent)" ,
292+ " " + JSON . stringify ( [ { permission : "read" , action : "allow" , pattern : "*" } ] ) ,
293+ ] . join ( "\n" ) ;
294+
295+ const result = parseAgentListCliOutput ( stdout ) ;
296+ NodeAssert . equal ( result . length , 2 ) ;
297+ NodeAssert . equal ( result [ 0 ] ! . name , "build" ) ;
298+ NodeAssert . equal ( result [ 0 ] ! . mode , "primary" ) ;
299+ NodeAssert . equal ( result [ 1 ] ! . name , "explore" ) ;
300+ NodeAssert . equal ( result [ 1 ] ! . mode , "subagent" ) ;
301+ } ) ;
302+
303+ it ( "strips ANSI CSI color escapes from agent headers" , ( ) => {
304+ const stdout = [
305+ "\x1b[31mbuild (primary)\x1b[0m" ,
306+ " " + JSON . stringify ( [ { permission : "*" , action : "allow" , pattern : "*" } ] ) ,
307+ ] . join ( "\n" ) ;
308+
309+ const result = parseAgentListCliOutput ( stdout ) ;
310+ NodeAssert . equal ( result . length , 1 ) ;
311+ NodeAssert . equal ( result [ 0 ] ! . name , "build" ) ;
312+ } ) ;
258313} ) ;
259314
260315describe ( "parseSkillsCliOutput" , ( ) => {
316+ it ( "strips OSC escapes before JSON parsing (opencode CLI leak)" , ( ) => {
317+ const polluted = "\x1b]0;tmp: ready\x07" + JSON . stringify ( [ { name : "review-pr" , location : "/tmp/x" , description : "d" , content : "c" } ] ) ;
318+ const result = parseSkillsCliOutput ( polluted ) ;
319+ NodeAssert . equal ( result . length , 1 ) ;
320+ NodeAssert . equal ( result [ 0 ] ! . name , "review-pr" ) ;
321+ } ) ;
322+
261323 it ( "parses skill metadata from the CLI JSON output" , ( ) => {
262324 const result = parseSkillsCliOutput (
263325 JSON . stringify ( [
0 commit comments