@aptove/bridge 0.1.18 → 0.2.0
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 +112 -95
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -12,8 +12,6 @@ A bridge library and application between Agent Client Protocol (ACP) agents and
|
|
|
12
12
|
- **Standalone binary** — run `bridge` as a separate process that spawns your ACP agent over stdio and exposes it over WebSocket to mobile or desktop clients.
|
|
13
13
|
- **Embedded library** — add `aptove-bridge` as a Rust dependency and run the bridge server in-process alongside your agent, with no subprocess or stdio pipe required.
|
|
14
14
|
|
|
15
|
-
The [Aptove](https://github.com/aptove/aptove) project is the reference implementation of the embedded library usage — `aptove run` starts both the ACP agent and bridge server in a single process.
|
|
16
|
-
|
|
17
15
|
## Transport Modes
|
|
18
16
|
|
|
19
17
|
| Mode | Use Case | Documentation |
|
|
@@ -32,7 +30,7 @@ One transport is active at a time. When multiple are enabled in `common.toml`, t
|
|
|
32
30
|
- ⚡ **WebSocket Streaming**: Real-time bidirectional communication
|
|
33
31
|
- 🌐 **Multi-Transport**: Local, Cloudflare, Tailscale — configure and switch between them
|
|
34
32
|
- 🔑 **Stable Agent Identity**: `agent_id` UUID persisted in `common.toml` for multi-transport dedup on mobile
|
|
35
|
-
- 🦀 **Embeddable**: Use as a library with `
|
|
33
|
+
- 🦀 **Embeddable**: Use as a library with `StdioBridge` for in-process deployment
|
|
36
34
|
|
|
37
35
|
---
|
|
38
36
|
|
|
@@ -48,58 +46,46 @@ aptove-bridge = "0.1"
|
|
|
48
46
|
### Minimal Example
|
|
49
47
|
|
|
50
48
|
```rust
|
|
51
|
-
use aptove_bridge::{
|
|
49
|
+
use aptove_bridge::{
|
|
50
|
+
bridge::StdioBridge,
|
|
51
|
+
common_config::CommonConfig,
|
|
52
|
+
tls::TlsConfig,
|
|
53
|
+
};
|
|
52
54
|
|
|
53
55
|
#[tokio::main]
|
|
54
56
|
async fn main() -> anyhow::Result<()> {
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
res = server.start() => { res?; }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
Ok(())
|
|
57
|
+
// Load (or initialise) shared config — generates agent_id and auth_token on first run
|
|
58
|
+
let mut config = CommonConfig::load()?;
|
|
59
|
+
config.ensure_agent_id();
|
|
60
|
+
config.ensure_auth_token();
|
|
61
|
+
config.save()?;
|
|
62
|
+
|
|
63
|
+
// Generate (or load) a self-signed TLS cert
|
|
64
|
+
let tls = TlsConfig::load_or_generate(&CommonConfig::config_dir(), &[])?;
|
|
65
|
+
|
|
66
|
+
StdioBridge::new("copilot --acp".to_string(), 8765)
|
|
67
|
+
.with_auth_token(Some(config.auth_token.clone()))
|
|
68
|
+
.with_tls(tls)
|
|
69
|
+
.start()
|
|
70
|
+
.await
|
|
73
71
|
}
|
|
74
72
|
```
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
|
81
|
-
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```rust
|
|
92
|
-
let config = BridgeServeConfig::load()?;
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Reference Implementation: Aptove
|
|
96
|
-
|
|
97
|
-
The [Aptove project](https://github.com/aptove/aptove) (`aptove run`) is the full reference implementation. Key patterns it uses:
|
|
98
|
-
|
|
99
|
-
- `BridgeServer::build_with_trigger_store()` — wires in a `TriggerStore` for webhook support
|
|
100
|
-
- `server.show_qr()` — uses the pairing handshake so clients deduplicate agents by `agentId`
|
|
101
|
-
- `server.take_transport()` + `run_message_loop()` — connects the in-process transport to the ACP dispatch loop
|
|
102
|
-
- `tokio::select!` on `agent_loop` and `server.start()` — clean shutdown when either side exits
|
|
74
|
+
### `StdioBridge` Builder Methods
|
|
75
|
+
|
|
76
|
+
| Method | Description |
|
|
77
|
+
|--------|-------------|
|
|
78
|
+
| `new(agent_command, port)` | Create a bridge that spawns the given command; listen on `port` |
|
|
79
|
+
| `.with_bind_addr(addr)` | Override bind address (default: `"0.0.0.0"`) |
|
|
80
|
+
| `.with_auth_token(token)` | Require a bearer token for connections |
|
|
81
|
+
| `.with_tls(tls_config)` | Enable TLS with a `TlsConfig` (self-signed cert) |
|
|
82
|
+
| `.with_external_tls()` | Signal that TLS is handled upstream (Tailscale Serve, Cloudflare) |
|
|
83
|
+
| `.with_pairing(manager)` | Enable QR pairing via a `PairingManager` |
|
|
84
|
+
| `.with_agent_pool(pool)` | Enable keep-alive sessions via an `AgentPool` |
|
|
85
|
+
| `.with_working_dir(dir)` | Set the working directory for the spawned agent process |
|
|
86
|
+
| `.with_push_relay(client)` | Enable push notifications via a relay |
|
|
87
|
+
| `.with_webhook_resolver(fn)` | Handle `POST /webhook/<token>` trigger requests |
|
|
88
|
+
| `.start()` | Start the WebSocket listener (runs until shutdown) |
|
|
103
89
|
|
|
104
90
|
---
|
|
105
91
|
|
|
@@ -111,13 +97,16 @@ The [Aptove project](https://github.com/aptove/aptove) (`aptove run`) is the ful
|
|
|
111
97
|
# Build
|
|
112
98
|
cargo build --release
|
|
113
99
|
|
|
114
|
-
# Start
|
|
115
|
-
./target/release/bridge
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
# Start the bridge — interactive agent selection menu
|
|
101
|
+
./target/release/bridge
|
|
102
|
+
|
|
103
|
+
# Or specify the agent directly
|
|
104
|
+
./target/release/bridge run --agent-command "copilot --acp"
|
|
118
105
|
```
|
|
119
106
|
|
|
120
|
-
|
|
107
|
+
Running `bridge` with no subcommand defaults to `run`. When `--agent-command` is omitted, an interactive menu lets you pick from known agents (Copilot, Gemini, Goose) or enter a custom command.
|
|
108
|
+
|
|
109
|
+
Scan the QR code with the mobile app to connect.
|
|
121
110
|
|
|
122
111
|
### Configuration — `common.toml`
|
|
123
112
|
|
|
@@ -125,16 +114,14 @@ All transport settings live in `common.toml`. The file is created automatically
|
|
|
125
114
|
|
|
126
115
|
**Default location:**
|
|
127
116
|
|
|
128
|
-
|
|
|
129
|
-
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
When using `aptove run`, this config is shared across all workspaces.
|
|
117
|
+
| Platform | Path |
|
|
118
|
+
|----------|------|
|
|
119
|
+
| macOS | `~/Library/Application Support/com.aptove.bridge/common.toml` |
|
|
120
|
+
| Linux | `~/.config/bridge/common.toml` |
|
|
134
121
|
|
|
135
|
-
Override with `--config-dir`:
|
|
122
|
+
Override with `-c` / `--config-dir`:
|
|
136
123
|
```bash
|
|
137
|
-
bridge
|
|
124
|
+
bridge -c ./my-config run --agent-command "copilot --acp"
|
|
138
125
|
```
|
|
139
126
|
|
|
140
127
|
#### Example `common.toml`
|
|
@@ -168,20 +155,50 @@ tls = true
|
|
|
168
155
|
|
|
169
156
|
Enable only the transports you need. `agent_id` and `auth_token` are generated automatically on first run and stay stable across restarts.
|
|
170
157
|
|
|
158
|
+
#### Config Directory Files
|
|
159
|
+
|
|
160
|
+
All bridge state lives in the config directory. These files are created automatically on first run:
|
|
161
|
+
|
|
162
|
+
| File | Purpose |
|
|
163
|
+
|------|---------|
|
|
164
|
+
| `common.toml` | Main config — `agent_id`, `auth_token`, and transport settings. Permissions `0600`. |
|
|
165
|
+
| `cert.pem` | Self-signed TLS certificate for the local transport WebSocket server. Its fingerprint is embedded in the QR pairing payload for certificate pinning. |
|
|
166
|
+
| `key.pem` | Private key for the TLS certificate. |
|
|
167
|
+
| `cert-extra-sans.json` | Tracks extra Subject Alternative Names (IPs/hostnames) baked into the TLS cert (e.g. `--advertise-addr` or Tailscale IP). When these change, the cert is automatically regenerated. |
|
|
168
|
+
|
|
171
169
|
### Commands
|
|
172
170
|
|
|
173
|
-
#### `run` — Start the bridge
|
|
171
|
+
#### `run` — Start the bridge (default)
|
|
172
|
+
|
|
173
|
+
`run` is the default subcommand — running `bridge` with no arguments is equivalent to `bridge run`.
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
|
-
|
|
176
|
+
# Interactive agent selection
|
|
177
|
+
bridge
|
|
178
|
+
|
|
179
|
+
# Or specify the agent directly
|
|
180
|
+
bridge run --agent-command "copilot --acp"
|
|
177
181
|
```
|
|
178
182
|
|
|
179
|
-
| Flag | Description | Default |
|
|
180
|
-
|
|
181
|
-
| `--agent-command <CMD>` | Command to spawn the ACP agent |
|
|
182
|
-
| `--bind <ADDR>` | Address to bind the listener | `0.0.0.0` |
|
|
183
|
-
| `--
|
|
184
|
-
| `--
|
|
183
|
+
| Flag | Short | Description | Default |
|
|
184
|
+
|------|-------|-------------|---------|
|
|
185
|
+
| `--agent-command <CMD>` | `-a` | Command to spawn the ACP agent | Interactive menu |
|
|
186
|
+
| `--bind <ADDR>` | `-b` | Address to bind the listener | `0.0.0.0` |
|
|
187
|
+
| `--verbose` | | Enable info-level logging | Off (warn only) |
|
|
188
|
+
| `--advertise-addr <ADDR>` | | Override LAN address in QR pairing URL | Auto-detected |
|
|
189
|
+
|
|
190
|
+
When `--agent-command` is omitted, the bridge presents an interactive menu:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
Select an agent to run:
|
|
194
|
+
[1] Copilot (copilot --acp)
|
|
195
|
+
[2] Gemini (gemini --experimental-acp)
|
|
196
|
+
[3] Goose (goose acp)
|
|
197
|
+
[4] Custom
|
|
198
|
+
Enter number [1]:
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The QR code for pairing is always displayed at startup.
|
|
185
202
|
|
|
186
203
|
Transport selection, port, TLS, and auth token are all read from `common.toml`.
|
|
187
204
|
|
|
@@ -193,12 +210,6 @@ bridge show-qr
|
|
|
193
210
|
|
|
194
211
|
Displays the connection QR code for the currently active transport. The bridge must already be running. Use this to pair an additional device without restarting.
|
|
195
212
|
|
|
196
|
-
To show the QR at initial startup, pass `--qr` to `bridge run` instead:
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
bridge run --agent-command "aptove stdio" --qr
|
|
200
|
-
```
|
|
201
|
-
|
|
202
213
|
#### `setup` — Provision Cloudflare infrastructure
|
|
203
214
|
|
|
204
215
|
```bash
|
|
@@ -243,16 +254,13 @@ Prints the active `common.toml` path, `agent_id`, enabled transports, and Tailsc
|
|
|
243
254
|
### Embedded (library)
|
|
244
255
|
|
|
245
256
|
```
|
|
246
|
-
┌─────────────┐
|
|
247
|
-
│ Client App │◄──────────────────►│ Your process
|
|
248
|
-
│ (iOS/Android│ WebSocket (TLS) │
|
|
249
|
-
└─────────────┘
|
|
250
|
-
│ │ (transport) │ │ (InProcessTransport│ │
|
|
251
|
-
│ └─────────────────┘ └────────────────────┘ │
|
|
252
|
-
└──────────────────────────────────────────────┘
|
|
257
|
+
┌─────────────┐ ┌──────────────────────────────────┐ ┌──────────────┐
|
|
258
|
+
│ Client App │◄──────────────────►│ Your process │◄──────►│ ACP Agent │
|
|
259
|
+
│ (iOS/Android│ WebSocket (TLS) │ StdioBridge (transport listener)│ stdio │ (your cmd) │
|
|
260
|
+
└─────────────┘ └──────────────────────────────────┘ └──────────────┘
|
|
253
261
|
```
|
|
254
262
|
|
|
255
|
-
|
|
263
|
+
The agent process is still spawned as a subprocess via stdio — `StdioBridge` handles the WebSocket server, TLS, auth, and pairing in-process alongside your application.
|
|
256
264
|
|
|
257
265
|
---
|
|
258
266
|
|
|
@@ -270,13 +278,24 @@ No subprocess is spawned. Agent and bridge communicate via in-process channels.
|
|
|
270
278
|
|
|
271
279
|
```bash
|
|
272
280
|
# Enable verbose logging
|
|
273
|
-
bridge run --
|
|
281
|
+
bridge run --verbose
|
|
274
282
|
|
|
275
283
|
# Check which transports are configured
|
|
276
284
|
bridge status
|
|
277
285
|
|
|
278
286
|
# Test agent command independently
|
|
279
|
-
echo '{"jsonrpc":"2.0","method":"initialize","id":1}' |
|
|
287
|
+
echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | copilot --acp
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Testing with Other ACP-Compatible Agents
|
|
291
|
+
|
|
292
|
+
Please note that the project is extensively tested only with Copilot CLI. Open a bug report if you notice any issues with other ACP-Compatible Agents.
|
|
293
|
+
|
|
294
|
+
The easiest way to test any supported agent is to run `bridge` and pick it from the interactive menu. Alternatively, pass the command directly:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
bridge run -a "gemini --experimental-acp" --verbose
|
|
298
|
+
bridge run -a "goose acp" --verbose
|
|
280
299
|
```
|
|
281
300
|
|
|
282
301
|
---
|
|
@@ -287,19 +306,17 @@ echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | gemini --experimental-ac
|
|
|
287
306
|
- **TLS**: self-signed certificate generated on first run. Certificate fingerprint is included in the QR pairing payload and pinned by the mobile app to prevent MITM attacks.
|
|
288
307
|
- **Pairing codes**: 6-digit, single-use, expire after 60 seconds. Rate-limited to 5 attempts per code.
|
|
289
308
|
- **`common.toml`**: contains all secrets. Permissions are set to `0600` automatically. Keep it secure.
|
|
309
|
+
- **Agent command**: the `--agent-command` value (or interactive menu selection) is validated at startup — the binary must exist and be executable before the server accepts connections. The command is never persisted to `common.toml`; it must be supplied each time the bridge is started. The bridge is an operator tool: whoever can invoke it already has local shell access, so the agent command is implicitly trusted to the same degree as any other command that user could run.
|
|
290
310
|
|
|
291
311
|
To rotate credentials (invalidates all paired devices):
|
|
292
312
|
|
|
293
313
|
```bash
|
|
294
|
-
#
|
|
295
|
-
rm ~/Library/Application\ Support/
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
rm ~/Library/Application\ Support/com.aptove.bridge/common.toml # macOS
|
|
301
|
-
rm ~/.config/bridge/common.toml # Linux
|
|
302
|
-
bridge run --agent-command "aptove stdio" --qr
|
|
314
|
+
# macOS
|
|
315
|
+
rm ~/Library/Application\ Support/com.aptove.bridge/common.toml
|
|
316
|
+
# Linux
|
|
317
|
+
rm ~/.config/bridge/common.toml
|
|
318
|
+
|
|
319
|
+
bridge
|
|
303
320
|
```
|
|
304
321
|
|
|
305
322
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aptove/bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "ACP bridge — connects ACP agents to mobile and desktop clients over WebSocket",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"node": ">=16"
|
|
34
34
|
},
|
|
35
35
|
"optionalDependencies": {
|
|
36
|
-
"@aptove/bridge-darwin-arm64": "0.
|
|
37
|
-
"@aptove/bridge-darwin-x64": "0.
|
|
38
|
-
"@aptove/bridge-linux-arm64": "0.
|
|
39
|
-
"@aptove/bridge-linux-x64": "0.
|
|
40
|
-
"@aptove/bridge-win32-x64": "0.
|
|
36
|
+
"@aptove/bridge-darwin-arm64": "0.2.0",
|
|
37
|
+
"@aptove/bridge-darwin-x64": "0.2.0",
|
|
38
|
+
"@aptove/bridge-linux-arm64": "0.2.0",
|
|
39
|
+
"@aptove/bridge-linux-x64": "0.2.0",
|
|
40
|
+
"@aptove/bridge-win32-x64": "0.2.0"
|
|
41
41
|
}
|
|
42
42
|
}
|