@turmind/halo 2.0.8 → 2.1.0

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 (37) hide show
  1. package/admin-out/404.html +1 -1
  2. package/admin-out/_next/static/chunks/{241-75bac3bb8e7aca1b.js → 398-9a8be186767b4504.js} +1 -1
  3. package/admin-out/_next/static/chunks/989-04766caa08c5f506.js +1 -0
  4. package/admin-out/_next/static/chunks/app/page-ee1d0dae346ba9d2.js +1 -0
  5. package/admin-out/_next/static/css/e395d2ae2e0636a0.css +1 -0
  6. package/admin-out/index.html +1 -1
  7. package/admin-out/index.txt +5 -5
  8. package/bundled-docs/design/architecture.md +3 -1
  9. package/bundled-docs/design/canvas-extensions.md +1 -1
  10. package/bundled-docs/design/node.md +98 -0
  11. package/bundled-docs/design/prompt-system.md +2 -0
  12. package/bundled-docs/design/storage.md +3 -3
  13. package/bundled-docs/design/ws.md +1 -0
  14. package/bundled-docs/dev/api.md +21 -0
  15. package/bundled-docs/dev/env.md +1 -0
  16. package/bundled-docs/dev/tools.md +58 -1
  17. package/bundled-docs/guide/README.md +4 -0
  18. package/bundled-docs/guide/agents.md +1 -1
  19. package/bundled-docs/guide/cli.md +23 -0
  20. package/bundled-docs/guide/delegation-and-access.md +2 -2
  21. package/bundled-docs/guide/node.md +86 -0
  22. package/bundled-docs/requirements/agent.md +1 -1
  23. package/bundled-docs/requirements/workspace.md +2 -0
  24. package/dist/evo-wrapper.js +3 -0
  25. package/dist/index.js +1829 -734
  26. package/package.json +1 -1
  27. package/templates/agents/default/agent.yaml +2 -0
  28. package/templates/models/aws-bedrock-mantle.yaml +44 -4
  29. package/templates/models/aws-bedrock-openai.yaml +44 -4
  30. package/templates/models/doubao.yaml +97 -7
  31. package/templates/models/kimi.yaml +41 -3
  32. package/templates/models/minimax.yaml +35 -4
  33. package/admin-out/_next/static/chunks/989-af7e27a2004069ac.js +0 -1
  34. package/admin-out/_next/static/chunks/app/page-2af2482b39d6ec64.js +0 -1
  35. package/admin-out/_next/static/css/2e6b00182ac44ae1.css +0 -1
  36. /package/admin-out/_next/static/{pBIsb2BS3McG20ieKaTDx → a5z_n1eIm6T8T3Ty_MMHF}/_buildManifest.js +0 -0
  37. /package/admin-out/_next/static/{pBIsb2BS3McG20ieKaTDx → a5z_n1eIm6T8T3Ty_MMHF}/_ssgManifest.js +0 -0
@@ -535,6 +535,63 @@ The remotes configured on this server (the same list in every workspace) — eac
535
535
 
536
536
  Returns `{ "code": 0, "remotes": [{ name, agent, description, skills }], "pending": [{ remote, context_id, task_id, since }] }`.
537
537
 
