@frontendxlab/opencode-computer-use 0.1.4 → 0.1.5

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ ## 0.1.5 — 2026-10-30
4
+
5
+ ### Setup and discovery
6
+
7
+ - Register a development checkout with `opencode-computer-use-setup --source .`.
8
+ - Use backed-up JSON/JSONC edits for both global and local setup instead of
9
+ assuming a particular OpenCode plugin-management subcommand.
10
+ - Reject invalid JSONC and conflicting V1/V2 configurations before writing.
11
+ - Preserve pinned npm entries, avoid duplicate registration across configuration
12
+ files, retain options when switching to a checkout, and preserve backups on
13
+ unchanged runs.
14
+ - Return failure for unsuccessful manual setup while keeping dependency
15
+ postinstall best-effort.
16
+ - Recognize Windows executable/environment-name conventions and resolve npm
17
+ native-runtime shims without invoking a shell for desktop control.
18
+ - Include guided desktop prerequisite onboarding when lifecycle scripts run.
19
+
20
+ ### Runtime fixes
21
+
22
+ - Enforce an empty deny-by-default app policy before native app binding.
23
+ - Emit filtered `getState()` and `listApps()` inventories by default and honor
24
+ `emit: false` without exposing denied apps.
25
+ - Handle native stdio failures as controlled transport errors and clean up the
26
+ owned child process.
27
+ - Parse executable import syntax instead of rejecting the word `import` inside
28
+ typed text, strings, comments, regexes, and ordinary property names. Executable
29
+ imports and the existing VM restrictions remain blocked.
30
+ - Make REPL `--help` exit without starting native automation, and report startup
31
+ configuration failures without an uncaught stack trace.
32
+
33
+ ### Verification and documentation
34
+
35
+ - Add regressions for the setup, policy, inventory, transport, import, and CLI
36
+ failures above.
37
+ - Add an opt-in real OpenCode smoke test with isolated settings and fake/native
38
+ startup modes, plus a Linux/macOS/Windows CI integration job pinned to 1.19.3.
39
+ - Document checkout installation, correct scoped npm executable commands,
40
+ registration troubleshooting, per-device installation, and server-host scope.
41
+ - Correct WebMCP API-reference lookups for method names with signatures.
42
+
43
+ ### Support boundaries
44
+
45
+ The adapter controls the desktop of the machine running its local MCP process.
46
+ This release does not add remote device pairing, a network transport, or mobile
47
+ native runtimes. Linux x64 registration, read-only discovery, and semantic click
48
+ and text-value actions in a disposable GTK fixture are exercised locally.
49
+ Screenshots were unavailable in the tested GNOME Wayland session. Packaged
50
+ macOS/Windows runtimes still require live desktop validation;
51
+ headless adapter or CLI tests do not certify screenshot/input behavior. Wayland
52
+ capture and synthetic input remain dependent on the compositor and target app.
package/README.md CHANGED
@@ -3,6 +3,9 @@
3
3
  A dual-generation OpenCode plugin that provides a Codex-style Computer Use
4
4
  session.
5
5
 
6
+ It registers a local MCP server named `cua_repl` with two tools, `js` and
7
+ `js_reset`. It does not add a slash command or a dedicated OpenCode panel.
8
+
6
9
  Documentation: https://opencode-computer-use.pages.dev/
7
10
 
8
11
  The model does not receive a pile of low-level desktop MCP tools. It receives a
@@ -51,25 +54,34 @@ The optional `open-computer-use@0.3.5` package ships native runtimes for:
51
54
  - `linux-arm64`, `linux-x64`
52
55
  - `win32-arm64`, `win32-x64`
53
56
 
54
- The current project has been exercised against the Linux runtime contract. macOS
55
- and Windows support is provided by the upstream native packages, but live
56
- permission and desktop validation must still be run on those operating systems.
57
+ The repository CI is configured to test the adapter headlessly on Linux, macOS,
58
+ and Windows through a GitHub Actions matrix. The native package publishes binaries for the six targets
59
+ above. Live accessibility, capture, focus, and input behavior still depends on
60
+ the host desktop session and must be validated on each operating system.
57
61
 
58
62
  ### Validation status
