@nordbyte/nordrelay 0.2.1 → 0.3.1
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/.env.example +22 -0
- package/CHANGELOG.md +26 -0
- package/README.md +147 -19
- package/dist/access-control.js +6 -0
- package/dist/agent-adapter.js +60 -0
- package/dist/audit-log.js +54 -0
- package/dist/bot-preferences.js +13 -9
- package/dist/bot-ui.js +6 -0
- package/dist/bot.js +526 -26
- package/dist/channel-adapter.js +58 -0
- package/dist/codex-session.js +3 -1
- package/dist/config.js +47 -0
- package/dist/context-key.js +23 -0
- package/dist/index.js +47 -2
- package/dist/logger.js +24 -1
- package/dist/operations.js +340 -15
- package/dist/prompt-store.js +33 -11
- package/dist/relay-runtime.js +908 -0
- package/dist/session-locks.js +81 -0
- package/dist/session-registry.js +11 -7
- package/dist/settings-service.js +253 -0
- package/dist/state-backend.js +83 -0
- package/dist/web-dashboard.js +890 -0
- package/dist/web-state.js +131 -0
- package/docker-compose.yml +1 -1
- package/package.json +4 -1
- package/plugins/nordrelay/.codex-plugin/plugin.json +1 -1
- package/plugins/nordrelay/scripts/nordrelay.mjs +235 -13
package/.env.example
CHANGED
|
@@ -56,6 +56,12 @@ ENABLE_TELEGRAM_LOGIN=true
|
|
|
56
56
|
ENABLE_TELEGRAM_REACTIONS=false
|
|
57
57
|
TELEGRAM_RATE_LIMIT_MIN_INTERVAL_MS=80
|
|
58
58
|
TELEGRAM_EDIT_MIN_INTERVAL_MS=1200
|
|
59
|
+
TELEGRAM_TRANSPORT=polling
|
|
60
|
+
TELEGRAM_WEBHOOK_URL=
|
|
61
|
+
TELEGRAM_WEBHOOK_HOST=127.0.0.1
|
|
62
|
+
TELEGRAM_WEBHOOK_PORT=8080
|
|
63
|
+
TELEGRAM_WEBHOOK_PATH=/telegram/webhook
|
|
64
|
+
TELEGRAM_WEBHOOK_SECRET=
|
|
59
65
|
TELEGRAM_CLI_MIRROR_MODE=status
|
|
60
66
|
TELEGRAM_CLI_MIRROR_MIN_UPDATE_MS=4000
|
|
61
67
|
TELEGRAM_NOTIFY_MODE=minimal
|
|
@@ -69,6 +75,22 @@ ARTIFACT_IGNORE_DIRS=
|
|
|
69
75
|
ARTIFACT_IGNORE_GLOBS=
|
|
70
76
|
TELEGRAM_AUTO_SEND_ARTIFACTS=false
|
|
71
77
|
|
|
78
|
+
# State and team controls. Use sqlite for a single-file state database when
|
|
79
|
+
# better-sqlite3 is available; json keeps separate human-readable files.
|
|
80
|
+
NORDRELAY_STATE_BACKEND=json
|
|
81
|
+
NORDRELAY_AUDIT_MAX_EVENTS=1000
|
|
82
|
+
NORDRELAY_SESSION_LOCK_TTL_MS=1800000
|
|
83
|
+
NORDRELAY_VERSION_CACHE_TTL_MS=3600000
|
|
84
|
+
|
|
85
|
+
# Local WebUI dashboard. Binding to 0.0.0.0 requires either token auth or
|
|
86
|
+
# basic auth; startup fails without one of these credentials.
|
|
87
|
+
NORDRELAY_DASHBOARD_HOST=127.0.0.1
|
|
88
|
+
NORDRELAY_DASHBOARD_PORT=31878
|
|
89
|
+
NORDRELAY_DASHBOARD_TOKEN=
|
|
90
|
+
NORDRELAY_DASHBOARD_USER=
|
|
91
|
+
NORDRELAY_DASHBOARD_PASSWORD=
|
|
92
|
+
NORDRELAY_ENV_FILE=
|
|
93
|
+
|
|
72
94
|
# Optional workspace guardrails. Leave WORKSPACE_ALLOWED_ROOTS empty to allow
|
|
73
95
|
# all workspaces discovered from enabled agent state.
|
|
74
96
|
WORKSPACE_ALLOWED_ROOTS=
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.3.1 - 2026-05-12
|
|
4
|
+
|
|
5
|
+
Commits since `v0.3.0`:
|
|
6
|
+
|
|
7
|
+
- Move runtime home to .nordrelay.
|
|
8
|
+
- Improve dashboard live status handling.
|
|
9
|
+
- Separate dashboard contexts from Telegram sessions.
|
|
10
|
+
- Expand dashboard controls and activity views.
|
|
11
|
+
|
|
12
|
+
## v0.3.0 - 2026-05-12
|
|
13
|
+
|
|
14
|
+
Commits since `v0.2.1`:
|
|
15
|
+
|
|
16
|
+
- Prepare v0.3.0 release with copyable WebUI thread IDs and aligned session controls.
|
|
17
|
+
- Improve dashboard usability and uploads.
|
|
18
|
+
- Expand WebUI dashboard.
|
|
19
|
+
- Keep dashboard server running.
|
|
20
|
+
- Expand NordRelay platform features.
|
|
21
|
+
- Hide missing timestamp marker in logs.
|
|
22
|
+
- Show CLI paths directly in version output.
|
|
23
|
+
- Add version freshness checks.
|
|
24
|
+
- Render log messages as normal text.
|
|
25
|
+
- Improve version and log display.
|
|
26
|
+
- Improve logs and self-update behavior.
|
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ Session control:
|
|
|
24
24
|
- `/handback` returns a ready-to-run CLI command for continuing in the native agent CLI.
|
|
25
25
|
- `/retry` resends the last prompt for the current Telegram context.
|
|
26
26
|
- `/queue`, inline run/top/up/down/cancel buttons, `/cancel <queue-id>`, and `/clearqueue` manage queued prompts for a busy Telegram context.
|
|
27
|
+
- `/queue later <minutes> <prompt>` schedules a prompt for later execution, and `/queue inspect <queue-id>` shows full queue metadata.
|
|
27
28
|
- `/abort`, `/stop`, and the inline Abort button cancel the active agent turn.
|
|
28
29
|
- Busy prompts are queued per Telegram context instead of being dropped.
|
|
29
30
|
- If the attached thread is currently active in the local Codex CLI, Telegram prompts are queued until that CLI task finishes.
|
|
@@ -36,6 +37,15 @@ Session control:
|
|
|
36
37
|
- `/tasks` and `/progress` show the current turn status, queue length, active tool, elapsed time, and last error.
|
|
37
38
|
- `/activity` shows a compact timeline of recent rollout events for the active thread, with filters and export.
|
|
38
39
|
- `/diagnostics` reports redacted runtime, config, role, Telegram rate-limit, mirror, voice, session, queue, and progress details for admins.
|
|
40
|
+
- `/lock`, `/unlock`, and `/locks` provide a team write-lock for shared sessions so one user can operate while others watch.
|
|
41
|
+
- `/audit` shows recent prompt, queue, lock, and command audit events for admins.
|
|
42
|
+
|
|
43
|
+
Adapter architecture:
|
|
44
|
+
|
|
45
|
+
- Telegram is implemented as the first channel adapter with text, typing, streaming edits, inline buttons, files, photos, voice, topics, and webhook capability metadata.
|
|
46
|
+
- `/channels` shows available and planned messaging adapters for Discord, WhatsApp, Slack, and Matrix.
|
|
47
|
+
- Codex and Pi are implemented as agent adapters, with descriptors for future Claude Code, OpenClaw, and Hermes support.
|
|
48
|
+
- `/agents` shows available/planned agent adapters and whether Codex/Pi are enabled.
|
|
39
49
|
|
|
40
50
|
Codex runtime:
|
|
41
51
|
|
|
@@ -95,6 +105,7 @@ Telegram output:
|
|
|
95
105
|
- Image artifacts are sent with Telegram previews; large multi-file outputs are bundled into one ZIP when possible.
|
|
96
106
|
- `/artifacts` lists recent generated files and can resend the latest or a specific artifact turn.
|
|
97
107
|
- `/artifacts` includes inline actions to resend, ZIP, or delete artifact turns.
|
|
108
|
+
- `/artifacts images`, `/artifacts docs`, `/artifacts search <text>`, and `/artifacts delete <turn-id>` filter, find, and clean up artifacts from Telegram.
|
|
98
109
|
- Old artifact and inbox turn directories are pruned automatically with configurable retention.
|
|
99
110
|
- Optional Telegram message reactions can acknowledge work start and completion with `ENABLE_TELEGRAM_REACTIONS=true`.
|
|
100
111
|
|
|
@@ -120,24 +131,43 @@ Operations:
|
|
|
120
131
|
- Plugin command/skill starts, stops, restarts, and inspects the connector process.
|
|
121
132
|
- Manual process commands support `start`, `stop`, `restart`, `status`, and `foreground`.
|
|
122
133
|
- Telegram admin commands support `/logs`, `/diagnostics`, `/restart`, and `/update`.
|
|
123
|
-
- `/update`
|
|
124
|
-
-
|
|
134
|
+
- `/update` detects the install type: npm installs update with `npm install -g @nordbyte/nordrelay@latest`; source checkouts pull `origin/main`, install dependencies, run check, tests, and build, then restart.
|
|
135
|
+
- `/logs` renders redacted connector and update logs with local-time timestamps, levels, file path, last-modified time, and highlighted warnings/errors.
|
|
136
|
+
- Logs can be emitted as timestamped plain text or JSON records with `CONNECTOR_LOG_FORMAT`.
|
|
125
137
|
- Telegram sends/edits/documents are routed through a rate-limit queue that honors Telegram retry-after responses.
|
|
126
138
|
- Context metadata, queues, and preferences are written atomically with backup recovery.
|
|
127
|
-
-
|
|
139
|
+
- Context metadata, queues, preferences, audit events, and locks can use JSON files or the optional SQLite state backend with `NORDRELAY_STATE_BACKEND=sqlite`.
|
|
140
|
+
- Runtime config, state, and logs are written under `~/.nordrelay/`.
|
|
141
|
+
- `nordrelay init` creates a private runtime config, `nordrelay doctor` validates host prerequisites, and `nordrelay web` starts a full local WebUI dashboard.
|
|
142
|
+
- The WebUI has responsive header/sidebar/footer navigation, live chat streaming, session controls, queue/artifact/log/diagnostic views, and settings management.
|
|
143
|
+
- The WebUI supports light and dark themes, tabbed settings groups, paginated session browsing, and chat uploads for images, documents, and audio transcription.
|
|
144
|
+
- The WebUI exposes REST and SSE endpoints for chat streaming, sessions, settings, queue, artifacts, logs, health, and diagnostics.
|
|
145
|
+
- Binding the dashboard to `0.0.0.0` is refused unless `NORDRELAY_DASHBOARD_TOKEN` or `NORDRELAY_DASHBOARD_USER` plus `NORDRELAY_DASHBOARD_PASSWORD` is configured.
|
|
146
|
+
- Telegram can run with long polling or an HTTP webhook via `TELEGRAM_TRANSPORT=webhook`.
|
|
147
|
+
- Version freshness checks are cached with `NORDRELAY_VERSION_CACHE_TTL_MS` to keep `/version` responsive.
|
|
148
|
+
- CI includes typecheck, tests, package dry run, npm audit, and a separate secret-scan workflow.
|
|
128
149
|
- `npm run dev`, `npm run build`, `npm run check`, `npm test`, `npm start`, `npm stop`, and `npm run status` are available.
|
|
129
150
|
- Dockerfile and `docker-compose.yml` are included for containerized operation.
|
|
130
151
|
- A `launchd/start.sh` helper is included for host-managed startup.
|
|
131
152
|
|
|
132
153
|
## First Run Setup
|
|
133
154
|
|
|
134
|
-
|
|
155
|
+
Recommended npm setup:
|
|
135
156
|
|
|
136
157
|
```bash
|
|
137
158
|
npm install -g @nordbyte/nordrelay
|
|
159
|
+
nordrelay init
|
|
160
|
+
nordrelay doctor
|
|
161
|
+
nordrelay start
|
|
138
162
|
```
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
npm is the fastest install path and is the recommended default for normal use. `nordrelay init` writes the private runtime config to `~/.nordrelay/nordrelay.env`.
|
|
165
|
+
|
|
166
|
+
Non-interactive setup is also supported:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
nordrelay init --token 123456789:replace-me --admin-id 123456789
|
|
170
|
+
```
|
|
141
171
|
|
|
142
172
|
Source checkout setup:
|
|
143
173
|
|
|
@@ -146,7 +176,9 @@ Install dependencies and build the runtime:
|
|
|
146
176
|
```bash
|
|
147
177
|
npm install
|
|
148
178
|
npm run build
|
|
149
|
-
|
|
179
|
+
mkdir -p ~/.nordrelay
|
|
180
|
+
cp .env.example ~/.nordrelay/nordrelay.env
|
|
181
|
+
chmod 600 ~/.nordrelay/nordrelay.env
|
|
150
182
|
```
|
|
151
183
|
|
|
152
184
|
Create the Telegram bot:
|
|
@@ -154,11 +186,11 @@ Create the Telegram bot:
|
|
|
154
186
|
1. Open Telegram and talk to `@BotFather`.
|
|
155
187
|
2. Run `/newbot`.
|
|
156
188
|
3. Choose a display name and bot username.
|
|
157
|
-
4. Copy the bot token into `TELEGRAM_BOT_TOKEN` in
|
|
189
|
+
4. Copy the bot token into `TELEGRAM_BOT_TOKEN` in `~/.nordrelay/nordrelay.env`.
|
|
158
190
|
5. Find your Telegram user id with a trusted id helper bot, for example `@userinfobot`, or from Telegram API tooling.
|
|
159
191
|
6. Put your user id into `TELEGRAM_ADMIN_USER_IDS`.
|
|
160
192
|
|
|
161
|
-
Minimal private-bot
|
|
193
|
+
Minimal private-bot `~/.nordrelay/nordrelay.env`:
|
|
162
194
|
|
|
163
195
|
```dotenv
|
|
164
196
|
TELEGRAM_BOT_TOKEN=123456789:replace-me
|
|
@@ -187,7 +219,7 @@ Codex authentication:
|
|
|
187
219
|
Pi setup:
|
|
188
220
|
|
|
189
221
|
- Install Pi from https://pi.dev/ and confirm `pi --help` works on the host.
|
|
190
|
-
- Set `NORDRELAY_PI_ENABLED=true` in
|
|
222
|
+
- Set `NORDRELAY_PI_ENABLED=true` in `~/.nordrelay/nordrelay.env`.
|
|
191
223
|
- Keep `NORDRELAY_DEFAULT_AGENT=codex` to start chats in Codex, or set `NORDRELAY_DEFAULT_AGENT=pi` to start chats in Pi.
|
|
192
224
|
- Optional: set `PI_SESSION_DIR` if your Pi sessions are not stored in `~/.pi/agent/sessions/`.
|
|
193
225
|
- Optional: set `PI_DEFAULT_MODEL=openai-codex/gpt-5.5` and `PI_DEFAULT_THINKING=medium`.
|
|
@@ -219,11 +251,14 @@ The old unnamespaced `/remote` command is no longer required and current Codex T
|
|
|
219
251
|
Manual process commands:
|
|
220
252
|
|
|
221
253
|
```bash
|
|
254
|
+
nordrelay init
|
|
255
|
+
nordrelay doctor
|
|
222
256
|
nordrelay start
|
|
223
257
|
nordrelay status
|
|
224
258
|
nordrelay restart
|
|
225
259
|
nordrelay stop
|
|
226
260
|
nordrelay foreground
|
|
261
|
+
nordrelay web
|
|
227
262
|
```
|
|
228
263
|
|
|
229
264
|
Source checkout process commands:
|
|
@@ -234,6 +269,8 @@ node plugins/nordrelay/scripts/nordrelay.mjs status
|
|
|
234
269
|
node plugins/nordrelay/scripts/nordrelay.mjs restart
|
|
235
270
|
node plugins/nordrelay/scripts/nordrelay.mjs stop
|
|
236
271
|
node plugins/nordrelay/scripts/nordrelay.mjs foreground
|
|
272
|
+
node plugins/nordrelay/scripts/nordrelay.mjs doctor
|
|
273
|
+
node plugins/nordrelay/scripts/nordrelay.mjs web
|
|
237
274
|
```
|
|
238
275
|
|
|
239
276
|
NPM shortcuts:
|
|
@@ -247,15 +284,76 @@ npm run foreground
|
|
|
247
284
|
|
|
248
285
|
Runtime files:
|
|
249
286
|
|
|
250
|
-
- PID file: `~/.
|
|
251
|
-
- State file: `~/.
|
|
252
|
-
- Log file: `~/.
|
|
287
|
+
- PID file: `~/.nordrelay/nordrelay.pid`
|
|
288
|
+
- State file: `~/.nordrelay/state.json`
|
|
289
|
+
- Log file: `~/.nordrelay/nordrelay.log`
|
|
253
290
|
- Home override: `NORDRELAY_HOME=/custom/path`
|
|
291
|
+
- Local dashboard: `nordrelay web --host 127.0.0.1 --port 31878`
|
|
292
|
+
|
|
293
|
+
## WebUI Dashboard
|
|
294
|
+
|
|
295
|
+
Start the local WebUI:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
nordrelay web
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Open:
|
|
302
|
+
|
|
303
|
+
```text
|
|
304
|
+
http://127.0.0.1:31878/
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The dashboard is a second NordRelay client next to Telegram. It can:
|
|
308
|
+
|
|
309
|
+
- Start a new Codex or Pi session.
|
|
310
|
+
- Start a new session from a modal with agent, workspace, model, reasoning/thinking, fast mode, and launch-profile choices.
|
|
311
|
+
- Switch or attach existing sessions, and copy thread IDs from the session list.
|
|
312
|
+
- Send prompts and receive streamed text/tool/plan updates through Server-Sent Events.
|
|
313
|
+
- Upload images, documents, and audio files from the chat composer. Images are passed as image inputs, documents are staged for the agent, and audio is transcribed through the configured voice backend.
|
|
314
|
+
- Keep a persistent per-thread WebUI chat history across page reloads.
|
|
315
|
+
- Control the active session model, reasoning/thinking, fast mode, and launch profile directly from the chat view.
|
|
316
|
+
- Abort turns, hand sessions back to the native CLI, and inspect the active session.
|
|
317
|
+
- Manage queued prompts with pause/resume, run, cancel, reorder buttons, and drag-and-drop prioritization.
|
|
318
|
+
- Browse, preview, download, ZIP, and delete artifacts.
|
|
319
|
+
- Inspect the activity timeline for WebUI and mirrored CLI turns.
|
|
320
|
+
- Edit all supported runtime settings from tabbed Settings groups with option selects, validation feedback, and restart actions.
|
|
321
|
+
- View filtered logs, structured diagnostics, enabled channels, and agent adapters.
|
|
322
|
+
|
|
323
|
+
Dashboard API endpoints are served under `/api/*`. Streaming uses `GET /api/events`.
|
|
324
|
+
|
|
325
|
+
Dashboard auth:
|
|
326
|
+
|
|
327
|
+
```dotenv
|
|
328
|
+
NORDRELAY_DASHBOARD_HOST=127.0.0.1
|
|
329
|
+
NORDRELAY_DASHBOARD_PORT=31878
|
|
330
|
+
NORDRELAY_DASHBOARD_TOKEN=replace-with-random-token
|
|
331
|
+
# or:
|
|
332
|
+
NORDRELAY_DASHBOARD_USER=admin
|
|
333
|
+
NORDRELAY_DASHBOARD_PASSWORD=replace-with-random-password
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
When `NORDRELAY_DASHBOARD_HOST=0.0.0.0`, NordRelay refuses to start the dashboard unless token or basic auth is configured. Login cookies use `SameSite=Strict`, and every dashboard route, API endpoint, SSE stream, artifact download, and health endpoint requires the same auth.
|
|
337
|
+
|
|
338
|
+
Webhook mode:
|
|
339
|
+
|
|
340
|
+
```dotenv
|
|
341
|
+
TELEGRAM_TRANSPORT=webhook
|
|
342
|
+
TELEGRAM_WEBHOOK_URL=https://relay.example
|
|
343
|
+
TELEGRAM_WEBHOOK_HOST=127.0.0.1
|
|
344
|
+
TELEGRAM_WEBHOOK_PORT=8080
|
|
345
|
+
TELEGRAM_WEBHOOK_PATH=/telegram/webhook
|
|
346
|
+
TELEGRAM_WEBHOOK_SECRET=replace-with-random-secret
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Run NordRelay behind your reverse proxy so the public URL forwards to `http://127.0.0.1:8080/telegram/webhook`. `GET /healthz` returns a simple health check.
|
|
254
350
|
|
|
255
351
|
## Telegram Commands
|
|
256
352
|
|
|
257
353
|
- `/start` shows welcome text and the selected launch profile.
|
|
258
354
|
- `/help` shows the grouped command reference.
|
|
355
|
+
- `/channels` shows available and planned messaging adapters.
|
|
356
|
+
- `/agents` shows available and planned coding-agent adapters.
|
|
259
357
|
- `/agent` selects the active agent for this Telegram context.
|
|
260
358
|
- `/new` starts a new thread. If the selected agent knows multiple workspaces, Telegram shows a workspace picker.
|
|
261
359
|
- `/session` shows current thread details.
|
|
@@ -272,13 +370,19 @@ Runtime files:
|
|
|
272
370
|
- `/queue` shows queued prompts for this Telegram context with inline run/top/up/down/cancel buttons.
|
|
273
371
|
- `/queue pause` pauses automatic queued prompt execution.
|
|
274
372
|
- `/queue resume` resumes automatic queued prompt execution.
|
|
373
|
+
- `/queue later <minutes> <prompt>` schedules a prompt for later execution.
|
|
374
|
+
- `/queue inspect <queue-id>` shows one queued prompt with created time, schedule time, attempts, and last error.
|
|
275
375
|
- `/queue move <queue-id> top|up|down` changes queued prompt priority.
|
|
276
376
|
- `/queue run <queue-id>` resumes the queue and runs that prompt next when the session is idle.
|
|
277
377
|
- Queued prompt replies include a cancel button while the prompt is still waiting.
|
|
278
378
|
- `/cancel <queue-id>` removes one queued prompt; the queue id is the short code shown in messages such as `Queued prompt 332kmt`.
|
|
279
379
|
- `/clearqueue` clears queued prompts for this Telegram context.
|
|
280
380
|
- `/activity [all|tools|errors|user|agent|tasks] [limit] [since 1h] [export]` shows or exports rollout activity for the active thread.
|
|
281
|
-
- `/
|
|
381
|
+
- `/audit [limit]` shows recent audit events. Admin only.
|
|
382
|
+
- `/lock` locks writes for this Telegram session to the current user.
|
|
383
|
+
- `/unlock` releases the current session write lock.
|
|
384
|
+
- `/locks` lists active write locks.
|
|
385
|
+
- `/artifacts [latest|zip latest|turn-id|images|docs|search <text>|delete <turn-id>]` lists, filters, resends, zips, searches, or deletes generated artifacts for the current workspace.
|
|
282
386
|
- `/workspaces` lists workspaces known to the selected agent and allowed by the workspace policy.
|
|
283
387
|
- `/abort` cancels the current operation.
|
|
284
388
|
- `/stop` is an alias for `/abort`.
|
|
@@ -300,11 +404,13 @@ Runtime files:
|
|
|
300
404
|
- `/tasks` or `/progress` reports the current turn and queue progress.
|
|
301
405
|
- `/status` reports connector runtime status.
|
|
302
406
|
- `/health` reports runtime health, auth, PIDs, Codex CLI, Pi CLI, and state DB.
|
|
303
|
-
- `/version` reports connector, Codex CLI, and Pi CLI
|
|
304
|
-
- `/logs [lines]` shows a redacted connector log tail. Admin only.
|
|
407
|
+
- `/version` reports connector, Codex CLI, and Pi CLI paths plus installed/latest NordRelay, Codex, and Pi versions with status icons.
|
|
408
|
+
- `/logs [lines]` shows a redacted, timestamped connector log tail. Admin only.
|
|
409
|
+
- `/logs update [lines]` shows the self-update log. Admin only.
|
|
410
|
+
- `/logs all [lines]` shows connector and self-update logs together. Admin only.
|
|
305
411
|
- `/diagnostics` shows redacted connector diagnostics. Admin only.
|
|
306
412
|
- `/restart` restarts the connector process. Admin only.
|
|
307
|
-
- `/update`
|
|
413
|
+
- `/update` updates through npm or git depending on the detected install type, then restarts only on success. Admin only.
|
|
308
414
|
|
|
309
415
|
## Command Examples
|
|
310
416
|
|
|
@@ -422,6 +528,8 @@ Artifacts:
|
|
|
422
528
|
- When more than five artifacts are sent, the connector tries to send one ZIP bundle instead of many separate files.
|
|
423
529
|
- Use `/artifacts` to list recent artifact turns with inline Send/ZIP/Delete actions.
|
|
424
530
|
- Use `/artifacts latest`, `/artifacts zip latest`, or `/artifacts <turn-id>` from text commands.
|
|
531
|
+
- Use `/artifacts images`, `/artifacts docs`, or `/artifacts search <text>` to narrow large artifact histories.
|
|
532
|
+
- Use `/artifacts delete <turn-id>` to delete an artifact turn without opening the inline confirmation flow.
|
|
425
533
|
- Telegram file delivery is capped at the configured `MAX_FILE_SIZE` per artifact or ZIP bundle.
|
|
426
534
|
- Old turn and inbox directories are pruned automatically to keep workspace state compact.
|
|
427
535
|
|
|
@@ -475,6 +583,12 @@ Telegram:
|
|
|
475
583
|
- `TELEGRAM_ROLE_POLICIES_JSON`: optional JSON object mapping roles to permissions. Permissions are `inspect`, `sessions`, `prompt`, `files`, `settings`, `auth`, and `admin`.
|
|
476
584
|
- `TELEGRAM_RATE_LIMIT_MIN_INTERVAL_MS`: minimum interval for normal Telegram API sends. Defaults to `80`.
|
|
477
585
|
- `TELEGRAM_EDIT_MIN_INTERVAL_MS`: minimum interval for Telegram message edits. Defaults to `1200`.
|
|
586
|
+
- `TELEGRAM_TRANSPORT`: `polling` or `webhook`. Defaults to `polling`.
|
|
587
|
+
- `TELEGRAM_WEBHOOK_URL`: public base URL for webhook mode, for example `https://relay.example`.
|
|
588
|
+
- `TELEGRAM_WEBHOOK_HOST`: local bind host for webhook mode. Defaults to `127.0.0.1`.
|
|
589
|
+
- `TELEGRAM_WEBHOOK_PORT`: local bind port for webhook mode. Defaults to `8080`.
|
|
590
|
+
- `TELEGRAM_WEBHOOK_PATH`: webhook request path. Defaults to `/telegram/webhook`.
|
|
591
|
+
- `TELEGRAM_WEBHOOK_SECRET`: optional Telegram webhook secret token.
|
|
478
592
|
- `TELEGRAM_CLI_MIRROR_MODE`: default CLI mirror mode: `off`, `status`, `final`, or `full`. Defaults to `status`.
|
|
479
593
|
- `TELEGRAM_CLI_MIRROR_MIN_UPDATE_MS`: minimum interval for mirrored CLI status edits. Defaults to `4000`.
|
|
480
594
|
- `TELEGRAM_NOTIFY_MODE`: default notification mode: `off`, `minimal`, or `all`. Defaults to `minimal`.
|
|
@@ -492,6 +606,19 @@ Agent selection:
|
|
|
492
606
|
- `NORDRELAY_CODEX_ENABLED`: enables Codex contexts. Defaults to `true`.
|
|
493
607
|
- `NORDRELAY_PI_ENABLED`: enables Pi contexts. Defaults to `false`.
|
|
494
608
|
- `NORDRELAY_DEFAULT_AGENT`: `codex` or `pi`, used for new Telegram contexts. Defaults to the first enabled agent.
|
|
609
|
+
- `NORDRELAY_STATE_BACKEND`: `json` or `sqlite`. JSON is the default; SQLite requires `better-sqlite3`.
|
|
610
|
+
- `NORDRELAY_AUDIT_MAX_EVENTS`: maximum audit events retained. Defaults to `1000`.
|
|
611
|
+
- `NORDRELAY_SESSION_LOCK_TTL_MS`: session write-lock TTL. Defaults to `1800000`.
|
|
612
|
+
- `NORDRELAY_VERSION_CACHE_TTL_MS`: npm version freshness cache TTL. Defaults to `3600000`; set `0` to disable.
|
|
613
|
+
|
|
614
|
+
Dashboard:
|
|
615
|
+
|
|
616
|
+
- `NORDRELAY_DASHBOARD_HOST`: dashboard bind host. Defaults to `127.0.0.1`.
|
|
617
|
+
- `NORDRELAY_DASHBOARD_PORT`: dashboard bind port. Defaults to `31878`.
|
|
618
|
+
- `NORDRELAY_DASHBOARD_TOKEN`: optional dashboard bearer/login token. Required when binding to `0.0.0.0` unless basic auth is configured.
|
|
619
|
+
- `NORDRELAY_DASHBOARD_USER`: optional dashboard basic-auth user.
|
|
620
|
+
- `NORDRELAY_DASHBOARD_PASSWORD`: optional dashboard basic-auth password. Required with `NORDRELAY_DASHBOARD_USER`.
|
|
621
|
+
- `NORDRELAY_ENV_FILE`: optional explicit env-file path used by the wrapper and edited by the dashboard settings page. Defaults to `~/.nordrelay/nordrelay.env`.
|
|
495
622
|
|
|
496
623
|
Codex:
|
|
497
624
|
|
|
@@ -550,8 +677,9 @@ Auth and voice:
|
|
|
550
677
|
|
|
551
678
|
NordRelay wrapper:
|
|
552
679
|
|
|
553
|
-
- `NORDRELAY_HOME`: state/log directory override. Defaults to `~/.
|
|
680
|
+
- `NORDRELAY_HOME`: config/state/log directory override. Defaults to `~/.nordrelay`.
|
|
554
681
|
- `NORDRELAY_SOURCE_ROOT`: runtime source root override. Useful when the plugin is launched from Codex cache.
|
|
682
|
+
- `NORDRELAY_UPDATE_METHOD`: optional `auto`, `npm`, or `git` self-update method override. Auto uses git when the runtime root has a `.git` directory and npm otherwise.
|
|
555
683
|
- `NORDRELAY_KEEP_PENDING_UPDATES`: set true to avoid dropping pending Telegram updates on start.
|
|
556
684
|
- `NORDRELAY_FORWARD_TOOL_OUTPUT`: backward-compatible alias that sets `TOOL_VERBOSITY=all` when `TOOL_VERBOSITY` is unset.
|
|
557
685
|
- `NORDRELAY_STATE_FILE`: internal state-file path passed by the wrapper.
|
|
@@ -597,7 +725,7 @@ Unsafe profiles are intentionally gated. Telegram asks for confirmation before a
|
|
|
597
725
|
- Do not leave `TELEGRAM_ALLOW_ANY_CHAT=true` enabled after setup.
|
|
598
726
|
- Treat `danger-full-access` as equivalent to shell access on the host.
|
|
599
727
|
- Treat uploaded files as untrusted input. They are staged inside the active workspace so the selected sandbox policy still matters.
|
|
600
|
-
- Keep `CODEX_API_KEY` and `OPENAI_API_KEY` in
|
|
728
|
+
- Keep `CODEX_API_KEY` and `OPENAI_API_KEY` in `~/.nordrelay/nordrelay.env` or host secret management.
|
|
601
729
|
- In group chats, remember that any allowed user can prompt Codex in that chat context.
|
|
602
730
|
- Use `TOOL_VERBOSITY=summary` or `errors-only` when command output may include sensitive data.
|
|
603
731
|
- Review and unsafe launch profiles add a Telegram approve/deny gate before each turn starts.
|
|
@@ -655,7 +783,7 @@ Voice not working:
|
|
|
655
783
|
|
|
656
784
|
- Run `/voice` to list available backends.
|
|
657
785
|
- Install `ffmpeg` and `faster-whisper` on Linux, install `parakeet-coreml` on macOS Apple Silicon, or set `OPENAI_API_KEY`.
|
|
658
|
-
- Check `~/.
|
|
786
|
+
- Check `~/.nordrelay/nordrelay.log` for transcription errors.
|
|
659
787
|
|
|
660
788
|
Files not returned:
|
|
661
789
|
|
package/dist/access-control.js
CHANGED
|
@@ -13,10 +13,13 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
13
13
|
["status", "inspect"],
|
|
14
14
|
["health", "inspect"],
|
|
15
15
|
["version", "inspect"],
|
|
16
|
+
["channels", "inspect"],
|
|
17
|
+
["agents", "inspect"],
|
|
16
18
|
["diagnostics", "admin"],
|
|
17
19
|
["tasks", "inspect"],
|
|
18
20
|
["progress", "inspect"],
|
|
19
21
|
["activity", "inspect"],
|
|
22
|
+
["audit", "admin"],
|
|
20
23
|
["mirror", "settings"],
|
|
21
24
|
["notify", "settings"],
|
|
22
25
|
["workspaces", "sessions"],
|
|
@@ -32,6 +35,9 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
32
35
|
["handback", "sessions"],
|
|
33
36
|
["new", "sessions"],
|
|
34
37
|
["sync", "sessions"],
|
|
38
|
+
["lock", "sessions"],
|
|
39
|
+
["unlock", "sessions"],
|
|
40
|
+
["locks", "sessions"],
|
|
35
41
|
["queue", "inspect"],
|
|
36
42
|
["cancel", "prompt"],
|
|
37
43
|
["clearqueue", "prompt"],
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { CODEX_AGENT_CAPABILITIES, PI_AGENT_CAPABILITIES, } from "./agent.js";
|
|
2
|
+
export const BUILTIN_AGENT_ADAPTERS = [
|
|
3
|
+
{
|
|
4
|
+
id: "codex",
|
|
5
|
+
label: "Codex",
|
|
6
|
+
status: "available",
|
|
7
|
+
capabilities: CODEX_AGENT_CAPABILITIES,
|
|
8
|
+
envFlag: "NORDRELAY_CODEX_ENABLED",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "pi",
|
|
12
|
+
label: "Pi",
|
|
13
|
+
status: "available",
|
|
14
|
+
capabilities: PI_AGENT_CAPABILITIES,
|
|
15
|
+
envFlag: "NORDRELAY_PI_ENABLED",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "claude-code",
|
|
19
|
+
label: "Claude Code",
|
|
20
|
+
status: "planned",
|
|
21
|
+
capabilities: plannedCapabilities(),
|
|
22
|
+
notes: "Use this descriptor as the target contract for a future Claude Code session service.",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "openclaw",
|
|
26
|
+
label: "OpenClaw",
|
|
27
|
+
status: "planned",
|
|
28
|
+
capabilities: plannedCapabilities(),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "hermes",
|
|
32
|
+
label: "Hermes",
|
|
33
|
+
status: "planned",
|
|
34
|
+
capabilities: plannedCapabilities(),
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
export function listAgentAdapterDescriptors() {
|
|
38
|
+
return BUILTIN_AGENT_ADAPTERS.map((descriptor) => ({
|
|
39
|
+
...descriptor,
|
|
40
|
+
capabilities: { ...descriptor.capabilities },
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
function plannedCapabilities() {
|
|
44
|
+
return {
|
|
45
|
+
launchProfiles: false,
|
|
46
|
+
fastMode: false,
|
|
47
|
+
externalActivity: false,
|
|
48
|
+
cliMirror: false,
|
|
49
|
+
activityLog: false,
|
|
50
|
+
auth: false,
|
|
51
|
+
login: false,
|
|
52
|
+
logout: false,
|
|
53
|
+
usageLimits: false,
|
|
54
|
+
workspaces: true,
|
|
55
|
+
attachments: true,
|
|
56
|
+
modelSelection: true,
|
|
57
|
+
reasoningSelection: true,
|
|
58
|
+
handback: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createDocumentStore } from "./state-backend.js";
|
|
3
|
+
export class AuditLogStore {
|
|
4
|
+
store;
|
|
5
|
+
maxEvents;
|
|
6
|
+
constructor(workspace, backend = "json", maxEvents = 1000) {
|
|
7
|
+
this.store = createDocumentStore({
|
|
8
|
+
workspace,
|
|
9
|
+
fileName: "audit.json",
|
|
10
|
+
sqliteKey: "audit",
|
|
11
|
+
backend,
|
|
12
|
+
});
|
|
13
|
+
this.maxEvents = maxEvents;
|
|
14
|
+
}
|
|
15
|
+
append(event) {
|
|
16
|
+
const payload = this.readPayload();
|
|
17
|
+
const next = {
|
|
18
|
+
id: randomUUID().replace(/-/g, "").slice(0, 12),
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
channelId: "telegram",
|
|
21
|
+
...event,
|
|
22
|
+
};
|
|
23
|
+
payload.events.push(next);
|
|
24
|
+
if (payload.events.length > this.maxEvents) {
|
|
25
|
+
payload.events.splice(0, payload.events.length - this.maxEvents);
|
|
26
|
+
}
|
|
27
|
+
this.store.write(payload);
|
|
28
|
+
return next;
|
|
29
|
+
}
|
|
30
|
+
list(limit = 20) {
|
|
31
|
+
return this.readPayload().events.slice(-Math.max(1, Math.min(200, limit))).reverse();
|
|
32
|
+
}
|
|
33
|
+
readPayload() {
|
|
34
|
+
const payload = this.store.read();
|
|
35
|
+
if (!payload || payload.version !== 1 || !Array.isArray(payload.events)) {
|
|
36
|
+
return { version: 1, events: [] };
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
version: 1,
|
|
40
|
+
events: payload.events.filter(isAuditEvent),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function isAuditEvent(value) {
|
|
45
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const candidate = value;
|
|
49
|
+
return typeof candidate.id === "string" &&
|
|
50
|
+
typeof candidate.timestamp === "string" &&
|
|
51
|
+
typeof candidate.action === "string" &&
|
|
52
|
+
typeof candidate.status === "string" &&
|
|
53
|
+
typeof candidate.contextKey === "string";
|
|
54
|
+
}
|
package/dist/bot-preferences.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { readJsonFileWithBackup, writeJsonFileAtomic } from "./persistence.js";
|
|
1
|
+
import { createDocumentStore } from "./state-backend.js";
|
|
3
2
|
export class BotPreferencesStore {
|
|
4
|
-
|
|
3
|
+
store;
|
|
5
4
|
contexts = new Map();
|
|
6
|
-
constructor(workspace) {
|
|
7
|
-
this.
|
|
5
|
+
constructor(workspace, backend = "json") {
|
|
6
|
+
this.store = createDocumentStore({
|
|
7
|
+
workspace,
|
|
8
|
+
fileName: "preferences.json",
|
|
9
|
+
sqliteKey: "preferences",
|
|
10
|
+
backend,
|
|
11
|
+
});
|
|
8
12
|
this.load();
|
|
9
13
|
}
|
|
10
14
|
get(contextKey) {
|
|
@@ -29,14 +33,14 @@ export class BotPreferencesStore {
|
|
|
29
33
|
version: 1,
|
|
30
34
|
contexts: Object.fromEntries(this.contexts.entries()),
|
|
31
35
|
};
|
|
32
|
-
|
|
36
|
+
this.store.write(payload);
|
|
33
37
|
}
|
|
34
38
|
load() {
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
39
|
+
const payload = this.store.read();
|
|
40
|
+
if (!payload?.contexts || typeof payload.contexts !== "object") {
|
|
37
41
|
return;
|
|
38
42
|
}
|
|
39
|
-
for (const [contextKey, rawPreferences] of Object.entries(
|
|
43
|
+
for (const [contextKey, rawPreferences] of Object.entries(payload.contexts)) {
|
|
40
44
|
const preferences = normalizePreferences(rawPreferences);
|
|
41
45
|
if (preferences) {
|
|
42
46
|
this.contexts.set(contextKey, preferences);
|
package/dist/bot-ui.js
CHANGED
|
@@ -51,12 +51,15 @@ export function renderHelpMessage() {
|
|
|
51
51
|
commands: [
|
|
52
52
|
["/start", "Welcome & status"],
|
|
53
53
|
["/help", "This reference"],
|
|
54
|
+
["/channels", "Messaging adapter status"],
|
|
55
|
+
["/agents", "Agent adapter status"],
|
|
54
56
|
["/voice", "Voice transcription status"],
|
|
55
57
|
["/status", "Connector runtime status"],
|
|
56
58
|
["/health", "Connector health report"],
|
|
57
59
|
["/version", "Connector version"],
|
|
58
60
|
["/tasks", "Current turn progress"],
|
|
59
61
|
["/activity", "Thread activity timeline"],
|
|
62
|
+
["/audit", "Recent audit events"],
|
|
60
63
|
],
|
|
61
64
|
},
|
|
62
65
|
{
|
|
@@ -64,6 +67,9 @@ export function renderHelpMessage() {
|
|
|
64
67
|
commands: [
|
|
65
68
|
["/logs", "Show connector log tail"],
|
|
66
69
|
["/diagnostics", "Connector diagnostics"],
|
|
70
|
+
["/lock", "Lock session writes to you"],
|
|
71
|
+
["/unlock", "Release session write lock"],
|
|
72
|
+
["/locks", "List active write locks"],
|
|
67
73
|
["/restart", "Restart connector"],
|
|
68
74
|
["/update", "Pull, build, and restart"],
|
|
69
75
|
],
|