538
+ ## Node tools
539
+
540
+ File: `packages/server/src/nodes/tools.ts` (`buildNodeTools`). Design notes in [design/node.md](../design/node.md); user guide [guide/node.md](../guide/node.md).
541
+
542
+ Act on the user's **linked machines** — computers running `halo node`, paired with this workspace in Admin → Channels → Linked machines. Each node tool mirrors one local workspace tool and runs **that same tool** on the machine (same arguments, same output), plus a required `node` argument naming the machine:
543
+
544
+ | Tool | Mirrors | Extra / different args |
545
+ |---|---|---|
546
+ | `node_list` | — | none |
547
+ | `node_read` | `file_read` | `node` |
548
+ | `node_write` | `file_write` | `node` |
549
+ | `node_edit` | `file_edit` | `node` |
550
+ | `node_list_dir` | `file_list` | `node` |
551
+ | `node_grep` | `grep` | `node` |
552
+ | `node_glob` | `glob` | `node` |
553
+ | `node_run` | `shell_exec` | `node`, `command`, `cwd` (default: the machine's folder) |
554
+
555
+ **Enabling**: opt-in by the single name `node_list` in `agent.yaml`'s `tools:` — it brings all eight; the other seven names are not recognised on their own. **Full-access sessions only** (`accessLevel === null`). The bundled `default` agent lists it. The admin tool picker shows one `node_list` chip naming the set. Names, descriptions and schemas are constants — which machines are online never changes the tool list or the system prompt (prompt-cache invariant); online state is only in `node_list`'s result.
556
+
557
+ **Paths**: a machine shares one folder (`--root`; `root` in `node_list`) — relative paths resolve against it, paths that resolve outside it (symlinks included) are refused: `"<p>" is outside this machine's shared folder (<root>) — node tools can only reach paths inside it`. A whole-machine node (`root: null, wholeMachine: true`) has no such check; relative paths resolve against its `base`.
558
+
559
+ **Runtime**: in `halo server` calls go over the machine's WebSocket; cron runs (a `halo cli` child) reach it through the server's loopback relay. In the standalone CLI / TUI, the evo sandbox and AgentCore mode the tools are listed but every one — `node_list` included — returns `linked machines are not available in this runtime — only \`halo server\` accepts \`halo node\` connections. This is permanent for this runtime, not a temporary outage: do not retry. …`.
560
+
561
+ **Errors** (returned as the tool error text):
562
+
563
+ | Case | Message |
564
+ |---|---|
565
+ | Machine linked but not connected | `machine "<n>" is offline (\`halo node\` is not connected). Do not retry in a loop — tell the user to start it.` |
566
+ | Name not linked to this workspace | `unknown machine "<n>" — machines linked to this workspace: <a, b \| (none)> (see node_list)` |
567
+ | Link dropped mid-call | `machine "<n>" went offline during the call (connection lost). The operation may or may not have completed on the machine — check its state before retrying.` |
568
+ | No answer in time (120 s; node_run: shell timeout + 15 s) | `machine "<n>" did not answer within <s>s — the call was cancelled; it may or may not have taken effect.` |
569
+ | node_run without `--allow-shell` | `node_run is disabled on this machine — the user must restart \`halo node\` with --allow-shell to allow commands` |
570
+ | Request over 8 MB | `request too large to send to the machine (<x> MB > 8 MB limit)` |
571
+
572
+ Results over 256K chars are cut on the machine (`[Content truncated on the machine: N chars total]`); the usual tool-result budget then applies.
573
+
574
+ ### node_list
575
+
576
+ The machines linked to this workspace and whether each is online. No arguments. Its description doubles as the usage note for the whole set.
577
+
578
+ Returns `{ "code": 0, "nodes": [...] }`, one entry per linked machine:
579
+
580
+ - offline: `{ "name": "nas", "online": false }`
581
+ - online: `{ "name": "mbp", "online": true, "root": "/Users/a/proj", "shell": true, "shellTimeoutSec": 120, "os": "darwin", "since": "<ISO>" }` — whole-machine: `"root": null, "wholeMachine": true, "base": "<start dir>"`; `shellTimeoutSec` only when `shell` is true.
582
+
583
+ No machines at all → `"nodes": []` plus `"hint": "No machines linked — create a token in Admin → Channels → Linked machines, then run \`halo node\` on the machine."`.
584
+
585
+ ### node_run
586
+
587
+ `shell_exec` on the machine; needs `shell: true` in `node_list`. Runs unsandboxed as the machine's user in `cwd` (default: its folder; in folder mode `cwd` must stay inside it, the command itself is not confined). Killed after `shellTimeoutSec`; output capped like `shell_exec` (~8000 chars to the model) — redirect large output to a file, start long jobs with `nohup … &`. `{{ns.params.x}}` placeholders are not substituted.
588
+
589
+ | Arg | Type | Required | Description |
590
+ |---|---|---|---|
591
+ | `node` | string | yes | Machine name from `node_list` |
592
+ | `command` | string | yes | Shell command |
593
+ | `cwd` | string | no | Directory to run in, like `path` (default: the machine's folder) |
594
+
538
595
  ## Tool assignment
539
596
 
540
597
  Workspace tools are enabled strictly by name in `agent.yaml`'s `tools` list:
@@ -547,7 +604,7 @@ skills:
547
604
  - code-review # auto-injects activate_skill
548
605
  ```
549
606
 
550
- Tools not listed are not injected. Session/delegation tools do **not** go in `tools:` — they ride on a non-empty `team` (see [Session tools](#session-tools) above). `activate_skill` is auto-injected whenever the YAML lists `skills` (no need to put it in `tools`), and `continue_task` is auto-injected for **every** agent unconditionally (see [continue_task](#continue_task)). The relay and A2A sets are the two name-gated bundles: listing `relay_send` alone brings `relay_interrupt` / `relay_stop` / `relay_read` / `relay_list` with it, full-access sessions only (see [Relay tools](#relay-tools)); listing `a2a_send` alone brings `a2a_stop` / `a2a_read` / `a2a_list`, at every access level except the A2A read-only profile (see [A2A tools](#a2a-tools)).
607
+ Tools not listed are not injected. Session/delegation tools do **not** go in `tools:` — they ride on a non-empty `team` (see [Session tools](#session-tools) above). `activate_skill` is auto-injected whenever the YAML lists `skills` (no need to put it in `tools`), and `continue_task` is auto-injected for **every** agent unconditionally (see [continue_task](#continue_task)). The relay, A2A and node sets are the three name-gated bundles: listing `relay_send` alone brings `relay_interrupt` / `relay_stop` / `relay_read` / `relay_list` with it, full-access sessions only (see [Relay tools](#relay-tools)); listing `a2a_send` alone brings `a2a_stop` / `a2a_read` / `a2a_list`, at every access level except the A2A read-only profile (see [A2A tools](#a2a-tools)); listing `node_list` alone brings the other seven `node_*` tools, full-access sessions only (see [Node tools](#node-tools)).
551
608
 
552
609
  There is **no implicit default tool set**: `filterTools()` (in `agent-loader.ts`) returns only the tools whose names appear in `agent.yaml`'s `tools:` list. If the field is absent or empty, the agent has zero workspace tools. The admin UI's "Create agent" form scaffolds a fresh agent with an empty `tools: []` for the same reason — fill it in deliberately. The `default` agent's bundled `agent.yaml` lists the common set (`file_read` / `file_write` / `file_edit` / `view_image` / `file_list` / `shell_exec` / `grep` / `glob` / `web_fetch`) that most agents will want; copy that line if you're starting from scratch.
553
610
 
@@ -24,6 +24,10 @@ Aimed at Halo end-users. Pick the doc that matches your situation.
24
24
  - [WeChat](channels/wechat.md) — QR-scan iLink bot
25
25
  - [ACP](channels/acp.md) — Zed / JetBrains or other ACP clients driving a remote halo
26
26
 
27
+ ## Linked machines
28
+
29
+ [node.md](node.md) — run `halo node` on your own computer so a workspace's agents can work on files there.
30
+
27
31
  ## Related docs
28
32
 
29
33
  - Development: [dev/](../dev/) — environment, API, tool reference
@@ -69,7 +69,7 @@ team: # a non-empty team is what enables delegation
69
69
  - executor # the agent ids this one may spawn
70
70
  ```
71
71
 
72
- **Workspace tools**: `file_read / view_image / file_write / file_edit / file_list / shell_exec / grep / glob / web_fetch` — listed by name under `tools`.
72
+ **Workspace tools**: `file_read / view_image / file_write / file_edit / file_list / shell_exec / grep / glob / web_fetch` — listed by name under `tools`. `node_list` switches on the eight `node_*` tools for [linked machines](node.md) as one set (full-access sessions only).
73
73
 
74
74
  **Session tools**: `start_session / session_list / query_session / interrupt_session / stop_session / archive_session / get_session_output / query_agent` — **not** listed under `tools`. The whole bundle is granted automatically the moment an agent declares a non-empty `team`; an empty/absent `team` means no delegation (no session tools, no roster). To let a sub-agent delegate further, give it its own `team`. Add the agent's own id to its `team` to enable parallel self-spawn.
75
75
 
@@ -308,6 +308,29 @@ the caller-side `auth: sigv4` remote, session dirs and ops notes:
308
308
  [design/agentcore.md](../design/agentcore.md). The hub skill `agentcore-deploy`
309
309
  builds the image and creates the runtime for you.
310
310
 
311
+ ## Linked machine (`halo node`)
312
+
313
+ ```bash
314
+ HALO_NODE_TOKEN=<token> halo node --server https://halo.example.com --root ~/proj [--allow-shell]
315
+ ```
316
+
317
+ Links this machine to a workspace on a halo server, so that workspace's
318
+ full-access agents can work on files here with the `node_*` tools. Runs in the
319
+ foreground, reconnects on its own, Ctrl-C to stop. Needs no `halo setup` and
320
+ no model keys — nothing is written under `~/.halo/`. Create the token in
321
+ Admin → Channels → Linked machines.
322
+
323
+ | Flag / env | Meaning |
324
+ |---|---|
325
+ | `--server <url>` | Server address, `http(s)://host:port` (`ws(s)://` also accepted) — required |
326
+ | `--token <t>` / `HALO_NODE_TOKEN` | Pairing token — required; prefer the env var (flags show up in `ps`) |
327
+ | `--root <dir>` | Folder to share; every path must stay inside it. Omit (or `/`) for whole-machine mode: any path this user can reach, relative paths from the current dir |
328
+ | `--allow-shell` | Let agents run commands (`node_run`) as this user, not sandboxed. Off by default |
329
+ | `--header "Name: value"` | Repeatable. Extra header on the connection, for an auth proxy in front of the server |
330
+
331
+ Exits 1 on a rejected / revoked token, a deleted workspace or a protocol
332
+ mismatch; retries everything else. Full guide: [node.md](node.md).
333
+
311
334
  ## Architecture
312
335
 
313
336
  ```
@@ -94,7 +94,7 @@ Three session levels, stored per session (`agent_sessions.access_level`; `full`
94
94
 
95
95
  | Level | Tools the agent can get (from its `tools:` list) | Sandbox |
96
96
  |---|---|---|
97
- | `full` | all 9 workspace tools | none (the `rm` guard still applies) |
97
+ | `full` | all 9 workspace tools, plus the full-only bundles `relay_send` and `node_list` (linked machines) when listed | none (the `rm` guard still applies) |
98
98
  | `workspace` | all 9 | writes only inside the workspace; credentials and workspace runtime state are hidden |
99
99
  | `readonly` | all 9 with an OS sandbox (writes fail); only `file_read`, `view_image`, `file_list`, `grep`, `glob` without one | nothing writable |
100
100
 
@@ -103,7 +103,7 @@ Extra rules:
103
103
  - A readonly `shell_exec` gets no secret substitution — `{{…params…}}` / `<<ENV>>` placeholders stay literal.
104
104
  - `view_image` also needs a vision-capable model.
105
105
  - A skill with `requiresAccess` above the session level is hidden (no metadata, no `activate_skill`).
106
- - Relay tools are only built for `full` sessions. A2A tools (`a2a_send` in `tools:`) are built at every level except the A2A read-only profile; a non-full session's `files` must sit in the workspace or the temp dir ([dev/tools.md → A2A tools](../dev/tools.md#a2a-tools)).
106
+ - Relay tools and linked-machine tools (`node_list` in `tools:` → the eight `node_*` tools, [node.md](node.md)) are only built for `full` sessions. A2A tools (`a2a_send` in `tools:`) are built at every level except the A2A read-only profile; a non-full session's `files` must sit in the workspace or the temp dir ([dev/tools.md → A2A tools](../dev/tools.md#a2a-tools)).
107
107
  - Hidden from `workspace` / `readonly` sessions only (Full sessions, the admin file explorer and the terminal see everything): a built-in list that is always included (`~/.halo/secrets`, `~/.aws`, `~/.ssh`, `~/.gnupg`, `~/.docker`, `~/.config/gh`, `~/.gitconfig`, `~/.git-credentials`, `~/.npmrc`, `~/.netrc`, the global evo/cron/runs databases, internal-session transcripts, logs, …), any extra paths added in `general.sandbox.hidden_dirs` / `hidden_files` (they add to the built-in list, never replace it), plus the workspace's own `.halo/sessions`, `.halo/logs`, `.halo/evo`, `.halo/halo.db*` (fixed in code). The rest of `.halo/` stays readable.
108
108
 
109
109
  ### Where a session's level comes from
@@ -0,0 +1,86 @@
1
+ # Linked machines (`halo node`)
2
+
3
+ Let a workspace's agents work on files on **your own computer** — a laptop, a desktop, a box behind NAT — while the agents themselves keep running on the halo server. You run `halo node` on that machine; it dials out to the server (no port to open), and the workspace's agents get `node_*` tools that read, write, search and (if you allow it) run commands there.
4
+
5
+ ```
6
+ [your laptop] [server]
7
+ halo node --root ~/proj ──WebSocket──────▶ halo server ── agent in workspace W
8
+ (files, optional shell) node_read / node_write / … / node_run
9
+ ```
10
+
11
+ The machine needs only the `halo` package — no `halo setup`, no model keys, nothing under `~/.halo/`.
12
+
13
+ Supported: **macOS and Linux**. Windows works on a best-effort basis (not regularly tested; `node_run` commands go to `cmd.exe`).
14
+
15
+ ## 1. Create a token
16
+
17
+ Admin → **Channels → Linked machines** → **Add machine**. Pick the workspace and a machine name (`a-z 0-9 -`, e.g. `mbp`; unique within the workspace — the agent uses it to address the machine). The dialog shows a command to copy:
18
+
19
+ ```bash
20
+ HALO_NODE_TOKEN=<token> halo node --server https://halo.example.com --root <folder>
21
+ ```
22
+
23
+ The token stays on the list row (copy button). Deleting the row revokes it at once and disconnects the machine.
24
+
25
+ ## 2. Run `halo node` on the machine
26
+
27
+ ```bash
28
+ npm install -g @turmind/halo # once
29
+ export HALO_NODE_TOKEN=<token> # better than --token: flags show up in ps / shell history
30
+ halo node --server https://halo.example.com --root ~/proj
31
+ ```
32
+
33
+ It runs in the foreground and logs each call (`[Node] read src/app.ts`, `[Node] refused write ../x: outside root`). Ctrl-C stops it. It reconnects by itself after network drops or a server restart; it exits on a bad / revoked token or when the workspace is gone.
34
+
35
+ The admin row turns green (live, no refresh) and shows `folder · shell on/off · os`.
36
+
37
+ ### Folder mode vs whole-machine mode
38
+
39
+ - **`--root <folder>`** — share one folder. Every path the agent passes must stay inside it (symlinks pointing out are refused too); relative paths start from it.
40
+ - **No `--root`** (or `--root /`) — **whole-machine mode**: the agent can reach every path your user can, like a full-access local session. Relative paths start from the directory you ran `halo node` in. A startup line warns about it, and the admin shows "Whole machine".
41
+
42
+ Prefer `--root` unless you really mean the whole machine.
43
+
44
+ ### `--allow-shell`
45
+
46
+ Off by default — `node_run` then refuses with "restart `halo node` with --allow-shell". With it, agents can run **any command as your user, not sandboxed**. In folder mode only the command's working directory is held inside the folder; the command itself (`cat ~/.ssh/...`, `curl ...`) can reach anything your user can. Turn it on only for agents and workspaces you trust. Commands are killed after the shell timeout (120 s, or `HALO_SHELL_TIMEOUT` in ms on the machine).
47
+
48
+ ### What the agent can see
49
+
50
+ Everything inside the shared folder — including `.env` files, keys, credentials and git history. Don't share a folder that holds secrets you wouldn't paste into the chat. Whole-machine mode exposes your whole home directory.
51
+
52
+ ### Behind a login proxy
53
+
54
+ `halo node` sends a bearer token, nothing else. If the server sits behind an auth proxy (Cloudflare Access, an SSO gateway, basic auth), either point `--server` at an address the machine can reach directly, or pass the proxy's credentials with `--header` (repeatable, `Name: value`, split on the first colon):
55
+
56
+ ```bash
57
+ halo node --server https://halo.example.com --root ~/proj \
58
+ --header "CF-Access-Client-Id: <id>" --header "CF-Access-Client-Secret: <secret>"
59
+ ```
60
+
61
+ ## 3. Let the agent use it
62
+
63
+ Node tools are enabled per agent by **`node_list`** in `agent.yaml`'s `tools:` — that one name brings all eight (`node_list`, `node_read`, `node_write`, `node_edit`, `node_list_dir`, `node_grep`, `node_glob`, `node_run`). The bundled `default` agent lists it. If your workspace overrides the default agent (`<workspace>/.halo/agents/default/agent.yaml`), or you use another agent, add it yourself:
64
+
65
+ ```yaml
66
+ tools:
67
+ - file_read
68
+ # …
69
+ - node_list # linked machines (whole node_* set)
70
+ ```
71
+
72
+ Only **Full** access sessions get node tools — a Workspace or Readonly session listing `node_list` gets none. Cron jobs in the workspace can use them too.
73
+
74
+ Then just ask: "list my machines", "read `notes/todo.md` on mbp", "run the tests on mbp". The agent calls `node_list` first to see which machines are online.
75
+
76
+ ## Troubleshooting
77
+
78
+ | Message | Meaning |
79
+ |---|---|
80
+ | `token rejected by the server (401)` | Wrong / deleted token — create a new one. 5 bad tries in 15 min lock the address out for a while (429). |
81
+ | `the workspace this token is bound to no longer exists (404)` | The workspace folder was removed on the server. |
82
+ | `protocol mismatch (426)` | `halo` versions too far apart — upgrade the older side. |
83
+ | `this token is already connected from another process` | Another `halo node` with the same token is running; this one keeps retrying until that one stops. Also normal right after the machine rebooted or woke from sleep: the server needs 40–60 s to notice the old connection is dead, so the new process backs off and can take up to ~90 s to come online. |
84
+ | agent: `machine "mbp" is offline` | `halo node` isn't running / connected. |
85
+ | agent: `went offline during the call` | The connection dropped mid-call; the operation may or may not have happened. Running commands on the machine were stopped. |
86
+ | agent: `not available in this runtime` | You're in the standalone CLI / TUI — linked machines only work through `halo server` (admin UI or a channel). |
@@ -60,7 +60,7 @@ Same id present in both scopes: workspace wins; the overridden global is greyed
60
60
 
61
61
  ### Tool selection
62
62
  - **Session tools**: `start_session` / `session_list` / `query_session` / `interrupt_session` / `stop_session` / `archive_session` / `get_session_output` / `query_agent` — **not** selected by name; the whole bundle is granted automatically by a non-empty `team` (see below). Listing them under `agent.yaml tools` has no effect.
63
- - **Workspace tools**: `file_read` / `view_image` / `file_write` / `file_edit` / `file_list` / `shell_exec` / `grep` / `glob` / `web_fetch`, plus the single `relay_send` chip (grants the whole cross-workspace relay set, full-access sessions only) and the single `a2a_send` chip (grants the cross-server A2A set — `a2a_send` / `a2a_stop` / `a2a_read` / `a2a_list` — at every access level except the A2A read-only profile), returned by `GET /api/agent-configs/tools`. `view_image` is dropped at runtime when the model can't take images (the form dims it)
63
+ - **Workspace tools**: `file_read` / `view_image` / `file_write` / `file_edit` / `file_list` / `shell_exec` / `grep` / `glob` / `web_fetch`, plus the single `relay_send` chip (grants the whole cross-workspace relay set, full-access sessions only) the single `a2a_send` chip (grants the cross-server A2A set — `a2a_send` / `a2a_stop` / `a2a_read` / `a2a_list` — at every access level except the A2A read-only profile) and the single `node_list` chip (grants the eight linked-machine `node_*` tools, full-access sessions only — see [design/node.md](../design/node.md)), returned by `GET /api/agent-configs/tools`. `view_image` is dropped at runtime when the model can't take images (the form dims it)
64
64
  - **`activate_skill`**: auto-injected when the YAML lists at least one usable skill (not disabled, allowed at the session's access level); loads the full SKILL.md on demand
65
65
 
66
66
  ### Team (delegation switch + whitelist)
@@ -67,6 +67,8 @@ Two tabs:
67
67
 
68
68
  Current tab stored in `editorStore.bottomTab`.
69
69
 
70
+ The middle of the tab bar shows the current tab's title — the session title on Chat ("New session" for a draft, "Untitled session" until it has one), the active terminal's name on Terminal. It is truncated with an ellipsis when it doesn't fit (full text on hover) and hidden when the bar is too narrow.
71
+
70
72
  ### Floating mode
71
73
  The tab bar has a maximize button and, at the far right, a float button. Toggling the float button detaches the panel into a draggable window:
72
74
  - **Default position/size**: bottom-right corner, 480×640 with a 24px margin
@@ -211,6 +211,9 @@ function cleanChildEnv() {
211
211
  const env = { ...process.env };
212
212
  delete env.HALO_PASSWORD;
213
213
  delete env.HALO_JWT_SECRET;
214
+ delete env.HALO_NODE_RELAY_URL;
215
+ delete env.HALO_NODE_RELAY_TOKEN;
216
+ delete env.HALO_NODE_TOKEN;
214
217
  for (const key of settingsOtelEnvKeys)
215
218
  delete env[key];
216
219
  return env;