59
63
 
60
- - Linux x64 native discovery, read-only app listing, MCP registration, and the
61
- persistent JavaScript session have passed local smoke tests.
62
- - The current Ubuntu/GNOME Wayland session exposed a Chrome pseudo-window whose
63
- AT-SPI tree had no actionable children. The native Linux runtime accepted
64
- coordinate and keyboard requests, but those synthetic events did not change
65
- that window. The adapter reports the native result rather than claiming that
66
- an unsupported input path worked.
67
- - macOS and Windows have not been live-tested in this environment. Their
68
- accessibility, screen-capture, foreground, and OS permission behavior must be
69
- verified on those operating systems.
70
-
71
- The Codex-style surface is portable, but the native runtime's desktop
72
- capabilities remain OS and session dependent.
64
+ - The JavaScript adapter, MCP registration, sandbox, timeout recovery, setup,
65
+ packaging, and fake-native integration suite are designed to run on Linux,
66
+ macOS, and Windows without a graphical desktop.
67
+ - Linux x64 native discovery, app listing, actual OpenCode 1.19.3 registration,
68
+ persistent JavaScript bindings, and session reset passed local smoke tests.
69
+ - On 2026-10-30, a disposable GTK 3 window in Ubuntu/GNOME Wayland exposed an
70
+ actionable accessibility tree. An element-index click changed its counter
71
+ from 0 to 1, and `setValue` changed its text field; both results were checked
72
+ against fresh accessibility state and the test application's own state.
73
+ - Screenshot capture for that window returned `Screenshot unavailable`.
74
+ Keyboard/coordinate input was not certified. Other apps may expose incomplete
75
+ accessibility trees, and Wayland capture/input behavior remains app- and
76
+ compositor-dependent. See the dated record in `docs/NATIVE_VALIDATION.md`.
77
+ - macOS and Windows native desktop behavior has not been live-certified from
78
+ this development machine. Their accessibility, screen-capture, foreground,
79
+ and OS permission behavior must still be verified on real interactive hosts.
80
+
81
+ The Codex-style surface is portable across the published x64/ARM64 desktop
82
+ targets, but native desktop capabilities remain OS, permission, display-server,
83
+ and session dependent. Other CPU/OS combinations fail with an explicit target
84
+ diagnostic and can use a compatible custom backend.
73
85
 
74
86
  ## Requirements
75
87
 
@@ -81,9 +93,34 @@ capabilities remain OS and session dependent.
81
93
  - Linux AT-SPI and the input/capture services required by the native runtime.
82
94
  - Windows UI Automation in the current interactive desktop session.
83
95
 
96
+ The V1 integration has been exercised with OpenCode 1.19.3. The V2 entrypoint
97
+ has adapter contract tests; a real OpenCode2 installation remains a separate
98
+ integration check. A native runtime's successful `doctor` exit is a prerequisite
99
+ check, not proof that screenshots, focus, or input work in a particular app.
100
+
84
101
  The plugin cannot control a lock screen, login screen, UAC secure desktop, or
85
102
  other OS-owned consent surface. It does not bypass permissions.
86
103
 
104
+ ## Which computer is controlled?
105
+
106
+ The controlled desktop belongs to the machine running the OpenCode **server
107
+ and its MCP child process**. There is no built-in device discovery, pairing,
108
+ remote desktop transport, or session synchronization.
109
+
110
+ | Setup | Desktop controlled |
111
+ | --- | --- |
112
+ | OpenCode runs on computer A | Computer A's signed-in graphical session. |
113
+ | A browser or attached OpenCode client on B connects to the server on A | Still computer A. |
114
+ | Install and run OpenCode plus this plugin separately on B | Computer B, after its own runtime and permission checks. |
115
+ | Copy a configuration containing A's absolute paths to B | Paths must be re-created for B; configuration alone does not install the runtime. |
116
+
117
+ Cross-platform support means separate installations on the packaged macOS,
118
+ Linux, and Windows targets. Android and iOS are not native targets. Containers,
119
+ WSL, SSH sessions, and background services do not automatically expose another
120
+ machine's or the host operating system's interactive desktop. A custom backend
121
+ must implement the native protocol; selecting `custom` does not add remote
122
+ device support by itself.
123
+
87
124
  ## Install
