@oar-sh/oar 0.9.7 → 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 (38) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +46 -18
  3. package/bin/oar.js +320 -18
  4. package/package.json +1 -1
  5. package/server/claude-worker/claude-sdk-adapter.mjs +0 -11
  6. package/server/claude-worker/claude-session-process.mjs +196 -28
  7. package/server/claude-worker/sdk-message-normalizer.mjs +28 -0
  8. package/server/public/app/activity-replay-state.mjs +68 -5
  9. package/server/public/app/api-client.js +6 -2
  10. package/server/public/app/bootstrap.js +124 -57
  11. package/server/public/app/context-usage-view.mjs +127 -8
  12. package/server/public/app/conversation-view.js +62 -7
  13. package/server/public/app/pwa-install.js +5 -0
  14. package/server/public/app/scrollbar-hover.mjs +78 -0
  15. package/server/public/app/settings-modal.js +4 -1
  16. package/server/public/app/socket-handlers.js +2 -1
  17. package/server/public/app/store.js +26 -0
  18. package/server/public/app/transcript-separators.mjs +48 -11
  19. package/server/public/app-icon-192.png +0 -0
  20. package/server/public/app-icon-512.png +0 -0
  21. package/server/public/app-icon-light-192.png +0 -0
  22. package/server/public/app-icon-light-512.png +0 -0
  23. package/server/public/app-icon-light-maskable-512.png +0 -0
  24. package/server/public/app-icon-light.svg +4 -0
  25. package/server/public/app-icon-maskable-512.png +0 -0
  26. package/server/public/app-icon.svg +3 -3
  27. package/server/public/favicon.ico +0 -0
  28. package/server/public/index.html +183 -13
  29. package/server/public/manifest.webmanifest +9 -3
  30. package/server/public/sw.js +6 -1
  31. package/server/routes/messages-routes.mjs +3 -1
  32. package/server/routes/sessions-routes.mjs +15 -2
  33. package/server/server-runtime.mjs +10 -8
  34. package/server/services/claude-context-usage.mjs +51 -3
  35. package/server/services/oar-cli-helpers.mjs +67 -1
  36. package/server/services/pwa-manifest-theme.mjs +30 -0
  37. package/server/services/session-worker-registry-service.mjs +18 -1
  38. package/server/services/update-install-service.mjs +9 -3
package/CHANGELOG.md CHANGED
@@ -5,6 +5,119 @@ 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
+
8
121
  ## [0.9.7] — 2026-10-03
9
122
 
10
123
  Highlights: Claude Cloud chats (experimental, off by default) run Claude Code
package/README.md CHANGED
@@ -1,3 +1,10 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="server/public/app-icon.svg">
4
+ <img src="server/public/app-icon-light.svg" alt="The OAR logo: an otter standing upright" width="120" height="120">
5
+ </picture>
6
+ </p>
7
+
1
8
  # OAR — Open Agent Relay
2
9
 
3
10
  Drive the coding agents on your machine from any browser (phone, tablet, or a second computer) through a self-hosted web relay.
@@ -29,23 +36,23 @@ OAR is under active development, so expect occasional rough edges and some provi
29
36
  <table>
30
37
  <tr>
31
38
  <td width="42%" rowspan="3" valign="top">
32
- <a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.3"><img src="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.3" alt="OAR on a phone: a finished agent turn in a conversation, with the composer below"></a>
39
+ <a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.8"><img src="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.8" alt="OAR on a phone: a finished agent turn in a conversation, with the composer below"></a>
33
40
  <br><sub>On a phone: the same conversations, installable as an app.</sub>
34
41
  </td>
35
42
  <td width="58%" valign="top">
36
- <a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.3"><img src="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.3" alt="Background subagents running in parallel in the task panel, each with live token counts, elapsed time, and its own Stop button"></a>
43
+ <a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.8"><img src="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.8" alt="Background subagents running in parallel in the task panel, each with live token counts, elapsed time, and its own Stop button"></a>
37
44
  <br><sub>Agents working in parallel, each with live token counts and its own Stop.</sub>
38
45
  </td>
39
46
  </tr>
