@oar-sh/oar 0.9.10 → 0.9.11
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 +314 -1
- package/README.md +156 -972
- package/package.json +13 -13
- package/server/README.md +95 -22
- package/server/claude-worker/claude-session-process.mjs +89 -11
- package/server/claude-worker/claude-session-worker.mjs +9 -1
- package/server/copilot-worker/copilot-sdk-session-process.mjs +76 -11
- package/server/copilot-worker/copilot-sdk-session-worker.mjs +6 -0
- package/server/db-schema.mjs +59 -2
- package/server/grok-worker/acp-client.mjs +2 -1
- package/server/grok-worker/acp-host-services.mjs +4 -3
- package/server/migrations/0013-previews.mjs +130 -0
- package/server/migrations/0014-conversation-groups.mjs +89 -0
- package/server/migrations/0015-conversation-group-position.mjs +76 -0
- package/server/migrations/0016-share-access-log.mjs +110 -0
- package/server/public/app/about-ui.js +73 -0
- package/server/public/app/about-view.mjs +234 -0
- package/server/public/app/action-confirmations.js +31 -14
- package/server/public/app/agent-exchange-fold-view.mjs +40 -101
- package/server/public/app/api-client.js +251 -16
- package/server/public/app/ask-user-view.js +17 -15
- package/server/public/app/bootstrap.js +158 -32
- package/server/public/app/chat-actions-menu-state.mjs +20 -10
- package/server/public/app/context-menu.mjs +90 -6
- package/server/public/app/conversation-group-drag.mjs +191 -0
- package/server/public/app/conversation-group-order.mjs +265 -0
- package/server/public/app/conversation-group-state.mjs +100 -0
- package/server/public/app/conversation-list-drag.mjs +449 -0
- package/server/public/app/conversation-turn-state.mjs +81 -0
- package/server/public/app/conversation-view.js +136 -93
- package/server/public/app/cwd-picker.js +1 -1
- package/server/public/app/hidden-messages-view.mjs +312 -0
- package/server/public/app/host-suspend-ui.js +7 -1
- package/server/public/app/journal-view.js +787 -22
- package/server/public/app/preview-cards.mjs +117 -31
- package/server/public/app/preview-command.mjs +10 -1
- package/server/public/app/relay-board-view.js +19 -6
- package/server/public/app/relay-restart-error.mjs +16 -0
- package/server/public/app/settings-modal.js +40 -8
- package/server/public/app/settings-tabs.js +1 -1
- package/server/public/app/share-format.mjs +49 -0
- package/server/public/app/share-preview-marks.mjs +167 -0
- package/server/public/app/share-state.js +109 -0
- package/server/public/app/shared-conversations-settings.js +480 -0
- package/server/public/app/socket-handlers.js +80 -14
- package/server/public/app/store.js +96 -30
- package/server/public/app/subagent-row.mjs +3 -3
- package/server/public/app/subagent-viewer.mjs +30 -6
- package/server/public/app/thinking-follow.js +0 -4
- package/server/public/app/transcript-jump-bottom-view.mjs +194 -20
- package/server/public/app/transcript-jump-bottom.mjs +132 -21
- package/server/public/app/transcript-viewport-anchor.mjs +140 -0
- package/server/public/index.html +386 -15
- package/server/relay-tools.md +2 -1
- package/server/relay.mjs +2 -1
- package/server/repositories/conversation-group-repository.mjs +444 -0
- package/server/repositories/message-repository.mjs +1 -0
- package/server/repositories/session-repository.mjs +12 -37
- package/server/repositories/share-repository.mjs +322 -0
- package/server/repositories/share-visibility-statements.mjs +10 -0
- package/server/routes/about-routes.mjs +15 -0
- package/server/routes/cache-routes.mjs +4 -0
- package/server/routes/conversation-group-routes.mjs +171 -0
- package/server/routes/messages-routes.mjs +184 -65
- package/server/routes/preview-routes.mjs +9 -1
- package/server/routes/sessions-routes.mjs +771 -193
- package/server/server-runtime.mjs +316 -100
- package/server/services/about-service.mjs +461 -0
- package/server/services/background-task-store.mjs +128 -0
- package/server/services/background-work-view.mjs +228 -0
- package/server/services/cache-rebuild-service.mjs +30 -0
- package/server/services/delete-archive-service.mjs +4 -1
- package/server/services/detached-worker-watch-service.mjs +150 -0
- package/server/services/hidden-message-list.mjs +21 -0
- package/server/services/host-suspend-command.mjs +2 -1
- package/server/services/message-pin-list.mjs +1 -1
- package/server/services/preview-health-probe.mjs +8 -1
- package/server/services/preview-proxy-server.mjs +8 -4
- package/server/services/preview-registry-service.mjs +676 -26
- package/server/services/preview-static-handler.mjs +40 -7
- package/server/services/preview-store.mjs +274 -0
- package/server/services/rate-limit-service.mjs +12 -1
- package/server/services/relay-auth.mjs +183 -0
- package/server/services/relay-cli-launcher-service.mjs +3 -1
- package/server/services/relay-event-service.mjs +17 -0
- package/server/services/remote-relay-dispatcher.mjs +57 -5
- package/server/services/request-boundary.mjs +183 -0
- package/server/services/session-activity-tracker.mjs +227 -19
- package/server/services/session-worker-launch-service.mjs +190 -6
- package/server/services/session-worker-process-service.mjs +10 -6
- package/server/services/share-access-log-service.mjs +123 -0
- package/server/services/share-path-redaction.mjs +424 -0
- package/server/services/status-event-service.mjs +7 -3
- package/server/services/tunnel-worker-path-guard.mjs +24 -41
- package/server/services/windows-autostart-service.mjs +6 -1
- package/server/services/windows-boot-autostart-service.mjs +207 -23
- package/shared/preview-tool-core.mjs +15 -5
- package/shared/remote-relay-contract.mjs +3 -1
- package/shared/share-path-privacy.mjs +30 -0
- package/shared/windows-system-tools.mjs +106 -0
- package/shared/worker-runtime/background-task-digest.mjs +30 -0
- package/shared/worker-runtime/heartbeat.mjs +24 -0
- package/shared/worker-runtime/kept-posts.mjs +83 -0
- package/shared/worker-runtime/worker-websocket-link.mjs +47 -15
package/server/public/index.html
CHANGED
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
if (sharedIdx >= 0) {
|
|
30
30
|
return path.slice(0, sharedIdx).replace(/\/+$/, '');
|
|
31
31
|
}
|
|
32
|
+
const previewIdx = path.indexOf('/share-preview/');
|
|
33
|
+
if (previewIdx >= 0) {
|
|
34
|
+
return path.slice(0, previewIdx).replace(/\/+$/, '');
|
|
35
|
+
}
|
|
32
36
|
return path.replace(/\/+$/, '');
|
|
33
37
|
};
|
|
34
38
|
const __APP_BASE = typeof __APP_CONFIG?.basePath === 'string' && __APP_CONFIG.basePath.trim()
|
|
@@ -526,6 +530,31 @@
|
|
|
526
530
|
opacity: 0;
|
|
527
531
|
pointer-events: none;
|
|
528
532
|
}
|
|
533
|
+
/* "Preview as shared": what a viewer gets instead of a path, and what still
|
|
534
|
+
looks like one (share-preview-marks.mjs). */
|
|
535
|
+
mark.share-preview-redacted,
|
|
536
|
+
mark.share-preview-suspect {
|
|
537
|
+
color: inherit;
|
|
538
|
+
border-radius: 3px;
|
|
539
|
+
padding: 0 2px;
|
|
540
|
+
}
|
|
541
|
+
mark.share-preview-redacted {
|
|
542
|
+
background: rgba(63, 185, 80, 0.18);
|
|
543
|
+
box-shadow: inset 0 -1px 0 rgba(63, 185, 80, 0.65);
|
|
544
|
+
}
|
|
545
|
+
mark.share-preview-suspect {
|
|
546
|
+
background: rgba(210, 153, 34, 0.2);
|
|
547
|
+
box-shadow: inset 0 -2px 0 rgba(210, 153, 34, 0.9);
|
|
548
|
+
}
|
|
549
|
+
#share-preview-banner {
|
|
550
|
+
display: none;
|
|
551
|
+
padding: 6px 12px;
|
|
552
|
+
font-size: var(--fs-meta-sm);
|
|
553
|
+
color: var(--muted);
|
|
554
|
+
border-bottom: 1px solid var(--border);
|
|
555
|
+
background: var(--bg2);
|
|
556
|
+
}
|
|
557
|
+
body.share-preview-mode #share-preview-banner { display: block; }
|
|
529
558
|
body.shared-reader-mode #sidebar,
|
|
530
559
|
body.shared-reader-mode #sidebar-resizer,
|
|
531
560
|
body.shared-reader-mode #sidebar-overlay,
|
|
@@ -586,7 +615,8 @@
|
|
|
586
615
|
.header-icon-count:empty { display: none; }
|
|
587
616
|
/* The display rule above outranks the UA [hidden] rule, same trap as the
|
|
588
617
|
other [hidden] overrides in this file. */
|
|
589
|
-
#pinned-messages-btn[hidden]
|
|
618
|
+
#pinned-messages-btn[hidden],
|
|
619
|
+
#hidden-messages-btn[hidden] { display: none; }
|
|
590
620
|
/* Same trap: without this the ⋯ trigger stays drawn as a dead button. */
|
|
591
621
|
#chat-actions-menu-btn[hidden] { display: none; }
|
|
592
622
|
#cli-dot {
|
|
@@ -660,7 +690,8 @@
|
|
|
660
690
|
/* The display rule above outranks the UA [hidden] rule, same trap as the
|
|
661
691
|
other [hidden] overrides in this file. */
|
|
662
692
|
#conv-filter-clear[hidden] { display: none; }
|
|
663
|
-
#conv-filter-status
|
|
693
|
+
#conv-filter-status,
|
|
694
|
+
#conv-list-announce {
|
|
664
695
|
position: absolute;
|
|
665
696
|
width: 1px;
|
|
666
697
|
height: 1px;
|
|
@@ -906,6 +937,118 @@
|
|
|
906
937
|
font-weight: 600;
|
|
907
938
|
vertical-align: middle;
|
|
908
939
|
}
|
|
940
|
+
/* ── Session groups in the sidebar ──
|
|
941
|
+
A head row (the session that created the others, or a line of its own for
|
|
942
|
+
a hand-made or headless group) with a fold button and a pill that sums up
|
|
943
|
+
the members; the members indented under it while the group is open. */
|
|
944
|
+
.conv-group-fold {
|
|
945
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
946
|
+
width: 20px; height: 20px; margin: 0 2px 0 -4px; padding: 0;
|
|
947
|
+
border: none; border-radius: 6px; background: transparent; color: var(--muted);
|
|
948
|
+
font: inherit; font-size: var(--fs-meta-md); line-height: 1; cursor: pointer; vertical-align: middle;
|
|
949
|
+
}
|
|
950
|
+
.conv-group-fold:hover { background: var(--bg3); color: var(--text); }
|
|
951
|
+
.conv-item.conv-group-synthetic { cursor: default; }
|
|
952
|
+
.conv-item.conv-group-synthetic .conv-title { color: var(--text); font-weight: 600; }
|
|
953
|
+
.conv-item.conv-group-synthetic.worker-ui-question .conv-title { color: var(--conversation-title-question); }
|
|
954
|
+
.conv-item.conv-group-member {
|
|
955
|
+
margin-left: 14px;
|
|
956
|
+
border-left: 2px solid color-mix(in srgb, var(--accent) 45%, transparent);
|
|
957
|
+
border-top-left-radius: 0; border-bottom-left-radius: 0;
|
|
958
|
+
}
|
|
959
|
+
/* The head row keeps its title and meta line clear of the archive and
|
|
960
|
+
delete icons (absolute, at the row's right), so nothing sits under them
|
|
961
|
+
on hover; a synthetic head has no icons. The margin is outside the
|
|
962
|
+
rectangles, so a measurement sees the clearance. */
|
|
963
|
+
.conv-item.conv-group-head:not(.conv-group-synthetic) .conv-title,
|
|
964
|
+
.conv-item.conv-group-head:not(.conv-group-synthetic) .conv-meta {
|
|
965
|
+
padding-right: 0;
|
|
966
|
+
margin-right: 48px;
|
|
967
|
+
}
|
|
968
|
+
/* In a head row's meta line the date gives way first and completely, then
|
|
969
|
+
the pill shortens with an ellipsis (its full text is its title), and the
|
|
970
|
+
provider chip always stays inside. Both shrink factors are 1 or more:
|
|
971
|
+
a factor below 1 that is left alone shrinks only that share of the
|
|
972
|
+
overflow, which is how the chip once left the row. */
|
|
973
|
+
.conv-item.conv-group-head .conv-meta-primary { flex: 0 1000 auto; }
|
|
974
|
+
.conv-group-summary {
|
|
975
|
+
display: inline-block; flex: 0 1 auto; min-width: 2.5em;
|
|
976
|
+
padding: 0 6px; border-radius: 999px;
|
|
977
|
+
border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
|
|
978
|
+
background: color-mix(in srgb, currentColor 12%, transparent);
|
|
979
|
+
color: var(--muted); font-size: var(--fs-ui-chip); font-weight: 600; line-height: 1.3;
|
|
980
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle;
|
|
981
|
+
}
|
|
982
|
+
.conv-group-summary-running { color: var(--conversation-title-ready); }
|
|
983
|
+
.conv-group-summary-waiting { color: var(--conversation-title-question); cursor: pointer; }
|
|
984
|
+
.conv-group-summary-error { color: var(--conversation-title-error); }
|
|
985
|
+
.conv-group-summary[data-open-waiting]:hover { border-color: currentColor; }
|
|
986
|
+
/* Drag and drop (conversation-list-drag.mjs): a long press lifts a row, the
|
|
987
|
+
dragged row stays dimmed in place while a ghost follows the pointer, a
|
|
988
|
+
line shows where it lands, the target group is tinted, and a loose row
|
|
989
|
+
that would make a new group with it is highlighted. */
|
|
990
|
+
.conv-item.conv-drag-lifted {
|
|
991
|
+
background: var(--bg3);
|
|
992
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
|
|
993
|
+
transform: scale(1.02);
|
|
994
|
+
transition: transform 0.12s ease-out, box-shadow 0.12s ease-out;
|
|
995
|
+
z-index: 1;
|
|
996
|
+
}
|
|
997
|
+
#conv-list.conv-list-dragging { cursor: grabbing; }
|
|
998
|
+
#conv-list.conv-list-dragging .conv-item { cursor: grabbing; }
|
|
999
|
+
#conv-list.conv-list-dragging .conv-item:hover:not(.conv-drop-group):not(.conv-drop-new-group) { background: transparent; }
|
|
1000
|
+
.conv-item.conv-drag-source { opacity: 0.35; }
|
|
1001
|
+
.conv-item.conv-drag-ghost {
|
|
1002
|
+
position: fixed; z-index: 12900; margin: 0; pointer-events: none;
|
|
1003
|
+
background: var(--bg2); border-color: var(--accent);
|
|
1004
|
+
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45); opacity: 0.95;
|
|
1005
|
+
cursor: grabbing; will-change: transform;
|
|
1006
|
+
}
|
|
1007
|
+
.conv-item.conv-drop-group {
|
|
1008
|
+
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
|
1009
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
|
|
1010
|
+
}
|
|
1011
|
+
.conv-item.conv-drop-new-group,
|
|
1012
|
+
.conv-item.conv-drop-inside {
|
|
1013
|
+
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
|
1014
|
+
border-color: var(--accent);
|
|
1015
|
+
}
|
|
1016
|
+
.conv-item.conv-drop-before::before,
|
|
1017
|
+
.conv-item.conv-drop-after::after {
|
|
1018
|
+
content: ''; position: absolute; left: 4px; right: 4px; height: 3px;
|
|
1019
|
+
border-radius: 2px; background: var(--accent); pointer-events: none;
|
|
1020
|
+
}
|
|
1021
|
+
.conv-item.conv-drop-before::before { top: -3px; }
|
|
1022
|
+
.conv-item.conv-drop-after::after { bottom: -3px; }
|
|
1023
|
+
.conv-item.conv-drop-flash { animation: conv-drop-flash 1.1s ease-out; }
|
|
1024
|
+
@keyframes conv-drop-flash {
|
|
1025
|
+
0%, 30% { background: color-mix(in srgb, var(--accent) 28%, transparent); }
|
|
1026
|
+
100% { background: transparent; }
|
|
1027
|
+
}
|
|
1028
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1029
|
+
.conv-item.conv-drag-lifted { transform: none; transition: none; }
|
|
1030
|
+
.conv-item.conv-drop-flash { animation: none; outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
1031
|
+
}
|
|
1032
|
+
/* The group picker and the rename form (inside the summary modal). */
|
|
1033
|
+
.conv-group-choices { display: flex; flex-direction: column; gap: 6px; max-height: 40vh; overflow-y: auto; }
|
|
1034
|
+
.conv-group-choice {
|
|
1035
|
+
display: flex; align-items: baseline; justify-content: space-between; gap: 10px; width: 100%;
|
|
1036
|
+
padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg3); color: var(--text);
|
|
1037
|
+
font: inherit; font-size: var(--fs-meta-md); text-align: left; cursor: pointer;
|
|
1038
|
+
}
|
|
1039
|
+
.conv-group-choice:hover:not([disabled]), .conv-group-choice:focus-visible { border-color: var(--accent); outline: none; }
|
|
1040
|
+
.conv-group-choice[disabled] { opacity: 0.6; cursor: default; }
|
|
1041
|
+
.conv-group-choice-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1042
|
+
.conv-group-choice-count { flex: 0 0 auto; color: var(--muted); font-size: var(--fs-meta-xs); }
|
|
1043
|
+
.conv-group-picker-empty { color: var(--muted); font-size: var(--fs-meta-md); margin: 0 0 6px; }
|
|
1044
|
+
.conv-group-form { margin-top: 14px; }
|
|
1045
|
+
.conv-group-form-label { display: block; color: var(--muted); font-size: var(--fs-meta-xs); margin-bottom: 4px; }
|
|
1046
|
+
.conv-group-form-row { display: flex; gap: 8px; align-items: center; }
|
|
1047
|
+
.conv-group-input {
|
|
1048
|
+
flex: 1 1 auto; min-width: 0; width: 100%; padding: 7px 10px;
|
|
1049
|
+
border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--text); font: inherit;
|
|
1050
|
+
}
|
|
1051
|
+
.conv-group-input:focus { outline: none; border-color: var(--accent); }
|
|
909
1052
|
/* ── Main Chat ── */
|
|
910
1053
|
#main {
|
|
911
1054
|
/* Containing block for #transcript-separator-rail. Safe to add: every
|
|
@@ -2229,9 +2372,42 @@
|
|
|
2229
2372
|
text-align: center;
|
|
2230
2373
|
}
|
|
2231
2374
|
.jump-to-bottom-badge[hidden] { display: none; }
|
|
2375
|
+
/* Something new landed below a reader who is scrolled up: the accent
|
|
2376
|
+
colour, and a count or (news without a row to count) a dot. */
|
|
2377
|
+
#jump-to-bottom-btn[data-state="new"] { border-color: var(--accent); color: var(--accent); }
|
|
2378
|
+
.jump-to-bottom-badge.jump-to-bottom-badge-dot {
|
|
2379
|
+
top: -3px;
|
|
2380
|
+
right: -3px;
|
|
2381
|
+
min-width: 12px;
|
|
2382
|
+
width: 12px;
|
|
2383
|
+
height: 12px;
|
|
2384
|
+
padding: 0;
|
|
2385
|
+
border-radius: 50%;
|
|
2386
|
+
border: 2px solid var(--bg2);
|
|
2387
|
+
}
|
|
2388
|
+
/* A question, an approval or a board waits below: the button is filled. */
|
|
2389
|
+
#jump-to-bottom-btn[data-state="question"] {
|
|
2390
|
+
border-color: var(--warn);
|
|
2391
|
+
background: var(--warn);
|
|
2392
|
+
color: #000;
|
|
2393
|
+
animation: jump-to-bottom-attention 1.6s ease-out 2;
|
|
2394
|
+
}
|
|
2395
|
+
:root[data-theme="light"] #jump-to-bottom-btn[data-state="question"] { color: #fff; }
|
|
2396
|
+
#jump-to-bottom-btn[data-state="question"] .jump-to-bottom-badge {
|
|
2397
|
+
background: var(--bg2);
|
|
2398
|
+
color: var(--warn);
|
|
2399
|
+
border: 1px solid var(--warn);
|
|
2400
|
+
line-height: 16px;
|
|
2401
|
+
font-size: 12px;
|
|
2402
|
+
}
|
|
2403
|
+
@keyframes jump-to-bottom-attention {
|
|
2404
|
+
0% { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35), 0 0 0 0 var(--warn); }
|
|
2405
|
+
100% { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35), 0 0 0 12px transparent; }
|
|
2406
|
+
}
|
|
2232
2407
|
@media (prefers-reduced-motion: reduce) {
|
|
2233
2408
|
#jump-to-bottom-btn,
|
|
2234
2409
|
#jump-to-bottom-btn.visible { transition: none; }
|
|
2410
|
+
#jump-to-bottom-btn[data-state="question"] { animation: none; }
|
|
2235
2411
|
}
|
|
2236
2412
|
/* ── Context usage modal ── */
|
|
2237
2413
|
.ctx-usage-model {
|
|
@@ -2565,6 +2741,25 @@
|
|
|
2565
2741
|
}
|
|
2566
2742
|
.plan-usage-link { color: var(--accent); text-decoration: none; }
|
|
2567
2743
|
.plan-usage-link:hover { text-decoration: underline; }
|
|
2744
|
+
/* About OAR: the plan-usage cards and tables, stacked. */
|
|
2745
|
+
.about-modal { display: flex; flex-direction: column; gap: 12px; }
|
|
2746
|
+
.about-section .plan-usage-card-head { margin-bottom: 4px; }
|
|
2747
|
+
.about-section code { font-size: 0.82rem; }
|
|
2748
|
+
.about-usage-provider { font-size: 0.82rem; font-weight: 600; margin-top: 8px; }
|
|
2749
|
+
.about-usage-provider:first-child { margin-top: 0; }
|
|
2750
|
+
.about-state { font-weight: 600; }
|
|
2751
|
+
.about-state[data-state="online"] { color: var(--success); }
|
|
2752
|
+
.about-state[data-state="offline"] { color: var(--warn); }
|
|
2753
|
+
.about-state[data-state="idle"] { color: var(--muted); }
|
|
2754
|
+
.about-inline-button {
|
|
2755
|
+
background: none;
|
|
2756
|
+
border: none;
|
|
2757
|
+
padding: 0;
|
|
2758
|
+
font: inherit;
|
|
2759
|
+
cursor: pointer;
|
|
2760
|
+
text-align: left;
|
|
2761
|
+
}
|
|
2762
|
+
.about-links { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; font-size: 0.86rem; padding: 2px 0 4px; }
|
|
2568
2763
|
@media (prefers-reduced-motion: reduce) {
|
|
2569
2764
|
.plan-usage-bar-fill { transition: none; }
|
|
2570
2765
|
}
|
|
@@ -3213,6 +3408,32 @@
|
|
|
3213
3408
|
.preview-close:hover:not(:disabled) { border-color: #f85149; color: #f85149; }
|
|
3214
3409
|
.preview-close:disabled { opacity: 0.5; cursor: default; }
|
|
3215
3410
|
#settings-previews-empty { color: var(--muted); font-size: var(--fs-meta-sm); }
|
|
3411
|
+
/* Settings → Sharing: one row per shared conversation, the preview row's
|
|
3412
|
+
grammar, with its access log folded underneath. */
|
|
3413
|
+
#settings-shares-list { width: 100%; }
|
|
3414
|
+
.share-row { margin-top: 8px; padding: 6px 8px; border-radius: 8px; background: var(--bg2); }
|
|
3415
|
+
.share-row-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
3416
|
+
.share-row-main { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
3417
|
+
.share-row-title {
|
|
3418
|
+
background: none; border: 0; padding: 0; text-align: left; cursor: pointer;
|
|
3419
|
+
color: var(--text); font: inherit; overflow-wrap: anywhere;
|
|
3420
|
+
}
|
|
3421
|
+
.share-row-title:hover { color: var(--accent); text-decoration: underline; }
|
|
3422
|
+
.share-row-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
3423
|
+
.share-row-actions button {
|
|
3424
|
+
flex-shrink: 0; background: transparent; border: 1px solid var(--border);
|
|
3425
|
+
color: var(--text); border-radius: 8px; padding: 3px 10px; cursor: pointer;
|
|
3426
|
+
font-size: var(--fs-meta-sm); line-height: 1.5;
|
|
3427
|
+
}
|
|
3428
|
+
.share-row-actions button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
|
|
3429
|
+
.share-row-actions button.share-stop:hover:not(:disabled) { border-color: #f85149; color: #f85149; }
|
|
3430
|
+
.share-row-actions button:disabled { opacity: 0.5; cursor: default; }
|
|
3431
|
+
.share-opens { margin-top: 6px; border-top: 1px solid var(--border); padding-top: 4px; }
|
|
3432
|
+
.share-open { padding: 4px 0; font-size: var(--fs-meta-sm); border-bottom: 1px solid var(--border); }
|
|
3433
|
+
.share-open:last-child { border-bottom: 0; }
|
|
3434
|
+
.share-open-meta { color: var(--text); }
|
|
3435
|
+
.share-open-agent { color: var(--muted); overflow-wrap: anywhere; }
|
|
3436
|
+
#settings-shares-empty { color: var(--muted); font-size: var(--fs-meta-sm); }
|
|
3216
3437
|
/* Remote relays (Settings → Relays, the @mention popup): a health dot —
|
|
3217
3438
|
online green, unreachable/refused red, never checked grey. */
|
|
3218
3439
|
.remote-relay-dot {
|
|
@@ -3332,17 +3553,15 @@
|
|
|
3332
3553
|
.relay-event-line.relay-event-error,
|
|
3333
3554
|
.relay-event-line.relay-event-task-failed,
|
|
3334
3555
|
.relay-event-line.relay-event-stalled { color: var(--text, inherit); }
|
|
3335
|
-
/* Agent exchanges: an agent's prompt
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
and the
|
|
3339
|
-
|
|
3340
|
-
bubble's width. */
|
|
3556
|
+
/* Agent exchanges: an agent's prompt folded into one row in the event
|
|
3557
|
+
rows' look (agent-exchange-fold-view.mjs). The row is the first child of
|
|
3558
|
+
the prompt's own node; closed, the prompt's bubble is hidden. The reply
|
|
3559
|
+
and the live bubble are never part of it. The prompt's node spans the
|
|
3560
|
+
pane for the row; its bubble keeps a user bubble's width. */
|
|
3341
3561
|
.msg.agent-exchange-head { align-self: stretch; max-width: 100%; }
|
|
3342
3562
|
.msg.agent-exchange-head > .msg-bubble { max-width: 82%; }
|
|
3343
3563
|
.msg.agent-exchange-head.agent-exchange-closed > .msg-bubble,
|
|
3344
|
-
.msg.agent-exchange-head.agent-exchange-closed > .msg-label
|
|
3345
|
-
#messages > .msg.agent-exchange-member.agent-exchange-closed { display: none; }
|
|
3564
|
+
.msg.agent-exchange-head.agent-exchange-closed > .msg-label { display: none; }
|
|
3346
3565
|
.agent-exchange-row {
|
|
3347
3566
|
align-self: stretch; min-width: 0;
|
|
3348
3567
|
border: 1px dashed var(--border); border-left: 3px solid var(--accent);
|
|
@@ -3719,7 +3938,19 @@
|
|
|
3719
3938
|
.file-preview-markdown p { margin-bottom: 0.55em; }
|
|
3720
3939
|
.file-preview-markdown h1, .file-preview-markdown h2, .file-preview-markdown h3 { margin: 0.6em 0 0.35em; }
|
|
3721
3940
|
.file-preview-markdown ul, .file-preview-markdown ol { margin-left: 1.3em; margin-bottom: 0.55em; }
|
|
3722
|
-
|
|
3941
|
+
/* A table wider than the text scrolls sideways in its own box, as code
|
|
3942
|
+
does: the body itself never scrolls sideways, and the gallery swipe
|
|
3943
|
+
knows to leave a sideways scroller alone. */
|
|
3944
|
+
.file-preview-markdown table {
|
|
3945
|
+
display: block;
|
|
3946
|
+
width: max-content;
|
|
3947
|
+
max-width: 100%;
|
|
3948
|
+
overflow-x: auto;
|
|
3949
|
+
-webkit-overflow-scrolling: touch;
|
|
3950
|
+
border-collapse: collapse;
|
|
3951
|
+
margin: 0.55em 0;
|
|
3952
|
+
font-size: 0.88em;
|
|
3953
|
+
}
|
|
3723
3954
|
.file-preview-markdown th, .file-preview-markdown td { border: 1px solid var(--border); padding: 6px 9px; }
|
|
3724
3955
|
.file-preview-markdown th { background: var(--bg3); }
|
|
3725
3956
|
.file-preview-markdown img { display: block; max-width: 100%; height: auto; }
|
|
@@ -4763,6 +4994,44 @@
|
|
|
4763
4994
|
font-size: var(--fs-meta-sm);
|
|
4764
4995
|
padding: 8px 6px;
|
|
4765
4996
|
}
|
|
4997
|
+
/* Hidden messages list (kind 'hidden-messages'): the pin list's rows, with
|
|
4998
|
+
Unhide as a word where the pin list has 🗑, and Unhide all above. */
|
|
4999
|
+
.hidden-row-unhide {
|
|
5000
|
+
appearance: none;
|
|
5001
|
+
border: 0;
|
|
5002
|
+
border-left: 1px solid var(--border);
|
|
5003
|
+
background: transparent;
|
|
5004
|
+
color: var(--muted);
|
|
5005
|
+
cursor: pointer;
|
|
5006
|
+
flex: 0 0 auto;
|
|
5007
|
+
min-width: 44px;
|
|
5008
|
+
min-height: 44px;
|
|
5009
|
+
padding: 0 12px;
|
|
5010
|
+
font: inherit;
|
|
5011
|
+
font-size: var(--fs-meta-sm);
|
|
5012
|
+
}
|
|
5013
|
+
.hidden-row-unhide:hover:not(:disabled) {
|
|
5014
|
+
color: var(--accent);
|
|
5015
|
+
background: var(--bg2);
|
|
5016
|
+
}
|
|
5017
|
+
.hidden-row-unhide:disabled { cursor: wait; opacity: 0.55; }
|
|
5018
|
+
.hidden-list-actions,
|
|
5019
|
+
.hidden-unhide-all-confirm {
|
|
5020
|
+
margin-bottom: 10px;
|
|
5021
|
+
}
|
|
5022
|
+
.hidden-list-actions {
|
|
5023
|
+
display: flex;
|
|
5024
|
+
justify-content: flex-end;
|
|
5025
|
+
}
|
|
5026
|
+
.hidden-unhide-all-confirm {
|
|
5027
|
+
border: 1px solid var(--border);
|
|
5028
|
+
border-radius: 10px;
|
|
5029
|
+
padding: 10px 12px;
|
|
5030
|
+
}
|
|
5031
|
+
.hidden-unhide-all-confirm p {
|
|
5032
|
+
margin: 0 0 8px;
|
|
5033
|
+
font-size: var(--fs-meta-sm);
|
|
5034
|
+
}
|
|
4766
5035
|
|
|
4767
5036
|
#git-changes-modal,
|
|
4768
5037
|
#git-diff-modal {
|
|
@@ -5755,6 +6024,14 @@
|
|
|
5755
6024
|
}
|
|
5756
6025
|
.conv-meta { font-size: var(--fs-meta-sm); margin-top: 5px; }
|
|
5757
6026
|
.conv-delete { opacity: 1; right: 4px; font-size: var(--fs-ui-icon); }
|
|
6027
|
+
/* Session groups on a phone: a shallower indent, and a fold target that
|
|
6028
|
+
is easy to hit without stealing the row's width. */
|
|
6029
|
+
.conv-item.conv-group-member { margin-left: 10px; }
|
|
6030
|
+
.conv-group-fold { width: 24px; height: 24px; margin-left: -6px; }
|
|
6031
|
+
/* The finger covers the row it lifts: the ghost sits a little higher. */
|
|
6032
|
+
.conv-item.conv-drag-ghost { margin: -18px 0 0; }
|
|
6033
|
+
.conv-item.conv-drop-before::before,
|
|
6034
|
+
.conv-item.conv-drop-after::after { height: 4px; }
|
|
5758
6035
|
#chat-header {
|
|
5759
6036
|
padding: var(--chat-header-top-pad-mobile) 10px 10px;
|
|
5760
6037
|
gap: 6px 8px;
|
|
@@ -6125,10 +6402,31 @@
|
|
|
6125
6402
|
}
|
|
6126
6403
|
/* The pin list has one action, Close: the full-width action row above
|
|
6127
6404
|
would leave its title no room. Title left, close button right. */
|
|
6128
|
-
#summary-modal[data-kind="pinned-messages"] .summary-header-actions
|
|
6405
|
+
#summary-modal[data-kind="pinned-messages"] .summary-header-actions,
|
|
6406
|
+
#summary-modal[data-kind="hidden-messages"] .summary-header-actions {
|
|
6407
|
+
width: auto;
|
|
6408
|
+
}
|
|
6409
|
+
#summary-modal[data-kind="pinned-messages"] .summary-header-actions .summary-close,
|
|
6410
|
+
#summary-modal[data-kind="hidden-messages"] .summary-header-actions .summary-close {
|
|
6411
|
+
flex: 0 0 auto;
|
|
6412
|
+
min-width: 40px;
|
|
6413
|
+
}
|
|
6414
|
+
/* The session-group picker, rename and confirmations: the same layout,
|
|
6415
|
+
so their title ("Add to group", the chat's name) stays readable. */
|
|
6416
|
+
#summary-modal[data-kind^="group-"] .summary-header-actions {
|
|
6417
|
+
width: auto;
|
|
6418
|
+
}
|
|
6419
|
+
#summary-modal[data-kind^="group-"] .summary-header-actions .summary-close {
|
|
6420
|
+
flex: 0 0 auto;
|
|
6421
|
+
min-width: 40px;
|
|
6422
|
+
}
|
|
6423
|
+
/* About OAR: the same, with Refresh beside the close button. */
|
|
6424
|
+
#summary-modal[data-kind="about"] .summary-header-actions {
|
|
6129
6425
|
width: auto;
|
|
6426
|
+
flex: 0 0 auto;
|
|
6130
6427
|
}
|
|
6131
|
-
#summary-modal[data-kind="
|
|
6428
|
+
#summary-modal[data-kind="about"] .summary-header-actions .summary-btn,
|
|
6429
|
+
#summary-modal[data-kind="about"] .summary-header-actions .summary-close {
|
|
6132
6430
|
flex: 0 0 auto;
|
|
6133
6431
|
min-width: 40px;
|
|
6134
6432
|
}
|
|
@@ -6389,6 +6687,7 @@
|
|
|
6389
6687
|
</div>
|
|
6390
6688
|
<div id="conv-archived-banner" hidden>Archived conversations <button type="button" class="conv-archived-back" onclick="toggleArchivedConversations()">Back to the list</button></div>
|
|
6391
6689
|
<div id="conv-list"></div>
|
|
6690
|
+
<div id="conv-list-announce" role="status" aria-live="polite"></div>
|
|
6392
6691
|
</div>
|
|
6393
6692
|
<div id="sidebar-resizer" role="separator" aria-orientation="vertical" aria-label="Resize conversations sidebar"></div>
|
|
6394
6693
|
|
|
@@ -6405,6 +6704,7 @@
|
|
|
6405
6704
|
</div>
|
|
6406
6705
|
<div id="chat-header-actions">
|
|
6407
6706
|
<button id="pinned-messages-btn" class="header-icon-btn has-count" type="button" title="Pinned messages" aria-label="Pinned messages" hidden>📍<span class="header-icon-count"></span></button>
|
|
6707
|
+
<button id="hidden-messages-btn" class="header-icon-btn has-count" type="button" title="Hidden from shared viewers" aria-label="Hidden from shared viewers" hidden>🙈<span class="header-icon-count"></span></button>
|
|
6408
6708
|
<button id="message-search-btn" class="header-icon-btn" onclick="openMessageSearchModal()" title="Search messages" aria-label="Search messages">🔍</button>
|
|
6409
6709
|
<button id="context-btn" class="header-icon-btn" onclick="showContext()" title="Check current context" aria-label="Check current context">🧠</button>
|
|
6410
6710
|
<div id="chat-actions-menu-wrap">
|
|
@@ -6413,11 +6713,14 @@
|
|
|
6413
6713
|
<div id="chat-menu-pwa-version" class="chat-actions-menu-meta chat-actions-menu-meta-stacked" aria-hidden="true"><span class="chat-actions-menu-meta-primary">PWA shell version</span><span class="chat-actions-menu-meta-secondary" id="chat-menu-pwa-version-value">v?</span></div>
|
|
6414
6714
|
<div id="chat-menu-queue-status" class="chat-actions-menu-meta chat-actions-menu-meta-stacked" aria-hidden="true"><div class="chat-actions-menu-meta-top"><span class="chat-actions-menu-meta-primary">Queue</span><button id="chat-menu-empty-queue" class="chat-actions-menu-meta-label" type="button">🚮 Empty queue</button></div><span class="chat-actions-menu-meta-secondary" id="chat-menu-queue-status-value">pending=?, processing=?, parked=?</span></div>
|
|
6415
6715
|
<button id="chat-menu-edit-title" class="chat-actions-menu-item" type="button" role="menuitem">✍️ Edit conversation title</button>
|
|
6416
|
-
<button id="chat-menu-
|
|
6716
|
+
<button id="chat-menu-theme-toggle" class="chat-actions-menu-item" type="button" role="menuitem" hidden>🌙/☀️ Day/Night mode</button>
|
|
6417
6717
|
<button id="chat-menu-usage" class="chat-actions-menu-item" type="button" role="menuitem">📊 Check Usage</button>
|
|
6418
6718
|
<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>
|
|
6419
6719
|
<button id="chat-menu-share-conversation" class="chat-actions-menu-item" type="button" role="menuitem">➡️ Share conversation</button>
|
|
6720
|
+
<button id="chat-menu-stop-sharing" class="chat-actions-menu-item" type="button" role="menuitem" hidden>⛔ Stop sharing</button>
|
|
6721
|
+
<button id="chat-menu-preview-shared" class="chat-actions-menu-item" type="button" role="menuitem">🔍 Preview as shared</button>
|
|
6420
6722
|
<button id="chat-menu-archive" class="chat-actions-menu-item" type="button" role="menuitem">🗄 Archive conversation</button>
|
|
6723
|
+
<button id="chat-menu-group" class="chat-actions-menu-item" type="button" role="menuitem">🧩 Session group…</button>
|
|
6421
6724
|
<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>
|
|
6422
6725
|
<button id="chat-menu-inspect-tmux" class="chat-actions-menu-item" type="button" role="menuitem">🖥️ Inspect tmux console</button>
|
|
6423
6726
|
<button id="chat-menu-select-models" class="chat-actions-menu-item" type="button" role="menuitem">🤗 Select Models</button>
|
|
@@ -6425,6 +6728,7 @@
|
|
|
6425
6728
|
<button id="chat-menu-git-changes" class="chat-actions-menu-item" type="button" role="menuitem">🌿 Git changes</button>
|
|
6426
6729
|
<button id="chat-menu-open-cloud-session" class="chat-actions-menu-item" type="button" role="menuitem" hidden>☁️ Open on claude.ai</button>
|
|
6427
6730
|
<button id="chat-menu-settings" class="chat-actions-menu-item" type="button" role="menuitem">⚙️ Settings</button>
|
|
6731
|
+
<button id="chat-menu-about" class="chat-actions-menu-item" type="button" role="menuitem">ℹ️ About OAR</button>
|
|
6428
6732
|
<button id="chat-menu-restart-relay" class="chat-actions-menu-item" type="button" role="menuitem">🌄 Restart web relay</button>
|
|
6429
6733
|
<button id="chat-menu-suspend-host" class="chat-actions-menu-item" type="button" role="menuitem" onclick="openSuspendHostConfirmation()">💤 Suspend host</button>
|
|
6430
6734
|
<button id="chat-menu-kill-session" class="chat-actions-menu-item" type="button" role="menuitem">☠️ Kill session</button>
|
|
@@ -6445,6 +6749,7 @@
|
|
|
6445
6749
|
<div id="input-area">
|
|
6446
6750
|
<button id="jump-to-bottom-btn" type="button" title="Jump to the latest message" aria-label="Jump to the latest message"><span class="jump-to-bottom-icon" aria-hidden="true">⌄</span><span class="jump-to-bottom-badge" hidden></span></button>
|
|
6447
6751
|
<div id="offline-banner">⚠️ CLI is offline — messages will queue until it reconnects</div>
|
|
6752
|
+
<div id="share-preview-banner" role="note"></div>
|
|
6448
6753
|
<div id="model-banner"></div>
|
|
6449
6754
|
<div id="usage-limit-banner" role="status" aria-live="polite" hidden></div>
|
|
6450
6755
|
<div id="model-lock-note" hidden></div>
|
|
@@ -6627,6 +6932,16 @@
|
|
|
6627
6932
|
tabindex="-1"
|
|
6628
6933
|
data-settings-tab="previews"
|
|
6629
6934
|
>Previews</button>
|
|
6935
|
+
<button
|
|
6936
|
+
id="settings-tab-shares"
|
|
6937
|
+
class="settings-tab"
|
|
6938
|
+
type="button"
|
|
6939
|
+
role="tab"
|
|
6940
|
+
aria-selected="false"
|
|
6941
|
+
aria-controls="settings-panel-shares"
|
|
6942
|
+
tabindex="-1"
|
|
6943
|
+
data-settings-tab="shares"
|
|
6944
|
+
>Sharing</button>
|
|
6630
6945
|
<button
|
|
6631
6946
|
id="settings-tab-notifications"
|
|
6632
6947
|
class="settings-tab"
|
|
@@ -6679,6 +6994,17 @@
|
|
|
6679
6994
|
>
|
|
6680
6995
|
</div>
|
|
6681
6996
|
<div class="settings-help" style="margin-top: 6px;">Hide the menu action when host suspend is unsupported or not needed on this device.</div>
|
|
6997
|
+
<div class="settings-row" style="margin-top: 12px; margin-bottom: 0;">
|
|
6998
|
+
<label for="scroll-on-send-toggle">Jump to the end when I send a message</label>
|
|
6999
|
+
<input
|
|
7000
|
+
id="scroll-on-send-toggle"
|
|
7001
|
+
type="checkbox"
|
|
7002
|
+
onchange="updateScrollOnSendSetting(this.checked)"
|
|
7003
|
+
aria-label="Jump to the end when I send a message"
|
|
7004
|
+
checked
|
|
7005
|
+
>
|
|
7006
|
+
</div>
|
|
7007
|
+
<div class="settings-help" style="margin-top: 6px;">A conversation only scrolls by itself while you are at its end. Anywhere else it stays where you are reading, and the round button above the composer shows that something new or a question is waiting below. Your own message is the exception: sending one takes you to the end. Switch this off to stay put then too. Saved in this browser.</div>
|
|
6682
7008
|
<div class="settings-row settings-row-column" style="margin-top: 12px; margin-bottom: 0;">
|
|
6683
7009
|
<label for="turn-ceiling-slider">Max turn duration <span id="turn-ceiling-value">No limit</span></label>
|
|
6684
7010
|
<input
|
|
@@ -7436,7 +7762,52 @@
|
|
|
7436
7762
|
<label>Live previews</label>
|
|
7437
7763
|
<div id="settings-previews-list"></div>
|
|
7438
7764
|
<div id="settings-previews-empty" class="settings-help">Loading previews…</div>
|
|
7439
|
-
<div class="settings-help">Local dev servers published on the preview host. Previews never expire
|
|
7765
|
+
<div class="settings-help">Local dev servers and folders published on the preview host. Previews never expire and survive a relay restart — they live until you close them here or delete their conversation (a dev-server preview also ends when the machine reboots). Every link is public: anyone with the URL reaches the app without logging in.</div>
|
|
7766
|
+
</div>
|
|
7767
|
+
</div>
|
|
7768
|
+
<div
|
|
7769
|
+
id="settings-panel-shares"
|
|
7770
|
+
class="settings-panel"
|
|
7771
|
+
role="tabpanel"
|
|
7772
|
+
tabindex="0"
|
|
7773
|
+
aria-labelledby="settings-tab-shares"
|
|
7774
|
+
data-settings-panel="shares"
|
|
7775
|
+
hidden
|
|
7776
|
+
>
|
|
7777
|
+
<!-- One section per concern; further sharing settings (such as how
|
|
7778
|
+
paths show in a shared view) get their own section in here. -->
|
|
7779
|
+
<div id="shares-settings-sections" class="shares-settings-sections">
|
|
7780
|
+
<div id="shares-settings-section" class="settings-row settings-row-column" style="margin-top: 12px; margin-bottom: 0;">
|
|
7781
|
+
<label>Shared conversations</label>
|
|
7782
|
+
<div id="settings-shares-list"></div>
|
|
7783
|
+
<div id="settings-shares-empty" class="settings-help">Loading shared conversations…</div>
|
|
7784
|
+
<div class="settings-help">Every link is public: anyone with the URL can read the conversation without logging in, until you stop sharing it. Renew link gives the conversation a new link; the old one stops working at once and the access log carries over. Stop sharing ends the link and deletes its access log.</div>
|
|
7785
|
+
</div>
|
|
7786
|
+
<div id="shares-access-log-section" class="settings-row settings-row-column" style="margin-top: 16px; margin-bottom: 0;">
|
|
7787
|
+
<label>Access log</label>
|
|
7788
|
+
<div class="settings-row" style="width: 100%; margin-bottom: 0;">
|
|
7789
|
+
<label for="settings-shares-store-ip">Store viewer IP addresses</label>
|
|
7790
|
+
<input id="settings-shares-store-ip" type="checkbox" aria-label="Store viewer IP addresses" checked>
|
|
7791
|
+
</div>
|
|
7792
|
+
<div class="settings-help">Each open of a shared link is logged with its time, browser and country. Off: new entries keep no IP address (entries logged before keep theirs), and distinct viewers are still told apart by a keyed hash. The log is kept until you stop sharing the link or delete the conversation.</div>
|
|
7793
|
+
<div id="settings-shares-status" class="settings-help" role="status"></div>
|
|
7794
|
+
</div>
|
|
7795
|
+
<div id="shares-path-privacy-section" class="settings-row settings-row-column" style="margin-top: 16px; margin-bottom: 0;">
|
|
7796
|
+
<label id="settings-shares-path-privacy-label">Paths and file names</label>
|
|
7797
|
+
<div role="radiogroup" aria-labelledby="settings-shares-path-privacy-label" style="display: flex; flex-direction: column; gap: 4px;">
|
|
7798
|
+
<label style="font-weight: normal;">
|
|
7799
|
+
<input type="radio" name="settings-shares-path-privacy" value="show"> Show every path and file name
|
|
7800
|
+
</label>
|
|
7801
|
+
<label style="font-weight: normal;">
|
|
7802
|
+
<input type="radio" name="settings-shares-path-privacy" value="filename"> Hide the path, show the file name
|
|
7803
|
+
</label>
|
|
7804
|
+
<label style="font-weight: normal;">
|
|
7805
|
+
<input type="radio" name="settings-shares-path-privacy" value="hide"> Hide paths and file names
|
|
7806
|
+
</label>
|
|
7807
|
+
</div>
|
|
7808
|
+
<div class="settings-help">What every shared link shows of this relay's paths; your own view always shows everything. Free text (replies, thoughts, tool output) is filtered on a best-effort basis: check a conversation with ⋯ → Preview as shared.</div>
|
|
7809
|
+
<div id="settings-shares-path-privacy-status" class="settings-help" role="status"></div>
|
|
7810
|
+
</div>
|
|
7440
7811
|
</div>
|
|
7441
7812
|
</div>
|
|
7442
7813
|
<div
|
package/server/relay-tools.md
CHANGED
|
@@ -24,7 +24,7 @@ Use `restart: true` in the request body when the user wants a real relay restart
|
|
|
24
24
|
|
|
25
25
|
## Preview servers
|
|
26
26
|
|
|
27
|
-
Publish a local web server or a static directory on a public preview URL so the user can open it from any device, or list/close existing previews. Use this whenever the user wants to see, try, or share something with a web UI — never ask them to open localhost or forward a port. For a dev server: call this FIRST with {action:"create", port} to get the basePath, then start the server configured to serve under that basePath (Vite --base, Next basePath, Express mount prefix); the proxy forwards X-Forwarded-Prefix but does not rewrite bodies, so root-absolute asset paths will not work. For plain files or a build output: pass {action:"create", dir} instead and the relay serves the directory itself — no dev server needed. Always tell the user the returned URL and that the link is public: anyone who has it can reach the app without logging in. Previews never expire
|
|
27
|
+
Publish a local web server or a static directory on a public preview URL so the user can open it from any device, or list/close existing previews. Use this whenever the user wants to see, try, or share something with a web UI — never ask them to open localhost or forward a port. For a dev server: call this FIRST with {action:"create", port} to get the basePath, then start the server configured to serve under that basePath (Vite --base, Next basePath, Express mount prefix); the proxy forwards X-Forwarded-Prefix but does not rewrite bodies, so root-absolute asset paths will not work. For plain files or a build output: pass {action:"create", dir} instead and the relay serves the directory itself — no dev server needed. Always tell the user the returned URL and that the link is public: anyone who has it can reach the app without logging in. Publishing the same port or directory again in this conversation returns the same link. Previews never expire and survive a relay restart (a port preview until the machine reboots); close them with {action:"close"} when the user is done.
|
|
28
28
|
|
|
29
29
|
If you have a `preview` tool, use it. Otherwise use the authenticated localhost API (same auth as `POST /api/relay/shutdown`): `POST /api/previews` with `{ "conversationId": "<conv>", "port": 5173, "label": "web app" }` (or `"dir": "./dist"` instead of the port) publishes, `GET /api/previews` lists, `DELETE /api/previews/:token` closes the link without touching the dev server behind it. A 503 with `details` means the preview lane is disabled or misconfigured — surface those details, they are the operator's fix. See `docs/preview-servers.md`.
|
|
30
30
|
|
|
@@ -38,6 +38,7 @@ This relay itself is listed with "self": true when its owner switched agent sess
|
|
|
38
38
|
|
|
39
39
|
- `create_session` starts a session with any provider that `relay_info` lists: a local one in a folder ("cwd"), or provider "claude-cloud" with "repo" (a GitHub URL or owner/repo) and an optional "branch". At most 4 sessions you started may work at the same time; a fifth is refused until one finishes.
|
|
40
40
|
- The first `create_session` on this relay shows the user an approval card, once per conversation. A session that an agent created cannot create sessions itself (one level only).
|
|
41
|
+
- Sessions you start here are grouped under this session in the user's sidebar. `list_sessions` lists in the sidebar's order (a group sorts by its newest session, head first) and shows the group as a "group" field (id, name, role); `read_session` adds the group's live members with their state. Agents only read groups, the user arranges them.
|
|
41
42
|
- A new session knows nothing of this conversation: write a self-contained prompt. A Claude Cloud session works on a fresh clone in a sandbox at Anthropic, so name the branch it should work on and push.
|
|
42
43
|
- Follow each session with `wait` (the message id comes back from `create_session` and `send`) and `read_session`; "wait_seconds" is limited to the maximum set on the relay (default 600).
|
|
43
44
|
- Sessions run on the relay owner's accounts and cost their usage: start only what the task needs.
|
package/server/relay.mjs
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
extractModelDescriptors,
|
|
33
33
|
normalizeContextLimitTokens,
|
|
34
34
|
} from '../shared/model-descriptors.mjs';
|
|
35
|
+
import { windowsSystemToolPath } from '../shared/windows-system-tools.mjs';
|
|
35
36
|
|
|
36
37
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
37
38
|
|
|
@@ -379,7 +380,7 @@ async function spawnForegroundCliViaPowerShell(tcpConnectionToken, port) {
|
|
|
379
380
|
].join(' ');
|
|
380
381
|
|
|
381
382
|
const psCommand = `$env:COPILOT_CONNECTION_TOKEN='${tcpConnectionToken}'; & '${NODE_PATH}' ${nodeArgs}`;
|
|
382
|
-
const child = await waitForProcessSpawn('powershell.exe', [
|
|
383
|
+
const child = await waitForProcessSpawn(windowsSystemToolPath('powershell.exe'), [
|
|
383
384
|
'-NoExit',
|
|
384
385
|
'-Command',
|
|
385
386
|
psCommand,
|