diff --git a/.github/mutant-porte.py b/.github/mutant-porte.py index e17a659f..f8ccc593 100644 --- a/.github/mutant-porte.py +++ b/.github/mutant-porte.py @@ -18,10 +18,14 @@ k = subprocess.run(['node', proeve], capture_output=True, text=True, timeout=600, env={**os.environ, 'TMPDIR': tmp + '/'}) groen[proeve] = k.returncode == 0 except subprocess.TimeoutExpired: - groen[proeve] = False + groen[proeve] = False; k = None finally: shutil.rmtree(tmp, ignore_errors=True) - if not groen[proeve]: print(f"::error::proeven {proeve} er ROED uden mutation - dens mutanter er ikke bevist") + if not groen[proeve]: + print(f"::error::proeven {proeve} er ROED uden mutation - dens mutanter er ikke bevist") + # 30/10 (0.4.1-LISTE #4): uden hvorfor kunne ingen se, at baggrund-mus/stop-alle kun var roede her - vis halen. + ud = ((k.stdout or '') + (k.stderr or '')).splitlines() if k else ['timeout efter 600 s'] + print(f"::group::{proeve} umuteret - de sidste linjer"); print('\n'.join(ud[-40:])); print("::endgroup::") for m in MUTANTER: if not groen.get(m['proeve']): fejl.append(f"{m['navn']}: proeven {m['proeve']} er roed uden mutation"); continue diff --git a/.github/workflows/fremmed-mac.yml b/.github/workflows/fremmed-mac.yml index 1116c052..5aa45490 100644 --- a/.github/workflows/fremmed-mac.yml +++ b/.github/workflows/fremmed-mac.yml @@ -167,6 +167,9 @@ jobs: - name: Mange agenter samtidig id: par continue-on-error: true + # 1/11 (panel R2-R3): parallelproeven hang til jobfristen (41077418047 forsoeg 1); mutationsbeviset blev sprunget + # over, og slutporten afviste koerslen. Et normalt trin tager ~4 min. + timeout-minutes: 30 run: | killall Chess Calculator Contacts "System Settings" "Activity Monitor" Notes Safari "Script Editor" 2>/dev/null || true CMCP_FILM="$RUNNER_TEMP/film" CMCP_PARALLEL_RAPPORT="$RUNNER_TEMP/parallel.json" node test/parallel.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c072e1..36f5abb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,67 @@ # Changelog -Dates are the day the version was tagged. Everything here was measured before it -was written down; where a claim has a test, the test is named. +Newest first. Where a claim has a test, the test is named; what is not measured +says so. + +## 0.4.1 (in progress) + +**The consent box no longer says password apps ask while the agent works in the +background.** In the background they are refused outright, but the box said +"Password apps still always ask". It now says "Password apps stay refused while +it works in the background." The text shown in the foreground was already true. +`test/ikon-godkend.mjs` D2 checks the wording, and fails with the old text. + +**The MIT license ships with the package.** The npm package did not carry +`LICENSE`; it does now (`npm pack` lists it), and the MCPB bundle copies the same +file list. + +**The lockfile was renewed on 1 November.** An `npx` install has no lockfile and +resolves the newest versions in range; on 1 November that was MCP SDK 1.32.2, +with no `npm audit` findings. 0.4.0's lockfile, which the tests and the MCPB +bundle install from, had SDK 1.32.1 and five audit findings (zod, body-parser, +@hono/node-server, fast-uri, qs). It was replaced that day by a fresh +resolution of this version's `package.json`; newer releases in range can +appear after it. The SDK also has to be at least 1.32.1. + +**Several agents at once.** In `test/parallel.mjs`, 5, 10 and 15 agents work in +the background while another test types into TextEdit. An agent that opens a +Finder window brings Finder forward for a moment, and the front is handed +straight back - the longest one that was handed back lasted 2.8 seconds. In +eleven completed runs on GitHub's Mac, on macOS 15.7 and 15.8 alike, it happened twice at +32 of 33 levels; the recording on the front page shows the same thing. In one +of 65 such moments the front could not be handed back: Finder stayed in front +for the rest of that round (at least 40 seconds), and the reply said so +(`gave_back: false`). Under load an agent can also stop and wait when it cannot +tell which app the person is in - it then does nothing - and one run hung until +GitHub's time limit; the cause of the hang is not found. None of this is fixed +in this version. Every word the typing test sent into TextEdit was verified by +the helper (4,939 of 4,939 across the eleven runs); whether keys typed by hand +during such a moment land in Finder is not measured. The test used to blame +whichever agent happened to start during the moment - even one that only +reads - and now judges it on GitHub's Mac the way it already did on a person's +own Mac. + +**Tests.** `test/stille-vej.mjs` gives `scroll --app` a point, as 0.4.0's helper +requires; on a foreign Mac that check had failed on 0.4.0. The mutation gate now +prints the last lines of a test that fails before anything is mutated. +`scripts/release.sh` looks for the CI run in the last 100 runs, not 20. + +**Known limits found while measuring 0.4.1.** The mutation gate on GitHub's Mac +runs `test/baggrund-mus.mjs` after the many-agents test, and there a menu +opened by a click behind is not closed again (`menu_closed: false` in the +reply) - with Finder in front, and in two runs that put Script Editor in front +first, with Script Editor in front - though these menu checks pass in the +suite. The cause is not found. Its 38 mutants are therefore not proven on a +foreign Mac. In `test/sikker-frigivelse.mjs`, the check that the helper process +ends within 500 ms of a stop (F2b) failed in 4 of 13 completed runs by +1 November (517-546 ms), on 0.4.0 and 0.4.1 alike; the mouse button was +released in all of them (F2). + +**Corrected.** The 0.2.1 notes below said "Password managers ask every single +time, in every mode." In background mode they are refused, not asked; in the +foreground they ask every time. The 0.4.0 notes say "A click behind never leaves +a menu over your work." In the mutation gate on GitHub's Mac a menu opened by a +click behind was left open, and the reply said so (`menu_closed: false`). ## 0.4.0 (in progress) @@ -447,7 +507,8 @@ that it is leaving and the helper finishes the file on its own. A server killed anything. Needs macOS 15. **Consent, as it actually works.** `allow` is the default, so an agent can be -left running. Password managers ask every single time, in every mode. Terminals +left running. Password managers ask every single time, in every mode (corrected +in 0.4.1: in background mode they are refused). Terminals and editors ask once per app per session. Quitting, closing a window, switching Space and destructive-looking menu items ask every time. Several pages said otherwise; they now match the code, and a test derives the forbidden phrasings diff --git a/README.md b/README.md index e8a14efd..3bee9215 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,11 @@ in the hours you are not watching. - **It does not take over your Mac.** It presses buttons and fills fields in windows that stay behind the one you are in, and it leaves your pointer where you put it. When an app pulls itself to the front as it opens, the front is - handed straight back and the reply says so - nothing is left stealing what you - are typing. + handed straight back and the reply says so. In one of 65 measured moments like + it (GitHub's Mac, many agents at once) it could not be, and the reply said that too (`gave_back: + false`): until you click back, what you type goes to that app. It also leaves + the front alone when you clicked, scrolled or pressed a modifier key such as + Shift in the last 1.5 seconds - that is taken to be you. - **It does not pretend.** When something is refused or fails, it says so and says why. The most common complaint about agents driving a computer is that they carry on as if it worked. @@ -133,11 +136,11 @@ and that its chain holds. ```jsonl -{"ts":"2026-10-20T18:52:45.701Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"1b330dc3a979","salted":true},"text":{"length":37,"sha256_12":"51f664abcb74","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"e02a3d1b3560ea17"} -{"ts":"2026-10-20T18:52:45.705Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"c1e763106513c3e7"} -{"ts":"2026-10-20T18:52:46.112Z","session":"fabb2663","call":"746fffee","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"b053781eb3511c4d"} -{"ts":"2026-10-20T18:52:47.761Z","session":"fabb2663","call":"88f2d9ae","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"0771e2f86fa0","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.0","icon":"0.4.0","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"9b82d6ae5a36942d"} -{"ts":"2026-10-20T18:52:48.229Z","session":"fabb2663","call":"0ba79155","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"84b5a01fae6a","salted":true},"text":{"length":7,"sha256_12":"b56e1d9fbfd2","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"1be981d7eeaf7445"} +{"ts":"2026-10-31T22:35:10.230Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"78743a52a54c","salted":true},"text":{"length":37,"sha256_12":"cdde26c85cca","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"4fb5f61a6e442962"} +{"ts":"2026-10-31T22:35:10.231Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"13cd03c71bfb3b38"} +{"ts":"2026-10-31T22:35:10.321Z","session":"56f00545","call":"02bc741b","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"79696176e8603981"} +{"ts":"2026-10-31T22:35:11.481Z","session":"56f00545","call":"ac33c074","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"2c65732d0d4e","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.1","icon":"0.4.1","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"ad20dddb1195fa7a"} +{"ts":"2026-10-31T22:35:11.578Z","session":"56f00545","call":"5b15b900","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"ac0afc1b1e97","salted":true},"text":{"length":7,"sha256_12":"f0b579393774","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"2332aa9606dd896e"} ``` @@ -237,13 +240,14 @@ the same way - including when the call failed halfway, because a half-done write that took the screen must not be the one line that stays silent. `press` and `menu` carry it too: an app can bring itself forward in response (measured: File > New Finder Window did), and when it does, the answer says so -and the front is handed straight back to the app you were in (`gave_back`). +and the front is handed straight back to the app you were in - `gave_back` +says whether that worked. `set_value`, `drag`, `paste` and `move` do not carry the field yet. `computer_launch` joins them with `background: true`: the app starts behind what you are doing. Many apps bring themselves forward as they start - six of eight did on a clean Mac - and when one does, the front is handed straight back -and the answer says `took_screen` and `gave_back`. It is a moment, not nothing. Seven are still held back: +and the answer says `took_screen`, and in `gave_back` whether that worked. It is a moment, not nothing. Seven are still held back: `move`, `activate`, `quit`, `space`, `window`, `drag` and `paste` - until you lend the screen: `computer_request_screen` asks you in the box in the corner of your screen (and in the menu bar), one agent at a time, approved with Touch ID, for at diff --git a/bundle/manifest.json b/bundle/manifest.json index e7eb8798..8d2f2313 100644 --- a/bundle/manifest.json +++ b/bundle/manifest.json @@ -2,7 +2,7 @@ "manifest_version": "0.3", "name": "computer-mcp", "display_name": "Computer MCP", - "version": "0.4.0", + "version": "0.4.1", "description": "macOS computer use you can leave running: it stays behind your window and never touches passwords.", "long_description": "A macOS computer-use MCP server built for the hours you are not watching. It acts in windows behind the one you are in and leaves your pointer alone, it says so when something fails, several can run at once, and it will not go near your password manager. Every action is written to an append-only audit log. Runs in any MCP client, macOS, MIT, no account.", "author": { diff --git a/docs/docs/capability-matrix/index.html b/docs/docs/capability-matrix/index.html index 5a709556..4276e6de 100644 --- a/docs/docs/capability-matrix/index.html +++ b/docs/docs/capability-matrix/index.html @@ -221,7 +221,7 @@

