Commit 17b8a5c
authored
Studio Code: run the remote-session bridge as a background daemon (#3300)
## Related issues
- Fixes STU-1649
## How AI was used in this PR
Implementation drafted with Claude Code, I reviewed the diff, ran the
test suite, and smoke-tested the new CLI surface locally.
## Proposed Changes
The experimental Telegram remote-session bridge added in #3196
(STU-1612) blocks the terminal it was launched from. If the user closes
that terminal, the bridge dies and Studio loses connectivity to the
remote agent. This PR makes the bridge daemonizable so users can close
the terminal without dropping the session.
New subcommand tree under `studio code`, gated behind
`STUDIO_ENABLE_REMOTE_SESSION=true`:
- `studio code remote-session start [--detach] [--remote-chat-id N]
[--remote-bot foo]`. Without `--detach` it behaves like `studio code
--remote-session`. With `--detach` it forks a detached child via
`spawn(..., { detached: true, stdio: 'ignore', windowsHide: true })`,
sets `STUDIO_REMOTE_SESSION_DAEMON_CHILD=1` on the child env, and waits
up to 5s for the child to write `~/.studio/remote-session.pid` (mode
0600) before returning. Config (token) is validated in the parent, so a
missing token fails fast in the foreground.
- `studio code remote-session stop`. Reads the PID file, sends SIGTERM,
polls for exit up to 5s, escalates to SIGKILL if needed, and always
removes the PID file. The daemon's existing SIGTERM handler keeps the
graceful detach path, so chats still receive `🔴 Local agent detached.`
- `studio code remote-session status`. Probes liveness via
`process.kill(pid, 0)`, removes stale PID files automatically, and
prints a human-readable status.
The pre-existing `studio code --remote-session` flag continues to work
unchanged.
## Testing Instructions
- `npm run cli:build`
- `export STUDIO_ENABLE_REMOTE_SESSION=true` and make sure you have a
remote-session token (logging in with `/login` inside `studio code` is
enough)
- `node apps/cli/dist/cli/main.mjs code remote-session status` should
print `not running`
- `node apps/cli/dist/cli/main.mjs code remote-session start --detach`
should print `Started (PID …, log: …)` and return
- Re-run `status` from a fresh terminal: should still report running
- Send a Telegram message to your test bot: the local agent should
respond
- `node apps/cli/dist/cli/main.mjs code remote-session stop` should
print stopped, and Telegram should receive the detach message.
Negative path
- In a clean DEV_CONFIG_DIR with no token, `node
apps/cli/dist/cli/main.mjs code remote-session start --detach` should
print the missing-token error in the foreground and exit non-zero with
no daemon spawned and no PID file written
- Confirm `studio code --help` does NOT show `remote-session` when the
feature flag is off
| Scenario | Command | Output |
| --- | --- | --- |
| No daemon yet | `studio code remote-session status` | <img
width="1000" height="148" alt="CleanShot 2026-05-01 at 10 48 35@2x"
src="https://github.com/user-attachments/assets/e8d48b10-0d92-46a2-ba1e-c8bfc16d9c46"
/> |
| Start as daemon | `studio code remote-session start --detach` | <img
width="1510" height="146" alt="CleanShot 2026-05-01 at 10 48 56@2x"
src="https://github.com/user-attachments/assets/cb9104b0-92c1-4aa0-a7d9-f5c398789bb8"
/> |
| Confirm from a fresh terminal | `studio code remote-session status` |
<img width="1506" height="208" alt="CleanShot 2026-05-01 at 10 49 30@2x"
src="https://github.com/user-attachments/assets/a3e9fc7d-ca6a-4474-8ec3-27b8d772f2b8"
/> |
| Bridge end-to-end | Telegram chat | <img width="1736" height="1538"
alt="CleanShot 2026-05-01 at 10 53 52@2x"
src="https://github.com/user-attachments/assets/7f4ac4e5-b4fd-45fa-a924-642fe90ff586"
/> |
| Graceful stop | `studio code remote-session stop` | <img width="1506"
height="144" alt="CleanShot 2026-05-01 at 10 54 09@2x"
src="https://github.com/user-attachments/assets/f70e1885-88d1-4ffb-acb3-96350fdffb18"
/> |
| Back to clean state | `studio code remote-session status` | <img
width="1506" height="144" alt="CleanShot 2026-05-01 at 10 54 20@2x"
src="https://github.com/user-attachments/assets/1a2f5f42-a0d2-4fd5-9ad6-228877918ee5"
/> |
| Already running | `studio code remote-session start --detach` (second
time) | <img width="1618" height="144" alt="CleanShot 2026-05-01 at 10
54 39@2x"
src="https://github.com/user-attachments/assets/17ee49cf-b2f5-4e22-b8cc-67907ce6ffc4"
/> |
| No token configured | `studio code remote-session start --detach`
(clean DEV_CONFIG_DIR) | <img width="1618" height="212" alt="CleanShot
2026-05-01 at 10 55 38@2x"
src="https://github.com/user-attachments/assets/b549acc2-1e85-4d8f-80ad-1e8fd1c888b6"
/> |
| Stop when not running | `studio code remote-session stop` | <img
width="1486" height="124" alt="CleanShot 2026-05-01 at 10 56 02@2x"
src="https://github.com/user-attachments/assets/1cacc9fd-090f-4f9b-915e-33c6b39b36fa"
/> |
| Stale PID file | `studio code remote-session status` (after editing
PID file to a dead PID) | <img width="1486" height="126" alt="CleanShot
2026-05-01 at 10 57 52@2x"
src="https://github.com/user-attachments/assets/c438569a-aa90-4575-9adf-4d2f198d5a7c"
/> |
| Feature flag off | `studio code --help` | <img width="1486"
height="674" alt="CleanShot 2026-05-01 at 10 59 31@2x"
src="https://github.com/user-attachments/assets/80490b88-042c-4e14-99aa-23fcef87ce60"
/> |
| Feature flag on | `studio code --help` | <img width="1486"
height="874" alt="CleanShot 2026-05-01 at 10 58 09@2x"
src="https://github.com/user-attachments/assets/c6483ee1-e204-4eb3-8c94-ed5e6fe6d1a8"
/> |
## Pre-merge Checklist
- [x] Have you checked for TypeScript, React or other console errors?1 parent cc9b462 commit 17b8a5c
7 files changed
Lines changed: 837 additions & 8 deletions
File tree
- apps/cli
- commands/ai
- remote-session
- tests
- specs
- tools/common/lib
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
127 | 132 | | |
128 | 133 | | |
129 | 134 | | |
| |||
0 commit comments