@nordbyte/nordrelay 0.3.1 → 0.4.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 +45 -2
- package/README.md +221 -35
- package/dist/access-control.js +3 -0
- package/dist/agent-activity.js +300 -0
- package/dist/agent-adapter.js +17 -30
- package/dist/agent-factory.js +27 -0
- package/dist/agent-feature-matrix.js +42 -0
- package/dist/agent-updates.js +294 -0
- package/dist/agent.js +123 -9
- package/dist/artifacts.js +1 -1
- package/dist/audit-log.js +1 -1
- package/dist/bot-ui.js +1 -1
- package/dist/bot.js +483 -354
- package/dist/channel-actions.js +372 -0
- package/dist/claude-code-auth.js +121 -0
- package/dist/claude-code-cli.js +19 -0
- package/dist/claude-code-launch.js +73 -0
- package/dist/claude-code-session.js +660 -0
- package/dist/claude-code-state.js +590 -0
- package/dist/codex-session.js +12 -1
- package/dist/config.js +113 -9
- package/dist/hermes-api.js +150 -0
- package/dist/hermes-auth.js +96 -0
- package/dist/hermes-cli.js +19 -0
- package/dist/hermes-launch.js +57 -0
- package/dist/hermes-session.js +477 -0
- package/dist/hermes-state.js +609 -0
- package/dist/index.js +51 -8
- package/dist/openclaw-auth.js +27 -0
- package/dist/openclaw-cli.js +19 -0
- package/dist/openclaw-gateway.js +285 -0
- package/dist/openclaw-launch.js +65 -0
- package/dist/openclaw-session.js +549 -0
- package/dist/openclaw-state.js +409 -0
- package/dist/operations.js +115 -9
- package/dist/pi-auth.js +59 -0
- package/dist/pi-launch.js +61 -0
- package/dist/pi-rpc.js +18 -0
- package/dist/pi-session.js +103 -15
- package/dist/pi-state.js +253 -0
- package/dist/relay-runtime.js +798 -72
- package/dist/session-format.js +98 -19
- package/dist/session-registry.js +40 -15
- package/dist/settings-service.js +35 -4
- package/dist/web-dashboard-assets.js +2 -0
- package/dist/web-dashboard-client.js +275 -0
- package/dist/web-dashboard-style.js +9 -0
- package/dist/web-dashboard-ui.js +18 -0
- package/dist/web-dashboard.js +296 -196
- package/package.json +8 -3
- package/plugins/nordrelay/.codex-plugin/plugin.json +7 -4
- package/plugins/nordrelay/commands/remote.md +2 -2
- package/plugins/nordrelay/scripts/nordrelay.mjs +187 -12
- package/plugins/nordrelay/skills/telegram-remote/SKILL.md +2 -2
- package/CHANGELOG.md +0 -26
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { agentLabel } from "./agent.js";
|
|
6
|
+
import { resolveClaudeCodeCli } from "./claude-code-cli.js";
|
|
7
|
+
import { resolveCodexCli } from "./codex-cli.js";
|
|
8
|
+
import { resolveHermesCli } from "./hermes-cli.js";
|
|
9
|
+
import { resolveOpenClawCli } from "./openclaw-cli.js";
|
|
10
|
+
import { getAgentUpdateLogPath, getConnectorHome } from "./operations.js";
|
|
11
|
+
import { resolvePiCli } from "./pi-cli.js";
|
|
12
|
+
import { redactText } from "./redaction.js";
|
|
13
|
+
export class AgentUpdateManager {
|
|
14
|
+
options;
|
|
15
|
+
jobs = new Map();
|
|
16
|
+
home;
|
|
17
|
+
manifestPath;
|
|
18
|
+
aggregateLogPath;
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.home = options.home ?? getConnectorHome();
|
|
22
|
+
this.manifestPath = path.join(this.home, "updates", "jobs.json");
|
|
23
|
+
this.aggregateLogPath = getAgentUpdateLogPath(this.home);
|
|
24
|
+
this.loadPersistedJobs();
|
|
25
|
+
}
|
|
26
|
+
list() {
|
|
27
|
+
return [...this.jobs.values()]
|
|
28
|
+
.sort((left, right) => right.startedAt.localeCompare(left.startedAt))
|
|
29
|
+
.map((job) => this.snapshot(job));
|
|
30
|
+
}
|
|
31
|
+
get(id) {
|
|
32
|
+
const job = this.jobs.get(id);
|
|
33
|
+
return job ? this.snapshot(job) : null;
|
|
34
|
+
}
|
|
35
|
+
readLog(id) {
|
|
36
|
+
const job = this.requireJob(id);
|
|
37
|
+
try {
|
|
38
|
+
return { job: this.snapshot(job), plain: redactText(readFileSync(job.logPath, "utf8")) };
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
job: this.snapshot(job),
|
|
43
|
+
plain: `Cannot read update log: ${error instanceof Error ? error.message : String(error)}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
start(agentId, context = {}) {
|
|
48
|
+
const running = [...this.jobs.values()].find((job) => job.agentId === agentId && job.status === "running");
|
|
49
|
+
if (running) {
|
|
50
|
+
throw new Error(`${agentLabel(agentId)} update is already running.`);
|
|
51
|
+
}
|
|
52
|
+
const plan = resolveAgentUpdatePlan(agentId, { ...context, env: context.env ?? this.options.env });
|
|
53
|
+
const now = new Date().toISOString();
|
|
54
|
+
const id = `${agentId.replace(/[^a-z0-9]/gi, "")}-${Date.now().toString(36)}`;
|
|
55
|
+
const logPath = path.join(this.home, "updates", `${id}.log`);
|
|
56
|
+
mkdirSync(path.dirname(logPath), { recursive: true });
|
|
57
|
+
const job = {
|
|
58
|
+
id,
|
|
59
|
+
agentId,
|
|
60
|
+
agentLabel: plan.agentLabel,
|
|
61
|
+
status: "running",
|
|
62
|
+
method: plan.method,
|
|
63
|
+
command: plan.command,
|
|
64
|
+
args: plan.args,
|
|
65
|
+
cwd: plan.cwd,
|
|
66
|
+
summary: plan.summary,
|
|
67
|
+
interactive: plan.interactive,
|
|
68
|
+
canInput: true,
|
|
69
|
+
needsInput: false,
|
|
70
|
+
startedAt: now,
|
|
71
|
+
updatedAt: now,
|
|
72
|
+
logPath,
|
|
73
|
+
ownerPid: process.pid,
|
|
74
|
+
output: "",
|
|
75
|
+
outputTail: "",
|
|
76
|
+
};
|
|
77
|
+
this.jobs.set(id, job);
|
|
78
|
+
this.persistJobs();
|
|
79
|
+
this.append(job, [
|
|
80
|
+
`[${now}] Starting ${job.agentLabel} update`,
|
|
81
|
+
`Method: ${job.method}`,
|
|
82
|
+
`Command: ${[job.command, ...job.args].join(" ")}`,
|
|
83
|
+
`Working directory: ${job.cwd}`,
|
|
84
|
+
"",
|
|
85
|
+
].join("\n"));
|
|
86
|
+
const child = spawn(plan.command, plan.args, {
|
|
87
|
+
cwd: plan.cwd,
|
|
88
|
+
env: { ...process.env, ...(this.options.env ?? {}), ...(context.env ?? {}) },
|
|
89
|
+
shell: process.platform === "win32",
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
stdio: "pipe",
|
|
92
|
+
});
|
|
93
|
+
job.child = child;
|
|
94
|
+
child.stdin.setDefaultEncoding("utf8");
|
|
95
|
+
child.stdout.on("data", (chunk) => this.append(job, chunk.toString("utf8")));
|
|
96
|
+
child.stderr.on("data", (chunk) => this.append(job, chunk.toString("utf8")));
|
|
97
|
+
child.on("error", (error) => {
|
|
98
|
+
this.finish(job, "failed", null, null, error.message);
|
|
99
|
+
});
|
|
100
|
+
child.on("close", (code, signal) => {
|
|
101
|
+
if (job.status !== "running") {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.finish(job, code === 0 ? "completed" : "failed", code, signal, code === 0 ? undefined : `Update exited with code ${code ?? "unknown"}`);
|
|
105
|
+
});
|
|
106
|
+
this.emit(job);
|
|
107
|
+
return this.snapshot(job);
|
|
108
|
+
}
|
|
109
|
+
sendInput(id, input) {
|
|
110
|
+
const job = this.requireJob(id);
|
|
111
|
+
if (job.status !== "running" || !job.child?.stdin.writable) {
|
|
112
|
+
throw new Error("Update job is not accepting input.");
|
|
113
|
+
}
|
|
114
|
+
const line = input.endsWith("\n") ? input : `${input}\n`;
|
|
115
|
+
job.child.stdin.write(line);
|
|
116
|
+
job.needsInput = false;
|
|
117
|
+
this.append(job, `[${new Date().toISOString()}] Input sent from dashboard.\n`);
|
|
118
|
+
return this.snapshot(job);
|
|
119
|
+
}
|
|
120
|
+
cancel(id) {
|
|
121
|
+
const job = this.requireJob(id);
|
|
122
|
+
if (job.status !== "running") {
|
|
123
|
+
return this.snapshot(job);
|
|
124
|
+
}
|
|
125
|
+
job.child?.kill("SIGTERM");
|
|
126
|
+
this.finish(job, "cancelled", null, "SIGTERM", "Cancelled from dashboard.");
|
|
127
|
+
return this.snapshot(job);
|
|
128
|
+
}
|
|
129
|
+
cancelAll() {
|
|
130
|
+
for (const job of this.jobs.values()) {
|
|
131
|
+
if (job.status === "running") {
|
|
132
|
+
job.child?.kill("SIGTERM");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
requireJob(id) {
|
|
137
|
+
const job = this.jobs.get(id);
|
|
138
|
+
if (!job) {
|
|
139
|
+
throw new Error(`Unknown update job: ${id}`);
|
|
140
|
+
}
|
|
141
|
+
return job;
|
|
142
|
+
}
|
|
143
|
+
append(job, text) {
|
|
144
|
+
const redacted = redactText(text);
|
|
145
|
+
job.output += redacted;
|
|
146
|
+
if (job.output.length > 120_000) {
|
|
147
|
+
job.output = job.output.slice(-120_000);
|
|
148
|
+
}
|
|
149
|
+
job.outputTail = job.output.slice(-16_000);
|
|
150
|
+
job.updatedAt = new Date().toISOString();
|
|
151
|
+
job.needsInput = job.status === "running" && looksLikePrompt(job.outputTail);
|
|
152
|
+
writeFileSync(job.logPath, redacted, { flag: "a", encoding: "utf8" });
|
|
153
|
+
this.appendAggregate(job, redacted);
|
|
154
|
+
this.persistJobs();
|
|
155
|
+
this.emit(job);
|
|
156
|
+
}
|
|
157
|
+
finish(job, status, code, signal, error) {
|
|
158
|
+
job.status = status;
|
|
159
|
+
job.canInput = false;
|
|
160
|
+
job.needsInput = false;
|
|
161
|
+
job.exitCode = code;
|
|
162
|
+
job.signal = signal;
|
|
163
|
+
job.error = error ? redactText(error) : undefined;
|
|
164
|
+
job.finishedAt = new Date().toISOString();
|
|
165
|
+
job.updatedAt = job.finishedAt;
|
|
166
|
+
job.child = undefined;
|
|
167
|
+
this.append(job, `\n[${job.finishedAt}] ${job.agentLabel} update ${status}${error ? `: ${job.error}` : ""}\n`);
|
|
168
|
+
}
|
|
169
|
+
emit(job) {
|
|
170
|
+
this.options.onUpdate?.(this.snapshot(job));
|
|
171
|
+
}
|
|
172
|
+
snapshot(job) {
|
|
173
|
+
const { child: _child, output: _output, ...snapshot } = job;
|
|
174
|
+
return { ...snapshot };
|
|
175
|
+
}
|
|
176
|
+
loadPersistedJobs() {
|
|
177
|
+
if (!existsSync(this.manifestPath)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const parsed = JSON.parse(readFileSync(this.manifestPath, "utf8"));
|
|
182
|
+
let changed = false;
|
|
183
|
+
for (const snapshot of parsed) {
|
|
184
|
+
const staleRunning = snapshot.status === "running" && !isProcessRunning(snapshot.ownerPid);
|
|
185
|
+
if (staleRunning) {
|
|
186
|
+
changed = true;
|
|
187
|
+
}
|
|
188
|
+
const job = {
|
|
189
|
+
...snapshot,
|
|
190
|
+
status: staleRunning ? "failed" : snapshot.status,
|
|
191
|
+
canInput: false,
|
|
192
|
+
needsInput: false,
|
|
193
|
+
error: staleRunning
|
|
194
|
+
? "Update process was still running when NordRelay restarted; inspect the agent update log before retrying."
|
|
195
|
+
: snapshot.error,
|
|
196
|
+
finishedAt: staleRunning ? new Date().toISOString() : snapshot.finishedAt,
|
|
197
|
+
updatedAt: staleRunning ? new Date().toISOString() : snapshot.updatedAt,
|
|
198
|
+
output: snapshot.outputTail ?? "",
|
|
199
|
+
outputTail: snapshot.outputTail ?? "",
|
|
200
|
+
};
|
|
201
|
+
this.jobs.set(job.id, job);
|
|
202
|
+
}
|
|
203
|
+
if (changed) {
|
|
204
|
+
this.persistJobs();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
this.jobs.clear();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
persistJobs() {
|
|
212
|
+
mkdirSync(path.dirname(this.manifestPath), { recursive: true });
|
|
213
|
+
const snapshots = this.list().slice(0, 100);
|
|
214
|
+
writeFileSync(this.manifestPath, `${JSON.stringify(snapshots, null, 2)}\n`, "utf8");
|
|
215
|
+
}
|
|
216
|
+
appendAggregate(job, text) {
|
|
217
|
+
const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
218
|
+
if (lines.length === 0) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
mkdirSync(path.dirname(this.aggregateLogPath), { recursive: true });
|
|
222
|
+
const now = new Date().toISOString();
|
|
223
|
+
const prefix = `[${now}] INFO [${job.id}]`;
|
|
224
|
+
appendFileSync(this.aggregateLogPath, `${lines.map((line) => `${prefix} ${line}`).join("\n")}\n`, "utf8");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function isProcessRunning(pid) {
|
|
228
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
process.kill(pid, 0);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
export function resolveAgentUpdatePlan(agentId, context = {}) {
|
|
240
|
+
const env = context.env ?? process.env;
|
|
241
|
+
switch (agentId) {
|
|
242
|
+
case "codex": {
|
|
243
|
+
const cli = resolveCodexCli(env);
|
|
244
|
+
if (!cli.path) {
|
|
245
|
+
throw new Error("Codex CLI is not installed on PATH. Install or update it with npm i -g @openai/codex@latest.");
|
|
246
|
+
}
|
|
247
|
+
return plan(agentId, "codex update", cli.path, ["update"], "Runs the Codex CLI self-updater. If this install cannot self-update, use npm i -g @openai/codex@latest.", env);
|
|
248
|
+
}
|
|
249
|
+
case "pi": {
|
|
250
|
+
const cli = resolvePiCli(env, context.piCliPath);
|
|
251
|
+
if (!cli.path) {
|
|
252
|
+
throw new Error("Pi CLI is not installed on PATH. Install or update it with npm install -g @earendil-works/pi-coding-agent@latest.");
|
|
253
|
+
}
|
|
254
|
+
return plan(agentId, "pi update pi", cli.path, ["update", "pi"], "Updates only the Pi coding agent, not installed Pi extensions.", env);
|
|
255
|
+
}
|
|
256
|
+
case "hermes": {
|
|
257
|
+
const cli = resolveHermesCli(env, context.hermesCliPath);
|
|
258
|
+
if (!cli.path) {
|
|
259
|
+
throw new Error("Hermes CLI is not installed on PATH. Install Hermes with the official installer before updating.");
|
|
260
|
+
}
|
|
261
|
+
return plan(agentId, "hermes update --yes", cli.path, ["update", "--yes"], "Runs the Hermes git/dependency updater with confirmation prompts accepted where supported.", env);
|
|
262
|
+
}
|
|
263
|
+
case "openclaw": {
|
|
264
|
+
const cli = resolveOpenClawCli(env, context.openClawCliPath);
|
|
265
|
+
if (!cli.path) {
|
|
266
|
+
throw new Error("OpenClaw CLI is not installed on PATH. Install OpenClaw before updating.");
|
|
267
|
+
}
|
|
268
|
+
return plan(agentId, "openclaw update --yes", cli.path, ["update", "--yes"], "Runs the OpenClaw updater, which detects npm/git installs and may restart the Gateway.", env);
|
|
269
|
+
}
|
|
270
|
+
case "claude-code": {
|
|
271
|
+
const cli = resolveClaudeCodeCli(env, context.claudeCodeCliPath);
|
|
272
|
+
if (!cli.path) {
|
|
273
|
+
throw new Error("Claude Code host CLI is not installed on PATH. Bundled SDK updates arrive with NordRelay releases.");
|
|
274
|
+
}
|
|
275
|
+
return plan(agentId, "claude update", cli.path, ["update"], "Runs the Claude Code updater. Some package-manager installs may print a manual command instead.", env);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function plan(agentId, method, command, args, summary, env) {
|
|
280
|
+
return {
|
|
281
|
+
agentId,
|
|
282
|
+
agentLabel: agentLabel(agentId),
|
|
283
|
+
method,
|
|
284
|
+
command,
|
|
285
|
+
args,
|
|
286
|
+
cwd: env.HOME || os.homedir(),
|
|
287
|
+
summary,
|
|
288
|
+
interactive: true,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function looksLikePrompt(text) {
|
|
292
|
+
const tail = text.split(/\r?\n/).slice(-4).join("\n");
|
|
293
|
+
return /\b(y\/n|yes\/no|continue|proceed|confirm|password|passphrase|token|api key|enter|select)\b|[?>]\s*$/i.test(tail);
|
|
294
|
+
}
|
package/dist/agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const AGENT_IDS = ["codex", "pi"];
|
|
1
|
+
export const AGENT_IDS = ["codex", "pi", "hermes", "openclaw", "claude-code"];
|
|
2
2
|
export const CODEX_REASONING_EFFORTS = [
|
|
3
3
|
"minimal",
|
|
4
4
|
"low",
|
|
@@ -14,6 +14,29 @@ export const PI_THINKING_LEVELS = [
|
|
|
14
14
|
"high",
|
|
15
15
|
"xhigh",
|
|
16
16
|
];
|
|
17
|
+
export const HERMES_REASONING_EFFORTS = [
|
|
18
|
+
"none",
|
|
19
|
+
"minimal",
|
|
20
|
+
"low",
|
|
21
|
+
"medium",
|
|
22
|
+
"high",
|
|
23
|
+
"xhigh",
|
|
24
|
+
];
|
|
25
|
+
export const OPENCLAW_THINKING_LEVELS = [
|
|
26
|
+
"off",
|
|
27
|
+
"minimal",
|
|
28
|
+
"low",
|
|
29
|
+
"medium",
|
|
30
|
+
"high",
|
|
31
|
+
"xhigh",
|
|
32
|
+
];
|
|
33
|
+
export const CLAUDE_CODE_EFFORT_LEVELS = [
|
|
34
|
+
"off",
|
|
35
|
+
"low",
|
|
36
|
+
"medium",
|
|
37
|
+
"high",
|
|
38
|
+
"xhigh",
|
|
39
|
+
];
|
|
17
40
|
export const CODEX_AGENT_CAPABILITIES = {
|
|
18
41
|
launchProfiles: true,
|
|
19
42
|
fastMode: true,
|
|
@@ -23,6 +46,8 @@ export const CODEX_AGENT_CAPABILITIES = {
|
|
|
23
46
|
auth: true,
|
|
24
47
|
login: true,
|
|
25
48
|
logout: true,
|
|
49
|
+
usageStats: true,
|
|
50
|
+
subscriptionLimits: true,
|
|
26
51
|
usageLimits: true,
|
|
27
52
|
workspaces: true,
|
|
28
53
|
attachments: true,
|
|
@@ -31,14 +56,70 @@ export const CODEX_AGENT_CAPABILITIES = {
|
|
|
31
56
|
handback: true,
|
|
32
57
|
};
|
|
33
58
|
export const PI_AGENT_CAPABILITIES = {
|
|
34
|
-
launchProfiles:
|
|
59
|
+
launchProfiles: true,
|
|
60
|
+
fastMode: false,
|
|
61
|
+
externalActivity: true,
|
|
62
|
+
cliMirror: true,
|
|
63
|
+
activityLog: true,
|
|
64
|
+
auth: true,
|
|
65
|
+
login: false,
|
|
66
|
+
logout: false,
|
|
67
|
+
usageStats: true,
|
|
68
|
+
subscriptionLimits: false,
|
|
69
|
+
usageLimits: false,
|
|
70
|
+
workspaces: true,
|
|
71
|
+
attachments: true,
|
|
72
|
+
modelSelection: true,
|
|
73
|
+
reasoningSelection: true,
|
|
74
|
+
handback: true,
|
|
75
|
+
};
|
|
76
|
+
export const HERMES_AGENT_CAPABILITIES = {
|
|
77
|
+
launchProfiles: true,
|
|
35
78
|
fastMode: false,
|
|
36
|
-
externalActivity:
|
|
37
|
-
cliMirror:
|
|
38
|
-
activityLog:
|
|
39
|
-
auth:
|
|
79
|
+
externalActivity: true,
|
|
80
|
+
cliMirror: true,
|
|
81
|
+
activityLog: true,
|
|
82
|
+
auth: true,
|
|
83
|
+
login: true,
|
|
84
|
+
logout: true,
|
|
85
|
+
usageStats: true,
|
|
86
|
+
subscriptionLimits: false,
|
|
87
|
+
usageLimits: false,
|
|
88
|
+
workspaces: true,
|
|
89
|
+
attachments: true,
|
|
90
|
+
modelSelection: true,
|
|
91
|
+
reasoningSelection: true,
|
|
92
|
+
handback: true,
|
|
93
|
+
};
|
|
94
|
+
export const OPENCLAW_AGENT_CAPABILITIES = {
|
|
95
|
+
launchProfiles: true,
|
|
96
|
+
fastMode: false,
|
|
97
|
+
externalActivity: true,
|
|
98
|
+
cliMirror: true,
|
|
99
|
+
activityLog: true,
|
|
100
|
+
auth: true,
|
|
40
101
|
login: false,
|
|
41
102
|
logout: false,
|
|
103
|
+
usageStats: true,
|
|
104
|
+
subscriptionLimits: false,
|
|
105
|
+
usageLimits: false,
|
|
106
|
+
workspaces: true,
|
|
107
|
+
attachments: true,
|
|
108
|
+
modelSelection: true,
|
|
109
|
+
reasoningSelection: true,
|
|
110
|
+
handback: true,
|
|
111
|
+
};
|
|
112
|
+
export const CLAUDE_CODE_AGENT_CAPABILITIES = {
|
|
113
|
+
launchProfiles: true,
|
|
114
|
+
fastMode: false,
|
|
115
|
+
externalActivity: true,
|
|
116
|
+
cliMirror: true,
|
|
117
|
+
activityLog: true,
|
|
118
|
+
auth: true,
|
|
119
|
+
login: true,
|
|
120
|
+
logout: true,
|
|
121
|
+
usageStats: true,
|
|
122
|
+
subscriptionLimits: false,
|
|
42
123
|
usageLimits: false,
|
|
43
124
|
workspaces: true,
|
|
44
125
|
attachments: true,
|
|
@@ -47,11 +128,44 @@ export const PI_AGENT_CAPABILITIES = {
|
|
|
47
128
|
handback: true,
|
|
48
129
|
};
|
|
49
130
|
export function isAgentId(value) {
|
|
50
|
-
return value
|
|
131
|
+
return AGENT_IDS.includes(value);
|
|
51
132
|
}
|
|
52
133
|
export function agentLabel(agentId) {
|
|
53
|
-
|
|
134
|
+
if (agentId === "pi") {
|
|
135
|
+
return "Pi";
|
|
136
|
+
}
|
|
137
|
+
if (agentId === "hermes") {
|
|
138
|
+
return "Hermes";
|
|
139
|
+
}
|
|
140
|
+
if (agentId === "openclaw") {
|
|
141
|
+
return "OpenClaw";
|
|
142
|
+
}
|
|
143
|
+
if (agentId === "claude-code") {
|
|
144
|
+
return "Claude Code";
|
|
145
|
+
}
|
|
146
|
+
return "Codex";
|
|
54
147
|
}
|
|
55
148
|
export function agentReasoningLabel(agentId) {
|
|
56
|
-
|
|
149
|
+
if (agentId === "pi" || agentId === "openclaw") {
|
|
150
|
+
return "Thinking";
|
|
151
|
+
}
|
|
152
|
+
if (agentId === "claude-code") {
|
|
153
|
+
return "Effort";
|
|
154
|
+
}
|
|
155
|
+
return "Reasoning";
|
|
156
|
+
}
|
|
157
|
+
export function agentReasoningOptions(agentId) {
|
|
158
|
+
if (agentId === "pi") {
|
|
159
|
+
return PI_THINKING_LEVELS;
|
|
160
|
+
}
|
|
161
|
+
if (agentId === "hermes") {
|
|
162
|
+
return HERMES_REASONING_EFFORTS;
|
|
163
|
+
}
|
|
164
|
+
if (agentId === "openclaw") {
|
|
165
|
+
return OPENCLAW_THINKING_LEVELS;
|
|
166
|
+
}
|
|
167
|
+
if (agentId === "claude-code") {
|
|
168
|
+
return CLAUDE_CODE_EFFORT_LEVELS;
|
|
169
|
+
}
|
|
170
|
+
return CODEX_REASONING_EFFORTS;
|
|
57
171
|
}
|
package/dist/artifacts.js
CHANGED
|
@@ -178,7 +178,7 @@ export async function createArtifactZipBundle(artifacts, outDir, options = {}) {
|
|
|
178
178
|
}
|
|
179
179
|
const bundleDir = path.join(outDir, ".telegram-artifacts");
|
|
180
180
|
await mkdir(bundleDir, { recursive: true });
|
|
181
|
-
const bundleName = options.bundleName ?? `
|
|
181
|
+
const bundleName = options.bundleName ?? `nordrelay-artifacts-${sanitizeZipStem(path.basename(path.dirname(outDir)))}.zip`;
|
|
182
182
|
const bundlePath = path.join(bundleDir, bundleName);
|
|
183
183
|
await rm(bundlePath, { force: true }).catch(() => { });
|
|
184
184
|
try {
|
package/dist/audit-log.js
CHANGED
|
@@ -17,8 +17,8 @@ export class AuditLogStore {
|
|
|
17
17
|
const next = {
|
|
18
18
|
id: randomUUID().replace(/-/g, "").slice(0, 12),
|
|
19
19
|
timestamp: new Date().toISOString(),
|
|
20
|
-
channelId: "telegram",
|
|
21
20
|
...event,
|
|
21
|
+
channelId: event.channelId ?? "telegram",
|
|
22
22
|
};
|
|
23
23
|
payload.events.push(next);
|
|
24
24
|
if (payload.events.length > this.maxEvents) {
|
package/dist/bot-ui.js
CHANGED
|
@@ -8,7 +8,7 @@ export function renderHelpMessage() {
|
|
|
8
8
|
title: "💬 Session",
|
|
9
9
|
commands: [
|
|
10
10
|
["/new", "Start a new thread"],
|
|
11
|
-
["/agent", "Select
|
|
11
|
+
["/agent", "Select agent"],
|
|
12
12
|
["/session", "Current thread details"],
|
|
13
13
|
["/sessions", "Browse & switch threads"],
|
|
14
14
|
["/sync", "Sync active sessions from CLI state"],
|