88
125
 
89
126
  The published package is `@frontendxlab/opencode-computer-use`. It registers a
@@ -102,12 +139,18 @@ When both generations are installed, it uses an existing `plugin` or `plugins`
102
139
  configuration to disambiguate. If that is not possible, it makes no change and
103
140
  prints both manual configuration formats.
104
141
 
142
+ Both local and global setup use a backed-up JSON/JSONC edit. Setup does not
143
+ depend on a version-specific `opencode plugin add` command. A project install
144
+ affects that project; use `--global` to configure all projects for the current
145
+ user. Package installation and OpenCode registration are separate steps when
146
+ lifecycle scripts are disabled.
147
+
105
148
  You can run setup explicitly at any time:
106
149
 
107
150
  ```sh
108
- npx opencode-computer-use-setup
109
- npx opencode-computer-use-setup --local --v2
110
- npx opencode-computer-use-setup --global --v1
151
+ npm exec --package=@frontendxlab/opencode-computer-use -- opencode-computer-use-setup --local --v1
152
+ npm exec --package=@frontendxlab/opencode-computer-use -- opencode-computer-use-setup --local --v2
153
+ npm exec --package=@frontendxlab/opencode-computer-use -- opencode-computer-use-setup --global --v1
111
154
  ```
112
155
 
113
156
  Use `--dry-run` to inspect the action without changing files. Set
@@ -115,21 +158,30 @@ Use `--dry-run` to inspect the action without changing files. Set
115
158
  skips automatically when `CI=1` or `CI=true`. Restart OpenCode after a
116
159
  successful setup so the plugin is loaded.
117
160
 
118
- The postinstall flow also runs the native permission check. To rerun it later:
161
+ Explicit setup returns a nonzero exit status when it fails; automatic dependency
162
+ `postinstall` remains best-effort and prints manual instructions. Check the
163
+ reported configuration path. The shorthand `npx opencode-computer-use-setup`
164
+ only selects this package's executable when it is already installed locally;
165
+ the scoped `npm exec --package=...` form above also works from a fresh directory.
166
+
167
+ Starting with v0.1.5, desktop prerequisite onboarding is part of `postinstall` when lifecycle scripts are allowed.
168
+ After OpenCode configuration, the installer runs `opencode-computer-use-permissions --install`:
169
+
170
+ - macOS runs the native `doctor` check and opens the Open Computer Use onboarding/System Settings when Accessibility or Screen Recording is missing. Apple still requires the user to click the protected privacy toggles.
171
+ - GNOME Linux best-effort enables `org.gnome.desktop.interface toolkit-accessibility` and then runs the native AT-SPI/session check. Other Linux desktops get diagnostics without changing desktop settings.
172
+ - Windows runs the UI Automation/session check. Windows has no separate UI Automation permission toggle; it must run in the signed-in interactive desktop session.
173
+
174
+ Rerun the guided check at any time:
119
175
 
120
176
  ```sh
121
- npx opencode-computer-use-permissions
177
+ npm exec --package=@frontendxlab/opencode-computer-use -- opencode-computer-use-permissions --strict
122
178
  # or, from a pnpm project
123
- pnpm exec opencode-computer-use-permissions
179
+ pnpm exec opencode-computer-use-permissions --strict
124
180
  ```
125
181
 
126
- The command delegates to the native `open-computer-use doctor` flow. macOS runs
127
- the native Accessibility and Screen Recording onboarding when needed. Linux
128
- reports AT-SPI and desktop-session requirements. Windows reports UI Automation
129
- and interactive-session requirements. The command never changes permissions
130
- automatically. Use `--strict` when a missing or failed native
131
- check should return a nonzero exit status, or set
132
- `OPENCODE_COMPUTER_USE_SKIP_PERMISSIONS=1` to skip it.
182
+ Set `OPENCODE_COMPUTER_USE_SKIP_PERMISSIONS=1` to skip install-time desktop onboarding.
183
+ CI and package-development installs skip it automatically. The helper never bypasses macOS TCC,
184
+ Windows secure desktops, or other OS permission boundaries.
133
185
 
