moondesk 0.9.3 → 0.9.4
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/README.md +27 -6
- package/npm/install-binary.js +1 -1
- package/npm/moondesk.js +21 -0
- package/package.json +3 -2
- package/skills/browser/SKILL.md +81 -0
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ No reverse engineering. No API key. No separate agent service.
|
|
|
34
34
|
- **Local file tools** — read, search, write, edit, and delete inside a workspace.
|
|
35
35
|
- **Shell commands** — run short commands or start background jobs with polling, preserved output, and cancellation.
|
|
36
36
|
- **Multiple workspaces** — serve several projects from one MoonDesk process, each with its own secret MCP URL.
|
|
37
|
-
- **
|
|
37
|
+
- **Lazy browser control** — a stable `browser_command` + `view_page` surface backed by a pinned Chrome DevTools runtime. Selecting Browser/Both does not launch Chrome; the shared browser session starts only on first use.
|
|
38
38
|
- **Read-only mode** — expose only safe local read tools when mutation is unnecessary.
|
|
39
39
|
- **Cross-platform** — Windows, macOS, and Linux.
|
|
40
40
|
- **Native binary distribution** — install with npm; MoonDesk downloads and verifies the matching release binary on first run.
|
|
@@ -44,7 +44,7 @@ No reverse engineering. No API key. No separate agent service.
|
|
|
44
44
|
|
|
45
45
|
### 1. Install
|
|
46
46
|
|
|
47
|
-
Node.js
|
|
47
|
+
MoonDesk requires Node.js `^20.19.0 || ^22.12.0 || >=23`, matching the pinned browser runtime. Node 21 and Node 22.0-22.11 are not supported.
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
50
|
npm install -g moondesk
|
|
@@ -121,7 +121,7 @@ Each workspace keeps its own file boundary, command jobs, retained output, histo
|
|
|
121
121
|
|
|
122
122
|
Use `[w] Workspaces` to add, rename, inspect, copy, rotate, or remove projects. On Windows, `[b] Explorer` opens the native Explorer folder picker for adding a workspace; `[a] Path` remains available for manual path entry. Launching `moondesk` from another project while a host is already running can attach that directory to the existing host instead of starting another server.
|
|
123
123
|
|
|
124
|
-
Browser control is shared by the host
|
|
124
|
+
Browser control is shared by the host. Workspaces using browser mode share one lazy **isolated agent browser** session that starts only on first use. It never attaches to or reuses your personal browser profile, cookies, or logged-in sessions.
|
|
125
125
|
|
|
126
126
|
Because every workspace shares this host and public tunnel, stopping MoonDesk disconnects all active workspace connectors. Pressing `q` or `Ctrl+C` in the live dashboard therefore opens a shutdown confirmation instead of stopping the host immediately; `Enter` confirms and `Esc` keeps MoonDesk running.
|
|
127
127
|
|
|
@@ -146,9 +146,30 @@ In `multi-tools` mode MoonDesk exposes 12 local tools:
|
|
|
146
146
|
|
|
147
147
|
Use `run_command` for short work. Use `start_command` + `poll_command` for builds, tests, package installs, dev servers, and other long-running commands. Polls long-wait by default and report elapsed, idle, and timeout timing so agents can avoid rapid blind polling.
|
|
148
148
|
|
|
149
|
-
`read-only` mode
|
|
149
|
+
`read-only` mode removes local mutation/shell tools. In Browser/Both mode it still permits bounded browser inspection, while state-changing browser commands and browser file-output flags remain blocked.
|
|
150
150
|
|
|
151
|
-
Browser mode
|
|
151
|
+
Browser mode has a stable tool catalog instead of forwarding the full Chrome DevTools MCP schema:
|
|
152
|
+
|
|
153
|
+
| Browser tool | Purpose |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `browser_command` | Run one browser/DevTools CLI operation in the shared lazy session |
|
|
156
|
+
| `view_page` | Attach the current rendered page directly to the model as bounded image content |
|
|
157
|
+
|
|
158
|
+
For one-off actions, use `browser_command`. Navigate first, set the target viewport, then run `take_snapshot` before element interactions and use UIDs from the latest snapshot. Use `resize_page` for ordinary desktop window sizes. For exact tablet/mobile QA, use `emulate --viewport=390x844x1,mobile,touch` (or another target size); Chromium can clamp very narrow desktop windows, and viewport emulation can recreate the page context, so take a fresh snapshot afterward. For visual layout/rendering checks, use `view_page`; text/accessibility snapshots do not replace pixel inspection.
|
|
159
|
+
|
|
160
|
+
The same `moondesk` CLI also has a `browser` subcommand for deterministic scripted flows in `Both` mode:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
moondesk browser skill
|
|
164
|
+
moondesk browser navigate_page --url=http://localhost:3000
|
|
165
|
+
moondesk browser emulate --viewport=390x844x1,mobile,touch
|
|
166
|
+
moondesk browser take_snapshot
|
|
167
|
+
moondesk browser list_console_messages
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The `browser` subcommand is handled by MoonDesk itself and acts as a lightweight authenticated localhost client to the **running MoonDesk host**. It does not launch a separate browser runtime, so separate shell commands, MCP `browser_command`, and MCP `view_page` all operate on the same host-owned agent-browser session. MoonDesk directly owns the pinned `chrome-devtools-mcp` stdio process tree and its isolated Chromium child instead of relying on the upstream detached CLI daemon. Each agent-browser session uses an isolated temporary profile, so personal cookies/logins are never inherited and browser state is discarded when that session ends. Sensitive network headers are redacted, CrUX URL lookups and usage statistics are disabled, local-file navigation is blocked, and a lost runtime is invalidated so the next browser operation starts a fresh isolated session without replaying the ambiguous failed action.
|
|
171
|
+
|
|
172
|
+
The browser runtime is intentionally pinned to `chrome-devtools-mcp@1.7.0`. Version `1.8.0` changed required CLI argument shapes for commands MoonDesk currently invokes with the 1.7 contract, so upgrading the pin requires an explicit command-contract migration and the full browser regression matrix rather than a blind dependency bump.
|
|
152
173
|
|
|
153
174
|
## Workspace security
|
|
154
175
|
|
|
@@ -192,7 +213,7 @@ On macOS Terminal.app, MoonDesk can manage a dedicated terminal profile. Set `MO
|
|
|
192
213
|
| Tunnel | ngrok |
|
|
193
214
|
| MCP server | Custom implementation |
|
|
194
215
|
| MCP protocol | `2025-11-25` |
|
|
195
|
-
| Browser
|
|
216
|
+
| Browser runtime | pinned `chrome-devtools-mcp@1.7.0` stdio child owned by MoonDesk, started lazily |
|
|
196
217
|
| Distribution | npm + native binaries |
|
|
197
218
|
|
|
198
219
|
## Contributing
|
package/npm/install-binary.js
CHANGED
|
@@ -297,7 +297,7 @@ async function ensureBinary(options = {}) {
|
|
|
297
297
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
298
298
|
|
|
299
299
|
if (typeof fetchImpl !== "function") {
|
|
300
|
-
throw new Error("MoonDesk requires Node.js
|
|
300
|
+
throw new Error("MoonDesk requires Node.js ^20.19.0 || ^22.12.0 || >=23 so the native binary can be downloaded securely");
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
const binaryPath = path.join(installDir, targetInfo.executableName);
|
package/npm/moondesk.js
CHANGED
|
@@ -21,6 +21,18 @@ const {
|
|
|
21
21
|
writePostUpdateNotice,
|
|
22
22
|
} = require("./update-manager");
|
|
23
23
|
|
|
24
|
+
const SUPPORTED_NODE_RANGE = "^20.19.0 || ^22.12.0 || >=23";
|
|
25
|
+
|
|
26
|
+
function isSupportedNodeVersion(version = process.versions.node) {
|
|
27
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version));
|
|
28
|
+
if (!match) return false;
|
|
29
|
+
const major = Number(match[1]);
|
|
30
|
+
const minor = Number(match[2]);
|
|
31
|
+
if (major === 20) return minor >= 19;
|
|
32
|
+
if (major === 22) return minor >= 12;
|
|
33
|
+
return major >= 23;
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
function cleanManagedUpdateEnv(source = process.env) {
|
|
25
37
|
const env = { ...source };
|
|
26
38
|
delete env.MOONDESK_NPM_MANAGED;
|
|
@@ -109,6 +121,13 @@ function nativeStartFailureHints(error, binaryPath, options = {}) {
|
|
|
109
121
|
|
|
110
122
|
async function orchestrate(options = {}) {
|
|
111
123
|
const logger = options.logger ?? console;
|
|
124
|
+
const nodeVersion = options.nodeVersion ?? process.versions.node;
|
|
125
|
+
if (!isSupportedNodeVersion(nodeVersion)) {
|
|
126
|
+
logger.error(
|
|
127
|
+
`MoonDesk requires Node.js ${SUPPORTED_NODE_RANGE} because the pinned browser runtime does not support Node.js ${nodeVersion}.`,
|
|
128
|
+
);
|
|
129
|
+
return { code: 1, signal: null };
|
|
130
|
+
}
|
|
112
131
|
const originalArgs = options.args ?? process.argv.slice(2);
|
|
113
132
|
const originalCwd = options.cwd ?? process.cwd();
|
|
114
133
|
const baseEnv = cleanManagedUpdateEnv(options.env ?? process.env);
|
|
@@ -341,8 +360,10 @@ if (require.main === module) {
|
|
|
341
360
|
}
|
|
342
361
|
|
|
343
362
|
module.exports = {
|
|
363
|
+
SUPPORTED_NODE_RANGE,
|
|
344
364
|
cleanManagedUpdateEnv,
|
|
345
365
|
cleanupEphemeralUpdateFiles,
|
|
366
|
+
isSupportedNodeVersion,
|
|
346
367
|
orchestrate,
|
|
347
368
|
runNative,
|
|
348
369
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moondesk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "MoonDesk — use ChatGPT Chat as a local coding agent, by Shattermoon.",
|
|
5
5
|
"author": "Shattermoon",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
"npm/moondesk.js",
|
|
20
20
|
"npm/install-binary.js",
|
|
21
21
|
"npm/update-manager.js",
|
|
22
|
+
"skills/browser/SKILL.md",
|
|
22
23
|
"LICENSE",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|
|
25
26
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
27
|
+
"node": "^20.19.0 || ^22.12.0 || >=23"
|
|
27
28
|
},
|
|
28
29
|
"publishConfig": {
|
|
29
30
|
"access": "public",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser
|
|
3
|
+
description: Control MoonDesk's shared Chromium session without exposing the full Chrome DevTools MCP schema to the model.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MoonDesk Browser
|
|
7
|
+
|
|
8
|
+
Use MoonDesk's browser runtime for local web-app inspection, UI testing, console/network debugging, accessibility snapshots, performance checks, and scripted browser flows.
|
|
9
|
+
|
|
10
|
+
## Interfaces
|
|
11
|
+
|
|
12
|
+
- **MCP `browser_command`**: preferred for one browser action at a time and the only browser action primitive needed in Browser-only mode.
|
|
13
|
+
- **MCP `view_page`**: preferred whenever appearance matters. It returns the current rendered page as model-visible pixels.
|
|
14
|
+
- **`moondesk browser` CLI**: preferred in Both mode when several deterministic browser actions are easier to express as a shell script or loop. It calls the same MoonDesk native browser runtime, so it shares the same isolated agent-browser session as MCP without touching the user's personal browser profile.
|
|
15
|
+
|
|
16
|
+
Do not invoke `npx chrome-devtools-mcp` directly. MoonDesk pins and manages the compatible Chrome DevTools runtime.
|
|
17
|
+
|
|
18
|
+
## Core workflow
|
|
19
|
+
|
|
20
|
+
1. Navigate or select the target page.
|
|
21
|
+
2. Set the target viewport before taking interaction UIDs. Use `resize_page` for normal desktop window sizes; use `emulate --viewport=<width>x<height>x<dpr>[,mobile][,touch]` for exact tablet/mobile responsive testing because Chromium may clamp very narrow desktop windows.
|
|
22
|
+
3. After navigation or viewport emulation, run `take_snapshot`. Those operations can recreate the page context, so older UIDs may be stale.
|
|
23
|
+
4. Use snapshot UIDs with `click`, `fill`, `hover`, `drag`, `upload_file`, etc.
|
|
24
|
+
5. Take another snapshot after a state-changing action when the page structure may have changed.
|
|
25
|
+
6. Use `view_page` for visual judgment. Accessibility/text snapshots are structural evidence, not a substitute for seeing the rendered page.
|
|
26
|
+
7. Inspect console/network/performance data when it helps the task; do not collect large traces by default.
|
|
27
|
+
|
|
28
|
+
The browser starts lazily on the first operation. Normal commands reuse the existing session. If the owned browser runtime is lost or a dispatched operation exceeds its deadline, MoonDesk invalidates that runtime before allowing another browser operation; the next call starts a fresh isolated session. MoonDesk does not automatically replay an ambiguous state-changing action, so navigate/select the target page and take a fresh snapshot after session loss.
|
|
29
|
+
|
|
30
|
+
## Local dev-server verification
|
|
31
|
+
|
|
32
|
+
When an agent starts a local web server, browser verification is part of completing the task rather than a separate setup step:
|
|
33
|
+
|
|
34
|
+
1. Wait until the server reports its localhost URL as ready.
|
|
35
|
+
2. Navigate the shared agent browser to that URL.
|
|
36
|
+
3. Set the viewport being tested, then take a fresh snapshot.
|
|
37
|
+
4. Exercise the user-visible flow with snapshot UIDs.
|
|
38
|
+
5. Inspect console/network output when debugging behavior.
|
|
39
|
+
6. Use `view_page` to verify the actual rendered result; do not declare visual success from DOM text alone.
|
|
40
|
+
7. Repeat at the relevant desktop/tablet/mobile viewport when the change is responsive.
|
|
41
|
+
|
|
42
|
+
## Common CLI commands
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
moondesk browser list_pages
|
|
46
|
+
moondesk browser new_page https://example.com
|
|
47
|
+
moondesk browser navigate_page --url=https://example.com
|
|
48
|
+
moondesk browser take_snapshot
|
|
49
|
+
moondesk browser click 1_23 --includeSnapshot
|
|
50
|
+
moondesk browser fill 1_31 "hello"
|
|
51
|
+
moondesk browser press_key Enter --includeSnapshot
|
|
52
|
+
moondesk browser resize_page 1280 800
|
|
53
|
+
moondesk browser emulate --viewport=390x844x1,mobile,touch
|
|
54
|
+
moondesk browser take_snapshot
|
|
55
|
+
moondesk browser list_console_messages
|
|
56
|
+
moondesk browser list_network_requests
|
|
57
|
+
moondesk browser evaluate_script "() => ({title: document.title, href: location.href})"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Use `moondesk browser <command> --help` when a command's positional arguments or flags are unclear.
|
|
61
|
+
|
|
62
|
+
## Scripted flows
|
|
63
|
+
|
|
64
|
+
For repetitive deterministic work in Both mode, keep the browser operations in one shell script instead of spending one MCP schema/tool call per action. Example:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
moondesk browser navigate_page --url=http://localhost:3000
|
|
68
|
+
moondesk browser emulate --viewport=390x844x1,mobile,touch
|
|
69
|
+
moondesk browser take_snapshot
|
|
70
|
+
moondesk browser list_console_messages
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Prefer the CLI for orchestration, but return to `view_page` whenever the task requires actual visual inspection.
|
|
74
|
+
|
|
75
|
+
## Safety and lifecycle
|
|
76
|
+
|
|
77
|
+
- Do not run browser lifecycle commands (`start`, `status`, `stop`) through MCP `browser_command` or `moondesk browser`; the running MoonDesk host owns that lifecycle.
|
|
78
|
+
- `moondesk browser` is a lightweight localhost client to the running MoonDesk host. It does not own a separate browser process; independent shell commands share the same MoonDesk-owned agent-browser session as MCP.
|
|
79
|
+
- ReadOnly mode permits inspection commands only; navigation, JavaScript execution, interaction, uploads, resizing, and other state-changing browser commands are blocked.
|
|
80
|
+
- Treat `evaluate_script` as code execution in the currently selected page. Use it only when needed and keep the function narrowly scoped.
|
|
81
|
+
- Browser file paths are local machine paths. Use verified workspace paths for uploads or file-producing commands.
|