/** Production experts module + real isolated FS. Controlled Electron path/MCP state and injected I/O failures. */ import fs from 'node:fs/promises' import path from 'node:path' import assert from 'node:assert/strict' import { build } from 'esbuild' import { pathToFileURL } from 'node:url' import { createHash } from 'node:crypto' const output = await fs.mkdtemp(path.resolve('.tmp/expert-review-snapshot-')) const relative = path.relative(path.resolve('.tmp'), output) assert.ok(relative.startsWith('expert-review-snapshot-') && !relative.includes('..') && !path.isAbsolute(relative)) const data = path.join(output, 'data'); await fs.mkdir(data) globalThis.expertReviewMcp = { servers: [], hook: null, calls: [], generation: 1 } await build({ stdin: { contents: `export * from ${JSON.stringify(path.resolve('src/main/capabilities/experts.ts'))};export {createCapabilitySnapshot} from ${JSON.stringify(path.resolve('src/main/capabilities/runtime.ts'))};`, resolveDir: process.cwd(), sourcefile: 'expert-snapshot-review-entry.ts', loader: 'ts' }, outfile: path.join(output, 'experts.mjs'), bundle: true, platform: 'node', format: 'esm', packages: 'external', plugins: [{ name: 'isolated-review-host', setup(builder) { builder.onResolve({ filter: /^electron$/ }, () => ({ path: 'electron', namespace: 'review' })) builder.onLoad({ filter: /.*/, namespace: 'review' }, () => ({ contents: `export const app={getPath:()=>${JSON.stringify(data)}}` })) builder.onResolve({ filter: /^\.\/mcp$/ }, () => ({ path: 'mcp', namespace: 'review-mcp' })) builder.onLoad({ filter: /.*/, namespace: 'review-mcp' }, () => ({ contents: `export async function listMcpServers(){const state=globalThis.expertReviewMcp;state.calls.push('gate');if(state.hook)await state.hook();return state.servers}export async function snapshotMcpTools(){const state=globalThis.expertReviewMcp;state.calls.push('snapshot');const generation=state.generation;return {specs:[{type:'function',function:{name:'controlled_mcp',description:'controlled snapshot',parameters:{type:'object'}}}],describe:()=>({serverName:'worker',toolName:'echo'}),execute:async()=>generation===state.generation?{ok:true,content:'captured'}:{ok:false,content:'CONTROLLED_GENERATION_CHANGED'}}}` })) } }], logLevel: 'warning' }) const api = await import(pathToFileURL(path.join(output, 'experts.mjs')).href) const checks = [], packages = path.join(data, 'plugins', 'marketplaces', 'my-experts', 'plugins'), market = path.join(data, 'plugins', 'marketplaces', 'my-experts', '.codebuddy-plugin', 'marketplace.json') const check = (name, actual, expected) => { assert.deepEqual(actual, expected, name); checks.push(name) } function fixture(id, label = 'OLD_LABEL', role = 'OLD_ROLE') { const p = { name: id, version: '1.0.0', description: 'controlled fixture', expertType: 'agent', agentName: id, plugin: id, agents: [`./agents/${id}.md`], displayName: { zh: label, en: label }, profession: { zh: label, en: label }, displayDescription: { zh: '测试专家用于明确受控的隔离验证本地角色技能包数据一致性并保持行为诚实不伪造任何外部环境状态', en: 'controlled' }, defaultInitPrompt: { zh: 'hello', en: 'hello' }, quickPrompts: [{ zh: 'hello', en: 'hello' }, { zh: 'two', en: 'two' }, { zh: 'three', en: 'three' }], tags: [{ zh: 'one', en: 'one' }, { zh: 'two', en: 'two' }, { zh: 'three', en: 'three' }] } return { '.codebuddy-plugin/plugin.json': JSON.stringify(p), [`agents/${id}.md`]: `---\nname: ${id}\ndescription: fixture\n---\n${role}\n` } } async function install(id, files, session = 'owner-' + id) { await api.expertPackageOperation(session, { id, action: 'write', files }); return api.expertPackageOperation(session, { id, action: 'register' }) } const catalogHas = async id => JSON.parse(await fs.readFile(market, 'utf8')).plugins.some(item => item.name === id) const exists = file => fs.stat(file).then(() => true, () => false) const originalRm = fs.rm, originalRename = fs.rename try { let files = fixture('snapshot-expert'), metadata = JSON.parse(files['.codebuddy-plugin/plugin.json']) metadata.mcpServers = {}; files['.codebuddy-plugin/plugin.json'] = JSON.stringify(metadata) await install('snapshot-expert', files) globalThis.expertReviewMcp.hook = async () => { globalThis.expertReviewMcp.hook = null; await install('snapshot-expert', fixture('snapshot-expert', 'NEW_LABEL', 'NEW_ROLE'), 'concurrent-editor') } const snapshot = await api.expertTurnContext('snapshot-expert') check('concurrent register does not mix assistant identity with role', [snapshot.display.name, snapshot.context.includes('OLD_ROLE'), snapshot.context.includes('NEW_ROLE')], ['OLD_LABEL', true, false]) check('concurrent register actually publishes new package', (await api.readExpert('snapshot-expert')).prompt, 'NEW_ROLE') files = fixture('dependency-expert'); metadata = JSON.parse(files['.codebuddy-plugin/plugin.json']); metadata.mcpServers = { worker: { command: 'node', args: ['expected.js'] } }; files['.codebuddy-plugin/plugin.json'] = JSON.stringify(metadata) await install('dependency-expert', files) globalThis.expertReviewMcp.servers = [{ id: 'worker', name: 'worker', enabled: true, trusted: true, status: 'connected', transport: 'stdio', command: 'node', args: ['other.js'] }] await assert.rejects(api.activateExpert('dependency-expert'), /参数/); checks.push('same-name trusted connector with different args is rejected') globalThis.expertReviewMcp.servers[0].args = ['expected.js']; check('matching actual connector allows activation', (await api.activateExpert('dependency-expert')).id, 'dependency-expert') await install('remove-expert', fixture('remove-expert')) fs.rm = async (target, options) => { if (path.basename(String(target)).startsWith('.remove-')) { await fs.unlink(path.join(String(target), 'agents', 'remove-expert.md')); throw Object.assign(Error('Injected partial tomb cleanup failure'), { code: 'EIO' }) }; return originalRm.call(fs, target, options) } await api.removeExpert('remove-expert'); fs.rm = originalRm check('partial delete cleanup never resurrects catalog registration', await catalogHas('remove-expert'), false) check('partial delete cleanup leaves original managed identity absent', await exists(path.join(packages, 'remove-expert')), false) await install('rollback-expert', fixture('rollback-expert')) fs.rename = async (from, to) => { if (path.resolve(String(to)) === market) throw Object.assign(Error('Injected atomic catalog commit failure'), { code: 'EIO' }); return originalRename.call(fs, from, to) } await assert.rejects(api.removeExpert('rollback-expert'), /Injected/); fs.rename = originalRename check('delete catalog failure restores full original package', [(await api.readExpert('rollback-expert')).prompt, await catalogHas('rollback-expert')], ['OLD_ROLE', true]) await api.expertPackageOperation('rollback-editor', { id: 'rollback-expert', action: 'write', files: fixture('rollback-expert', 'EDITED_LABEL', 'EDITED_ROLE') }) fs.rename = async (from, to) => { if (path.resolve(String(to)) === market) throw Object.assign(Error('Injected atomic catalog commit failure'), { code: 'EIO' }); return originalRename.call(fs, from, to) } await assert.rejects(api.expertPackageOperation('rollback-editor', { id: 'rollback-expert', action: 'register' }), /Injected/); fs.rename = originalRename check('register catalog failure restores full original package', [(await api.readExpert('rollback-expert')).prompt, await catalogHas('rollback-expert')], ['OLD_ROLE', true]) await install('cleanup-expert', fixture('cleanup-expert')) fs.rm = async (target, options) => { if (path.basename(String(target)).startsWith('.backup-') || String(target).includes('expert-drafts') && path.basename(String(target)) === 'cleanup-expert.json') throw Object.assign(Error('Injected postcommit cleanup failure'), { code: 'EIO' }); return originalRm.call(fs, target, options) } const registered = await install('cleanup-expert', fixture('cleanup-expert', 'EDITED_LABEL', 'EDITED_ROLE'), 'cleanup-editor'); fs.rm = originalRm check('postcommit cleanup failure reports genuine committed success', [registered.success, (await api.readExpert('cleanup-expert')).prompt, await catalogHas('cleanup-expert')], [true, 'EDITED_ROLE', true]) await api.expertPackageOperation('corrupt-market-editor', { id: 'leak-expert', action: 'write', files: fixture('leak-expert') }) await fs.writeFile(market, 'INVALID JSON') const before = (await fs.readdir(packages)).filter(name => name.startsWith('.stage-')).length await assert.rejects(api.expertPackageOperation('corrupt-market-editor', { id: 'leak-expert', action: 'register' })) check('invalid catalog does not leak install stage', (await fs.readdir(packages)).filter(name => name.startsWith('.stage-')).length, before) assert.throws(() => api.expertManagerResource('__proto__'), /不存在/); assert.throws(() => api.expertManagerResource('constructor'), /不存在/); checks.push('builtin manager refuses inherited resource properties') globalThis.expertReviewMcp.calls = [] globalThis.expertReviewMcp.hook = async () => { globalThis.expertReviewMcp.hook = null; globalThis.expertReviewMcp.generation++ } const capability = await api.createCapabilitySnapshot([], output, { sessionId: 'controlled-turn', expertId: 'dependency-expert' }) check('actual runtime captures MCP before expert dependency validation', globalThis.expertReviewMcp.calls, ['snapshot', 'gate']) const ctx = { runId: 'controlled-turn', toolCallId: 'controlled-call', workspaceRoot: output, permissionMode: 'full-access', signal: new AbortController().signal, emit() {} } check('actual runtime retains captured snapshot when connection generation changes', await capability.execute('controlled_mcp', {}, ctx), { ok: false, content: 'CONTROLLED_GENERATION_CHANGED', metadata: { capability: 'mcp', serverName: 'worker', toolName: 'echo' } }) check('active expert refuses inherited resource properties', (await capability.execute('ycode_expert_resource', { path: '__proto__' }, ctx)).ok, false) check('active expert still reads actual package resource', (await capability.execute('ycode_expert_resource', { path: 'agents/dependency-expert.md' }, ctx)).content.includes('OLD_ROLE'), true) await fs.writeFile(path.join(output, 'report.json'), JSON.stringify({ result: 'PASS', checks, sources: await Promise.all(['src/main/capabilities/experts.ts', 'src/main/capabilities/runtime.ts'].map(async file => ({ file, sha256: createHash('sha256').update(await fs.readFile(file)).digest('hex') }))), limits: 'Actual isolated FS + production experts/runtime module; Electron path and MCP state/generation contract are controlled. Actual network/SDK generation guard and WorkBuddy pixels are not asserted.' }, null, 2)) console.log(JSON.stringify({ result: 'PASS', checks: checks.length, output })) } finally { fs.rm = originalRm; fs.rename = originalRename }