Walls we clear partly, and say so

- + diff --git a/docs/docs/install-claude-code/index.html b/docs/docs/install-claude-code/index.html index 72f0a00b..53b6b42c 100644 --- a/docs/docs/install-claude-code/index.html +++ b/docs/docs/install-claude-code/index.html @@ -182,7 +182,7 @@

Install Computer MCP for Claude Code

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/docs/install-claude-desktop/index.html b/docs/docs/install-claude-desktop/index.html index ff9754e6..ca07cb9f 100644 --- a/docs/docs/install-claude-desktop/index.html +++ b/docs/docs/install-claude-desktop/index.html @@ -182,7 +182,7 @@

Install Computer MCP for Claude Desktop

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/docs/install-codex/index.html b/docs/docs/install-codex/index.html index a1c7638e..49cd6302 100644 --- a/docs/docs/install-codex/index.html +++ b/docs/docs/install-codex/index.html @@ -182,7 +182,7 @@

Install Computer MCP for OpenAI Codex

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/docs/install-copilot/index.html b/docs/docs/install-copilot/index.html index 17d2856d..ead17a43 100644 --- a/docs/docs/install-copilot/index.html +++ b/docs/docs/install-copilot/index.html @@ -182,7 +182,7 @@

Install Computer MCP for GitHub Copilot

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/docs/install-cursor/index.html b/docs/docs/install-cursor/index.html index dd68e070..fbb5335e 100644 --- a/docs/docs/install-cursor/index.html +++ b/docs/docs/install-cursor/index.html @@ -182,7 +182,7 @@