134
186
  Recent pnpm releases may require explicit approval before running lifecycle
135
187
  scripts from dependencies. If pnpm reports `ERR_PNPM_IGNORED_BUILDS`, approve
@@ -142,8 +194,30 @@ pnpm install
142
194
 
143
195
  If scripts are intentionally disabled, run `pnpm exec opencode-computer-use-setup` manually instead.
144
196
 
145
- A local checkout can be loaded by replacing the package name with its absolute
146
- path.
197
+ ### Run this checkout
198
+
199
+ Cloning this repository does not register it in OpenCode. A development
200
+ `npm install` intentionally skips the automatic configuration and desktop
201
+ onboarding hooks. Run these commands from the checkout:
202
+
203
+ ```sh
204
+ npm ci --ignore-scripts
205
+ node bin/opencode-computer-use-setup.js --local --v1 --source .
206
+ node bin/opencode-computer-use-permissions.js --strict
207
+ opencode mcp list
208
+ ```
209
+
210
+ Close and reopen an already-running OpenCode session. The MCP list should show
211
+ `cua_repl` as connected. To make this checkout available to all projects, replace
212
+ `--local` with `--global`. For OpenCode2, select `--v2` and use that runtime's MCP
213
+ status command. The `--source` flag accepts a directory, an entrypoint file, or
214
+ a file URL and writes the canonical absolute `file://` URL. It requires this
215
+ checkout's updated setup script; an older published package may not have it.
216
+
217
+ The generated local `opencode.json` is machine-specific and ignored by this
218
+ repository. Re-run setup on a second computer rather than copying its absolute
219
+ path. Install dependencies on that computer; do not copy `node_modules` between
220
+ operating systems or CPU architectures.
147
221
 
148
222
  ### OpenCode 1
149
223
 
@@ -233,6 +307,29 @@ syntax:
233
307
  The custom command must implement the native MCP operations used by `cua`:
234
308
  `initialize`, `tools/list`, `tools/call`, and notifications.
235
309
 
310
+ If plugin loading is unavailable in your host version, the same REPL can also
311
+ be registered directly as a local MCP server. Use exactly one registration:
312
+
313
+ ```json
314
+ {
315
+ "mcp": {
316
+ "cua_repl": {
317
+ "type": "local",
318
+ "command": ["node", "/absolute/path/to/opencode-computer-use/bin/opencode-computer-use-repl.js"],
319
+ "environment": {
320
+ "OPENCODE_COMPUTER_USE_SAFETY_MODE": "read-only"
321
+ },
322
+ "enabled": true
323
+ }
324
+ }
325
+ }
326
+ ```
327
+
328
+ This example uses read-only mode for initial validation. Replace the path with
329
+ the actual installed checkout path, and use an absolute Node path if the host
330
+ cannot resolve `node`. Plugin options do not apply to a separately configured
331
+ MCP server; use the matching environment variables in that case.
332
+
236
333
  ## Model workflow
237
334
 
238
335
  The `js` tool accepts:
@@ -272,6 +369,10 @@ The `cua` API includes:
272
369
  - `app.setValue(elementIndex, value)`
273
370
  - `app.performSecondaryAction(elementIndex, action)`
274
371
 
372
+ `cua.getState()` and `cua.listApps()` emit the permitted app inventory by default.
373
+ Use `{ emit: false }` when assigning it to a variable and writing your own output.
374
+ Both the returned inventory and its visible output honor `appAccess` rules.
375
+
275
376
  Use `nodeRepl.write(value)` for text output and
276
377
  `await nodeRepl.emitImage(bytesOrDataUrl)` for screenshots or other images.
277
378
 
@@ -334,24 +435,50 @@ Policy, and a compatible browser or Cloudflare Browser Run lab session.
334
435
  Before asking an agent to act, run the native runtime's read-only checks:
335
436
 
336
437
  ```bash
337
- open-computer-use doctor
338
- open-computer-use list-apps
438
+ npm exec --package=open-computer-use@0.3.5 -- open-computer-use doctor
439
+ npm exec --package=open-computer-use@0.3.5 -- open-computer-use list-apps
339
440
  ```
