@oar-sh/oar 0.9.10 → 0.9.12

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 (135) hide show
  1. package/CHANGELOG.md +440 -1
  2. package/README.md +156 -972
  3. package/package.json +13 -13
  4. package/server/README.md +112 -25
  5. package/server/claude-worker/claude-remote-relay-tool.mjs +2 -0
  6. package/server/claude-worker/claude-sdk-adapter.mjs +57 -4
  7. package/server/claude-worker/claude-session-process.mjs +217 -11
  8. package/server/claude-worker/claude-session-worker.mjs +26 -1
  9. package/server/claude-worker/task-output-discovery.mjs +126 -0
  10. package/server/copilot-worker/copilot-sdk-session-process.mjs +235 -14
  11. package/server/copilot-worker/copilot-sdk-session-worker.mjs +8 -0
  12. package/server/copilot-worker/copilot-shell-output-mirror.mjs +94 -0
  13. package/server/copilot-worker/copilot-task-settle.mjs +96 -0
  14. package/server/db-schema.mjs +68 -2
  15. package/server/grok-worker/acp-client.mjs +2 -1
  16. package/server/grok-worker/acp-host-services.mjs +46 -6
  17. package/server/grok-worker/grok-background-tasks.mjs +241 -0
  18. package/server/grok-worker/grok-sdk-adapter.mjs +3 -1
  19. package/server/grok-worker/grok-session-worker.mjs +33 -1
  20. package/server/grok-worker/grok-turn-runner.mjs +11 -0
  21. package/server/migrations/0013-previews.mjs +130 -0
  22. package/server/migrations/0014-conversation-groups.mjs +89 -0
  23. package/server/migrations/0015-conversation-group-position.mjs +76 -0
  24. package/server/migrations/0016-share-access-log.mjs +110 -0
  25. package/server/migrations/0017-conversation-history-indexes.mjs +89 -0
  26. package/server/public/app/about-ui.js +73 -0
  27. package/server/public/app/about-view.mjs +234 -0
  28. package/server/public/app/action-confirmations.js +31 -14
  29. package/server/public/app/agent-exchange-fold-view.mjs +40 -101
  30. package/server/public/app/api-client.js +264 -16
  31. package/server/public/app/ask-user-view.js +17 -15
  32. package/server/public/app/background-tasks-view.mjs +285 -16
  33. package/server/public/app/bootstrap.js +253 -37
  34. package/server/public/app/chat-actions-menu-state.mjs +20 -10
  35. package/server/public/app/claude-background-command-limit-options.mjs +21 -0
  36. package/server/public/app/context-menu.mjs +90 -6
  37. package/server/public/app/conversation-group-drag.mjs +191 -0
  38. package/server/public/app/conversation-group-order.mjs +265 -0
  39. package/server/public/app/conversation-group-state.mjs +100 -0
  40. package/server/public/app/conversation-list-drag.mjs +449 -0
  41. package/server/public/app/conversation-payload-cache.mjs +357 -0
  42. package/server/public/app/conversation-turn-state.mjs +81 -0
  43. package/server/public/app/conversation-view.js +567 -94
  44. package/server/public/app/conversation-window-retention.mjs +96 -0
  45. package/server/public/app/cwd-picker.js +1 -1
  46. package/server/public/app/hidden-messages-view.mjs +312 -0
  47. package/server/public/app/host-suspend-ui.js +7 -1
  48. package/server/public/app/journal-view.js +1033 -82
  49. package/server/public/app/preview-cards.mjs +117 -31
  50. package/server/public/app/preview-command.mjs +10 -1
  51. package/server/public/app/relay-board-view.js +19 -6
  52. package/server/public/app/relay-prompt-sanitizer.mjs +11 -4
  53. package/server/public/app/relay-restart-error.mjs +16 -0
  54. package/server/public/app/settings-modal.js +150 -10
  55. package/server/public/app/settings-tabs.js +1 -1
  56. package/server/public/app/share-format.mjs +49 -0
  57. package/server/public/app/share-preview-marks.mjs +167 -0
  58. package/server/public/app/share-state.js +109 -0
  59. package/server/public/app/shared-conversations-settings.js +480 -0
  60. package/server/public/app/socket-handlers.js +138 -20
  61. package/server/public/app/store.js +121 -30
  62. package/server/public/app/subagent-row.mjs +3 -3
  63. package/server/public/app/subagent-viewer.mjs +37 -7
  64. package/server/public/app/task-console-render.mjs +237 -0
  65. package/server/public/app/task-console-watch.mjs +42 -0
  66. package/server/public/app/task-console.mjs +630 -0
  67. package/server/public/app/task-output-text.mjs +234 -0
  68. package/server/public/app/thinking-follow.js +0 -4
  69. package/server/public/app/transcript-island.mjs +73 -0
  70. package/server/public/app/transcript-jump-bottom-view.mjs +230 -26
  71. package/server/public/app/transcript-jump-bottom.mjs +170 -22
  72. package/server/public/app/transcript-reading-anchor.mjs +256 -0
  73. package/server/public/app/transcript-reload-freshness.mjs +17 -1
  74. package/server/public/app/transcript-viewport-anchor.mjs +159 -0
  75. package/server/public/index.html +625 -21
  76. package/server/relay-tools.md +3 -1
  77. package/server/relay.mjs +2 -1
  78. package/server/repositories/conversation-group-repository.mjs +444 -0
  79. package/server/repositories/message-repository.mjs +9 -0
  80. package/server/repositories/question-repository.mjs +4 -0
  81. package/server/repositories/session-repository.mjs +12 -37
  82. package/server/repositories/share-repository.mjs +322 -0
  83. package/server/repositories/share-visibility-statements.mjs +10 -0
  84. package/server/routes/about-routes.mjs +15 -0
  85. package/server/routes/cache-routes.mjs +4 -0
  86. package/server/routes/conversation-group-routes.mjs +171 -0
  87. package/server/routes/messages-routes.mjs +433 -68
  88. package/server/routes/preview-routes.mjs +9 -1
  89. package/server/routes/sessions-routes.mjs +901 -253
  90. package/server/server-runtime.mjs +392 -99
  91. package/server/services/about-service.mjs +461 -0
  92. package/server/services/background-task-store.mjs +365 -0
  93. package/server/services/background-work-view.mjs +228 -0
  94. package/server/services/cache-rebuild-service.mjs +30 -0
  95. package/server/services/cli-process-runner.mjs +4 -21
  96. package/server/services/conversation-history-page.mjs +199 -0
  97. package/server/services/delete-archive-service.mjs +4 -1
  98. package/server/services/detached-worker-watch-service.mjs +150 -0
  99. package/server/services/hidden-message-list.mjs +21 -0
  100. package/server/services/host-suspend-command.mjs +2 -1
  101. package/server/services/message-pin-list.mjs +1 -1
  102. package/server/services/preview-health-probe.mjs +8 -1
  103. package/server/services/preview-proxy-server.mjs +8 -4
  104. package/server/services/preview-registry-service.mjs +676 -26
  105. package/server/services/preview-static-handler.mjs +40 -7
  106. package/server/services/preview-store.mjs +274 -0
  107. package/server/services/rate-limit-service.mjs +12 -1
  108. package/server/services/relay-auth.mjs +183 -0
  109. package/server/services/relay-cli-launcher-service.mjs +3 -1
  110. package/server/services/relay-event-service.mjs +17 -0
  111. package/server/services/relay-prompt-sanitizer.mjs +11 -4
  112. package/server/services/remote-relay-dispatcher.mjs +187 -7
  113. package/server/services/request-boundary.mjs +183 -0
  114. package/server/services/session-activity-tracker.mjs +231 -19
  115. package/server/services/session-worker-launch-service.mjs +190 -6
  116. package/server/services/session-worker-process-service.mjs +10 -6
  117. package/server/services/share-access-log-service.mjs +123 -0
  118. package/server/services/share-path-redaction.mjs +424 -0
  119. package/server/services/status-event-service.mjs +7 -3
  120. package/server/services/task-output-rooms.mjs +259 -0
  121. package/server/services/task-output-service.mjs +562 -0
  122. package/server/services/tunnel-worker-path-guard.mjs +24 -41
  123. package/server/services/windows-autostart-service.mjs +6 -1
  124. package/server/services/windows-boot-autostart-service.mjs +207 -23
  125. package/shared/claude-background-command-limit.mjs +83 -0
  126. package/shared/preview-tool-core.mjs +15 -5
  127. package/shared/remote-relay-contract.mjs +35 -3
  128. package/shared/share-path-privacy.mjs +30 -0
  129. package/shared/task-output-text.mjs +737 -0
  130. package/shared/windows-system-tools.mjs +106 -0
  131. package/shared/worker-runtime/background-task-digest.mjs +30 -0
  132. package/shared/worker-runtime/heartbeat.mjs +24 -0
  133. package/shared/worker-runtime/kept-posts.mjs +83 -0
  134. package/shared/worker-runtime/task-output-spool.mjs +181 -0
  135. package/shared/worker-runtime/worker-websocket-link.mjs +47 -15
