@nordbyte/nordrelay 0.5.0 → 0.5.2

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.
Files changed (44) hide show
  1. package/.env.example +2 -0
  2. package/README.md +23 -14
  3. package/dist/access-control.js +2 -0
  4. package/dist/agent-updates.js +61 -10
  5. package/dist/bot-ui.js +1 -0
  6. package/dist/bot.js +142 -1065
  7. package/dist/channel-actions.js +8 -8
  8. package/dist/codex-cli.js +1 -1
  9. package/dist/config-metadata.js +2 -0
  10. package/dist/operations.js +233 -122
  11. package/dist/relay-artifact-service.js +126 -0
  12. package/dist/relay-external-activity-monitor.js +216 -0
  13. package/dist/relay-queue-service.js +66 -0
  14. package/dist/relay-runtime-types.js +1 -0
  15. package/dist/relay-runtime.js +119 -371
  16. package/dist/state-backend.js +3 -0
  17. package/dist/support-bundle.js +221 -0
  18. package/dist/telegram-agent-commands.js +212 -0
  19. package/dist/telegram-artifact-commands.js +139 -0
  20. package/dist/telegram-command-menu.js +1 -0
  21. package/dist/telegram-command-types.js +1 -0
  22. package/dist/telegram-diagnostics-command.js +102 -0
  23. package/dist/telegram-general-commands.js +52 -0
  24. package/dist/telegram-operational-commands.js +153 -0
  25. package/dist/telegram-preference-commands.js +198 -0
  26. package/dist/telegram-queue-commands.js +278 -0
  27. package/dist/telegram-support-command.js +53 -0
  28. package/dist/telegram-update-commands.js +6 -1
  29. package/dist/web-api-contract.js +79 -31
  30. package/dist/web-api-types.js +1 -0
  31. package/dist/web-dashboard-access-routes.js +163 -0
  32. package/dist/web-dashboard-artifact-routes.js +65 -0
  33. package/dist/web-dashboard-assets.js +2 -0
  34. package/dist/web-dashboard-http.js +143 -0
  35. package/dist/web-dashboard-pages.js +257 -0
  36. package/dist/web-dashboard-runtime-routes.js +92 -0
  37. package/dist/web-dashboard-session-routes.js +209 -0
  38. package/dist/web-dashboard.js +44 -882
  39. package/dist/webui-assets/dashboard.css +74 -4
  40. package/dist/webui-assets/dashboard.js +163 -24
  41. package/dist/zip-writer.js +83 -0
  42. package/package.json +10 -4
  43. package/plugins/nordrelay/.codex-plugin/plugin.json +1 -1
  44. package/plugins/nordrelay/scripts/nordrelay.mjs +258 -5
package/.env.example CHANGED
@@ -209,6 +209,8 @@ NORDRELAY_AUDIT_MAX_EVENTS=1000
209
209
  NORDRELAY_SESSION_LOCK_TTL_MS=1800000
210
210
  # NPM version cache TTL.
211
211
  NORDRELAY_VERSION_CACHE_TTL_MS=3600000
212
+ # Installed agent CLI version cache TTL.
213
+ NORDRELAY_CLI_VERSION_CACHE_TTL_MS=60000
212
214
 
213
215
  # Voice
214
216
  # Optional voice transcription settings.
package/README.md CHANGED
@@ -37,6 +37,7 @@ Session control:
37
37
  - `/tasks` and `/progress` show the current turn status, queue length, active tool, elapsed time, and last error.
38
38
  - `/activity` shows a compact timeline of recent rollout events for the active thread, with filters and export.
39
39
  - `/diagnostics` reports redacted runtime, config, user/group authorization, Telegram rate-limit, mirror, voice, session, queue, and progress details.
40
+ - `/support` exports a redacted diagnostics ZIP with config, health, versions, agent paths, recent logs, audit events, update jobs, state backend, and OS/Node/npm info.
40
41
  - `/lock`, `/unlock`, and `/locks` provide a team write-lock for shared sessions so one user can operate while others watch.
41
42
  - `/audit` shows recent prompt, queue, lock, command, authentication, permission-denied, user, group, Telegram-link, Telegram-chat, and web-session audit events for admins.