340
441
 
341
442
  The first screenshot may trigger a desktop permission dialog. A screenshot,
342
443
  accessibility tree, or typed value can contain sensitive data and should stay
343
444
  local.
344
445
 
446
+ ## Troubleshooting registration and desktop access
447
+
448
+ | Symptom | Check and remedy |
449
+ | --- | --- |
450
+ | No `cua_repl` in OpenCode | Run setup for the right project/global scope and generation, check its printed config path, then restart OpenCode and run `opencode mcp list`. A clone or dependency install by itself is not registration. |
451
+ | Installed from npm but new fixes are missing | Compare `npm view @frontendxlab/opencode-computer-use version` with the checkout's `package.json`. Use `--source .` to test the checkout before publication. |
452
+ | `--pure` / `OPENCODE_PURE` is enabled | OpenCode deliberately skips external plugins. Start it with plugins enabled. |
453
+ | An existing `cua_repl` entry is disabled or points elsewhere | The plugin preserves that entry by default. Correct it, or explicitly use the plugin's `override: true` option after reviewing the replacement. |
454
+ | `node` cannot be found | Set `OPENCODE_NODE` to the absolute Node executable in the environment that starts OpenCode. A desktop launcher may have a different `PATH` from a terminal. |
455
+ | Native runtime unavailable | Install the optional `open-computer-use@0.3.5` dependency; check whether the package manager omitted optional packages. Run the permissions helper from the same graphical session. |
456
+ | `cua_repl` connects but the app list is empty | Verify the signed-in desktop/session and accessibility prerequisites. An MCP handshake does not prove native app access. |
457
+ | Linux actions return but the app does not change | Refresh accessibility state and verify the result. Wayland may block synthetic input or capture; prefer semantic AT-SPI actions when the app exposes them. |
458
+ | Works on one computer but not another | Install on each supported desktop and re-run its permission/session checks. Absolute paths, environment, architecture, and app accessibility differ. |
459
+
460
+ For Windows npm command shims, the backend resolves the adjacent packaged native
461
+ `.exe` without invoking a shell. A nonstandard `.cmd`/`.bat` installation without
462
+ that executable must use an absolute native `OPEN_COMPUTER_USE_NATIVE_COMMAND`.
463
+
345
464
  ## Development
346
465
 
347
466
  ```bash
348
- npm install
467
+ npm ci --ignore-scripts
349
468
  npm test
350
469
  npm run lint
470
+ npm run test:opencode
351
471
  ```
352
472
 
353
473
  The adapter tests use a fake native MCP server and never require a real desktop.
354
- Live desktop validation must be run separately on each supported OS.
474
+ The repository CI is configured to run them on Linux, macOS, and Windows across
475
+ the declared Node compatibility matrix. `test:opencode` additionally requires an
476
+ installed OpenCode CLI and checks actual plugin registration/MCP startup in an
477
+ isolated configuration with a fake native backend. Use `npm run test:opencode --
478
+ --native` on an interactive host to check registration with its native backend.
479
+ Neither smoke test sends desktop input. Live desktop validation remains a separate release check for native input,
480
+ capture, focus, and accessibility behavior.
481
+ Use `docs/NATIVE_VALIDATION.md` for the per-OS certification checklist.
355
482
 
356
483
  ## License and attribution
357
484
 
package/SECURITY.md CHANGED
@@ -28,8 +28,12 @@ sandbox.
28
28
  conflicting or malformed configuration. Ambiguous setup is non-destructive
29
29
  and prints manual instructions. CI and explicit skip environments bypass
30
30
  postinstall mutation.
31
- - The permission command delegates to the native runtime's `doctor` flow. It
32
- may open macOS onboarding, but it never grants or changes permissions.
31
+ - Install-time permission onboarding is guided and best-effort. The postinstall
32
+ hook delegates to the native runtime's `doctor` flow. On macOS it may open
33
+ Accessibility/Screen Recording onboarding, but the protected TCC toggles still
34
+ require user approval. On GNOME Linux it may enable toolkit accessibility.
35
+ Windows only validates UI Automation/session requirements. The installer never
36
+ bypasses OS permission boundaries or grants protected permissions silently.
33
37
 
