feat(browser): 接入 CCS browser MCP 与最小交互闭环

新增 browser MCP 安装、Chrome 复用与运行时接线,
实现 navigate、click、type、take_screenshot 四个 phase-1 工具并补齐相关单测。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
walkerandClaude Opus 4.6 authored and walker1211 committed 2026-04-13 11:19:16 +08:00
1 parent efecd7c7d9
commit eb8149e8fa
29 files changed
+3627 -118

No files matched your search

+53 -1
View File
@@ -144,7 +144,7 @@ describe('InstanceManager MCP sync', () => {
});
});
it('repairs managed ccs-websearch entries from global config while preserving other instance MCP overrides', () => {
it('repairs managed ccs-websearch and ccs-browser entries from global config while preserving other instance MCP overrides', () => {
fs.writeFileSync(
path.join(tempRoot, '.claude.json'),
JSON.stringify(
@@ -156,6 +156,12 @@ describe('InstanceManager MCP sync', () => {
args: ['/global/server.cjs'],
env: {},
},
'ccs-browser': {
type: 'stdio',
command: 'node',
args: ['/global/browser-server.cjs'],
env: {},
},
shared: { command: 'global-shared' },
},
},
@@ -179,6 +185,12 @@ describe('InstanceManager MCP sync', () => {
args: ['/old/server.cjs'],
env: {},
},
'ccs-browser': {
type: 'stdio',
command: 'node',
args: ['/old/browser-server.cjs'],
env: {},
},
shared: { command: 'instance-shared' },
instanceOnly: { command: 'instance-only' },
},
@@ -201,11 +213,51 @@ describe('InstanceManager MCP sync', () => {
args: ['/global/server.cjs'],
env: {},
},
'ccs-browser': {
type: 'stdio',
command: 'node',
args: ['/global/browser-server.cjs'],
env: {},
},
shared: { command: 'instance-shared' },
instanceOnly: { command: 'instance-only' },
});
});
it('preserves existing instance .claude.json permissions when syncing managed MCP servers', () => {
fs.writeFileSync(
path.join(tempRoot, '.claude.json'),
JSON.stringify(
{
mcpServers: {
'ccs-browser': {
type: 'stdio',
command: 'node',
args: ['/global/browser.cjs'],
env: {},
},
},
},
null,
2
),
'utf8'
);
const manager = new InstanceManager();
const instancePath = manager.getInstancePath('work');
fs.mkdirSync(instancePath, { recursive: true });
const instanceClaudeJson = path.join(instancePath, '.claude.json');
fs.writeFileSync(instanceClaudeJson, JSON.stringify({ existing: true }, null, 2) + '\n', {
encoding: 'utf8',
mode: 0o640,
});
fs.chmodSync(instanceClaudeJson, 0o640);
expect(manager.syncMcpServers(instancePath)).toBe(true);
expect(fs.statSync(instanceClaudeJson).mode & 0o777).toBe(0o640);
});
it('logs warning when global MCP sync fails', () => {
fs.writeFileSync(path.join(tempRoot, '.claude.json'), '{invalid-json', 'utf8');
const warnSpy = spyOn(console, 'warn').mockImplementation(() => {});