Skip to content
Open
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
b209ff3
feat(codex): surface Computer Use and MCP tool approvals; Windows nat…
Nelglor Aug 10, 2026
fae3dcb
fix(desktop): declare NSAppleEventsUsageDescription so Computer Use c…
sheehanmunim Aug 13, 2026
976ec26
Add macOS desktop control and agent-owned browser tabs
sheehanmunim Aug 13, 2026
ee6d42e
Avoid a needless spread when listing agent tabs
sheehanmunim Aug 13, 2026
ab27a20
test(desktop): cover the Apple Events usage description in build config
sheehanmunim Aug 13, 2026
30bd070
refactor(codex): drop the Windows Computer Use transport bridge
sheehanmunim Aug 13, 2026
2bb4e68
feat(desktop): add the Windows desktop-control MCP server
sheehanmunim Aug 13, 2026
28f93cc
feat(desktop): add the Linux desktop-control backend
sheehanmunim Aug 13, 2026
1c0496b
feat(desktop): ship the desktop-control server on Windows and Linux
sheehanmunim Aug 13, 2026
aa82e57
fix(desktop): write text through AT-SPI on Linux instead of synthetic…
sheehanmunim Aug 13, 2026
aff71b5
feat(desktop): bring agent-owned Chrome tabs to Windows and Linux
sheehanmunim Aug 13, 2026
4473c33
fix(repo): stop the pre-commit formatter failing on native-only changes
sheehanmunim Aug 13, 2026
707a432
fix(desktop): prefer X11 for capture when both display servers are pr…
sheehanmunim Aug 13, 2026
5386ba3
fix(desktop): capture on Wayland through wlr-screencopy when xcap cannot
sheehanmunim Aug 13, 2026
90ec012
fix(desktop): commit the desktop server lockfile
sheehanmunim Aug 13, 2026
2d573ae
refactor(desktop): name the desktop server executable in one place
sheehanmunim Aug 13, 2026
b39a131
fix(desktop): report the requested url when a new tab has not loaded
sheehanmunim Aug 13, 2026
f1fd6dc
fix(desktop): confirm browser actions in the macOS server's words
sheehanmunim Aug 13, 2026
4530158
feat(desktop): give the agent its own pointer, and stop taking the us…
sheehanmunim Aug 13, 2026
c2f3627
feat(desktop): Computer Use settings, pointer polish, Windows backgro…
sheehanmunim Aug 13, 2026
6ab7d2d
feat(desktop): polish Computer Use settings and fix Windows Gdi import
sheehanmunim Aug 13, 2026
ee60735
fix(desktop): satisfy Effect diagnostics in Computer Use permissions
sheehanmunim Aug 13, 2026
47de73e
fix(desktop): inject t3-desktop MCP for Cursor/Grok without HTTP session
sheehanmunim Aug 13, 2026
2934b57
fix(desktop): address Computer Use review findings
sheehanmunim Aug 13, 2026
9dfd172
fix(desktop): resolve Computer Use settings without widening session R
sheehanmunim Aug 13, 2026
b0b323e
fix(desktop): skip bad MCP binary candidates and avoid overlay SIGPIPE
sheehanmunim Aug 13, 2026
dfd96e9
fix(desktop): make ServerSettings acquisition unmistakable for Macros…
sheehanmunim Aug 13, 2026
d49a849
fix(desktop): finish Computer Use correctness follow-ups
sheehanmunim Aug 13, 2026
828539f
fix(desktop): harden background input fallbacks and group creation
sheehanmunim Aug 13, 2026
dc26af4
fix(desktop): close remaining Computer Use correctness gaps
sheehanmunim Aug 13, 2026
d276236
fix(desktop): inject t3-desktop MCP into Codex sessions
sheehanmunim Aug 13, 2026
a3e68a6
fix(desktop): avoid JSON.stringify in Codex MCP -c overrides
sheehanmunim Aug 13, 2026
116be76
fix(desktop): Windows agent cursor and Chrome extension reconnect
sheehanmunim Aug 14, 2026
d03f89a
fix(desktop): address Computer Use bot review findings
sheehanmunim Aug 14, 2026
2ca65a5
fix(desktop): unique MCP elicitation correlation and session teardown
sheehanmunim Aug 14, 2026
e05cc85
fix(desktop): serialize Chrome session cleanup and clear Effect path
sheehanmunim Aug 14, 2026
7de28f6
fix(chrome-extension): keep agent group id across reconnect cleanup
sheehanmunim Aug 14, 2026
b9024f1
fix(desktop-mcp): raise Linux apps via EWMH when AT-SPI focus fails
sheehanmunim Aug 14, 2026
f9937a6
fix(desktop-mcp): harden Linux activate/type/press_key and Windows chmod
sheehanmunim Aug 14, 2026
c916e4f
fix(desktop-mcp): use short bridge socket path when App Support is to…
sheehanmunim Aug 14, 2026
4af984d
fix(desktop-mcp): harden agent window ownership and Linux input cleanup
sheehanmunim Aug 14, 2026
9212d78
fix(desktop-mcp): address follow-up Computer Use bot findings
sheehanmunim Aug 14, 2026
7c3beff
fix(desktop-mcp): process follow-up Computer Use bot findings
sheehanmunim Aug 14, 2026
8a2b9e1
fix(desktop-mcp): clear remaining Linux Computer Use bot findings
sheehanmunim Aug 14, 2026
a22d5e2
fix(desktop-mcp): drop accidental history.rs from Computer Use branch
sheehanmunim Aug 14, 2026
73ac3d7
fix(desktop-mcp): keep AT-SPI insert on caret errors; harden Wayland …
sheehanmunim Aug 14, 2026
9fe19bb
fix(desktop-mcp): append on caret miss; drop Effect shim; Wayland scroll
sheehanmunim Aug 14, 2026
7e6c8ef
fix(desktop-mcp): error when Shift is required but unavailable
sheehanmunim Aug 14, 2026
53ce8f5
fix(desktop-mcp): reject out-of-range pointer coords; lazy Shift_R lo…
sheehanmunim Aug 14, 2026
d4d459f
fix(desktop-mcp): sync Computer Use with Macroscope MCP hardening
sheehanmunim Aug 15, 2026
2177db7
fix(desktop): repair ipc doc comment; drop unused Codex stateDir
sheehanmunim Aug 15, 2026
7bc547a
fix(settings): decorative brand icons and Computer Use bridge fallback
sheehanmunim Aug 15, 2026
5b23a7a
fix(desktop): port pointer animation and Win/Linux Computer Use parity
sheehanmunim Aug 15, 2026
93b0a2a
fix(desktop): repair desktop-mcp stage JSDoc opener
sheehanmunim Aug 15, 2026
e3e20c3
fix(desktop): clear Macroscope Computer Use correctness findings
sheehanmunim Aug 15, 2026
ab65a80
fix(desktop): restore CaptureBox for window PNG race safety
sheehanmunim Aug 15, 2026
baa2a17
fix(desktop): clear follow-up Macroscope and Bugbot findings
sheehanmunim Aug 15, 2026
419f672
fix(desktop): prefer under-point click targets and cap click_count
sheehanmunim Aug 15, 2026
0be8ba2
fix(desktop): scope browser disconnects and tighten click/app resolution
sheehanmunim Aug 15, 2026
b55dd77
fix(desktop): constrain click targeting and lock disconnect generation
sheehanmunim Aug 15, 2026
9983d3e
fix(desktop): report real tab ids and clearer off-screen click errors
sheehanmunim Aug 15, 2026
45b3ad2
fix(desktop): ignore agent-cursor overlay in under-point hit tests
sheehanmunim Aug 15, 2026
df9f718
fix(desktop): resolve explicit app for drag/click without stale pid
sheehanmunim Aug 15, 2026
a50d9f1
fix(desktop): allow background drags under occluding windows
sheehanmunim Aug 15, 2026
46ba045
fix(settings): use shared CollapsibleContent for More browsers
sheehanmunim Aug 15, 2026
c4ab2d2
fix(web): use CollapsiblePanel for More browsers disclosure
sheehanmunim Aug 15, 2026
fba68db
fix(settings): extract More browsers collapsible into shared component
sheehanmunim Aug 15, 2026
efc0758
fix(native): harden shared Computer Use bridge, capture, and app listing
sheehanmunim Aug 15, 2026
fd34492
fix(settings): share SettingRowTitle across Computer Use settings
sheehanmunim Aug 15, 2026
973a27f
fix(native): hold agent-window lock through creation
sheehanmunim Aug 15, 2026
7904e86
fix(native): drop computer-history entry from computer-use main
sheehanmunim Aug 15, 2026
2fc56ed
fix(cu): align bridge socket cleanup, display listing, and privacy se…
sheehanmunim Aug 15, 2026
9e08487
fix(desktop): port shared Computer Use correctness fixes from history…
sheehanmunim Aug 15, 2026
3dc9da5
fix(desktop): reject empty app query in macOS resolveApp
sheehanmunim Aug 15, 2026
fa8f096
fix(desktop-mcp): resolve numeric app names when PID is absent
sheehanmunim Aug 15, 2026
9bd1919
fix(desktop-mcp): keep agent windows across AX gaps; exact numeric names
sheehanmunim Aug 15, 2026
ddbbb19
fix(desktop-mcp): remove History CLI; exact-match numeric app names
sheehanmunim Aug 15, 2026
13dea33
fix(desktop-mcp): remove stray brace after native-host entry
sheehanmunim Aug 15, 2026
2fb6531
fix(desktop-mcp): port shared Macroscope CU hardening from History
sheehanmunim Aug 15, 2026
b1a6fc5
fix(desktop-mcp): use MSG_DONTWAIT bridge writes; fix Shift and FRONT…
sheehanmunim Aug 15, 2026
f35e608
fix(desktop-mcp): invoke press/click AT-SPI actions by name
sheehanmunim Aug 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/desktop/scripts/electron-launcher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ function patchMainBundleInfoPlist(appBundlePath, iconPath, executableName) {
setPlistString(infoPlistPath, "CFBundleIdentifier", APP_BUNDLE_ID);
setPlistString(infoPlistPath, "CFBundleExecutable", executableName);
setPlistString(infoPlistPath, "CFBundleIconFile", "icon.icns");
// Without this key macOS denies every Apple Event with errAEEventNotPermitted
// (-1743) and never shows the Automation prompt, so Codex Computer Use and any
// other MCP server we spawn silently fail to drive other apps.
setPlistString(
infoPlistPath,
"NSAppleEventsUsageDescription",
"This app needs to control other apps to run Computer Use automations you approve.",
);
setPlistJson(infoPlistPath, "CFBundleURLTypes", [
{
CFBundleURLName: APP_BUNDLE_ID,
Expand Down
99 changes: 99 additions & 0 deletions apps/desktop/src/computerUse/permissions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// @effect-diagnostics nodeBuiltinImport:off - Fixture reads of Chrome Secure Preferences stay synchronous.
import * as NodeFS from "node:fs";
import * as NodeOS from "node:os";
import * as NodePath from "node:path";
import { assert, describe, it } from "@effect/vitest";
import { vi } from "vite-plus/test";

vi.mock("electron", () => ({
systemPreferences: {
isTrustedAccessibilityClient: vi.fn(() => false),
getMediaAccessStatus: vi.fn(() => "denied"),
},
shell: {
openExternal: vi.fn(async () => undefined),
},
}));

import * as Electron from "electron";

import { openComputerUsePrivacySettings, readComputerUsePermissions } from "./permissions.ts";

describe("computerUse permissions", () => {
it("reports accessibility and screen recording on darwin", () => {
const previous = process.platform;
Object.defineProperty(process, "platform", { value: "darwin" });
try {
const state = readComputerUsePermissions();
assert.equal(state.platform, "darwin");
assert.deepEqual(
state.permissions.map((permission) => permission.kind),
["accessibility", "screenRecording"],
);
assert.equal(state.permissions[0]?.status, "denied");
assert.equal(state.permissions[1]?.status, "denied");
} finally {
Object.defineProperty(process, "platform", { value: previous });
}
});

it("marks privacy permissions not required off macOS", () => {
const previous = process.platform;
Object.defineProperty(process, "platform", { value: "linux" });
try {
const state = readComputerUsePermissions();
assert.equal(state.platform, "linux");
assert.isTrue(state.permissions.every((permission) => permission.status === "notRequired"));
} finally {
Object.defineProperty(process, "platform", { value: previous });
}
});

it("opens the Accessibility privacy pane and prompts trust", async () => {
const previous = process.platform;
Object.defineProperty(process, "platform", { value: "darwin" });
try {
const opened = await openComputerUsePrivacySettings("accessibility");
assert.isTrue(opened);
assert.equal(
vi.mocked(Electron.systemPreferences.isTrustedAccessibilityClient).mock.calls.at(-1)?.[0],
true,
);
assert.equal(
vi.mocked(Electron.shell.openExternal).mock.calls.at(-1)?.[0],
"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility",
);
} finally {
Object.defineProperty(process, "platform", { value: previous });
}
});

it("detects an unpacked extension from Secure Preferences without state", () => {
const previous = process.platform;
Object.defineProperty(process, "platform", { value: "darwin" });
const home = NodeOS.homedir();
const securePath = NodePath.join(
home,
"Library/Application Support/Google/Chrome/Default/Secure Preferences",
);
try {
if (!NodeFS.existsSync(securePath)) return;
const raw = NodeFS.readFileSync(securePath, "utf8");
const parsed = JSON.parse(raw) as {
extensions?: { settings?: Record<string, unknown> };
};
const hasExtension = Boolean(parsed.extensions?.settings?.kgdolgnijopbghhomnblabjkmjhnoage);
const state = readComputerUsePermissions();
if (hasExtension) {
assert.deepEqual(state.chromeExtension, {
status: "installed",
detail: "Browser extension installed",
});
} else {
assert.isTrue(["missing", "unknown"].includes(state.chromeExtension.status));
}
} finally {
Object.defineProperty(process, "platform", { value: previous });
}
});
});
Loading
Loading