34
38
  ## Operator responsibilities
35
39
 
@@ -18,6 +18,10 @@ The automatic setup command uses `jsonc-parser@3.3.1`, copyright Microsoft
18
18
  Corporation and contributors, under the MIT license. It is used only to make
19
19
  targeted edits to OpenCode JSONC configuration files.
20
20
 
21
+ The import-syntax guard uses `acorn@8.19.0` under the MIT license to parse
22
+ JavaScript without executing it. Acorn's license is included in its separately
23
+ installed dependency package.
24
+
21
25
  The adapter was changed to resolve the optional runtime package, use a
22
26
  minimal desktop environment allowlist, expose the session through the
23
27
  OpenCode plugin entrypoint, and run model code in a restricted VM context.
@@ -11,35 +11,84 @@ const SKIP_ENV = "OPENCODE_COMPUTER_USE_SKIP_PERMISSIONS";
11
11
  const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
12
 
13
13
  function print(text, stream = "stdout") {
14
- process[stream].write(`${text}\n`);
14
+ process[stream].write(String(text) + "\n");
15
15
  }
16
16
 
17
17
  export function usage() {
18
- return `Usage: opencode-computer-use-permissions [options]
19
-
20
- Run the native Open Computer Use permission and runtime onboarding check.
21
-
22
- Options:
23
- --strict Return a failure when the native check cannot run
24
- --help, -h Show this help
25
-
26
- The command uses the installed open-computer-use runtime:
27
- macOS checks or launches Accessibility and Screen Recording onboarding
28
- Linux reports AT-SPI and signed-in desktop-session requirements
29
- Windows reports UI Automation and interactive-session requirements
30
- `;
18
+ return [
19
+ "Usage: opencode-computer-use-permissions [options]",
20
+ "",
21
+ "Run the native Open Computer Use permission and runtime onboarding check.",
22
+ "",
23
+ "Options:",
24
+ " --install Guided install mode used by the package postinstall hook",
25
+ " --strict Return a failure when the native check cannot run",
26
+ " --help, -h Show this help",
27
+ "",
28
+ "The command uses the installed open-computer-use runtime:",
29
+ " macOS checks or launches Accessibility and Screen Recording onboarding.",
30
+ " macOS still requires the user to approve protected TCC toggles.",
31
+ " Linux checks AT-SPI and the signed-in desktop session. On GNOME, install",
32
+ " mode best-effort enables toolkit accessibility with gsettings.",
33
+ " Windows checks UI Automation and the interactive signed-in desktop session.",
34
+ ].join("\n");
31
35
  }
32
36
 
33
37
  function parseArguments(argv) {
34
- const options = { strict: false, help: false };
38
+ const options = { install: false, strict: false, help: false };
35
39
  for (const argument of argv) {
36
- if (argument === "--strict") options.strict = true;
40
+ if (argument === "--install") options.install = true;
41
+ else if (argument === "--strict") options.strict = true;
37
42
  else if (argument === "--help" || argument === "-h") options.help = true;
38
- else throw new Error(`Unknown permission option: ${argument}`);
43
+ else throw new Error("Unknown permission option: " + argument);
39
44
  }
40
45
  return options;
41
46
  }
42
47
 