package/CHANGELOG.md CHANGED
@@ -3,7 +3,446 @@
3
3
  All notable changes to OAR are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow semver.
5
5
 
6
- ## [Unreleased]
6
+ ## [0.9.12] — 2026-10-18
7
+
8
+ Highlights: a background command or monitor in the task panel opens a
9
+ console with its output, live, in colour and with secrets blanked, paging
10
+ back through the whole log and with its own **Stop**. Task rows say when a
11
+ task has gone quiet ("no output for 12 min", amber after a time you set in
12
+ Settings) and show a **✓ 412 ✘ 2** chip when the output is a test run;
13
+ sub-agent rows count their steps, and agents read a task's output on a
14
+ paired relay with `remote_relay` `read_task_output`. Long conversations open
15
+ and page back fast, and switching away and back, or reloading, returns to
16
+ the message you were reading, older pages included; new messages wait below
17
+ a place far up the history instead of skipping the ones in between.
18
+
19
+ ### Upgrade notes
20
+
21
+ - Migration 0017 (two indexes for the history of long conversations) runs by
22
+ itself on the first start. The Node.js requirement is unchanged (22.13 or
23
+ newer), and no setting or config key needs changing.
24
+ - Two new settings in **Settings › General**: **Mark a background task as
25
+ quiet after** (10 minutes by default, for the relay) and **Messages kept
26
+ per conversation for switching back** (200 by default, per browser).
27
+ - **Claude background commands may run for 2 hours** before Claude Code
28
+ stops them, and up to 8 hours when Claude asks; **Settings › Providers ›
29
+ Claude** sets the limit. OAR now sets `BASH_DEFAULT_TIMEOUT_MS`, `BASH_MAX_TIMEOUT_MS` and
30
+ `CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS` for the Claude sessions it starts,
31
+ so values of these in the relay's environment no longer apply. Commands
32
+ that start with `sleep`, and sub-agents' commands, are not moved to the
33
+ background after 2 minutes and may block a turn up to the limit.
34
+
35
+ ### Added
36
+
37
+ - **Click a background command to watch its output.** A backgrounded shell
38
+ command or monitor in the composer's task panel opens a console: the last
39
+ 2,000 lines, following live, with **Load earlier** paging back through the
40
+ whole log (about 5 MB at most). Progress-bar redraws collapse to their last
41
+ state, repeated lines fold into one with ×N, colours are kept and other
42
+ control codes dropped, secrets are blanked, and the console has its own
43
+ **Stop**. A finished command keeps a dimmed ✓/✘ row for an hour so a failed
44
+ run can still be read. Claude reads the file its CLI writes for the command,
45
+ Copilot a detached shell's log or an attached shell's recent output, and
46
+ Grok now lists its terminals as tasks. A session started before this
47
+ release names no output file; its console says so and that a restart of
48
+ the session helps.
49
+ - **Task rows say when a task has gone quiet** ("no output for 12 min", amber
50
+ after **Settings › General › Mark a background task as quiet after**, 10
51
+ minutes by default) and show a **✓ 412 ✘ 2** chip when the output is a
52
+ vitest, Playwright, node:test, jest, pytest or turbo run (also through
53
+ pnpm); the console header's chip jumps to the first failure, and a run
54
+ that ends shows its final counts within a moment.
55
+ - **Sub-agent rows in the task panel show their step count** ("22 steps"), as
56
+ the rows in the reply already did.
57
+ - **Settings › Providers › Claude › Claude background command limit** (30
58
+ minutes to 8 hours, 2 hours by default) sets how long a command Claude runs
59
+ in the background may take before Claude Code stops it, when Claude gives it
60
+ no timeout of its own; Claude may still ask for up to 8 hours for one
61
+ command. A foreground command moves to the background after 2 minutes, so
62
+ the turn goes on while it runs. Claude is also told to write the output of
63
+ long runs to a log file instead of piping it into `tail`, and to start runs
64
+ that must survive a session restart with `nohup`. A change applies to Claude
65
+ sessions started afterwards; Claude Cloud is not affected.
66
+ - **`remote_relay` action `read_task_output`** gives agents the same tail,
67
+ quiet time and counts of a task on a relay they may read; `read_session`
68
+ lists the task ids with that health.
69
+
70
+ ### Changed
71
+
72
+ - **Long conversations open and scroll back fast.** A history page used to
73
+ load and prepare every message of the conversation, so a chat with a few
74
+ thousand messages took about two seconds per page and per live refresh. The
75
+ relay now reads only the requested page from the database (migration 0017
76
+ adds the indexes for it), so a page loads in well under a tenth of a second
77
+ however long the conversation is.
78
+ - Switching back to a conversation already viewed in this tab draws it at
79
+ once from what the page kept of it; the relay's fresh answer is merged into
80
+ it when it arrives.
81
+ - **Settings › General › Messages kept per conversation for switching back**
82
+ (200 by default, 100 to 1,000 or no limit, saved in this browser) sets how
83
+ many loaded messages each of the last eight conversations keeps.
84
+ - **The conversation list shows activity by the title's colour.** The three
85
+ animated dots after a working session's title are gone: a ready session
86
+ that runs a turn or background work keeps the bright green title, an idle
87
+ one turns a darker green (a muted green in the light theme), and the chat
88
+ header follows the same rule. Question, error, offline and archived titles
89
+ keep their colours.
90
+ - The npm package guard allows 7.5 MiB unpacked and 510 entries (was 7.25
91
+ MiB and 490); the task console, the transcript's handling of new
92
+ messages below a place far up the history, the Copilot task report and the
93
+ Claude background command limit grew the server and the app to about 7.37
94
+ MiB and 505 entries.
95
+
96
+ ### Fixed
97
+
98
+ - **Copilot background tasks report how they ended.** Finished shells and
99
+ sub-agents of Copilot's SDK engine showed the status *unknown* and no exit
100
+ code, in the task data agents read and wherever the end is shown. The
101
+ worker now reports completed, failed or cancelled, a shell's exit code, and
102
+ a sub-agent's result (or its error) as its summary; a passing status line
103
+ such as *Thinking…* is no longer kept as the final summary.
104
+ - **Cancel on a usage-limit pause removes the relay's held follow-up from the
105
+ open conversation at once.** The *Automatic message from OAR* row was
106
+ deleted on the relay but stayed on the page, and in what the page kept for
107
+ switching back, until a reload. A row deleted while you were elsewhere
108
+ leaves too, also when it was the conversation's newest.
109
+
110
+ - **Switching away from a long conversation and back keeps your place.** After
111
+ loading older messages and scrolling back into them, a switch to another
112
+ conversation and back lost the reading position: with more than 100 messages
113
+ loaded the oldest were dropped, and messages written meanwhile moved the view
114
+ by as many rows. The page now remembers the message you were reading and
115
+ keeps the loaded messages, so you come back to the same message at the same
116
+ place, older pages included; after a reload it opens at that message too.
117
+ - **New messages no longer skip the ones in between while you read far up.**
118
+ Opened at a pin, a search result or the place you were reading after a
119
+ reload, a conversation shows the messages around it. A message or reply that
120
+ arrived then was put right under them, and the messages between were never
121
+ loaded when you scrolled down, only the jump-to-bottom button brought them.
122
+ Now new messages wait: the button counts them, and scrolling down loads
123
+ every message in between, in order, before them. A reply still being
124
+ written shows once you are there. A message you send from there takes you
125
+ to the end, where it, its reply and everything in between show.
126
+ - **Images that load late no longer push the message you are reading down.**
127
+ In a browser without scroll anchoring (Safari, for one), pictures above
128
+ your place that arrived after a switch back, a reload or an older page moved
129
+ the text by their height. The transcript now holds your place while they
130
+ load, and lets go as soon as you scroll.
131
+
132
+ ## [0.9.11] — 2026-10-17
133
+
134
+ Highlights: sessions an agent starts now sit in a group under the session
135
+ that started it, with a pill that sums up what runs and what waits for you,
136
+ and rows drag into, out of and within a group. Settings › Sharing lists every
137
+ shared link with Copy, Renew and Stop and an access log of each open (the IP
138
+ address optional), shared views hide the host's paths in one of three modes,
139
+ **Preview as shared** shows what a viewer gets, and a 🙈 list gathers the
140
+ messages hidden from viewers. The relay is harder to reach from outside: ten
141
+ wrong tokens lock an address out for a minute, the live channel accepts only
142
+ the relay's own origin, forwarded headers count only from a trusted proxy, and
143
+ `?token=` signs in the page only. Day/Night is back in the ⋯ menu, next to the
144
+ new **About OAR**.
145
+
146
+ ### Upgrade notes
147
+
148
+ - **Behind a reverse proxy on another host or origin, set `trustProxy` and
149
+ `allowedOrigins`.** This is the first release that checks the origin of the
150
+ live Socket.IO channel and that reads the client address, host and scheme
151
+ from `X-Forwarded-*` headers only when the proxy is trusted. A proxy on the
152
+ relay host itself is trusted already (`trustProxy` defaults to
153
+ `"loopback"`). For one on another machine, or one that rewrites the `Host`
154
+ header, add to the config file (`~/.oar/config.json`, or `server/config.json`
155
+ in a git checkout) and restart the relay:
156
+
157
+ ```json
158
+ "trustProxy": "192.0.2.10",
159
+ "allowedOrigins": ["https://relay.example.com"]
160
+ ```
161
+
162
+ `trustProxy` takes what Express's `trust proxy` takes: the proxy's address,
163
+ a subnet such as `"10.0.0.0/8"`, or a hop count such as `1`.
164
+ `allowedOrigins` lists the public origins exactly as the browser shows them
165
+ (scheme, host, a port other than the default). Without them, the page loads
166
+ but its live connection is refused (the relay logs `Refused a handshake from
167
+ origin …`), and every client shares the proxy's address, so one client's
168
+ ten wrong tokens lock the rest out for a minute.
169
+ - **Ten wrong tokens from one address within a minute answer `429`** with
170
+ `Retry-After` until the minute is over. Requests from the relay host itself
171
+ that no proxy forwarded are never counted.
172
+ - **`?token=` works on the page address only.** Scripts that fetch API, file
173
+ or asset URLs with `?token=` must send `Authorization: Bearer <token>`
174
+ instead (or the cookie); a Socket.IO client passes it as `auth.token` (or
175
+ the cookie), not in the query.
176
+ - **Restart web relay, cancelling a queued restart and Empty queue need only
177
+ the token**, from any signed-in device. The session-worker socket and the
178
+ image-operation run answer only requests from the relay host that no tunnel
179
+ or proxy forwarded.
180
+ - Four database migrations (0013 previews, 0014 session groups, 0015 the place
181
+ in a group, 0016 the share access log) run by themselves on the first
182
+ start. The Node.js requirement is unchanged (22.13 or newer).
183
+
184
+ ### Added
185
+
186
+ - **Session groups in the sidebar.** A session that an agent starts with the
187
+ `remote_relay` tool now sits under the session that started it. The head
188
+ row carries a fold button and a pill that sums up the members ("3 · 1 waiting
189
+ for you, 2 running"); the members are indented under it, folded away once
190
+ everything in the group has finished unless you fold or unfold it yourself.
191
+ A question or approval waiting in a folded member shows on the head row,
192
+ and a tap on it opens that member. A member's activity lifts the whole
193
+ group to the top of the list. The head row's menu archives the whole group
194
+ (members still working are kept and named) and stops everything running in
195
+ it, and dissolves it; any row's menu adds a conversation to a group,
196
+ moves it, or takes it out, and groups can be named by hand. The `remote_relay` tool's
197
+ `list_sessions` and `read_session` show the group a session is in (agents
198
+ only read it). Migration 0014 adds the `conversation_groups` table and the
199
+ `group_id` column; nothing is backfilled.
200
+ - **Drag and drop for session groups.** Drag a session into a group, out of
201
+ it, or to another place inside it; the order you set stays, and later
202
+ arrivals join at the end. Drop one loose session onto the middle of another
203
+ and the two make a new group. On a phone a long press lifts the row and a
204
+ move drags it; with the keyboard, a member's menu has "Move up" and "Move
205
+ down". Migration 0015 adds the `group_position` column. Rolling back needs
206
+ no data change: older releases ignore the column, and a stale place they
207
+ leave behind is cleared when this release starts again.
208
+ - **A 🙈 list of the messages hidden from shared viewers.** Next to 📍, a 🙈
209
+ button with a count appears while the open conversation hides messages
210
+ from its shared link (never in the shared view itself). It opens a list
211
+ like the pinned one: each row jumps to its message, also one far up in the
212
+ history, and has Unhide; "Unhide all" asks first and leaves only a message
213
+ whose turn is still running hidden, naming it. The count and the list cover
214
+ messages outside the loaded page, and other open tabs and devices follow a
215
+ change without a reload.
216
+ - **Manage your shared links in Settings › Sharing.** Every shared
217
+ conversation is listed with when it was shared and last opened, how often
218
+ and by how many viewers. **Copy link** copies it, **Renew link** gives the
219
+ conversation a new link (the old one stops working at once), and **Stop
220
+ sharing** ends it; the `⋯` menu has **Stop sharing** too while the open
221
+ conversation is shared, and asks first. Each row unfolds into an access
222
+ log: one entry per open of the page (not per refresh) with time, IP
223
+ address, country and browser. The log carries over to a renewed link and
224
+ is deleted when you stop sharing or delete the conversation. Switch off
225
+ **Store viewer IP addresses** to log new opens without the address (the
226
+ status log of shared reads follows it); switching it off also offers to
227
+ remove the addresses already stored, from both logs. Distinct viewers are
228
+ still told apart. Migration 0016 adds the share lineage and the
229
+ `conversation_share_opens` table.
230
+ - **Preview as shared.** The `⋯` menu's new entry opens the conversation as
231
+ a share link shows it, without creating one: what viewers get instead of a
232
+ path is marked green, whatever still looks like a path amber.
233
+ - **Sub-agent records in shared views.** A sub-agent's row in a shared
234
+ conversation now opens its record, read-only and without Stop, filtered
235
+ like the rest of the share.
236
+
237
+ - **Wrong tokens lock an address out for a minute.** Ten wrong tokens from
238
+ one address within a minute (a Bearer header, the cookie, the sign-in field
239
+ or a Socket.IO handshake) make the relay answer that address `429` with
240
+ `Retry-After` until the minute is over, the right token included, and the
241
+ sign-in page says how long to wait. The same stale value repeated counts
242
+ once, so a tab with an old cookie does not lock you out. Requests from the
243
+ relay host itself that no proxy forwarded are never locked out, so the
244
+ relay's own workers and agent tools keep working.
245
+ - **About OAR in the ⋯ menu.** A new entry, "ℹ️ About OAR · <version>",
246
+ opens what this relay is and has done: version, commit (for a git
247
+ checkout) and when the relay started; each provider that is on, with its
248
+ CLI and SDK version and whether it is online; conversations, turns and
249
+ messages since the first conversation, turns per provider, and the usage
250
+ the providers report (Copilot premium requests, Cursor and Grok tokens and
251
+ cost, Claude Cloud cost); uptime, database size and running workers. With
252
+ the opt-in update check on it names the latest version, otherwise it says
253
+ where to turn the check on. Shared viewers do not get the entry. The data
254
+ comes from the new `GET /api/about`, which counts large databases in small
255
+ steps and keeps the totals for a minute.
256
+
257
+ ### Changed
258
+
259
+ - **A stopped or renewed share link answers a plain 404**, the page included,
260
+ exactly like a link that never existed, and a shared page that is still open
261
+ stops at its next refresh instead of polling on. The address in the access
262
+ log and in the status log of shared reads is now the one the relay trusts
263
+ through its `trustProxy` setting; a forwarded header from an untrusted peer
264
+ no longer sets it.
265
+
266
+ - **A share link no longer carries the relay host's paths.** The relay
267
+ filters what it serves to shared viewers, by **Paths and file names** in
268
+ Settings › Sharing: show every path, hide the path and keep the file name
269
+ (the default), or hide both. Tool lines, thoughts, replies, attachments and sub-agent records all
270
+ pass through it; before, only the viewer's browser shortened the paths in
271
+ tool lines, and attachments carried their full path on the host. Free text
272
+ is filtered on a best-effort basis: relative paths are left as they are.
273
+
274
+ - **A long press on a sidebar row opens its menu when the finger lifts**, no
275
+ longer while it is still down: a long press that then moves drags the row
276
+ instead. Where rows cannot move (the Archived view, under a filter, on a
277
+ group's own line) the menu still opens during the press.
278
+
279
+ - **A reply to another agent's note is no longer folded away.** Only the
280
+ note itself folds into its row now, "note from linux-test · report builder ·
281
+ answered below"; the session's reply to it always shows, like a reply to
282
+ you, because it may hold a line for you. A turn you steered a message into
283
+ folds its note too, since nothing of yours is behind the row any more. The
284
+ ⌄ button's badge counts the note and the reply as two rows.
285
+
286
+ - **A conversation no longer scrolls down by itself while you read further
287
+ up.** It only moves when you are at its end, or when you have just sent a
288
+ message yourself. Anywhere else it stays exactly where it is, whatever
289
+ lands: a reply, a relay event, another agent's note, a question, an approval
290
+ or a plan board. The ⌄ button then tells you: it turns blue with a count
291
+ (or a dot while a reply is still being written) when something new is
292
+ below, and amber with a "?" when a question or an approval waits for your
293
+ answer; a screen reader hears both. The text you are reading also keeps its
294
+ place when the reply you are in the middle of is finished and when the
295
+ conversation reloads. New in Settings › General: "Jump to the end when I
296
+ send a message", on by default and saved in the browser; switch it off and
297
+ your own messages leave you where you are as well.
298
+
299
+ - The npm package guard allows 7.25 MiB unpacked and 490 entries (was 6.75
300
+ MiB and 450); session groups, the stored previews, the background-task
301
+ resync, the transcript anchor, share management, path privacy in shared
302
+ views and About OAR grew the server and the app to about 7.05 MiB and 485
303
+ entries.
304
+
305
+ - **Restart web relay, cancelling a queued restart and Empty queue work from
306
+ every signed-in device.** They were meant for the relay host only, but the
307
+ check let everything through a tunnel or a proxy on the same machine and
308
+ refused only a direct LAN connection; they now need the token and nothing
309
+ else. The other way round, the session-worker socket and the image-operation
310
+ run now answer only requests from the relay host itself: a loopback peer
311
+ with no `cf-ray` or other tunnel marker and no `X-Forwarded-For`,
312
+ `Forwarded` or `X-Real-IP`. A same-host proxy that adds no marker no longer
313
+ reaches them.
314
+
315
+ - **A `?token=` signs in the page only.** The page takes it out of the address
316
+ and signs in with it as before; API, file and asset URLs now accept the
317
+ token in the `Authorization` header or the cookie only, and a Socket.IO
318
+ handshake no longer reads a `token` query.
319
+
320
+ - **The live Socket.IO channel accepts the relay's own origin only** (it
321
+ accepted any). The host compared is the one the browser addressed,
322
+ `X-Forwarded-Host` included when a trusted proxy sends it; for a proxy that
323
+ rewrites the `Host` header, list the public origin in the new
324
+ `allowedOrigins` setting.
325
+
326
+ ### Fixed
327
+
328
+ - **Day/Night is back in the ⋯ menu.** Since 0.9.10 the entry showed only in
329
+ a shared view; everywhere else, on every screen size, it was gone from the
330
+ menu. It is there again whenever you are signed in, with or without a
331
+ conversation open, and stays the one entry of a shared view.
332
+
333
+ - **A shared conversation no longer marks every reply "ran on" its own
334
+ provider.** In a shared link to a Claude, Cursor, Grok or OpenAI
335
+ conversation, each reply carried the red `ran on claude` (etc.) chip, as if
336
+ the turn had run on the wrong provider. The shared view now knows which
337
+ provider the conversation is bound to, and shows the chip only when a reply
338
+ really ran on another one; with no provider bound it shows none.
339
+
340
+ - **A wide table in the file reader scrolls sideways.** A markdown table wider
341
+ than the reader made the whole page scroll sideways, and a sideways swipe to
342
+ read the rest of it turned to the next file instead. The table now scrolls
343
+ in its own box, as code blocks do; a swipe that starts on it stays in the
344
+ file.
345
+
346
+ - **A worker no longer stops reconnecting after a relay restart.** On Node
347
+ 22, a worker whose reconnect reached a relay that was not ready yet gave up
348
+ for good: its process kept running without a connection, the relay started
349
+ no new one while that process lived, and every message to the session
350
+ stayed queued until the worker was killed and launched by hand. A failed
351
+ connect now always leads to the next attempt, with the usual backoff of up
352
+ to 8 seconds. As a safety net, the relay replaces a worker that has had no
353
+ connection for 60 seconds while a message waits for it: it stops the old
354
+ process and starts a new one, which then takes the message. It never does
355
+ so while a turn or background work of that session is running, and logs a
356
+ `WORKER DETACHED` line when it does.
357
+
358
+ - **A relay restart no longer forgets running background tasks.** A session
359
+ with a background shell or sub-agent still running read as idle after the
360
+ relay restarted: its task panel was empty, **Suspend host** saw nothing
361
+ to wait for, and a watching session could be told `all_idle`. The relay
362
+ now asks each worker for its tasks again on the worker's next heartbeat,
363
+ and the tasks come back with their original start time. A session whose
364
+ worker was started before this update shows "background work, details not
365
+ reported since the relay restarted" until it reports. For the first 45
366
+ seconds after a relay start a suspend waits for sessions that are still
367
+ reporting, and a task that ended while the relay was away still reports
368
+ its end.
369
+
370
+ - **Workers start when no `node` is on the relay's PATH.** A relay started
371
+ by the Windows system-startup task, before anyone signed in, ran fine, but
372
+ none of its workers ever started: they were launched with a bare `node`
373
+ that the task's PATH did not have, Windows reported the failure in a
374
+ dialog no one could see, and the log showed only a heartbeat timeout
375
+ every 90 seconds. Workers now run on the relay's own Node by its full path
376
+ on every platform, tmux included; `COPILOT_WEB_RELAY_NODE` still overrides
377
+ it. That Node's folder is added at the end of a worker's PATH when the PATH
378
+ lacks it, so the CLIs and commands a worker starts find a `node` too; a
379
+ PATH that has one keeps it.
380
+
381
+ - **A worker that cannot be started says why.** On Windows, a launch whose
382
+ `start` command fails or never returns now fails at once, naming the
383
+ program, and the conversation's launch note shows it; before, the relay
384
+ waited for a heartbeat that never came. The relay log names the command
385
+ and the PATH, SystemRoot and ComSpec it was started with, also when a
386
+ launch saw no worker process yet, and a failed process-list read logs its
387
+ exit code and error output. Windows' own programs (PowerShell, schtasks,
388
+ taskkill and others) are called by their full path. Changing the launch
389
+ folder and the Windows autostart setting show the relay's reason when they
390
+ fail, not a bare "Failed to …", and an autostart read that fails is logged.
391
+
392
+ - **The Windows system-startup launcher copes with an early boot.** The
393
+ launcher OAR generates adds Node's folder at the end of PATH and waits up
394
+ to two minutes for the `%TEMP%` folder to exist before it starts the relay
395
+ (a temp folder on a drive that a startup script creates later no longer
396
+ makes the relay and its CLIs fail); a wait that runs out is logged next to
397
+ the launcher. Settings now names how a boot task or launcher differs from
398
+ the generated one (a missing boot delay, an edited launcher) instead of
399
+ treating it as a failure; selecting "At system startup" again regenerates
400
+ both and keeps a changed launcher as a `.bak` copy. A boot task that cannot
401
+ be read no longer breaks the setting.
402
+
403
+ - **Preview links survive a relay restart.** A preview lived only in the
404
+ relay's memory, so an update, a queued restart or a crash turned every
405
+ preview link into a 404, and publishing again gave a new link. Previews are
406
+ now kept in the relay's database and restored when it starts, each checked
407
+ again: a folder preview while its folder is still inside the workspace root,
408
+ a dev-server preview until the machine reboots (on Windows with fast
409
+ startup, until a Restart: Shut down and power-on is not seen as one).
410
+ Publishing the same port or folder again in a conversation returns the same
411
+ link. Deleting a conversation, also through a cache rebuild, closes its
412
+ previews; archiving keeps them. Settings → Previews shows when each preview
413
+ was published and last opened, and the limit of 8 names the oldest ones and
414
+ how to close them. Relay logs no longer carry a preview's token; a publicly
415
+ shared transcript shows a preview card with its label only and removes every
416
+ preview link quoted in its text, also one cut short by a reply still being
417
+ written. A preview the relay cannot check at a start (a busy database, an
418
+ unreadable folder) is not served, shows as such in Settings, and is checked
419
+ again every 15 s for ten minutes. The table comes with migration 0013, which
420
+ runs by itself on the first start; the npm package gains two modules for it.
421
+
422
+ - **An install gets the dependency versions the release was tested with.**
423
+ The package asked for each of its dependencies "this version or newer", so
424
+ an install or update fetched whatever was newest that day, e.g. a newer
425
+ Copilot SDK than any release was tested with. The packages OAR depends on
426
+ directly (the Claude, Copilot and Cursor SDKs among them) are now pinned to
427
+ exact versions; a newer one arrives with an OAR update. Packages those
428
+ depend on still follow their own version ranges.
429
+
430
+ - **Restart web relay no longer reports success when the relay refuses it.**
431
+ A refused request said "Relay restart requested"; it now shows the relay's
432
+ reason, and a request that got no answer says so instead of claiming
433
+ success. The restart after a feature-flag change and cancelling a queued
434
+ restart report their errors the same way, and Empty queue names the reason
435
+ it failed.
436
+
437
+ - **Forwarded headers count only from a trusted proxy everywhere.** The
438
+ shared-view presence limit read `X-Forwarded-For` and `X-Real-IP` and the
439
+ share links read `X-Forwarded-Host` and `X-Forwarded-Proto` straight from the
440
+ request, so a direct client could pick its own rate-limit bucket or the
441
+ host of a new share link. Both now follow the `trustProxy` setting.
442
+
443
+ - **`tunnelMarkerHeaders: []` in the config no longer switches off
444
+ `COPILOT_TUNNEL_MARKER_HEADERS`.** The two lists are merged, with `cf-ray`
445
+ always included.
7
446
 
8
447
  ## [0.9.10] — 2026-10-12
9
448