@oar-sh/oar 0.9.8 → 0.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +478 -0
- package/README.md +129 -39
- package/bin/bat/oar.bat +46 -46
- package/bin/oar.js +814 -228
- package/package.json +5 -6
- package/server/README.md +306 -4
- package/server/claude-worker/claude-remote-relay-tool.mjs +10 -0
- package/server/claude-worker/claude-session-process.mjs +35 -1
- package/server/claude-worker/claude-turn-publisher.mjs +3 -0
- package/server/claude-worker/sdk-message-normalizer.mjs +31 -4
- package/server/claude-worker/subagent-timeline-recorder.mjs +572 -0
- package/server/copilot-worker/copilot-sdk-session-process.mjs +3 -1
- package/server/cursor-worker/cursor-sdk-adapter.mjs +56 -2
- package/server/db-schema.mjs +44 -0
- package/server/migrations/0008-message-pins.mjs +85 -0
- package/server/migrations/0009-subagent-timeline.mjs +135 -0
- package/server/migrations/0010-subagent-timeline-pruning.mjs +89 -0
- package/server/migrations/0011-relay-event-subscriptions.mjs +125 -0
- package/server/migrations/0012-cross-relay-event-subscriptions.mjs +116 -0
- package/server/public/app/agent-exchange-fold-view.mjs +248 -0
- package/server/public/app/api-client.js +91 -0
- package/server/public/app/archive-confirm.mjs +28 -0
- package/server/public/app/ask-user-view.js +3 -0
- package/server/public/app/attachments-view.js +1024 -131
- package/server/public/app/back-guard.mjs +58 -0
- package/server/public/app/background-tasks-view.mjs +18 -26
- package/server/public/app/bootstrap.js +230 -35
- package/server/public/app/chat-actions-menu-state.mjs +116 -0
- package/server/public/app/claude-cloud-conversation-ui.js +10 -22
- package/server/public/app/composer-control-state.mjs +16 -0
- package/server/public/app/composer-keyboard.mjs +54 -0
- package/server/public/app/conversation-view.js +471 -110
- package/server/public/app/explorer-edit-state.mjs +68 -0
- package/server/public/app/external-link-policy.mjs +4 -1
- package/server/public/app/file-version.mjs +58 -0
- package/server/public/app/host-suspend-ui.js +6 -3
- package/server/public/app/journal-view.js +161 -27
- package/server/public/app/no-conversation-state.mjs +58 -0
- package/server/public/app/pinned-messages-view.mjs +253 -0
- package/server/public/app/provider-readiness.mjs +120 -0
- package/server/public/app/pwa-install.js +1 -1
- package/server/public/app/relay-board-view.js +3 -0
- package/server/public/app/relay-dot-state.mjs +8 -1
- package/server/public/app/relay-event-subscriptions-ui.js +184 -0
- package/server/public/app/relay-event-view.mjs +234 -0
- package/server/public/app/router.js +8 -2
- package/server/public/app/settings-modal.js +53 -1
- package/server/public/app/socket-handlers.js +65 -28
- package/server/public/app/store.js +25 -2
- package/server/public/app/subagent-row.mjs +138 -0
- package/server/public/app/subagent-timeline-view.mjs +186 -0
- package/server/public/app/subagent-viewer-watch.mjs +50 -0
- package/server/public/app/subagent-viewer.mjs +534 -0
- package/server/public/app/task-row-format.mjs +29 -0
- package/server/public/app/thinking-follow.js +4 -0
- package/server/public/app/transcript-jump-bottom-view.mjs +290 -0
- package/server/public/app/transcript-jump-bottom.mjs +99 -0
- package/server/public/app/transcript-reload-freshness.mjs +25 -0
- package/server/public/app/update-ui.js +1 -1
- package/server/public/app/viewer-chat-gallery.mjs +59 -0
- package/server/public/app/viewer-controls-state.mjs +59 -0
- package/server/public/app/viewer-gallery.mjs +46 -0
- package/server/public/app/viewer-gestures.mjs +105 -0
- package/server/public/app/viewer-history.mjs +45 -0
- package/server/public/app/viewer-tap.mjs +112 -0
- package/server/public/index.html +700 -59
- package/server/repositories/message-pin-statements.mjs +39 -0
- package/server/repositories/message-repository.mjs +34 -3
- package/server/repositories/question-repository.mjs +9 -3
- package/server/repositories/remote-relay-repository.mjs +6 -2
- package/server/repositories/subagent-timeline-statements.mjs +170 -0
- package/server/routes/ask-user-routes.mjs +3 -0
- package/server/routes/messages-routes.mjs +548 -111
- package/server/routes/relay-event-routes.mjs +157 -0
- package/server/routes/remote-relay-routes.mjs +15 -0
- package/server/routes/sessions-routes.mjs +164 -24
- package/server/server-runtime.mjs +274 -62
- package/server/services/cloudflared-tunnel-service.mjs +139 -41
- package/server/services/explorer-entry-name.mjs +26 -0
- package/server/services/explorer-mutations.mjs +122 -0
- package/server/services/file-serving.mjs +155 -0
- package/server/services/message-pin-list.mjs +52 -0
- package/server/services/oar-cli-helpers.mjs +139 -4
- package/server/services/oar-cli-menu.mjs +240 -0
- package/server/services/oar-cli-wsl.mjs +129 -0
- package/server/services/preview-proxy-server.mjs +41 -23
- package/server/services/push-dispatch-service.mjs +18 -0
- package/server/services/relay-event-link-service.mjs +289 -0
- package/server/services/relay-event-service.mjs +1935 -0
- package/server/services/relay-shutdown-gate.mjs +31 -0
- package/server/services/remote-relay-caller-context.mjs +52 -7
- package/server/services/remote-relay-dispatcher.mjs +494 -2
- package/server/services/remote-relay-registry-service.mjs +11 -1
- package/server/services/safe-served-content.mjs +61 -11
- package/server/services/session-activity-tracker.mjs +487 -0
- package/server/services/session-history-refresh-service.mjs +31 -0
- package/server/services/stale-attempt-log-limiter.mjs +96 -0
- package/server/services/stale-recovery-clock-guard.mjs +57 -0
- package/server/services/stale-subagent-run-sweep.mjs +109 -0
- package/server/services/subagent-record-retention.mjs +164 -0
- package/server/services/subagent-timeline-service.mjs +328 -0
- package/server/services/subagent-viewer-rooms.mjs +119 -0
- package/server/services/upgrade-socket-guard.mjs +16 -0
- package/shared/relay-events.mjs +371 -0
- package/shared/remote-relay-contract.mjs +157 -5
- package/shared/subagent-record-retention.mjs +31 -0
- package/shared/subagent-timeline.mjs +79 -0
package/server/public/index.html
CHANGED
|
@@ -572,6 +572,23 @@
|
|
|
572
572
|
opacity: 0.5;
|
|
573
573
|
cursor: not-allowed;
|
|
574
574
|
}
|
|
575
|
+
/* An icon with a number beside it (📍 3) grows with the number. */
|
|
576
|
+
.header-icon-btn.has-count {
|
|
577
|
+
width: auto;
|
|
578
|
+
min-width: 32px;
|
|
579
|
+
padding: 0 7px;
|
|
580
|
+
gap: 4px;
|
|
581
|
+
}
|
|
582
|
+
.header-icon-count {
|
|
583
|
+
font-size: var(--fs-meta-sm);
|
|
584
|
+
font-variant-numeric: tabular-nums;
|
|
585
|
+
}
|
|
586
|
+
.header-icon-count:empty { display: none; }
|
|
587
|
+
/* The display rule above outranks the UA [hidden] rule, same trap as the
|
|
588
|
+
other [hidden] overrides in this file. */
|
|
589
|
+
#pinned-messages-btn[hidden] { display: none; }
|
|
590
|
+
/* Same trap: without this the ⋯ trigger stays drawn as a dead button. */
|
|
591
|
+
#chat-actions-menu-btn[hidden] { display: none; }
|
|
575
592
|
#cli-dot {
|
|
576
593
|
width: 12px;
|
|
577
594
|
height: 12px;
|
|
@@ -853,7 +870,8 @@
|
|
|
853
870
|
/* The conversation context menu (context-menu.mjs): right-click / long press. */
|
|
854
871
|
.context-menu {
|
|
855
872
|
position: fixed;
|
|
856
|
-
|
|
873
|
+
/* Above every modal: the explorer (10001, 12400 as a CWD picker) opens one too. */
|
|
874
|
+
z-index: 13000;
|
|
857
875
|
min-width: 200px;
|
|
858
876
|
max-width: min(320px, calc(100vw - 8px));
|
|
859
877
|
padding: 4px;
|
|
@@ -1427,7 +1445,27 @@
|
|
|
1427
1445
|
}
|
|
1428
1446
|
.empty-state .icon { font-size: 3rem; margin-bottom: 12px; }
|
|
1429
1447
|
.empty-state h3 { font-size: var(--fs-core-chat-title); margin-bottom: 8px; color: var(--text); }
|
|
1430
|
-
.empty-state p { font-size: var(--fs-meta-md); line-height: 1.5; }
|
|
1448
|
+
.empty-state p { font-size: var(--fs-meta-md); line-height: 1.5; max-width: 36em; }
|
|
1449
|
+
/* The actions of the "no conversation open" screen: Settings, New chat, the
|
|
1450
|
+
list on the phone. Same shapes as .summary-btn and #new-conv-btn. */
|
|
1451
|
+
.empty-state-actions {
|
|
1452
|
+
display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; align-items: center;
|
|
1453
|
+
margin-top: 18px;
|
|
1454
|
+
}
|
|
1455
|
+
.empty-state-btn {
|
|
1456
|
+
border: 1px solid var(--border); background: var(--bg2); color: var(--text);
|
|
1457
|
+
border-radius: 8px; height: 36px; padding: 0 14px; font-size: var(--fs-meta-md);
|
|
1458
|
+
cursor: pointer;
|
|
1459
|
+
}
|
|
1460
|
+
.empty-state-btn:hover { border-color: var(--accent); color: var(--accent); }
|
|
1461
|
+
.empty-state-btn.empty-state-btn-accent {
|
|
1462
|
+
background: var(--accent); color: #000; border-color: var(--accent); font-weight: 600;
|
|
1463
|
+
}
|
|
1464
|
+
.empty-state-btn.empty-state-btn-accent:hover { color: #000; opacity: 0.85; }
|
|
1465
|
+
.empty-state-btn.empty-state-link {
|
|
1466
|
+
border-color: transparent; background: transparent; color: var(--muted); text-decoration: underline;
|
|
1467
|
+
}
|
|
1468
|
+
.empty-state-btn.empty-state-link:hover { color: var(--accent); }
|
|
1431
1469
|
|
|
1432
1470
|
.msg {
|
|
1433
1471
|
display: flex;
|
|
@@ -1771,8 +1809,13 @@
|
|
|
1771
1809
|
opacity: 0;
|
|
1772
1810
|
pointer-events: none;
|
|
1773
1811
|
}
|
|
1812
|
+
/* `.msg-actions-revealed`: a tap on the bubble on a touch screen. The tap
|
|
1813
|
+
also leaves an emulated :hover behind, but Chromium drops that hover at
|
|
1814
|
+
the next scroll or layout change (seen on Linux), which left the row
|
|
1815
|
+
untappable; the class holds the reveal until a tap lands elsewhere. */
|
|
1774
1816
|
.msg-bubble:hover .msg-share-visibility-btn[data-hidden-from-shares="false"],
|
|
1775
|
-
.msg-bubble:focus-within .msg-share-visibility-btn[data-hidden-from-shares="false"]
|
|
1817
|
+
.msg-bubble:focus-within .msg-share-visibility-btn[data-hidden-from-shares="false"],
|
|
1818
|
+
.msg-bubble.msg-actions-revealed .msg-share-visibility-btn[data-hidden-from-shares="false"] {
|
|
1776
1819
|
opacity: 1;
|
|
1777
1820
|
pointer-events: auto;
|
|
1778
1821
|
}
|
|
@@ -1780,7 +1823,46 @@
|
|
|
1780
1823
|
.msg.user .msg-share-visibility-btn { color: var(--user-bubble-fg); opacity: 0.8; }
|
|
1781
1824
|
.msg.user .msg-share-visibility-btn[data-hidden-from-shares="false"] { opacity: 0; }
|
|
1782
1825
|
.msg.user .msg-bubble:hover .msg-share-visibility-btn[data-hidden-from-shares="false"],
|
|
1783
|
-
.msg.user .msg-bubble:focus-within .msg-share-visibility-btn[data-hidden-from-shares="false"]
|
|
1826
|
+
.msg.user .msg-bubble:focus-within .msg-share-visibility-btn[data-hidden-from-shares="false"],
|
|
1827
|
+
.msg.user .msg-bubble.msg-actions-revealed .msg-share-visibility-btn[data-hidden-from-shares="false"] { opacity: 0.8; }
|
|
1828
|
+
/* The pin half of the same corner row: `Pin` is revealed like `Hide`, a
|
|
1829
|
+
pinned message keeps its label and `Unpin` in view. */
|
|
1830
|
+
.msg-share-visibility { flex-wrap: wrap; }
|
|
1831
|
+
.msg-pinned-label {
|
|
1832
|
+
color: var(--muted);
|
|
1833
|
+
font-size: var(--fs-ui-chip);
|
|
1834
|
+
white-space: nowrap;
|
|
1835
|
+
}
|
|
1836
|
+
.msg-pin-btn {
|
|
1837
|
+
appearance: none;
|
|
1838
|
+
border: 0;
|
|
1839
|
+
background: transparent;
|
|
1840
|
+
color: var(--muted);
|
|
1841
|
+
cursor: pointer;
|
|
1842
|
+
font-size: var(--fs-ui-chip);
|
|
1843
|
+
line-height: 1;
|
|
1844
|
+
padding: 4px;
|
|
1845
|
+
text-decoration: underline;
|
|
1846
|
+
text-underline-offset: 2px;
|
|
1847
|
+
}
|
|
1848
|
+
.msg-pin-btn:hover:not(:disabled) { color: var(--accent); }
|
|
1849
|
+
.msg-pin-btn:disabled { cursor: wait; opacity: 0.55; }
|
|
1850
|
+
.msg-pin-btn[data-pinned="false"] {
|
|
1851
|
+
opacity: 0;
|
|
1852
|
+
pointer-events: none;
|
|
1853
|
+
}
|
|
1854
|
+
.msg-bubble:hover .msg-pin-btn[data-pinned="false"],
|
|
1855
|
+
.msg-bubble:focus-within .msg-pin-btn[data-pinned="false"],
|
|
1856
|
+
.msg-bubble.msg-actions-revealed .msg-pin-btn[data-pinned="false"] {
|
|
1857
|
+
opacity: 1;
|
|
1858
|
+
pointer-events: auto;
|
|
1859
|
+
}
|
|
1860
|
+
.msg.user .msg-pinned-label,
|
|
1861
|
+
.msg.user .msg-pin-btn { color: var(--user-bubble-fg); opacity: 0.8; }
|
|
1862
|
+
.msg.user .msg-pin-btn[data-pinned="false"] { opacity: 0; }
|
|
1863
|
+
.msg.user .msg-bubble:hover .msg-pin-btn[data-pinned="false"],
|
|
1864
|
+
.msg.user .msg-bubble:focus-within .msg-pin-btn[data-pinned="false"],
|
|
1865
|
+
.msg.user .msg-bubble.msg-actions-revealed .msg-pin-btn[data-pinned="false"] { opacity: 0.8; }
|
|
1784
1866
|
.thinking-thoughts-panel {
|
|
1785
1867
|
margin-bottom: 8px;
|
|
1786
1868
|
min-width: 0;
|
|
@@ -2088,6 +2170,69 @@
|
|
|
2088
2170
|
opacity: 1;
|
|
2089
2171
|
transition: width 0.2s ease, background-size 0.2s ease, box-shadow 0.2s ease;
|
|
2090
2172
|
}
|
|
2173
|
+
/* Jump to the end of the transcript (transcript-jump-bottom-view.mjs).
|
|
2174
|
+
Anchored to the composer's top edge, so it rides above the composer and
|
|
2175
|
+
the background-task panel at whatever height they have, and above the
|
|
2176
|
+
on-screen keyboard with them. Below the composer popups (z-index 30). */
|
|
2177
|
+
#jump-to-bottom-btn {
|
|
2178
|
+
position: absolute;
|
|
2179
|
+
right: calc(20px + env(safe-area-inset-right, 0px));
|
|
2180
|
+
bottom: calc(100% + 12px);
|
|
2181
|
+
z-index: 25;
|
|
2182
|
+
width: 40px;
|
|
2183
|
+
height: 40px;
|
|
2184
|
+
padding: 0;
|
|
2185
|
+
border-radius: 50%;
|
|
2186
|
+
border: 1px solid var(--border);
|
|
2187
|
+
background: var(--bg2);
|
|
2188
|
+
color: var(--text);
|
|
2189
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
|
|
2190
|
+
display: flex;
|
|
2191
|
+
align-items: center;
|
|
2192
|
+
justify-content: center;
|
|
2193
|
+
cursor: pointer;
|
|
2194
|
+
touch-action: manipulation;
|
|
2195
|
+
-webkit-tap-highlight-color: transparent;
|
|
2196
|
+
opacity: 0;
|
|
2197
|
+
visibility: hidden;
|
|
2198
|
+
transform: translateY(6px);
|
|
2199
|
+
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0.18s, border-color 0.15s ease, color 0.15s ease;
|
|
2200
|
+
}
|
|
2201
|
+
#jump-to-bottom-btn.visible {
|
|
2202
|
+
opacity: 1;
|
|
2203
|
+
visibility: visible;
|
|
2204
|
+
transform: none;
|
|
2205
|
+
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s, border-color 0.15s ease, color 0.15s ease;
|
|
2206
|
+
}
|
|
2207
|
+
#jump-to-bottom-btn:hover,
|
|
2208
|
+
#jump-to-bottom-btn:focus-visible { border-color: var(--accent); color: var(--accent); }
|
|
2209
|
+
.jump-to-bottom-icon {
|
|
2210
|
+
font-size: 26px;
|
|
2211
|
+
line-height: 1;
|
|
2212
|
+
/* The arrowhead sits low in its em box. */
|
|
2213
|
+
transform: translateY(-4px);
|
|
2214
|
+
}
|
|
2215
|
+
.jump-to-bottom-badge {
|
|
2216
|
+
position: absolute;
|
|
2217
|
+
top: -6px;
|
|
2218
|
+
right: -6px;
|
|
2219
|
+
min-width: 18px;
|
|
2220
|
+
height: 18px;
|
|
2221
|
+
padding: 0 5px;
|
|
2222
|
+
box-sizing: border-box;
|
|
2223
|
+
border-radius: 9px;
|
|
2224
|
+
background: var(--accent);
|
|
2225
|
+
color: #000;
|
|
2226
|
+
font-size: 11px;
|
|
2227
|
+
font-weight: 700;
|
|
2228
|
+
line-height: 18px;
|
|
2229
|
+
text-align: center;
|
|
2230
|
+
}
|
|
2231
|
+
.jump-to-bottom-badge[hidden] { display: none; }
|
|
2232
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2233
|
+
#jump-to-bottom-btn,
|
|
2234
|
+
#jump-to-bottom-btn.visible { transition: none; }
|
|
2235
|
+
}
|
|
2091
2236
|
/* ── Context usage modal ── */
|
|
2092
2237
|
.ctx-usage-model {
|
|
2093
2238
|
font-size: 0.95rem;
|
|
@@ -2935,6 +3080,110 @@
|
|
|
2935
3080
|
}
|
|
2936
3081
|
.bg-task-stop:hover:not(:disabled) { border-color: #f85149; color: #f85149; }
|
|
2937
3082
|
.bg-task-stop:disabled { opacity: 0.5; cursor: default; }
|
|
3083
|
+
/* Sub-agent rows (reply bubble, viewer): the task panel's row grammar. The
|
|
3084
|
+
title is a button that opens the agent's record in the viewer. */
|
|
3085
|
+
.subagent-rows { display: flex; flex-direction: column; margin-top: 4px; }
|
|
3086
|
+
.subagent-row-bubble { background: var(--bg3); border: 1px solid var(--border); }
|
|
3087
|
+
.subagent-row-timeline { margin-top: 0; background: var(--bg3); border: 1px solid var(--border); }
|
|
3088
|
+
.bg-task-desc.subagent-open {
|
|
3089
|
+
display: block; -webkit-line-clamp: unset; background: none; border: 0; padding: 0; margin: 0;
|
|
3090
|
+
font: inherit; color: var(--text); text-align: left; cursor: pointer;
|
|
3091
|
+
text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px;
|
|
3092
|
+
}
|
|
3093
|
+
.bg-task-desc.subagent-open:hover, .bg-task-desc.subagent-open:focus-visible {
|
|
3094
|
+
color: var(--accent); text-decoration-color: currentColor; outline: none;
|
|
3095
|
+
}
|
|
3096
|
+
.subagent-row-status.subagent-status-failed { color: #f85149; }
|
|
3097
|
+
.subagent-row-status.subagent-status-completed { color: #3fb950; }
|
|
3098
|
+
/* The sub-agent viewer: one agent's thoughts, tool calls and reply in order.
|
|
3099
|
+
Below the file viewer, so a file opened from the record comes on top. */
|
|
3100
|
+
#subagent-viewer-modal {
|
|
3101
|
+
position: fixed; inset: 0; z-index: 10900; display: none;
|
|
3102
|
+
align-items: center; justify-content: center;
|
|
3103
|
+
background: rgba(0, 0, 0, 0.68); padding: 18px;
|
|
3104
|
+
}
|
|
3105
|
+
#subagent-viewer-modal.visible { display: flex; }
|
|
3106
|
+
.subagent-viewer-dialog {
|
|
3107
|
+
position: relative; width: min(980px, 100%); height: min(90vh, 1000px);
|
|
3108
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
3109
|
+
background: var(--bg2); border: 1px solid var(--border); border-radius: 14px;
|
|
3110
|
+
}
|
|
3111
|
+
.subagent-viewer-header {
|
|
3112
|
+
display: flex; flex-direction: column; gap: 4px; padding: 10px 14px;
|
|
3113
|
+
border-bottom: 1px solid var(--border); background: var(--bg3);
|
|
3114
|
+
}
|
|
3115
|
+
.subagent-viewer-title-row { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
3116
|
+
#subagent-viewer-title { flex: 1; min-width: 0; margin: 0; font-size: 1.05rem; font-weight: 600; overflow-wrap: anywhere; }
|
|
3117
|
+
#subagent-viewer-meta { color: var(--muted); font-size: var(--fs-meta-sm); overflow-wrap: anywhere; }
|
|
3118
|
+
.subagent-viewer-btn {
|
|
3119
|
+
flex-shrink: 0; border: 1px solid var(--border); background: var(--bg2); color: var(--text);
|
|
3120
|
+
border-radius: 8px; height: 32px; padding: 0 10px; font-size: var(--fs-meta-sm); cursor: pointer;
|
|
3121
|
+
}
|
|
3122
|
+
.subagent-viewer-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
|
|
3123
|
+
#subagent-viewer-stop:hover:not(:disabled) { border-color: #f85149; color: #f85149; }
|
|
3124
|
+
.subagent-viewer-btn:disabled { opacity: 0.5; cursor: default; }
|
|
3125
|
+
.subagent-viewer-close { font-size: 1.2rem; line-height: 1; }
|
|
3126
|
+
#subagent-viewer-parent {
|
|
3127
|
+
align-self: flex-start; background: none; border: 0; padding: 0; color: var(--accent);
|
|
3128
|
+
cursor: pointer; font-size: var(--fs-meta-sm);
|
|
3129
|
+
}
|
|
3130
|
+
#subagent-viewer-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 8px 14px 28px; }
|
|
3131
|
+
#subagent-viewer-status { color: var(--muted); padding: 14px 0; font-size: var(--fs-meta-sm); }
|
|
3132
|
+
#subagent-viewer-jump {
|
|
3133
|
+
position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
|
|
3134
|
+
border: 1px solid var(--accent); background: var(--bg3); color: var(--accent);
|
|
3135
|
+
border-radius: 999px; padding: 5px 14px; font-size: var(--fs-meta-sm); cursor: pointer;
|
|
3136
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
|
|
3137
|
+
}
|
|
3138
|
+
.sav-entry { margin: 6px 0; min-width: 0; }
|
|
3139
|
+
.sav-entry details > summary {
|
|
3140
|
+
cursor: pointer; display: flex; align-items: baseline; gap: 6px; min-width: 0; list-style: none;
|
|
3141
|
+
}
|
|
3142
|
+
.sav-entry details > summary::-webkit-details-marker { display: none; }
|
|
3143
|
+
.sav-entry details > summary::before { content: '▸'; color: var(--muted); flex-shrink: 0; }
|
|
3144
|
+
.sav-entry details[open] > summary::before { content: '▾'; }
|
|
3145
|
+
.sav-call-line { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
|
|
3146
|
+
.sav-kind { flex-shrink: 0; }
|
|
3147
|
+
.sav-tool-name { font-weight: 600; flex-shrink: 0; }
|
|
3148
|
+
.sav-summary-text, .sav-tool-summary {
|
|
3149
|
+
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
3150
|
+
}
|
|
3151
|
+
.sav-tool-summary { color: var(--muted); font-family: var(--mono, monospace); font-size: var(--fs-meta-sm); }
|
|
3152
|
+
.sav-pre {
|
|
3153
|
+
margin: 6px 0 0; padding: 8px 10px; max-height: 50vh; overflow: auto;
|
|
3154
|
+
white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--mono, monospace);
|
|
3155
|
+
font-size: var(--fs-meta-sm); background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
|
|
3156
|
+
}
|
|
3157
|
+
.sav-entry-tool_result { margin-left: 22px; color: var(--muted); font-size: var(--fs-meta-sm); }
|
|
3158
|
+
.sav-entry-tool_result .sav-pre { color: var(--text); }
|
|
3159
|
+
.sav-entry-tool_result.is-error .sav-result-label { color: #f85149; }
|
|
3160
|
+
.sav-entry-thought { color: var(--muted); }
|
|
3161
|
+
.sav-thought-body { padding: 4px 0 0 18px; color: var(--text); opacity: 0.85; }
|
|
3162
|
+
.sav-text {
|
|
3163
|
+
padding: 8px 12px; border-radius: 10px; background: var(--bg3); border: 1px solid var(--border);
|
|
3164
|
+
overflow-wrap: anywhere;
|
|
3165
|
+
}
|
|
3166
|
+
.sav-entry.is-open .sav-text::after,
|
|
3167
|
+
.sav-entry-thought.is-open .sav-thought-body::after {
|
|
3168
|
+
content: '▍'; margin-left: 2px; animation: bg-task-pulse 1s ease-in-out infinite;
|
|
3169
|
+
}
|
|
3170
|
+
/* Markdown in the record reads like a reply bubble. */
|
|
3171
|
+
.sav-text p, .sav-thought-body p { margin: 0 0 0.5em; }
|
|
3172
|
+
.sav-text p:last-child, .sav-thought-body p:last-child { margin-bottom: 0; }
|
|
3173
|
+
.sav-text ul, .sav-text ol, .sav-thought-body ul, .sav-thought-body ol { padding-left: 1.4em; margin: 0 0 0.5em; }
|
|
3174
|
+
.sav-text h1, .sav-text h2, .sav-text h3 { margin: 0.5em 0 0.25em; font-size: 1em; }
|
|
3175
|
+
.sav-text pre, .sav-thought-body pre { margin: 0.5em 0; border-radius: 8px; max-width: 100%; overflow-x: auto; }
|
|
3176
|
+
.sav-text code:not(pre code), .sav-thought-body code:not(pre code) {
|
|
3177
|
+
background: var(--inline-code-bg); padding: 2px 6px; border-radius: 4px; font-size: 0.875em; overflow-wrap: anywhere;
|
|
3178
|
+
}
|
|
3179
|
+
.sav-note { color: var(--muted); font-size: var(--fs-meta-sm); font-style: italic; }
|
|
3180
|
+
.sav-note-failed { color: #f85149; }
|
|
3181
|
+
.sav-muted { color: var(--muted); }
|
|
3182
|
+
@media (max-width: 680px) {
|
|
3183
|
+
#subagent-viewer-modal { padding: 0; }
|
|
3184
|
+
.subagent-viewer-dialog { width: 100%; height: 100%; border: 0; border-radius: 0; }
|
|
3185
|
+
#subagent-viewer-body { padding: 8px 10px 28px; }
|
|
3186
|
+
}
|
|
2938
3187
|
/* Preview cards: same row grammar as a background task, with a link-shaped
|
|
2939
3188
|
primary action. Shared by the composer panel and the settings list. */
|
|
2940
3189
|
.preview-row {
|
|
@@ -3056,6 +3305,102 @@
|
|
|
3056
3305
|
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
3057
3306
|
}
|
|
3058
3307
|
#chat-title-origin button.conv-origin-agent { padding: 3px 0; }
|
|
3308
|
+
/* Relay events: the event rows the relay writes into a watcher's
|
|
3309
|
+
conversation (never a bubble of the user's), the "watching" chip with its
|
|
3310
|
+
list, and the "watched" badge. */
|
|
3311
|
+
.msg.relay-event { align-self: stretch; max-width: 100%; align-items: stretch; }
|
|
3312
|
+
.relay-event-row {
|
|
3313
|
+
border: 1px dashed var(--border); border-left: 3px solid var(--accent);
|
|
3314
|
+
border-radius: 6px; background: var(--bg2); color: var(--muted);
|
|
3315
|
+
font-size: var(--fs-meta-xs); padding: 2px 8px;
|
|
3316
|
+
}
|
|
3317
|
+
.relay-event-row.relay-event-urgent { border-left-color: var(--warn); }
|
|
3318
|
+
.relay-event-summary {
|
|
3319
|
+
cursor: pointer; display: flex; gap: 8px; align-items: baseline; min-width: 0;
|
|
3320
|
+
padding: 3px 0; list-style-position: inside;
|
|
3321
|
+
}
|
|
3322
|
+
.relay-event-tag {
|
|
3323
|
+
flex: 0 0 auto; text-transform: uppercase; letter-spacing: 0.04em;
|
|
3324
|
+
font-size: var(--fs-ui-chip); color: var(--accent);
|
|
3325
|
+
}
|
|
3326
|
+
.relay-event-urgent .relay-event-tag { color: var(--warn); }
|
|
3327
|
+
.relay-event-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3328
|
+
.relay-event-time { flex: 0 0 auto; }
|
|
3329
|
+
.relay-event-lines { margin: 2px 0 4px; padding-left: 18px; }
|
|
3330
|
+
.relay-event-line { margin: 2px 0; overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
3331
|
+
.relay-event-line.relay-event-question-asked,
|
|
3332
|
+
.relay-event-line.relay-event-error,
|
|
3333
|
+
.relay-event-line.relay-event-task-failed,
|
|
3334
|
+
.relay-event-line.relay-event-stalled { color: var(--text, inherit); }
|
|
3335
|
+
/* Agent exchanges: an agent's prompt and this session's reply folded into
|
|
3336
|
+
one row in the event rows' look (agent-exchange-fold-view.mjs). The row
|
|
3337
|
+
is the first child of the prompt's own node; closed, the prompt's bubble
|
|
3338
|
+
and the exchange's other rows (the reply, the live bubble) are hidden.
|
|
3339
|
+
The prompt's node spans the pane for the row; its bubble keeps a user
|
|
3340
|
+
bubble's width. */
|
|
3341
|
+
.msg.agent-exchange-head { align-self: stretch; max-width: 100%; }
|
|
3342
|
+
.msg.agent-exchange-head > .msg-bubble { max-width: 82%; }
|
|
3343
|
+
.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; }
|
|
3346
|
+
.agent-exchange-row {
|
|
3347
|
+
align-self: stretch; min-width: 0;
|
|
3348
|
+
border: 1px dashed var(--border); border-left: 3px solid var(--accent);
|
|
3349
|
+
border-radius: 6px; background: var(--bg2); color: var(--muted);
|
|
3350
|
+
font-size: var(--fs-meta-xs); padding: 2px 8px;
|
|
3351
|
+
}
|
|
3352
|
+
.msg.agent-exchange-head:not(.agent-exchange-closed) > .agent-exchange-row { margin-bottom: 6px; }
|
|
3353
|
+
.agent-exchange-summary {
|
|
3354
|
+
cursor: pointer; display: flex; gap: 8px; align-items: baseline; min-width: 0;
|
|
3355
|
+
padding: 3px 0; list-style: none;
|
|
3356
|
+
}
|
|
3357
|
+
.agent-exchange-summary::-webkit-details-marker { display: none; }
|
|
3358
|
+
.agent-exchange-summary::before { content: '▸'; flex: 0 0 auto; color: var(--accent); }
|
|
3359
|
+
.agent-exchange-row[open] > .agent-exchange-summary::before { content: '▾'; }
|
|
3360
|
+
.agent-exchange-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3361
|
+
.agent-exchange-status,
|
|
3362
|
+
.agent-exchange-time { flex: 0 0 auto; }
|
|
3363
|
+
.agent-exchange-status { color: var(--text, inherit); }
|
|
3364
|
+
.agent-exchange-row.agent-exchange-failed,
|
|
3365
|
+
.agent-exchange-row.agent-exchange-stopped { border-left-color: var(--warn); }
|
|
3366
|
+
.agent-exchange-failed .agent-exchange-status,
|
|
3367
|
+
.agent-exchange-stopped .agent-exchange-status { color: var(--warn); }
|
|
3368
|
+
@media (max-width: 680px) {
|
|
3369
|
+
.msg.agent-exchange-head > .msg-bubble { max-width: 95%; }
|
|
3370
|
+
}
|
|
3371
|
+
#chat-title-relay-events {
|
|
3372
|
+
display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 2px;
|
|
3373
|
+
font-size: var(--fs-meta-xs); line-height: 1.2; color: var(--muted); position: relative;
|
|
3374
|
+
}
|
|
3375
|
+
#chat-title-relay-events[hidden] { display: none; }
|
|
3376
|
+
.relay-watch-panel[hidden] { display: none; }
|
|
3377
|
+
.relay-watch-chip {
|
|
3378
|
+
font: inherit; color: var(--accent); background: transparent; cursor: pointer;
|
|
3379
|
+
border: 1px solid var(--border); border-radius: 10px; padding: 2px 8px;
|
|
3380
|
+
}
|
|
3381
|
+
.relay-watch-panel {
|
|
3382
|
+
position: fixed; top: 0; left: 0; z-index: 60; overflow-y: auto; box-sizing: border-box;
|
|
3383
|
+
min-width: min(260px, calc(100vw - 16px)); max-width: min(calc(100vw - 16px), 480px);
|
|
3384
|
+
font-size: var(--fs-meta-xs); line-height: 1.2; color: var(--muted);
|
|
3385
|
+
background: var(--bg2); border: 1px solid var(--border); border-radius: 8px;
|
|
3386
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25); padding: 6px;
|
|
3387
|
+
}
|
|
3388
|
+
.relay-watch-list { list-style: none; margin: 0; padding: 0; }
|
|
3389
|
+
.relay-watch-item {
|
|
3390
|
+
display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 8px; align-items: center;
|
|
3391
|
+
padding: 6px 4px; border-bottom: 1px solid var(--border);
|
|
3392
|
+
}
|
|
3393
|
+
.relay-watch-item:last-child { border-bottom: none; }
|
|
3394
|
+
.relay-watch-what { color: var(--text, inherit); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3395
|
+
.relay-watch-events { grid-column: 1; font-size: var(--fs-ui-chip); }
|
|
3396
|
+
.relay-watch-unsubscribe {
|
|
3397
|
+
grid-column: 2; grid-row: 1 / span 2; font: inherit; cursor: pointer;
|
|
3398
|
+
color: var(--danger); background: transparent; border: 1px solid var(--border); border-radius: 6px; padding: 4px 8px;
|
|
3399
|
+
}
|
|
3400
|
+
.conv-watched-badge {
|
|
3401
|
+
flex: 0 0 auto; font-size: var(--fs-ui-chip); color: var(--accent);
|
|
3402
|
+
border: 1px solid var(--border); border-radius: 8px; padding: 0 5px;
|
|
3403
|
+
}
|
|
3059
3404
|
/* Agent sessions (Settings → Relays). The slider spans the row so a thumb
|
|
3060
3405
|
has room to travel at phone width, with a taller touch area than the
|
|
3061
3406
|
track itself. */
|
|
@@ -3226,28 +3571,62 @@
|
|
|
3226
3571
|
.workspace-file-link { text-decoration: underline; }
|
|
3227
3572
|
.workspace-file-link:hover { opacity: 0.9; }
|
|
3228
3573
|
|
|
3574
|
+
/* The file viewer fills the screen. Its chrome (title, toolbar, meta line
|
|
3575
|
+
above; position and prev/next below) floats over the content and slides
|
|
3576
|
+
away when the controls are hidden. Text kinds keep the app background and
|
|
3577
|
+
a readable column; media kinds go black edge to edge. */
|
|
3229
3578
|
#file-preview-modal {
|
|
3230
3579
|
position: fixed; inset: 0; z-index: 11000;
|
|
3231
|
-
display: none;
|
|
3232
|
-
background:
|
|
3233
|
-
|
|
3580
|
+
display: none;
|
|
3581
|
+
background: var(--bg2);
|
|
3582
|
+
--file-viewer-chrome-top: 0px;
|
|
3234
3583
|
}
|
|
3235
|
-
#file-preview-modal.visible { display:
|
|
3584
|
+
#file-preview-modal.visible { display: block; }
|
|
3585
|
+
#file-preview-modal.media-mode { background: #000; }
|
|
3236
3586
|
.file-preview-dialog {
|
|
3237
|
-
|
|
3238
|
-
max-height: min(90vh, 900px);
|
|
3239
|
-
display: flex;
|
|
3240
|
-
flex-direction: column;
|
|
3241
|
-
background: var(--bg2);
|
|
3242
|
-
border: 1px solid var(--border);
|
|
3243
|
-
border-radius: 14px;
|
|
3587
|
+
position: absolute; inset: 0;
|
|
3244
3588
|
overflow: hidden;
|
|
3245
3589
|
}
|
|
3590
|
+
.file-preview-chrome {
|
|
3591
|
+
position: absolute; left: 0; right: 0; z-index: 2;
|
|
3592
|
+
transition: opacity 0.18s ease, transform 0.18s ease;
|
|
3593
|
+
}
|
|
3594
|
+
.file-preview-chrome-top {
|
|
3595
|
+
top: 0;
|
|
3596
|
+
padding-top: env(safe-area-inset-top);
|
|
3597
|
+
background: color-mix(in srgb, var(--bg3) 92%, transparent);
|
|
3598
|
+
-webkit-backdrop-filter: blur(10px);
|
|
3599
|
+
backdrop-filter: blur(10px);
|
|
3600
|
+
border-bottom: 1px solid var(--border);
|
|
3601
|
+
}
|
|
3602
|
+
#file-preview-modal.media-mode .file-preview-chrome-top {
|
|
3603
|
+
background: linear-gradient(rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0.62) 70%, rgba(0, 0, 0, 0));
|
|
3604
|
+
border-bottom: 0;
|
|
3605
|
+
-webkit-backdrop-filter: none;
|
|
3606
|
+
backdrop-filter: none;
|
|
3607
|
+
color: #fff;
|
|
3608
|
+
padding-bottom: 18px;
|
|
3609
|
+
}
|
|
3610
|
+
.file-preview-chrome-bottom {
|
|
3611
|
+
bottom: 0;
|
|
3612
|
+
display: flex; align-items: center; justify-content: center; gap: 14px;
|
|
3613
|
+
padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
|
|
3614
|
+
background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.62));
|
|
3615
|
+
color: #fff;
|
|
3616
|
+
}
|
|
3617
|
+
.file-preview-chrome-bottom[hidden] { display: none; }
|
|
3618
|
+
#file-preview-modal.controls-hidden .file-preview-chrome { opacity: 0; pointer-events: none; }
|
|
3619
|
+
#file-preview-modal.controls-hidden .file-preview-chrome-top { transform: translateY(-12px); }
|
|
3620
|
+
#file-preview-modal.controls-hidden .file-preview-chrome-bottom { transform: translateY(12px); }
|
|
3621
|
+
.file-preview-position {
|
|
3622
|
+
min-width: 4ch; text-align: center;
|
|
3623
|
+
font-size: var(--fs-meta-md);
|
|
3624
|
+
font-variant-numeric: tabular-nums;
|
|
3625
|
+
}
|
|
3626
|
+
.file-preview-nav { font-size: 1.3rem; line-height: 1; padding: 4px 14px; }
|
|
3246
3627
|
.file-preview-header {
|
|
3247
3628
|
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
|
3248
3629
|
padding: 12px 14px;
|
|
3249
|
-
border-bottom: 1px solid var(--border);
|
|
3250
|
-
background: var(--bg3);
|
|
3251
3630
|
}
|
|
3252
3631
|
.file-preview-title {
|
|
3253
3632
|
min-width: 0;
|
|
@@ -3272,23 +3651,35 @@
|
|
|
3272
3651
|
}
|
|
3273
3652
|
.file-preview-toolbar {
|
|
3274
3653
|
display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
|
|
3275
|
-
padding:
|
|
3276
|
-
border-bottom: 1px solid var(--border);
|
|
3654
|
+
padding: 0 14px 10px;
|
|
3277
3655
|
}
|
|
3278
3656
|
.file-preview-btn {
|
|
3279
3657
|
border: 1px solid var(--border);
|
|
3280
|
-
background: var(--
|
|
3658
|
+
background: var(--bg2);
|
|
3281
3659
|
color: var(--text);
|
|
3282
3660
|
border-radius: 8px;
|
|
3283
3661
|
padding: 6px 10px;
|
|
3284
3662
|
font-size: var(--fs-meta-md);
|
|
3285
3663
|
cursor: pointer;
|
|
3664
|
+
text-decoration: none;
|
|
3286
3665
|
}
|
|
3287
3666
|
.file-preview-btn.active {
|
|
3288
3667
|
border-color: var(--accent);
|
|
3289
3668
|
color: var(--accent);
|
|
3290
3669
|
}
|
|
3291
3670
|
.file-preview-btn[hidden] { display: none; }
|
|
3671
|
+
#file-preview-modal.media-mode .file-preview-btn,
|
|
3672
|
+
#file-preview-modal.media-mode .file-preview-close {
|
|
3673
|
+
background: rgba(255, 255, 255, 0.14);
|
|
3674
|
+
border-color: rgba(255, 255, 255, 0.22);
|
|
3675
|
+
color: #fff;
|
|
3676
|
+
}
|
|
3677
|
+
#file-preview-modal.media-mode .file-preview-btn.active {
|
|
3678
|
+
border-color: var(--accent);
|
|
3679
|
+
color: #fff;
|
|
3680
|
+
background: color-mix(in srgb, var(--accent) 45%, transparent);
|
|
3681
|
+
}
|
|
3682
|
+
#file-preview-modal.media-mode .file-preview-meta { color: rgba(255, 255, 255, 0.72); }
|
|
3292
3683
|
.file-preview-warning {
|
|
3293
3684
|
display: none;
|
|
3294
3685
|
margin-left: auto;
|
|
@@ -3297,16 +3688,30 @@
|
|
|
3297
3688
|
}
|
|
3298
3689
|
.file-preview-warning.visible { display: inline; }
|
|
3299
3690
|
.file-preview-meta {
|
|
3300
|
-
padding:
|
|
3691
|
+
padding: 0 14px 8px;
|
|
3301
3692
|
font-size: var(--fs-meta-sm);
|
|
3302
3693
|
color: var(--muted);
|
|
3303
|
-
border-bottom: 1px dashed var(--border);
|
|
3304
3694
|
}
|
|
3695
|
+
.file-preview-meta:empty { display: none; }
|
|
3696
|
+
/* Text starts below the chrome so the first line is readable with the
|
|
3697
|
+
controls up; the chrome's height is measured into the variable. */
|
|
3305
3698
|
.file-preview-body {
|
|
3306
|
-
|
|
3307
|
-
min-height: 0; /* prevents flex child from overflowing the dialog's max-height */
|
|
3699
|
+
position: absolute; inset: 0;
|
|
3308
3700
|
overflow: auto;
|
|
3309
|
-
|
|
3701
|
+
-webkit-overflow-scrolling: touch;
|
|
3702
|
+
padding: calc(var(--file-viewer-chrome-top) + 12px) 14px calc(28px + env(safe-area-inset-bottom));
|
|
3703
|
+
/* Up and down scroll the text; sideways is left to the viewer (a swipe
|
|
3704
|
+
to the next file). A block that scrolls sideways itself keeps that. */
|
|
3705
|
+
touch-action: pan-y pinch-zoom;
|
|
3706
|
+
}
|
|
3707
|
+
.file-preview-markdown pre,
|
|
3708
|
+
.file-preview-code pre,
|
|
3709
|
+
.file-preview-markdown table { touch-action: pan-x pan-y; }
|
|
3710
|
+
.file-preview-nav:disabled { opacity: 0.35; cursor: default; }
|
|
3711
|
+
.file-preview-markdown,
|
|
3712
|
+
.file-preview-body > .file-preview-code {
|
|
3713
|
+
max-width: 56rem;
|
|
3714
|
+
margin: 0 auto;
|
|
3310
3715
|
}
|
|
3311
3716
|
.file-preview-markdown {
|
|
3312
3717
|
line-height: 1.5;
|
|
@@ -3369,42 +3774,71 @@
|
|
|
3369
3774
|
user-select: none;
|
|
3370
3775
|
-webkit-user-drag: none;
|
|
3371
3776
|
}
|
|
3372
|
-
.file-preview-video-shell
|
|
3777
|
+
.file-preview-video-shell,
|
|
3778
|
+
.file-preview-audio-shell {
|
|
3373
3779
|
display: flex;
|
|
3374
3780
|
flex-direction: column;
|
|
3781
|
+
align-items: center;
|
|
3782
|
+
justify-content: center;
|
|
3375
3783
|
gap: 10px;
|
|
3376
3784
|
width: 100%;
|
|
3377
3785
|
height: 100%;
|
|
3378
3786
|
}
|
|
3379
3787
|
.file-preview-video {
|
|
3380
|
-
width: 100%;
|
|
3381
3788
|
max-width: 100%;
|
|
3382
|
-
max-height:
|
|
3789
|
+
max-height: 100%;
|
|
3790
|
+
width: auto;
|
|
3791
|
+
height: auto;
|
|
3383
3792
|
background: #000;
|
|
3384
|
-
border-radius: 10px;
|
|
3385
3793
|
}
|
|
3386
|
-
/*
|
|
3794
|
+
/* The player takes the card's width; a percentage on the player alone
|
|
3795
|
+
would resolve against a content-sized flex row and come out as zero. */
|
|
3796
|
+
.file-preview-audio-shell .file-preview-card { width: min(560px, calc(100% - 28px)); }
|
|
3797
|
+
.file-preview-audio-shell .file-preview-card-actions { width: 100%; }
|
|
3798
|
+
.file-preview-audio-shell audio { width: 100%; }
|
|
3799
|
+
/* Media and cards: no scrolling, the content is centred on the whole screen. */
|
|
3387
3800
|
.file-preview-body.image-zoom-mode,
|
|
3388
|
-
.file-preview-body.video-preview-mode
|
|
3389
|
-
|
|
3390
|
-
|
|
3801
|
+
.file-preview-body.video-preview-mode,
|
|
3802
|
+
.file-preview-body.audio-preview-mode,
|
|
3803
|
+
.file-preview-body.card-preview-mode {
|
|
3391
3804
|
overflow: hidden;
|
|
3392
3805
|
padding: 0;
|
|
3393
3806
|
display: flex;
|
|
3394
3807
|
flex-direction: column;
|
|
3395
|
-
|
|
3808
|
+
touch-action: none;
|
|
3396
3809
|
}
|
|
3397
3810
|
.file-preview-body.image-zoom-mode .file-preview-image {
|
|
3398
3811
|
flex: 1;
|
|
3399
|
-
min-height: 0; /*
|
|
3400
|
-
|
|
3812
|
+
min-height: 0; /* lets the img's max-height:100% resolve */
|
|
3813
|
+
}
|
|
3814
|
+
.file-preview-body.image-zoom-mode .file-preview-image img { border-radius: 0; }
|
|
3815
|
+
/* A file with nothing to show inline (a PDF, an unknown binary) or an audio
|
|
3816
|
+
file: a card in the middle with the name, the size and what can be done. */
|
|
3817
|
+
.file-preview-card {
|
|
3818
|
+
margin: auto;
|
|
3819
|
+
max-width: min(420px, calc(100% - 28px));
|
|
3820
|
+
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
|
3821
|
+
text-align: center;
|
|
3822
|
+
padding: 24px;
|
|
3823
|
+
border: 1px solid var(--border);
|
|
3824
|
+
border-radius: 16px;
|
|
3825
|
+
background: var(--bg3);
|
|
3401
3826
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3827
|
+
#file-preview-modal.media-mode .file-preview-card {
|
|
3828
|
+
background: rgba(255, 255, 255, 0.08);
|
|
3829
|
+
border-color: rgba(255, 255, 255, 0.16);
|
|
3830
|
+
color: #fff;
|
|
3831
|
+
}
|
|
3832
|
+
.file-preview-card-icon { font-size: 3rem; line-height: 1; }
|
|
3833
|
+
.file-preview-card-name {
|
|
3834
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
3835
|
+
font-size: var(--fs-meta-md);
|
|
3836
|
+
word-break: break-all;
|
|
3407
3837
|
}
|
|
3838
|
+
.file-preview-card-meta { font-size: var(--fs-meta-sm); color: var(--muted); }
|
|
3839
|
+
#file-preview-modal.media-mode .file-preview-card-meta { color: rgba(255, 255, 255, 0.72); }
|
|
3840
|
+
.file-preview-card-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 8px; }
|
|
3841
|
+
.file-preview-card-actions .file-preview-btn { padding: 10px 16px; }
|
|
3408
3842
|
.msg-attachment-video-chip {
|
|
3409
3843
|
display: inline-flex;
|
|
3410
3844
|
align-items: center;
|
|
@@ -3421,6 +3855,11 @@
|
|
|
3421
3855
|
color: var(--muted);
|
|
3422
3856
|
margin-top: 10px;
|
|
3423
3857
|
}
|
|
3858
|
+
.file-preview-body.image-zoom-mode .file-preview-note,
|
|
3859
|
+
.file-preview-body.video-preview-mode .file-preview-note {
|
|
3860
|
+
margin: auto;
|
|
3861
|
+
padding: 14px;
|
|
3862
|
+
}
|
|
3424
3863
|
|
|
3425
3864
|
/* Annotation editor. Clones the file-preview shell, but sits above it
|
|
3426
3865
|
(z-index 11500) so annotating a sent image can layer over the lightbox. */
|
|
@@ -3916,6 +4355,28 @@
|
|
|
3916
4355
|
border-color: var(--accent);
|
|
3917
4356
|
color: var(--accent);
|
|
3918
4357
|
}
|
|
4358
|
+
/* The one main action of a dialog, in #new-conv-btn's colours. */
|
|
4359
|
+
.summary-btn.summary-btn-accent {
|
|
4360
|
+
background: var(--accent);
|
|
4361
|
+
color: #000;
|
|
4362
|
+
border-color: var(--accent);
|
|
4363
|
+
font-weight: 600;
|
|
4364
|
+
}
|
|
4365
|
+
.summary-btn.summary-btn-accent:hover { opacity: 0.85; }
|
|
4366
|
+
#new-conversation-open-settings[hidden] { display: none; }
|
|
4367
|
+
/* New Chat with no provider ready: the note above the buttons. */
|
|
4368
|
+
.new-conversation-setup-note {
|
|
4369
|
+
margin-top: 14px;
|
|
4370
|
+
padding: 10px 12px;
|
|
4371
|
+
border: 1px solid var(--border);
|
|
4372
|
+
border-left: 3px solid var(--accent);
|
|
4373
|
+
border-radius: 8px;
|
|
4374
|
+
background: var(--bg3);
|
|
4375
|
+
color: var(--text);
|
|
4376
|
+
font-size: var(--fs-meta-md);
|
|
4377
|
+
line-height: 1.5;
|
|
4378
|
+
}
|
|
4379
|
+
.new-conversation-setup-note[hidden] { display: none; }
|
|
3919
4380
|
.summary-close {
|
|
3920
4381
|
width: 32px;
|
|
3921
4382
|
padding: 0;
|
|
@@ -4224,6 +4685,84 @@
|
|
|
4224
4685
|
font-size: var(--fs-meta-sm);
|
|
4225
4686
|
padding: 8px 6px;
|
|
4226
4687
|
}
|
|
4688
|
+
/* Pinned messages list (the summary modal, kind 'pinned-messages'). */
|
|
4689
|
+
.pinned-list {
|
|
4690
|
+
display: flex;
|
|
4691
|
+
flex-direction: column;
|
|
4692
|
+
gap: 8px;
|
|
4693
|
+
}
|
|
4694
|
+
.pinned-row {
|
|
4695
|
+
display: flex;
|
|
4696
|
+
align-items: stretch;
|
|
4697
|
+
border: 1px solid var(--border);
|
|
4698
|
+
background: var(--bg3);
|
|
4699
|
+
border-radius: 10px;
|
|
4700
|
+
overflow: hidden;
|
|
4701
|
+
}
|
|
4702
|
+
.pinned-row:hover,
|
|
4703
|
+
.pinned-row:focus-within {
|
|
4704
|
+
border-color: var(--accent);
|
|
4705
|
+
}
|
|
4706
|
+
.pinned-row-jump {
|
|
4707
|
+
appearance: none;
|
|
4708
|
+
border: 0;
|
|
4709
|
+
background: transparent;
|
|
4710
|
+
color: var(--text);
|
|
4711
|
+
font: inherit;
|
|
4712
|
+
text-align: left;
|
|
4713
|
+
cursor: pointer;
|
|
4714
|
+
flex: 1;
|
|
4715
|
+
min-width: 0;
|
|
4716
|
+
padding: 10px 12px;
|
|
4717
|
+
display: flex;
|
|
4718
|
+
flex-direction: column;
|
|
4719
|
+
gap: 4px;
|
|
4720
|
+
}
|
|
4721
|
+
.pinned-row-meta {
|
|
4722
|
+
font-size: var(--fs-meta-xs);
|
|
4723
|
+
color: var(--muted);
|
|
4724
|
+
}
|
|
4725
|
+
.pinned-row-chip {
|
|
4726
|
+
border: 1px solid var(--border);
|
|
4727
|
+
border-radius: 999px;
|
|
4728
|
+
padding: 0 6px;
|
|
4729
|
+
white-space: nowrap;
|
|
4730
|
+
}
|
|
4731
|
+
.pinned-row-preview {
|
|
4732
|
+
font-size: var(--fs-meta-sm);
|
|
4733
|
+
line-height: 1.4;
|
|
4734
|
+
display: -webkit-box;
|
|
4735
|
+
-webkit-line-clamp: 2;
|
|
4736
|
+
-webkit-box-orient: vertical;
|
|
4737
|
+
overflow: hidden;
|
|
4738
|
+
overflow-wrap: anywhere;
|
|
4739
|
+
}
|
|
4740
|
+
.pinned-row-no-text {
|
|
4741
|
+
color: var(--muted);
|
|
4742
|
+
font-style: italic;
|
|
4743
|
+
}
|
|
4744
|
+
/* 44px: a thumb-sized target, always in view (no hover on a phone). */
|
|
4745
|
+
.pinned-row-unpin {
|
|
4746
|
+
appearance: none;
|
|
4747
|
+
border: 0;
|
|
4748
|
+
border-left: 1px solid var(--border);
|
|
4749
|
+
background: transparent;
|
|
4750
|
+
color: var(--muted);
|
|
4751
|
+
cursor: pointer;
|
|
4752
|
+
flex: 0 0 44px;
|
|
4753
|
+
min-height: 44px;
|
|
4754
|
+
font-size: var(--fs-ui-icon);
|
|
4755
|
+
line-height: 1;
|
|
4756
|
+
}
|
|
4757
|
+
.pinned-row-unpin:hover {
|
|
4758
|
+
color: var(--danger);
|
|
4759
|
+
background: rgba(248, 81, 73, 0.08);
|
|
4760
|
+
}
|
|
4761
|
+
.pinned-empty {
|
|
4762
|
+
color: var(--muted);
|
|
4763
|
+
font-size: var(--fs-meta-sm);
|
|
4764
|
+
padding: 8px 6px;
|
|
4765
|
+
}
|
|
4227
4766
|
|
|
4228
4767
|
#git-changes-modal,
|
|
4229
4768
|
#git-diff-modal {
|
|
@@ -4819,6 +5358,43 @@
|
|
|
4819
5358
|
font-size: var(--fs-meta-md);
|
|
4820
5359
|
padding: 10px 6px;
|
|
4821
5360
|
}
|
|
5361
|
+
/* Explorer edits: the New-folder row at the top of the folder pane and the in-place rename. */
|
|
5362
|
+
.repo-tree-summary, .repo-entry-row, .repo-card { -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
|
|
5363
|
+
.repo-inline-edit {
|
|
5364
|
+
display: grid;
|
|
5365
|
+
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
|
5366
|
+
align-items: center;
|
|
5367
|
+
gap: 8px;
|
|
5368
|
+
margin: 0 0 10px;
|
|
5369
|
+
padding: 8px 10px;
|
|
5370
|
+
border: 1px solid var(--accent);
|
|
5371
|
+
border-radius: 10px;
|
|
5372
|
+
background: rgba(88, 166, 255, 0.08);
|
|
5373
|
+
}
|
|
5374
|
+
.repo-inline-edit input,
|
|
5375
|
+
.repo-rename-input,
|
|
5376
|
+
.repo-delete-confirm-input {
|
|
5377
|
+
min-width: 0;
|
|
5378
|
+
width: 100%;
|
|
5379
|
+
border: 1px solid var(--border);
|
|
5380
|
+
border-radius: 8px;
|
|
5381
|
+
background: var(--bg);
|
|
5382
|
+
color: var(--text);
|
|
5383
|
+
padding: 6px 8px;
|
|
5384
|
+
font: inherit;
|
|
5385
|
+
font-size: var(--fs-meta-md);
|
|
5386
|
+
}
|
|
5387
|
+
.repo-inline-edit input:focus, .repo-rename-input:focus, .repo-delete-confirm-input:focus { outline: none; border-color: var(--accent); }
|
|
5388
|
+
.repo-inline-edit-error { grid-column: 1 / -1; color: var(--danger); font-size: var(--fs-meta-xs); min-height: 0; }
|
|
5389
|
+
.repo-inline-edit-error:empty { display: none; }
|
|
5390
|
+
.repo-rename-input { display: inline-block; width: auto; max-width: 100%; padding: 2px 6px; }
|
|
5391
|
+
.repo-tree-summary .repo-rename-input { width: calc(100% - 2.2em); }
|
|
5392
|
+
.repo-delete-confirm-label { display: block; margin: 10px 0 0; font-size: var(--fs-meta-md); color: var(--muted); }
|
|
5393
|
+
.repo-delete-confirm-input { margin-top: 6px; }
|
|
5394
|
+
@media (max-width: 720px) {
|
|
5395
|
+
.repo-inline-edit { grid-template-columns: auto minmax(0, 1fr); }
|
|
5396
|
+
.repo-inline-edit .repo-browser-btn { grid-column: span 1; }
|
|
5397
|
+
}
|
|
4822
5398
|
|
|
4823
5399
|
.msg-mode {
|
|
4824
5400
|
display: inline-block; font-size: var(--fs-ui-chip); background: var(--bg3);
|
|
@@ -5131,6 +5707,10 @@
|
|
|
5131
5707
|
pointer-events: auto;
|
|
5132
5708
|
}
|
|
5133
5709
|
#sidebar-resizer { display: none; }
|
|
5710
|
+
/* The "no conversation open" actions stack on the phone. */
|
|
5711
|
+
.empty-state { padding: 16px; }
|
|
5712
|
+
.empty-state-actions { flex-direction: column; align-items: stretch; width: min(100%, 320px); }
|
|
5713
|
+
.empty-state-btn { height: 40px; }
|
|
5134
5714
|
#fullscreen-btn { display: inline-flex; align-items: center; justify-content: center; }
|
|
5135
5715
|
#sidebar-overlay { display: block; opacity: 0; pointer-events: none; transition: opacity 0.25s; }
|
|
5136
5716
|
#sidebar-overlay.visible { opacity: 1; pointer-events: all; }
|
|
@@ -5304,12 +5884,14 @@
|
|
|
5304
5884
|
}
|
|
5305
5885
|
#pending-question-banner { font-size: var(--fs-ui-chip); padding: 3px 8px; }
|
|
5306
5886
|
.header-icon-btn { width: 30px; height: 30px; border-radius: 8px; font-size: var(--fs-ui-icon); }
|
|
5887
|
+
.header-icon-btn.has-count { min-width: 30px; padding: 0 6px; }
|
|
5307
5888
|
#chat-actions-menu { min-width: 200px; }
|
|
5308
5889
|
/* Slightly taller than desktop so the tap target barely changes; the row
|
|
5309
5890
|
pitch still drops from 36px to 32px thanks to the tighter menu gap. */
|
|
5310
5891
|
.chat-actions-menu-item,
|
|
5311
5892
|
.chat-actions-menu-meta { min-height: 30px; }
|
|
5312
5893
|
#input-area { padding: 2px 10px calc(6px + env(safe-area-inset-bottom, 0px)); }
|
|
5894
|
+
#jump-to-bottom-btn { width: 44px; height: 44px; right: calc(12px + env(safe-area-inset-right, 0px)); bottom: calc(100% + 10px); }
|
|
5313
5895
|
.input-row {
|
|
5314
5896
|
display: flex;
|
|
5315
5897
|
flex-wrap: wrap;
|
|
@@ -5541,6 +6123,15 @@
|
|
|
5541
6123
|
flex: 1 1 calc(50% - 4px);
|
|
5542
6124
|
min-height: 40px;
|
|
5543
6125
|
}
|
|
6126
|
+
/* The pin list has one action, Close: the full-width action row above
|
|
6127
|
+
would leave its title no room. Title left, close button right. */
|
|
6128
|
+
#summary-modal[data-kind="pinned-messages"] .summary-header-actions {
|
|
6129
|
+
width: auto;
|
|
6130
|
+
}
|
|
6131
|
+
#summary-modal[data-kind="pinned-messages"] .summary-header-actions .summary-close {
|
|
6132
|
+
flex: 0 0 auto;
|
|
6133
|
+
min-width: 40px;
|
|
6134
|
+
}
|
|
5544
6135
|
.model-variant-row {
|
|
5545
6136
|
min-height: 48px;
|
|
5546
6137
|
padding: 10px 4px;
|
|
@@ -5813,10 +6404,11 @@
|
|
|
5813
6404
|
</form>
|
|
5814
6405
|
</div>
|
|
5815
6406
|
<div id="chat-header-actions">
|
|
6407
|
+
<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>
|
|
5816
6408
|
<button id="message-search-btn" class="header-icon-btn" onclick="openMessageSearchModal()" title="Search messages" aria-label="Search messages">🔍</button>
|
|
5817
6409
|
<button id="context-btn" class="header-icon-btn" onclick="showContext()" title="Check current context" aria-label="Check current context">🧠</button>
|
|
5818
6410
|
<div id="chat-actions-menu-wrap">
|
|
5819
|
-
<button id="chat-actions-menu-btn" class="header-icon-btn" type="button" title="
|
|
6411
|
+
<button id="chat-actions-menu-btn" class="header-icon-btn" type="button" title="Menu" aria-label="Menu" aria-haspopup="menu" aria-expanded="false">⋯</button>
|
|
5820
6412
|
<div id="chat-actions-menu" role="menu" hidden>
|
|
5821
6413
|
<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>
|
|
5822
6414
|
<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>
|
|
@@ -5843,13 +6435,15 @@
|
|
|
5843
6435
|
<button id="pending-question-banner" onclick="openPendingQuestionFromBanner()" title="Open pending question"></button>
|
|
5844
6436
|
</div>
|
|
5845
6437
|
<div id="messages">
|
|
6438
|
+
<!-- Replaced on start by conversation-view.js (no-conversation-state.mjs),
|
|
6439
|
+
which knows whether a provider is ready and whether chats exist. -->
|
|
5846
6440
|
<div class="empty-state">
|
|
5847
6441
|
<div class="icon">💬</div>
|
|
5848
|
-
<h3>No conversation
|
|
5849
|
-
<p>Click <b>+ New Conversation</b> to start chatting with your Copilot CLI</p>
|
|
6442
|
+
<h3>No conversation open</h3>
|
|
5850
6443
|
</div>
|
|
5851
6444
|
</div>
|
|
5852
6445
|
<div id="input-area">
|
|
6446
|
+
<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>
|
|
5853
6447
|
<div id="offline-banner">⚠️ CLI is offline — messages will queue until it reconnects</div>
|
|
5854
6448
|
<div id="model-banner"></div>
|
|
5855
6449
|
<div id="usage-limit-banner" role="status" aria-live="polite" hidden></div>
|
|
@@ -5925,6 +6519,7 @@
|
|
|
5925
6519
|
<button id="repo-toggle-hidden-btn" class="repo-browser-btn" onclick="toggleRepoBrowserHidden()">Hidden: Off</button>
|
|
5926
6520
|
<button id="repo-toggle-heavy-btn" class="repo-browser-btn" onclick="toggleRepoBrowserHeavy()">Heavy: Off</button>
|
|
5927
6521
|
<button class="repo-browser-btn" onclick="refreshRepoBrowser()">Refresh</button>
|
|
6522
|
+
<button id="repo-new-folder-btn" class="repo-browser-btn" onclick="startRepoNewFolder()" title="Create a folder inside the open folder">📁+ New folder</button>
|
|
5928
6523
|
</div>
|
|
5929
6524
|
<div class="repo-browser-layout">
|
|
5930
6525
|
<section class="repo-pane">
|
|
@@ -6114,6 +6709,17 @@
|
|
|
6114
6709
|
>
|
|
6115
6710
|
</div>
|
|
6116
6711
|
<div class="settings-help" style="margin-top: 6px;">How long background tasks may keep a session alive after its turn ends: backgrounded commands, subagents and monitors on Claude; background agents and detached shells on Copilot's SDK engine. When the limit is reached the tasks are stopped. Set to 0 for no limit — tasks then run until they finish or you stop them from the composer panel.</div>
|
|
6712
|
+
<div class="settings-row" style="margin-top: 12px; margin-bottom: 0;">
|
|
6713
|
+
<label for="subagent-record-retention-select">Keep sub-agent tool output</label>
|
|
6714
|
+
<select id="subagent-record-retention-select" onchange="updateSubagentRecordRetentionSetting(this.value)" aria-label="Keep sub-agent tool output">
|
|
6715
|
+
<option value="7">7 days</option>
|
|
6716
|
+
<option value="14">14 days</option>
|
|
6717
|
+
<option value="30">30 days</option>
|
|
6718
|
+
<option value="90" selected>90 days</option>
|
|
6719
|
+
<option value="0">Always</option>
|
|
6720
|
+
</select>
|
|
6721
|
+
</div>
|
|
6722
|
+
<div class="settings-help" style="margin-top: 6px;">A sub-agent's record keeps every tool call's full input and the first 4 KB of each result. After this many days the relay removes them from finished agents, once a day; the thoughts, the reply, notes and the one-line summary of each call stay. Always keeps everything.</div>
|
|
6117
6723
|
<div id="windows-autostart-setting" hidden>
|
|
6118
6724
|
<div class="settings-row settings-row-column" style="margin-top: 12px; margin-bottom: 0;">
|
|
6119
6725
|
<label>Autostart (Windows)</label>
|
|
@@ -6973,8 +7579,13 @@
|
|
|
6973
7579
|
<select id="new-conversation-size-select"></select>
|
|
6974
7580
|
<div id="new-conversation-size-status" style="margin-top:8px;font-size:0.78rem;color:var(--muted);">Image size used for generated outputs in this chat.</div>
|
|
6975
7581
|
</div>
|
|
7582
|
+
<!-- No provider known to be ready (journal-view.js): the note says so and
|
|
7583
|
+
Settings is the main button; Start stays as "anyway", because the
|
|
7584
|
+
Copilot signal can be wrong. -->
|
|
7585
|
+
<div id="new-conversation-setup-note" class="new-conversation-setup-note" role="status" hidden></div>
|
|
6976
7586
|
<div class="summary-modal-actions">
|
|
6977
7587
|
<button type="button" class="summary-btn" onclick="closeNewConversationModelModal()">Cancel</button>
|
|
7588
|
+
<button id="new-conversation-open-settings" type="button" class="summary-btn summary-btn-accent" hidden>Open Settings → Providers</button>
|
|
6978
7589
|
<button id="new-conversation-model-confirm" type="button" class="summary-btn" onclick="confirmNewConversationModel()">Start chat</button>
|
|
6979
7590
|
</div>
|
|
6980
7591
|
</div>
|
|
@@ -7025,25 +7636,55 @@
|
|
|
7025
7636
|
</div>
|
|
7026
7637
|
</div>
|
|
7027
7638
|
|
|
7028
|
-
<!--
|
|
7639
|
+
<!-- Sub-agent viewer: one sub-agent's thoughts, tool calls with their results
|
|
7640
|
+
and reply, in order, live while it runs (subagent-viewer.mjs). -->
|
|
7641
|
+
<div id="subagent-viewer-modal" aria-hidden="true">
|
|
7642
|
+
<div class="subagent-viewer-dialog" role="dialog" aria-modal="true" aria-labelledby="subagent-viewer-title">
|
|
7643
|
+
<div class="subagent-viewer-header">
|
|
7644
|
+
<button id="subagent-viewer-parent" type="button" hidden></button>
|
|
7645
|
+
<div class="subagent-viewer-title-row">
|
|
7646
|
+
<span aria-hidden="true">🤖</span>
|
|
7647
|
+
<h2 id="subagent-viewer-title">Sub-agent</h2>
|
|
7648
|
+
<button id="subagent-viewer-stop" class="subagent-viewer-btn" type="button" hidden>Stop</button>
|
|
7649
|
+
<button class="subagent-viewer-btn subagent-viewer-close" type="button" aria-label="Close">×</button>
|
|
7650
|
+
</div>
|
|
7651
|
+
<div id="subagent-viewer-meta"></div>
|
|
7652
|
+
</div>
|
|
7653
|
+
<div id="subagent-viewer-body">
|
|
7654
|
+
<div id="subagent-viewer-timeline"></div>
|
|
7655
|
+
<div id="subagent-viewer-status"></div>
|
|
7656
|
+
</div>
|
|
7657
|
+
<button id="subagent-viewer-jump" type="button" hidden>New entries ↓</button>
|
|
7658
|
+
</div>
|
|
7659
|
+
</div>
|
|
7660
|
+
|
|
7661
|
+
<!-- Fullscreen file viewer. The content fills the screen; the chrome bars
|
|
7662
|
+
float over it and a tap on the content shows or hides them. -->
|
|
7029
7663
|
<div id="file-preview-modal" aria-hidden="true">
|
|
7030
7664
|
<div class="file-preview-dialog" role="dialog" aria-modal="true" aria-label="File preview">
|
|
7031
|
-
<div class="file-preview-
|
|
7032
|
-
|
|
7033
|
-
<
|
|
7665
|
+
<div id="file-preview-body" class="file-preview-body"></div>
|
|
7666
|
+
<div id="file-preview-chrome-top" class="file-preview-chrome file-preview-chrome-top">
|
|
7667
|
+
<div class="file-preview-header">
|
|
7668
|
+
<div id="file-preview-title" class="file-preview-title">File preview</div>
|
|
7669
|
+
<button class="file-preview-close" onclick="closeFilePreview()" aria-label="Close preview">×</button>
|
|
7670
|
+
</div>
|
|
7671
|
+
<div class="file-preview-toolbar">
|
|
7672
|
+
<button id="file-preview-back" class="file-preview-btn" type="button" onclick="goBackFilePreview()" hidden disabled>← Back</button>
|
|
7673
|
+
<button id="file-preview-mode-preview" class="file-preview-btn active" onclick="setFilePreviewMode('preview')">Preview</button>
|
|
7674
|
+
<button id="file-preview-mode-raw" class="file-preview-btn" onclick="setFilePreviewMode('raw')">Raw</button>
|
|
7675
|
+
<button id="file-preview-html-toggle" class="file-preview-btn" onclick="toggleFilePreviewHtml()">Show literal HTML</button>
|
|
7676
|
+
<a id="file-preview-open-raw" class="file-preview-btn" download>Download</a>
|
|
7677
|
+
<button id="file-preview-copy-btn" class="file-preview-btn" type="button" onclick="copyFilePreviewImage()" hidden>Copy</button>
|
|
7678
|
+
<button id="file-preview-annotate-btn" class="file-preview-btn" type="button" onclick="openAnnotateEditorForPreview()" hidden>🖍️ Annotate</button>
|
|
7679
|
+
<span id="file-preview-warning" class="file-preview-warning">⚠ Safe layout HTML enabled; active content is blocked</span>
|
|
7680
|
+
</div>
|
|
7681
|
+
<div id="file-preview-meta" class="file-preview-meta"></div>
|
|
7034
7682
|
</div>
|
|
7035
|
-
<div class="file-preview-
|
|
7036
|
-
<button id="file-preview-
|
|
7037
|
-
<
|
|
7038
|
-
<button id="file-preview-
|
|
7039
|
-
<button id="file-preview-html-toggle" class="file-preview-btn" onclick="toggleFilePreviewHtml()">Show literal HTML</button>
|
|
7040
|
-
<a id="file-preview-open-raw" class="file-preview-btn" download>Download</a>
|
|
7041
|
-
<button id="file-preview-copy-btn" class="file-preview-btn" type="button" onclick="copyFilePreviewImage()" hidden>Copy</button>
|
|
7042
|
-
<button id="file-preview-annotate-btn" class="file-preview-btn" type="button" onclick="openAnnotateEditorForPreview()" hidden>🖍️ Annotate</button>
|
|
7043
|
-
<span id="file-preview-warning" class="file-preview-warning">⚠ Safe layout HTML enabled; active content is blocked</span>
|
|
7683
|
+
<div id="file-preview-chrome-bottom" class="file-preview-chrome file-preview-chrome-bottom" hidden>
|
|
7684
|
+
<button id="file-preview-prev" class="file-preview-btn file-preview-nav" type="button" aria-label="Previous file">‹</button>
|
|
7685
|
+
<span id="file-preview-position" class="file-preview-position"></span>
|
|
7686
|
+
<button id="file-preview-next" class="file-preview-btn file-preview-nav" type="button" aria-label="Next file">›</button>
|
|
7044
7687
|
</div>
|
|
7045
|
-
<div id="file-preview-meta" class="file-preview-meta"></div>
|
|
7046
|
-
<div id="file-preview-body" class="file-preview-body"></div>
|
|
7047
7688
|
</div>
|
|
7048
7689
|
</div>
|
|
7049
7690
|
|