42
43
 
@@ -182,10 +183,10 @@ Authentication and safety:
182
183
  Operations:
183
184
 
184
185
  - Plugin command/skill starts, stops, restarts, and inspects the connector process.
185
- - Manual process commands support `start`, `stop`, `restart`, `status`, and `foreground`.
186
- - Telegram admin commands support `/logs`, `/diagnostics`, `/restart`, and `/update` for NordRelay and agent CLIs.
187
- - `/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.
188
- - `/update agents`, `/update <agent>`, `/update jobs`, `/update log <id>`, `/update cancel <id>`, and `/update input <id> <text>` manage Codex, Pi, Hermes, OpenClaw, and Claude Code updater jobs from Telegram.
186
+ - Manual process commands support `start`, `stop`, `restart`, `status`, `update`, and `foreground`.
187
+ - Telegram admin commands support `/logs`, `/diagnostics`, `/support`, `/restart`, and `/update` for NordRelay and agent CLIs.
188
+ - `nordrelay update`, `/update`, and the WebUI update button detect 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 if the connector is running.
189
+ - `/update agents`, `/update <agent>`, `/update install <agent>`, `/update jobs`, `/update log <id>`, `/update cancel <id>`, and `/update input <id> <text>` manage Codex, Pi, Hermes, OpenClaw, and Claude Code updater or installer jobs from Telegram.
189
190
  - `/logs` renders redacted connector, NordRelay update, and agent update logs with local-time timestamps, levels, file path, last-modified time, and highlighted warnings/errors.
190
191
  - Logs can be emitted as timestamped plain text or JSON records with `CONNECTOR_LOG_FORMAT`.
191
192
  - Telegram sends/edits/documents are routed through a rate-limit queue that honors Telegram retry-after responses.
@@ -195,12 +196,12 @@ Operations:
195
196
  - `nordrelay init` creates a private runtime config, `nordrelay doctor` validates host prerequisites, and `nordrelay web` starts the connector plus a full local WebUI dashboard.
196
197
  - The WebUI has responsive header/sidebar/footer navigation, live chat streaming, session controls, queue/artifact/log/diagnostic views, and settings management.
197
198
  - The WebUI supports light and dark themes, tabbed settings groups, paginated session browsing, and chat uploads for images, documents, and audio transcription.
198
- - The WebUI exposes REST and SSE endpoints for chat streaming, sessions, settings, queue, artifacts, logs, health, and diagnostics.
199
+ - The WebUI exposes REST and SSE endpoints for chat streaming, sessions, settings, queue, artifacts, logs, health, diagnostics, and redacted diagnostics bundle export.
199
200
  - The dashboard can bind to `127.0.0.1` or `0.0.0.0`; user login and session cookies are mandatory in both modes.
200
201
  - Telegram can run with long polling or an HTTP webhook via `TELEGRAM_TRANSPORT=webhook`.
201
- - Version freshness checks are cached with `NORDRELAY_VERSION_CACHE_TTL_MS` to keep `/version` responsive.
202
- - CI includes typecheck, tests, package dry run, npm audit, and a separate secret-scan workflow.
203
- - `npm run dev`, `npm run build`, `npm run check`, `npm test`, `npm start`, `npm stop`, and `npm run status` are available.
202
+ - Version freshness checks are cached with `NORDRELAY_VERSION_CACHE_TTL_MS`, and installed agent CLI version checks are cached with `NORDRELAY_CLI_VERSION_CACHE_TTL_MS`, to keep `/version` and adapter health responsive.
203
+ - CI runs on Ubuntu, Windows, and macOS with typecheck, Vitest, Playwright WebUI browser tests, package dry run, npm audit, and a separate secret-scan workflow.
204
+ - `npm run dev`, `npm run build`, `npm run check`, `npm test`, `npm run test:e2e`, `npm start`, `npm stop`, and `npm run status` are available.
204
205
  - Dockerfile and `docker-compose.yml` are included for containerized operation.
205
206
  - A `launchd/start.sh` helper is included for host-managed startup.
206
207
 
@@ -355,6 +356,7 @@ nordrelay init
355
356
  nordrelay doctor
356
357
  nordrelay start
357
358
  nordrelay status
359
+ nordrelay update
358
360
  nordrelay restart
359
361
  nordrelay stop
360
362
  nordrelay foreground
@@ -366,6 +368,7 @@ Source checkout process commands:
366
368
  ```bash