Install Computer MCP for Cursor

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/docs/install-vscode/index.html b/docs/docs/install-vscode/index.html index 6a3cc578..95a3e983 100644 --- a/docs/docs/install-vscode/index.html +++ b/docs/docs/install-vscode/index.html @@ -182,7 +182,7 @@

Install Computer MCP for VS Code

access, window control, moving windows between screens, pasting, opening and quitting apps, waiting for something to appear, writing into a field behind another window, and asking you for a password without the model ever seeing it. -Those ship with 0.4.0, which is built and tested but not published yet.

+Those ship with 0.4.1, which is built and tested but not published yet.

Everything else on this page works with what you install today. If you want all of them now, build from source: about thirty-five seconds, and nothing to download.

diff --git a/docs/index.html b/docs/index.html index bf272930..d267710b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -751,7 +751,7 @@

Install in two minutes

Have your agent run computer_permissions. It tells you what is missing.

Want to look before it can touch? Start it with CMCP_MODE=readonly. No tool takes - your screen by default; CMCP_BACKGROUND=0 adds the seven that do. An app that pulls itself forward is handed back, and the reply says so. + your screen by default; CMCP_BACKGROUND=0 adds the seven that do. An app that pulls itself forward is handed back, and the reply says whether that worked. Guides: Claude Code, Codex, Cursor, Copilot, Claude Desktop, VS Code.

