@oar-sh/oar 0.9.6 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +285 -0
- package/README.md +222 -40
- package/bin/oar.js +320 -18
- package/package.json +1 -1
- package/server/README.md +174 -7
- package/server/claude-cloud-worker/claude-cloud-event-normalizer.mjs +340 -0
- package/server/claude-cloud-worker/claude-cloud-session-process.mjs +1325 -0
- package/server/claude-cloud-worker/claude-cloud-session-worker.mjs +155 -0
- package/server/claude-worker/claude-remote-relay-tool.mjs +2 -0
- package/server/claude-worker/claude-sdk-adapter.mjs +18 -13
- package/server/claude-worker/claude-session-process.mjs +225 -24
- package/server/claude-worker/claude-session-worker.mjs +6 -0
- package/server/claude-worker/sdk-message-normalizer.mjs +28 -0
- package/server/db-schema.mjs +17 -0
- package/server/migrations/0006-workspace-root-settings.mjs +67 -0
- package/server/migrations/0007-claude-cloud.mjs +82 -0
- package/server/public/app/activity-replay-state.mjs +68 -5
- package/server/public/app/agent-sessions-settings-ui.js +197 -0
- package/server/public/app/agent-sessions-settings.mjs +134 -0
- package/server/public/app/api-client.js +149 -6
- package/server/public/app/attachments-view.js +20 -1
- package/server/public/app/attribution-control.mjs +46 -0
- package/server/public/app/bootstrap.js +468 -88
- package/server/public/app/claude-cloud-conversation-ui.js +110 -0
- package/server/public/app/claude-cloud-settings-ui.js +374 -0
- package/server/public/app/claude-cloud-ui.mjs +611 -0
- package/server/public/app/composer-control-state.mjs +11 -0
- package/server/public/app/context-menu.mjs +140 -0
- package/server/public/app/context-tier-options.mjs +4 -0
- package/server/public/app/context-usage-view.mjs +127 -8
- package/server/public/app/conversation-origin-ui.js +27 -0
- package/server/public/app/conversation-provider-indicator.mjs +22 -4
- package/server/public/app/conversation-view.js +145 -11
- package/server/public/app/cwd-picker.js +12 -0
- package/server/public/app/journal-view.js +698 -28
- package/server/public/app/math-dollars.mjs +89 -0
- package/server/public/app/model-selector-options.mjs +1 -1
- package/server/public/app/plan-usage-view.mjs +36 -8
- package/server/public/app/pwa-install.js +5 -0
- package/server/public/app/relay-error-ctas.mjs +16 -2
- package/server/public/app/remote-relay-origin-view.mjs +120 -4
- package/server/public/app/router.js +49 -12
- package/server/public/app/scrollbar-hover.mjs +78 -0
- package/server/public/app/settings-modal.js +37 -3
- package/server/public/app/settings-tabs.js +1 -1
- package/server/public/app/socket-handlers.js +53 -1
- package/server/public/app/store.js +26 -0
- package/server/public/app/transcript-separators.mjs +48 -11
- package/server/public/app-icon-192.png +0 -0
- package/server/public/app-icon-512.png +0 -0
- package/server/public/app-icon-light-192.png +0 -0
- package/server/public/app-icon-light-512.png +0 -0
- package/server/public/app-icon-light-maskable-512.png +0 -0
- package/server/public/app-icon-light.svg +4 -0
- package/server/public/app-icon-maskable-512.png +0 -0
- package/server/public/app-icon.svg +3 -3
- package/server/public/favicon.ico +0 -0
- package/server/public/index.html +564 -20
- package/server/public/manifest.webmanifest +9 -3
- package/server/public/sw.js +6 -1
- package/server/relay-tools.md +13 -1
- package/server/repositories/remote-relay-repository.mjs +42 -1
- package/server/repositories/session-repository.mjs +47 -1
- package/server/routes/claude-cloud-routes.mjs +140 -0
- package/server/routes/git-routes.mjs +37 -0
- package/server/routes/messages-routes.mjs +123 -16
- package/server/routes/remote-relay-routes.mjs +15 -1
- package/server/routes/sessions-routes.mjs +517 -74
- package/server/server-runtime.mjs +268 -33
- package/server/services/claude-account-usage-service.mjs +176 -0
- package/server/services/claude-cloud-repo-service.mjs +408 -0
- package/server/services/claude-cloud-session-service.mjs +326 -0
- package/server/services/claude-cloud-settings-service.mjs +269 -0
- package/server/services/claude-context-usage.mjs +51 -3
- package/server/services/git-remote-service.mjs +115 -0
- package/server/services/oar-cli-helpers.mjs +67 -1
- package/server/services/plan-usage-claude-cloud.mjs +211 -0
- package/server/services/plan-usage-claude.mjs +202 -40
- package/server/services/plan-usage-contract.mjs +39 -3
- package/server/services/plan-usage-service.mjs +82 -2
- package/server/services/provider-reasoning-effort.mjs +3 -0
- package/server/services/pwa-manifest-theme.mjs +30 -0
- package/server/services/remote-relay-caller-context.mjs +49 -10
- package/server/services/remote-relay-client.mjs +9 -0
- package/server/services/remote-relay-dispatcher.mjs +383 -35
- package/server/services/remote-relay-inbound.mjs +49 -2
- package/server/services/remote-relay-loopback.mjs +245 -0
- package/server/services/remote-relay-registry-service.mjs +52 -0
- package/server/services/session-worker-launch-service.mjs +100 -15
- package/server/services/session-worker-process-service.mjs +348 -129
- package/server/services/session-worker-registry-service.mjs +18 -1
- package/server/services/session-worker-stop-service.mjs +24 -13
- package/server/services/session-worker-supervisor-service.mjs +56 -1
- package/server/services/update-install-service.mjs +9 -3
- package/server/services/usage-limit-pause-service.mjs +3 -1
- package/server/services/worker-launch-note-service.mjs +151 -0
- package/shared/claude-attribution.mjs +117 -0
- package/shared/claude-cloud/api-client.mjs +809 -0
- package/shared/claude-cloud/base-url.mjs +47 -0
- package/shared/claude-cloud/credentials.mjs +221 -0
- package/shared/claude-cloud/repo-url.mjs +111 -0
- package/shared/provider-routing.mjs +4 -2
- package/shared/remote-relay-contract.mjs +153 -22
- package/shared/remote-relay-tool-core.mjs +11 -8
- package/shared/steer-settle-failure.mjs +1 -0
package/server/public/index.html
CHANGED
|
@@ -3,12 +3,23 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
|
|
6
|
-
<meta name="theme-color" content="#
|
|
6
|
+
<meta name="theme-color" content="#0d1117">
|
|
7
7
|
<meta name="application-name" content="OAR">
|
|
8
8
|
<meta name="apple-mobile-web-app-title" content="OAR">
|
|
9
9
|
<meta name="mobile-web-app-capable" content="yes">
|
|
10
10
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
11
11
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
12
|
+
<script>
|
|
13
|
+
// The stored Theme setting, applied before the first paint so the start
|
|
14
|
+
// screen (and its logo) already match it.
|
|
15
|
+
const __STORED_THEME = (() => {
|
|
16
|
+
try { return window.localStorage.getItem('copilot_theme') === 'light' ? 'light' : 'dark'; } catch { return 'dark'; }
|
|
17
|
+
})();
|
|
18
|
+
if (__STORED_THEME === 'light') {
|
|
19
|
+
document.documentElement.setAttribute('data-theme', 'light');
|
|
20
|
+
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', '#ffffff');
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
12
23
|
<script>
|
|
13
24
|
window.__COPILOT_APP_CONFIG = { basePath: '' };
|
|
14
25
|
const __APP_CONFIG = window.__COPILOT_APP_CONFIG;
|
|
@@ -163,13 +174,35 @@
|
|
|
163
174
|
if (errorEl) errorEl.textContent = 'Could not reach the relay';
|
|
164
175
|
}
|
|
165
176
|
};
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
// Manifest and tab icons for one theme: the dark icon set, or its
|
|
178
|
+
// `app-icon-light*` twin with a white launch background.
|
|
179
|
+
const __themeAssetLinks = (theme) => {
|
|
180
|
+
const light = theme === 'light';
|
|
181
|
+
const icon = light ? 'app-icon-light' : 'app-icon';
|
|
182
|
+
return [
|
|
183
|
+
...(__IS_SHARED_ROUTE ? [] : [
|
|
184
|
+
{ rel: 'manifest', href: `${__APP_BASE}/manifest.webmanifest?${__PWA_BUST}${light ? '&theme=light' : ''}` },
|
|
185
|
+
]),
|
|
186
|
+
{ rel: 'icon', type: 'image/png', sizes: '192x192', href: `${__APP_BASE}/${icon}-192.png?${__PWA_BUST}` },
|
|
187
|
+
{ rel: 'icon', type: 'image/png', sizes: '512x512', href: `${__APP_BASE}/${icon}-512.png?${__PWA_BUST}` },
|
|
188
|
+
{ rel: 'icon', type: 'image/svg+xml', href: `${__APP_BASE}/${icon}.svg?${__PWA_BUST}` },
|
|
189
|
+
{ rel: 'apple-touch-icon', href: `${__APP_BASE}/${icon}-192.png?${__PWA_BUST}` },
|
|
190
|
+
];
|
|
191
|
+
};
|
|
192
|
+
const __themeAssetLinkHtml = (theme) => __themeAssetLinks(theme)
|
|
193
|
+
.map((link) => `<link data-theme-asset="1" ${Object.entries(link).map(([key, value]) => `${key}="${value}"`).join(' ')}>`)
|
|
194
|
+
.join('');
|
|
195
|
+
document.write(__themeAssetLinkHtml(__STORED_THEME));
|
|
196
|
+
document.write(`<style>
|
|
197
|
+
.brand-logo { background-image: url("${__APP_BASE}/app-icon.svg?${__PWA_BUST}"); }
|
|
198
|
+
:root[data-theme="light"] .brand-logo { background-image: url("${__APP_BASE}/app-icon-light.svg?${__PWA_BUST}"); }
|
|
199
|
+
</style>`);
|
|
200
|
+
// A Theme change swaps them in place (settings-modal's updateTheme).
|
|
201
|
+
window.__applyThemeAssets = (theme) => {
|
|
202
|
+
const next = theme === 'light' ? 'light' : 'dark';
|
|
203
|
+
for (const node of Array.from(document.head.querySelectorAll('link[data-theme-asset]'))) node.remove();
|
|
204
|
+
document.head.insertAdjacentHTML('beforeend', __themeAssetLinkHtml(next));
|
|
205
|
+
};
|
|
173
206
|
</script>
|
|
174
207
|
<title>OAR — Open Agent Relay</title>
|
|
175
208
|
<script>document.write('<scr'+'ipt src="'+__APP_BASE+'/socket.io/socket.io.js"><\/scr'+'ipt>');</script>
|
|
@@ -256,6 +289,7 @@
|
|
|
256
289
|
--provider-claude: #e0855a;
|
|
257
290
|
--provider-cursor: #a78bfa;
|
|
258
291
|
--provider-grok: #e879f9;
|
|
292
|
+
--provider-claude-cloud: #7dd3fc;
|
|
259
293
|
--viewport-top-offset: 0px;
|
|
260
294
|
--header-safe-top: max(env(safe-area-inset-top, 0px), var(--viewport-top-offset, 0px));
|
|
261
295
|
--chat-header-top-base-desktop: 14px;
|
|
@@ -317,6 +351,7 @@
|
|
|
317
351
|
--provider-claude: #b4531f;
|
|
318
352
|
--provider-cursor: #6b3fd4;
|
|
319
353
|
--provider-grok: #a21caf;
|
|
354
|
+
--provider-claude-cloud: #0369a1;
|
|
320
355
|
--inline-code-bg: #eff1f3;
|
|
321
356
|
}
|
|
322
357
|
:root {
|
|
@@ -382,12 +417,44 @@
|
|
|
382
417
|
display: none; align-items: center; justify-content: center;
|
|
383
418
|
height: var(--app-height); padding: 24px;
|
|
384
419
|
}
|
|
420
|
+
/* The start screen lies over the page until the app (or the sign-in box)
|
|
421
|
+
is ready. In the installed app it takes over from the system's launch
|
|
422
|
+
screen: the logo starts where and as large as the launch screen showed
|
|
423
|
+
it, then settles into this layout while the label fades in. */
|
|
385
424
|
#startup-loading {
|
|
386
|
-
|
|
387
|
-
|
|
425
|
+
position: fixed; inset: 0; z-index: 10000;
|
|
426
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;
|
|
427
|
+
padding: 24px 24px 124px;
|
|
428
|
+
background: var(--bg);
|
|
388
429
|
color: var(--muted);
|
|
389
430
|
font-size: var(--fs-core-subtitle);
|
|
431
|
+
transition: opacity 150ms ease;
|
|
432
|
+
}
|
|
433
|
+
#startup-loading.is-leaving { opacity: 0; }
|
|
434
|
+
#startup-loading .brand-logo { width: 148px; height: 148px; }
|
|
435
|
+
#startup-loading.is-animated .brand-logo {
|
|
436
|
+
animation: startup-logo-settle 500ms cubic-bezier(0.22, 1, 0.36, 1) 200ms both;
|
|
390
437
|
}
|
|
438
|
+
#startup-loading.is-animated .startup-label {
|
|
439
|
+
animation: startup-label-in 400ms ease 450ms both;
|
|
440
|
+
}
|
|
441
|
+
#startup-loading .startup-label { transition: opacity 150ms ease; }
|
|
442
|
+
@keyframes startup-logo-settle {
|
|
443
|
+
from { transform: translate(var(--startup-dx, 0px), var(--startup-dy, 0px)) scale(var(--startup-scale, 1)); }
|
|
444
|
+
to { transform: none; }
|
|
445
|
+
}
|
|
446
|
+
@keyframes startup-label-in {
|
|
447
|
+
from { opacity: 0; }
|
|
448
|
+
to { opacity: 1; }
|
|
449
|
+
}
|
|
450
|
+
/* The logo for the active theme. A background, not an <img>: the browser
|
|
451
|
+
fetches only the one the matching rule names (the rules with the URLs are
|
|
452
|
+
written by the head script, which knows the relay's base path). */
|
|
453
|
+
.brand-logo {
|
|
454
|
+
width: 128px; height: 128px; flex: none;
|
|
455
|
+
background-position: center; background-size: contain; background-repeat: no-repeat;
|
|
456
|
+
}
|
|
457
|
+
.auth-box .brand-logo { width: 96px; height: 96px; margin: 0 auto 16px; }
|
|
391
458
|
.auth-box {
|
|
392
459
|
background: var(--bg2); border: 1px solid var(--border); border-radius: 12px;
|
|
393
460
|
padding: 40px 32px; width: 100%; max-width: 400px; text-align: center;
|
|
@@ -541,7 +608,7 @@
|
|
|
541
608
|
border-radius: 8px;
|
|
542
609
|
background: var(--bg2);
|
|
543
610
|
color: var(--text);
|
|
544
|
-
padding: 0
|
|
611
|
+
padding: 0 76px 0 10px;
|
|
545
612
|
font-size: var(--fs-meta-md);
|
|
546
613
|
}
|
|
547
614
|
/* iOS Safari zooms the page on focus for inputs under 16px, and the mobile
|
|
@@ -724,6 +791,7 @@
|
|
|
724
791
|
.conv-provider-indicator[data-provider="claude"] { color: var(--provider-claude); }
|
|
725
792
|
.conv-provider-indicator[data-provider="cursor"] { color: var(--provider-cursor); }
|
|
726
793
|
.conv-provider-indicator[data-provider="grok"] { color: var(--provider-grok); }
|
|
794
|
+
.conv-provider-indicator[data-provider="claude-cloud"] { color: var(--provider-claude-cloud); }
|
|
727
795
|
.conv-item.worker-ui-offline .conv-title,
|
|
728
796
|
#chat-title[data-ui-state="offline"] { color: var(--conversation-title-offline); }
|
|
729
797
|
.conv-item.worker-ui-ready .conv-title,
|
|
@@ -744,6 +812,70 @@
|
|
|
744
812
|
}
|
|
745
813
|
.conv-item:hover .conv-delete { opacity: 1; }
|
|
746
814
|
.conv-delete:hover { color: var(--danger); }
|
|
815
|
+
/* Archive / unarchive sits left of the bin, shown on hover like it. */
|
|
816
|
+
.conv-archive {
|
|
817
|
+
position: absolute; right: 34px; top: 50%; transform: translateY(-50%);
|
|
818
|
+
background: none; border: none; color: var(--muted); cursor: pointer; font-size: var(--fs-ui-icon);
|
|
819
|
+
opacity: 0; transition: opacity 0.15s; padding: 4px;
|
|
820
|
+
}
|
|
821
|
+
.conv-item:hover .conv-archive { opacity: 1; }
|
|
822
|
+
.conv-archive:hover { color: var(--text); }
|
|
823
|
+
.conv-item.archived .conv-title { color: var(--muted); }
|
|
824
|
+
/* The Archived view: a toggle in the filter row, a banner above the list. */
|
|
825
|
+
#conv-archived-toggle {
|
|
826
|
+
position: absolute;
|
|
827
|
+
top: 50%;
|
|
828
|
+
right: 46px;
|
|
829
|
+
transform: translateY(-50%);
|
|
830
|
+
height: 28px;
|
|
831
|
+
min-width: 28px;
|
|
832
|
+
padding: 0 6px;
|
|
833
|
+
border: 1px solid transparent;
|
|
834
|
+
border-radius: 6px;
|
|
835
|
+
background: transparent;
|
|
836
|
+
color: var(--muted);
|
|
837
|
+
cursor: pointer;
|
|
838
|
+
font-size: var(--fs-meta-md);
|
|
839
|
+
}
|
|
840
|
+
#conv-archived-toggle:hover { color: var(--text); border-color: var(--border); }
|
|
841
|
+
#conv-archived-toggle[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }
|
|
842
|
+
#conv-archived-banner {
|
|
843
|
+
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
844
|
+
margin: 0 16px 6px; padding: 6px 10px;
|
|
845
|
+
border: 1px solid var(--border); border-radius: 8px; background: var(--bg2);
|
|
846
|
+
font-size: var(--fs-meta-sm); color: var(--muted);
|
|
847
|
+
}
|
|
848
|
+
#conv-archived-banner[hidden] { display: none; }
|
|
849
|
+
.conv-archived-back {
|
|
850
|
+
border: 1px solid var(--border); border-radius: 6px; background: var(--bg3); color: var(--text);
|
|
851
|
+
font-size: var(--fs-meta-xs); padding: 2px 8px; cursor: pointer;
|
|
852
|
+
}
|
|
853
|
+
/* The conversation context menu (context-menu.mjs): right-click / long press. */
|
|
854
|
+
.context-menu {
|
|
855
|
+
position: fixed;
|
|
856
|
+
z-index: 1200;
|
|
857
|
+
min-width: 200px;
|
|
858
|
+
max-width: min(320px, calc(100vw - 8px));
|
|
859
|
+
padding: 4px;
|
|
860
|
+
display: flex;
|
|
861
|
+
flex-direction: column;
|
|
862
|
+
gap: 2px;
|
|
863
|
+
background: var(--bg2);
|
|
864
|
+
border: 1px solid var(--border);
|
|
865
|
+
border-radius: 10px;
|
|
866
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
867
|
+
}
|
|
868
|
+
.context-menu-item {
|
|
869
|
+
display: flex; align-items: center; gap: 8px; width: 100%; min-height: 34px;
|
|
870
|
+
border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--text);
|
|
871
|
+
padding: 0 10px; font: inherit; font-size: var(--fs-meta-md); text-align: left; cursor: pointer;
|
|
872
|
+
touch-action: manipulation; -webkit-tap-highlight-color: transparent;
|
|
873
|
+
}
|
|
874
|
+
.context-menu-item:hover, .context-menu-item:focus-visible { background: var(--bg3); border-color: var(--border); outline: none; }
|
|
875
|
+
.context-menu-item:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
876
|
+
.context-menu-item-danger { color: var(--danger); }
|
|
877
|
+
.context-menu-sep { height: 1px; margin: 3px 6px; background: var(--border); }
|
|
878
|
+
#conv-list .conv-item { -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
|
|
747
879
|
.conv-open-questions {
|
|
748
880
|
display: inline-flex;
|
|
749
881
|
margin-left: 6px;
|
|
@@ -1285,6 +1417,9 @@
|
|
|
1285
1417
|
padding: 2px 10px;
|
|
1286
1418
|
background: var(--bg2);
|
|
1287
1419
|
}
|
|
1420
|
+
/* A compaction that is still running: the label trails the bouncing dots. */
|
|
1421
|
+
.transcript-separator.is-pending .dots { margin-left: 6px; }
|
|
1422
|
+
.transcript-separator.is-pending .dots span { width: 4px; height: 4px; }
|
|
1288
1423
|
|
|
1289
1424
|
.empty-state {
|
|
1290
1425
|
flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
@@ -1434,6 +1569,17 @@
|
|
|
1434
1569
|
overflow-wrap: normal;
|
|
1435
1570
|
word-break: normal;
|
|
1436
1571
|
}
|
|
1572
|
+
/* An inline formula breaks only between its terms: one long term is a box
|
|
1573
|
+
wider than the bubble and made the whole bubble scroll sideways. It
|
|
1574
|
+
scrolls inside itself instead. */
|
|
1575
|
+
.msg-bubble :not(.katex-display) > .katex {
|
|
1576
|
+
display: inline-block;
|
|
1577
|
+
max-width: 100%;
|
|
1578
|
+
overflow-x: auto;
|
|
1579
|
+
overflow-y: hidden;
|
|
1580
|
+
vertical-align: bottom;
|
|
1581
|
+
-webkit-overflow-scrolling: touch;
|
|
1582
|
+
}
|
|
1437
1583
|
.katex-error {
|
|
1438
1584
|
color: var(--danger);
|
|
1439
1585
|
white-space: pre-wrap;
|
|
@@ -1666,6 +1812,12 @@
|
|
|
1666
1812
|
word-break: break-word;
|
|
1667
1813
|
}
|
|
1668
1814
|
.thinking-stream[hidden] { display: none; }
|
|
1815
|
+
.thinking-compacting-note {
|
|
1816
|
+
color: var(--muted);
|
|
1817
|
+
font-size: var(--fs-meta-sm);
|
|
1818
|
+
font-style: italic;
|
|
1819
|
+
}
|
|
1820
|
+
.thinking-compacting-note[hidden] { display: none; }
|
|
1669
1821
|
.thinking-stream > :first-child { margin-top: 0; }
|
|
1670
1822
|
.thinking-stream > :last-child { margin-bottom: 0; }
|
|
1671
1823
|
.thinking-activity {
|
|
@@ -2019,8 +2171,19 @@
|
|
|
2019
2171
|
font-size: 0.76rem;
|
|
2020
2172
|
color: var(--muted);
|
|
2021
2173
|
}
|
|
2174
|
+
.ctx-autocompact-notes { display: flex; flex-direction: column; gap: 4px; }
|
|
2175
|
+
.ctx-autocompact-notes:empty { display: none; }
|
|
2176
|
+
.ctx-autocompact-warning { color: var(--warn); }
|
|
2022
2177
|
/* Claude-only thinking control (on/off + text visibility), under the
|
|
2023
2178
|
auto-compact slider. */
|
|
2179
|
+
/* The folder's commit attribution (attribution-control.mjs), styled like
|
|
2180
|
+
the thinking rows above it. */
|
|
2181
|
+
.ctx-attribution { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
|
|
2182
|
+
.ctx-attribution-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
2183
|
+
.ctx-attribution-label { font-size: var(--fs-meta-sm); color: var(--muted); }
|
|
2184
|
+
.ctx-attribution-select { font-size: var(--fs-meta-sm); max-width: 100%; }
|
|
2185
|
+
.ctx-attribution-note { margin-top: 6px; font-size: var(--fs-meta-sm); color: var(--muted); line-height: 1.4; overflow-wrap: anywhere; }
|
|
2186
|
+
.ctx-attribution-note code { font-size: inherit; }
|
|
2024
2187
|
.ctx-thinking {
|
|
2025
2188
|
margin-top: 14px;
|
|
2026
2189
|
padding-top: 12px;
|
|
@@ -2119,6 +2282,13 @@
|
|
|
2119
2282
|
}
|
|
2120
2283
|
.plan-usage-card[data-status="unavailable"],
|
|
2121
2284
|
.plan-usage-card[data-status="not-configured"] { opacity: 0.72; }
|
|
2285
|
+
/* A card whose provider is being read live while the kept reading shows. */
|
|
2286
|
+
.plan-usage-card[data-updating] .plan-usage-card-title::after {
|
|
2287
|
+
content: " · updating…";
|
|
2288
|
+
font-weight: 400;
|
|
2289
|
+
font-size: 0.78rem;
|
|
2290
|
+
color: var(--muted);
|
|
2291
|
+
}
|
|
2122
2292
|
.plan-usage-card-head {
|
|
2123
2293
|
display: flex;
|
|
2124
2294
|
align-items: center;
|
|
@@ -2516,6 +2686,40 @@
|
|
|
2516
2686
|
#model-lock-note[data-provider="claude"] { color: var(--provider-claude); }
|
|
2517
2687
|
#model-lock-note[data-provider="cursor"] { color: var(--provider-cursor); }
|
|
2518
2688
|
#model-lock-note[data-provider="grok"] { color: var(--provider-grok); }
|
|
2689
|
+
#model-lock-note[data-provider="claude-cloud"] { color: var(--provider-claude-cloud); }
|
|
2690
|
+
/* Claude Cloud conversations (claude-cloud-conversation-ui.js): where the
|
|
2691
|
+
session runs and what it pushed, above the composer like the lock note.
|
|
2692
|
+
The items wrap instead of scrolling, so a long branch name can never push
|
|
2693
|
+
the composer wider than a phone. */
|
|
2694
|
+
#cloud-session-line {
|
|
2695
|
+
display: flex;
|
|
2696
|
+
flex-wrap: wrap;
|
|
2697
|
+
align-items: center;
|
|
2698
|
+
gap: 2px 10px;
|
|
2699
|
+
margin-bottom: 6px;
|
|
2700
|
+
min-width: 0;
|
|
2701
|
+
color: var(--muted);
|
|
2702
|
+
font-size: var(--fs-meta-sm);
|
|
2703
|
+
line-height: 1.4;
|
|
2704
|
+
}
|
|
2705
|
+
#cloud-session-line[hidden] { display: none; }
|
|
2706
|
+
.cloud-line-item {
|
|
2707
|
+
min-width: 0;
|
|
2708
|
+
max-width: 100%;
|
|
2709
|
+
overflow: hidden;
|
|
2710
|
+
text-overflow: ellipsis;
|
|
2711
|
+
white-space: nowrap;
|
|
2712
|
+
}
|
|
2713
|
+
a.cloud-line-item { color: var(--accent); text-decoration: none; }
|
|
2714
|
+
a.cloud-line-item:hover { text-decoration: underline; }
|
|
2715
|
+
.cloud-line-repo { color: var(--provider-claude-cloud); font-weight: 600; }
|
|
2716
|
+
a.cloud-line-repo { color: var(--provider-claude-cloud); }
|
|
2717
|
+
/* No relay modes, no effort choice and no context tier in a cloud chat. */
|
|
2718
|
+
body.claude-cloud-conversation #mode-select,
|
|
2719
|
+
body.claude-cloud-conversation #context-tier-select,
|
|
2720
|
+
body.claude-cloud-conversation #reasoning-effort-select {
|
|
2721
|
+
display: none;
|
|
2722
|
+
}
|
|
2519
2723
|
#model-select:disabled,
|
|
2520
2724
|
#reasoning-effort-select:disabled {
|
|
2521
2725
|
opacity: 0.55;
|
|
@@ -2822,6 +3026,46 @@
|
|
|
2822
3026
|
flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
2823
3027
|
color: var(--muted); font-size: var(--fs-ui-chip);
|
|
2824
3028
|
}
|
|
3029
|
+
/* "via agent · “title”": an agent on this relay started the conversation.
|
|
3030
|
+
A button while the conversation it runs in can be opened, a span when it
|
|
3031
|
+
is gone. The title is long, so in the sidebar the date keeps its share. */
|
|
3032
|
+
.conv-origin-marker.conv-origin-agent { max-width: 60%; }
|
|
3033
|
+
button.conv-origin-agent,
|
|
3034
|
+
button.msg-origin-badge {
|
|
3035
|
+
font-family: inherit; cursor: pointer; text-align: left;
|
|
3036
|
+
touch-action: manipulation; -webkit-tap-highlight-color: transparent;
|
|
3037
|
+
}
|
|
3038
|
+
button.conv-origin-agent {
|
|
3039
|
+
background: none; border: none; padding: 0; margin: 0; line-height: inherit;
|
|
3040
|
+
color: var(--accent);
|
|
3041
|
+
}
|
|
3042
|
+
/* A finger needs more than one line of chip text: the padding grows the
|
|
3043
|
+
button, the negative margin keeps the row's height. */
|
|
3044
|
+
button.conv-origin-marker.conv-origin-agent { padding: 6px 0; margin: -6px 0; }
|
|
3045
|
+
button.conv-origin-agent:hover,
|
|
3046
|
+
button.msg-origin-badge:hover { text-decoration: underline; }
|
|
3047
|
+
button.msg-origin-badge { color: inherit; }
|
|
3048
|
+
#chat-title-origin {
|
|
3049
|
+
display: block; margin-top: 2px; min-width: 0;
|
|
3050
|
+
font-size: var(--fs-meta-xs); line-height: 1.2; color: var(--muted);
|
|
3051
|
+
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
3052
|
+
}
|
|
3053
|
+
#chat-title-origin[hidden] { display: none; }
|
|
3054
|
+
#chat-title-origin .conv-origin-agent {
|
|
3055
|
+
display: block; max-width: 100%; font-size: inherit;
|
|
3056
|
+
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
3057
|
+
}
|
|
3058
|
+
#chat-title-origin button.conv-origin-agent { padding: 3px 0; }
|
|
3059
|
+
/* Agent sessions (Settings → Relays). The slider spans the row so a thumb
|
|
3060
|
+
has room to travel at phone width, with a taller touch area than the
|
|
3061
|
+
track itself. */
|
|
3062
|
+
#agent-sessions-section[hidden] { display: none; }
|
|
3063
|
+
#agent-sessions-max-wait-slider {
|
|
3064
|
+
width: min(420px, 100%); min-height: 32px; margin: 0; box-sizing: border-box;
|
|
3065
|
+
accent-color: var(--accent); touch-action: pan-y;
|
|
3066
|
+
}
|
|
3067
|
+
#agent-sessions-max-wait-slider:disabled { opacity: 0.5; }
|
|
3068
|
+
#agent-sessions-status { overflow-wrap: anywhere; }
|
|
2825
3069
|
/* Transcript card: a preview published during this turn, pinned into the
|
|
2826
3070
|
response bubble. Compact single row; closed previews keep the label but
|
|
2827
3071
|
lose the dead link. */
|
|
@@ -2865,6 +3109,11 @@
|
|
|
2865
3109
|
background: rgba(63, 185, 80, 0.12); color: var(--relay-tone-online);
|
|
2866
3110
|
border-radius: 6px; padding: 0 6px; font-size: var(--fs-meta-sm);
|
|
2867
3111
|
}
|
|
3112
|
+
/* The relay's note while a session's worker cannot be started
|
|
3113
|
+
(worker-launch-note-service.mjs): a notice of the relay's, not a reply.
|
|
3114
|
+
Amber while the relay keeps trying or has stopped, green once started. */
|
|
3115
|
+
.msg.assistant.msg-worker-launch .msg-bubble { border-left: 3px solid #d29922; }
|
|
3116
|
+
.msg.assistant.msg-worker-launch-started .msg-bubble { border-left-color: var(--relay-tone-online); }
|
|
2868
3117
|
/* Mid-turn steering. The CLI usually FOLDS a steered message into the
|
|
2869
3118
|
running turn and answers everything with one reply; the steered row then
|
|
2870
3119
|
settles as a compact marker under its own message (kind='folded'). More
|
|
@@ -2926,6 +3175,7 @@
|
|
|
2926
3175
|
body.shared-reader-mode #reasoning-effort-select,
|
|
2927
3176
|
body.shared-reader-mode #send-btn,
|
|
2928
3177
|
body.shared-reader-mode #model-lock-note,
|
|
3178
|
+
body.shared-reader-mode #cloud-session-line,
|
|
2929
3179
|
body.shared-reader-mode #model-pricing-details {
|
|
2930
3180
|
display: none !important;
|
|
2931
3181
|
}
|
|
@@ -3298,12 +3548,16 @@
|
|
|
3298
3548
|
#new-conversation-context-select,
|
|
3299
3549
|
#new-conversation-size-select,
|
|
3300
3550
|
#new-conversation-cwd-select,
|
|
3301
|
-
#new-conversation-cwd-manual
|
|
3551
|
+
#new-conversation-cwd-manual,
|
|
3552
|
+
#new-conversation-cloud-repo,
|
|
3553
|
+
#new-conversation-cloud-branch {
|
|
3302
3554
|
width: 100%;
|
|
3303
3555
|
min-height: 42px;
|
|
3304
3556
|
margin-top: 8px;
|
|
3305
3557
|
}
|
|
3306
|
-
#new-conversation-cwd-manual
|
|
3558
|
+
#new-conversation-cwd-manual,
|
|
3559
|
+
#new-conversation-cloud-repo,
|
|
3560
|
+
#new-conversation-cloud-branch {
|
|
3307
3561
|
box-sizing: border-box;
|
|
3308
3562
|
padding: 0 10px;
|
|
3309
3563
|
border-radius: 8px;
|
|
@@ -3312,6 +3566,84 @@
|
|
|
3312
3566
|
color: var(--text);
|
|
3313
3567
|
}
|
|
3314
3568
|
#new-conversation-cwd-manual[hidden] { display: none; }
|
|
3569
|
+
#new-conversation-cloud-repo[aria-invalid="true"],
|
|
3570
|
+
#new-conversation-cloud-branch[aria-invalid="true"] { border-color: var(--danger); }
|
|
3571
|
+
/* Warning lines under Repository/Branch: what the cloud clone will not see. */
|
|
3572
|
+
#new-conversation-cloud-warnings {
|
|
3573
|
+
margin-top: 8px;
|
|
3574
|
+
font-size: 0.78rem;
|
|
3575
|
+
line-height: 1.4;
|
|
3576
|
+
color: var(--warn);
|
|
3577
|
+
overflow-wrap: anywhere;
|
|
3578
|
+
}
|
|
3579
|
+
#new-conversation-cloud-warnings:empty { display: none; }
|
|
3580
|
+
.new-conversation-cloud-warning::before { content: "⚠ "; }
|
|
3581
|
+
#new-conversation-cloud-error {
|
|
3582
|
+
margin-top: 8px;
|
|
3583
|
+
font-size: 0.78rem;
|
|
3584
|
+
line-height: 1.4;
|
|
3585
|
+
color: var(--danger);
|
|
3586
|
+
overflow-wrap: anywhere;
|
|
3587
|
+
}
|
|
3588
|
+
#new-conversation-cloud-error[hidden] { display: none; }
|
|
3589
|
+
/* Suggestions under Repository/Branch: a list in the flow of the modal
|
|
3590
|
+
(not a floating one: the modal scrolls on a phone and a popover would
|
|
3591
|
+
be clipped), at most a few rows high, scrolling inside itself. */
|
|
3592
|
+
.new-conversation-cloud-suggest {
|
|
3593
|
+
margin-top: 4px;
|
|
3594
|
+
max-height: min(40vh, 220px);
|
|
3595
|
+
overflow-y: auto;
|
|
3596
|
+
border: 1px solid var(--border);
|
|
3597
|
+
border-radius: 8px;
|
|
3598
|
+
background: var(--bg3);
|
|
3599
|
+
}
|
|
3600
|
+
.new-conversation-cloud-suggest[hidden] { display: none; }
|
|
3601
|
+
.new-conversation-cloud-suggest-item {
|
|
3602
|
+
display: flex;
|
|
3603
|
+
align-items: baseline;
|
|
3604
|
+
justify-content: space-between;
|
|
3605
|
+
gap: 8px;
|
|
3606
|
+
width: 100%;
|
|
3607
|
+
box-sizing: border-box;
|
|
3608
|
+
min-height: 38px;
|
|
3609
|
+
padding: 8px 10px;
|
|
3610
|
+
border: 0;
|
|
3611
|
+
border-bottom: 1px solid var(--border);
|
|
3612
|
+
background: transparent;
|
|
3613
|
+
color: var(--text);
|
|
3614
|
+
font: inherit;
|
|
3615
|
+
text-align: left;
|
|
3616
|
+
cursor: pointer;
|
|
3617
|
+
overflow-wrap: anywhere;
|
|
3618
|
+
}
|
|
3619
|
+
.new-conversation-cloud-suggest-item:last-child { border-bottom: 0; }
|
|
3620
|
+
.new-conversation-cloud-suggest-item:hover,
|
|
3621
|
+
.new-conversation-cloud-suggest-item[aria-selected="true"] { background: var(--bg2); }
|
|
3622
|
+
.new-conversation-cloud-suggest-meta {
|
|
3623
|
+
flex: 0 0 auto;
|
|
3624
|
+
font-size: 0.72rem;
|
|
3625
|
+
color: var(--muted);
|
|
3626
|
+
white-space: nowrap;
|
|
3627
|
+
}
|
|
3628
|
+
.new-conversation-cloud-refresh {
|
|
3629
|
+
margin-left: 6px;
|
|
3630
|
+
padding: 0 6px;
|
|
3631
|
+
min-height: 22px;
|
|
3632
|
+
border: 1px solid transparent;
|
|
3633
|
+
border-radius: 6px;
|
|
3634
|
+
background: transparent;
|
|
3635
|
+
color: var(--muted);
|
|
3636
|
+
font: inherit;
|
|
3637
|
+
cursor: pointer;
|
|
3638
|
+
vertical-align: middle;
|
|
3639
|
+
}
|
|
3640
|
+
.new-conversation-cloud-refresh:hover { color: var(--text); border-color: var(--border); }
|
|
3641
|
+
.new-conversation-cloud-refresh[aria-busy="true"] { opacity: 0.5; cursor: progress; }
|
|
3642
|
+
.new-conversation-cloud-suggest-note {
|
|
3643
|
+
padding: 8px 10px;
|
|
3644
|
+
font-size: 0.78rem;
|
|
3645
|
+
color: var(--muted);
|
|
3646
|
+
}
|
|
3315
3647
|
/* Shared row/button recipe for the file-explorer CWD browse buttons in the
|
|
3316
3648
|
New chat and Change CWD modals — one place to restyle both. */
|
|
3317
3649
|
.cwd-browse-row {
|
|
@@ -4826,6 +5158,7 @@
|
|
|
4826
5158
|
#status-btn { min-width: 72px; padding: 9px 10px; font-size: var(--fs-meta-md); }
|
|
4827
5159
|
#conv-filter-row { padding: 8px 12px; }
|
|
4828
5160
|
#conv-filter-clear { right: 16px; }
|
|
5161
|
+
#conv-archived-toggle { right: 42px; }
|
|
4829
5162
|
#conv-list { padding: 0 5px 8px; }
|
|
4830
5163
|
.conv-item { padding: 6px 11px; border-radius: 8px; }
|
|
4831
5164
|
.conv-title {
|
|
@@ -4890,6 +5223,10 @@
|
|
|
4890
5223
|
overflow: hidden;
|
|
4891
5224
|
text-overflow: ellipsis;
|
|
4892
5225
|
}
|
|
5226
|
+
#chat-title-origin {
|
|
5227
|
+
margin-top: 1px;
|
|
5228
|
+
font-size: clamp(0.62rem, 2vw, 0.7rem);
|
|
5229
|
+
}
|
|
4893
5230
|
#chat-header-actions {
|
|
4894
5231
|
margin-left: auto;
|
|
4895
5232
|
}
|
|
@@ -5040,6 +5377,12 @@
|
|
|
5040
5377
|
font-size: var(--fs-meta-md);
|
|
5041
5378
|
}
|
|
5042
5379
|
#attach-btn { order: 4; flex: 0 0 40px; }
|
|
5380
|
+
/* A cloud chat hides mode, context tier and effort: the model select
|
|
5381
|
+
takes the room they leave. */
|
|
5382
|
+
body.claude-cloud-conversation #model-select {
|
|
5383
|
+
flex: 1 1 0;
|
|
5384
|
+
width: auto;
|
|
5385
|
+
}
|
|
5043
5386
|
#context-tier-select {
|
|
5044
5387
|
order: 5;
|
|
5045
5388
|
flex: 0 0 70px;
|
|
@@ -5319,6 +5662,18 @@
|
|
|
5319
5662
|
::-webkit-scrollbar { width: 6px; }
|
|
5320
5663
|
::-webkit-scrollbar-track { background: transparent; }
|
|
5321
5664
|
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
5665
|
+
/* With a mouse the track is twice as wide and the thumb is drawn thin in
|
|
5666
|
+
its middle; the thumb fills the track while the pointer is on the
|
|
5667
|
+
scrollbar and for a moment after (scrollbar-hover.mjs). The track keeps
|
|
5668
|
+
its width, so the page does not move when the thumb grows. */
|
|
5669
|
+
@media (hover: hover) and (pointer: fine) {
|
|
5670
|
+
::-webkit-scrollbar { width: 12px; }
|
|
5671
|
+
::-webkit-scrollbar-thumb {
|
|
5672
|
+
border: 3px solid transparent; border-top-width: 0; border-bottom-width: 0;
|
|
5673
|
+
background-clip: padding-box; border-radius: 6px;
|
|
5674
|
+
}
|
|
5675
|
+
.scrollbar-wide::-webkit-scrollbar-thumb { border-width: 0; background: var(--muted); }
|
|
5676
|
+
}
|
|
5322
5677
|
</style>
|
|
5323
5678
|
</head>
|
|
5324
5679
|
<body>
|
|
@@ -5326,7 +5681,8 @@
|
|
|
5326
5681
|
<!-- Auth Gate -->
|
|
5327
5682
|
<div id="auth-gate">
|
|
5328
5683
|
<div class="auth-box">
|
|
5329
|
-
<
|
|
5684
|
+
<div class="brand-logo" aria-hidden="true"></div>
|
|
5685
|
+
<h1>OAR</h1>
|
|
5330
5686
|
<p>Enter your access token to connect</p>
|
|
5331
5687
|
<input id="token-input" type="password" placeholder="Access token" autofocus onkeydown="if(event.key==='Enter')window.__copilotAuthConnect(event)">
|
|
5332
5688
|
<button onclick="window.__copilotAuthConnect(event)">Connect</button>
|
|
@@ -5334,7 +5690,87 @@
|
|
|
5334
5690
|
</div>
|
|
5335
5691
|
</div>
|
|
5336
5692
|
|
|
5337
|
-
<div id="startup-loading" role="status" aria-live="polite">Connecting to OAR…</div>
|
|
5693
|
+
<div id="startup-loading" role="status" aria-live="polite"><div class="brand-logo" aria-hidden="true"></div><div class="startup-label">Connecting to OAR…</div></div>
|
|
5694
|
+
<script>
|
|
5695
|
+
// The start screen's hand-over from the system launch screen, and its two
|
|
5696
|
+
// ways out: into the app (finish) or into the sign-in box (toAuth). Only the
|
|
5697
|
+
// installed app animates and makes its exits wait for the animation; a
|
|
5698
|
+
// browser tab has no launch screen to continue from and leaves at once.
|
|
5699
|
+
window.__startupSplash = (() => {
|
|
5700
|
+
const root = document.getElementById('startup-loading');
|
|
5701
|
+
const logo = root.querySelector('.brand-logo');
|
|
5702
|
+
const label = root.querySelector('.startup-label');
|
|
5703
|
+
const media = (query) => { try { return window.matchMedia(query).matches; } catch { return false; } };
|
|
5704
|
+
const installed = media('(display-mode: standalone)') || media('(display-mode: fullscreen)')
|
|
5705
|
+
|| window.navigator.standalone === true;
|
|
5706
|
+
const animated = installed && !media('(prefers-reduced-motion: reduce)');
|
|
5707
|
+
const wait = (ms) => new Promise((resolve) => { setTimeout(resolve, ms); });
|
|
5708
|
+
let done = Promise.resolve();
|
|
5709
|
+
if (animated) {
|
|
5710
|
+
// Android draws its launch icon around the centre of the whole screen,
|
|
5711
|
+
// 275 px across for a maskable icon, which makes the otter 155 px wide.
|
|
5712
|
+
// The tile used here carries the otter at 373/512 of its width.
|
|
5713
|
+
const LAUNCH_TILE_PX = 155.2 / (373 / 512);
|
|
5714
|
+
// The page only knows the sum of the system bars; a three-button
|
|
5715
|
+
// navigation bar (48 px) is assumed for the split.
|
|
5716
|
+
const NAV_BAR_PX = 48;
|
|
5717
|
+
const rect = logo.getBoundingClientRect();
|
|
5718
|
+
const bars = Math.max(0, (window.screen?.height || window.innerHeight) - window.innerHeight);
|
|
5719
|
+
const topBar = Math.max(0, bars - NAV_BAR_PX);
|
|
5720
|
+
let targetY = (window.screen?.height || window.innerHeight) / 2 - topBar;
|
|
5721
|
+
// An implausible reading (split screen, a desktop window) falls back to
|
|
5722
|
+
// the middle of the page.
|
|
5723
|
+
if (!(Math.abs(targetY - window.innerHeight / 2) <= 60)) targetY = window.innerHeight / 2;
|
|
5724
|
+
root.style.setProperty('--startup-dx', `${window.innerWidth / 2 - (rect.left + rect.width / 2)}px`);
|
|
5725
|
+
root.style.setProperty('--startup-dy', `${targetY - (rect.top + rect.height / 2)}px`);
|
|
5726
|
+
root.style.setProperty('--startup-scale', String(LAUNCH_TILE_PX / rect.width));
|
|
5727
|
+
root.classList.add('is-animated');
|
|
5728
|
+
// Rest 200 ms, settle 500 ms; the label's fade ends at 850 ms.
|
|
5729
|
+
done = wait(850);
|
|
5730
|
+
}
|
|
5731
|
+
let left = null;
|
|
5732
|
+
const leave = (run) => {
|
|
5733
|
+
// Removed whatever happens on the way out: a start screen left over
|
|
5734
|
+
// the page would cover the whole app.
|
|
5735
|
+
if (!left) {
|
|
5736
|
+
left = (animated && root.isConnected ? done.then(run) : Promise.resolve())
|
|
5737
|
+
.catch(() => {})
|
|
5738
|
+
.then(() => { root.remove(); });
|
|
5739
|
+
}
|
|
5740
|
+
return left;
|
|
5741
|
+
};
|
|
5742
|
+
return {
|
|
5743
|
+
animated,
|
|
5744
|
+
// Into the app: fade the start screen away over the page below it.
|
|
5745
|
+
finish: () => leave(async () => {
|
|
5746
|
+
root.classList.add('is-leaving');
|
|
5747
|
+
await wait(150);
|
|
5748
|
+
}),
|
|
5749
|
+
// Into the sign-in box: the logo travels on into the box's own logo
|
|
5750
|
+
// place, shrinking to its size, and the box fades in around it.
|
|
5751
|
+
toAuth: () => leave(async () => {
|
|
5752
|
+
const box = document.querySelector('#auth-gate .auth-box');
|
|
5753
|
+
const target = box?.querySelector('.brand-logo')?.getBoundingClientRect();
|
|
5754
|
+
if (!box || !target || !target.width) return;
|
|
5755
|
+
box.style.opacity = '0';
|
|
5756
|
+
root.style.background = 'transparent';
|
|
5757
|
+
label.style.animation = 'none';
|
|
5758
|
+
label.style.opacity = '0';
|
|
5759
|
+
const from = logo.getBoundingClientRect();
|
|
5760
|
+
logo.style.animation = 'none';
|
|
5761
|
+
logo.style.transition = 'transform 450ms cubic-bezier(0.22, 1, 0.36, 1)';
|
|
5762
|
+
logo.style.transform = `translate(${target.left + target.width / 2 - (from.left + from.width / 2)}px, `
|
|
5763
|
+
+ `${target.top + target.height / 2 - (from.top + from.height / 2)}px) scale(${target.width / from.width})`;
|
|
5764
|
+
await wait(450);
|
|
5765
|
+
box.style.transition = 'opacity 300ms ease';
|
|
5766
|
+
box.style.opacity = '1';
|
|
5767
|
+
await wait(300);
|
|
5768
|
+
box.style.transition = '';
|
|
5769
|
+
box.style.opacity = '';
|
|
5770
|
+
}),
|
|
5771
|
+
};
|
|
5772
|
+
})();
|
|
5773
|
+
</script>
|
|
5338
5774
|
|
|
5339
5775
|
<!-- Sidebar overlay (mobile) -->
|
|
5340
5776
|
<div id="sidebar-overlay" onclick="closeSidebar()"></div>
|
|
@@ -5357,8 +5793,10 @@
|
|
|
5357
5793
|
<div id="conv-filter-row">
|
|
5358
5794
|
<input id="conv-filter-input" type="text" placeholder="Filter conversations…" autocomplete="off" spellcheck="false" aria-label="Filter conversations by title">
|
|
5359
5795
|
<button id="conv-filter-clear" type="button" title="Clear filter" aria-label="Clear filter" hidden>×</button>
|
|
5796
|
+
<button id="conv-archived-toggle" type="button" title="Show archived conversations" aria-label="Show archived conversations" aria-pressed="false" onclick="toggleArchivedConversations()">🗄</button>
|
|
5360
5797
|
<div id="conv-filter-status" role="status" aria-live="polite"></div>
|
|
5361
5798
|
</div>
|
|
5799
|
+
<div id="conv-archived-banner" hidden>Archived conversations <button type="button" class="conv-archived-back" onclick="toggleArchivedConversations()">Back to the list</button></div>
|
|
5362
5800
|
<div id="conv-list"></div>
|
|
5363
5801
|
</div>
|
|
5364
5802
|
<div id="sidebar-resizer" role="separator" aria-orientation="vertical" aria-label="Resize conversations sidebar"></div>
|
|
@@ -5367,7 +5805,7 @@
|
|
|
5367
5805
|
<div id="chat-header">
|
|
5368
5806
|
<button id="sidebar-toggle" class="header-icon-btn" type="button" title="Toggle conversations sidebar" aria-label="Toggle conversations sidebar">☰</button>
|
|
5369
5807
|
<div id="chat-title-wrap">
|
|
5370
|
-
<span id="chat-title-slot"><span id="chat-title-primary"><span id="chat-title-watch-indicator" hidden>👁️ </span><span id="chat-title">Select or start a conversation</span></span><span id="chat-title-cwd" hidden></span><span id="chat-title-session-usage" hidden></span></span>
|
|
5808
|
+
<span id="chat-title-slot"><span id="chat-title-primary"><span id="chat-title-watch-indicator" hidden>👁️ </span><span id="chat-title">Select or start a conversation</span></span><span id="chat-title-origin" hidden></span><span id="chat-title-cwd" hidden></span><span id="chat-title-session-usage" hidden></span></span>
|
|
5371
5809
|
<form id="chat-title-editor" hidden>
|
|
5372
5810
|
<input id="chat-title-input" type="text" maxlength="120" autocomplete="off" spellcheck="false">
|
|
5373
5811
|
<button id="chat-title-save-btn" class="chat-title-action-btn" type="submit">Save</button>
|
|
@@ -5387,11 +5825,13 @@
|
|
|
5387
5825
|
<button id="chat-menu-usage" class="chat-actions-menu-item" type="button" role="menuitem">📊 Check Usage</button>
|
|
5388
5826
|
<button id="chat-menu-compact" class="chat-actions-menu-item" type="button" role="menuitem" hidden disabled aria-hidden="true" tabindex="-1" style="display:none">🗜️ Compact</button>
|
|
5389
5827
|
<button id="chat-menu-share-conversation" class="chat-actions-menu-item" type="button" role="menuitem">➡️ Share conversation</button>
|
|
5828
|
+
<button id="chat-menu-archive" class="chat-actions-menu-item" type="button" role="menuitem">🗄 Archive conversation</button>
|
|
5390
5829
|
<button id="chat-menu-refresh-history" class="chat-actions-menu-item" type="button" role="menuitem" hidden disabled aria-hidden="true" tabindex="-1" style="display:none">🔄️ Refresh history</button>
|
|
5391
5830
|
<button id="chat-menu-inspect-tmux" class="chat-actions-menu-item" type="button" role="menuitem">🖥️ Inspect tmux console</button>
|
|
5392
5831
|
<button id="chat-menu-select-models" class="chat-actions-menu-item" type="button" role="menuitem">🤗 Select Models</button>
|
|
5393
5832
|
<button id="chat-menu-change-cwd" class="chat-actions-menu-item" type="button" role="menuitem">🗂️ Change CWD</button>
|
|
5394
5833
|
<button id="chat-menu-git-changes" class="chat-actions-menu-item" type="button" role="menuitem">🌿 Git changes</button>
|
|
5834
|
+
<button id="chat-menu-open-cloud-session" class="chat-actions-menu-item" type="button" role="menuitem" hidden>☁️ Open on claude.ai</button>
|
|
5395
5835
|
<button id="chat-menu-settings" class="chat-actions-menu-item" type="button" role="menuitem">⚙️ Settings</button>
|
|
5396
5836
|
<button id="chat-menu-restart-relay" class="chat-actions-menu-item" type="button" role="menuitem">🌄 Restart web relay</button>
|
|
5397
5837
|
<button id="chat-menu-suspend-host" class="chat-actions-menu-item" type="button" role="menuitem" onclick="openSuspendHostConfirmation()">💤 Suspend host</button>
|
|
@@ -5414,6 +5854,7 @@
|
|
|
5414
5854
|
<div id="model-banner"></div>
|
|
5415
5855
|
<div id="usage-limit-banner" role="status" aria-live="polite" hidden></div>
|
|
5416
5856
|
<div id="model-lock-note" hidden></div>
|
|
5857
|
+
<div id="cloud-session-line" aria-label="Cloud session" hidden></div>
|
|
5417
5858
|
<div id="model-metadata-blocker" aria-live="polite">
|
|
5418
5859
|
<span id="model-metadata-blocker-text">Model metadata is unavailable. Refresh to choose a model and reasoning effort.</span>
|
|
5419
5860
|
<button type="button" id="model-metadata-retry-btn">Refresh models</button>
|
|
@@ -5794,6 +6235,16 @@
|
|
|
5794
6235
|
tabindex="-1"
|
|
5795
6236
|
data-settings-provider-tab="claude"
|
|
5796
6237
|
>Claude</button>
|
|
6238
|
+
<button
|
|
6239
|
+
id="settings-provider-tab-claude-cloud"
|
|
6240
|
+
class="settings-tab settings-subtab"
|
|
6241
|
+
type="button"
|
|
6242
|
+
role="tab"
|
|
6243
|
+
aria-selected="false"
|
|
6244
|
+
aria-controls="settings-provider-panel-claude-cloud"
|
|
6245
|
+
tabindex="-1"
|
|
6246
|
+
data-settings-provider-tab="claude-cloud"
|
|
6247
|
+
>Claude Cloud</button>
|
|
5797
6248
|
<button
|
|
5798
6249
|
id="settings-provider-tab-grok"
|
|
5799
6250
|
class="settings-tab settings-subtab"
|
|
@@ -5982,6 +6433,13 @@
|
|
|
5982
6433
|
placeholder="claude-sonnet-5"
|
|
5983
6434
|
aria-label="Claude model ID"
|
|
5984
6435
|
>
|
|
6436
|
+
<label for="claude-attribution-select" style="margin-top: 8px;">Commit attribution</label>
|
|
6437
|
+
<select id="claude-attribution-select" aria-label="Commit attribution" onchange="window.previewClaudeAttribution?.(this.value)">
|
|
6438
|
+
<option value="oar">OAR — Co-authored-by: Open Agent Relay (model)</option>
|
|
6439
|
+
<option value="vanilla">Vanilla — Claude Code's own attribution</option>
|
|
6440
|
+
<option value="off">Off — no attribution</option>
|
|
6441
|
+
</select>
|
|
6442
|
+
<div id="claude-attribution-example" class="settings-help"></div>
|
|
5985
6443
|
<div id="claude-settings-status" class="settings-help settings-provider-status">Loading Claude settings…</div>
|
|
5986
6444
|
<div style="display: flex; gap: 8px; margin-top: 8px;">
|
|
5987
6445
|
<button id="claude-save-btn" type="button" class="summary-btn" onclick="saveClaudeSettings()">Save Claude settings</button>
|
|
@@ -5989,6 +6447,42 @@
|
|
|
5989
6447
|
<div class="settings-help">Runs Claude conversations through the Claude Agent SDK using the relay host's logged-in Claude credentials (no API key stored). Disabling also rebinds conversations that have not sent a message yet.</div>
|
|
5990
6448
|
</div>
|
|
5991
6449
|
</div>
|
|
6450
|
+
<!-- Claude Cloud (claude-cloud-settings-ui.js). The login itself is managed on
|
|
6451
|
+
the Claude tab; this panel only says which account pays. -->
|
|
6452
|
+
<div
|
|
6453
|
+
id="settings-provider-panel-claude-cloud"
|
|
6454
|
+
class="settings-panel"
|
|
6455
|
+
role="tabpanel"
|
|
6456
|
+
tabindex="0"
|
|
6457
|
+
aria-labelledby="settings-provider-tab-claude-cloud"
|
|
6458
|
+
data-settings-provider-panel="claude-cloud"
|
|
6459
|
+
hidden
|
|
6460
|
+
>
|
|
6461
|
+
<div class="settings-row settings-row-column" style="margin-top: 12px; margin-bottom: 0;">
|
|
6462
|
+
<label for="claude-cloud-enabled-toggle">Claude Cloud</label>
|
|
6463
|
+
<div class="settings-help">Cloud chats run Claude Code in a sandbox at Anthropic, on its own clone of a GitHub repository, instead of on the relay host. They are billed to the Claude account below. The relay reads that account's login from the Claude CLI on the relay host; it does not store it or refresh it.</div>
|
|
6464
|
+
<div class="settings-row" style="width: 100%; margin-top: 8px; margin-bottom: 8px;">
|
|
6465
|
+
<label for="claude-cloud-enabled-toggle">Enable Claude Cloud for New Chat</label>
|
|
6466
|
+
<input id="claude-cloud-enabled-toggle" type="checkbox" onchange="toggleClaudeCloudProvider(this.checked)" disabled>
|
|
6467
|
+
</div>
|
|
6468
|
+
<div id="claude-cloud-account-row" class="settings-row" style="width: 100%; margin-bottom: 0;" hidden>
|
|
6469
|
+
<div id="claude-cloud-account" class="settings-help settings-provider-status" style="min-width: 0; overflow-wrap: anywhere;"></div>
|
|
6470
|
+
<button id="claude-cloud-login-btn" type="button" class="summary-btn" style="flex: 0 0 auto;" onclick="openClaudeCloudLoginTab()">Claude login</button>
|
|
6471
|
+
</div>
|
|
6472
|
+
<div id="claude-cloud-token" class="settings-help settings-provider-status" style="margin-top: 6px;" hidden></div>
|
|
6473
|
+
<label for="claude-cloud-environment-select" style="margin-top: 12px;">Cloud environment</label>
|
|
6474
|
+
<select id="claude-cloud-environment-select" aria-label="Cloud environment" style="max-width: 100%;" disabled></select>
|
|
6475
|
+
<div id="claude-cloud-environment-note" class="settings-help" hidden></div>
|
|
6476
|
+
<label for="claude-cloud-model-select" style="margin-top: 8px;">Default model</label>
|
|
6477
|
+
<select id="claude-cloud-model-select" aria-label="Default model for cloud chats" style="max-width: 100%;" disabled></select>
|
|
6478
|
+
<div id="claude-cloud-settings-status" class="settings-help settings-provider-status">Loading Claude Cloud settings…</div>
|
|
6479
|
+
<div style="display: flex; gap: 8px 12px; margin-top: 8px; flex-wrap: wrap; align-items: center;">
|
|
6480
|
+
<button id="claude-cloud-save-btn" type="button" class="summary-btn" onclick="saveClaudeCloudSettings()" disabled>Save Claude Cloud settings</button>
|
|
6481
|
+
<a id="claude-cloud-open-link" class="plan-usage-link" href="https://claude.ai/code" target="_blank" rel="noopener noreferrer" style="font-size: var(--fs-meta-sm);">Open claude.ai/code</a>
|
|
6482
|
+
</div>
|
|
6483
|
+
<div class="settings-help">A cloud chat works on what is pushed to GitHub, and its results come back as pushed branches. It has no relay modes, no reasoning effort choice and no mid-turn steering, and it takes images as its only attachments.</div>
|
|
6484
|
+
</div>
|
|
6485
|
+
</div>
|
|
5992
6486
|
<div
|
|
5993
6487
|
id="settings-provider-panel-grok"
|
|
5994
6488
|
class="settings-panel"
|
|
@@ -6240,6 +6734,42 @@
|
|
|
6240
6734
|
>
|
|
6241
6735
|
</div>
|
|
6242
6736
|
<div class="settings-help" style="margin-top: 6px;">When off, agents on paired relays can still read sessions here, but cannot send prompts, start sessions, answer questions or stop turns. The relay token stays the real boundary: anyone holding it has full access.</div>
|
|
6737
|
+
<!-- Agent sessions (agent-sessions-settings-ui.js). Hidden until the relay
|
|
6738
|
+
answers with settings; a relay without the route never shows it. -->
|
|
6739
|
+
<div id="agent-sessions-section" hidden>
|
|
6740
|
+
<div class="settings-row settings-row-column" style="margin-top: 16px; margin-bottom: 0;">
|
|
6741
|
+
<label>Agent sessions</label>
|
|
6742
|
+
</div>
|
|
6743
|
+
<div class="settings-row" style="margin-top: 6px; margin-bottom: 0;">
|
|
6744
|
+
<label for="agent-sessions-enabled-toggle" style="font-weight: normal;">Agents may start and use sessions on this relay</label>
|
|
6745
|
+
<input
|
|
6746
|
+
id="agent-sessions-enabled-toggle"
|
|
6747
|
+
type="checkbox"
|
|
6748
|
+
onchange="toggleAgentSessions(this.checked)"
|
|
6749
|
+
aria-label="Agents may start and use sessions on this relay"
|
|
6750
|
+
disabled
|
|
6751
|
+
>
|
|
6752
|
+
</div>
|
|
6753
|
+
<div class="settings-help" style="margin-top: 6px;">Sessions an agent starts use this relay's accounts. The first one in a conversation asks for your approval. <span id="agent-sessions-cap" hidden></span></div>
|
|
6754
|
+
<div class="settings-row settings-row-column" style="margin-top: 12px; margin-bottom: 0;">
|
|
6755
|
+
<label for="agent-sessions-max-wait-slider">Longest wait per tool call <span id="agent-sessions-max-wait-value">10 min</span></label>
|
|
6756
|
+
<input
|
|
6757
|
+
id="agent-sessions-max-wait-slider"
|
|
6758
|
+
type="range"
|
|
6759
|
+
min="120"
|
|
6760
|
+
max="3600"
|
|
6761
|
+
step="60"
|
|
6762
|
+
value="600"
|
|
6763
|
+
aria-label="Longest wait per tool call"
|
|
6764
|
+
aria-valuetext="10 min"
|
|
6765
|
+
oninput="previewAgentSessionsMaxWait(this.value)"
|
|
6766
|
+
onchange="saveAgentSessionsMaxWait(this.value)"
|
|
6767
|
+
disabled
|
|
6768
|
+
>
|
|
6769
|
+
</div>
|
|
6770
|
+
<div class="settings-help" style="margin-top: 6px;">How long an agent may wait for a session in one call, on this relay or a paired one. It can call again to keep waiting.</div>
|
|
6771
|
+
<div id="agent-sessions-status" class="settings-help settings-provider-status" style="margin-top: 6px;" role="status" aria-live="polite" hidden></div>
|
|
6772
|
+
</div>
|
|
6243
6773
|
<div id="remote-relays-list-section" class="settings-row settings-row-column" style="margin-top: 16px; margin-bottom: 0;">
|
|
6244
6774
|
<label>Remote relays</label>
|
|
6245
6775
|
<div id="remote-relays-list"></div>
|
|
@@ -6414,11 +6944,25 @@
|
|
|
6414
6944
|
</select>
|
|
6415
6945
|
<div id="new-conversation-provider-help" style="margin-top:8px;font-size:0.78rem;color:var(--muted);">Copilot models use your GitHub Copilot runtime.</div>
|
|
6416
6946
|
</div>
|
|
6947
|
+
<!-- Claude Cloud only (journal-view.js): the GitHub repository and branch
|
|
6948
|
+
the cloud session clones, filled from the folder picked above. -->
|
|
6949
|
+
<div id="new-conversation-cloud-row" hidden>
|
|
6950
|
+
<label for="new-conversation-cloud-repo" style="display:block;margin-top:12px;">Repository <button id="new-conversation-cloud-repo-refresh" type="button" class="new-conversation-cloud-refresh" title="Read the repository list again" aria-label="Read the repository list again" onclick="refreshNewConversationCloudRepoList()">↻</button></label>
|
|
6951
|
+
<input id="new-conversation-cloud-repo" type="text" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="new-conversation-cloud-repo-list" inputmode="url" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="owner/repo or GitHub URL" aria-describedby="new-conversation-cloud-warnings new-conversation-cloud-error">
|
|
6952
|
+
<div id="new-conversation-cloud-repo-list" class="new-conversation-cloud-suggest" role="listbox" aria-label="Repositories" hidden></div>
|
|
6953
|
+
<label for="new-conversation-cloud-branch" style="display:block;margin-top:12px;">Branch</label>
|
|
6954
|
+
<input id="new-conversation-cloud-branch" type="text" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="new-conversation-cloud-branch-list" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Default branch" aria-describedby="new-conversation-cloud-warnings new-conversation-cloud-error">
|
|
6955
|
+
<div id="new-conversation-cloud-branch-list" class="new-conversation-cloud-suggest" role="listbox" aria-label="Branches" hidden></div>
|
|
6956
|
+
<div id="new-conversation-cloud-warnings" role="status" aria-live="polite"></div>
|
|
6957
|
+
<div id="new-conversation-cloud-error" role="alert" hidden></div>
|
|
6958
|
+
</div>
|
|
6417
6959
|
<label for="new-conversation-model-select" style="display:block;margin-top:12px;">Model</label>
|
|
6418
6960
|
<select id="new-conversation-model-select"></select>
|
|
6419
|
-
<
|
|
6420
|
-
|
|
6421
|
-
|
|
6961
|
+
<div id="new-conversation-reasoning-row">
|
|
6962
|
+
<label for="new-conversation-reasoning-select" style="display:block;margin-top:12px;">Reasoning effort</label>
|
|
6963
|
+
<select id="new-conversation-reasoning-select"></select>
|
|
6964
|
+
<div id="new-conversation-reasoning-status" style="margin-top:8px;font-size:0.78rem;color:var(--muted);">Choose the effort used when this conversation starts.</div>
|
|
6965
|
+
</div>
|
|
6422
6966
|
<div id="new-conversation-context-row" style="display:none;">
|
|
6423
6967
|
<label for="new-conversation-context-select" style="display:block;margin-top:12px;">Context window</label>
|
|
6424
6968
|
<select id="new-conversation-context-select" disabled aria-readonly="true"></select>
|
|
@@ -6534,8 +7078,8 @@
|
|
|
6534
7078
|
|
|
6535
7079
|
<script>
|
|
6536
7080
|
window.__loadCopilotApp().catch((error) => {
|
|
6537
|
-
document.getElementById('startup-loading')?.remove();
|
|
6538
7081
|
document.getElementById('auth-gate').style.display = 'flex';
|
|
7082
|
+
void window.__startupSplash.toAuth();
|
|
6539
7083
|
const errorEl = document.getElementById('auth-error');
|
|
6540
7084
|
if (errorEl) errorEl.textContent = `App failed to initialize: ${String(error?.message || error || 'unknown error')}`;
|
|
6541
7085
|
});
|