367
369
  node plugins/nordrelay/scripts/nordrelay.mjs start
368
370
  node plugins/nordrelay/scripts/nordrelay.mjs status
371
+ node plugins/nordrelay/scripts/nordrelay.mjs update
369
372
  node plugins/nordrelay/scripts/nordrelay.mjs restart
370
373
  node plugins/nordrelay/scripts/nordrelay.mjs stop
371
374
  node plugins/nordrelay/scripts/nordrelay.mjs foreground
@@ -424,7 +427,7 @@ The dashboard is a second NordRelay client next to Telegram. It can:
424
427
  - Edit all supported runtime settings from tabbed Settings groups with option selects, validation feedback, and restart actions.
425
428
  - View filtered connector/update/agent-update logs, structured diagnostics, enabled channels, and agent adapters.
426
429
  - Inspect a per-agent capability matrix showing model, reasoning, launch, fast mode, attachments, activity, usage, auth, login/logout, and handback support.
427
- - Check NordRelay and agent CLI versions, then start Codex, Pi, Hermes, OpenClaw, or Claude Code updates from outdated version rows with live output, cancel, delete-log, and stdin response controls for interactive updaters.
430
+ - Check NordRelay and agent CLI versions, then start Codex, Pi, Hermes, OpenClaw, or Claude Code updates from outdated rows or installs from not-installed rows with live output, cancel, delete-log, and stdin response controls.
428
431
  - Build dashboard CSS and client JavaScript from modular source assets through esbuild, then serve them as authenticated static assets instead of inline HTML.
429
432
 
430
433
  Dashboard API endpoints are served under `/api/*`. Streaming uses `GET /api/events`.
@@ -515,10 +518,11 @@ Run NordRelay behind your reverse proxy so the public URL forwards to `http://12
515
518
  - `/logs update [lines]` shows the self-update log. Requires `logs.read`.
516
519
  - `/logs agent [lines]` shows the aggregate agent updater log. Requires `logs.read`.
517
520
  - `/logs all [lines]` shows connector, self-update, and agent update logs together. Requires `logs.read`.
518
- - `/diagnostics` shows redacted connector diagnostics. Requires `logs.read`.
521
+ - `/diagnostics` shows redacted connector diagnostics. Requires `diagnostics.read`.
522
+ - `/support` exports a redacted diagnostics ZIP. Requires `diagnostics.read`.
519
523
  - `/restart` restarts the connector process. Requires `system.restart`.
520
524
  - `/update` updates through npm or git depending on the detected install type, then restarts only on success. Requires `updates.run`.
521
- - `/update agents`, `/update <agent>`, `/update jobs`, `/update log <id>`, `/update cancel <id>`, and `/update input <id> <text>` manage agent CLI update jobs. Requires `updates.run`.
525
+ - `/update agents`, `/update <agent>`, `/update install <agent>`, `/update jobs`, `/update log <id>`, `/update cancel <id>`, and `/update input <id> <text>` manage agent CLI update and install jobs. Requires `updates.run`.
522
526
 
523
527
  ## Command Examples
524
528
 
@@ -735,6 +739,7 @@ Agent selection:
735
739
  - `NORDRELAY_AUDIT_MAX_EVENTS`: maximum audit events retained. Defaults to `1000`.
736
740
  - `NORDRELAY_SESSION_LOCK_TTL_MS`: session write-lock TTL. Defaults to `1800000`.
737
741
  - `NORDRELAY_VERSION_CACHE_TTL_MS`: npm version freshness cache TTL. Defaults to `3600000`; set `0` to disable.
742
+ - `NORDRELAY_CLI_VERSION_CACHE_TTL_MS`: installed agent CLI version cache TTL. Defaults to `60000`; set `0` to disable.
738
743
 
739
744
  Dashboard:
740
745
 
@@ -835,8 +840,8 @@ NordRelay wrapper:
835
840
 
836
841
  - `NORDRELAY_HOME`: config/state/log directory override. Defaults to `~/.nordrelay`.
837
842
  - `NORDRELAY_SOURCE_ROOT`: runtime source root override. Useful when the plugin is launched from Codex cache.
838
- - `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.
839
- - Agent updates from the dashboard and Telegram use each agent's native updater where possible: `codex update`, `pi update pi`, `hermes update --yes`, `openclaw update --yes`, and `claude update`.
843
+ - `NORDRELAY_UPDATE_METHOD`: optional `auto`, `npm`, or `git` self-update method override used by `nordrelay update`, `/update`, and the WebUI update button. Auto uses git when the runtime root has a `.git` directory and npm otherwise.
844
+ - Agent updates from the dashboard and Telegram use each agent's native updater where possible: `codex update`, `pi update pi`, `hermes update --yes`, `openclaw update --yes`, and `claude update`. Not-installed agents can be installed from the dashboard or with `/update install <agent>` using npm global installs.
840
845
  - `NORDRELAY_KEEP_PENDING_UPDATES`: set true to avoid dropping pending Telegram updates on start.
