cli-jaw 2.17.68 → 2.17.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.ja.md +1 -2
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -2
  4. package/README.zh-CN.md +1 -2
  5. package/dist/bin/commands/employee.js +1 -1
  6. package/dist/lib/mcp/computer-use-config.js +134 -0
  7. package/dist/lib/mcp/computer-use-config.js.map +1 -0
  8. package/dist/lib/mcp/computer-use-constants.js +12 -0
  9. package/dist/lib/mcp/computer-use-constants.js.map +1 -0
  10. package/dist/lib/mcp/computer-use-proxy-main.js +20 -0
  11. package/dist/lib/mcp/computer-use-proxy-main.js.map +1 -0
  12. package/dist/lib/mcp/computer-use-proxy.js +246 -0
  13. package/dist/lib/mcp/computer-use-proxy.js.map +1 -0
  14. package/dist/lib/mcp/format-converters.js +26 -14
  15. package/dist/lib/mcp/format-converters.js.map +1 -1
  16. package/dist/lib/mcp-sync.js +2 -0
  17. package/dist/lib/mcp-sync.js.map +1 -1
  18. package/dist/server.js +8 -1
  19. package/dist/server.js.map +1 -1
  20. package/dist/src/agent/spawn.js +2 -0
  21. package/dist/src/agent/spawn.js.map +1 -1
  22. package/dist/src/core/employees.js +1 -23
  23. package/dist/src/core/employees.js.map +1 -1
  24. package/dist/src/prompt/builder.js +23 -4
  25. package/dist/src/prompt/builder.js.map +1 -1
  26. package/dist/src/prompt/templates/a1-system.md +17 -42
  27. package/dist/src/prompt/templates/employee.md +6 -5
  28. package/dist/src/prompt/templates/orchestration.md +1 -1
  29. package/dist/src/routes/employees.js +1 -1
  30. package/dist/src/routes/employees.js.map +1 -1
  31. package/package.json +1 -1
  32. package/public/dist/.vite/manifest.json +2 -2
  33. package/public/dist/assets/MilkdownWysiwygEditor-BK26KbJ4.js +160 -0
  34. package/public/dist/assets/{manager-Dhz8mX5E.js → manager-nquYZ7_x.js} +1 -1
  35. package/public/dist/manager/index.html +1 -1
  36. package/public/js/features/employees.ts +1 -1
  37. package/scripts/audit-allowlist.json +45 -0
  38. package/dist/src/prompt/templates/control-system.md +0 -70
  39. package/public/dist/assets/MilkdownWysiwygEditor-AL9Y5CIv.js +0 -160
package/README.ja.md CHANGED
@@ -445,7 +445,7 @@ jaw dispatch --virtual "security" --task "Review this branch for auth and secret
445
445
 
446
446
  ### ブラウザとデスクトップの自動化
447
447
 
448
- DevTools Protocol 経由で Chrome を操作し、`jaw browser vision-click "Login button"` で説明からクリックし、macOS と Windows では Codex Computer Use でデスクトップアプリを操作し、`jaw browser web-ai` で ChatGPT、Gemini、Grok の Web UI に問い合わせられます。
448
+ DevTools Protocol 経由で Chrome を操作し、`jaw browser vision-click "Login button"` で説明からクリックできます。対応する macOS および Windows ホストでは `jaw-computer-use` MCP ツール(または Codex 標準の Computer Use プラグイン)でデスクトップアプリを操作し、`jaw browser web-ai` で ChatGPT、Gemini、Grok の Web UI に問い合わせられます。
449
449
 
450
450
  ### メッセージング
451
451
 
@@ -591,4 +591,3 @@ npm run electron:dev # desktop app with hot reload
591
591
  <p align="center"><a href="LICENSE"><b>MIT License</b></a> · AI アプリのタブ切り替えに疲れた開発者たちが作りました。</p>
592
592
 
593
593
 
594
-
package/README.ko.md CHANGED
@@ -447,7 +447,7 @@ jaw dispatch --virtual "security" --task "Review this branch for auth and secret
447
447
 
448
448
  ### 브라우저와 데스크톱 자동화
449
449
 
