|
| 1 | +import assert from 'node:assert/strict'; |
| 2 | +import {mkdtemp, mkdir, writeFile, cp, chmod, rm, realpath} from 'node:fs/promises'; |
| 3 | +import {tmpdir} from 'node:os'; |
| 4 | +import {dirname,join,delimiter} from 'node:path'; |
| 5 | +import {fileURLToPath} from 'node:url'; |
| 6 | +import {Client} from '@modelcontextprotocol/sdk/client/index.js'; |
| 7 | +import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; |
| 8 | +const repo=fileURLToPath(new URL('..',import.meta.url)); |
| 9 | +const parent=await mkdtemp(join(tmpdir(),'apc polyglot MCP ')); |
| 10 | +const root=join(parent,'plugin with spaces'); |
| 11 | +await cp(join(repo,'plugins/agent-plugins-conformance-core'),root,{recursive:true}); |
| 12 | +await mkdir(join(root,'bin')); |
| 13 | +await writeFile(join(root,'bin/package.json'),'{"type":"commonjs"}\n'); |
| 14 | +const jsBody='0</* :\n@node "%~dp0..\\dist\\probe.mjs" %*\n@exit /b %errorlevel%\n*/0;\nimport("../dist/probe.mjs");\n'; |
| 15 | +const shBody=':; exec node "$(dirname "$0")/../dist/probe.mjs" "$@"\n@echo off\nnode "%~dp0..\\dist\\probe.mjs" %*\nexit /b %errorlevel%\n'; |
| 16 | +const variants={ |
| 17 | + node_plain:'#!/usr/bin/env node\n'+jsBody, |
| 18 | + node_envS:'#!/usr/bin/env -S node # 2>nul\n'+jsBody, |
| 19 | + node_envS_double_space:'#!/usr/bin/env -S node # 2>nul\n'+jsBody, |
| 20 | + shell_envS:'#!/usr/bin/env -S sh # 2>nul\n'+shBody, |
| 21 | +}; |
| 22 | +const env={...process.env,PLUGIN_ROOT:root,PLUGIN_DATA:parent}; |
| 23 | +if(process.platform==='win32') { |
| 24 | + for(const key of Object.keys(env)) if(key.toLowerCase()==='path') delete env[key]; |
| 25 | + env.PATH=[dirname(process.execPath),join(process.env.SystemRoot,'System32'),process.env.SystemRoot].join(delimiter); |
| 26 | +} |
| 27 | +const results=[]; |
| 28 | +try { |
| 29 | + for(const [name,body] of Object.entries(variants)) { |
| 30 | + const file=join(root,'bin',name+'.cmd'); await writeFile(file,body);await chmod(file,0o755); |
| 31 | + const routes={sdk:{command:file,args:['relative']}}; |
| 32 | + if(process.platform==='win32') for(const quiet of [false,true]) routes[quiet?'cmdQuiet':'cmd']={command:process.env.ComSpec||'cmd.exe',args:['/d',...(quiet?['/q']:[]),'/s','/c',`"${file}" relative`]}; |
| 33 | + for(const [route,launch] of Object.entries(routes)){ |
| 34 | + const client=new Client({name:'polyglot-prototype',version:'1'}); |
| 35 | + const transport=new StdioClientTransport({...launch,cwd:join(root,'probe-workdir'),env,stderr:'pipe'}); |
| 36 | + const row={name,route,launch,stderr:'',protocolErrors:[],success:false}; |
| 37 | + client.onerror=error=>row.protocolErrors.push(String(error)); |
| 38 | + transport.stderr?.on('data',data=>row.stderr+=data.toString()); |
| 39 | + try{ |
| 40 | + await client.connect(transport,{timeout:10000}); |
| 41 | + const result=await client.callTool({name:'observe',arguments:{}},undefined,{timeout:10000}); |
| 42 | + assert.ok(!result.isError); |
| 43 | + const observation=result.structuredContent; |
| 44 | + assert.equal(observation.evidence.root,await realpath(root)); |
| 45 | + assert.equal(observation.evidence.cwd,await realpath(join(root,'probe-workdir'))); |
| 46 | + assert.deepEqual(observation.evidence.argv,['relative']); |
| 47 | + row.observation=observation; row.success=true; |
| 48 | + }catch(error){row.error=String(error)} |
| 49 | + finally{await client.close();} |
| 50 | + row.protocolClean=row.success&&row.protocolErrors.length===0; |
| 51 | + results.push(row); |
| 52 | + } |
| 53 | + } |
| 54 | +}finally{await rm(parent,{recursive:true,force:true});} |
| 55 | +console.log(JSON.stringify({platform:process.platform,node:process.version,path:env.PATH,results},null,2)); |
0 commit comments