841
846
  - `NORDRELAY_FORWARD_TOOL_OUTPUT`: backward-compatible alias that sets `TOOL_VERBOSITY=all` when `TOOL_VERBOSITY` is unset.
842
847
  - `NORDRELAY_STATE_FILE`: internal state-file path passed by the wrapper.
@@ -1041,9 +1046,13 @@ npm run build
1041
1046
  - `plugins/nordrelay/scripts/nordrelay.mjs`: process manager for `start`, `stop`, `restart`, `status`, and `foreground`.
1042
1047
  - `src/index.ts`: runtime entrypoint, config load, auth check, state-file writes, polling lifecycle, shutdown.
1043
1048
  - `src/bot.ts`: Telegram prompt/session runtime, streaming, file/photo/voice handling, artifacts, and error handling.
1044
- - `src/telegram-access-commands.ts`, `src/telegram-update-commands.ts`, and `src/telegram-command-menu.ts`: focused Telegram command groups for access linking, update jobs, and command menu registration.
1049
+ - `src/telegram-general-commands.ts`, `src/telegram-agent-commands.ts`, `src/telegram-preference-commands.ts`, `src/telegram-access-commands.ts`, `src/telegram-diagnostics-command.ts`, `src/telegram-update-commands.ts`, `src/telegram-support-command.ts`, and `src/telegram-command-menu.ts`: focused Telegram command groups for start/help/adapters, agent/auth controls, per-chat preferences, access linking, diagnostics/log/version commands, update jobs, diagnostics bundle export, and command menu registration.
1045
1050
  - `src/channel-adapter.ts`, `src/channel-runtime.ts`, and `src/channel-actions.ts`: channel descriptors, generic command routing, outbound delivery contracts, and channel-neutral command responses.
1046
1051
  - `src/config-metadata.ts`: shared setting metadata used by the WebUI settings page and generated `.env.example`.
1052
+ - `src/support-bundle.ts` and `src/zip-writer.ts`: redacted diagnostics bundle creation with a dependency-free ZIP writer.
1053
+ - `src/relay-queue-service.ts`, `src/relay-artifact-service.ts`, and `src/relay-external-activity-monitor.ts`: Web runtime queue operations, artifact preview/export/persistence, and external CLI activity mirroring.
1054
+ - `src/relay-runtime-types.ts`: shared Runtime/WebUI DTO types used by runtime, API contracts, and dashboard code.
1055
+ - `src/web-dashboard-http.ts`, `src/web-dashboard-pages.ts`, and `src/web-dashboard-runtime-routes.ts`: dashboard HTTP helpers, HTML shell rendering, and operational runtime API routes.
1047
1056
  - `src/webui/`: focused WebUI source assets for core runtime state/API helpers, overview rendering, live events, chat/session workflows, admin pages, and CSS sections.
1048
1057
  - `src/bot-preferences.ts`: per-context mirror, notification, quiet-hour, and voice preference persistence.
