@oar-sh/oar 0.9.8 → 0.9.10
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.
- package/CHANGELOG.md +478 -0
- package/README.md +129 -39
- package/bin/bat/oar.bat +46 -46
- package/bin/oar.js +814 -228
- package/package.json +5 -6
- package/server/README.md +306 -4
- package/server/claude-worker/claude-remote-relay-tool.mjs +10 -0
- package/server/claude-worker/claude-session-process.mjs +35 -1
- package/server/claude-worker/claude-turn-publisher.mjs +3 -0
- package/server/claude-worker/sdk-message-normalizer.mjs +31 -4
- package/server/claude-worker/subagent-timeline-recorder.mjs +572 -0
- package/server/copilot-worker/copilot-sdk-session-process.mjs +3 -1
- package/server/cursor-worker/cursor-sdk-adapter.mjs +56 -2
- package/server/db-schema.mjs +44 -0
- package/server/migrations/0008-message-pins.mjs +85 -0
- package/server/migrations/0009-subagent-timeline.mjs +135 -0
- package/server/migrations/0010-subagent-timeline-pruning.mjs +89 -0
- package/server/migrations/0011-relay-event-subscriptions.mjs +125 -0
- package/server/migrations/0012-cross-relay-event-subscriptions.mjs +116 -0
- package/server/public/app/agent-exchange-fold-view.mjs +248 -0
- package/server/public/app/api-client.js +91 -0
- package/server/public/app/archive-confirm.mjs +28 -0
- package/server/public/app/ask-user-view.js +3 -0
- package/server/public/app/attachments-view.js +1024 -131
- package/server/public/app/back-guard.mjs +58 -0
- package/server/public/app/background-tasks-view.mjs +18 -26
- package/server/public/app/bootstrap.js +230 -35
- package/server/public/app/chat-actions-menu-state.mjs +116 -0
- package/server/public/app/claude-cloud-conversation-ui.js +10 -22
- package/server/public/app/composer-control-state.mjs +16 -0
- package/server/public/app/composer-keyboard.mjs +54 -0
- package/server/public/app/conversation-view.js +471 -110
- package/server/public/app/explorer-edit-state.mjs +68 -0
- package/server/public/app/external-link-policy.mjs +4 -1
- package/server/public/app/file-version.mjs +58 -0
- package/server/public/app/host-suspend-ui.js +6 -3
- package/server/public/app/journal-view.js +161 -27
- package/server/public/app/no-conversation-state.mjs +58 -0
- package/server/public/app/pinned-messages-view.mjs +253 -0
- package/server/public/app/provider-readiness.mjs +120 -0
- package/server/public/app/pwa-install.js +1 -1
- package/server/public/app/relay-board-view.js +3 -0
- package/server/public/app/relay-dot-state.mjs +8 -1
- package/server/public/app/relay-event-subscriptions-ui.js +184 -0
- package/server/public/app/relay-event-view.mjs +234 -0
- package/server/public/app/router.js +8 -2
- package/server/public/app/settings-modal.js +53 -1
- package/server/public/app/socket-handlers.js +65 -28
- package/server/public/app/store.js +25 -2
- package/server/public/app/subagent-row.mjs +138 -0
- package/server/public/app/subagent-timeline-view.mjs +186 -0
- package/server/public/app/subagent-viewer-watch.mjs +50 -0
- package/server/public/app/subagent-viewer.mjs +534 -0
- package/server/public/app/task-row-format.mjs +29 -0
- package/server/public/app/thinking-follow.js +4 -0
- package/server/public/app/transcript-jump-bottom-view.mjs +290 -0
- package/server/public/app/transcript-jump-bottom.mjs +99 -0
- package/server/public/app/transcript-reload-freshness.mjs +25 -0
- package/server/public/app/update-ui.js +1 -1
- package/server/public/app/viewer-chat-gallery.mjs +59 -0
- package/server/public/app/viewer-controls-state.mjs +59 -0
- package/server/public/app/viewer-gallery.mjs +46 -0
- package/server/public/app/viewer-gestures.mjs +105 -0
- package/server/public/app/viewer-history.mjs +45 -0
- package/server/public/app/viewer-tap.mjs +112 -0
- package/server/public/index.html +700 -59
- package/server/repositories/message-pin-statements.mjs +39 -0
- package/server/repositories/message-repository.mjs +34 -3
- package/server/repositories/question-repository.mjs +9 -3
- package/server/repositories/remote-relay-repository.mjs +6 -2
- package/server/repositories/subagent-timeline-statements.mjs +170 -0
- package/server/routes/ask-user-routes.mjs +3 -0
- package/server/routes/messages-routes.mjs +548 -111
- package/server/routes/relay-event-routes.mjs +157 -0
- package/server/routes/remote-relay-routes.mjs +15 -0
- package/server/routes/sessions-routes.mjs +164 -24
- package/server/server-runtime.mjs +274 -62
- package/server/services/cloudflared-tunnel-service.mjs +139 -41
- package/server/services/explorer-entry-name.mjs +26 -0
- package/server/services/explorer-mutations.mjs +122 -0
- package/server/services/file-serving.mjs +155 -0
- package/server/services/message-pin-list.mjs +52 -0
- package/server/services/oar-cli-helpers.mjs +139 -4
- package/server/services/oar-cli-menu.mjs +240 -0
- package/server/services/oar-cli-wsl.mjs +129 -0
- package/server/services/preview-proxy-server.mjs +41 -23
- package/server/services/push-dispatch-service.mjs +18 -0
- package/server/services/relay-event-link-service.mjs +289 -0
- package/server/services/relay-event-service.mjs +1935 -0
- package/server/services/relay-shutdown-gate.mjs +31 -0
- package/server/services/remote-relay-caller-context.mjs +52 -7
- package/server/services/remote-relay-dispatcher.mjs +494 -2
- package/server/services/remote-relay-registry-service.mjs +11 -1
- package/server/services/safe-served-content.mjs +61 -11
- package/server/services/session-activity-tracker.mjs +487 -0
- package/server/services/session-history-refresh-service.mjs +31 -0
- package/server/services/stale-attempt-log-limiter.mjs +96 -0
- package/server/services/stale-recovery-clock-guard.mjs +57 -0
- package/server/services/stale-subagent-run-sweep.mjs +109 -0
- package/server/services/subagent-record-retention.mjs +164 -0
- package/server/services/subagent-timeline-service.mjs +328 -0
- package/server/services/subagent-viewer-rooms.mjs +119 -0
- package/server/services/upgrade-socket-guard.mjs +16 -0
- package/shared/relay-events.mjs +371 -0
- package/shared/remote-relay-contract.mjs +157 -5
- package/shared/subagent-record-retention.mjs +31 -0
- package/shared/subagent-timeline.mjs +79 -0
package/README.md
CHANGED
|
@@ -35,27 +35,33 @@ OAR is under active development, so expect occasional rough edges and some provi
|
|
|
35
35
|
|
|
36
36
|
<table>
|
|
37
37
|
<tr>
|
|
38
|
-
<td width="42%" rowspan="
|
|
39
|
-
<a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.
|
|
38
|
+
<td width="42%" rowspan="4" valign="top">
|
|
39
|
+
<a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.10"><img src="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.10" alt="OAR on a phone: a finished agent turn in a conversation, with the composer below"></a>
|
|
40
40
|
<br><sub>On a phone: the same conversations, installable as an app.</sub>
|
|
41
41
|
</td>
|
|
42
42
|
<td width="58%" valign="top">
|
|
43
|
-
<a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.
|
|
43
|
+
<a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.10"><img src="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.10" alt="Background subagents running in parallel in the task panel, each with live token counts, elapsed time, and its own Stop button"></a>
|
|
44
44
|
<br><sub>Agents working in parallel, each with live token counts and its own Stop.</sub>
|
|
45
45
|
</td>
|
|
46
46
|
</tr>
|
|
47
47
|
<tr>
|
|
48
48
|
<td valign="top">
|
|
49
|
-
<a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.
|
|
49
|
+
<a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.10"><img src="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.10" alt="A question card in the middle of a turn: the agent offers several choices and a free-text reply"></a>
|
|
50
50
|
<br><sub>When the agent needs a decision, it asks, and waits for your answer.</sub>
|
|
51
51
|
</td>
|
|
52
52
|
</tr>
|
|
53
53
|
<tr>
|
|
54
54
|
<td valign="top">
|
|
55
|
-
<a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.
|
|
55
|
+
<a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.10"><img src="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.10" alt="An expanded Thoughts block showing the agent's reasoning above its reply"></a>
|
|
56
56
|
<br><sub>Read the reasoning, not just the answer.</sub>
|
|
57
57
|
</td>
|
|
58
58
|
</tr>
|
|
59
|
+
<tr>
|
|
60
|
+
<td valign="top">
|
|
61
|
+
<a href="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.10"><img src="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.10" alt="A session watching two other sessions: a finished reply arrives as a compact relay-event row, the watching 2 sessions list is open with Unsubscribe, and a request to also watch a session on a paired relay waits on an Allow / Deny card"></a>
|
|
62
|
+
<br><sub>Agents that watch agents: woken by events, approving nothing.</sub>
|
|
63
|
+
</td>
|
|
64
|
+
</tr>
|
|
59
65
|
</table>
|
|
60
66
|
|
|
61
67
|
<a id="quick-start"></a>
|
|
@@ -70,12 +76,13 @@ You need Node.js plus whatever the runtimes you actually use need. Nothing else
|
|
|
70
76
|
| ----------- | ---------- | ----- |
|
|
71
77
|
| 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)) |
|
|
72
78
|
| 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 |
|
|
73
|
-
| GitHub CLI (`gh`), signed in |
|
|
79
|
+
| GitHub CLI (`gh`), signed in | `oar copilot`; 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` |
|
|
74
80
|
| OpenAI API key | OpenAI and OpenAI Image chats | Entered in **⚙️ Settings**, stored in the relay database |
|
|
75
81
|
| A Claude login on the relay host | Claude chats | Log in from **⚙️ Settings → Providers → Claude → Relogin** (the panel can install the Claude Code CLI first), or run `claude` once on the host. The relay stores no Claude key |
|
|
76
82
|
| The same Claude login, from a claude.ai account with GitHub connected | Claude Cloud chats | The Claude GitHub app must be allowed on each repository a cloud chat works on (see [Claude Cloud](#claude-cloud)) |
|
|
77
83
|
| Cursor API key | Cursor chats | Entered in **⚙️ Settings**, stored in the relay database |
|
|
78
84
|
| Grok CLI, signed in | Grok chats | Install it and sign in from **⚙️ Settings → Providers → Grok**, or set `XAI_API_KEY` in the relay's environment |
|
|
85
|
+
| `cloudflared` (optional) | the built-in Cloudflare tunnel | Not included; install it yourself (see [Cloudflare Tunnel](#optional-remote-internet-access-cloudflare-tunnel)) |
|
|
79
86
|
| tmux (optional) | Linux and macOS | Session workers run in detached tmux sessions you can watch from the browser (**🖥️ Inspect tmux console**). Without tmux they run as plain background processes |
|
|
80
87
|
|
|
81
88
|
### macOS and Linux
|
|
@@ -100,7 +107,7 @@ The relay is started as a systemd user service where a systemd user session exis
|
|
|
100
107
|
|
|
101
108
|
```bash
|
|
102
109
|
curl -fsSL oar.sh/install | sh -s -- --yes
|
|
103
|
-
curl -fsSL oar.sh/install | OAR_VERSION=0.9.
|
|
110
|
+
curl -fsSL oar.sh/install | OAR_VERSION=0.9.10 OAR_PORT=3400 sh
|
|
104
111
|
```
|
|
105
112
|
|
|
106
113
|
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).
|
|
@@ -113,16 +120,16 @@ Read it before you run it: [oar.sh/install](https://oar.sh/install).
|
|
|
113
120
|
irm oar.sh/install.ps1 | iex
|
|
114
121
|
```
|
|
115
122
|
|
|
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.
|
|
123
|
+
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.10'` before the command.
|
|
117
124
|
|
|
118
125
|
### npm
|
|
119
126
|
|
|
120
127
|
```bash
|
|
121
|
-
npm install -g --allow-scripts=better-sqlite3,
|
|
128
|
+
npm install -g --allow-scripts=better-sqlite3,koffi @oar-sh/oar
|
|
122
129
|
oar setup
|
|
123
130
|
```
|
|
124
131
|
|
|
125
|
-
npm 12 runs no install script it was not told to allow, and
|
|
132
|
+
npm 12 runs no install script it was not told to allow, and two 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
133
|
|
|
127
134
|
### From a git checkout
|
|
128
135
|
|
|
@@ -150,12 +157,11 @@ Development workflows, tests, and relay internals are in [DEVELOPING.md](DEVELOP
|
|
|
150
157
|
|
|
151
158
|
### Start the relay
|
|
152
159
|
|
|
153
|
-
The macOS and Linux installer starts the relay itself. After a manual install, `oar setup` creates the config and prints the relay URL
|
|
160
|
+
The macOS and Linux installer starts the relay itself. After a manual install, `oar setup` creates the config and prints the relay URL, but it does not start the relay unless you pass `--start`. `oar` alone, in a terminal, opens a menu with everything below.
|
|
154
161
|
|
|
155
|
-
- **Any global install
|
|
156
|
-
- **
|
|
157
|
-
- **
|
|
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.
|
|
162
|
+
- **Any global install:** `oar start` starts the relay in the background (through the systemd user service when one is installed) and prints the relay URL. `oar stop` stops it, `oar restart` restarts it, `oar status` says whether it runs; stop and restart wait for running turns.
|
|
163
|
+
- **At every login:** `oar service install`. On Linux that writes and enables a systemd user service and enables lingering, so the relay is back after a reboot and keeps running while you are logged out; the unit carries the `PATH` of the shell that ran the command, plus `~/.local/bin`, so the relay's sessions find the tools you have (run it again after your `PATH` changed). On Windows it switches on the same autostart as **⚙️ Settings → General → Autostart (Windows)** → *At sign-in*; *At system startup*, which runs the relay headless before anyone signs in, is set in the web UI because it needs one admin confirmation. `oar service remove` takes it out again. Not available on macOS yet, nor on a Linux without a systemd user session (containers, WSL without systemd): use `oar start` there.
|
|
164
|
+
- **With a Copilot terminal session:** `oar copilot` 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 copilot` started stops again when that session ends. It needs the GitHub CLI.
|
|
159
165
|
|
|
160
166
|
To run the relay of a global install in the foreground, start the server the way the systemd unit does:
|
|
161
167
|
|
|
@@ -168,22 +174,24 @@ node "$(npm root -g)/@oar-sh/oar/server/server.js"
|
|
|
168
174
|
|
|
169
175
|
On Windows, point the same three variables at `%APPDATA%\oar\config.json`, `%APPDATA%\oar\data`, and `%APPDATA%\oar\logs`. The directory you start it from becomes the default working directory for new sessions.
|
|
170
176
|
|
|
171
|
-
Then open the URL that `oar setup` printed
|
|
177
|
+
Then open the URL that `oar setup` printed (`oar url` prints it again). With access set to this machine only (the default, `localhostOnly` in the config) that is `http://localhost:3333/` on the relay host; reach it from other devices through a [tunnel](#remote-access), or switch on LAN access with `oar setup --lan`, which also prints a QR code for your phone. The URL carries your token once (`?token=…`); after that, the relay keeps the browser signed in with an HttpOnly cookie.
|
|
172
178
|
|
|
173
179
|
### The `oar` command
|
|
174
180
|
|
|
175
181
|
| Command | What it does |
|
|
176
182
|
| ------- | ------------ |
|
|
177
|
-
| `oar` |
|
|
178
|
-
| `oar
|
|
179
|
-
| `oar
|
|
180
|
-
| `oar
|
|
181
|
-
| `oar
|
|
182
|
-
| `oar
|
|
183
|
-
| `oar
|
|
184
|
-
| `oar
|
|
183
|
+
| `oar` | In a terminal: a menu with the relay's status (running or stopped, version, URL, port, access, service) and an entry for each command below; arrow keys or digits, Enter, `q`. Without a terminal: the status and the usage |
|
|
184
|
+
| `oar start` | Starts the relay in the background, through the systemd user service when one is installed, and prints the relay URL. A relay that is already running is left alone. Global installs only; a git checkout uses `npm start` |
|
|
185
|
+
| `oar stop` | Stops the relay: the systemd service through `systemctl --user stop oar`, any other relay through its own API, once no turn is running |
|
|
186
|
+
| `oar restart` | Restarts a running relay once no turn is running (the service through systemd, at once), or starts a stopped one |
|
|
187
|
+
| `oar status` | Says whether the relay runs, on which port and with which access, and whether the service is installed. Exit code 0 when it runs, 3 when it does not |
|
|
188
|
+
| `oar url` | Prints the relay URL. With LAN access it also prints a QR code; with access for this machine only it says how to get phone access instead. When the running relay reports a tunnel address, that address and its QR code follow |
|
|
189
|
+
| `oar setup` | Creates or updates the config. In a terminal it asks, showing the current value (Enter keeps it): a new auth token (which signs every device out), access (this machine only, or LAN), and the port. Options answer without a question: `--port <port>`, `--lan` or `--local`, `--new-token`; `--defaults` keeps everything of an existing config and gives a new one access for this machine only and the first free port from 3333 on. A port must be free, unless the install's own running relay holds it. When the token, the port or the access changed while the relay runs, setup restarts it (in a terminal it asks first) and waits until it answers with the new settings. `--start` (global installs, used by the installer) also installs the service where a systemd user session exists and starts the relay. `--migrate-from <dir>` copies the relay state of a pre-rename git checkout at `<dir>` into the OAR state root, once; the source is never changed, and a relay still running from it blocks the copy |
|
|
190
|
+
| `oar service install` \| `remove` \| `status` | Starts the relay at every login: a systemd user service on Linux, the sign-in autostart on Windows. See [Start the relay](#start-the-relay) |
|
|
191
|
+
| `oar copilot [-- <args>]` | Starts the relay in the background unless one already answers on its port, then runs `gh copilot` in the same shell, passing `<args>` through (`gh copilot -- <args>`). `--port <port>` finds or starts the relay on that port for this run without changing the config; a config this command creates saves it. `--install-extension` writes or refreshes the user-global Copilot CLI extension wrapper in `~/.copilot/extensions/web-relay/`, then exits; every run does that unless `--no-install-extension` is given. The same options without the word `copilot` (`oar -- <args>`, `oar --install-extension`) still run this command |
|
|
192
|
+
| `oar doctor` | Prints the version, Node.js, install mode, state root, config path, port, whether an auth token is set, the tunnel mode and whether the `cloudflared` it needs is installed, the database path and size, and which provider CLIs (`gh`, `claude`, `grok`) answer. It changes nothing |
|
|
185
193
|
| `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 |
|
|
186
|
-
| `oar --version`, `oar
|
|
194
|
+
| `oar --version`, `oar help` | Prints the version, or the usage. An unknown command or option prints the usage and exits with code 2 |
|
|
187
195
|
|
|
188
196
|
### Where OAR keeps its files
|
|
189
197
|
|
|
@@ -421,6 +429,16 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
421
429
|
|
|
422
430
|
## Highlights
|
|
423
431
|
|
|
432
|
+
### New in 0.9.10
|
|
433
|
+
|
|
434
|
+
- **Watching sessions**: an agent subscribes to other sessions, on its own relay or on a paired one, and is woken by what happens there: a question waiting for an answer, an error, a reply, a background task that finished or failed, a session gone quiet, nothing running any more. Each wake-up is a short automated message in its conversation, shown as a compact row. Subscriptions only notify; they approve nothing. The first subscribe of a conversation asks you on a card, and the header shows **watching N sessions** with an Unsubscribe per subscription. See [Watching sessions](#watching-sessions).
|
|
435
|
+
- **Notes between agents fold away**: a prompt another agent sent a session and the session's reply show as one row that opens to both.
|
|
436
|
+
- **A sub-agent's whole record**: its title in the task panel, or its row under the finished reply, opens a viewer with its thoughts, every tool call with input and result, and its reply, live while it runs. **Keep sub-agent tool output** under Settings → General decides how long tool inputs and results are kept.
|
|
437
|
+
- **What the plans have left**: `remote_relay`'s `usage` action tells an agent what each provider's plan has left on its own relay or a paired one, before it starts work that costs; `list_sessions` and `read_session` say whether a session is running a turn, only background work, or nothing.
|
|
438
|
+
- **Folders in the file browser**: **📁+ New folder**, and a right-click (a long press on a phone) on a file or folder to rename or delete it.
|
|
439
|
+
- **Back to the latest message**: a ⌄ button above the composer, with a count of the rows that arrived since, jumps back to the end, and the transcript follows new rows again.
|
|
440
|
+
- **Fewer surprises**: archiving a session whose process is still active asks first, Settings opens with no conversation open (so a fresh install can turn on a provider), a queued relay restart no longer waits forever on a busy relay, and waking the host from sleep no longer restarts the running turns.
|
|
441
|
+
|
|
424
442
|
### New in 0.9.7
|
|
425
443
|
|
|
426
444
|
- **Claude Cloud (experimental, off by default)**: a chat that runs Claude Code in a sandbox at Anthropic, on its own clone of a GitHub repository. Pick the repository and branch from a list, follow the turn live, answer its questions, stop it, change the model between turns; the results come back as pushed branches. See [Claude Cloud](#claude-cloud) for what it needs and what it does with the Claude login.
|
|
@@ -472,6 +490,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
472
490
|
- 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
|
|
473
491
|
- **Screenshot annotations**: mark up an uploaded screenshot with highlighter strokes before or after sending; the original upload is never modified
|
|
474
492
|
- **Share** a conversation by read-only link, and hide individual messages from the shared view
|
|
493
|
+
- **Pin** messages in a conversation and get back to them from a list that scrolls to each one
|
|
475
494
|
- Conversation history in local SQLite, including the Copilot sessions already stored on the host
|
|
476
495
|
- `/compact` continues in a fresh conversation seeded with a summary; `/preview` publishes a local dev server or folder on a public preview host
|
|
477
496
|
- Workspace and drive browser with file previews, **Git changes** with a diff viewer, and `@file:` / `@folder:` reference tokens
|
|
@@ -503,6 +522,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
503
522
|
- **Steer or queue.** On Claude, and on Copilot's SDK engine, a message you send during a live turn is pushed into that turn; the send button reads **Steer**. A folded message keeps a compact *merged* marker in the transcript, and one the agent answers separately gets its own reply. While the turn waits on a question card or plan approval, or is compacting, the button reads **Queue** and its tooltip says why: the message waits as a pending bubble (with **Cancel**) and steers in once the card is answered or the compaction ends. On the other runtimes, and on Copilot's Extension engine, messages sent during a turn queue behind it, and the button reads **Queue**.
|
|
504
523
|
- **Stop** is on the running reply's bubble, whose header stays pinned at the top while a long reply scrolls; the send button never turns into Stop. Queued messages carry their own **Cancel** until they are picked up. A steered message that a Stop cut off is marked *Stopped with the turn — not answered* and offers **Resend**; the button then reads **Resent** on every device.
|
|
505
524
|
- On Copilot, **Stop** ends only the reply: background agents the turn started keep running under their own **Stop** in the task panel.
|
|
525
|
+
- The transcript follows new rows while you are at its end. Once you scroll about a screen up, a round **⌄** button fades in above the composer, with a badge counting the rows that arrived since; it takes you back to the end and the transcript follows again. From a search result or a pin deep in the history it loads the end first.
|
|
506
526
|
|
|
507
527
|
### Question cards
|
|
508
528
|
|
|
@@ -516,6 +536,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
516
536
|
- The composer's task panel lists background work that outlives the reply that started it: backgrounded commands, subagents, monitors, and workflows on Claude; background agents and detached shells on Copilot's SDK engine. Each row shows its state, the model it runs on, the command it is running right now, its token count, and its own **Stop**. The panel scrolls when it holds more tasks than fit.
|
|
517
537
|
- An **Ultracode** workflow folds out into a tree of its phases and agents (state, model, tokens). When it finishes, the summarizing reply keeps a collapsed *Finished background task* card holding the final tree, which survives reloads.
|
|
518
538
|
- A background task's result arrives as its own *continuation* reply.
|
|
539
|
+
- A sub-agent's title in the panel opens its whole record: its thoughts, every tool call with its full input and its result, its reply and the agents it started itself, in order and live while it runs, with its own **Stop**. The finished reply lists the turn's sub-agents as the same rows (model, type, tokens, time, how they ended), so the record stays one click away; a child agent opens in place and back returns to its parent. Claude records everything; Copilot and Cursor show what they report. A tool result is kept to its first 4 KB and a record to 2000 entries; **Keep sub-agent tool output** in Settings → General decides how long tool inputs and results are kept.
|
|
519
540
|
- **⚙️ Settings → General → Background task timeout** (default 4 h; 0 = no limit, up to 10 h) caps how long background tasks alone may keep a Claude or Copilot session running after its reply. When the limit is reached, the tasks are stopped.
|
|
520
541
|
|
|
521
542
|
### Drafts across devices
|
|
@@ -527,13 +548,14 @@ The composer draft, attachments included, is saved per conversation on the relay
|
|
|
527
548
|
- **Filter conversations…** above the list matches titles, ignoring case. It clears with **×** or Escape, and while it is active it loads older pages, so it searches every conversation, not just the loaded ones.
|
|
528
549
|
- **🔍** in the conversation header searches message text across all conversations.
|
|
529
550
|
- On startup, the relay imports the Copilot sessions stored on the host (through the installed Copilot runtime) into its database, so they appear in the list with their history. If the runtime is unavailable, the import is reported as failed rather than guessed from the filesystem.
|
|
530
|
-
- **Archive** (🗄 on the row, or **Archive conversation** in the `⋯` menu) takes a conversation out of the list without deleting anything: its session worker is stopped, and a Claude Cloud chat's session at Anthropic is archived with it. The 🗄 toggle above the list shows the archived conversations; **Unarchive** (📂) brings one back, cloud session included. An archived chat that is opened cannot be sent to until it is unarchived; a message that reaches it anyway (an agent's through a paired relay, say) unarchives it. A conversation that is still working is not archived — stop it first.
|
|
551
|
+
- **Archive** (🗄 on the row, or **Archive conversation** in the `⋯` menu) takes a conversation out of the list without deleting anything: its session worker is stopped, and a Claude Cloud chat's session at Anthropic is archived with it. The 🗄 toggle above the list shows the archived conversations; **Unarchive** (📂) brings one back, cloud session included. An archived chat that is opened cannot be sent to until it is unarchived; a message that reaches it anyway (an agent's through a paired relay, say) unarchives it. Archiving a conversation whose session process is still active (green in the list, idle or working) asks first, because archiving stops it. A conversation that is still working is not archived — stop it first.
|
|
531
552
|
- A **right-click on a row** (a long press on a phone) opens a menu with Open, Edit title, Stop turn, Kill session, Archive or Unarchive, and Delete, so a session can be stopped or killed without opening it.
|
|
532
553
|
- Deleting a conversation stops its session worker and removes its CLI session too (Copilot through the runtime, Claude by deleting that session's transcript). A Claude Cloud conversation's session at Anthropic is archived, not deleted. An imported Copilot session the relay never ran is only hidden: its CLI session stays, and nothing is stopped for it. A conversation that is still working — a running turn, one waiting on a question card or approval, or live background tasks — is not deleted, and the sidebar says why so you can stop it first.
|
|
533
554
|
|
|
534
555
|
### Files, git, and previews
|
|
535
556
|
|
|
536
557
|
- Use **📁 Browse files** to inspect the workspace (💼), drives (📀), or the session's own folder (🕵️), and to open previews. The **Hidden** and **Heavy** toolbar filters are remembered per browser, and a refresh re-opens the folders you had expanded.
|
|
558
|
+
- **📁+ New folder** in the browser's toolbar opens a name field at the top of the folder pane; Enter creates the folder inside the open one and opens it. It works in the repository, on the drives, in the session folder, and in the folder picker of **New chat** and **Change CWD**. A right-click on a folder in the tree or a file in the folder pane (a long press on a phone) offers **Rename** and **Delete**, and on a folder **New folder here**. Delete says what goes, and a folder with content asks for its name to be typed first. Links are never followed or changed; roots (the repository root, `/`, a drive, the session folder) cannot be renamed or deleted, and the session folder is read-only apart from new folders.
|
|
537
559
|
- Click the file and folder copy controls to insert `@file:...` / `@folder:...` tokens.
|
|
538
560
|
- Workspace browsing follows the selected session's effective working directory. Running sessions keep their learned runtime directory, **🗂️ Change CWD** in the `⋯` menu changes the directory for the next launch, and `cd ...` typed in chat does not retarget the browser. A Claude Cloud chat has no **Change CWD**: it works on a clone at Anthropic.
|
|
539
561
|
- Use **🌿 Git changes** in the conversation `⋯` menu to review the workspace repository: the header shows the branch with ahead/behind counts and a **⬇ Pull** button, and the list shows every staged, unstaged, and untracked file (deleted files struck through). Clicking a file opens a diff viewer with **Changes** and **Full file** modes; closing it returns to the still-open list.
|
|
@@ -558,6 +580,10 @@ The composer draft, attachments included, is saved per conversation on the relay
|
|
|
558
580
|
|
|
559
581
|
Use **➡️ Share conversation** in the `⋯` menu to publish a read-only link. Each message has a **Hide** button that keeps it out of the shared view without deleting it; hidden messages stay fully visible to you, marked *Hidden from shared viewers*, with an **Unhide** button. Anyone with the link can read the shared view, without signing in.
|
|
560
582
|
|
|
583
|
+
### Pinned messages
|
|
584
|
+
|
|
585
|
+
Each message has a **Pin** button next to **Hide**; a pinned message is marked *📍 Pinned* and offers **Unpin**. Once a conversation has pins, a **📍** button with their count appears in its header. It opens the list of pinned messages in conversation order, each with a short preview. A row closes the list and scrolls to its message, also when that message is far up in the history; **🗑** in a row unpins it. Pins are kept on the relay and show on every device at once, up to 100 per conversation. They are your own bookmarks: the shared view does not show them, and a conversation continued with `/compact` starts without them.
|
|
586
|
+
|
|
561
587
|
### Notifications and the app
|
|
562
588
|
|
|
563
589
|
- **⚙️ Settings → Notifications** turns on push notifications per device: for questions from the agent, completed or failed turns, plan boards, and the CLI going offline. They need a secure context (HTTPS, or `localhost`), are sent only while no device has the app in the foreground, and show generic text unless you opt in to message previews on that device.
|
|
@@ -573,7 +599,7 @@ Besides the entries above, the `⋯` menu holds **✍️ Edit conversation title
|
|
|
573
599
|
|
|
574
600
|
### Settings (⚙️ in the web UI)
|
|
575
601
|
|
|
576
|
-
The modal is organised into six tabs — **General**, **Providers** (with a **Copilot**, **OpenAI**, **Claude**, **Claude Cloud**, **Grok**, and **Cursor** sub-tab), **Relays**, **Previews**, **Notifications**, and **Features** — and reopens on the tab you used last. Unless noted as per browser, these settings live in the relay database rather than the config file, and apply to every browser that connects:
|
|
602
|
+
The modal is organised into six tabs — **General**, **Providers** (with a **Copilot**, **OpenAI**, **Claude**, **Claude Cloud**, **Grok**, and **Cursor** sub-tab), **Relays**, **Previews**, **Notifications**, and **Features** — and reopens on the tab you used last. The `⋯` menu opens it with no conversation open too, so a fresh install can turn on a provider before the first chat; until a provider is ready, the empty screen and **New Chat** point to Settings → Providers. Unless noted as per browser, these settings live in the relay database rather than the config file, and apply to every browser that connects:
|
|
577
603
|
|
|
578
604
|
| Tab | Setting | Default | What it does |
|
|
579
605
|
| --- | ------- | ------- | ------------ |
|
|
@@ -581,6 +607,7 @@ The modal is organised into six tabs — **General**, **Providers** (with a **Co
|
|
|
581
607
|
| General | Show Suspend host action | on | Per browser: shows **💤 Suspend host** in the conversation menu |
|
|
582
608
|
| General | Max turn duration | `60 min` | Hard cap on how long one turn may run before the relay requeues it (0 = no limit, up to 10 h; see below) |
|
|
583
609
|
| General | Background task timeout | `4 h` | How long background tasks alone may keep a Claude or Copilot session running after its reply; then they are stopped (0 = no limit, up to 10 h) |
|
|
610
|
+
| General | Keep sub-agent tool output | `90 days` | 7, 14, 30 or 90 days, or always: once a finished sub-agent's record is older, its tool inputs and results are removed (once a day); its thoughts, reply and the one-line summary of each tool call stay |
|
|
584
611
|
| General | Autostart (Windows) | Off | *At sign-in* (a visible terminal after you log on) or *At system startup* (headless, no logon needed, one admin confirmation) |
|
|
585
612
|
| General | Relay name | `OAR` (the hostname for paired relays) | Label of the installed PWA on every device, and this relay's name for [paired relays](#remote-relays) |
|
|
586
613
|
| General | Check for updates automatically | off | Opt-in: the relay asks oar.sh for the latest version about twice a day. **Check for updates** works regardless; `OAR_NO_UPDATE_CHECK=1` blocks both |
|
|
@@ -640,7 +667,7 @@ The config file is `server/config.json` in a git checkout and `~/.oar/config.jso
|
|
|
640
667
|
| `cloudflaredTunnel.mode` | `disabled` | Cloudflare tunnel mode (`disabled` or `managed`; `enabled: true` is a legacy alias for `managed`) |
|
|
641
668
|
| `cloudflaredTunnel.required` | `false` | Pause dequeue while the managed Cloudflare tunnel is disconnected |
|
|
642
669
|
| `cloudflaredTunnel.token` | — | The tunnel token from your own Cloudflare Zero Trust tunnel |
|
|
643
|
-
| `cloudflaredTunnel.binary` |
|
|
670
|
+
| `cloudflaredTunnel.binary` | `cloudflared` | Path or command name of the `cloudflared` you installed; defaults to `cloudflared` on `PATH` |
|
|
644
671
|
| `cloudflaredTunnel.extraArgs` | `[]` | Extra arguments appended to `cloudflared tunnel run` |
|
|
645
672
|
| `previews.enabled` | `false` | Publish local dev servers on a separate listener (see [docs/preview-servers.md](docs/preview-servers.md)) |
|
|
646
673
|
| `previews.port` | `port + 1` | Loopback port for the preview listener; `0` picks an ephemeral port |
|
|
@@ -726,11 +753,18 @@ An alternative to the SSH tunnel that needs no VPS and no inbound port: the rela
|
|
|
726
753
|
supervises Cloudflare's `cloudflared` binary, and Cloudflare carries your hostname down
|
|
727
754
|
to `127.0.0.1:3333`.
|
|
728
755
|
|
|
756
|
+
OAR does not include `cloudflared`; install it on the relay host first:
|
|
757
|
+
|
|
758
|
+
| System | Install |
|
|
759
|
+
| ------ | ------- |
|
|
760
|
+
| Windows | `winget install --id Cloudflare.cloudflared` |
|
|
761
|
+
| macOS | `brew install cloudflared` |
|
|
762
|
+
| Linux | Cloudflare's package repository (Debian, Ubuntu, RHEL): [pkg.cloudflare.com](https://pkg.cloudflare.com/) |
|
|
763
|
+
|
|
729
764
|
1. In your own Cloudflare Zero Trust account, create a tunnel and route a public hostname on
|
|
730
765
|
your zone to `http://localhost:3333` (or your `port`). That routing lives in Cloudflare, not
|
|
731
766
|
on this machine.
|
|
732
|
-
2. Put the tunnel's token into the config and restart the relay
|
|
733
|
-
tunnel on for you; it still needs the token.)
|
|
767
|
+
2. Put the tunnel's token into the config and restart the relay (`oar restart`).
|
|
734
768
|
|
|
735
769
|
```json
|
|
736
770
|
"cloudflaredTunnel": {
|
|
@@ -746,17 +780,21 @@ Environment overrides: `COPILOT_CLOUDFLARED_MODE`, `COPILOT_CLOUDFLARED_TOKEN`,
|
|
|
746
780
|
`COPILOT_CLOUDFLARED_BINARY`.
|
|
747
781
|
|
|
748
782
|
`localhostOnly` stays `true`: `cloudflared` connects outbound and nothing binds publicly.
|
|
749
|
-
The
|
|
750
|
-
|
|
751
|
-
|
|
783
|
+
The relay runs the `cloudflared` named in `cloudflaredTunnel.binary`, or else the one on
|
|
784
|
+
its `PATH`. When there is none, the relay starts as usual and the tunnel stays off: the
|
|
785
|
+
status dot's tooltip, `oar doctor` and the server log say that `cloudflared` is not
|
|
786
|
+
installed and how to install it. The relay looks again every minute and starts the tunnel
|
|
787
|
+
once `cloudflared` is there; restart the relay if it was installed into a folder that is
|
|
788
|
+
not on the relay's `PATH`. With `required: true` the queue stays paused for as long as
|
|
789
|
+
the tunnel is not connected, a missing `cloudflared` included. Connection drops reconnect with jittered exponential backoff,
|
|
752
790
|
and repeated fast exits (deleted tunnel or bad token) are reported as `auth-or-config`
|
|
753
791
|
instead of hammering Cloudflare.
|
|
754
792
|
|
|
755
793
|
The relay status dot turns **amber** while the Cloudflare tunnel is connected, so it is
|
|
756
794
|
obvious at a glance that the relay is reachable from the internet rather than only from
|
|
757
795
|
this machine. It stays green when no tunnel is configured and grey when the relay itself
|
|
758
|
-
is unreachable; a managed tunnel that has dropped keeps the dot green — the relay
|
|
759
|
-
answers locally — and
|
|
796
|
+
is unreachable; a managed tunnel that has dropped, or could not start, keeps the dot green — the relay
|
|
797
|
+
still answers locally — and gives the reason in the tooltip.
|
|
760
798
|
|
|
761
799
|
### Session-worker path guard
|
|
762
800
|
|
|
@@ -821,6 +859,12 @@ is started with `provider: "claude-cloud"`, a `repo` (a GitHub URL or `owner/rep
|
|
|
821
859
|
the default model of the other relay's Claude Cloud tab. Claude Cloud must be switched on there.
|
|
822
860
|
A cloud session that exists can be read, prompted, waited for and stopped like any other.
|
|
823
861
|
|
|
862
|
+
Two read actions help an agent plan: `usage` says what each provider's plan has left on a relay
|
|
863
|
+
(Cursor's spend against its limit, Claude's windows and whether a usage limit has paused turns,
|
|
864
|
+
Copilot and Grok where they are tracked; never account names, addresses or tokens), and
|
|
865
|
+
`list_sessions` / `read_session` give each session's `state` (`running_turn`, `background_only` or
|
|
866
|
+
`idle`) with its background agents and shell tasks.
|
|
867
|
+
|
|
824
868
|
A `send`, `create_session` or `wait` call waits for the reply for as long as the agent asks, up to
|
|
825
869
|
**Longest wait per tool call** of the relay the agent runs on (10 minutes unless you changed it,
|
|
826
870
|
see [Agent sessions](#agent-sessions)). When the time is up the agent gets what there is so far
|
|
@@ -889,13 +933,57 @@ to this relay's agents when they wait for a session on a paired relay, so the sl
|
|
|
889
933
|
whether or not the switch above it is on. A turn that waits is still subject to **Max turn duration**
|
|
890
934
|
under **General** (60 minutes by default), which does not know about the wait.
|
|
891
935
|
|
|
936
|
+
### Watching sessions
|
|
937
|
+
|
|
938
|
+
An agent can watch other sessions instead of polling them: with `remote_relay`'s `subscribe` it
|
|
939
|
+
asks to be woken when something happens there. It works for every provider, on this relay (with
|
|
940
|
+
[agent sessions](#agent-sessions) switched on) and on a paired one.
|
|
941
|
+
|
|
942
|
+
**What wakes it.** A question waiting for an answer (with its options), an error (a failed turn,
|
|
943
|
+
the usage limit, a worker that died), a reply (with a preview), a background agent or shell task
|
|
944
|
+
that finished or failed, a session that went quiet while working (15 minutes by default), and the
|
|
945
|
+
moment nothing runs any more in the watched sessions. A subscription names sessions, or `all`
|
|
946
|
+
for every session, later ones included; the watcher's own conversation is never watched. It can
|
|
947
|
+
filter replies and task results by a regular expression, end after it fired once, and add a
|
|
948
|
+
heartbeat while work runs.
|
|
949
|
+
|
|
950
|
+
**What it looks like.** OAR writes a short message into the watcher's conversation: a new turn
|
|
951
|
+
when the watcher is idle, a steer into the running turn on Claude and Copilot's SDK engine, the
|
|
952
|
+
next turn otherwise. The message says it is automated, not from you, and that it approves
|
|
953
|
+
nothing; it shows as a compact row, never as one of your messages. Events within 30 seconds come
|
|
954
|
+
as one message; past 20 wake-ups an hour the rest comes as a digest every ten minutes, while
|
|
955
|
+
questions and errors still come at once.
|
|
956
|
+
|
|
957
|
+
**What it may do.** A subscription only notifies. It approves nothing and answers
|
|
958
|
+
nothing; what an event asks for is decided as before, by you or by the agent within what
|
|
959
|
+
it may do anyway. The first subscribe of a conversation, and any to `all`, asks you on an approval
|
|
960
|
+
card naming the sessions (and the relay); `transfer_subscriptions`, which hands every subscription
|
|
961
|
+
of an old watcher to a new one, always asks.
|
|
962
|
+
|
|
963
|
+
**Where you see it.** The watcher's header shows **watching N sessions**; the chip opens the list
|
|
964
|
+
of its subscriptions with an **Unsubscribe** button each. A watched session shows a **watched**
|
|
965
|
+
badge.
|
|
966
|
+
|
|
967
|
+
**Lifetime.** Subscriptions survive a restart and end on unsubscribe, when the watcher or the
|
|
968
|
+
watched session is archived, after firing once (`once`), or, for a paired relay, when the pairing
|
|
969
|
+
is removed.
|
|
970
|
+
|
|
971
|
+
**On a paired relay** the relay must be unlocked in the conversation and allow at least reading,
|
|
972
|
+
and the other relay must accept other relays' agents; nothing is asked there. This relay fetches
|
|
973
|
+
the events every few seconds over the pairing (a pairing in one direction is enough), and their
|
|
974
|
+
lines start with the other relay's name. If the link drops, the other relay keeps what happens
|
|
975
|
+
(up to 500 events per subscription, for 7 days) and delivers it as one row tagged **replayed** once
|
|
976
|
+
it answers again, questions and errors first, between "link lost" and "link restored". A relay
|
|
977
|
+
that runs an older OAR answers that it needs an update.
|
|
978
|
+
|
|
892
979
|
## Security notes
|
|
893
980
|
|
|
894
|
-
- The auth token guards the API and the Socket.IO channel. A browser signs in once, with the token or with a URL carrying `?token=` (such as the one `oar setup`
|
|
895
|
-
- Keep the config file private (the relay keeps it owner-only) and rotate `authToken` if it is exposed: `oar setup`
|
|
981
|
+
- The auth token guards the API and the Socket.IO channel. A browser signs in once, with the token or with a URL carrying `?token=` (such as the one `oar setup` and `oar url` print), and then holds an HttpOnly cookie for 30 days, marked `Secure` when the relay is reached over HTTPS. Treat the token, and that URL, like a password.
|
|
982
|
+
- Keep the config file private (the relay keeps it owner-only) and rotate `authToken` if it is exposed: `oar setup --new-token` writes a new one and restarts the relay, which signs every device out.
|
|
896
983
|
- `localhostOnly` (default `true`) keeps the relay on loopback. Beyond your LAN, use HTTPS through one of the [tunnels](#remote-access) rather than an open port.
|
|
897
984
|
- Agents act with the permissions of the user the relay runs as. OAR adds reach, not a sandbox: whoever holds the token can have them run commands on the host. `workspaceRootAllowList` limits the directories conversations may start in.
|
|
898
985
|
- Shared conversation links and preview links are public by design: anyone with the URL can read the shared transcript or reach the previewed app, without signing in.
|
|
986
|
+
- Files the relay serves (workspace and drive files, attachments) are never run as pages on its origin: HTML and XML go out as plain text, every file carries `nosniff` and a `Content-Security-Policy` with `sandbox`. An SVG keeps its type so it can be previewed, and the sandbox denies it script and an origin should it be opened as a page. A PDF is the one exception, served without `sandbox` (browsers refuse to show a sandboxed PDF in their built-in viewer, and PDF viewers run no document script) and framable only by the relay's own origin.
|
|
899
987
|
- A [paired relay](#remote-relays) holds a token that opens the other relay completely. The per-relay "Agents may" limit and the "Accept prompts from other relays' agents" switch are honoured by OAR's own traffic, but anyone holding the token can still use the full API: the token is the real boundary. A token entered for a paired relay is stored like the API keys below and never sent to browsers or agents.
|
|
900
988
|
- API keys you enter (OpenAI, Cursor) are stored in the relay database on the host and never sent to browsers. Claude and Grok credentials stay with their CLIs on the host.
|
|
901
989
|
- Claude Cloud, when you switch it on, reads the Claude CLI's login and uses it against Anthropic API endpoints that are not a documented public API. The token is only read and held in memory, and goes to `api.anthropic.com` only (see [Claude Cloud](#claude-cloud)). A cloud agent works in Anthropic's sandbox, not on your host.
|
|
@@ -906,7 +994,8 @@ under **General** (60 minutes by default), which does not know about the wait.
|
|
|
906
994
|
| Symptom | What to check |
|
|
907
995
|
| ---------------------------------- | -------------------------------------------------------------------------------- |
|
|
908
996
|
| Banner says *CLI is offline* | No session worker has reported in during the last 10 seconds, which can be normal on an idle relay. Send a message: the relay starts that conversation's worker, and the banner clears once it connects. If it stays, check `/api/status` and the worker's `worker-<session>.log` in the log directory |
|
|
909
|
-
| `oar`
|
|
997
|
+
| `oar copilot` says the GitHub CLI is missing | It runs `gh copilot` beside the relay. Install the GitHub CLI, or [run only the relay](#start-the-relay) |
|
|
998
|
+
| WSL: the browser on Windows shows another relay, or refuses the token | In WSL's default networking a port can be free in the distro while a Windows program listens on it; `localhost:<port>` in a Windows browser then reaches that program. `oar setup` picks a port that is free on both sides, and `oar status`, `oar start` and `oar doctor` warn when Windows holds the relay's port: choose another with `oar setup --port <port>` |
|
|
910
999
|
| Settings refuses the **SDK** engine | Install or upgrade the Copilot CLI, run `copilot` once, and restart the relay (see [engine choice](#github-copilot--engine-choice)) |
|
|
911
1000
|
| Messages stuck pending | Only one relay may run per data directory (a second one exits on the singleton lock), and only one process may own port `3333`. `oar doctor` shows the config and database in use |
|
|
912
1001
|
| Wrong or old model list | **🤗 Select Models → Refresh** reruns discovery; `/api/model-variants` shows the Copilot catalog's `source` and `refreshedAt` |
|
|
@@ -925,7 +1014,8 @@ under **General** (60 minutes by default), which does not know about the wait.
|
|
|
925
1014
|
| A conversation seems wedged | **☠️ Kill session** in the `⋯` menu stops its worker; retry the turn or send a new message |
|
|
926
1015
|
| **🌄 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
1016
|
| `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,
|
|
1017
|
+
| 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,koffi @oar-sh/oar` |
|
|
1018
|
+
| The Cloudflare tunnel stays off and the status dot's tooltip says `cloudflared is not installed` | OAR runs the `cloudflared` on the relay host and ships none. Install it (see [Cloudflare Tunnel](#optional-remote-internet-access-cloudflare-tunnel)); the tunnel starts within a minute |
|
|
929
1019
|
| `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 |
|
|
930
1020
|
| No usage line under a reply | Expected for OpenAI, Claude, Claude Cloud, Cursor, and Grok turns; only Copilot turns record plan usage |
|
|
931
1021
|
|
package/bin/bat/oar.bat
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
setlocal EnableExtensions
|
|
3
|
-
|
|
4
|
-
set "SCRIPT_DIR=%~dp0"
|
|
5
|
-
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
|
6
|
-
|
|
7
|
-
for %%I in ("%SCRIPT_DIR%\..\..") do set "REPO_ROOT=%%~fI"
|
|
8
|
-
|
|
9
|
-
if not exist "%REPO_ROOT%\package.json" (
|
|
10
|
-
echo [oar] Unable to locate the repository root from "%SCRIPT_DIR%".
|
|
11
|
-
exit /b 1
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
echo(;%PATH%; | findstr /I /C:";%SCRIPT_DIR%;" >nul
|
|
15
|
-
if errorlevel 1 (
|
|
16
|
-
call :AddToUserPath "%SCRIPT_DIR%"
|
|
17
|
-
if errorlevel 1 (
|
|
18
|
-
echo [oar] Warning: could not update your user PATH.
|
|
19
|
-
) else (
|
|
20
|
-
echo [oar] Ensured "%SCRIPT_DIR%" is in your user PATH.
|
|
21
|
-
echo [oar] Open a new cmd.exe window to use oar by name.
|
|
22
|
-
echo.
|
|
23
|
-
)
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
set "COPILOT_WORKSPACE_ROOT=%REPO_ROOT%"
|
|
27
|
-
set "COPILOT_WEB_RELAY_ROOT=%REPO_ROOT%"
|
|
28
|
-
set "COPILOT_WEB_RELAY_SERVER_DIR=%REPO_ROOT%\server"
|
|
29
|
-
|
|
30
|
-
pushd "%REPO_ROOT%" >nul
|
|
31
|
-
if errorlevel 1 (
|
|
32
|
-
echo [oar] Failed to change to repo root: "%REPO_ROOT%".
|
|
33
|
-
exit /b 1
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
echo [oar] Starting Copilot from "%REPO_ROOT%"...
|
|
37
|
-
gh copilot -- --allow-all
|
|
38
|
-
set "EXIT_CODE=%errorlevel%"
|
|
39
|
-
popd >nul
|
|
40
|
-
exit /b %EXIT_CODE%
|
|
41
|
-
|
|
42
|
-
:AddToUserPath
|
|
43
|
-
set "TARGET_DIR=%~1"
|
|
44
|
-
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "$target = [System.IO.Path]::GetFullPath($env:TARGET_DIR.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar)); $current = [Environment]::GetEnvironmentVariable('Path', 'User'); $parts = @(); if ($current) { $parts = $current -split ';' | ForEach-Object { $_.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) } | Where-Object { $_ } }; if ($parts -contains $target) { exit 0 }; $next = ($parts + $target) -join ';'; [Environment]::SetEnvironmentVariable('Path', $next, 'User')" >nul
|
|
45
|
-
if errorlevel 1 exit /b 1
|
|
46
|
-
exit /b 0
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableExtensions
|
|
3
|
+
|
|
4
|
+
set "SCRIPT_DIR=%~dp0"
|
|
5
|
+
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
|
6
|
+
|
|
7
|
+
for %%I in ("%SCRIPT_DIR%\..\..") do set "REPO_ROOT=%%~fI"
|
|
8
|
+
|
|
9
|
+
if not exist "%REPO_ROOT%\package.json" (
|
|
10
|
+
echo [oar] Unable to locate the repository root from "%SCRIPT_DIR%".
|
|
11
|
+
exit /b 1
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
echo(;%PATH%; | findstr /I /C:";%SCRIPT_DIR%;" >nul
|
|
15
|
+
if errorlevel 1 (
|
|
16
|
+
call :AddToUserPath "%SCRIPT_DIR%"
|
|
17
|
+
if errorlevel 1 (
|
|
18
|
+
echo [oar] Warning: could not update your user PATH.
|
|
19
|
+
) else (
|
|
20
|
+
echo [oar] Ensured "%SCRIPT_DIR%" is in your user PATH.
|
|
21
|
+
echo [oar] Open a new cmd.exe window to use oar by name.
|
|
22
|
+
echo.
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
set "COPILOT_WORKSPACE_ROOT=%REPO_ROOT%"
|
|
27
|
+
set "COPILOT_WEB_RELAY_ROOT=%REPO_ROOT%"
|
|
28
|
+
set "COPILOT_WEB_RELAY_SERVER_DIR=%REPO_ROOT%\server"
|
|
29
|
+
|
|
30
|
+
pushd "%REPO_ROOT%" >nul
|
|
31
|
+
if errorlevel 1 (
|
|
32
|
+
echo [oar] Failed to change to repo root: "%REPO_ROOT%".
|
|
33
|
+
exit /b 1
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
echo [oar] Starting Copilot from "%REPO_ROOT%"...
|
|
37
|
+
gh copilot -- --allow-all
|
|
38
|
+
set "EXIT_CODE=%errorlevel%"
|
|
39
|
+
popd >nul
|
|
40
|
+
exit /b %EXIT_CODE%
|
|
41
|
+
|
|
42
|
+
:AddToUserPath
|
|
43
|
+
set "TARGET_DIR=%~1"
|
|
44
|
+
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "$target = [System.IO.Path]::GetFullPath($env:TARGET_DIR.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar)); $current = [Environment]::GetEnvironmentVariable('Path', 'User'); $parts = @(); if ($current) { $parts = $current -split ';' | ForEach-Object { $_.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) } | Where-Object { $_ } }; if ($parts -contains $target) { exit 0 }; $next = ($parts + $target) -join ';'; [Environment]::SetEnvironmentVariable('Path', $next, 'User')" >nul
|
|
45
|
+
if errorlevel 1 exit /b 1
|
|
46
|
+
exit /b 0
|