40
47
  <tr>
41
48
  <td valign="top">
42
- <a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.3"><img src="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.3" alt="A question card in the middle of a turn: the agent offers several choices and a free-text reply"></a>
49
+ <a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.8"><img src="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.8" alt="A question card in the middle of a turn: the agent offers several choices and a free-text reply"></a>
43
50
  <br><sub>When the agent needs a decision, it asks, and waits for your answer.</sub>
44
51
  </td>
45
52
  </tr>
46
53
  <tr>
47
54
  <td valign="top">
48
- <a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.3"><img src="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.3" alt="An expanded Thoughts block showing the agent's reasoning above its reply"></a>
55
+ <a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.8"><img src="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.8" alt="An expanded Thoughts block showing the agent's reasoning above its reply"></a>
49
56
  <br><sub>Read the reasoning, not just the answer.</sub>
50
57
  </td>
51
58
  </tr>
@@ -61,7 +68,7 @@ You need Node.js plus whatever the runtimes you actually use need. Nothing else
61
68
 
62
69
  | Requirement | Needed for | Notes |
63
70
  | ----------- | ---------- | ----- |
64
- | Node.js 22.13 or newer | always | Both installers check this. Running the development test suite needs Node 24 (see [DEVELOPING.md](DEVELOPING.md#node-version)) |
71
+ | Node.js 22.13 or newer | always | The macOS and Linux installer fetches its own copy when yours is missing or too old; the Windows installer only checks. Running the development test suite needs Node 24 (see [DEVELOPING.md](DEVELOPING.md#node-version)) |
65
72
  | GitHub Copilot CLI (`copilot`), signed in | Copilot and OpenAI (BYOK) chats | Install it with `npm install -g @github/copilot`, then run `copilot` once on the relay host and sign in. The relay looks for the CLI's runtime when it starts, so restart the relay after installing or upgrading the CLI. Needs a GitHub Copilot plan that includes Copilot CLI |
66
73
  | GitHub CLI (`gh`), signed in | the `oar` launcher command; Extension-engine sessions on Windows; the Copilot card in **Check Usage** | `gh copilot` is built into current GitHub CLI releases, so there is no extension to install. The usage card also accepts a token in `GH_TOKEN` or `GITHUB_TOKEN` |
67
74
  | OpenAI API key | OpenAI and OpenAI Image chats | Entered in **⚙️ Settings**, stored in the relay database |
@@ -77,12 +84,27 @@ You need Node.js plus whatever the runtimes you actually use need. Nothing else
77
84
  curl -fsSL oar.sh/install | sh
78
85
  ```
79
86
 
80
- The script checks for Node.js 22.13 or newer, runs `npm install -g @oar-sh/oar`, and then hands off to `oar setup` (with `--defaults` when there is no terminal to ask questions in). It refuses to run as root, because OAR installs per user. `OAR_VERSION=x.y.z` pins a version, `OAR_CHANNEL=beta` follows the beta channel, and `OAR_DRY_RUN=1` only prints what it would do:
87
+ The script looks at what the machine has, prints what it is about to do, and asks once. After a yes it installs OAR, writes the config with a fresh auth token, starts the relay, and prints the relay URL with a QR code. Nothing needs root (it refuses to run as root, because OAR installs per user), and everything lands in your home directory:
88
+
89
+ | The machine has | What the installer does |
90
+ | --------------- | ----------------------- |
91
+ | Node.js 22.13 or newer whose global npm folder you can write (nvm, fnm, Homebrew, a user prefix) | `npm install -g @oar-sh/oar`, as you would by hand |
92
+ | Node.js 22.13 or newer whose global npm folder needs root (a distribution or NodeSource package) | Installs the package into `~/.oar/npm` with your Node.js and puts an `oar` command into `~/.local/bin`. Your npm setup is not changed |
93
+ | No Node.js, or an older one | Downloads the current Node.js 24 from nodejs.org into `~/.oar/runtime/node` (checksum verified, about 30 MB), installs the package into `~/.oar/npm` with it, and puts an `oar` command into `~/.local/bin`. Only OAR uses that Node.js; one of your own stays first on `PATH` |
94
+
95
+ When it puts the command into `~/.local/bin` and that folder is not on your `PATH`, it adds one line to your shell's startup file (`~/.bashrc`, `~/.zshrc`, or `~/.profile`) and says so.
96
+
97
+ The relay is started as a systemd user service where a systemd user session exists, with lingering enabled, so it is back after a reboot and keeps running while you are logged out. Elsewhere (macOS, containers, WSL without systemd) it is started in the background; after a reboot, `oar start` starts it again.
98
+
99
+ `--yes` skips the question, for scripts and CI; without a terminal to ask on, the installer stops and says so. `OAR_VERSION=x.y.z` pins a version, `OAR_CHANNEL=beta` follows the beta channel, `OAR_PORT=n` sets the relay port, `OAR_NODE=private` uses OAR's own Node.js even when yours would do, and `OAR_DRY_RUN=1` only prints the plan:
81
100
 
82
101
  ```bash
83
- curl -fsSL oar.sh/install | OAR_VERSION=0.9.6 sh
102
+ curl -fsSL oar.sh/install | sh -s -- --yes
103
+ curl -fsSL oar.sh/install | OAR_VERSION=0.9.8 OAR_PORT=3400 sh
84
104
  ```
85
105
 
106
+ The installer needs `curl` or `wget`, and `tar` when it fetches Node.js. It has no Node.js build for musl systems (Alpine) or for CPUs other than x64 and arm64; there, install Node.js yourself first. Releases before 0.9.8 are installed the same way, but their `oar setup` cannot start the relay: see [Start the relay](#start-the-relay).
107
+
86
108
  Read it before you run it: [oar.sh/install](https://oar.sh/install).
87
109
 
88
110
  ### Windows
@@ -91,15 +113,17 @@ Read it before you run it: [oar.sh/install](https://oar.sh/install).
91
113
  irm oar.sh/install.ps1 | iex
92
114
  ```
93
115
 
94
- The PowerShell installer (PowerShell 5 or newer) does the same: it checks Node.js, runs `npm install -g @oar-sh/oar`, then `oar setup`. It reads the same `OAR_VERSION`, `OAR_CHANNEL`, and `OAR_DRY_RUN` variables, for example `$env:OAR_VERSION = '0.9.6'` before the command.
116
+ The PowerShell installer (PowerShell 5 or newer) expects Node.js 22.13 or newer to be installed: it checks Node.js, runs `npm install -g @oar-sh/oar`, then `oar setup`. It reads the same `OAR_VERSION`, `OAR_CHANNEL`, and `OAR_DRY_RUN` variables, for example `$env:OAR_VERSION = '0.9.6'` before the command.
95
117
 
96
118
  ### npm
97
119
 
98
120
  ```bash
99
- npm install -g @oar-sh/oar
121
+ npm install -g --allow-scripts=better-sqlite3,cloudflared,koffi @oar-sh/oar
100
122
  oar setup
101
123
  ```
102
124
 
125
+ npm 12 runs no install script it was not told to allow, and three of OAR's dependencies fetch their native binary in one; without `--allow-scripts` the install succeeds there and the relay then fails to start. npm 10 and 11 accept the flag and need none. The installers and `oar update` pass it themselves.
126
+
103
127
  ### From a git checkout
104
128
 
105
129
  ```bash
@@ -126,13 +150,14 @@ Development workflows, tests, and relay internals are in [DEVELOPING.md](DEVELOP
126
150
 
127
151
  ### Start the relay
128
152
 
129
- `oar setup` creates the config and prints the relay URL with a QR code, but it does not start the relay. Pick one:
153
+ The macOS and Linux installer starts the relay itself. After a manual install, `oar setup` creates the config and prints the relay URL with a QR code, but it does not start the relay unless you pass `--start`. Pick one:
130
154
 
131
- - **Linux (global install):** accept the systemd user service that `oar setup` offers, then run `systemctl --user enable --now oar`. The relay then starts when you log in; run `loginctl enable-linger "$USER"` once if it should keep running while you are logged out.
155
+ - **Any global install on macOS or Linux:** `oar start` starts the relay in the background (through the systemd user service when one is installed) and prints the relay URL. `oar setup --defaults --start` is what the installer runs: it also installs and enables the systemd user service where a systemd user session exists, and enables lingering.
156
+ - **Linux (global install), by hand:** accept the systemd user service that `oar setup` offers, then run `systemctl --user enable --now oar`. The relay then starts when you log in; run `loginctl enable-linger "$USER"` once if it should keep running while you are logged out. The unit carries the `PATH` of the shell that ran `oar setup`, plus `~/.local/bin`, so the relay's sessions find the tools you have; rerun `oar setup` after your `PATH` changed.
132
157
  - **Windows:** start the relay once with `oar`, then choose **⚙️ Settings → General → Autostart (Windows)**: *At sign-in* opens a visible terminal after you log on, and *At system startup* runs it headless before anyone signs in, after one admin confirmation on the PC itself.
133
158
  - **Any platform:** `oar` starts the relay in the background if it is not already running, then opens the Copilot CLI (`gh copilot`) in the same shell. A relay that `oar` started stops again when that Copilot session ends, and `oar` needs the GitHub CLI.
134
159
 
135
- To run only the relay from a global install, without a Copilot session, start the server the way the systemd unit does:
160
+ To run the relay of a global install in the foreground, start the server the way the systemd unit does:
136
161
 
137
162
  ```bash
138
163
  COPILOT_WEB_RELAY_CONFIG="$HOME/.oar/config.json" \
@@ -154,14 +179,15 @@ Then open the URL that `oar setup` printed, or scan its QR code. With `localhost
154
179
  | `oar --port <port>` | Finds or starts the relay on `<port>` for this run, overriding the config's `port` without changing the file; a config this command creates saves it. Without it, `oar` uses the config's `port` (default `3333`) |
155
180
  | `oar --migrate-from <dir>` | Global installs: copies the relay state of a pre-rename git checkout at `<dir>` into the OAR state root, once. The source is never moved or changed, and a relay still running from it blocks the copy. `oar setup` accepts the same option |
156
181
  | `oar --install-extension` | Writes or refreshes the user-global Copilot CLI extension wrapper in `~/.copilot/extensions/web-relay/`, then exits. Plain `oar` does this on every run; `--no-install-extension` skips it |
157
- | `oar setup [--defaults]` | Creates or updates the config: generates an auth token (with a config already present it offers a new one, which signs every device out), asks whether a new config should allow LAN access and whether to enable the managed Cloudflare tunnel, offers the systemd user service on Linux global installs, then prints the relay URL and a QR code. An existing config keeps its `localhostOnly` value. `--defaults` accepts every default without asking |
182
+ | `oar setup [--defaults] [--start] [--port <port>]` | Creates or updates the config: generates an auth token (with a config already present it offers a new one, which signs every device out), asks whether a new config should allow LAN access and whether to enable the managed Cloudflare tunnel, offers the systemd user service on Linux global installs, then prints the relay URL and a QR code. An existing config keeps its `localhostOnly` value. `--defaults` accepts every default without asking. `--port` sets the relay port; without it a new config takes the first free port from 3333 on, and an existing config keeps its port. `--start` (global installs) also gets the relay running without a question: with a systemd user session it writes and enables the service and enables lingering, elsewhere it starts the relay in the background; a relay that is already running is left alone |
183
+ | `oar start` | Global installs: starts the relay in the background without a Copilot session, through the systemd user service when one is installed, and prints the relay URL. A relay that is already running is left alone |
158
184
  | `oar doctor` | Prints the version, Node.js, install mode, state root, config path, port, whether an auth token is set, the tunnel mode, the database path and size, and which provider CLIs (`gh`, `claude`, `grok`) answer. It changes nothing |
159
- | `oar update [--beta] [--to X.Y.Z]` | Global installs: looks up the newest release of your channel in `https://oar.sh/latest.json` (`--beta` for the beta channel), installs it with `npm install -g`, and asks a running relay to restart once no turn is running. `--to X.Y.Z` installs that version straight from npm, which works even when `OAR_NO_UPDATE_CHECK=1` blocks the lookup |
185
+ | `oar update [--beta] [--to X.Y.Z]` | Global installs: looks up the newest release of your channel in `https://oar.sh/latest.json` (`--beta` for the beta channel), installs it with `npm install -g` (the npm of the Node.js that runs `oar`, into the folder the package is installed in), and asks a running relay to restart once no turn is running. `--to X.Y.Z` installs that version straight from npm, which works even when `OAR_NO_UPDATE_CHECK=1` blocks the lookup |
160
186
  | `oar --version`, `oar --help` | Prints the version, or the usage |
161
187
 
162
188
  ### Where OAR keeps its files
163
189
 
164
- A global install keeps its state in `~/.oar` (`%APPDATA%\oar` on Windows; `OAR_STATE_ROOT` moves it): `config.json`, `data/` (the database and uploads), and `logs/` (`server.log` when `oar` started the relay, and a `worker-<session>.log` per Node session worker). `npm install -g` updates never touch it. A git checkout uses `server/config.json`, `server/data/`, `server/uploads/`, and `server/logs/` instead.
190
+ A global install keeps its state in `~/.oar` (`%APPDATA%\oar` on Windows; `OAR_STATE_ROOT` moves it): `config.json`, `data/` (the database and uploads), and `logs/` (`server.log` when `oar` started the relay, and a `worker-<session>.log` per Node session worker). `npm install -g` updates never touch it. The macOS and Linux installer may add two folders there that are not state: `npm/` (the package, when npm's own global folder was not writable) and `runtime/node/` (OAR's own Node.js, when the machine had none new enough). A git checkout uses `server/config.json`, `server/data/`, `server/uploads/`, and `server/logs/` instead.
165
191
 
166
192
  `COPILOT_WEB_RELAY_CONFIG`, `COPILOT_WEB_RELAY_DATA_DIR`, and `COPILOT_WEB_RELAY_LOG_DIR` override the config file, the data directory, and the log directory. `oar doctor` prints the paths in use.
167
193
 
@@ -440,7 +466,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
440
466
  - Question cards for clarification: one-click choices, multi-select checkmarks, free text, and multi-field structured forms validated against their JSON schema
441
467
  - Mathematical and scientific notation rendering for TeX/LaTeX equations and chemical formulas, written as `$…$`, `\(…\)`, `$$…$$` or `\[…\]`. A single `$` opens a formula only when a non-space character follows it directly and the next `$` has a non-space character directly before it and no digit directly after it (a digit is allowed after something that looks like TeX, as in `$x^2$3`), so prices such as `$5 and $9` stay text
442
468
  - **Context usage** modal with a per-category token breakdown of the model's context window, plus a per-conversation **auto-compact window** slider for Claude sessions
443
- - **Transcript breaks**: day separators, a marker where a Claude session auto-compacted its context, and matching dots beside the scrollbar
469
+ - **Transcript breaks**: day separators, a marker where a Claude session auto-compacted its context (shown while the compaction runs), and matching dots beside the scrollbar
444
470
  - **Plan usage** modal with subscription credits, rate-limit windows, and reset countdowns for Copilot, Claude, Claude Cloud, Cursor, and Grok
445
471
  - **Image conversations** (OpenAI Image): generate images in chat and iterate on a generated image with **Edit this image**
446
472
  - Agents can embed **images, video, and audio** in a reply by their absolute path, on every runtime; clicking an embedded image opens the file viewer with zoom, download, and copy
@@ -525,8 +551,8 @@ The composer draft, attachments included, is saved per conversation on the relay
525
551
  - **Grok** — the live weekly subscription quota, read with the host's Grok CLI login, plus per-turn tokens and estimated cost from the agent's prompt result. An optional monthly USD allowance in Settings adds an estimated remaining meter; the card is hidden when Grok is disabled. Billing: [console.x.ai](https://console.x.ai).
526
552
  - Per-reply usage lines are recorded only for Copilot turns — OpenAI, Claude, Claude Cloud, Cursor, and Grok turns do not consume Copilot premium requests, and no usage line is attached to them.
527
553
  - Use the **🧠** context button for a per-category breakdown of the conversation's context window (Claude sessions also show the auto-compact window, the thinking controls and the folder's commit attribution there): a usage bar, a token/percentage table, and free space. Claude sessions report exact SDK categories; Copilot sessions show the coarser system/tools + messages + buffer split, labelled as a lower-bound estimate when the runtime no longer emits full buckets. A Claude Cloud session reports how much of its window is used after each turn, without categories.
528
- - Claude conversations additionally get an **auto-compact window** slider in that modal. Claude Code compacts a session once it approaches a model-tuned window (around 967k tokens on a 1M-context model), which is why long conversations rarely compact at all; setting a smaller window makes it happen sooner and keeps turns cheaper. *Auto* hands the choice back to the CLI. The smallest window is 100k, because the CLI silently ignores anything below that and falls back to its own default. The line beneath the slider reports the window actually in force and where it came from — your setting, the model default, or the `CLAUDE_CODE_AUTO_COMPACT_WINDOW` environment override — and fills in once the conversation's first turn completes. The change reaches a running session on its next message.
529
- - The transcript marks day boundaries, and marks the point where a Claude session compacted its context with the tokens before and after. Both appear as dots beside the scrollbar for the messages currently loaded.
554
+ - Claude conversations additionally get an **auto-compact window** slider in that modal. Claude Code compacts a session once it approaches a model-tuned window (around 967k tokens on a 1M-context model), which is why long conversations rarely compact at all; setting a smaller window makes it happen sooner and keeps turns cheaper. *Auto* hands the choice back to the CLI. The smallest window is 100k, because the CLI silently ignores anything below that and falls back to its own default. The line beneath the slider reports the window actually in force and where it came from — your setting, the model default, or the `CLAUDE_CODE_AUTO_COMPACT_WINDOW` environment override — and fills in once the conversation's first turn completes. The slider is saved when the modal closes. Claude Code reads the window only when a session starts, so a running session restarts once, before the next message, to pick up a new one; while a turn or background work is running the change waits, and the note under the slider says for what. A window below what the conversation already uses compacts it on the next message, which the slider warns about. The modal's headline shows the tokens in use, the compaction window and, when known, the model's own limit.
555
+ - The transcript marks day boundaries, and marks the point where a Claude session compacted its context with the tokens before and after. While a compaction runs, the line reads *Compacting context…* and the turn's bubble says so; it turns into the final line when the compaction ends. Both kinds appear as dots beside the scrollbar for the messages currently loaded.
530
556
 
531
557
  ### Sharing
532
558
 
@@ -898,6 +924,8 @@ under **General** (60 minutes by default), which does not know about the wait.
898
924
  | A conversation will not delete | It is still working: a running turn, one waiting on a question card or approval, or live background tasks. Stop it, then delete |
899
925
  | A conversation seems wedged | **☠️ Kill session** in the `⋯` menu stops its worker; retry the turn or send a new message |
900
926
  | **🌄 Restart web relay** fails with *localhost-only* | The restart endpoint accepts loopback connections only: use it on the relay host or through a tunnel, not over a direct LAN connection |
927
+ | `npm install -g @oar-sh/oar` fails with `EACCES` | npm's global folder needs root (a distribution or NodeSource Node.js). Do not use `sudo`; run the installer (`curl -fsSL oar.sh/install \| sh`), which installs into `~/.oar/npm` instead |
928
+ | The relay does not start after an install with npm 12 (a `better-sqlite3` error in `server-err.log`) | npm 12 skipped the install scripts of OAR's native dependencies. Reinstall with `npm install -g --allow-scripts=better-sqlite3,cloudflared,koffi @oar-sh/oar` |
901
929
  | `npm install -g @oar-sh/oar` fails with node-gyp or prebuild errors | `better-sqlite3` has no prebuilt binary for your platform; install a C/C++ build toolchain and Python, then retry |
902
930
  | No usage line under a reply | Expected for OpenAI, Claude, Claude Cloud, Cursor, and Grok turns; only Copilot turns record plan usage |
903
931