48
+ export function platformGuidance(platform = process.platform) {
49
+ if (platform === "darwin") {
50
+ return [
51
+ "macOS permission setup:",
52
+ " - Requires macOS 14 or newer.",
53
+ " - Open Computer Use needs Accessibility and Screen Recording.",
54
+ " - The installer runs the native doctor; if either permission is missing,",
55
+ " the Open Computer Use onboarding window opens and guides you to System Settings.",
56
+ " - macOS requires a human approval for these protected TCC permissions.",
57
+ " - Manual: open-computer-use doctor",
58
+ ' - Accessibility pane: open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"',
59
+ ' - Screen Recording pane: open "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"',
60
+ ];
61
+ }
62
+ if (platform === "linux") {
63
+ return [
64
+ "Linux desktop setup:",
65
+ " - There is no macOS-style permission dialog.",
66
+ " - Open Computer Use needs a signed-in graphical session with AT-SPI2/D-Bus.",
67
+ " - On GNOME, install mode best-effort enables toolkit accessibility with:",
68
+ " gsettings set org.gnome.desktop.interface toolkit-accessibility true",
69
+ " - Wayland screenshot and coordinate input support remains compositor-dependent.",
70
+ " - Manual verification: open-computer-use doctor && open-computer-use call list_apps",
71
+ ];
72
+ }
73
+ if (platform === "win32") {
74
+ return [
75
+ "Windows desktop setup:",
76
+ " - There is no separate UI Automation permission toggle to grant.",
77
+ " - Open Computer Use must run in the signed-in interactive desktop session.",
78
+ " - Detached services/session 0 cannot control the user's desktop.",
79
+ " - Manual verification: open-computer-use doctor && open-computer-use call list_apps",
80
+ ];
81
+ }
82
+ return [
83
+ "Desktop permission setup is not defined for " + platform + ".",
84
+ "Use a supported macOS, Linux, or Windows native runtime.",
85
+ ];
86
+ }
87
+
88
+ function printPlatformGuidance(platform, io) {
89
+ for (const line of platformGuidance(platform)) io(line);
90
+ }
91
+
43
92
  function shouldSkip(env) {
44
93
  const developmentInstall = env.npm_lifecycle_event === "postinstall"
45
94
  && env.INIT_CWD
@@ -47,15 +96,67 @@ function shouldSkip(env) {
47
96
  return developmentInstall || env.CI === "true" || env.CI === "1" || env[SKIP_ENV] === "1";
48
97
  }
49
98
 
99
+ function commandAvailable(command, env) {
100
+ const result = spawnSync(command, ["--version"], {
101
+ env,
102
+ stdio: "ignore",
103
+ windowsHide: true,
104
+ timeout: 5_000,
105
+ });
106
+ return !result.error && result.status === 0;
107
+ }
108
+
109
+ function maybeEnableGnomeAccessibility(env, io) {
110
+ const desktop = ((env.XDG_CURRENT_DESKTOP || "") + " " + (env.DESKTOP_SESSION || "")).toLowerCase();
111
+ if (!desktop.includes("gnome")) {
112
+ io("Linux accessibility auto-enable skipped: GNOME was not detected; AT-SPI will be verified by the native runtime.");
113
+ return;
114
+ }
115
+ if (!commandAvailable("gsettings", env)) {
116
+ io("Linux accessibility auto-enable skipped: gsettings is unavailable.");
117
+ return;
118
+ }
119
+ const result = spawnSync(
120
+ "gsettings",
121
+ ["set", "org.gnome.desktop.interface", "toolkit-accessibility", "true"],
122
+ {
123
+ env,
124
+ encoding: "utf8",
125
+ windowsHide: true,
126
+ timeout: 10_000,
127
+ },
128
+ );
129
+ if (result.error || result.status !== 0) {
130
+ io("Linux accessibility auto-enable could not update GNOME settings. Run the documented gsettings command manually.");
131
+ return;
132
+ }
133
+ io("GNOME toolkit accessibility enabled.");
134
+ }
135
+
136
+ function printInstallSessionHint(platform, env, io) {
137
+ if (platform === "linux") {
138
+ io("Desktop: " + (env.XDG_CURRENT_DESKTOP || env.DESKTOP_SESSION || "unknown")
139
+ + "; session: " + (env.XDG_SESSION_TYPE || "unknown") + ".");
140
+ if (!env.DBUS_SESSION_BUS_ADDRESS) {
141
+ io("No DBUS_SESSION_BUS_ADDRESS is visible to the installer; the native runtime will try to discover the signed-in user's session automatically.");
142
+ }
143
+ } else if (platform === "win32") {
144
+ io("Windows session: " + (env.SESSIONNAME || "unknown")
145
+ + ". UI Automation requires the signed-in interactive desktop.");
146
+ }
147
+ }
148
+
50
149
  export function main(argv = process.argv.slice(2), env = process.env, io = print) {
51
150
  let options;
52
151
  try {
53
152
  options = parseArguments(argv);
54
153
  } catch (error) {
55
- io(`[opencode-computer-use-permissions] ${error instanceof Error ? error.message : String(error)}`, "stderr");
154
+ io("[opencode-computer-use-permissions] "
155
+ + (error instanceof Error ? error.message : String(error)), "stderr");
56
156
  io(usage(), "stderr");
57
157
  return 2;
58
158
  }
159
+
59
160
  if (options.help) {
60
161
  io(usage());
61
162
  return 0;
@@ -65,12 +166,19 @@ export function main(argv = process.argv.slice(2), env = process.env, io = print
65
166
  return 0;
66
167
  }
67
168
 
169
+ if (options.install) {
170
+ io("OpenCode Computer Use is checking desktop prerequisites as part of installation.");
171
+ printPlatformGuidance(process.platform, io);
172
+ printInstallSessionHint(process.platform, env, io);
173
+ if (process.platform === "linux") maybeEnableGnomeAccessibility(env, io);
174
+ }
175
+
68
176
  let backend;
69
177
  try {
70
178
  backend = resolveBackend({ backend: "native" }, env);
71
179
  } catch (error) {
72
180
  const message = error instanceof Error ? error.message : String(error);
73
- io(`[opencode-computer-use-permissions] Native permission check unavailable: ${message}`);
181
+ io("[opencode-computer-use-permissions] Native permission check unavailable: " + message);
74
182
  if (options.strict) return 1;
75
183
  io("Install the optional open-computer-use runtime, then run this command again.");
76
184
  return 0;
@@ -83,13 +191,18 @@ export function main(argv = process.argv.slice(2), env = process.env, io = print
83
191
  timeout: 120_000,
84
192
  });
85
193
  if (result.error) {
86
- io(`[opencode-computer-use-permissions] Permission check failed: ${result.error.message}`);
194
+ io("[opencode-computer-use-permissions] Permission check failed: " + result.error.message);
87
195
  return options.strict ? 1 : 0;
88
196
  }
89
197
  if (result.status !== 0) {
90
- io(`[opencode-computer-use-permissions] Native permission check exited with status ${result.status}.`);
198
+ io("[opencode-computer-use-permissions] Native permission check exited with status "
199
+ + result.status + ".");
91
200
  return options.strict ? 1 : 0;
92
201
  }
202
+ if (options.install) {
203
+ io("Desktop onboarding check complete.");
204
+ io("You can rerun it any time with: npx opencode-computer-use-permissions --strict");
205
+ }
93
206
  return 0;
94
207
  }
95
208
 
@@ -2,11 +2,33 @@
2
2
 
3
3
  import { resolveNativeCommand, runServer } from "../lib/repl.mjs";
4
4
 
5
- const native = resolveNativeCommand(process.argv.slice(2));
6
- runServer(native).catch((error) => {
5
+ const argv = process.argv.slice(2);
6
+ const help = `Usage: opencode-computer-use-repl [-- native-command [args...]]
7
+
8
+ Start the local stdio MCP server exposing js and js_reset.
9
+ With no command override, use the configured open-computer-use native runtime.
10
+
11
+ Options:
12
+ --help, -h Show this help without starting the native runtime
13
+
14
+ Configuration: OPENCODE_COMPUTER_USE_* environment variables.
15
+ Desktop access requires the server host's signed-in graphical session.
16
+ `;
17
+
18
+ try {
19
+ if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h")) {
20
+ process.stdout.write(help);
21
+ } else {
22
+ if (argv.length > 0 && argv[0] !== "--") {
23
+ throw new Error(`Unknown REPL option: ${argv[0]}. Use --help or -- followed by a native command.`);
24
+ }
25
+ const native = resolveNativeCommand(argv);
26
+ await runServer(native);
27
+ }
28
+ } catch (error) {
7
29
  const message = (error instanceof Error ? error.message : String(error))
8
30
  .replace(/\b(token|secret|password|api[_-]?key|authorization)\s*[:=]\s*(?:bearer|basic)?[^\n\r,;]*/giu, "$1=[redacted]")
9
31
  .slice(0, 4_000);
10
32
  process.stderr.write(`[opencode-computer-use] ${message}\n`);
11
33
  process.exitCode = 1;
12
- });
34
+ }