@nordbyte/nordrelay 0.3.0 → 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/CHANGELOG.md +9 -0
- package/README.md +24 -18
- package/dist/bot.js +5 -2
- package/dist/codex-session.js +3 -1
- package/dist/context-key.js +23 -0
- package/dist/operations.js +1 -1
- package/dist/relay-runtime.js +436 -7
- package/dist/session-registry.js +3 -3
- package/dist/settings-service.js +46 -23
- package/dist/state-backend.js +17 -8
- package/dist/web-dashboard.js +159 -33
- package/dist/web-state.js +131 -0
- package/docker-compose.yml +1 -1
- package/package.json +1 -1
- package/plugins/nordrelay/scripts/nordrelay.mjs +42 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
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
|
+
|
|
3
12
|
## v0.3.0 - 2026-05-12
|
|
4
13
|
|
|
5
14
|
Commits since `v0.2.1`:
|
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ Operations:
|
|
|
137
137
|
- Telegram sends/edits/documents are routed through a rate-limit queue that honors Telegram retry-after responses.
|
|
138
138
|
- Context metadata, queues, and preferences are written atomically with backup recovery.
|
|
139
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 state and logs are written under `~/.
|
|
140
|
+
- Runtime config, state, and logs are written under `~/.nordrelay/`.
|
|
141
141
|
- `nordrelay init` creates a private runtime config, `nordrelay doctor` validates host prerequisites, and `nordrelay web` starts a full local WebUI dashboard.
|
|
142
142
|
- The WebUI has responsive header/sidebar/footer navigation, live chat streaming, session controls, queue/artifact/log/diagnostic views, and settings management.
|
|
143
143
|
- The WebUI supports light and dark themes, tabbed settings groups, paginated session browsing, and chat uploads for images, documents, and audio transcription.
|
|
@@ -161,7 +161,7 @@ nordrelay doctor
|
|
|
161
161
|
nordrelay start
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
npm is the fastest install path and is the recommended default for normal use.
|
|
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
165
|
|
|
166
166
|
Non-interactive setup is also supported:
|
|
167
167
|
|
|
@@ -176,7 +176,9 @@ Install dependencies and build the runtime:
|
|
|
176
176
|
```bash
|
|
177
177
|
npm install
|
|
178
178
|
npm run build
|
|
179
|
-
|
|
179
|
+
mkdir -p ~/.nordrelay
|
|
180
|
+
cp .env.example ~/.nordrelay/nordrelay.env
|
|
181
|
+
chmod 600 ~/.nordrelay/nordrelay.env
|
|
180
182
|
```
|
|
181
183
|
|
|
182
184
|
Create the Telegram bot:
|
|
@@ -184,11 +186,11 @@ Create the Telegram bot:
|
|
|
184
186
|
1. Open Telegram and talk to `@BotFather`.
|
|
185
187
|
2. Run `/newbot`.
|
|
186
188
|
3. Choose a display name and bot username.
|
|
187
|
-
4. Copy the bot token into `TELEGRAM_BOT_TOKEN` in
|
|
189
|
+
4. Copy the bot token into `TELEGRAM_BOT_TOKEN` in `~/.nordrelay/nordrelay.env`.
|
|
188
190
|
5. Find your Telegram user id with a trusted id helper bot, for example `@userinfobot`, or from Telegram API tooling.
|
|
189
191
|
6. Put your user id into `TELEGRAM_ADMIN_USER_IDS`.
|
|
190
192
|
|
|
191
|
-
Minimal private-bot
|
|
193
|
+
Minimal private-bot `~/.nordrelay/nordrelay.env`:
|
|
192
194
|
|
|
193
195
|
```dotenv
|
|
194
196
|
TELEGRAM_BOT_TOKEN=123456789:replace-me
|
|
@@ -217,7 +219,7 @@ Codex authentication:
|
|
|
217
219
|
Pi setup:
|
|
218
220
|
|
|
219
221
|
- Install Pi from https://pi.dev/ and confirm `pi --help` works on the host.
|
|
220
|
-
- Set `NORDRELAY_PI_ENABLED=true` in
|
|
222
|
+
- Set `NORDRELAY_PI_ENABLED=true` in `~/.nordrelay/nordrelay.env`.
|
|
221
223
|
- Keep `NORDRELAY_DEFAULT_AGENT=codex` to start chats in Codex, or set `NORDRELAY_DEFAULT_AGENT=pi` to start chats in Pi.
|
|
222
224
|
- Optional: set `PI_SESSION_DIR` if your Pi sessions are not stored in `~/.pi/agent/sessions/`.
|
|
223
225
|
- Optional: set `PI_DEFAULT_MODEL=openai-codex/gpt-5.5` and `PI_DEFAULT_THINKING=medium`.
|
|
@@ -282,9 +284,9 @@ npm run foreground
|
|
|
282
284
|
|
|
283
285
|
Runtime files:
|
|
284
286
|
|
|
285
|
-
- PID file: `~/.
|
|
286
|
-
- State file: `~/.
|
|
287
|
-
- Log file: `~/.
|
|
287
|
+
- PID file: `~/.nordrelay/nordrelay.pid`
|
|
288
|
+
- State file: `~/.nordrelay/state.json`
|
|
289
|
+
- Log file: `~/.nordrelay/nordrelay.log`
|
|
288
290
|
- Home override: `NORDRELAY_HOME=/custom/path`
|
|
289
291
|
- Local dashboard: `nordrelay web --host 127.0.0.1 --port 31878`
|
|
290
292
|
|
|
@@ -305,14 +307,18 @@ http://127.0.0.1:31878/
|
|
|
305
307
|
The dashboard is a second NordRelay client next to Telegram. It can:
|
|
306
308
|
|
|
307
309
|
- Start a new Codex or Pi session.
|
|
308
|
-
-
|
|
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.
|
|
309
312
|
- Send prompts and receive streamed text/tool/plan updates through Server-Sent Events.
|
|
310
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.
|
|
311
316
|
- Abort turns, hand sessions back to the native CLI, and inspect the active session.
|
|
312
|
-
- Manage queued prompts.
|
|
313
|
-
- Browse, download, ZIP, and delete artifacts.
|
|
314
|
-
-
|
|
315
|
-
-
|
|
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.
|
|
316
322
|
|
|
317
323
|
Dashboard API endpoints are served under `/api/*`. Streaming uses `GET /api/events`.
|
|
318
324
|
|
|
@@ -612,7 +618,7 @@ Dashboard:
|
|
|
612
618
|
- `NORDRELAY_DASHBOARD_TOKEN`: optional dashboard bearer/login token. Required when binding to `0.0.0.0` unless basic auth is configured.
|
|
613
619
|
- `NORDRELAY_DASHBOARD_USER`: optional dashboard basic-auth user.
|
|
614
620
|
- `NORDRELAY_DASHBOARD_PASSWORD`: optional dashboard basic-auth password. Required with `NORDRELAY_DASHBOARD_USER`.
|
|
615
|
-
- `NORDRELAY_ENV_FILE`: optional env
|
|
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`.
|
|
616
622
|
|
|
617
623
|
Codex:
|
|
618
624
|
|
|
@@ -671,7 +677,7 @@ Auth and voice:
|
|
|
671
677
|
|
|
672
678
|
NordRelay wrapper:
|
|
673
679
|
|
|
674
|
-
- `NORDRELAY_HOME`: state/log directory override. Defaults to `~/.
|
|
680
|
+
- `NORDRELAY_HOME`: config/state/log directory override. Defaults to `~/.nordrelay`.
|
|
675
681
|
- `NORDRELAY_SOURCE_ROOT`: runtime source root override. Useful when the plugin is launched from Codex cache.
|
|
676
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.
|
|
677
683
|
- `NORDRELAY_KEEP_PENDING_UPDATES`: set true to avoid dropping pending Telegram updates on start.
|
|
@@ -719,7 +725,7 @@ Unsafe profiles are intentionally gated. Telegram asks for confirmation before a
|
|
|
719
725
|
- Do not leave `TELEGRAM_ALLOW_ANY_CHAT=true` enabled after setup.
|
|
720
726
|
- Treat `danger-full-access` as equivalent to shell access on the host.
|
|
721
727
|
- Treat uploaded files as untrusted input. They are staged inside the active workspace so the selected sandbox policy still matters.
|
|
722
|
-
- 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.
|
|
723
729
|
- In group chats, remember that any allowed user can prompt Codex in that chat context.
|
|
724
730
|
- Use `TOOL_VERBOSITY=summary` or `errors-only` when command output may include sensitive data.
|
|
725
731
|
- Review and unsafe launch profiles add a Telegram approve/deny gate before each turn starts.
|
|
@@ -777,7 +783,7 @@ Voice not working:
|
|
|
777
783
|
|
|
778
784
|
- Run `/voice` to list available backends.
|
|
779
785
|
- Install `ffmpeg` and `faster-whisper` on Linux, install `parakeet-coreml` on macOS Apple Silicon, or set `OPENAI_API_KEY`.
|
|
780
|
-
- Check `~/.
|
|
786
|
+
- Check `~/.nordrelay/nordrelay.log` for transcription errors.
|
|
781
787
|
|
|
782
788
|
Files not returned:
|
|
783
789
|
|
package/dist/bot.js
CHANGED
|
@@ -17,7 +17,7 @@ import { enabledAgents } from "./agent-factory.js";
|
|
|
17
17
|
import { checkAuthStatus, clearAuthCache, startLogin, startLogout } from "./codex-auth.js";
|
|
18
18
|
import { findLaunchProfile, formatLaunchProfileBehavior, formatLaunchProfileLabel, } from "./codex-launch.js";
|
|
19
19
|
import { getThreadActivity, getThreadActivityLog, getThreadRolloutSnapshot, } from "./codex-state.js";
|
|
20
|
-
import { contextKeyFromCtx, isTopicContextKey, parseContextKey } from "./context-key.js";
|
|
20
|
+
import { contextKeyFromCtx, isTelegramContextKey, isTopicContextKey, parseContextKey } from "./context-key.js";
|
|
21
21
|
import { friendlyErrorText } from "./error-messages.js";
|
|
22
22
|
import { escapeHTML, formatTelegramHTML } from "./format.js";
|
|
23
23
|
import { getConnectorHealth, getUpdateLogPath, getVersionChecks, readConnectorState, readFormattedLogTail, spawnConnectorRestart, spawnSelfUpdate, } from "./operations.js";
|
|
@@ -331,12 +331,15 @@ export function createBot(config, registry) {
|
|
|
331
331
|
const contextKeys = new Set([
|
|
332
332
|
...registry.listContexts().map((context) => context.contextKey),
|
|
333
333
|
...promptStore.listContextKeys(),
|
|
334
|
-
]);
|
|
334
|
+
].filter(isTelegramContextKey));
|
|
335
335
|
for (const contextKey of contextKeys) {
|
|
336
336
|
await monitorExternalContext(contextKey);
|
|
337
337
|
}
|
|
338
338
|
};
|
|
339
339
|
const monitorExternalContext = async (contextKey) => {
|
|
340
|
+
if (!isTelegramContextKey(contextKey)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
340
343
|
const session = await registry.getOrCreate(contextKey, { deferThreadStart: true }).catch(() => null);
|
|
341
344
|
if (!session) {
|
|
342
345
|
return;
|
package/dist/codex-session.js
CHANGED
|
@@ -47,6 +47,8 @@ export class CodexSessionService {
|
|
|
47
47
|
const effectiveLaunchProfile = this.activeThreadLaunchProfile ?? this.currentLaunchProfile;
|
|
48
48
|
const codexFastMode = readCodexFastMode();
|
|
49
49
|
this.lastObservedFastMode = codexFastMode;
|
|
50
|
+
const attachedThreadFastMode = effectiveLaunchProfile.id === "attached-thread" &&
|
|
51
|
+
effectiveLaunchProfile.approvalPolicy === "never";
|
|
50
52
|
const info = {
|
|
51
53
|
agentId: "codex",
|
|
52
54
|
agentLabel: "Codex",
|
|
@@ -58,7 +60,7 @@ export class CodexSessionService {
|
|
|
58
60
|
launchProfileBehavior: formatLaunchProfileBehavior(effectiveLaunchProfile),
|
|
59
61
|
sandboxMode: effectiveLaunchProfile.sandboxMode,
|
|
60
62
|
approvalPolicy: effectiveLaunchProfile.approvalPolicy,
|
|
61
|
-
fastMode: codexFastMode ?? (effectiveLaunchProfile.approvalPolicy === "never"),
|
|
63
|
+
fastMode: attachedThreadFastMode || (codexFastMode ?? (effectiveLaunchProfile.approvalPolicy === "never")),
|
|
62
64
|
unsafeLaunch: effectiveLaunchProfile.unsafe,
|
|
63
65
|
capabilities: CODEX_AGENT_CAPABILITIES,
|
|
64
66
|
};
|
package/dist/context-key.js
CHANGED
|
@@ -21,3 +21,26 @@ export function parseContextKey(key) {
|
|
|
21
21
|
export function isTopicContextKey(key) {
|
|
22
22
|
return key.includes(":");
|
|
23
23
|
}
|
|
24
|
+
export function isTelegramContextKey(key) {
|
|
25
|
+
const parts = key.split(":");
|
|
26
|
+
if (parts.length < 1 || parts.length > 2) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const chatIdText = parts[0];
|
|
30
|
+
if (!chatIdText || !/^-?\d+$/.test(chatIdText)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const chatId = Number(chatIdText);
|
|
34
|
+
if (!Number.isSafeInteger(chatId) || chatId === 0) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
const threadIdText = parts[1];
|
|
38
|
+
if (threadIdText === undefined) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (!/^\d+$/.test(threadIdText)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const threadId = Number(threadIdText);
|
|
45
|
+
return Number.isSafeInteger(threadId) && threadId > 0;
|
|
46
|
+
}
|
package/dist/operations.js
CHANGED
|
@@ -10,7 +10,7 @@ const APP_NAME = "nordrelay";
|
|
|
10
10
|
const PACKAGE_NAME = "@nordbyte/nordrelay";
|
|
11
11
|
const CODEX_PACKAGE_NAME = "@openai/codex";
|
|
12
12
|
const PI_PACKAGE_NAME = "@mariozechner/pi-coding-agent";
|
|
13
|
-
const DEFAULT_HOME = path.join(os.homedir(), ".
|
|
13
|
+
const DEFAULT_HOME = path.join(os.homedir(), ".nordrelay");
|
|
14
14
|
const SECRET_RE = /(bot|token|api[_-]?key|authorization|bearer|password|secret)(["'=: ]+)([^\s"',]+)/gi;
|
|
15
15
|
const DEFAULT_VERSION_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
16
16
|
export function getConnectorHome() {
|