arena-bridge 0.6.4 → 0.6.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 +9 -0
- package/README.md +2 -1
- package/package.json +1 -1
- package/src/direct.mjs +1 -1
- package/src/hub.mjs +1 -1
- package/src/mac.mjs +58 -11
- package/src/mcp.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
The format follows [Keep a Changelog](https://keepachangelog.com/) and the project uses
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## 0.6.5
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Peekaboo 4.9 compatibility: `peekaboo list` was removed in v4, so `mac_apps` now uses
|
|
11
|
+
`app list` and `mac_windows` uses `window list` (enumerating the running apps when no app is
|
|
12
|
+
given). `mac_menu` / `mac_menu_click` accept a process id, run against the local host
|
|
13
|
+
(`--no-remote`) and read the `menu_structure` payload; `mac_spaces` / `mac_space_switch` also
|
|
14
|
+
run locally, because a remote host cannot read or switch Spaces.
|
|
15
|
+
|
|
7
16
|
## 0.6.4
|
|
8
17
|
|
|
9
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="license">
|
|
13
13
|
<img src="https://img.shields.io/badge/node-%3E%3D18-green.svg?style=flat-square" alt="node">
|
|
14
14
|
<img src="https://img.shields.io/badge/dependencies-0-brightgreen.svg?style=flat-square" alt="dependencies">
|
|
15
|
-
<img src="https://img.shields.io/badge/tests-
|
|
15
|
+
<img src="https://img.shields.io/badge/tests-112%20passed-brightgreen.svg?style=flat-square" alt="tests">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
@@ -157,6 +157,7 @@ cookies и localStorage нет.
|
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
Установить Peekaboo: `brew install peekaboo` (или бинарник в `/usr/local/bin/peekaboo`).
|
|
160
|
+
Проверено с Peekaboo 4.9 (4.3 тоже работает, но синтаксис команд обновлён под 4.9).
|
|
160
161
|
macOS спросит разрешения **Screen Recording** и **Accessibility** для терминала, из которого
|
|
161
162
|
запущен мост — без них скриншоты и клики не работают; `mac_permissions` покажет, что не так.
|
|
162
163
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arena-bridge",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Give a cloud AI agent (Arena.ai Agent Mode, Claude, Cursor, ...) controlled access to your own machine over HTTP/MCP: files, shell, Chrome and the macOS desktop, with an approval gate, trust windows and an audit log.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/direct.mjs
CHANGED
package/src/hub.mjs
CHANGED
package/src/mac.mjs
CHANGED
|
@@ -191,6 +191,7 @@ export function macTools(cfg = {}) {
|
|
|
191
191
|
if (!outPath) {
|
|
192
192
|
return [
|
|
193
193
|
['see', '--tree', '--no-screenshot', '--json', ...targetFlags(args)],
|
|
194
|
+
['see', '--tree', '--no-screenshot', '--no-remote', '--json', ...targetFlags(args)],
|
|
194
195
|
['see', '--tree', '--json', ...targetFlags(args)],
|
|
195
196
|
['see', '--json', ...targetFlags(args)],
|
|
196
197
|
];
|
|
@@ -198,6 +199,7 @@ export function macTools(cfg = {}) {
|
|
|
198
199
|
return [
|
|
199
200
|
[...base, '--json', '--path', outPath],
|
|
200
201
|
[...base, '--path', outPath, '--json'],
|
|
202
|
+
[...base, '--no-remote', '--json', '--path', outPath],
|
|
201
203
|
['image', '--mode', mode, ...targetFlags(args), '--json', '--path', outPath],
|
|
202
204
|
];
|
|
203
205
|
};
|
|
@@ -467,9 +469,9 @@ export function macTools(cfg = {}) {
|
|
|
467
469
|
const res = await runVariants(
|
|
468
470
|
p.bin,
|
|
469
471
|
[
|
|
470
|
-
['list', 'apps', '--json'],
|
|
471
472
|
['app', 'list', '--json'],
|
|
472
|
-
['list', 'apps'],
|
|
473
|
+
['list', 'apps', '--json'],
|
|
474
|
+
['app', 'list'],
|
|
473
475
|
],
|
|
474
476
|
{ timeout: 30 },
|
|
475
477
|
);
|
|
@@ -492,12 +494,16 @@ export function macTools(cfg = {}) {
|
|
|
492
494
|
const p = checkPeek(peek());
|
|
493
495
|
if (!p.ok) return p;
|
|
494
496
|
const flags = args.app ? ['--app', String(args.app)] : [];
|
|
497
|
+
if (!flags.length) {
|
|
498
|
+
const windows = await windowsOfAllApps(p.bin);
|
|
499
|
+
return { ok: true, windows, source: 'per-app', hint: 'Pass app or pid to narrow the list down.' };
|
|
500
|
+
}
|
|
495
501
|
const res = await runVariants(
|
|
496
502
|
p.bin,
|
|
497
503
|
[
|
|
498
|
-
['list', 'windows', ...flags, '--json'],
|
|
499
504
|
['window', 'list', ...flags, '--json'],
|
|
500
|
-
['list', 'windows', ...flags],
|
|
505
|
+
['list', 'windows', ...flags, '--json'],
|
|
506
|
+
['window', 'list', ...flags],
|
|
501
507
|
],
|
|
502
508
|
{ timeout: 30 },
|
|
503
509
|
);
|
|
@@ -642,10 +648,11 @@ export function macTools(cfg = {}) {
|
|
|
642
648
|
handler: async (args) => {
|
|
643
649
|
const p = checkPeek(peek());
|
|
644
650
|
if (!p.ok) return p;
|
|
645
|
-
const flags =
|
|
651
|
+
const flags = menuFlags(args);
|
|
646
652
|
const res = await runVariants(
|
|
647
653
|
p.bin,
|
|
648
654
|
[
|
|
655
|
+
['menu', 'list', ...flags, '--no-remote', '--json'],
|
|
649
656
|
['menu', 'list', ...flags, '--json'],
|
|
650
657
|
['menu', 'list', ...flags],
|
|
651
658
|
],
|
|
@@ -654,9 +661,10 @@ export function macTools(cfg = {}) {
|
|
|
654
661
|
const json = parseJson(res.stdout);
|
|
655
662
|
return {
|
|
656
663
|
ok: res.exit_code === 0,
|
|
657
|
-
menus: json ? (json.menus || json.data?.menus || json) : undefined,
|
|
664
|
+
menus: json ? (json.menus || json.data?.menus || json.data?.menu_structure || json) : undefined,
|
|
658
665
|
output: json ? undefined : res.stdout.slice(0, 4000),
|
|
659
666
|
error: res.exit_code === 0 ? undefined : (res.stderr || '').trim().slice(0, 600),
|
|
667
|
+
hint: res.exit_code === 0 ? undefined : menuHint(res),
|
|
660
668
|
};
|
|
661
669
|
},
|
|
662
670
|
},
|
|
@@ -670,6 +678,7 @@ export function macTools(cfg = {}) {
|
|
|
670
678
|
item: { type: 'string', description: 'name of the menu item' },
|
|
671
679
|
path: { type: 'string', description: 'nested path, e.g. "File > Export"' },
|
|
672
680
|
app: { type: 'string', description: 'required: the background menu click needs a target app' },
|
|
681
|
+
pid: { type: 'number', description: 'process id, when the app name is ambiguous' },
|
|
673
682
|
},
|
|
674
683
|
[],
|
|
675
684
|
),
|
|
@@ -680,22 +689,22 @@ export function macTools(cfg = {}) {
|
|
|
680
689
|
if (!args.item && !args.path) {
|
|
681
690
|
return { ok: false, error: 'missing_item', hint: 'Pass item ("Save") or path ("File > Export").' };
|
|
682
691
|
}
|
|
683
|
-
if (!args.app) {
|
|
692
|
+
if (!args.app && !args.pid) {
|
|
684
693
|
return {
|
|
685
694
|
ok: false,
|
|
686
695
|
error: 'missing_app',
|
|
687
696
|
hint: 'A background menu click needs an explicit app: mac_menu_click {"app":"Safari","item":"Save"}.',
|
|
688
697
|
};
|
|
689
698
|
}
|
|
690
|
-
const flags =
|
|
699
|
+
const flags = menuFlags(args);
|
|
691
700
|
const variants = args.path
|
|
692
701
|
? [
|
|
702
|
+
['menu', 'click', '--path', String(args.path), ...flags, '--no-remote'],
|
|
693
703
|
['menu', 'click', '--path', String(args.path), ...flags],
|
|
694
|
-
['menu', 'click', String(args.path), ...flags],
|
|
695
704
|
]
|
|
696
705
|
: [
|
|
706
|
+
['menu', 'click', '--item', String(args.item), ...flags, '--no-remote'],
|
|
697
707
|
['menu', 'click', '--item', String(args.item), ...flags],
|
|
698
|
-
['menu', 'click', String(args.item), ...flags],
|
|
699
708
|
];
|
|
700
709
|
const res = await runVariants(p.bin, variants, { timeout: 30 });
|
|
701
710
|
return finish(res, 'menu-click');
|
|
@@ -713,6 +722,7 @@ export function macTools(cfg = {}) {
|
|
|
713
722
|
const res = await runVariants(
|
|
714
723
|
p.bin,
|
|
715
724
|
[
|
|
725
|
+
['space', 'list', '--no-remote', '--json'],
|
|
716
726
|
['space', 'list', '--json'],
|
|
717
727
|
['space', 'list'],
|
|
718
728
|
],
|
|
@@ -740,8 +750,8 @@ export function macTools(cfg = {}) {
|
|
|
740
750
|
const res = await runVariants(
|
|
741
751
|
p.bin,
|
|
742
752
|
[
|
|
753
|
+
['space', 'switch', '--to', String(args.to), '--foreground', '--no-remote'],
|
|
743
754
|
['space', 'switch', '--to', String(args.to), '--foreground'],
|
|
744
|
-
['space', 'switch', String(args.to), '--foreground'],
|
|
745
755
|
],
|
|
746
756
|
{ timeout: 30 },
|
|
747
757
|
);
|
|
@@ -821,6 +831,43 @@ export function macTools(cfg = {}) {
|
|
|
821
831
|
];
|
|
822
832
|
}
|
|
823
833
|
|
|
834
|
+
function menuFlags(args) {
|
|
835
|
+
const f = [];
|
|
836
|
+
if (args.app) f.push('--app', String(args.app));
|
|
837
|
+
if (args.pid) f.push('--pid', String(args.pid));
|
|
838
|
+
return f;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function menuHint(res) {
|
|
842
|
+
const text = (res.stderr || res.stdout || '').trim();
|
|
843
|
+
if (/multiple apps match/i.test(text)) {
|
|
844
|
+
return 'Several apps share that name — pass the process id from mac_apps: mac_menu {"pid":12345}.';
|
|
845
|
+
}
|
|
846
|
+
return text.slice(0, 600);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
async function windowsOfAllApps(bin) {
|
|
850
|
+
const res = await runVariants(
|
|
851
|
+
bin,
|
|
852
|
+
[
|
|
853
|
+
['app', 'list', '--json'],
|
|
854
|
+
['list', 'apps', '--json'],
|
|
855
|
+
],
|
|
856
|
+
{ timeout: 30 },
|
|
857
|
+
);
|
|
858
|
+
const json = parseJson(res.stdout);
|
|
859
|
+
const apps = json ? (json.apps || json.data?.apps || []) : [];
|
|
860
|
+
const out = [];
|
|
861
|
+
for (const app of Array.isArray(apps) ? apps.slice(0, 6) : []) {
|
|
862
|
+
if (!app || !app.pid) continue;
|
|
863
|
+
const w = await run(bin, ['window', 'list', '--pid', String(app.pid), '--json'], { timeout: 20 });
|
|
864
|
+
const data = parseJson(w.stdout);
|
|
865
|
+
const list = data ? (data.windows || data.data?.windows || []) : [];
|
|
866
|
+
for (const win of Array.isArray(list) ? list : []) out.push({ ...win, app: app.name, pid: app.pid });
|
|
867
|
+
}
|
|
868
|
+
return out;
|
|
869
|
+
}
|
|
870
|
+
|
|
824
871
|
function checkPeek(p) {
|
|
825
872
|
if (!p) return { ok: false, error: 'peekaboo_not_found', hint: NOT_FOUND_HINT };
|
|
826
873
|
return { ok: true, bin: p };
|
package/src/mcp.mjs
CHANGED
|
@@ -48,7 +48,7 @@ export async function handleMcp(req, res, ctx) {
|
|
|
48
48
|
mcpResponse(id, {
|
|
49
49
|
protocolVersion: PROTOCOL_VERSION,
|
|
50
50
|
capabilities: { tools: { listChanged: false } },
|
|
51
|
-
serverInfo: { name: 'arena-bridge', version: '0.6.
|
|
51
|
+
serverInfo: { name: 'arena-bridge', version: '0.6.5' },
|
|
52
52
|
instructions:
|
|
53
53
|
'Tools operate the user\'s own machine. Dangerous operations may return ' +
|
|
54
54
|
'PROTECTED and require a local human approval.',
|