@oar-sh/oar 0.9.6 → 0.9.8

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 (105) hide show
  1. package/CHANGELOG.md +285 -0
  2. package/README.md +222 -40
  3. package/bin/oar.js +320 -18
  4. package/package.json +1 -1
  5. package/server/README.md +174 -7
  6. package/server/claude-cloud-worker/claude-cloud-event-normalizer.mjs +340 -0
  7. package/server/claude-cloud-worker/claude-cloud-session-process.mjs +1325 -0
  8. package/server/claude-cloud-worker/claude-cloud-session-worker.mjs +155 -0
  9. package/server/claude-worker/claude-remote-relay-tool.mjs +2 -0
  10. package/server/claude-worker/claude-sdk-adapter.mjs +18 -13
  11. package/server/claude-worker/claude-session-process.mjs +225 -24
  12. package/server/claude-worker/claude-session-worker.mjs +6 -0
  13. package/server/claude-worker/sdk-message-normalizer.mjs +28 -0
  14. package/server/db-schema.mjs +17 -0
  15. package/server/migrations/0006-workspace-root-settings.mjs +67 -0
  16. package/server/migrations/0007-claude-cloud.mjs +82 -0
  17. package/server/public/app/activity-replay-state.mjs +68 -5
  18. package/server/public/app/agent-sessions-settings-ui.js +197 -0
  19. package/server/public/app/agent-sessions-settings.mjs +134 -0
  20. package/server/public/app/api-client.js +149 -6
  21. package/server/public/app/attachments-view.js +20 -1
  22. package/server/public/app/attribution-control.mjs +46 -0
  23. package/server/public/app/bootstrap.js +468 -88
  24. package/server/public/app/claude-cloud-conversation-ui.js +110 -0
  25. package/server/public/app/claude-cloud-settings-ui.js +374 -0
  26. package/server/public/app/claude-cloud-ui.mjs +611 -0
  27. package/server/public/app/composer-control-state.mjs +11 -0
  28. package/server/public/app/context-menu.mjs +140 -0
  29. package/server/public/app/context-tier-options.mjs +4 -0
  30. package/server/public/app/context-usage-view.mjs +127 -8
  31. package/server/public/app/conversation-origin-ui.js +27 -0
  32. package/server/public/app/conversation-provider-indicator.mjs +22 -4
  33. package/server/public/app/conversation-view.js +145 -11
  34. package/server/public/app/cwd-picker.js +12 -0
  35. package/server/public/app/journal-view.js +698 -28
  36. package/server/public/app/math-dollars.mjs +89 -0
  37. package/server/public/app/model-selector-options.mjs +1 -1
  38. package/server/public/app/plan-usage-view.mjs +36 -8
  39. package/server/public/app/pwa-install.js +5 -0
  40. package/server/public/app/relay-error-ctas.mjs +16 -2
  41. package/server/public/app/remote-relay-origin-view.mjs +120 -4
  42. package/server/public/app/router.js +49 -12
  43. package/server/public/app/scrollbar-hover.mjs +78 -0
  44. package/server/public/app/settings-modal.js +37 -3
  45. package/server/public/app/settings-tabs.js +1 -1
  46. package/server/public/app/socket-handlers.js +53 -1
  47. package/server/public/app/store.js +26 -0
  48. package/server/public/app/transcript-separators.mjs +48 -11
  49. package/server/public/app-icon-192.png +0 -0
  50. package/server/public/app-icon-512.png +0 -0
  51. package/server/public/app-icon-light-192.png +0 -0
  52. package/server/public/app-icon-light-512.png +0 -0
  53. package/server/public/app-icon-light-maskable-512.png +0 -0
  54. package/server/public/app-icon-light.svg +4 -0
  55. package/server/public/app-icon-maskable-512.png +0 -0
  56. package/server/public/app-icon.svg +3 -3
  57. package/server/public/favicon.ico +0 -0
  58. package/server/public/index.html +564 -20
  59. package/server/public/manifest.webmanifest +9 -3
  60. package/server/public/sw.js +6 -1
  61. package/server/relay-tools.md +13 -1
  62. package/server/repositories/remote-relay-repository.mjs +42 -1
  63. package/server/repositories/session-repository.mjs +47 -1
  64. package/server/routes/claude-cloud-routes.mjs +140 -0
  65. package/server/routes/git-routes.mjs +37 -0
  66. package/server/routes/messages-routes.mjs +123 -16
  67. package/server/routes/remote-relay-routes.mjs +15 -1
  68. package/server/routes/sessions-routes.mjs +517 -74
  69. package/server/server-runtime.mjs +268 -33
  70. package/server/services/claude-account-usage-service.mjs +176 -0
  71. package/server/services/claude-cloud-repo-service.mjs +408 -0
  72. package/server/services/claude-cloud-session-service.mjs +326 -0
  73. package/server/services/claude-cloud-settings-service.mjs +269 -0
  74. package/server/services/claude-context-usage.mjs +51 -3
  75. package/server/services/git-remote-service.mjs +115 -0
  76. package/server/services/oar-cli-helpers.mjs +67 -1
  77. package/server/services/plan-usage-claude-cloud.mjs +211 -0
  78. package/server/services/plan-usage-claude.mjs +202 -40
  79. package/server/services/plan-usage-contract.mjs +39 -3
  80. package/server/services/plan-usage-service.mjs +82 -2
  81. package/server/services/provider-reasoning-effort.mjs +3 -0
  82. package/server/services/pwa-manifest-theme.mjs +30 -0
  83. package/server/services/remote-relay-caller-context.mjs +49 -10
  84. package/server/services/remote-relay-client.mjs +9 -0
  85. package/server/services/remote-relay-dispatcher.mjs +383 -35
  86. package/server/services/remote-relay-inbound.mjs +49 -2
  87. package/server/services/remote-relay-loopback.mjs +245 -0
  88. package/server/services/remote-relay-registry-service.mjs +52 -0
  89. package/server/services/session-worker-launch-service.mjs +100 -15
  90. package/server/services/session-worker-process-service.mjs +348 -129
  91. package/server/services/session-worker-registry-service.mjs +18 -1
  92. package/server/services/session-worker-stop-service.mjs +24 -13
  93. package/server/services/session-worker-supervisor-service.mjs +56 -1
  94. package/server/services/update-install-service.mjs +9 -3
  95. package/server/services/usage-limit-pause-service.mjs +3 -1
  96. package/server/services/worker-launch-note-service.mjs +151 -0
  97. package/shared/claude-attribution.mjs +117 -0
  98. package/shared/claude-cloud/api-client.mjs +809 -0
  99. package/shared/claude-cloud/base-url.mjs +47 -0
  100. package/shared/claude-cloud/credentials.mjs +221 -0
  101. package/shared/claude-cloud/repo-url.mjs +111 -0
  102. package/shared/provider-routing.mjs +4 -2
  103. package/shared/remote-relay-contract.mjs +153 -22
  104. package/shared/remote-relay-tool-core.mjs +11 -8
  105. package/shared/steer-settle-failure.mjs +1 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,291 @@ All notable changes to OAR are documented here. The format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.9.8] — 2026-10-04
