arena-bridge 0.7.2 → 0.7.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/CHANGELOG.md +14 -0
- package/README.md +27 -0
- package/package.json +1 -1
- package/src/direct.mjs +12 -2
- package/src/http.mjs +4 -2
- package/src/hub.mjs +13 -3
- package/src/mac.mjs +2 -1
- package/src/mcp.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ 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.7.4
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Approvals over HTTP work again: `POST /approvals/<id>` now answers with the decision instead
|
|
11
|
+
of an internal error, the local token is accepted by the API, and the agent token is refused —
|
|
12
|
+
an agent can no longer approve its own dangerous action.
|
|
13
|
+
- The same rule now applies to the hub mode.
|
|
14
|
+
|
|
15
|
+
## 0.7.3
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- `mac_scroll` speaks the current Peekaboo grammar: the removed `--ticks` option was replaced
|
|
19
|
+
with `--amount`, and the tool also accepts `amount` as an argument.
|
|
20
|
+
|
|
7
21
|
## 0.7.2
|
|
8
22
|
|
|
9
23
|
### Fixed
|
package/README.md
CHANGED
|
@@ -258,6 +258,33 @@ arena-bridge telegram inbox
|
|
|
258
258
|
|
|
259
259
|
---
|
|
260
260
|
|
|
261
|
+
## Нативное приложение для macOS
|
|
262
|
+
|
|
263
|
+
Окно, в котором всё видно и всё управляется: статус, пуск/стоп, подтверждения, журнал.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
git clone https://github.com/vernikr/arena-bridge.git
|
|
267
|
+
cd arena-bridge/macos/ArenaBridge
|
|
268
|
+
./build.sh # → dist/Arena Bridge.app
|
|
269
|
+
cp -R "dist/Arena Bridge.app" /Applications/
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Нужен только Swift из Xcode Command Line Tools (`xcode-select --install`), Xcode целиком не
|
|
273
|
+
требуется. Собирается под текущую архитектуру: `ARCH=x86_64` для Intel, `ARCH=arm64` для
|
|
274
|
+
Apple Silicon.
|
|
275
|
+
|
|
276
|
+
| Блок в окне | Что делает |
|
|
277
|
+
| --- | --- |
|
|
278
|
+
| Статус | запущен/остановлен, версия, режим, число инструментов, публичный адрес, Telegram |
|
|
279
|
+
| Управление | «Запустить» / «Остановить» (служба `ai.arena.bridge`) и «Настроить…» |
|
|
280
|
+
| Подтверждения | ожидающие запросы агента с кнопками «Разрешить» / «Отклонить» |
|
|
281
|
+
| Журнал | последние записи, фильтр по инструменту, «Сохранить…» в файл |
|
|
282
|
+
|
|
283
|
+
«Настроить…» собирает конфиг, службу и запуск одной кнопкой: туннель (ngrok/cloudflared),
|
|
284
|
+
зарезервированный домен, authtoken, папки для агента, Telegram (токен бота и chat id).
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
261
288
|
## Доверенное окно: работать без подтверждений
|
|
262
289
|
|
|
263
290
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arena-bridge",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
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
|
@@ -52,7 +52,7 @@ export function createDirectServer(cfg, engine) {
|
|
|
52
52
|
ok: true,
|
|
53
53
|
mode: 'direct',
|
|
54
54
|
device: cfg.device,
|
|
55
|
-
version: '0.7.
|
|
55
|
+
version: '0.7.4',
|
|
56
56
|
uptime_sec: Math.round(process.uptime()),
|
|
57
57
|
});
|
|
58
58
|
}
|
|
@@ -118,10 +118,20 @@ export function createDirectServer(cfg, engine) {
|
|
|
118
118
|
|
|
119
119
|
const approveMatch = /^\/approvals\/([\w-]+)$/.exec(p);
|
|
120
120
|
if (req.method === 'POST' && approveMatch) {
|
|
121
|
+
// settling a request is a local-only privilege: the agent token must not self-approve
|
|
122
|
+
const expected = loadConfig().localToken;
|
|
123
|
+
const presented = bearer(req);
|
|
124
|
+
if (!expected || !presented || !safeEqual(presented, expected)) {
|
|
125
|
+
return sendJson(res, 403, {
|
|
126
|
+
ok: false,
|
|
127
|
+
error: 'forbidden',
|
|
128
|
+
reason: 'approvals require the local token — run "arena-bridge approve <id>" on the machine',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
121
131
|
const body = await readJson(req, 64 * 1024);
|
|
122
132
|
const decision = body.decision === 'deny' ? 'deny' : 'approve';
|
|
123
133
|
const res2 = decide(approveMatch[1], decision, 'api');
|
|
124
|
-
return sendJson(res2.ok ? 200 : 400, res2);
|
|
134
|
+
return sendJson(res, res2.ok ? 200 : 400, res2);
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
if (req.method === 'POST' && p === '/exec') {
|
package/src/http.mjs
CHANGED
|
@@ -72,6 +72,8 @@ export function bearer(req) {
|
|
|
72
72
|
|
|
73
73
|
export function isAuthorized(req, cfg) {
|
|
74
74
|
const token = bearer(req);
|
|
75
|
-
if (!token
|
|
76
|
-
|
|
75
|
+
if (!token) return false;
|
|
76
|
+
if (cfg.token && safeEqual(token, cfg.token)) return true;
|
|
77
|
+
// the local token is for the machine owner: approvals and trust
|
|
78
|
+
return !!(cfg.localToken && safeEqual(token, cfg.localToken));
|
|
77
79
|
}
|
package/src/hub.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import crypto from 'node:crypto';
|
|
3
|
-
import { sendJson, sendText, readJson, readBody, isAuthorized, safeEqual } from './http.mjs';
|
|
3
|
+
import { sendJson, sendText, readJson, readBody, isAuthorized, bearer, safeEqual } from './http.mjs';
|
|
4
4
|
import { handleMcp } from './mcp.mjs';
|
|
5
5
|
import { buildPrompt } from './prompt.mjs';
|
|
6
6
|
import { toolCatalog } from './engine.mjs';
|
|
@@ -90,7 +90,7 @@ export function createHubServer(cfg) {
|
|
|
90
90
|
return sendJson(res, 200, {
|
|
91
91
|
ok: true,
|
|
92
92
|
mode: 'hub',
|
|
93
|
-
version: '0.7.
|
|
93
|
+
version: '0.7.4',
|
|
94
94
|
devices: [...devices.keys()],
|
|
95
95
|
});
|
|
96
96
|
}
|
|
@@ -158,10 +158,20 @@ export function createHubServer(cfg) {
|
|
|
158
158
|
|
|
159
159
|
const approveMatch = /^\/approvals\/([\w-]+)$/.exec(p);
|
|
160
160
|
if (req.method === 'POST' && approveMatch) {
|
|
161
|
+
// settling a request is a local-only privilege: the agent token must not self-approve
|
|
162
|
+
const expected = loadConfig().localToken;
|
|
163
|
+
const presented = bearer(req);
|
|
164
|
+
if (!expected || !presented || !safeEqual(presented, expected)) {
|
|
165
|
+
return sendJson(res, 403, {
|
|
166
|
+
ok: false,
|
|
167
|
+
error: 'forbidden',
|
|
168
|
+
reason: 'approvals require the local token — run "arena-bridge approve <id>" on the machine',
|
|
169
|
+
});
|
|
170
|
+
}
|
|
161
171
|
const body = await readJson(req, 64 * 1024);
|
|
162
172
|
const decision = body.decision === 'deny' ? 'deny' : 'approve';
|
|
163
173
|
const r = decide(approveMatch[1], decision, 'api');
|
|
164
|
-
return sendJson(r.ok ? 200 : 400, r);
|
|
174
|
+
return sendJson(res, r.ok ? 200 : 400, r);
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
if (req.method === 'POST' && p === '/exec') {
|
package/src/mac.mjs
CHANGED
|
@@ -423,6 +423,7 @@ export function macTools(cfg = {}) {
|
|
|
423
423
|
{
|
|
424
424
|
direction: { type: 'string', description: 'up or down' },
|
|
425
425
|
ticks: { type: 'number', description: 'how many steps, default 3' },
|
|
426
|
+
amount: { type: 'number', description: 'how many steps to scroll (same as ticks)' },
|
|
426
427
|
on: { type: 'string', description: 'element id from mac_see' },
|
|
427
428
|
app: { type: 'string' },
|
|
428
429
|
window_id: { type: 'string' },
|
|
@@ -439,7 +440,7 @@ export function macTools(cfg = {}) {
|
|
|
439
440
|
const res = await runVariants(
|
|
440
441
|
p.bin,
|
|
441
442
|
[
|
|
442
|
-
['scroll', '--direction', dir, '--
|
|
443
|
+
['scroll', '--direction', dir, '--amount', String(args.amount ?? args.ticks ?? 3), ...on, ...flags],
|
|
443
444
|
['scroll', '--direction', dir, ...on, ...flags],
|
|
444
445
|
],
|
|
445
446
|
{ timeout: 30 },
|
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.7.
|
|
51
|
+
serverInfo: { name: 'arena-bridge', version: '0.7.4' },
|
|
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.',
|