450
- Chrome을 DevTools Protocol로 제어하고, `jaw browser vision-click "Login button"`처럼 설명으로 클릭하며, macOS와 Windows에서 Codex Computer Use로 데스크톱 앱을 다루고, `jaw browser web-ai`로 ChatGPT, Gemini, Grok 웹 UI에 물어볼 수 있습니다.
450
+ Chrome을 DevTools Protocol로 제어하고, `jaw browser vision-click "Login button"`처럼 설명으로 클릭합니다. 지원되는 macOS 및 Windows 호스트에서는 `jaw-computer-use` MCP 도구(또는 Codex의 기본 Computer Use 플러그인)로 데스크톱 앱을 다루고, `jaw browser web-ai`로 ChatGPT, Gemini, Grok 웹 UI에 물어볼 수 있습니다.
451
451
 
452
452
  ### 메시징
453
453
 
package/README.md CHANGED
@@ -471,7 +471,7 @@ State survives restarts. Start with `jaw orchestrate` or `/pabcd`, resume with `
471
471
 
472
472
  ### Browser and desktop automation
473
473
 
474
- Drive Chrome through the DevTools Protocol, click by description with `jaw browser vision-click "Login button"`, control desktop apps through Codex Computer Use on macOS and Windows, and ask ChatGPT, Gemini or Grok web UIs with `jaw browser web-ai`.
474
+ Drive Chrome through the DevTools Protocol, click by description with `jaw browser vision-click "Login button"`, and control desktop apps through the `jaw-computer-use` MCP tool (or Codex's native Computer Use plugin) on supported macOS and Windows hosts. Ask ChatGPT, Gemini or Grok web UIs with `jaw browser web-ai`.
475
475
 
476
476
  ### Messaging
477
477
 
@@ -619,4 +619,3 @@ Public code and product docs live here. Private planning and history live only i
619
619
  <p align="center"><a href="LICENSE"><b>MIT License</b></a> · Built by developers who got tired of tab-switching between AI apps.</p>
620
620
 
621
621
 
622
-
package/README.zh-CN.md CHANGED
@@ -471,7 +471,7 @@ jaw dispatch --virtual "security" --task "Review this branch for auth and secret
471
471
 
472
472
  ### 浏览器和桌面自动化
473
473
 
474
- 通过 DevTools Protocol 驱动 Chrome;用 `jaw browser vision-click "Login button"` 按描述点击;在 macOS 和 Windows 上通过 Codex Computer Use 控制桌面应用;用 `jaw browser web-ai` 询问 ChatGPT、Gemini 或 Grok 的 Web UI。
474
+ 通过 DevTools Protocol 驱动 Chrome;用 `jaw browser vision-click "Login button"` 按描述点击;在受支持的 macOS 和 Windows 主机上,通过 `jaw-computer-use` MCP 工具(或 Codex 原生 Computer Use 插件)控制桌面应用;用 `jaw browser web-ai` 询问 ChatGPT、Gemini 或 Grok 的 Web UI。
475
475
 
476
476
  ### 消息
477
477
 
@@ -617,4 +617,3 @@ npm run electron:dev # desktop app with hot reload
617
617
  <p align="center"><a href="LICENSE"><b>MIT License</b></a> · 由受够了在 AI 应用之间来回切标签的开发者们打造。</p>
618
618
 
619
619
 
620
-
@@ -31,7 +31,7 @@ function printHelp() {
31
31
  Description:
32
32
  List employees or reset DB employees to built-in defaults.
33
33
  sessions-reset clears only persisted employee resume sessions.
34
- Static employees such as Control are merged into the list by the server.
34
+ Static employees, when configured, are merged into the list by the server.
35
35
  `);
36
36
  }
