@agentvault/secure-channel 0.5.0 → 0.6.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 +37 -16
- package/dist/channel.d.ts.map +1 -1
- package/dist/cli.js +191 -25
- package/dist/cli.js.map +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -15
- package/dist/index.js.map +4 -4
- package/dist/openclaw-entry.d.ts +16 -0
- package/dist/openclaw-entry.d.ts.map +1 -0
- package/dist/openclaw-plugin.d.ts +57 -0
- package/dist/openclaw-plugin.d.ts.map +1 -0
- package/dist/setup.d.ts +15 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/transport.d.ts +3 -1
- package/dist/transport.d.ts.map +1 -1
- package/openclaw.plugin.json +13 -0
- package/package.json +26 -3
package/README.md
CHANGED
|
@@ -2,28 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
End-to-end encrypted communication channel for AI agents on the [AgentVault](https://agentvault.chat) platform. Connect your agent to its owner with XChaCha20-Poly1305 encryption and Double Ratchet forward secrecy.
|
|
4
4
|
|
|
5
|
-
## What's New in v0.
|
|
5
|
+
## What's New in v0.5.0
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Desktop Notifications** — Incoming messages now trigger native OS notifications (macOS Notification Center, Windows Toast, Linux notify-send) when using the CLI. Enabled by default — disable with `--no-notifications`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Webhook URL CLI Flag** (v0.4.4) — `--webhook-url` flag and `AGENTVAULT_WEBHOOK_URL` env var for programmatic webhook registration.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
npm install @agentvault/secure-channel@latest
|
|
13
|
-
```
|
|
11
|
+
**Webhook Notifications** (v0.4.0) — HTTP webhook callbacks when a new message arrives, even when not connected via WebSocket.
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
### Upgrading
|
|
16
14
|
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
inviteToken: "your-token",
|
|
20
|
-
dataDir: "./agentvault-data",
|
|
21
|
-
apiUrl: "https://api.agentvault.chat",
|
|
22
|
-
webhookUrl: "https://your-server.com/webhook/agentvault", // NEW in 0.4.0
|
|
23
|
-
});
|
|
15
|
+
```bash
|
|
16
|
+
npm install @agentvault/secure-channel@latest
|
|
24
17
|
```
|
|
25
18
|
|
|
26
|
-
No
|
|
19
|
+
No code changes required — fully backward-compatible.
|
|
27
20
|
|
|
28
21
|
---
|
|
29
22
|
|
|
@@ -58,8 +51,10 @@ The CLI will:
|
|
|
58
51
|
| `--name` | `"CLI Agent"` | Agent display name |
|
|
59
52
|
| `--data-dir` | `./agentvault-data` | Directory for persistent state |
|
|
60
53
|
| `--api-url` | `https://api.agentvault.chat` | API endpoint |
|
|
54
|
+
| `--webhook-url` | (none) | URL for HTTP webhook notifications |
|
|
55
|
+
| `--no-notifications` | (notifications on) | Disable OS desktop notifications |
|
|
61
56
|
|
|
62
|
-
Environment variables (`AGENTVAULT_INVITE_TOKEN`, `AGENTVAULT_AGENT_NAME`, `AGENTVAULT_DATA_DIR`, `AGENTVAULT_API_URL`) work as alternatives to flags.
|
|
57
|
+
Environment variables (`AGENTVAULT_INVITE_TOKEN`, `AGENTVAULT_AGENT_NAME`, `AGENTVAULT_DATA_DIR`, `AGENTVAULT_API_URL`, `AGENTVAULT_WEBHOOK_URL`, `AGENTVAULT_NO_NOTIFICATIONS`) work as alternatives to flags.
|
|
63
58
|
|
|
64
59
|
### Option 2: SDK (Programmatic)
|
|
65
60
|
|
|
@@ -216,6 +211,32 @@ AgentVault supports multiple owner devices (e.g., desktop + mobile). The channel
|
|
|
216
211
|
|
|
217
212
|
No additional configuration needed — multi-device is handled transparently.
|
|
218
213
|
|
|
214
|
+
## Running as a Service
|
|
215
|
+
|
|
216
|
+
The agent process must stay running to receive messages and desktop notifications. Use [pm2](https://pm2.keymetrics.io/) to keep it alive:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Install pm2 globally
|
|
220
|
+
npm install -g pm2
|
|
221
|
+
|
|
222
|
+
# Start your agent as a background service
|
|
223
|
+
pm2 start npx --name "my-agent" -- @agentvault/secure-channel \
|
|
224
|
+
--token=YOUR_TOKEN --name="My Agent"
|
|
225
|
+
|
|
226
|
+
# View logs
|
|
227
|
+
pm2 logs my-agent
|
|
228
|
+
|
|
229
|
+
# Auto-restart on crash
|
|
230
|
+
pm2 save
|
|
231
|
+
|
|
232
|
+
# Stop the agent
|
|
233
|
+
pm2 stop my-agent
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
pm2 keeps the process running if the terminal closes and auto-restarts on crashes. Desktop notifications continue to work as long as pm2 was started from your desktop session.
|
|
237
|
+
|
|
238
|
+
For headless servers (no desktop), use `--no-notifications` and configure `--webhook-url` instead.
|
|
239
|
+
|
|
219
240
|
## Security
|
|
220
241
|
|
|
221
242
|
- **XChaCha20-Poly1305** symmetric encryption (192-bit nonces)
|
package/dist/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EAKb,MAAM,YAAY,CAAC;AAiDpB,qBAAa,aAAc,SAAQ,YAAY;IAiBjC,OAAO,CAAC,MAAM;IAhB1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAGH;IACd,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAA+B;gBAE7B,MAAM,EAAE,mBAAmB;IAI/C,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED,iEAAiE;IACjE,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAED,2CAA2C;IAC3C,IAAI,eAAe,IAAI,MAAM,EAAE,CAE9B;IAED,6CAA6C;IAC7C,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;OAGG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCtE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAsC1F;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;YAiCtE,OAAO;IAgDrB,OAAO,CAAC,KAAK;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EAKb,MAAM,YAAY,CAAC;AAiDpB,qBAAa,aAAc,SAAQ,YAAY;IAiBjC,OAAO,CAAC,MAAM;IAhB1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAGH;IACd,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAA+B;gBAE7B,MAAM,EAAE,mBAAmB;IAI/C,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED,iEAAiE;IACjE,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAED,2CAA2C;IAC3C,IAAI,eAAe,IAAI,MAAM,EAAE,CAE9B;IAED,6CAA6C;IAC7C,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;OAGG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCtE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAsC1F;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;YAiCtE,OAAO;IAgDrB,OAAO,CAAC,KAAK;YAsCC,SAAS;IAyIvB,OAAO,CAAC,QAAQ;IAsEhB;;;;OAIG;YACW,sBAAsB;IAwFpC;;;OAGG;YACW,oBAAoB;IAqClC;;;OAGG;YACW,uBAAuB;IAkCrC;;;;OAIG;YACW,mBAAmB;IAkEjC;;;OAGG;YACW,mBAAmB;IA4FjC,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,YAAY;IAKpB;;;OAGG;YACW,aAAa;CAc5B"}
|
package/dist/cli.js
CHANGED
|
@@ -89,7 +89,7 @@ var randomValuesStandard;
|
|
|
89
89
|
var crypto;
|
|
90
90
|
var randomValueNodeJS;
|
|
91
91
|
var _Module = Module;
|
|
92
|
-
Module.ready = new Promise(function(
|
|
92
|
+
Module.ready = new Promise(function(resolve3, reject) {
|
|
93
93
|
var Module2 = _Module;
|
|
94
94
|
Module2.onAbort = reject;
|
|
95
95
|
Module2.print = function(what) {
|
|
@@ -101,13 +101,13 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
101
101
|
Module2.onRuntimeInitialized = function() {
|
|
102
102
|
try {
|
|
103
103
|
Module2._crypto_secretbox_keybytes();
|
|
104
|
-
|
|
104
|
+
resolve3();
|
|
105
105
|
} catch (err2) {
|
|
106
106
|
reject(err2);
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
109
|
Module2.useBackupModule = function() {
|
|
110
|
-
return new Promise(function(
|
|
110
|
+
return new Promise(function(resolve4, reject2) {
|
|
111
111
|
var Module3 = {};
|
|
112
112
|
Module3.onAbort = reject2;
|
|
113
113
|
Module3.getRandomValue = _Module.getRandomValue;
|
|
@@ -120,7 +120,7 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
120
120
|
Object.keys(Module3).forEach(function(k2) {
|
|
121
121
|
_Module[k2] = Module3[k2];
|
|
122
122
|
});
|
|
123
|
-
|
|
123
|
+
resolve4();
|
|
124
124
|
};
|
|
125
125
|
var Module3 = typeof Module3 != "undefined" ? Module3 : {};
|
|
126
126
|
var ENVIRONMENT_IS_WEB2 = !!globalThis.window;
|
|
@@ -180,13 +180,13 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
180
180
|
}
|
|
181
181
|
readAsync2 = async (url) => {
|
|
182
182
|
if (isFileURI2(url)) {
|
|
183
|
-
return new Promise((
|
|
183
|
+
return new Promise((resolve5, reject3) => {
|
|
184
184
|
var xhr = new XMLHttpRequest();
|
|
185
185
|
xhr.open("GET", url, true);
|
|
186
186
|
xhr.responseType = "arraybuffer";
|
|
187
187
|
xhr.onload = () => {
|
|
188
188
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
189
|
-
|
|
189
|
+
resolve5(xhr.response);
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
192
192
|
reject3(xhr.status);
|
|
@@ -40099,9 +40099,9 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
40099
40099
|
}
|
|
40100
40100
|
var info = getWasmImports2();
|
|
40101
40101
|
if (Module3["instantiateWasm"]) {
|
|
40102
|
-
return new Promise((
|
|
40102
|
+
return new Promise((resolve5, reject3) => {
|
|
40103
40103
|
Module3["instantiateWasm"](info, (inst, mod) => {
|
|
40104
|
-
|
|
40104
|
+
resolve5(receiveInstance(inst, mod));
|
|
40105
40105
|
});
|
|
40106
40106
|
});
|
|
40107
40107
|
}
|
|
@@ -41004,13 +41004,13 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
41004
41004
|
}
|
|
41005
41005
|
readAsync = async (url) => {
|
|
41006
41006
|
if (isFileURI(url)) {
|
|
41007
|
-
return new Promise((
|
|
41007
|
+
return new Promise((resolve4, reject2) => {
|
|
41008
41008
|
var xhr = new XMLHttpRequest();
|
|
41009
41009
|
xhr.open("GET", url, true);
|
|
41010
41010
|
xhr.responseType = "arraybuffer";
|
|
41011
41011
|
xhr.onload = () => {
|
|
41012
41012
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
41013
|
-
|
|
41013
|
+
resolve4(xhr.response);
|
|
41014
41014
|
return;
|
|
41015
41015
|
}
|
|
41016
41016
|
reject2(xhr.status);
|
|
@@ -41124,9 +41124,9 @@ Module.ready = new Promise(function(resolve2, reject) {
|
|
|
41124
41124
|
}
|
|
41125
41125
|
var info = getWasmImports();
|
|
41126
41126
|
if (Module2["instantiateWasm"]) {
|
|
41127
|
-
return new Promise((
|
|
41127
|
+
return new Promise((resolve4, reject2) => {
|
|
41128
41128
|
Module2["instantiateWasm"](info, (inst, mod) => {
|
|
41129
|
-
|
|
41129
|
+
resolve4(receiveInstance(inst, mod));
|
|
41130
41130
|
});
|
|
41131
41131
|
});
|
|
41132
41132
|
}
|
|
@@ -45013,6 +45013,9 @@ async function enrollDevice(apiUrl2, inviteToken, identityPkHex, ephemeralPkHex,
|
|
|
45013
45013
|
}
|
|
45014
45014
|
async function pollDeviceStatus(apiUrl2, deviceId) {
|
|
45015
45015
|
const res = await fetch(`${apiUrl2}/api/v1/devices/${deviceId}/status`);
|
|
45016
|
+
if (res.status === 429) {
|
|
45017
|
+
return { device_id: deviceId, status: "PENDING", fingerprint: "", rateLimited: true };
|
|
45018
|
+
}
|
|
45016
45019
|
if (!res.ok) {
|
|
45017
45020
|
const detail = await res.text();
|
|
45018
45021
|
throw new Error(`Status poll failed (${res.status}): ${detail}`);
|
|
@@ -45033,7 +45036,7 @@ async function activateDevice(apiUrl2, deviceId) {
|
|
|
45033
45036
|
}
|
|
45034
45037
|
|
|
45035
45038
|
// src/channel.ts
|
|
45036
|
-
var POLL_INTERVAL_MS =
|
|
45039
|
+
var POLL_INTERVAL_MS = 6e3;
|
|
45037
45040
|
var RECONNECT_BASE_MS = 1e3;
|
|
45038
45041
|
var RECONNECT_MAX_MS = 3e4;
|
|
45039
45042
|
function migratePersistedState(raw) {
|
|
@@ -45318,6 +45321,10 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45318
45321
|
this.config.apiUrl,
|
|
45319
45322
|
this._deviceId
|
|
45320
45323
|
);
|
|
45324
|
+
if (status.rateLimited) {
|
|
45325
|
+
this._pollTimer = setTimeout(doPoll, POLL_INTERVAL_MS * 2);
|
|
45326
|
+
return;
|
|
45327
|
+
}
|
|
45321
45328
|
if (status.status === "APPROVED") {
|
|
45322
45329
|
await this._activate();
|
|
45323
45330
|
return;
|
|
@@ -45768,10 +45775,137 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45768
45775
|
};
|
|
45769
45776
|
|
|
45770
45777
|
// src/cli.ts
|
|
45771
|
-
import { resolve } from "node:path";
|
|
45778
|
+
import { resolve as resolve2 } from "node:path";
|
|
45772
45779
|
import { createInterface } from "node:readline";
|
|
45773
|
-
|
|
45780
|
+
|
|
45781
|
+
// src/setup.ts
|
|
45782
|
+
import { execSync } from "node:child_process";
|
|
45783
|
+
import { resolve } from "node:path";
|
|
45784
|
+
async function runSetupCommand(options) {
|
|
45785
|
+
const { token: token2, name: name2, apiUrl: apiUrl2 } = options;
|
|
45786
|
+
const dataDir2 = resolve(options.dataDir.replace(/^~/, process.env.HOME ?? "~"));
|
|
45787
|
+
console.log(`
|
|
45788
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
45789
|
+
\u2551 AgentVault \u2014 First-Time Setup \u2551
|
|
45790
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
45791
|
+
|
|
45792
|
+
Agent name : ${name2}
|
|
45793
|
+
Data dir : ${dataDir2}
|
|
45794
|
+
API : ${apiUrl2}
|
|
45795
|
+
`);
|
|
45796
|
+
let enrollDone = false;
|
|
45797
|
+
const channel2 = new SecureChannel({
|
|
45798
|
+
inviteToken: token2,
|
|
45799
|
+
dataDir: dataDir2,
|
|
45800
|
+
apiUrl: apiUrl2,
|
|
45801
|
+
agentName: name2,
|
|
45802
|
+
onMessage: () => {
|
|
45803
|
+
},
|
|
45804
|
+
// Not handling messages during setup
|
|
45805
|
+
onStateChange: (state) => {
|
|
45806
|
+
switch (state) {
|
|
45807
|
+
case "enrolling":
|
|
45808
|
+
console.log(" Enrolling with AgentVault server...");
|
|
45809
|
+
break;
|
|
45810
|
+
case "polling":
|
|
45811
|
+
console.log(" Waiting for approval in your AgentVault dashboard...");
|
|
45812
|
+
if (channel2.fingerprint) {
|
|
45813
|
+
console.log(`
|
|
45814
|
+
Fingerprint: ${channel2.fingerprint}`);
|
|
45815
|
+
console.log(" Verify this fingerprint matches the one shown in your dashboard");
|
|
45816
|
+
console.log(" before clicking Approve.\n");
|
|
45817
|
+
}
|
|
45818
|
+
break;
|
|
45819
|
+
case "activating":
|
|
45820
|
+
console.log(" Approved! Setting up encryption...");
|
|
45821
|
+
break;
|
|
45822
|
+
case "ready":
|
|
45823
|
+
enrollDone = true;
|
|
45824
|
+
console.log(" \u2705 Enrollment complete! Secure channel established.\n");
|
|
45825
|
+
break;
|
|
45826
|
+
case "error":
|
|
45827
|
+
console.error(" \u274C Setup encountered an error.");
|
|
45828
|
+
break;
|
|
45829
|
+
}
|
|
45830
|
+
}
|
|
45831
|
+
});
|
|
45832
|
+
channel2.on("error", (err) => {
|
|
45833
|
+
console.error(`
|
|
45834
|
+
\u274C Setup failed: ${err.message}
|
|
45835
|
+
`);
|
|
45836
|
+
process.exit(1);
|
|
45837
|
+
});
|
|
45838
|
+
await new Promise((res, rej) => {
|
|
45839
|
+
const check = setInterval(() => {
|
|
45840
|
+
if (enrollDone) {
|
|
45841
|
+
clearInterval(check);
|
|
45842
|
+
res();
|
|
45843
|
+
}
|
|
45844
|
+
}, 500);
|
|
45845
|
+
channel2.start().catch((err) => {
|
|
45846
|
+
clearInterval(check);
|
|
45847
|
+
rej(err);
|
|
45848
|
+
});
|
|
45849
|
+
});
|
|
45850
|
+
await channel2.stop();
|
|
45851
|
+
console.log(" Registering AgentVault channel in OpenClaw config...\n");
|
|
45852
|
+
const patchCommands = [
|
|
45853
|
+
`openclaw config set channels.agentvault.dataDir "${dataDir2}"`,
|
|
45854
|
+
`openclaw config set channels.agentvault.apiUrl "${apiUrl2}"`,
|
|
45855
|
+
`openclaw config set channels.agentvault.agentName "${name2}"`
|
|
45856
|
+
];
|
|
45857
|
+
let configPatched = false;
|
|
45858
|
+
for (const cmd of patchCommands) {
|
|
45859
|
+
try {
|
|
45860
|
+
execSync(cmd, { stdio: "pipe" });
|
|
45861
|
+
configPatched = true;
|
|
45862
|
+
} catch {
|
|
45863
|
+
configPatched = false;
|
|
45864
|
+
break;
|
|
45865
|
+
}
|
|
45866
|
+
}
|
|
45867
|
+
if (configPatched) {
|
|
45868
|
+
console.log(` \u2705 Channel registered in OpenClaw config.
|
|
45869
|
+
|
|
45870
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
45871
|
+
Restart OpenClaw to activate the secure channel:
|
|
45872
|
+
|
|
45873
|
+
openclaw gateway restart
|
|
45874
|
+
|
|
45875
|
+
After restart, your AgentVault UI will route
|
|
45876
|
+
encrypted messages directly into your agent.
|
|
45877
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
45878
|
+
`);
|
|
45879
|
+
} else {
|
|
45880
|
+
console.log(` \u26A0\uFE0F Could not auto-configure OpenClaw (is 'openclaw' in your PATH?).
|
|
45881
|
+
Add this to your OpenClaw config (openclaw.yaml or openclaw.json) manually:
|
|
45882
|
+
|
|
45883
|
+
channels:
|
|
45884
|
+
agentvault:
|
|
45885
|
+
dataDir: "${dataDir2}"
|
|
45886
|
+
apiUrl: "${apiUrl2}"
|
|
45887
|
+
agentName: "${name2}"
|
|
45888
|
+
|
|
45889
|
+
Then restart OpenClaw:
|
|
45890
|
+
openclaw gateway restart
|
|
45891
|
+
`);
|
|
45892
|
+
}
|
|
45893
|
+
}
|
|
45894
|
+
|
|
45895
|
+
// src/cli.ts
|
|
45896
|
+
var _notifier = null;
|
|
45897
|
+
async function tryNotify(title, message) {
|
|
45898
|
+
try {
|
|
45899
|
+
if (!_notifier) {
|
|
45900
|
+
const mod = await import("node-notifier");
|
|
45901
|
+
_notifier = mod.default ?? mod;
|
|
45902
|
+
}
|
|
45903
|
+
_notifier.notify({ title, message, sound: true });
|
|
45904
|
+
} catch {
|
|
45905
|
+
}
|
|
45906
|
+
}
|
|
45774
45907
|
var args = process.argv.slice(2);
|
|
45908
|
+
var subcommand = args[0]?.startsWith("--") ? null : args[0] ?? null;
|
|
45775
45909
|
var flags = {};
|
|
45776
45910
|
for (const arg of args) {
|
|
45777
45911
|
const kvMatch = arg.match(/^--(\w[\w-]*)=(.+)$/);
|
|
@@ -45787,12 +45921,45 @@ var dataDir = flags["data-dir"] || process.env.AGENTVAULT_DATA_DIR || "./agentva
|
|
|
45787
45921
|
var apiUrl = flags["api-url"] || process.env.AGENTVAULT_API_URL || "https://api.agentvault.chat";
|
|
45788
45922
|
var webhookUrl = flags["webhook-url"] || process.env.AGENTVAULT_WEBHOOK_URL;
|
|
45789
45923
|
var noNotifications = flags["no-notifications"] === "true" || process.env.AGENTVAULT_NO_NOTIFICATIONS === "1";
|
|
45924
|
+
if (subcommand === "setup") {
|
|
45925
|
+
if (!token) {
|
|
45926
|
+
console.error(`
|
|
45927
|
+
AgentVault Setup
|
|
45928
|
+
|
|
45929
|
+
Usage:
|
|
45930
|
+
npx @agentvault/secure-channel setup --token=YOUR_INVITE_TOKEN
|
|
45931
|
+
|
|
45932
|
+
Options:
|
|
45933
|
+
--token=TOKEN Invite token from the AgentVault dashboard (required)
|
|
45934
|
+
--name=NAME Agent display name (default: "CLI Agent")
|
|
45935
|
+
--data-dir=PATH Directory for persistent state (default: ~/.openclaw/agentvault)
|
|
45936
|
+
--api-url=URL API endpoint (default: https://api.agentvault.chat)
|
|
45937
|
+
|
|
45938
|
+
This command:
|
|
45939
|
+
1. Enrolls this machine as your agent with AgentVault
|
|
45940
|
+
2. Waits for your approval in the AgentVault dashboard
|
|
45941
|
+
3. Saves the encrypted session to --data-dir
|
|
45942
|
+
4. Registers the agentvault channel in your OpenClaw config
|
|
45943
|
+
|
|
45944
|
+
After setup, restart OpenClaw \u2014 messages will flow automatically.
|
|
45945
|
+
`);
|
|
45946
|
+
process.exit(1);
|
|
45947
|
+
}
|
|
45948
|
+
await runSetupCommand({
|
|
45949
|
+
token,
|
|
45950
|
+
name,
|
|
45951
|
+
apiUrl,
|
|
45952
|
+
dataDir: flags["data-dir"] || process.env.AGENTVAULT_DATA_DIR || "~/.openclaw/agentvault"
|
|
45953
|
+
});
|
|
45954
|
+
process.exit(0);
|
|
45955
|
+
}
|
|
45790
45956
|
if (!token) {
|
|
45791
45957
|
console.error(`
|
|
45792
45958
|
AgentVault Secure Channel CLI
|
|
45793
45959
|
|
|
45794
45960
|
Usage:
|
|
45795
|
-
npx @agentvault/secure-channel --token=
|
|
45961
|
+
npx @agentvault/secure-channel setup --token=TOKEN # First-time OpenClaw setup
|
|
45962
|
+
npx @agentvault/secure-channel --token=TOKEN # Standalone interactive CLI
|
|
45796
45963
|
|
|
45797
45964
|
Options:
|
|
45798
45965
|
--token=TOKEN Invite token from the AgentVault dashboard (required on first run)
|
|
@@ -45800,7 +45967,7 @@ Options:
|
|
|
45800
45967
|
--data-dir=PATH Directory for persistent state (default: ./agentvault-data)
|
|
45801
45968
|
--api-url=URL API endpoint (default: https://api.agentvault.chat)
|
|
45802
45969
|
--webhook-url=URL URL for HTTP webhook notifications on new messages
|
|
45803
|
-
--no-notifications Disable OS desktop notifications
|
|
45970
|
+
--no-notifications Disable OS desktop notifications
|
|
45804
45971
|
|
|
45805
45972
|
Environment variables:
|
|
45806
45973
|
AGENTVAULT_INVITE_TOKEN Same as --token
|
|
@@ -45810,9 +45977,12 @@ Environment variables:
|
|
|
45810
45977
|
AGENTVAULT_WEBHOOK_URL Same as --webhook-url
|
|
45811
45978
|
AGENTVAULT_NO_NOTIFICATIONS Set to "1" to disable desktop notifications
|
|
45812
45979
|
|
|
45813
|
-
|
|
45980
|
+
Examples:
|
|
45981
|
+
# One-time OpenClaw setup (recommended):
|
|
45982
|
+
npx @agentvault/secure-channel setup --token=av_tok_abc123
|
|
45983
|
+
|
|
45984
|
+
# Standalone interactive CLI:
|
|
45814
45985
|
npx @agentvault/secure-channel --token=av_tok_abc123 --name="My Agent"
|
|
45815
|
-
npx @agentvault/secure-channel --token=av_tok_abc123 --webhook-url=https://myapp.com/webhook
|
|
45816
45986
|
`);
|
|
45817
45987
|
process.exit(1);
|
|
45818
45988
|
}
|
|
@@ -45828,7 +45998,7 @@ var stateMessages = {
|
|
|
45828
45998
|
};
|
|
45829
45999
|
var channel = new SecureChannel({
|
|
45830
46000
|
inviteToken: token,
|
|
45831
|
-
dataDir:
|
|
46001
|
+
dataDir: resolve2(dataDir),
|
|
45832
46002
|
apiUrl,
|
|
45833
46003
|
agentName: name,
|
|
45834
46004
|
webhookUrl,
|
|
@@ -45839,11 +46009,7 @@ var channel = new SecureChannel({
|
|
|
45839
46009
|
process.stdout.write("\n> ");
|
|
45840
46010
|
if (!noNotifications) {
|
|
45841
46011
|
const body = plaintext.length > 100 ? plaintext.slice(0, 100) + "..." : plaintext;
|
|
45842
|
-
|
|
45843
|
-
title: "AgentVault \u2014 New Message",
|
|
45844
|
-
message: body,
|
|
45845
|
-
sound: true
|
|
45846
|
-
});
|
|
46012
|
+
void tryNotify("AgentVault \u2014 New Message", body);
|
|
45847
46013
|
}
|
|
45848
46014
|
},
|
|
45849
46015
|
onStateChange: (state) => {
|