9
+
10
+ Highlights: OAR has a logo, an otter, with icons that follow Day and Night
11
+ mode and a start screen that continues the phone's launch screen; a
12
+ *Compacting context…* line shows while a Claude session compacts, and a
13
+ changed auto-compact window now really applies; the one-line installer
14
+ finishes the job and `oar start` brings the relay up without a session;
15
+ scrollbars are easier to grab with a mouse.
16
+
17
+ ### Added
18
+
19
+ - **The otter logo, matching Day and Night mode.** OAR has a new logo. The
20
+ start screen and the sign-in box show it on a white tile in Day mode and on
21
+ a dark tile in Night mode, and only the matching file is loaded. The tab
22
+ icon, the toolbar colour and the installed app's icon and launch background
23
+ follow the Theme setting too (Android launchers get a full-bleed icon that
24
+ fills their shape), and the theme is applied before the first
25
+ paint, so Day mode no longer starts with a dark screen. On Android the
26
+ installed app's own launch screen updates when the system refreshes the
27
+ app, which can take a day.
28
+ - **The installed app starts in one motion.** The start screen continues the
29
+ phone's launch screen: the otter stands where and as large as the launch
30
+ screen showed it, then slides up and shrinks while *Connecting to OAR…*
31
+ fades in below. Without a stored token it travels on into the sign-in box,
32
+ which fades in around it. Launch screen, start screen and status bar share
33
+ one colour, so no plate shows around the logo. The app waits for the
34
+ animation (under a second); a browser tab starts at once as before, and so
35
+ does an installed app when motion is reduced in the system settings.
36
+ - **A compaction shows while it runs.** When a Claude session starts
37
+ compacting its context, a *Compacting context…* line appears above the
38
+ running turn and its bubble says *Compacting the conversation…*. When the
39
+ compaction ends, the same line becomes *Context compacted · 120k → 40k
40
+ tokens*; one that ends without a result leaves no line.
41
+ - **`oar start`, and `oar setup --start`.** `oar start` starts the relay of a
42
+ global install in the background, without a Copilot session tied to it
43
+ (through the systemd user service when one is installed), and prints the
44
+ relay URL. `oar setup --start` does the whole job without a question: where
45
+ a systemd user session exists it writes and enables the service and enables
46
+ lingering, elsewhere it starts the relay in the background. `oar setup
47
+ --port <port>` sets the port; a new config otherwise takes the first free
48
+ port from 3333 on.
49
+ - **The macOS and Linux installer does everything after one confirmation.**
50
+ `curl -fsSL oar.sh/install | sh` prints what it will do, asks once (`--yes`
51
+ skips the question), then installs OAR and starts the relay. Without
52
+ Node.js, or with one older than 22.13, it downloads Node.js 24 from
53
+ nodejs.org into `~/.oar/runtime/node` for OAR alone. Nothing needs root.
54
+
55
+ ### Changed
56
+
57
+ - **Scrollbars are easier to grab with a mouse.** A scrollbar doubles its
58
+ width while the pointer is on it and goes back to thin 2.5 seconds after
59
+ the pointer left. The space for the wide scrollbar is always kept, so
60
+ nothing on the page moves when it grows. Touch devices are unchanged.
61
+
62
+ - **The auto-compact window slider saves when the 🧠 modal closes.** Moving
63
+ it only changes the label and the notes beneath it; the value is saved
64
+ when the modal is closed, and setting it back sends nothing. A notice
65
+ warns when the new window is below what the conversation already uses
66
+ (*The conversation will be compacted on the next message.*), and another
67
+ says when the change takes effect: after the current turn, when
68
+ background work has finished, or on the next message. The modal's
69
+ headline reads `60.9k used · compaction window 100.0k · model limit 1M`.
70
+
71
+ ### Fixed
72
+
73
+ - **`oar start` no longer mistakes a leftover lock or another program for a
74
+ running relay.** It asks the relay itself: only an answer to OAR's own status
75
+ call with the configured token counts as running. A lock left behind by a
76
+ relay that did not stop cleanly is removed and the relay is started; if
77
+ another program holds the port, `oar start` says so and names
78
+ `oar setup --port`.
79
+ - **A new config no longer picks a port that is in use on Windows.** The
80
+ free-port check binds the loopback addresses as well as all interfaces and
81
+ tries a connection, since Windows allows a wildcard bind beside a listener
82
+ on 127.0.0.1 alone.
83
+ - **The compaction line survives a busy turn.** The live *Compacting context…*
84
+ / *Context compacted* line used to disappear after two dozen further
85
+ activity lines until the next reload.
86
+ - **The auto-compact slider is saved when the page closes.** Closing the tab
87
+ or the app with the context window still open used to drop a moved slider.
88
+
89
+ - **A "Compacting context…" line no longer stays on a waiting message.** When
90
+ the session compacted while a message waited behind a turn the agent had
91
+ opened itself, the line stayed on the waiting message for its whole turn.
92
+
93
+ - **A new auto-compact window now reaches a running Claude session.** The
94
+ CLI reads the window only when it starts, so a changed window used to wait
95
+ until the session restarted for some other reason. The session now
96
+ restarts once, before the next message, when nothing is running in it
97
+ (no turn, question, compaction or background work); the reply notes it
98
+ (*Restarted the session to apply the compaction window (Auto → 100k)*).
99
+ - **The installer no longer fails with `EACCES` on a Node.js from a
100
+ distribution or NodeSource package.** There npm's global folder needs root,
101
+ and the installer refuses to run as root, so the install could not succeed.
102
+ It now installs the package into `~/.oar/npm` and puts the `oar` command
103
+ into `~/.local/bin`.
104
+ - **Updates land in the install that is running.** `oar update` and the
105
+ **Update** button ran whatever `npm` was first on `PATH` into npm's default
106
+ global folder. They now run the npm of the Node.js that runs the relay, into
107
+ the folder the package is installed in, so an install made with `--prefix`,
108
+ a relay service without `npm` on its `PATH`, and a version manager pointing
109
+ at another Node.js all update correctly.
110
+ - **Installs and updates work on npm 12.** npm 12 runs no install script it
111
+ was not told to allow, so `better-sqlite3`, `koffi` and `cloudflared` were
112
+ installed without their binaries and the relay did not start. `oar update`,
113
+ the **Update** button and both installers now pass `--allow-scripts` for
114
+ these three; for a manual `npm install -g` the README gives the flag.
115
+ - **The systemd user service finds your tools.** The unit `oar setup` writes
116
+ now carries the `PATH` of the shell that ran it, plus `~/.local/bin` and the
117
+ directory of its Node.js. A user service otherwise starts with systemd's
118
+ bare `PATH`, on which the relay's sessions found neither the provider CLIs
119
+ nor, with a version manager, `node` itself.
120
+
121
+ ## [0.9.7] — 2026-10-03
122
+
123
+ Highlights: Claude Cloud chats (experimental, off by default) run Claude Code
124
+ in a sandbox at Anthropic on a GitHub repository; conversations can be
125
+ archived and have a context menu in the list; agents can start and use
126
+ sessions on the relay they run on; commits of Claude sessions say "Open
127
+ Agent Relay"; Check Usage opens at once.
128
+
129
+ ### Added
130
+
131
+ - **Archive conversations, and a context menu in the list.** Every
132
+ conversation row has an **Archive** button beside Delete (and the chat's
133
+ `⋯` menu an **Archive conversation** entry). An archived chat leaves the
134
+ list and its session worker is stopped; the 🗄 toggle at the top of the
135
+ sidebar shows the archived chats, each with **Unarchive**. A Claude Cloud
136
+ chat's cloud session is archived and unarchived at Anthropic with it. A
137
+ message into an archived chat (an agent's, say) brings it back by itself;
138
+ the composer of an archived chat says so instead of sending. A right-click
139
+ on a row — a long press on a phone — opens a menu with Open, Edit title,
140
+ Stop turn, Kill session, Archive/Unarchive and Delete.
141
+ - **Commits made from OAR say so.** Claude sessions now end their commit
142
+ messages with `Co-authored-by: Open Agent Relay (<model>) <no-reply@oar.sh>`
143
+ — the model's name in the parentheses, e.g. `Claude Fable 5.1` — and pull
144
+ request bodies with `🤖 Generated with [Open Agent Relay](https://oar.sh)`,
145
+ instead of Claude Code's own lines. Settings → Providers → Claude has the
146
+ choice: **OAR** (the default), **vanilla** (Claude Code's own attribution)
147
+ or **off** (none); a repo folder can override it from the 🧠 context modal
148
+ of any of its Claude sessions. A change reaches running sessions with their
149
+ next message. Claude Cloud chats follow the same setting: the sandbox gets
150
+ it with the first message and again when it changes, and in OAR mode the
151
+ `Claude-Session` link is left out of the commit as well. Other providers
152
+ are not touched: their tools have no such setting.
153
+ - **Claude Cloud (experimental): chats that run in a sandbox at Anthropic.**
154
+ A new provider, off by default. A Claude Cloud chat runs Claude Code in
155
+ Anthropic's cloud, on its own clone of a GitHub repository instead of on
156
+ the relay host. It is billed to the Claude account the host's Claude CLI
157
+ is logged in to, and its results come back as branches the agent pushes.
158
+ Switch it on in Settings → Providers → Claude Cloud and choose the cloud
159
+ environment and a default model there; it needs the Claude CLI logged in
160
+ with a claude.ai account on the relay host, GitHub connected to that
161
+ account, and the Claude GitHub app allowed on the repository.
162
+ - **New Chat** fills **Repository** and **Branch** from the folder you
163
+ pick, offers the repositories the Claude GitHub app can reach (the ones
164
+ used here before first) and the branches of the picked repository, lets
165
+ you type both, and warns about commits that are not pushed, changes
166
+ that are not committed and a repository the app cannot reach.
167
+ - **In the chat** the reply streams in live, the agent's questions and
168
+ permission prompts arrive as cards, **Stop** interrupts the turn, images
169
+ can be attached, and the model can be changed between turns. A line
170
+ above the composer links the session on claude.ai and every branch the
171
+ agent pushed to its comparison on GitHub, and shows the cost so far.
172
+ - **Turns** survive a restart of the worker or the relay without sending
173
+ your message twice. A turn stays open while the agent's background work
174
+ runs, a turn the session starts by itself (after long background work,
175
+ or from a message sent on claude.ai) appears as a reply of its own, and
176
+ a turn refused at the usage limit is paused until the reset like a
177
+ local Claude turn.
178
+ - **Commits** follow the relay's attribution setting (see above), and
179
+ deleting or archiving the chat archives the cloud session.
180
+ - **Not there:** relay modes, a reasoning effort, steering during a turn,
181
+ files other than images and anything else from the relay host, and the
182
+ relay's tools and previews inside the sandbox.
183
+ - **Before you switch it on:** the provider uses the Claude CLI's stored
184
+ login to call the Anthropic API endpoints the CLI itself uses. These
185
+ are not a documented public API and may change. OAR only reads the
186
+ token: it never stores or logs it and sends it nowhere but to
187
+ Anthropic; when it has run out, OAR lets the CLI refresh it. While the
188
+ provider is off the relay fetches nothing with that login, except for
189
+ cloud chats you created before. See "Claude Cloud" in the README.
190
+ `scripts/claude-cloud-live-check.mjs` checks a running relay's Claude
191
+ Cloud end to end.
192
+ - **Check Usage: live Claude limits and a Claude Cloud card.** With Claude
193
+ Cloud switched on, the Claude card reads the 5-hour, weekly and per-model
194
+ limits live from the account when you open the modal, instead of showing
195
+ the reading of your last Claude turn, and a limit that is getting close
196
+ carries Anthropic's warning. The card also shows which product the week
197
+ went to (Claude Code, chats and the others) and the organisation's prepaid
198
+ credits. The new Claude Cloud card shows the account's cloud credit (used,
199
+ left, and when it expires) and what the cloud chats on this relay have
200
+ cost as Anthropic reports it, in total and for the chat you opened the
201
+ modal from; a credit that is offered but not yet claimed is mentioned with
202
+ a link. The limit-reset vouchers (full reset, 5-hour reset) stay
203
+ claude.ai-only: no endpoint the CLI's login reaches carries them, so the
204
+ card links to the usage page instead. With Claude Cloud off, the Claude
205
+ card is what it was.
206
+ - **Agent sessions: an agent can hand parts of its task to other sessions on
207
+ the same relay.** The `remote_relay` tool now also works on the relay the
208
+ agent runs on: it starts sessions there, waits for them and reads their
209
+ replies, and each one is an ordinary conversation in your list. Off by
210
+ default; switch it on in Settings → Relays → Agent sessions (**Agents may
211
+ start and use sessions on this relay**). No relay has to be paired. The
212
+ first time the agent of a conversation starts a session, a card asks you
213
+ once for that conversation. At most 4 sessions it started may be at work at
214
+ the same time, a session that an agent created cannot start sessions
215
+ itself, and an agent cannot prompt, stop or archive the conversation it
216
+ runs in. A session can use any provider that is enabled on the relay
217
+ (image chats excepted); a Claude Cloud chat is started with the new `repo`
218
+ and `branch` arguments, and an agent on a paired relay can now start a
219
+ cloud chat here the same way. Sessions an agent starts use this relay's
220
+ accounts, show **via agent** with the title of the conversation they came
221
+ from in the sidebar and the header (a click opens it), and are never
222
+ archived automatically. The new
223
+ **Longest wait per tool call** slider in the same place sets how long one
224
+ call may wait for a reply: 10 minutes as before, up to 60; it applies to
225
+ waits on paired relays too. See "Agent sessions" in the README.
226
+
227
+ ### Changed
228
+
229
+ - **Check Usage opens at once.** The modal shows the reading it showed last
230
+ time immediately and reads only the open tab's provider live (the card says
231
+ "updating…" meanwhile), instead of fetching every provider and showing a
232
+ spinner until the slowest answered. A tab you switch to is read live when
233
+ its reading is older than a minute; **Refresh** reads the open tab only.
234
+ The relay keeps the last live answer of every provider, so the other cards
235
+ stay filled (`GET /api/usage?providers=…`).
236
+ - **Windows: the relay no longer stops while it reads the process list.**
237
+ Before every launch, every kill and every check of a worker that went
238
+ quiet, the relay reads the list of all processes through PowerShell. It
239
+ did so synchronously: half a second to a second and a half on an idle
240
+ machine, several seconds under load, during which the relay answered
241
+ nothing — under CI load that was enough for the tunnel to report 502 for
242
+ the whole relay. The list is now read off the relay's thread; callers that
243
+ ask at the same time share one read, and a read is reused for 1.5 s. A
244
+ worker that went quiet is checked by its pid first and by the list last.
245
+ `GET /api/status` → `sessionWorker.processList` shows when the list was
246
+ last read, how long it took and whether it failed; a read slower than two
247
+ seconds is logged. A kill or a workspace relaunch that cannot read the
248
+ list answers 409 with the reason instead of failing with 500 or stopping
249
+ blind.
250
+
251
+ ### Fixed
252
+
253
+ - **A reply that names an error code is a reply.** A reply a session
254
+ worker published was read as a failed turn when its one paragraph led up
255
+ to "Error code: relay.…" — a short report on a test that had failed with
256
+ that code, for instance. Workers always send the failure as a record, so
257
+ their replies are no longer read for one; the page's fix buttons under a
258
+ failure follow the same rule and no longer appear under a reply that
259
+ mentions a code in a quotation, a code span, a table or a list.
260
+ - **Two prices in one paragraph were shown as a formula.** In a reply such
261
+ as `this run cost $4.20, the earlier one $3.80`, everything between the
262
+ two dollar signs was rendered as maths. A dollar sign now starts a formula
263
+ only when it is written the way inline maths is: no space after the
264
+ opening sign, no space before the closing one, and no digit right after
265
+ it. Prices stay text; `$x^2$` is still maths. A wide inline formula also
266
+ no longer makes the whole message scroll sideways: it stays inside the
267
+ bubble and scrolls within itself.
268
+
269
+ - **Windows: no worker could start once an agent had run a command with an
270
+ arrow or a bullet in it.** Before every launch the relay reads the list of
271
+ all processes through PowerShell. Under the console's OEM code page
272
+ PowerShell wrote characters such as `→` and `•` as control bytes, the list
273
+ stopped being valid JSON, and every launch on the relay failed: each session
274
+ you wrote to turned yellow after six tries and stayed so, for every
275
+ provider, until the relay was restarted. The list is now written as UTF-8, a
276
+ control byte that still gets through is tolerated, a list the relay cannot
277
+ read no longer stops a launch, and a session whose launches were exhausted
278
+ is tried once more every minute instead of waiting for a restart.
279
+ - **A session whose worker cannot be started now says so.** Until now such a
280
+ session showed a yellow dot and nothing else. The relay now writes one note
281
+ into the conversation — why the worker could not be started, in one
282
+ sentence plus the cause — and keeps that same note up to date: it tries
283
+ again every minute for ten minutes, then stops and the note gets a
284
+ **Retry** button for once the cause is fixed; when the worker starts, the
285
+ note says so. Your message stays queued the whole time, and a queued
286
+ restart of the relay no longer waits for a message the relay has stopped
287
+ trying to deliver.
288
+ - **The Claude usage card showed extra-usage credits 100 times too high.**
289
+ Claude reports these amounts in the currency's minor units (cents), and
290
+ the card showed them as dollars: 12.50 used of a 50.00 limit read as 1250
291
+ of 5000. The percentage was right.
292
+
8
293
  ## [0.9.6] — 2026-09-29
9
294
 
10
295
  Highlights: a Claude turn pauses at the usage limit and carries on after the