37
37
  async function apiJson(baseUrl, path, init = {}) {
@@ -0,0 +1,134 @@
1
+ /** Provision the jaw-owned Computer Use proxy without replacing user MCP entries. */
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import { basename, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { COMPUTER_USE_MCP_NAME, PROXY_ENTRY_BASENAME } from './computer-use-constants.js';
7
+ import { resolveCuaRepl } from './computer-use-proxy.js';
8
+ import { toClaudeMcp, toOpenCodeMcp } from './format-converters.js';
9
+ export function computerUseServerEntry(opts = {}) {
10
+ return {
11
+ command: opts.nodePath ?? process.execPath,
12
+ args: [opts.entryPath ?? fileURLToPath(new URL('./computer-use-proxy-main.js', import.meta.url))],
13
+ };
14
+ }
15
+ export function isManagedComputerUseEntry(server) {
16
+ if (!isObject(server))
17
+ return false;
18
+ const args = server['args'];
19
+ if (Array.isArray(args) && typeof args[0] === 'string' && basename(args[0]) === PROXY_ENTRY_BASENAME)
20
+ return true;
21
+ const command = server['command'];
22
+ return Array.isArray(command) && typeof command[1] === 'string' && basename(command[1]) === PROXY_ENTRY_BASENAME;
23
+ }
24
+ function isObject(value) {
25
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
26
+ }
27
+ function readJson(path) {
28
+ const data = JSON.parse(fs.readFileSync(path, 'utf8'));
29
+ if (!isObject(data))
30
+ return null;
31
+ return data;
32
+ }
33
+ function same(a, b) {
34
+ return JSON.stringify(a) === JSON.stringify(b);
35
+ }
36
+ function writeJson(path, value) {
37
+ fs.writeFileSync(path, JSON.stringify(value, null, 4) + '\n');
38
+ }
39
+ function targets(home) {
40
+ return [
41
+ { path: join(home, '.claude.json'), key: 'mcpServers', format: 'claude' },
42
+ { path: join(home, '.gemini', 'settings.json'), key: 'mcpServers', format: 'claude' },
43
+ { path: join(home, '.config', 'opencode', 'opencode.json'), key: 'mcp', format: 'opencode' },
44
+ { path: join(home, '.copilot', 'mcp-config.json'), key: 'mcpServers', format: 'claude' },
45
+ { path: join(home, '.cursor', 'mcp.json'), key: 'mcpServers', format: 'claude' },
46
+ { path: join(home, '.gemini', 'antigravity', 'mcp_config.json'), key: 'mcpServers', format: 'claude' },
47
+ { path: join(home, '.kiro', 'settings', 'mcp.json'), key: 'mcpServers', format: 'claude' },
48
+ ];
49
+ }
50
+ export function ensureComputerUseMcp(opts = {}) {
51
+ const home = opts.homeDir ?? os.homedir();
52
+ const jawHome = opts.jawHome ?? process.env['CLI_JAW_HOME'] ?? join(home, '.cli-jaw');
53
+ const result = { action: 'unchanged', targets: [], skipped: [] };
54
+ const unifiedPath = join(jawHome, 'mcp.json');
55
+ let unified;
56
+ try {
57
+ const parsed = readJson(unifiedPath);
58
+ if (!parsed)
59
+ throw new Error('MCP config must be an object');
60
+ unified = parsed;
61
+ }
62
+ catch {
63
+ result.action = 'skipped-unreadable';
64
+ result.skipped.push(unifiedPath);
65
+ return result;
66
+ }
67
+ const currentServers = unified['servers'];
68
+ if (currentServers !== undefined && !isObject(currentServers)) {
69
+ result.action = 'skipped-unreadable';
70
+ result.skipped.push(unifiedPath);
71
+ return result;
72
+ }
73
+ const servers = isObject(currentServers) ? currentServers : {};
74
+ const prior = servers[COMPUTER_USE_MCP_NAME];
75
+ if (prior !== undefined && !isManagedComputerUseEntry(prior)) {
76
+ result.action = 'preserved-user-entry';
77
+ return result;
78
+ }
79
+ if (!prior && !(opts.resolve ?? resolveCuaRepl)({ codexHome: opts.codexHome })) {
80
+ result.action = 'skipped-no-plugin';
81
+ return result;
82
+ }
83
+ const entry = opts.entry ?? computerUseServerEntry();
84
+ if (!same(prior, entry)) {
85
+ const updated = { ...unified, servers: { ...servers, [COMPUTER_USE_MCP_NAME]: entry } };
86
+ try {
87
+ writeJson(unifiedPath, updated);
88
+ result.targets.push(unifiedPath);
89
+ result.action = prior ? 'updated' : 'added';
90
+ }
91
+ catch {
92
+ result.action = 'skipped-unreadable';
93
+ result.skipped.push(unifiedPath);
94
+ return result;
95
+ }
96
+ }
97
+ // A test run must never write the real user's CLI configs. An injected homeDir
98
+ // is already isolated, so only the implicit os.homedir() path is guarded.
99
+ const implicitHome = opts.homeDir === undefined;
100
+ if (implicitHome && (process.env['NODE_ENV'] === 'test' || basename(jawHome).startsWith('cli-jaw-test-')))
101
+ return result;
102
+ const claudeEntry = toClaudeMcp({ servers: { [COMPUTER_USE_MCP_NAME]: entry } }).mcpServers[COMPUTER_USE_MCP_NAME];
103
+ const opencodeEntry = toOpenCodeMcp({ servers: { [COMPUTER_USE_MCP_NAME]: entry } })[COMPUTER_USE_MCP_NAME];
104
+ for (const target of targets(home)) {
105
+ if (!fs.existsSync(target.path))
106
+ continue;
107
+ try {
108
+ const document = readJson(target.path);
109
+ if (!document)
110
+ throw new Error('MCP target must be an object');
111
+ const current = document[target.key];
112
+ if (current !== undefined && !isObject(current))
113
+ throw new Error('MCP server map must be an object');
114
+ const map = current ?? {};
115
+ const existing = map[COMPUTER_USE_MCP_NAME];
116
+ if (existing !== undefined && !isManagedComputerUseEntry(existing)) {
117
+ result.skipped.push(target.path);
118
+ continue;
119
+ }
120
+ const value = target.format === 'opencode' ? opencodeEntry : claudeEntry;
121
+ if (same(existing, value))
122
+ continue;
123
+ writeJson(target.path, { ...document, [target.key]: { ...map, [COMPUTER_USE_MCP_NAME]: value } });
124
+ result.targets.push(target.path);
125
+ if (result.action === 'unchanged')
126
+ result.action = 'updated';
127
+ }
128
+ catch {
129
+ result.skipped.push(target.path);
130
+ }
131
+ }
132
+ return result;
133
+ }
134
+ //# sourceMappingURL=computer-use-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computer-use-config.js","sourceRoot":"","sources":["../../../lib/mcp/computer-use-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * lib/mcp/computer-use-constants.ts
3
+ * Names shared by the jaw-computer-use proxy, its managed MCP entry and the
4
+ * spawn path that hands each run's approval policy to the proxy.
5
+ */
6
+ /** Unified MCP server name for the jaw-owned Computer Use proxy. */
7
+ export const COMPUTER_USE_MCP_NAME = 'jaw-computer-use';
8
+ /** Run-bound approval policy for Computer Use app approvals: exactly 'auto' approves. */
9
+ export const COMPUTER_USE_APPROVAL_ENV = 'JAW_COMPUTER_USE_APPROVAL';
10
+ /** Compiled entry file the managed MCP entry points at (dist/lib/mcp/...). */
11
+ export const PROXY_ENTRY_BASENAME = 'computer-use-proxy-main.js';
12
+ //# sourceMappingURL=computer-use-constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computer-use-constants.js","sourceRoot":"","sources":["../../../lib/mcp/computer-use-constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAExD,yFAAyF;AACzF,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAC;AAErE,8EAA8E;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,4BAA4B,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { resolveApprovalPolicy, resolveCuaRepl, runComputerUseProxy } from './computer-use-proxy.js';
2
+ export async function runComputerUseProxyMain() {
3
+ let child;
4
+ const stop = () => { child?.kill(); };
5
+ process.on('SIGTERM', stop);
6
+ process.on('SIGINT', stop);
7
+ const code = await runComputerUseProxy({ input: process.stdin, output: process.stdout, errorOutput: process.stderr }, {
8
+ spec: resolveCuaRepl({ codexHome: process.env['CODEX_HOME'] }),
9
+ policy: resolveApprovalPolicy(process.env),
10
+ onChild: spawned => { child = spawned; },
11
+ });
12
+ process.off('SIGTERM', stop);
13
+ process.off('SIGINT', stop);
14
+ // The missing-plugin path can finish immediately after a protocol error write.
15
+ await new Promise(resolve => process.stdout.write('', () => resolve()));
16
+ process.stdin.pause();
17
+ process.exitCode = code;
18
+ }
19
+ void runComputerUseProxyMain();
20
+ //# sourceMappingURL=computer-use-proxy-main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computer-use-proxy-main.js","sourceRoot":"","sources":["../../../lib/mcp/computer-use-proxy-main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAErG,MAAM,CAAC,KAAK,UAAU,uBAAuB;IACzC,IAAI,KAAiD,CAAC;IACtD,MAAM,IAAI,GAAG,GAAS,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE;QAClH,IAAI,EAAE,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9D,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC;QAC1C,OAAO,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC;KAC3C,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC5B,+EAA+E;IAC/E,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC9E,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC5B,CAAC;AAED,KAAK,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,246 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { isAbsolute, join } from 'node:path';
5
+ import { StringDecoder } from 'node:string_decoder';
6
+ import { COMPUTER_USE_APPROVAL_ENV } from './computer-use-constants.js';
7
+ function object(value) {
8
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
9
+ ? value : null;
10
+ }
11
+ function compareVersions(left, right) {
12
+ const a = left.split('.').map(BigInt);
13
+ const b = right.split('.').map(BigInt);
14
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
15
+ const difference = (a[i] ?? 0n) - (b[i] ?? 0n);
16
+ if (difference !== 0n)
17
+ return difference > 0n ? 1 : -1;
18
+ }
19
+ return 0;
20
+ }
21
+ /** Find the newest valid bundled cua_repl server without importing Jaw config. */
22
+ export function resolveCuaRepl(opts = {}) {
23
+ const root = join(opts.codexHome ?? process['env']['CODEX_HOME'] ?? join(homedir(), '.codex'), 'plugins', 'cache', 'openai-bundled', 'unified-computer-use');
24
+ const exists = opts.exists ?? existsSync;
25
+ let versions;
26
+ try {
27
+ versions = readdirSync(root).filter(version => /^\d+(?:\.\d+)*$/.test(version));
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ versions.sort((a, b) => compareVersions(b, a));
33
+ for (const version of versions) {
34
+ const configPath = join(root, version, '.mcp.json');
35
+ try {
36
+ const config = object(JSON.parse(readFileSync(configPath, 'utf8')));
37
+ const server = object(object(config?.['mcpServers'])?.['cua_repl']);
38
+ if (!server || typeof server['command'] !== 'string' || !isAbsolute(server['command']) || !exists(server['command']))
39
+ continue;
40
+ if (!Array.isArray(server['args']) || !server['args'].every(arg => typeof arg === 'string'))
41
+ continue;
42
+ const env = object(server['env'] ?? {});
43
+ if (!env || !Object.values(env).every(value => typeof value === 'string'))
44
+ continue;
45
+ return { command: server['command'], args: server['args'], env: env, version, configPath };
46
+ }
47
+ catch {
48
+ // A partial or malformed plugin cache entry must not hide an older valid version.
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ export function resolveApprovalPolicy(env) {
54
+ return env[COMPUTER_USE_APPROVAL_ENV] === 'auto' ? 'auto' : 'safe';
55
+ }
56
+ function hasId(message) {
57
+ return typeof message['id'] === 'string' || (typeof message['id'] === 'number' && Number.isFinite(message['id']));
58
+ }
59
+ /** Unknown messages from the same connector fail closed; other connectors pass through. */
60
+ export function classifyElicitation(msg) {
61
+ const message = object(msg);
62
+ if (message?.['method'] !== 'elicitation/create')
63
+ return 'other';
64
+ const params = object(message['params']);
65
+ const meta = object(params?.['_meta']);
66
+ if (meta?.['connector_id'] !== 'computer-use')
67
+ return 'other';
68
+ if (!hasId(message))
69
+ return 'cu-unknown';
70
+ if (params?.['mode'] !== undefined && params['mode'] !== 'form')
71
+ return 'cu-unknown';
72
+ if (meta['codex_approval_kind'] !== 'mcp_tool_call')
73
+ return 'cu-unknown';
74
+ if (params?.['requestedSchema'] !== undefined) {
75
+ const schema = object(params['requestedSchema']);
76
+ if (!schema || schema['type'] !== 'object')
77
+ return 'cu-unknown';
78
+ if (schema['required'] !== undefined && (!Array.isArray(schema['required']) || schema['required'].length !== 0))
79
+ return 'cu-unknown';
80
+ const properties = schema['properties'] === undefined ? {} : object(schema['properties']);
81
+ if (!properties || Object.keys(properties).length !== 0)
82
+ return 'cu-unknown';
83
+ }
84
+ return 'cu-approval';
85
+ }
86
+ export function isComputerUseApproval(msg) {
87
+ const message = object(msg);
88
+ return message !== null && hasId(message) && classifyElicitation(message) === 'cu-approval';
89
+ }
90
+ export function approvalReply(id, policy) {
91
+ return { jsonrpc: '2.0', id, result: policy === 'auto'
92
+ ? { action: 'accept', content: {} }
93
+ : { action: 'decline' } };
94
+ }
95
+ export function withElicitationCapability(initializeMsg) {
96
+ const message = object(initializeMsg);
97
+ if (message?.['method'] !== 'initialize')
98
+ return initializeMsg;
99
+ const params = object(message['params']) ?? {};
100
+ const capabilities = object(params['capabilities']) ?? {};
101
+ const elicitation = object(capabilities['elicitation']) ?? {};
102
+ return { ...message, params: { ...params, capabilities: {
103
+ ...capabilities, elicitation: { ...elicitation, form: {} },
104
+ } } };
105
+ }
106
+ function readLines(input, onLine, onEnd) {
107
+ const decoder = new StringDecoder('utf8');
108
+ let pending = '';
109
+ const consume = (text) => {
110
+ pending += text;
111
+ let newline = pending.indexOf('\n');
112
+ while (newline !== -1) {
113
+ const line = pending.slice(0, newline + 1);
114
+ pending = pending.slice(newline + 1);
115
+ onLine(line);
116
+ newline = pending.indexOf('\n');
117
+ }
118
+ };
119
+ input.on('data', (chunk) => consume(typeof chunk === 'string' ? chunk : decoder.write(chunk)));
120
+ input.once('end', () => {
121
+ consume(decoder.end());
122
+ if (pending)
123
+ onLine(pending);
124
+ onEnd();
125
+ });
126
+ }
127
+ function parseLine(line) {
128
+ try {
129
+ return object(JSON.parse(line));
130
+ }
131
+ catch {
132
+ return null;
133
+ }
134
+ }
135
+ const MISSING_PLUGIN_MESSAGE = 'precondition failed: Codex Computer Use (unified-computer-use cua_repl) not found under <codexHome>/plugins/cache/openai-bundled. Install the ChatGPT desktop app with Computer Use enabled.';
136
+ function writeResponse(output, reply) {
137
+ output.write(`${JSON.stringify(reply)}\n`);
138
+ }
139
+ function logValue(value) {
140
+ return typeof value === 'string' ? value.replace(/[\r\n\t]/g, ' ').slice(0, 200) : '-';
141
+ }
142
+ export async function runComputerUseProxy(io, opts) {
143
+ if (!opts.spec) {
144
+ return new Promise(resolve => {
145
+ let finished = false;
146
+ readLines(io.input, line => {
147
+ if (finished)
148
+ return;
149
+ const msg = parseLine(line);
150
+ if (!msg || !hasId(msg) || typeof msg['method'] !== 'string')
151
+ return;
152
+ writeResponse(io.output, { jsonrpc: '2.0', id: msg['id'],
153
+ error: { code: -32002, message: MISSING_PLUGIN_MESSAGE } });
154
+ if (msg['method'] === 'initialize') {
155
+ finished = true;
156
+ io.output.end();
157
+ resolve(1);
158
+ }
159
+ }, () => resolve(1));
160
+ });
161
+ }
162
+ const spec = opts.spec;
163
+ return new Promise(resolve => {
164
+ let child;
165
+ let pendingInitializeId;
166
+ let initialized = false;
167
+ let settled = false;
168
+ const finish = (code) => {
169
+ if (settled)
170
+ return;
171
+ settled = true;
172
+ resolve(code);
173
+ };
174
+ try {
175
+ child = opts.spawnChild
176
+ ? opts.spawnChild(spec)
177
+ : spawn(spec['command'], spec['args'], { env: { ...process['env'], ...spec['env'] }, stdio: 'pipe' });
178
+ opts.onChild?.(child);
179
+ }
180
+ catch (error) {
181
+ io.errorOutput.write(`[jaw-computer-use] spawn failed: ${String(error)}\n`);
182
+ finish(1);
183
+ return;
184
+ }
185
+ child.stderr.pipe(io.errorOutput, { end: false });
186
+ child.once('error', error => {
187
+ io.errorOutput.write(`[jaw-computer-use] spawn failed: ${error.message}\n`);
188
+ if (pendingInitializeId !== undefined)
189
+ writeResponse(io.output, { jsonrpc: '2.0', id: pendingInitializeId,
190
+ error: { code: -32002, message: `precondition failed: Computer Use proxy child could not start: ${error.message}` } });
191
+ finish(1);
192
+ });
193
+ // 'close' follows stdout/stderr EOF, so the final protocol line is observed first.
194
+ child.once('close', code => finish(code ?? 0));
195
+ child.stdin.on('error', error => {
196
+ if (!settled && error.code !== 'EPIPE') {
197
+ io.errorOutput.write(`[jaw-computer-use] child stdin failed: ${error.message}\n`);
198
+ }
199
+ });
200
+ readLines(io.input, line => {
201
+ if (settled)
202
+ return;
203
+ const msg = parseLine(line);
204
+ // Newer clients probe with server/discover before initialize. cua_repl's
205
+ // rmcp transport treats any pre-initialize request as fatal and exits, so
206
+ // answer the probe here and let the client fall back to initialize.
207
+ if (!initialized && msg && hasId(msg) && msg['method'] === 'server/discover') {
208
+ writeResponse(io.output, { jsonrpc: '2.0', id: msg['id'],
209
+ error: { code: -32601, message: 'Method not found: server/discover' } });
210
+ return;
211
+ }
212
+ if (msg?.['method'] === 'initialize') {
213
+ initialized = true;
214
+ if (hasId(msg))
215
+ pendingInitializeId = msg['id'];
216
+ child.stdin.write(`${JSON.stringify(withElicitationCapability(msg))}\n`);
217
+ }
218
+ else {
219
+ child.stdin.write(line);
220
+ }
221
+ }, () => { if (!settled)
222
+ child.stdin.end(); });
223
+ readLines(child.stdout, line => {
224
+ if (settled)
225
+ return;
226
+ const msg = parseLine(line);
227
+ if (msg && pendingInitializeId !== undefined && msg['id'] === pendingInitializeId)
228
+ pendingInitializeId = undefined;
229
+ const kind = classifyElicitation(msg);
230
+ if (kind === 'other') {
231
+ io.output.write(line);
232
+ return;
233
+ }
234
+ if (!msg || !hasId(msg)) {
235
+ io.errorOutput.write('[jaw-computer-use] dropped id-less computer-use elicitation\n');
236
+ return;
237
+ }
238
+ const action = kind === 'cu-approval' && opts.policy === 'auto' ? 'accept' : 'decline';
239
+ writeResponse(child.stdin, approvalReply(msg['id'], action === 'accept' ? 'auto' : 'safe'));
240
+ const meta = object(object(msg['params'])?.['_meta']);
241
+ const app = object(meta?.['tool_params'])?.['app'];
242
+ io.errorOutput.write(`[jaw-computer-use] ${action} ${logValue(meta?.['tool_name'])} ${logValue(app)}\n`);
243
+ }, () => undefined);
244
+ });
245
+ }
246
+ //# sourceMappingURL=computer-use-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computer-use-proxy.js","sourceRoot":"","sources":["../../../lib/mcp/computer-use-proxy.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  import fs from 'fs';
7
7
  import os from 'os';
8
8
  import { join, dirname } from 'path';
9
+ import { COMPUTER_USE_MCP_NAME } from './computer-use-constants.js';
9
10
  function getServers(config) {
10
11
  return config.servers ?? {};
11
12
  }
@@ -40,6 +41,8 @@ export function toClaudeMcp(config) {
40
41
  export function toCodexToml(config) {
41
42
  let toml = '';
42
43
  for (const [name, srv] of Object.entries(getServers(config))) {
44
+ if (name === COMPUTER_USE_MCP_NAME)
45
+ continue;
43
46
  toml += `[mcp_servers.${name}]\n`;
44
47
  if (srv.url) {
45
48
  toml += `url = ${tomlString(srv.url)}\n`;
@@ -81,20 +84,28 @@ export function toOpenCodeMcp(config) {
81
84
  return mcp;
82
85
  }
83
86
  // ─── Patch helpers ─────────────────────────────────
84
- /** Replace only [mcp_servers.*] sections in existing TOML, keep everything else */
85
- export function patchCodexToml(existingToml, newMcpToml) {
87
+ /** Replace only sections for MCP names emitted in this sync, including their subtables. */
88
+ export function patchCodexToml(existingToml, newMcpToml, emittedNames = new Set()) {
89
+ if (emittedNames.size === 0)
90
+ return existingToml;
86
91
  const lines = existingToml.split('\n');
87
92
  const output = [];
88
- let inMcp = false;
93
+ let removeSection = false;
89
94
  for (const line of lines) {
90
- if (/^\[mcp_servers\./.test(line)) {
91
- inMcp = true;
92
- continue;
93
- }
94
- if (inMcp && /^\[/.test(line) && !/^\[mcp_servers\./.test(line)) {
95
- inMcp = false;
95
+ const header = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/.exec(line);
96
+ if (header) {
97
+ removeSection = false;
98
+ const section = header[1];
99
+ if (section.startsWith('mcp_servers.')) {
100
+ const suffix = section.slice('mcp_servers.'.length);
101
+ const quoted = /^("(?:\\.|[^"\\])*")(?=\.|$)/.exec(suffix);
102
+ const literal = /^'([^']+)'(?=\.|$)/.exec(suffix);
103
+ const bare = /^([^\.\s]+)(?=\.|$)/.exec(suffix);
104
+ const name = quoted ? JSON.parse(quoted[1]) : literal?.[1] ?? bare?.[1];
105
+ removeSection = name !== undefined && emittedNames.has(name);
106
+ }
96
107
  }
97
- if (!inMcp)
108
+ if (!removeSection)
98
109
  output.push(line);
99
110
  }
100
111
  // Remove trailing blank lines before appending MCP section
@@ -143,7 +154,8 @@ export function syncToAll(config) {
143
154
  if (fs.existsSync(codexPath)) {
144
155
  const existing = fs.readFileSync(codexPath, 'utf8');
145
156
  const mcpToml = toCodexToml(config);
146
- fs.writeFileSync(codexPath, patchCodexToml(existing, mcpToml));
157
+ const emittedNames = new Set(Object.keys(config.servers ?? {}).filter(name => name !== COMPUTER_USE_MCP_NAME));
158
+ fs.writeFileSync(codexPath, patchCodexToml(existing, mcpToml, emittedNames));
147
159
  results.codex = true;
148
160
  console.log(`[mcp-sync] ✅ Codex: ${codexPath}`);
149
161
  }
@@ -197,7 +209,7 @@ export function syncToAll(config) {
197
209
  existing = JSON.parse(fs.readFileSync(copilotPath, 'utf8'));
198
210
  }
199
211
  catch { }
200
- existing["mcpServers"] = copilotData.mcpServers;
212
+ existing["mcpServers"] = { ...(existing["mcpServers"] ?? {}), ...copilotData.mcpServers };
201
213
  fs.writeFileSync(copilotPath, JSON.stringify(existing, null, 4) + '\n');
202
214
  results.copilot = true;
203
215
  console.log(`[mcp-sync] ✅ Copilot: ${copilotPath}`);
@@ -216,7 +228,7 @@ export function syncToAll(config) {
216
228
  existing = JSON.parse(fs.readFileSync(cursorPath, 'utf8'));
217
229
  }
218
230
  catch { }
219
- existing["mcpServers"] = cursorData.mcpServers;
231
+ existing["mcpServers"] = { ...(existing["mcpServers"] ?? {}), ...cursorData.mcpServers };
220
232
  fs.writeFileSync(cursorPath, JSON.stringify(existing, null, 4) + '\n');
221
233
  results.cursor = true;
222
234
  console.log(`[mcp-sync] ✅ Cursor: ${cursorPath}`);
@@ -234,7 +246,7 @@ export function syncToAll(config) {
234
246
  existing = JSON.parse(fs.readFileSync(antigravityPath, 'utf8'));
235
247
  }
236
248
  catch { }
237
- existing["mcpServers"] = antigravityData.mcpServers;
249
+ existing["mcpServers"] = { ...(existing["mcpServers"] ?? {}), ...antigravityData.mcpServers };
238
250
  fs.writeFileSync(antigravityPath, JSON.stringify(existing, null, 4) + '\n');
239
251
  results.antigravity = true;
240
252
  console.log(`[mcp-sync] ✅ Antigravity: ${antigravityPath}`);