1049
1058
  - `src/telegram-rate-limit.ts`: centralized Telegram API send/edit/document rate limiting and retry-after tracking.
@@ -79,6 +79,8 @@ const COMMAND_PERMISSIONS = new Map([
79
79
  ["voice", "inspect"],
80
80
  ["whoami", "inspect"],
81
81
  ["diagnostics", "diagnostics.read"],
82
+ ["support", "diagnostics.read"],
83
+ ["diagnostics_bundle", "diagnostics.read"],
82
84
  ["logs", "logs.read"],
83
85
  ["audit", "audit.read"],
84
86
  ["restart", "system.restart"],
@@ -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();
@@ -58,12 +65,12 @@ export class AgentUpdateManager {
58
65
  this.persistJobs();
59
66
  return snapshot;
60
67
  }
61
- start(agentId, context = {}) {
68
+ start(agentId, context = {}, operation = "update") {
62
69
  const running = [...this.jobs.values()].find((job) => job.agentId === agentId && job.status === "running");
63
70
  if (running) {
64
- throw new Error(`${agentLabel(agentId)} update is already running.`);
71
+ throw new Error(`${agentLabel(agentId)} update/install job is already running.`);
65
72
  }
66
- const plan = resolveAgentUpdatePlan(agentId, { ...context, env: context.env ?? this.options.env });
73
+ const plan = resolveAgentUpdatePlan(agentId, { ...context, env: context.env ?? this.options.env }, operation);
67
74
  const now = new Date().toISOString();
68
75
  const id = `${agentId.replace(/[^a-z0-9]/gi, "")}-${Date.now().toString(36)}`;
69
76
  const logPath = path.join(this.home, "updates", `${id}.log`);
@@ -72,6 +79,7 @@ export class AgentUpdateManager {
72
79
  id,
73
80
  agentId,
74
81
  agentLabel: plan.agentLabel,
82
+ operation,
75
83
  status: "running",
76
84
  method: plan.method,
77
85
  command: plan.command,
@@ -91,16 +99,17 @@ export class AgentUpdateManager {
91
99
  this.jobs.set(id, job);
92
100
  this.persistJobs();
93
101
  this.append(job, [
94
- `[${now}] Starting ${job.agentLabel} update`,
102
+ `[${now}] Starting ${job.agentLabel} ${job.operation}`,
95
103
  `Method: ${job.method}`,
96
104
  `Command: ${[job.command, ...job.args].join(" ")}`,
97
105
  `Working directory: ${job.cwd}`,
98
106
  "",
99
107
  ].join("\n"));
100
- const child = spawn(plan.command, plan.args, {
108
+ const useShell = process.platform === "win32";
109
+ const child = spawn(useShell ? formatShellCommand(plan.command, plan.args) : plan.command, useShell ? [] : plan.args, {
101
110
  cwd: plan.cwd,
102
111
  env: { ...process.env, ...(this.options.env ?? {}), ...(context.env ?? {}) },
103
- shell: process.platform === "win32",
112
+ shell: useShell,
104
113
  windowsHide: true,
105
114
  stdio: "pipe",
106
115
  });
@@ -115,7 +124,7 @@ export class AgentUpdateManager {
115
124
  if (job.status !== "running") {
116
125
  return;
117
126
  }
118
- this.finish(job, code === 0 ? "completed" : "failed", code, signal, code === 0 ? undefined : `Update exited with code ${code ?? "unknown"}`);
127
+ this.finish(job, code === 0 ? "completed" : "failed", code, signal, code === 0 ? undefined : `${capitalize(job.operation)} exited with code ${code ?? "unknown"}`);
119
128
  });
120
129
  this.emit(job);
121
130
  return this.snapshot(job);
@@ -178,7 +187,7 @@ export class AgentUpdateManager {
178
187
  job.finishedAt = new Date().toISOString();
179
188
  job.updatedAt = job.finishedAt;
180
189
  job.child = undefined;
181
- this.append(job, `\n[${job.finishedAt}] ${job.agentLabel} update ${status}${error ? `: ${job.error}` : ""}\n`);
190
+ this.append(job, `\n[${job.finishedAt}] ${job.agentLabel} ${job.operation} ${status}${error ? `: ${job.error}` : ""}\n`);
182
191
  }
183
192
  emit(job) {
184
193
  this.options.onUpdate?.(this.snapshot(job));
@@ -205,6 +214,7 @@ export class AgentUpdateManager {
205
214
  }
206
215
  const job = {
207
216
  ...snapshot,
217
+ operation: snapshot.operation ?? "update",
208
218
  status: staleRunning ? "failed" : snapshot.status,
209
219
  canInput: false,
210
220
  needsInput: false,
@@ -254,7 +264,10 @@ function isProcessRunning(pid) {
254
264
  return false;
255
265
  }
256
266
  }
257
- export function resolveAgentUpdatePlan(agentId, context = {}) {
267
+ export function resolveAgentUpdatePlan(agentId, context = {}, operation = "update") {
268
+ if (operation === "install") {
269
+ return resolveAgentInstallPlan(agentId, context);
270
+ }
258
271
  const env = context.env ?? process.env;
259
272
  switch (agentId) {
260
273
  case "codex": {
@@ -294,10 +307,30 @@ export function resolveAgentUpdatePlan(agentId, context = {}) {
294
307
  }
295
308
  }
296
309
  }
310
+ function resolveAgentInstallPlan(agentId, context = {}) {
311
+ const env = context.env ?? process.env;
312
+ const npm = resolveNpmSpawnCommand(env);
313
+ if (!npm) {
314
+ throw new Error(`Cannot install ${agentLabel(agentId)} because npm was not found on PATH.`);
315
+ }
316
+ const packageName = AGENT_INSTALL_PACKAGES[agentId];
317
+ return {
318
+ agentId,
319
+ agentLabel: agentLabel(agentId),
320
+ operation: "install",
321
+ method: `npm install -g ${packageName}@latest`,
322
+ command: npm.command,
323
+ args: [...npm.argsPrefix, "install", "-g", `${packageName}@latest`],
324
+ cwd: env.HOME || os.homedir(),
325
+ summary: `Installs the latest ${agentLabel(agentId)} CLI with npm. Restart NordRelay after installation if the agent was previously unavailable.`,
326
+ interactive: true,
327
+ };
328
+ }
297
329
  function plan(agentId, method, command, args, summary, env) {
298
330
  return {
299
331
  agentId,
300
332
  agentLabel: agentLabel(agentId),
333
+ operation: "update",
301
334
  method,
302
335
  command,
303
336
  args,
@@ -310,3 +343,21 @@ function looksLikePrompt(text) {
310
343
  const tail = text.split(/\r?\n/).slice(-4).join("\n");
311
344
  return /\b(y\/n|yes\/no|continue|proceed|confirm|password|passphrase|token|api key|enter|select)\b|[?>]\s*$/i.test(tail);
312
345
  }
346
+ function formatShellCommand(command, args) {
347
+ return [command, ...args].map(quoteWindowsCmdArg).join(" ");
348
+ }
349
+ function quoteWindowsCmdArg(value) {
350
+ if (value.length === 0) {
351
+ return "\"\"";
352
+ }
353
+ if (!/[\s"&|<>()^%]/.test(value)) {
354
+ return value;
355
+ }
356
+ return `"${value
357
+ .replace(/%/g, "%%")
358
+ .replace(/(\\*)"/g, '$1$1\\"')
359
+ .replace(/(\\+)$/g, "$1$1")}"`;
360
+ }
361
+ function capitalize(value) {
362
+ return value.charAt(0).toUpperCase() + value.slice(1);
363
+ }
package/dist/bot-ui.js CHANGED
@@ -67,6 +67,7 @@ export function renderHelpMessage() {
67
67
  commands: [
68
68
  ["/logs", "Show connector log tail"],
69
69
  ["/diagnostics", "Connector diagnostics"],
70
+ ["/support", "Export diagnostics bundle"],
70
71
  ["/lock", "Lock session writes to you"],
71
72
  ["/unlock", "Release session write lock"],
72
73
  ["/locks", "List active write locks"],