@nordbyte/nordrelay 0.4.1 → 0.5.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 +155 -64
- package/README.md +81 -65
- package/dist/access-control.js +126 -115
- package/dist/agent-updates.js +62 -9
- package/dist/bot-rendering.js +838 -0
- package/dist/bot-ui.js +1 -0
- package/dist/bot.js +342 -2498
- package/dist/channel-actions.js +8 -8
- package/dist/channel-runtime.js +89 -0
- package/dist/config-metadata.js +238 -0
- package/dist/config.js +0 -58
- package/dist/index.js +8 -0
- package/dist/operations.js +63 -9
- package/dist/relay-artifact-service.js +126 -0
- package/dist/relay-external-activity-monitor.js +216 -0
- package/dist/relay-queue-service.js +66 -0
- package/dist/relay-runtime-types.js +1 -0
- package/dist/relay-runtime.js +96 -354
- package/dist/settings-service.js +2 -117
- package/dist/support-bundle.js +205 -0
- package/dist/telegram-access-commands.js +123 -0
- package/dist/telegram-access-middleware.js +129 -0
- package/dist/telegram-agent-commands.js +212 -0
- package/dist/telegram-artifact-commands.js +139 -0
- package/dist/telegram-channel-runtime.js +132 -0
- package/dist/telegram-command-menu.js +55 -0
- package/dist/telegram-command-types.js +1 -0
- package/dist/telegram-diagnostics-command.js +102 -0
- package/dist/telegram-general-commands.js +52 -0
- package/dist/telegram-operational-commands.js +153 -0
- package/dist/telegram-output.js +216 -0
- package/dist/telegram-preference-commands.js +198 -0
- package/dist/telegram-queue-commands.js +278 -0
- package/dist/telegram-support-command.js +53 -0
- package/dist/telegram-update-commands.js +93 -0
- package/dist/user-management.js +708 -0
- package/dist/web-api-contract.js +104 -0
- package/dist/web-api-types.js +1 -0
- package/dist/web-dashboard-access-routes.js +163 -0
- package/dist/web-dashboard-artifact-routes.js +65 -0
- package/dist/web-dashboard-assets.js +35 -2
- package/dist/web-dashboard-http.js +143 -0
- package/dist/web-dashboard-pages.js +257 -0
- package/dist/web-dashboard-runtime-routes.js +92 -0
- package/dist/web-dashboard-session-routes.js +209 -0
- package/dist/web-dashboard-ui.js +14 -14
- package/dist/web-dashboard.js +330 -707
- package/dist/webui-assets/dashboard.css +989 -0
- package/dist/webui-assets/dashboard.js +1750 -0
- package/dist/zip-writer.js +83 -0
- package/package.json +13 -4
- package/plugins/nordrelay/.codex-plugin/plugin.json +1 -1
- package/plugins/nordrelay/commands/remote.md +1 -1
- package/plugins/nordrelay/scripts/nordrelay.mjs +227 -78
- package/plugins/nordrelay/skills/telegram-remote/SKILL.md +1 -1
- package/dist/web-dashboard-client.js +0 -275
- package/dist/web-dashboard-style.js +0 -9
package/dist/agent-updates.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { agentLabel } from "./agent.js";
|
|
@@ -7,9 +7,16 @@ import { resolveClaudeCodeCli } from "./claude-code-cli.js";
|
|
|
7
7
|
import { resolveCodexCli } from "./codex-cli.js";
|
|
8
8
|
import { resolveHermesCli } from "./hermes-cli.js";
|
|
9
9
|
import { resolveOpenClawCli } from "./openclaw-cli.js";
|
|
10
|
-
import { getAgentUpdateLogPath, getConnectorHome } from "./operations.js";
|
|
10
|
+
import { getAgentUpdateLogPath, getConnectorHome, resolveNpmSpawnCommand } from "./operations.js";
|
|
11
11
|
import { resolvePiCli } from "./pi-cli.js";
|
|
12
12
|
import { redactText } from "./redaction.js";
|
|
13
|
+
const AGENT_INSTALL_PACKAGES = {
|
|
14
|
+
codex: "@openai/codex",
|
|
15
|
+
pi: "@earendil-works/pi-coding-agent",
|
|
16
|
+
hermes: "hermes-agent",
|
|
17
|
+
openclaw: "openclaw",
|
|
18
|
+
"claude-code": "@anthropic-ai/claude-code",
|
|
19
|
+
};
|
|
13
20
|
export class AgentUpdateManager {
|
|
14
21
|
options;
|
|
15
22
|
jobs = new Map();
|
|
@@ -34,6 +41,9 @@ export class AgentUpdateManager {
|
|
|
34
41
|
}
|
|
35
42
|
readLog(id) {
|
|
36
43
|
const job = this.requireJob(id);
|
|
44
|
+
if (job.logDeletedAt) {
|
|
45
|
+
return { job: this.snapshot(job), plain: `Update log was deleted at ${job.logDeletedAt}.` };
|
|
46
|
+
}
|
|
37
47
|
try {
|
|
38
48
|
return { job: this.snapshot(job), plain: redactText(readFileSync(job.logPath, "utf8")) };
|
|
39
49
|
}
|
|
@@ -44,12 +54,23 @@ export class AgentUpdateManager {
|
|
|
44
54
|
};
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
|
-
|
|
57
|
+
deleteLog(id) {
|
|
58
|
+
const job = this.requireJob(id);
|
|
59
|
+
if (job.status === "running") {
|
|
60
|
+
throw new Error("Cannot delete the update log while the update job is still running.");
|
|
61
|
+
}
|
|
62
|
+
const snapshot = this.snapshot(job);
|
|
63
|
+
rmSync(job.logPath, { force: true });
|
|
64
|
+
this.jobs.delete(id);
|
|
65
|
+
this.persistJobs();
|
|
66
|
+
return snapshot;
|
|
67
|
+
}
|
|
68
|
+
start(agentId, context = {}, operation = "update") {
|
|
48
69
|
const running = [...this.jobs.values()].find((job) => job.agentId === agentId && job.status === "running");
|
|
49
70
|
if (running) {
|
|
50
|
-
throw new Error(`${agentLabel(agentId)} update is already running.`);
|
|
71
|
+
throw new Error(`${agentLabel(agentId)} update/install job is already running.`);
|
|
51
72
|
}
|
|
52
|
-
const plan = resolveAgentUpdatePlan(agentId, { ...context, env: context.env ?? this.options.env });
|
|
73
|
+
const plan = resolveAgentUpdatePlan(agentId, { ...context, env: context.env ?? this.options.env }, operation);
|
|
53
74
|
const now = new Date().toISOString();
|
|
54
75
|
const id = `${agentId.replace(/[^a-z0-9]/gi, "")}-${Date.now().toString(36)}`;
|
|
55
76
|
const logPath = path.join(this.home, "updates", `${id}.log`);
|
|
@@ -58,6 +79,7 @@ export class AgentUpdateManager {
|
|
|
58
79
|
id,
|
|
59
80
|
agentId,
|
|
60
81
|
agentLabel: plan.agentLabel,
|
|
82
|
+
operation,
|
|
61
83
|
status: "running",
|
|
62
84
|
method: plan.method,
|
|
63
85
|
command: plan.command,
|
|
@@ -77,7 +99,7 @@ export class AgentUpdateManager {
|
|
|
77
99
|
this.jobs.set(id, job);
|
|
78
100
|
this.persistJobs();
|
|
79
101
|
this.append(job, [
|
|
80
|
-
`[${now}] Starting ${job.agentLabel}
|
|
102
|
+
`[${now}] Starting ${job.agentLabel} ${job.operation}`,
|
|
81
103
|
`Method: ${job.method}`,
|
|
82
104
|
`Command: ${[job.command, ...job.args].join(" ")}`,
|
|
83
105
|
`Working directory: ${job.cwd}`,
|
|
@@ -101,7 +123,7 @@ export class AgentUpdateManager {
|
|
|
101
123
|
if (job.status !== "running") {
|
|
102
124
|
return;
|
|
103
125
|
}
|
|
104
|
-
this.finish(job, code === 0 ? "completed" : "failed", code, signal, code === 0 ? undefined :
|
|
126
|
+
this.finish(job, code === 0 ? "completed" : "failed", code, signal, code === 0 ? undefined : `${capitalize(job.operation)} exited with code ${code ?? "unknown"}`);
|
|
105
127
|
});
|
|
106
128
|
this.emit(job);
|
|
107
129
|
return this.snapshot(job);
|
|
@@ -164,7 +186,7 @@ export class AgentUpdateManager {
|
|
|
164
186
|
job.finishedAt = new Date().toISOString();
|
|
165
187
|
job.updatedAt = job.finishedAt;
|
|
166
188
|
job.child = undefined;
|
|
167
|
-
this.append(job, `\n[${job.finishedAt}] ${job.agentLabel}
|
|
189
|
+
this.append(job, `\n[${job.finishedAt}] ${job.agentLabel} ${job.operation} ${status}${error ? `: ${job.error}` : ""}\n`);
|
|
168
190
|
}
|
|
169
191
|
emit(job) {
|
|
170
192
|
this.options.onUpdate?.(this.snapshot(job));
|
|
@@ -181,12 +203,17 @@ export class AgentUpdateManager {
|
|
|
181
203
|
const parsed = JSON.parse(readFileSync(this.manifestPath, "utf8"));
|
|
182
204
|
let changed = false;
|
|
183
205
|
for (const snapshot of parsed) {
|
|
206
|
+
if (snapshot.logDeletedAt) {
|
|
207
|
+
changed = true;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
184
210
|
const staleRunning = snapshot.status === "running" && !isProcessRunning(snapshot.ownerPid);
|
|
185
211
|
if (staleRunning) {
|
|
186
212
|
changed = true;
|
|
187
213
|
}
|
|
188
214
|
const job = {
|
|
189
215
|
...snapshot,
|
|
216
|
+
operation: snapshot.operation ?? "update",
|
|
190
217
|
status: staleRunning ? "failed" : snapshot.status,
|
|
191
218
|
canInput: false,
|
|
192
219
|
needsInput: false,
|
|
@@ -236,7 +263,10 @@ function isProcessRunning(pid) {
|
|
|
236
263
|
return false;
|
|
237
264
|
}
|
|
238
265
|
}
|
|
239
|
-
export function resolveAgentUpdatePlan(agentId, context = {}) {
|
|
266
|
+
export function resolveAgentUpdatePlan(agentId, context = {}, operation = "update") {
|
|
267
|
+
if (operation === "install") {
|
|
268
|
+
return resolveAgentInstallPlan(agentId, context);
|
|
269
|
+
}
|
|
240
270
|
const env = context.env ?? process.env;
|
|
241
271
|
switch (agentId) {
|
|
242
272
|
case "codex": {
|
|
@@ -276,10 +306,30 @@ export function resolveAgentUpdatePlan(agentId, context = {}) {
|
|
|
276
306
|
}
|
|
277
307
|
}
|
|
278
308
|
}
|
|
309
|
+
function resolveAgentInstallPlan(agentId, context = {}) {
|
|
310
|
+
const env = context.env ?? process.env;
|
|
311
|
+
const npm = resolveNpmSpawnCommand(env);
|
|
312
|
+
if (!npm) {
|
|
313
|
+
throw new Error(`Cannot install ${agentLabel(agentId)} because npm was not found on PATH.`);
|
|
314
|
+
}
|
|
315
|
+
const packageName = AGENT_INSTALL_PACKAGES[agentId];
|
|
316
|
+
return {
|
|
317
|
+
agentId,
|
|
318
|
+
agentLabel: agentLabel(agentId),
|
|
319
|
+
operation: "install",
|
|
320
|
+
method: `npm install -g ${packageName}@latest`,
|
|
321
|
+
command: npm.command,
|
|
322
|
+
args: [...npm.argsPrefix, "install", "-g", `${packageName}@latest`],
|
|
323
|
+
cwd: env.HOME || os.homedir(),
|
|
324
|
+
summary: `Installs the latest ${agentLabel(agentId)} CLI with npm. Restart NordRelay after installation if the agent was previously unavailable.`,
|
|
325
|
+
interactive: true,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
279
328
|
function plan(agentId, method, command, args, summary, env) {
|
|
280
329
|
return {
|
|
281
330
|
agentId,
|
|
282
331
|
agentLabel: agentLabel(agentId),
|
|
332
|
+
operation: "update",
|
|
283
333
|
method,
|
|
284
334
|
command,
|
|
285
335
|
args,
|
|
@@ -292,3 +342,6 @@ function looksLikePrompt(text) {
|
|
|
292
342
|
const tail = text.split(/\r?\n/).slice(-4).join("\n");
|
|
293
343
|
return /\b(y\/n|yes\/no|continue|proceed|confirm|password|passphrase|token|api key|enter|select)\b|[?>]\s*$/i.test(tail);
|
|
294
344
|
}
|
|
345
|
+
function capitalize(value) {
|
|
346
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
347
|
+
}
|