diff --git a/gemini-extension.json b/gemini-extension.json index 6805b233..c78cae35 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "computer-mcp", - "version": "0.4.0", + "version": "0.4.1", "description": "Drive macOS from any MCP client with the guardrails on by default: password fields blacked out in memory before the screenshot is written, password managers that are refused and terminals that ask once per session, and a log the server only appends to that never stores typed text in clear. 32 tools, 14 read-only. No API key, MIT.", "mcpServers": { "computer": { diff --git a/helper/Sources/cmcp-helper/main.swift b/helper/Sources/cmcp-helper/main.swift index 70b6f38f..15ef87d7 100644 --- a/helper/Sources/cmcp-helper/main.swift +++ b/helper/Sources/cmcp-helper/main.swift @@ -22,7 +22,7 @@ func modtager(_ args: Args) -> pid_t? { } -let HELPER_VERSION = "0.4.0" +let HELPER_VERSION = "0.4.1" /// ⛔ 9/10 (F1 paa Gustavs Mac): `--app` blev sammenlignet med programnavne paa /// tyve steder hver for sig (find, vinduer, skaermbilleder, sloering, levering). diff --git a/mcp-server/LICENSE b/mcp-server/LICENSE new file mode 100644 index 00000000..d5cab333 --- /dev/null +++ b/mcp-server/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Agent360 Group ApS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mcp-server/README.md b/mcp-server/README.md index 5008e47c..94d89db2 100644 --- a/mcp-server/README.md +++ b/mcp-server/README.md @@ -11,8 +11,11 @@ in the hours you are not watching. - **It does not take over your Mac.** It presses buttons and fills fields in windows that stay behind the one you are in, and it leaves your pointer where you put it. When an app pulls itself to the front as it opens, the front is - handed straight back and the reply says so - nothing is left stealing what you - are typing. + handed straight back and the reply says so. In one of 65 measured moments like + it (GitHub's Mac, many agents at once) it could not be, and the reply said that too (`gave_back: + false`): until you click back, what you type goes to that app. It also leaves + the front alone when you clicked, scrolled or pressed a modifier key such as + Shift in the last 1.5 seconds - that is taken to be you. - **It does not pretend.** When something is refused or fails, it says so and says why. The most common complaint about agents driving a computer is that they carry on as if it worked. @@ -131,11 +134,11 @@ and that its chain holds. ```jsonl -{"ts":"2026-10-20T18:52:45.701Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"1b330dc3a979","salted":true},"text":{"length":37,"sha256_12":"51f664abcb74","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"e02a3d1b3560ea17"} -{"ts":"2026-10-20T18:52:45.705Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"c1e763106513c3e7"} -{"ts":"2026-10-20T18:52:46.112Z","session":"fabb2663","call":"746fffee","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"b053781eb3511c4d"} -{"ts":"2026-10-20T18:52:47.761Z","session":"fabb2663","call":"88f2d9ae","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"0771e2f86fa0","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.0","icon":"0.4.0","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"9b82d6ae5a36942d"} -{"ts":"2026-10-20T18:52:48.229Z","session":"fabb2663","call":"0ba79155","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"84b5a01fae6a","salted":true},"text":{"length":7,"sha256_12":"b56e1d9fbfd2","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"1be981d7eeaf7445"} +{"ts":"2026-10-31T22:35:10.230Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"78743a52a54c","salted":true},"text":{"length":37,"sha256_12":"cdde26c85cca","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"4fb5f61a6e442962"} +{"ts":"2026-10-31T22:35:10.231Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"13cd03c71bfb3b38"} +{"ts":"2026-10-31T22:35:10.321Z","session":"56f00545","call":"02bc741b","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"79696176e8603981"} +{"ts":"2026-10-31T22:35:11.481Z","session":"56f00545","call":"ac33c074","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"2c65732d0d4e","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.1","icon":"0.4.1","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"ad20dddb1195fa7a"} +{"ts":"2026-10-31T22:35:11.578Z","session":"56f00545","call":"5b15b900","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"ac0afc1b1e97","salted":true},"text":{"length":7,"sha256_12":"f0b579393774","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"2332aa9606dd896e"} ``` @@ -235,13 +238,14 @@ the same way - including when the call failed halfway, because a half-done write that took the screen must not be the one line that stays silent. `press` and `menu` carry it too: an app can bring itself forward in response (measured: File > New Finder Window did), and when it does, the answer says so -and the front is handed straight back to the app you were in (`gave_back`). +and the front is handed straight back to the app you were in - `gave_back` +says whether that worked. `set_value`, `drag`, `paste` and `move` do not carry the field yet. `computer_launch` joins them with `background: true`: the app starts behind what you are doing. Many apps bring themselves forward as they start - six of eight did on a clean Mac - and when one does, the front is handed straight back -and the answer says `took_screen` and `gave_back`. It is a moment, not nothing. Seven are still held back: +and the answer says `took_screen`, and in `gave_back` whether that worked. It is a moment, not nothing. Seven are still held back: `move`, `activate`, `quit`, `space`, `window`, `drag` and `paste` - until you lend the screen: `computer_request_screen` asks you in the box in the corner of your screen (and in the menu bar), one agent at a time, approved with Touch ID, for at diff --git a/mcp-server/package-lock.json b/mcp-server/package-lock.json index d96e39ec..91af9a44 100644 --- a/mcp-server/package-lock.json +++ b/mcp-server/package-lock.json @@ -1,15 +1,15 @@ { "name": "@agent360/computer-mcp", - "version": "0.4.0", + "version": "0.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@agent360/computer-mcp", - "version": "0.4.0", + "version": "0.4.1", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0" + "@modelcontextprotocol/sdk": "^1.32.1" }, "bin": { "computer-mcp": "bin/cli.js" @@ -19,21 +19,21 @@ } }, "node_modules/@hono/node-server": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.1.tgz", - "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.5.tgz", + "integrity": "sha512-MgP/I06GdvsilDspMk/qmRzpk8LOUStP6jFAbSRi40W09DhoyUn+Mj7eyKICPqeYKybOjVFLVIAQzvu1bfIa7Q==", "license": "MIT", "engines": { "node": ">=20" }, "peerDependencies": { - "hono": "^4" + "hono": "^4 || ^5.0.0-0" } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.32.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.32.1.tgz", - "integrity": "sha512-2DdE+SJDtzLEEWzY1ZjY7Q+VcPhcV1KisD3zI4u0XZyktsjHum1mwbMI+JaulUBi2OZk+KJAi2uPXzxichPkdw==", + "version": "1.32.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.32.2.tgz", + "integrity": "sha512-SWsVtH/0vULSQStoZ6xxH2K09Li8fXYTMC64ZeogCdpZ3XSi1eCPOByV1OpuJxuI3OcmHhosDWYyii07tpPsLw==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", @@ -117,18 +117,18 @@ } }, "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz", + "integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^2.0.0", + "content-type": "^2.1.0", "debug": "^4.4.3", "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", + "iconv-lite": "^0.7.3", "on-finished": "^2.4.1", - "qs": "^6.15.2", + "qs": "^6.16.1", "raw-body": "^3.0.2", "type-is": "^2.1.0" }, @@ -192,9 +192,9 @@ } }, "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", + "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", "license": "MIT", "engines": { "node": ">=18" @@ -309,12 +309,16 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.1.tgz", + "integrity": "sha512-Ev/hIyePLZtpL98x562lvPtenrUfGr0lfaf44HFZ+hDEwso7ccV9QAZrEVLg0hxNAzygaAFxy2dYaAKKM0G06A==", "license": "MIT", "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/es-define-property": { @@ -384,15 +388,15 @@ } }, "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.3.0.tgz", + "integrity": "sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", + "body-parser": "^2.3.0", + "content-disposition": "^2.0.1", + "content-type": "^2.0.0", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", @@ -408,14 +412,14 @@ "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", + "proxy-addr": "^2.0.8", + "qs": "^6.16.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", - "type-is": "^2.0.1", + "type-is": "^2.1.0", "vary": "^1.1.2" }, "engines": { @@ -427,9 +431,9 @@ } }, "node_modules/express-rate-limit": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.0.tgz", - "integrity": "sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==", + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.2.tgz", + "integrity": "sha512-U1ScocxDD9WI09LaBVypvNkOtNR5yWAmZLkuKJdAzIchA4YKFYF6GT5IKER7epG58oXtjvGlV0/6ii0F83EyZg==", "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -445,6 +449,19 @@ "express": ">= 4.11" } }, + "node_modules/express/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -452,9 +469,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", - "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "funding": [ { "type": "github", @@ -589,9 +606,9 @@ } }, "node_modules/hono": { - "version": "4.13.13", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.13.tgz", - "integrity": "sha512-CQ46U0ZkAGmbT/4UxdzzGJpacP2IeKgY4a5/tOI9AABbpOMfK739wfDXmv1usCk+3RkKj1hQy4/fjhiwa2xlrA==", + "version": "4.13.15", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.15.tgz", + "integrity": "sha512-BTUf5VVhV+eb9owxdzdfQBV6b7Uvh7oDPMMHOmpa9hRe9/fKUI5b3TsGiDro2R3hPl3cPT5FuGmb32H3MqReug==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -640,9 +657,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.7.4", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.4.tgz", - "integrity": "sha512-DWBMKyeM25D70nrIiTkgQth59/G+naKOTep6huF9j+GmeK3DMD60Zvxg5d5qQnz+38AHgou6ean2LECX+lrKDg==", + "version": "10.7.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz", + "integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==", "license": "MIT", "engines": { "node": ">= 12" @@ -670,9 +687,9 @@ "license": "ISC" }, "node_modules/jose": { - "version": "6.2.12", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", - "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", + "version": "6.2.14", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.14.tgz", + "integrity": "sha512-3JasLuki1NRLQvY4wCoC37KZk4qxoBx2k2aFqLxT84IezqW0bkJKnNtxnZj/Fu1xsQivoc/lytxaRHJoGLjJ1A==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -806,15 +823,19 @@ } }, "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.2.tgz", + "integrity": "sha512-ATWUv387i+nLD49EiDoOft5scf32Vsdz3ktrQJG9bi7jRFmaXTssvyvj1EmeKVVgvesbqUtvQQvaS2TpTukAZQ==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/once": { @@ -881,9 +902,9 @@ } }, "node_modules/qs": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", - "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "version": "6.17.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.17.1.tgz", + "integrity": "sha512-jd3COkaKVgGUW+ZHyEHCG9bH7RoaaiWuMgzsIBjUMVjLAaWGWpoUAVwljVvBHxRu/2qEHnadLGZrkutYUBPQJA==", "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", @@ -1188,9 +1209,9 @@ "license": "ISC" }, "node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/mcp-server/package.json b/mcp-server/package.json index 993e08b6..7379713f 100644 --- a/mcp-server/package.json +++ b/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@agent360/computer-mcp", - "version": "0.4.0", + "version": "0.4.1", "mcpName": "io.github.Agent360dk/computer-mcp", "description": "Computer use you can actually leave running. It works in windows behind the one you are in and leaves your pointer alone, it says so when something fails instead of pretending, several can run at once, and it will not go near your password manager. Everything is logged. macOS, MIT, no account.", "type": "module", @@ -9,6 +9,7 @@ "computer-mcp": "bin/cli.js" }, "files": [ + "LICENSE", "index.js", "tools.js", "policy.js", @@ -62,6 +63,6 @@ "security" ], "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0" + "@modelcontextprotocol/sdk": "^1.32.1" } } diff --git a/mcp-server/policy.js b/mcp-server/policy.js index 788b3572..86efef63 100644 --- a/mcp-server/policy.js +++ b/mcp-server/policy.js @@ -620,7 +620,8 @@ export async function decide({ tier, targetBundleId, describe, alwaysAsk = false if (sessionGranted) return { allow: true, reason: 'this session already has consent', asked: false }; if (baggrund()) { - const v = await viaIkonet({ omfang: 'If you allow it, the agent may click and type for the rest of this session. Password apps still always ask.' }); + // 0.4.1 (C19, panel R1 24/10): i baggrund afvises adgangskode-programmer (maaIkke) - de spoerger ikke. :631 (forgrund) er sand. + const v = await viaIkonet({ omfang: 'If you allow it, the agent may click and type for the rest of this session. Password apps stay refused while it works in the background.' }); if (v.allow) sessionGranted = true; return v; } diff --git a/scripts/release.sh b/scripts/release.sh index 21d6efba..666f7aa1 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -160,7 +160,7 @@ echo "== 2b/7 CI skal vaere groen paa den commit der udgives ==" HEADSHA=$(git rev-parse HEAD) # ⛔ 7/10 (panel R8, E): en fejlet forespoergsel (net, GitHub-timeout) blev under # set -e enten et tavst stop eller laest som «CI har ikke koert». Den er UKENDT. -if ! CIDOM=$(gh run list -R Agent360dk/computerMCP -w CI --limit 20 \ +if ! CIDOM=$(gh run list -R Agent360dk/computerMCP -w CI --limit 100 \ --json headSha,conclusion,status \ -q "[.[] | select(.headSha==\"$HEADSHA\")] | .[0].conclusion" 2>/dev/null); then echo "⛔ CI-status kunne ikke laeses fra GitHub (net eller timeout) - den er UKENDT, ikke «ikke koert»." diff --git a/server.json b/server.json index 180e7f63..b60c1a4f 100644 --- a/server.json +++ b/server.json @@ -7,13 +7,13 @@ "url": "https://github.com/Agent360dk/computerMCP", "source": "github" }, - "version": "0.4.0", + "version": "0.4.1", "websiteUrl": "https://computermcp.dev", "packages": [ { "registryType": "npm", "identifier": "@agent360/computer-mcp", - "version": "0.4.0", + "version": "0.4.1", "transport": { "type": "stdio" }, diff --git a/test/fixtures/audit-readme.jsonl b/test/fixtures/audit-readme.jsonl index f40fea94..b3e33785 100644 --- a/test/fixtures/audit-readme.jsonl +++ b/test/fixtures/audit-readme.jsonl @@ -1,7 +1,7 @@ -{"ts":"2026-10-20T18:52:44.507Z","session":"fabb2663","call":"13634812","tool":"computer_apps","tier":"read","args":{},"target":null,"mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"read-only action","l":1,"kaede":"ad0c114e049b146c"} -{"ts":"2026-10-20T18:52:45.180Z","session":"fabb2663","call":"13634812","tool":"computer_apps","outcome":"ok","l":1,"kaede":"3028db917a702ec3"} -{"ts":"2026-10-20T18:52:45.701Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"1b330dc3a979","salted":true},"text":{"length":37,"sha256_12":"51f664abcb74","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"e02a3d1b3560ea17"} -{"ts":"2026-10-20T18:52:45.705Z","session":"fabb2663","call":"746fffee","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"c1e763106513c3e7"} -{"ts":"2026-10-20T18:52:46.112Z","session":"fabb2663","call":"746fffee","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"b053781eb3511c4d"} -{"ts":"2026-10-20T18:52:47.761Z","session":"fabb2663","call":"88f2d9ae","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"0771e2f86fa0","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.0","icon":"0.4.0","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"9b82d6ae5a36942d"} -{"ts":"2026-10-20T18:52:48.229Z","session":"fabb2663","call":"0ba79155","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"84b5a01fae6a","salted":true},"text":{"length":7,"sha256_12":"b56e1d9fbfd2","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"1be981d7eeaf7445"} +{"ts":"2026-10-31T22:35:09.449Z","session":"56f00545","call":"7fb6f0ce","tool":"computer_apps","tier":"read","args":{},"target":null,"mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"read-only action","l":1,"kaede":"97f43c51a40454c5"} +{"ts":"2026-10-31T22:35:10.129Z","session":"56f00545","call":"7fb6f0ce","tool":"computer_apps","outcome":"ok","l":1,"kaede":"f547259cf8faa803"} +{"ts":"2026-10-31T22:35:10.230Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","args":{"app":{"length":8,"sha256_12":"78743a52a54c","salted":true},"text":{"length":37,"sha256_12":"cdde26c85cca","salted":true}},"target":"com.apple.TextEdit","mode":"allow","asker":"custom","decision":"allowed","asked":false,"reason":"CMCP_MODE=allow","l":1,"kaede":"4fb5f61a6e442962"} +{"ts":"2026-10-31T22:35:10.231Z","session":"56f00545","call":"02bc741b","tool":"computer_type","tier":"write","target":"com.apple.TextEdit","phase":"executing","l":1,"kaede":"13cd03c71bfb3b38"} +{"ts":"2026-10-31T22:35:10.321Z","session":"56f00545","call":"02bc741b","tool":"computer_type","outcome":"ok","effect":"sent","l":1,"kaede":"79696176e8603981"} +{"ts":"2026-10-31T22:35:11.481Z","session":"56f00545","call":"ac33c074","tool":"computer_menu","tier":"write","args":{"app":{"length":6,"sha256_12":"2c65732d0d4e","salted":true},"path":"File > Move to Trash"},"target":"com.apple.finder","mode":"allow","asker":"menubar","presence":{"idle_at_ask":600,"idle_at_end":600,"server":"0.4.1","icon":"0.4.1","box":"on","sessions":1,"surface_derived":"box+menu"},"decision":"denied","asked":true,"reason":"background mode: nobody answered in the menu bar in time","l":1,"kaede":"ad20dddb1195fa7a"} +{"ts":"2026-10-31T22:35:11.578Z","session":"56f00545","call":"5b15b900","tool":"computer_type","tier":"write","args":{"app":{"length":9,"sha256_12":"ac0afc1b1e97","salted":true},"text":{"length":7,"sha256_12":"f0b579393774","salted":true}},"target":"com.1password.1password","mode":"allow","asker":"custom","decision":"denied","asked":false,"reason":"background mode: this would need a dialog, and a dialog takes the screen (a password app can never be approved from the menu bar)","l":1,"kaede":"2332aa9606dd896e"} diff --git a/test/ikon-godkend.mjs b/test/ikon-godkend.mjs index f7bab639..75b1f266 100644 --- a/test/ikon-godkend.mjs +++ b/test/ikon-godkend.mjs @@ -419,6 +419,7 @@ const d2a = await D2.rpc('tools/call', { name: 'computer_type', arguments: { app const d2b = await D2.rpc('tools/call', { name: 'computer_type', arguments: { app: 'Finder', text: 'def' } }); check('D2 ask: foerste skrivning godkendt fra ikonet', !d2a.result.isError, d2a.result.content[0].text.slice(0, 70)); check('D2 ...ikonet fik omfanget «resten af sessionen»', /rest of this session/.test(ikonD.modtaget[foerD2]?.scope || ''), ikonD.modtaget[foerD2]?.scope); +check('D2 ...og omfanget lover ikke at adgangskode-programmer spoerger (i baggrund afvises de, policy.js maaIkke)', !/password (apps?|managers?)[^.]*\b(always\s+)?asks?\b/i.test(ikonD.modtaget[foerD2]?.scope || '') && /refused/i.test(ikonD.modtaget[foerD2]?.scope || ''), ikonD.modtaget[foerD2]?.scope); check('D2 ...og anden skrivning spurgte ikke igen', !d2b.result.isError && ikonD.modtaget.length === foerD2 + 1, `${ikonD.modtaget.length - foerD2} spoergsmaal`); D2.srv.kill(); ikonD.srv.close(); process.env.CMCP_MODE = 'allow'; diff --git a/test/parallel.mjs b/test/parallel.mjs index 8967e699..6092f15f 100644 --- a/test/parallel.mjs +++ b/test/parallel.mjs @@ -194,7 +194,9 @@ for (const n of NIVEAUER) { const t0 = Date.now(); // Én delt state-mappe pr. runde: programlaas og revisionskaede deles, som paa en rigtig Mac. const delt = mkdtempSync(join(tmpdir(), 'cmcp-parallel-state-')); - const res = await Promise.all(hold.map(s => koerScenarie(s, { film: false, menneskeArbejder: EGEN, stateDir: delt }))); + // 1/11 (panel R1, Opus): paa GitHubs Mac skriver en proeve ogsaa i TextEdit, saa et skift TILBAGE til TextEdit er + // menneskets program, ikke scenariets. Uden vaernet fik et rent laesende scenarie skylden for Finder-momentet. + const res = await Promise.all(hold.map(s => koerScenarie(s, { film: false, menneskeArbejder: FREMMED || EGEN, stateDir: delt }))); const sek = ((Date.now() - t0) / 1000).toFixed(1); await vent(2500); // et program kan hente sig selv frem sekunder efter (Kontakter, 27/9) const maaling = await vagt.stop(); diff --git a/test/stille-vej.mjs b/test/stille-vej.mjs index 696e1b2d..022b5925 100644 --- a/test/stille-vej.mjs +++ b/test/stille-vej.mjs @@ -290,7 +290,11 @@ try { if (!FREMMED_MASKINE) { sprang('leverer vi i det program mennesket SIDDER i, indroemmer den det', ROER_GRUND); } else if (forrestNavn) { - const eget = koer('scroll', '--dx', '0', '--dy', '0', '--app', forrestNavn); + // 0.4.1: siden ed09c85 (10/10) kraever hjaelperen et punkt sammen med --app (main.swift:1020) - samme punkt som + // serveren selv giver (computer_scroll i mcp-server, linje 1325-1328): midten af programmets forreste vindue. + const vf = (koer('windows', '--app', forrestNavn).windows || [])[0]?.frame; + const eget = vf ? koer('scroll', '--dx', '0', '--dy', '0', '--app', forrestNavn, '--x', String(vf.x + vf.w / 2), '--y', String(vf.y + vf.h / 2)) + : { took_screen: null, error: `${forrestNavn} har intet vindue at rulle i` }; check('leverer vi i det program mennesket SIDDER i, indroemmer den det', eget.took_screen === true, `${forrestNavn}: ${JSON.stringify(eget)}`); } else {
WallWhat actually happens
Redacting secretsmeasuredOnly what macOS marks as secure is painted out. Measured on a real web page: a password input carries role AXTextField with subrole AXSecureTextField and is redacted; a plain text field is not. A password in a text editor, or a token printed in a terminal, carries no marker and will not be hidden. Use readonly when the screen holds something the system cannot know about.
Working without taking over the screenmeasuredThree kinds, and the difference is how the action is delivered, not what the tool is called. Quiet by delivery: computer_press, computer_set_value and computer_menu fire the element's own accessibility action, so they work on a window behind the one you are in and never touch your pointer. The app can still bring itself forward in response - measured: File > New Finder Window did - and then press and menu answer took_screen and hand the front straight back. Quiet when you name the app: computer_click, computer_type, computer_key and computer_scroll are delivered into that app's own event queue - measured: the text arrived, the pointer stayed where it was left, and the front window did not change. computer_launch joins them with background: true - measured on a clean Mac, six of eight apps brought themselves forward as they started, and the front is handed straight back. Without an app they go through the system input tap and land wherever your keyboard focus is, so in background mode they are refused. One measured limit: keystrokes do not land in a Chromium window that is not focused, so for anything Chromium-based use computer_press and computer_set_value. Held back in background mode: computer_move, computer_drag, computer_paste, computer_activate, computer_quit, computer_space and computer_window. Each either moves your pointer, brings something to the front, or changes what you see - a window moved on a screen you are looking at is a quiet channel with a very visible result. computer_ask_user left this list on 29 September: in background mode its question waits in the menu bar icon instead of a dialog. And the held-back seven are no longer out of reach: computer_request_screen asks you to lend this one agent the screen, approved with Touch ID in the menu bar, for at most 15 minutes. While it has it, each step waits while you are using the keyboard or mouse (a step already running finishes), and one click in the menu takes the screen back and stops a step still running. Set CMCP_BACKGROUND and nothing can borrow it.
Working without taking over the screenmeasuredThree kinds, and the difference is how the action is delivered, not what the tool is called. Quiet by delivery: computer_press, computer_set_value and computer_menu fire the element's own accessibility action, so they work on a window behind the one you are in and never touch your pointer. The app can still bring itself forward in response - measured: File > New Finder Window did - and then press and menu answer took_screen and hand the front straight back - gave_back says whether that worked (once in 65 moments on GitHub’s Mac it did not). Quiet when you name the app: computer_click, computer_type, computer_key and computer_scroll are delivered into that app's own event queue - measured: the text arrived, the pointer stayed where it was left, and the front window did not change. computer_launch joins them with background: true - measured on a clean Mac, six of eight apps brought themselves forward as they started, and the front is handed straight back - gave_back says whether that worked. Without an app they go through the system input tap and land wherever your keyboard focus is, so in background mode they are refused. One measured limit: keystrokes do not land in a Chromium window that is not focused, so for anything Chromium-based use computer_press and computer_set_value. Held back in background mode: computer_move, computer_drag, computer_paste, computer_activate, computer_quit, computer_space and computer_window. Each either moves your pointer, brings something to the front, or changes what you see - a window moved on a screen you are looking at is a quiet channel with a very visible result. computer_ask_user left this list on 29 September: in background mode its question waits in the menu bar icon instead of a dialog. And the held-back seven are no longer out of reach: computer_request_screen asks you to lend this one agent the screen, approved with Touch ID in the menu bar, for at most 15 minutes. While it has it, each step waits while you are using the keyboard or mouse (a step already running finishes), and one click in the menu takes the screen back and stops a step still running. Set CMCP_BACKGROUND and nothing can borrow it.
Several agents at oncemeasuredEach MCP client runs its own server. Measured: two servers, 50 interleaved writes, zero torn lines, and every line carries a session mark. Writes in the same app take turns: each holds a lock for that app, so keys and clicks never interleave within an action. Between actions they still share one pointer and one focused window; give background work to computer_press.
Knowing where the cursor ismeasuredcomputer_focused reports the focused element and whether it is secure. The system-wide lookup alone returns nothing - measured - so it goes through the focused application, then the frontmost app.
A Save / Don't Save sheetmeasuredThe sheet you meet every time you close something with unsaved work. Measured: the sheet is found as AXSheet, all three buttons come back with a center and a pressable flag, and computer_find with contains: "Don't Save" returns exactly that one button - an agent looks for the words, not for a position. It is also the clearest case for the gate: a sheet can throw away work on your behalf, so in read-only mode pressing it is refused and nothing reaches the machine. Measured against a sheet the test puts up itself, in a fully transparent window, so proving it costs nobody their screen.