@aptove/bridge 0.2.1 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +151 -159
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -5,12 +5,9 @@
5
5
  [![npm](https://img.shields.io/npm/v/%40aptove%2Fbridge?logo=npm&label=npm)](https://www.npmjs.com/package/@aptove/bridge)
6
6
  [![Discord](https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white)](https://discord.gg/gD7AMxBy9y)
7
7
 
8
- A bridge library and application between Agent Client Protocol (ACP) agents and clients.
8
+ Aptove Bridge is a stand-alone app to connect any AI Agents that support Agent Client Protocol (ACP) with the Aptove Mobile App to seamlessly manage the AI agents running in a server or computer.
9
9
 
10
- `aptove-bridge` can be used in two ways:
11
-
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
- - **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.
10
+ Bridge is actively developed and we are still experimenting. Until the first stable version, expect breaking changes in the configuration files and how it works.
14
11
 
15
12
  ## Transport Modes
16
13
 
@@ -18,10 +15,7 @@ A bridge library and application between Agent Client Protocol (ACP) agents and
18
15
  |------|----------|---------------|
19
16
  | **Local** | Same Wi-Fi network, secure pairing with QR code | [docs/transport/local.md](docs/transport/local.md) |
20
17
  | **Cloudflare** | Remote access via Cloudflare Zero Trust (internet-accessible) | [docs/transport/cloudflare.md](docs/transport/cloudflare.md) |
21
- | **Tailscale Serve** | Private overlay network via MagicDNS + HTTPS | [docs/transport/tailscale.md](docs/transport/tailscale.md) |
22
- | **Tailscale IP** | Direct Tailscale IP with self-signed TLS | [docs/transport/tailscale.md](docs/transport/tailscale.md) |
23
-
24
- One transport is active at a time. When multiple are enabled in `common.toml`, the bridge prompts you to select one at startup.
18
+ | **Tailscale** | Private overlay network via MagicDNS + HTTPS (Recommended) | [docs/transport/tailscale.md](docs/transport/tailscale.md) |
25
19
 
26
20
  ## Features
27
21
 
@@ -30,98 +24,38 @@ One transport is active at a time. When multiple are enabled in `common.toml`, t
30
24
  - ⚡ **WebSocket Streaming**: Real-time bidirectional communication
31
25
  - 🌐 **Multi-Transport**: Local, Cloudflare, Tailscale — configure and switch between them
32
26
  - 🔑 **Stable Agent Identity**: `agent_id` UUID persisted in `common.toml` for multi-transport dedup on mobile
27
+ - 🔔 **Push Notifications**: Wake the mobile app when the agent responds while backgrounded
28
+ - 🖥️ **Terminal UI**: Interactive TUI for setup and day-to-day management
33
29
  - 🦀 **Embeddable**: Use as a library with `StdioBridge` for in-process deployment
34
30
 
35
31
  ---
36
32
 
37
- ## Using as a Library
38
-
39
- Add to your `Cargo.toml`:
40
-
41
- ```toml
42
- [dependencies]
43
- aptove-bridge = "0.2"
44
- ```
45
-
46
- ### Minimal Example
47
-
48
- ```rust
49
- use aptove_bridge::{
50
- bridge::StdioBridge,
51
- common_config::CommonConfig,
52
- tls::TlsConfig,
53
- };
54
-
55
- #[tokio::main]
56
- async fn main() -> anyhow::Result<()> {
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
71
- }
72
- ```
73
-
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) |
89
-
90
- ---
91
-
92
- ## Standalone Binary
93
-
94
33
  ### Quick Start
95
34
 
96
35
  ```bash
97
36
  # Build
98
37
  cargo build --release
99
38
 
100
- # Start the bridge — interactive agent selection menu
39
+ # Start the bridge — opens the interactive TUI (setup wizard on first run)
101
40
  ./target/release/bridge
102
41
 
103
- # Or specify the agent directly
104
- ./target/release/bridge run --agent-command "copilot --acp"
42
+ # Use a custom config directory
43
+ ./target/release/bridge -c ./my-config
105
44
  ```
106
45
 
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.
46
+ On first launch the setup wizard runs automatically: it asks you to choose an agent command and a transport, then starts the bridge and shows a QR code for pairing.
108
47
 
109
48
  Scan the QR code with the mobile app to connect.
110
49
 
111
50
  ### Configuration — `common.toml`
112
51
 
113
- All transport settings live in `common.toml`. The file is created automatically with local transport enabled on first run.
114
-
115
- **Default location:**
52
+ All settings live in `common.toml`, created automatically by the setup wizard on first run.
116
53
 
117
- | Platform | Path |
118
- |----------|------|
119
- | macOS | `~/Library/Application Support/com.aptove.bridge/common.toml` |
120
- | Linux | `~/.config/bridge/common.toml` |
54
+ **Default location:** `.aptove-bridge/` directory inside the working directory where the bridge is launched.
121
55
 
122
56
  Override with `-c` / `--config-dir`:
123
57
  ```bash
124
- bridge -c ./my-config run --agent-command "copilot --acp"
58
+ bridge -c ./my-config
125
59
  ```
126
60
 
127
61
  #### Example `common.toml`
@@ -129,6 +63,10 @@ bridge -c ./my-config run --agent-command "copilot --acp"
129
63
  ```toml
130
64
  agent_id = "550e8400-e29b-41d4-a716-446655440000" # auto-generated UUID
131
65
  auth_token = "base64urltoken" # auto-generated
66
+ agent_command = "copilot --acp" # set by setup wizard
67
+
68
+ keep_alive = true # prevent system sleep while bridge is running
69
+ log_level = "WARN" # ERROR / WARN / INFO / DEBUG / TRACE
132
70
 
133
71
  [transports.local]
134
72
  enabled = true
@@ -136,7 +74,7 @@ port = 8765
136
74
  tls = true
137
75
 
138
76
  [transports.cloudflare]
139
- enabled = true
77
+ enabled = false
140
78
  hostname = "https://agent.example.com"
141
79
  tunnel_id = "abc123"
142
80
  tunnel_secret = "..."
@@ -145,15 +83,19 @@ client_id = "client.access"
145
83
  client_secret = "xxxxx"
146
84
 
147
85
  [transports.tailscale-serve]
148
- enabled = true
149
-
150
- [transports.tailscale-ip]
151
- enabled = true
152
- port = 8765
153
- tls = true
86
+ enabled = false
87
+
88
+ # Optional — enables push notifications (see Push Notifications section below)
89
+ [push_relay]
90
+ url = "https://push.aptove.com"
91
+ token_url = "https://token.aptove.com"
92
+ client_id = "your-client-id"
93
+ client_secret = "your-client-secret"
154
94
  ```
155
95
 
156
- Enable only the transports you need. `agent_id` and `auth_token` are generated automatically on first run and stay stable across restarts.
96
+ No transports are pre-enabled. The setup wizard asks you to choose one on first run.
97
+
98
+ `agent_id` and `auth_token` are generated automatically on first run and stay stable across restarts.
157
99
 
158
100
  #### Config Directory Files
159
101
 
@@ -161,33 +103,30 @@ All bridge state lives in the config directory. These files are created automati
161
103
 
162
104
  | File | Purpose |
163
105
  |------|---------|
164
- | `common.toml` | Main config — `agent_id`, `auth_token`, and transport settings. Permissions `0600`. |
106
+ | `common.toml` | Main config — `agent_id`, `auth_token`, `agent_command`, and transport settings. Permissions `0600`. |
165
107
  | `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
108
  | `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
-
169
- ### Commands
109
+ | `cert-extra-sans.json` | Tracks extra Subject Alternative Names (IPs/hostnames) baked into the TLS cert. When these change, the cert is automatically regenerated. |
170
110
 
171
- #### `run` — Start the bridge (default)
111
+ ### CLI
172
112
 
173
- `run` is the default subcommand — running `bridge` with no arguments is equivalent to `bridge run`.
113
+ ```
114
+ bridge [OPTIONS] [COMMAND]
115
+ ```
174
116
 
175
- ```bash
176
- # Interactive agent selection
177
- bridge
117
+ | Flag | Short | Description |
118
+ |------|-------|-------------|
119
+ | `--config-dir <PATH>` | `-c` | Use a custom config directory instead of `.aptove-bridge/` |
120
+ | `--version` | `-v` | Print version |
178
121
 
179
- # Or specify the agent directly
180
- bridge run --agent-command "copilot --acp"
181
- ```
122
+ | Subcommand | Description |
123
+ |------------|-------------|
124
+ | *(none)* | Start the TUI (setup wizard if needed, then running screen) |
125
+ | `setup` | Re-run the Cloudflare Zero Trust setup wizard |
182
126
 
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 |
127
+ #### `bridge` (default — TUI)
189
128
 
190
- When `--agent-command` is omitted, the bridge presents an interactive menu:
129
+ Running `bridge` with no arguments opens the interactive TUI. On first launch it runs the setup wizard:
191
130
 
192
131
  ```
193
132
  Select an agent to run:
@@ -198,52 +137,123 @@ Select an agent to run:
198
137
  Enter number [1]:
199
138
  ```
200
139
 
201
- The QR code for pairing is always displayed at startup.
140
+ Select **Custom** to enter any ACP-compatible agent command, for example:
141
+
142
+ ```
143
+ npx @agentclientprotocol/claude-agent-acp
144
+ ```
145
+
146
+ After the wizard completes the bridge starts and displays a QR code for pairing.
202
147
 
203
- Transport selection, port, TLS, and auth token are all read from `common.toml`.
148
+ #### `bridge setup`
204
149
 
205
- #### `show-qr` — Show QR code for a second device
150
+ Re-runs the Cloudflare Zero Trust setup wizard as a TUI flow. Use this to reconfigure your Cloudflare tunnel credentials without restarting the running bridge.
206
151
 
207
152
  ```bash
208
- bridge show-qr
153
+ bridge setup
209
154
  ```
210
155
 
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.
156
+ No flags are needed — the wizard guides you through everything interactively.
212
157
 
213
- #### `setup` — Provision Cloudflare infrastructure
158
+ ### TUI slash commands
214
159
 
215
- ```bash
216
- bridge setup \
217
- --api-token "your-api-token" \
218
- --account-id "your-account-id" \
219
- --domain "example.com" \
220
- --subdomain "agent"
160
+ Type these in the input bar while the bridge is running:
161
+
162
+ | Command | Description |
163
+ |---------|-------------|
164
+ | `/qr` | Show QR pairing code |
165
+ | `/agent` | Change the AI agent command |
166
+ | `/push` | Configure push notifications |
167
+ | `/test-push` | Send a test push notification |
168
+ | `/reconnect` | Restart the transport |
169
+ | `/keep-alive` | Toggle prevent-sleep (on by default) |
170
+ | `/log-level` | Change log verbosity (default: WARN) |
171
+ | `/clear-logs` | Clear the log view |
172
+ | `/copy-logs` | Copy all logs to clipboard |
173
+ | `/help` | List all commands |
174
+ | `/quit` | Exit the bridge |
175
+
176
+ ---
177
+
178
+ ## Push Notifications
179
+
180
+ The bridge can alert the mobile app when the agent produces output while the app is backgrounded (WebSocket disconnected). The bridge never holds APNs/FCM credentials — it authenticates to a push relay service using a short-lived RS256 JWT and the relay handles APNs/FCM delivery.
181
+
182
+ ### How it works
183
+
184
+ ```
185
+ Mobile app (backgrounded) Bridge Push relay
186
+ (push.aptove.com)
187
+ │ │ │
188
+ │ [app backgrounds] │ │
189
+ │ │ │
190
+ │ │ agent produces output │
191
+ │ │◄───────────────────── │
192
+ │ │ │
193
+ │ │ no WebSocket receiver │
194
+ │ │ (broadcast send fails) │
195
+ │ │ │
196
+ │ │ POST /push (JWT Bearer) ───►│
197
+ │ │ │
198
+ │◄────────────────────────── APNs/FCM notification │
199
+ │ │ │
200
+ │ [app foregrounds] │ │
201
+ │ reconnects WebSocket ─────►│ │
202
+ │◄── buffered messages ───────│ │
221
203
  ```
222
204
 
223
- Creates the Cloudflare tunnel, DNS record, Access Application, and Service Token. Saves credentials to `common.toml` under `[transports.cloudflare]`. Only needed once.
205
+ ### Trigger logic
224
206
 
225
- | Flag | Description | Default |
226
- |------|-------------|---------|
227
- | `--api-token <TOKEN>` | Cloudflare API token | Required |
228
- | `--account-id <ID>` | Cloudflare account ID | Required |
229
- | `--domain <DOMAIN>` | Domain managed by Cloudflare | Required |
230
- | `--subdomain <SUB>` | Subdomain for the bridge endpoint | `agent` |
231
- | `--tunnel-name <NAME>` | Name for the Cloudflare tunnel | `aptove-tunnel` |
207
+ Push is triggered by **passive failure detection** — the bridge never polls for connectivity:
232
208
 
233
- #### `status` — Check configuration
209
+ | Site | Trigger | Source |
210
+ |------|---------|--------|
211
+ | Agent pool (main path) | Agent stdout arrives; `broadcast::Sender::send()` returns `Err` (zero receivers — no WebSocket client connected) | `src/agent_pool.rs` |
212
+ | Active connection drop | `ws_sender.send()` returns `Err` (client disconnected mid-stream); message is buffered before notify | `src/bridge.rs` |
234
213
 
235
- ```bash
236
- bridge status
214
+ A 30-second per-client debounce prevents notification storms when the agent is verbose.
215
+
216
+ ### Setup
217
+
218
+ Configure push via the `/push` TUI command or add the `[push_relay]` section directly to `common.toml`:
219
+
220
+ ```toml
221
+ [push_relay]
222
+ url = "https://push.aptove.com" # Push relay base URL
223
+ token_url = "https://token.aptove.com" # JWT token service URL
224
+ client_id = "your-client-id" # M2M client ID (JWT sub)
225
+ client_secret = "your-client-secret" # M2M client secret
237
226
  ```
238
227
 
239
- Prints the active `common.toml` path, `agent_id`, enabled transports, and Tailscale availability.
228
+ All four fields are required. If the section is absent or any field is empty, push is silently disabled. The push relay URL is included in the QR pairing payload so the mobile app knows where to register its device token.
229
+
230
+ ### Security
231
+
232
+ - Device tokens travel over the bridge's authenticated WebSocket (bearer `authToken` + TLS) — the same channel that carries the full LLM conversation.
233
+ - JWT credentials (`client_id`, `client_secret`) never leave the bridge process.
234
+ - The relay isolates registered devices per JWT `sub` (`client_id`) — one bridge cannot trigger pushes for another bridge's devices.
235
+ - Notification content is fixed (`"Your agent has new activity"`) to prevent leaking agent response text.
236
+
237
+ ### Library usage
238
+
239
+ ```rust
240
+ use aptove_bridge::push::PushRelayClient;
241
+
242
+ let push_client = PushRelayClient::new("https://push.aptove.com".into(), String::new())
243
+ .with_jwt_credentials(
244
+ "https://token.aptove.com".into(),
245
+ "your-client-id".into(),
246
+ "your-client-secret".into(),
247
+ );
248
+
249
+ let bridge = StdioBridge::new("copilot --acp".into(), 8765)
250
+ .with_push_relay(push_client);
251
+ ```
240
252
 
241
253
  ---
242
254
 
243
255
  ## Architecture
244
256
 
245
- ### Standalone
246
-
247
257
  ```
248
258
  ┌─────────────┐ ┌───────────────────────┐ ┌──────────────┐
249
259
  │ Client App │◄──────────────────►│ bridge binary │◄──────►│ ACP Agent │
@@ -251,16 +261,7 @@ Prints the active `common.toml` path, `agent_id`, enabled transports, and Tailsc
251
261
  └─────────────┘ └───────────────────────┘ └──────────────┘
252
262
  ```
253
263
 
254
- ### Embedded (library)
255
-
256
- ```
257
- ┌─────────────┐ ┌──────────────────────────────────┐ ┌──────────────┐
258
- │ Client App │◄──────────────────►│ Your process │◄──────►│ ACP Agent │
259
- │ (iOS/Android│ WebSocket (TLS) │ StdioBridge (transport listener)│ stdio │ (your cmd) │
260
- └─────────────┘ └──────────────────────────────────┘ └──────────────┘
261
- ```
262
-
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.
264
+ The agent process is spawned as a subprocess via stdio — `StdioBridge` handles the WebSocket server, TLS, auth, and pairing in-process alongside your application.
264
265
 
265
266
  ---
266
267
 
@@ -272,16 +273,16 @@ The agent process is still spawned as a subprocess via stdio — `StdioBridge` h
272
273
  | "Unauthorized" on connect | Wrong or missing auth token | Re-scan QR code |
273
274
  | TLS handshake failure | Certificate mismatch | Delete the config dir and restart to regenerate certs; re-pair the device |
274
275
  | App cannot reach bridge | Firewall blocking the port | Check OS firewall; ensure the port in `common.toml` is open |
275
- | Transport fails to start | `common.toml` has no `enabled = true` transport | Run `bridge status` to see configured transports |
276
+ | Transport fails to start | No transport has `enabled = true` | Run the bridge and check the setup wizard |
276
277
 
277
278
  ### Debugging
278
279
 
279
280
  ```bash
280
- # Enable verbose logging
281
- bridge run --verbose
281
+ # Change log verbosity via TUI
282
+ # Type /log-level and select DEBUG or TRACE
282
283
 
283
- # Check which transports are configured
284
- bridge status
284
+ # Or set it permanently in common.toml
285
+ log_level = "DEBUG"
285
286
 
286
287
  # Test agent command independently
287
288
  echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | copilot --acp
@@ -291,12 +292,7 @@ echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | copilot --acp
291
292
 
292
293
  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
 
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
299
- ```
295
+ Run `bridge` and pick an agent from the setup wizard, or edit `agent_command` directly in `common.toml`.
300
296
 
301
297
  ---
302
298
 
@@ -306,16 +302,12 @@ bridge run -a "goose acp" --verbose
306
302
  - **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.
307
303
  - **Pairing codes**: 6-digit, single-use, expire after 60 seconds. Rate-limited to 5 attempts per code.
308
304
  - **`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.
305
+ - **Agent command**: saved to `agent_command` in `common.toml` by the setup wizard. It can be changed at any time via the `/agent` TUI command. 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.
310
306
 
311
307
  To rotate credentials (invalidates all paired devices):
312
308
 
313
309
  ```bash
314
- # macOS
315
- rm ~/Library/Application\ Support/com.aptove.bridge/common.toml
316
- # Linux
317
- rm ~/.config/bridge/common.toml
318
-
310
+ rm .aptove-bridge/common.toml
319
311
  bridge
320
312
  ```
321
313
 
@@ -330,4 +322,4 @@ cargo test # Run tests
330
322
 
331
323
  ## License
332
324
 
333
- Apache 2.0 — see [LICENSE](LICENSE)
325
+ MIT — see [LICENSE](LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aptove/bridge",
3
- "version": "0.2.1",
3
+ "version": "0.2.5",
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.2.1",
37
- "@aptove/bridge-darwin-x64": "0.2.1",
38
- "@aptove/bridge-linux-arm64": "0.2.1",
39
- "@aptove/bridge-linux-x64": "0.2.1",
40
- "@aptove/bridge-win32-x64": "0.2.1"
36
+ "@aptove/bridge-darwin-arm64": "0.2.5",
37
+ "@aptove/bridge-darwin-x64": "0.2.5",
38
+ "@aptove/bridge-linux-arm64": "0.2.5",
39
+ "@aptove/bridge-linux-x64": "0.2.5",
40
+ "@aptove/bridge-win32-x64": "0.2.5"
41
41
  }
42
42
  }