@polderlabs/bizar-omp 0.6.5 → 0.6.7
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/README.md +3 -3
- package/dist/cli/agents-ink.d.ts +1 -1
- package/dist/cli/agents-ink.d.ts.map +1 -1
- package/dist/cli/agents-ink.js +8 -0
- package/dist/cli/agents-ink.js.map +1 -1
- package/dist/cli/agents.d.ts +1 -1
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/omb-commands.js +1 -1
- package/dist/cli/omb-commands.js.map +1 -1
- package/dist/cli/omb-update.d.ts +5 -0
- package/dist/cli/omb-update.d.ts.map +1 -1
- package/dist/cli/omb-update.js +14 -5
- package/dist/cli/omb-update.js.map +1 -1
- package/dist/cli/update-ink.d.ts +50 -0
- package/dist/cli/update-ink.d.ts.map +1 -0
- package/dist/cli/update-ink.js +185 -0
- package/dist/cli/update-ink.js.map +1 -0
- package/dist/omp/daemon-service.d.ts.map +1 -1
- package/dist/omp/daemon-service.js +453 -2
- package/dist/omp/daemon-service.js.map +1 -1
- package/dist/omp/daemon.d.ts +1 -1
- package/dist/omp/daemon.js +1 -1
- package/dist/omp/dashboard-html.d.ts.map +1 -1
- package/dist/omp/dashboard-html.js +292 -48
- package/dist/omp/dashboard-html.js.map +1 -1
- package/dist/omp/omb-sessions.d.ts +25 -0
- package/dist/omp/omb-sessions.d.ts.map +1 -1
- package/dist/omp/omb-sessions.js +100 -1
- package/dist/omp/omb-sessions.js.map +1 -1
- package/dist/omp/omb-settings.d.ts +13 -0
- package/dist/omp/omb-settings.d.ts.map +1 -1
- package/dist/omp/omb-settings.js +46 -2
- package/dist/omp/omb-settings.js.map +1 -1
- package/dist/omp/omp-provider-config.d.ts +26 -0
- package/dist/omp/omp-provider-config.d.ts.map +1 -0
- package/dist/omp/omp-provider-config.js +160 -0
- package/dist/omp/omp-provider-config.js.map +1 -0
- package/docs/compatibility/baseline.json +1 -1
- package/docs/releases/0.6.6.md +27 -0
- package/docs/releases/0.6.7.md +29 -0
- package/docs/releases/native-stable.md +1 -1
- package/package.json +4 -2
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const GSAP_SOURCE = readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8")
|
|
5
|
+
.replace(/<\/script/gi, "<\\/script");
|
|
1
6
|
/** Self-contained, authenticated browser dashboard. */
|
|
2
7
|
export const DASHBOARD_PATH = "/dash";
|
|
3
8
|
export function dashboardPageHtml() {
|
|
@@ -135,6 +140,7 @@ export function dashboardPageHtml() {
|
|
|
135
140
|
.card {
|
|
136
141
|
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
137
142
|
padding: 12px 16px; box-shadow: var(--shadow);
|
|
143
|
+
min-width: 0;
|
|
138
144
|
}
|
|
139
145
|
.card.invert { background: var(--panel-invert); border-color: var(--panel-invert); color: var(--text-invert); }
|
|
140
146
|
.card.invert .label { color: color-mix(in srgb, var(--text-invert) 62%, transparent); }
|
|
@@ -191,6 +197,21 @@ export function dashboardPageHtml() {
|
|
|
191
197
|
padding: 16px 24px; border-bottom: 1px solid var(--line);
|
|
192
198
|
}
|
|
193
199
|
.conversation-identity { min-width: 0; }
|
|
200
|
+
.rpc-pill {
|
|
201
|
+
display: inline-flex;
|
|
202
|
+
align-items: center;
|
|
203
|
+
gap: 6px;
|
|
204
|
+
padding: 4px 10px;
|
|
205
|
+
border-radius: 999px;
|
|
206
|
+
border: 1px solid var(--border);
|
|
207
|
+
font-size: 12px;
|
|
208
|
+
white-space: nowrap;
|
|
209
|
+
}
|
|
210
|
+
.rpc-pill[data-state="live"] { border-color: var(--success, #3fb950); color: var(--success, #3fb950); }
|
|
211
|
+
.rpc-pill[data-state="connecting"] { border-color: var(--warning, #d29922); color: var(--warning, #d29922); }
|
|
212
|
+
.rpc-pill[data-state="polling"] { border-color: var(--warning, #d29922); color: var(--muted); }
|
|
213
|
+
.rpc-pill[data-state="idle"] { color: var(--muted); }
|
|
214
|
+
.rpc-pill[data-state="offline"] { border-color: var(--danger, #f85149); color: var(--danger, #f85149); }
|
|
194
215
|
.state-label {
|
|
195
216
|
display: inline-flex; align-items: center; gap: 8px;
|
|
196
217
|
font-size: 10px; letter-spacing: var(--track); text-transform: uppercase; color: var(--muted);
|
|
@@ -200,35 +221,105 @@ export function dashboardPageHtml() {
|
|
|
200
221
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
201
222
|
}
|
|
202
223
|
.conversation-actions { display: flex; gap: 8px; flex: none; }
|
|
203
|
-
.
|
|
204
|
-
.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
224
|
+
.chat-stage { position: relative; flex: 1; min-height: 0; overflow: hidden; }
|
|
225
|
+
.message-scroll {
|
|
226
|
+
height: 100%; overflow-y: auto; overscroll-behavior: contain;
|
|
227
|
+
padding: 34px clamp(20px, 5vw, 72px) 210px; scroll-padding-bottom: 210px;
|
|
228
|
+
}
|
|
229
|
+
.message-stream { width: min(880px, 100%); margin: 0 auto; display: flex; flex-direction: column; gap: 28px; }
|
|
230
|
+
.message-state {
|
|
231
|
+
margin: auto; width: min(480px, 100%); padding: 34px 28px; text-align: center;
|
|
232
|
+
color: var(--muted); border: 1px dashed var(--line); border-radius: var(--radius);
|
|
233
|
+
}
|
|
234
|
+
.message-state strong { display: block; margin-bottom: 8px; color: var(--text); font-size: 13px; }
|
|
235
|
+
.message { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 12px; align-items: start; max-width: 88%; }
|
|
236
|
+
.message.user { grid-template-columns: minmax(0, 1fr) 34px; align-self: flex-end; max-width: 76%; }
|
|
237
|
+
.message.user .message-avatar { grid-column: 2; }
|
|
238
|
+
.message.user .message-content { grid-column: 1; grid-row: 1; }
|
|
239
|
+
.message-avatar {
|
|
240
|
+
width: 32px; height: 32px; display: grid; place-items: center; border: 1px solid var(--line);
|
|
241
|
+
border-radius: 10px; background: var(--panel); color: var(--muted); font-size: 9px; letter-spacing: 0.08em;
|
|
242
|
+
}
|
|
243
|
+
.message.assistant .message-avatar { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 48%, var(--line)); }
|
|
244
|
+
.message-content { min-width: 0; }
|
|
245
|
+
.message-meta { display: flex; align-items: center; gap: 10px; margin: 0 2px 7px; color: var(--muted); font-size: 10px; }
|
|
246
|
+
.message.user .message-meta { justify-content: flex-end; }
|
|
247
|
+
.message-bubble {
|
|
248
|
+
color: var(--text); font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
249
|
+
font-size: 14px; line-height: 1.66; overflow-wrap: anywhere;
|
|
250
|
+
}
|
|
251
|
+
.message.user .message-bubble {
|
|
252
|
+
padding: 13px 16px; border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line));
|
|
253
|
+
border-radius: 18px 18px 5px 18px; background: color-mix(in srgb, var(--accent) 11%, var(--panel));
|
|
254
|
+
}
|
|
255
|
+
.message-status { align-self:center; display:flex; align-items:center; gap:9px; max-width:min(620px,92%); padding:8px 12px; border:1px solid var(--line); border-radius:999px; background:color-mix(in srgb,var(--panel) 92%,transparent); color:var(--muted); font:11px/1.35 var(--mono); }
|
|
256
|
+
.message-status .status-icon { width:8px; height:8px; flex:none; border-radius:50%; background:var(--ok); }
|
|
257
|
+
.message-status[data-state="running"] .status-icon,.message-status[data-state="thinking"] .status-icon { background:var(--accent); box-shadow:0 0 10px color-mix(in srgb,var(--accent) 70%,transparent); animation:status-pulse 1.2s ease-in-out infinite; }
|
|
258
|
+
.message-status[data-state="failed"] { border-color:color-mix(in srgb,var(--err) 60%,var(--line)); color:var(--err); }
|
|
259
|
+
.message-status[data-state="failed"] .status-icon { background:var(--err); }
|
|
260
|
+
.message-status time { margin-left:auto; font-size:9px; opacity:.72; }
|
|
261
|
+
@keyframes status-pulse { 0%,100% { transform:scale(.75); opacity:.5; } 50% { transform:scale(1.15); opacity:1; } }
|
|
262
|
+
.message-bubble p { margin: 0 0 12px; }
|
|
263
|
+
.message-bubble p:last-child { margin-bottom: 0; }
|
|
264
|
+
.message-bubble h1, .message-bubble h2, .message-bubble h3 { margin: 18px 0 8px; font: inherit; font-weight: 750; }
|
|
265
|
+
.message-bubble h1:first-child, .message-bubble h2:first-child, .message-bubble h3:first-child { margin-top: 0; }
|
|
266
|
+
.message-bubble ul, .message-bubble ol { margin: 10px 0; padding-left: 22px; }
|
|
267
|
+
.message-bubble li + li { margin-top: 5px; }
|
|
268
|
+
.message-bubble code { padding: 2px 5px; border-radius: 5px; background: var(--panel-2); font: 0.88em/1.5 var(--mono); }
|
|
269
|
+
.message-bubble pre { margin: 0; padding: 16px; overflow-x: auto; background: #090a0d; color: #e7e9ee; }
|
|
270
|
+
.message-bubble pre code { padding: 0; background: transparent; font-size: 12px; }
|
|
271
|
+
.message-bubble blockquote { margin: 12px 0; padding-left: 14px; border-left: 2px solid var(--accent); color: var(--muted); }
|
|
272
|
+
.message-bubble hr { border:0; border-top:1px solid var(--line); margin:18px 0; }
|
|
273
|
+
.message-bubble a { text-decoration-thickness:1px; text-underline-offset:3px; }
|
|
274
|
+
.md-table-wrap { width:100%; margin:14px 0; overflow-x:auto; border:1px solid var(--line); border-radius:10px; }
|
|
275
|
+
.message-bubble table { width:100%; border-collapse:collapse; min-width:420px; font:12px/1.5 var(--mono); }
|
|
276
|
+
.message-bubble th,.message-bubble td { padding:9px 11px; border-right:1px solid var(--line); border-bottom:1px solid var(--line); text-align:left; vertical-align:top; }
|
|
277
|
+
.message-bubble th { background:var(--panel-2); color:var(--text); font-weight:700; }
|
|
278
|
+
.message-bubble tr:last-child td { border-bottom:0; }
|
|
279
|
+
.message-bubble th:last-child,.message-bubble td:last-child { border-right:0; }
|
|
280
|
+
.code-block { margin:12px 0; overflow:hidden; border:1px solid var(--line); border-radius:12px; background:#090a0d; }
|
|
281
|
+
.code-head { display:flex; align-items:center; justify-content:space-between; padding:7px 10px; border-bottom:1px solid #232833; color:#9299a8; font:10px/1.3 var(--mono); text-transform:uppercase; letter-spacing:.1em; }
|
|
282
|
+
.copy-code { border:0; background:transparent; color:#c7ccd6; padding:4px 7px; font:10px/1 var(--mono); cursor:pointer; }
|
|
283
|
+
.activity-strip {
|
|
284
|
+
position: absolute; left: 50%; bottom: 152px; transform: translateX(-50%); z-index: 3;
|
|
285
|
+
width: min(620px, calc(100% - 40px)); display: flex; align-items: center; gap: 10px;
|
|
286
|
+
padding: 9px 13px; border: 1px solid var(--line); border-radius: 12px;
|
|
287
|
+
background: color-mix(in srgb, var(--panel) 94%, transparent); color: var(--muted);
|
|
288
|
+
font-size: 11px; box-shadow: var(--shadow-overlay); backdrop-filter: blur(12px);
|
|
289
|
+
}
|
|
290
|
+
.activity-mark { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); flex: none; }
|
|
291
|
+
.activity-strip[data-idle="true"] { box-shadow: none; background: var(--panel); }
|
|
292
|
+
.activity-strip[data-idle="true"] .activity-mark { background: var(--muted); }
|
|
214
293
|
.follow-button {
|
|
215
|
-
position: absolute; right:
|
|
294
|
+
position: absolute; right: 24px; bottom: 154px; z-index: 4; display: inline-flex; align-items: center;
|
|
216
295
|
border: 1px solid var(--accent); background: var(--panel); color: var(--accent);
|
|
217
296
|
border-radius: 999px; padding: 8px 13px; font-family: var(--mono); font-size: 10px;
|
|
218
297
|
letter-spacing: var(--track); text-transform: uppercase; cursor: pointer;
|
|
219
298
|
box-shadow: var(--shadow-overlay);
|
|
220
299
|
}
|
|
221
|
-
.composer {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
.composer-
|
|
229
|
-
.composer-
|
|
230
|
-
|
|
231
|
-
|
|
300
|
+
.composer {
|
|
301
|
+
position: absolute; left: 50%; bottom: 20px; z-index: 5; transform: translateX(-50%);
|
|
302
|
+
width: min(920px, calc(100% - 40px)); display: grid; gap: 6px; padding: 12px;
|
|
303
|
+
border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--line)); border-radius: 22px;
|
|
304
|
+
background: color-mix(in srgb, var(--panel) 96%, transparent); box-shadow: 0 18px 54px rgba(0,0,0,.32);
|
|
305
|
+
backdrop-filter: blur(14px);
|
|
306
|
+
}
|
|
307
|
+
.composer-box { display: flex; gap: 8px; align-items: flex-end; min-width: 0; max-width: 100%; }
|
|
308
|
+
.composer-box textarea {
|
|
309
|
+
flex: 1; min-height: 64px; max-height: 180px; padding: 10px 10px 14px; resize: none;
|
|
310
|
+
border: 0; border-radius: 14px; background: transparent; font-family: ui-sans-serif, system-ui, sans-serif;
|
|
311
|
+
font-size: 15px; line-height: 1.45;
|
|
312
|
+
}
|
|
313
|
+
.composer-box textarea:focus { outline: 0; }
|
|
314
|
+
.composer-send { width: 48px; height: 48px; padding: 0; border-radius: 14px; flex: none; font-size: 15px; letter-spacing: 0; }
|
|
315
|
+
.composer-meta { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:0 8px 2px; font-size:10px; color:var(--muted); min-width:0; }
|
|
316
|
+
.composer-tools { display:flex; align-items:center; gap:8px; min-width:0; }
|
|
317
|
+
.composer-tool { width:auto; min-width:0; max-width:210px; padding:7px 9px; border:0; background:transparent; color:var(--muted); font-size:11px; }
|
|
318
|
+
.composer-tool:hover { color:var(--text); background:var(--panel-2); }
|
|
319
|
+
.composer-plus { width:34px; height:34px; border-radius:50%; border:1px solid var(--line); background:transparent; color:var(--text); font-size:20px; line-height:1; }
|
|
320
|
+
.composer-menu { position:absolute; left:12px; bottom:54px; width:220px; padding:7px; border:1px solid var(--line); border-radius:12px; background:var(--panel); box-shadow:var(--shadow-overlay); }
|
|
321
|
+
.composer-menu button { width:100%; border:0; border-radius:8px; padding:10px; text-align:left; background:transparent; color:var(--text); }
|
|
322
|
+
.composer-menu button:hover { background:var(--panel-2); }
|
|
232
323
|
#inspector { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 24px 24px; }
|
|
233
324
|
.inspector-section { margin-bottom: 24px; }
|
|
234
325
|
.inspector-section h2 {
|
|
@@ -254,6 +345,23 @@ export function dashboardPageHtml() {
|
|
|
254
345
|
.dialog-head h2 { margin: 4px 0 0; font-size: 15px; font-weight: 650; }
|
|
255
346
|
.dialog-body { display: grid; gap: 16px; padding: 16px 24px; max-height: 68vh; overflow-y: auto; }
|
|
256
347
|
.dialog-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 8px 24px 16px; }
|
|
348
|
+
.settings-dialog { width:min(980px,94vw); height:min(760px,90vh); }
|
|
349
|
+
.settings-shell { display:grid; grid-template-columns:230px minmax(0,1fr); height:100%; min-height:0; }
|
|
350
|
+
.settings-rail { padding:16px 12px; border-right:1px solid var(--line); display:flex; flex-direction:column; gap:10px; overflow:auto; }
|
|
351
|
+
.settings-close { align-self:flex-start; }
|
|
352
|
+
.settings-tabs { display:grid; gap:4px; }
|
|
353
|
+
.settings-tab { min-height:40px; border:0; border-radius:9px; padding:9px 10px; text-align:left; background:transparent; color:var(--muted); }
|
|
354
|
+
.settings-tab:hover,.settings-tab.active { color:var(--text); background:var(--panel-2); }
|
|
355
|
+
.settings-main { min-width:0; min-height:0; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
|
|
356
|
+
.settings-main .dialog-head { padding:20px 24px 14px; border-bottom:1px solid var(--line); }
|
|
357
|
+
.settings-panel { display:none; }
|
|
358
|
+
.settings-panel.active { display:grid; gap:16px; }
|
|
359
|
+
.settings-section { display:grid; gap:12px; }
|
|
360
|
+
.settings-section-title { margin:0; padding-bottom:8px; border-bottom:1px solid var(--line); font-size:11px; }
|
|
361
|
+
.provider-grid { display:grid; grid-template-columns:minmax(0,1fr) minmax(300px,.9fr); gap:16px; }
|
|
362
|
+
.provider-card { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:12px; align-items:center; }
|
|
363
|
+
.provider-editor { display:grid; gap:12px; padding:16px; }
|
|
364
|
+
.inline-fields { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
|
|
257
365
|
.field { display: grid; gap: 8px; }
|
|
258
366
|
.field-label { font-size: 10px; letter-spacing: var(--track); text-transform: uppercase; color: var(--muted); }
|
|
259
367
|
.field-help, .runtime-note { margin: 0; font-size: 11px; color: var(--muted); }
|
|
@@ -298,12 +406,38 @@ export function dashboardPageHtml() {
|
|
|
298
406
|
letter-spacing: var(--track); text-transform: uppercase;
|
|
299
407
|
}
|
|
300
408
|
.mobile-nav button.active { color: var(--accent); }
|
|
409
|
+
.primary-nav { display:flex; gap:4px; margin-left:24px; }
|
|
410
|
+
.primary-nav button { min-height:36px; border:0; border-bottom:2px solid transparent; background:transparent; color:var(--muted); padding:8px 10px; font-size:11px; letter-spacing:var(--track); text-transform:uppercase; }
|
|
411
|
+
.primary-nav button.active { color:var(--text); border-color:var(--accent); }
|
|
412
|
+
.overview { overflow:auto; padding:24px 28px 48px; }
|
|
413
|
+
.overview-grid { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px; margin:18px 0 24px; }
|
|
414
|
+
.metric { min-height:112px; display:flex; flex-direction:column; justify-content:space-between; }
|
|
415
|
+
.metric-value { font-size:30px; line-height:1; font-weight:700; }
|
|
416
|
+
.overview-columns { display:grid; grid-template-columns:minmax(0,1.6fr) minmax(240px,1fr); gap:18px; }
|
|
417
|
+
.overview-stack { display:grid; gap:18px; min-width:0; }
|
|
418
|
+
.overview-actions { display:flex; gap:8px; flex-wrap:wrap; margin-top:16px; }
|
|
419
|
+
.workspace-summary { display:grid; gap:0; }
|
|
420
|
+
.overview-list { display:grid; gap:8px; }
|
|
421
|
+
.overview-row { display:flex; justify-content:space-between; gap:12px; padding:10px 0; border-bottom:1px solid var(--line); flex-wrap:wrap; }
|
|
422
|
+
.overview-row > * { min-width: 0; }
|
|
423
|
+
.provider-order-list { display:grid; gap:8px; }
|
|
424
|
+
.provider-order-row { display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:12px; padding:10px 12px; }
|
|
425
|
+
.provider-order-actions { display:flex; gap:6px; }
|
|
426
|
+
.provider-order-actions .btn { min-width:38px; padding:7px 9px; }
|
|
427
|
+
.utility-menu { position:absolute; right:28px; top:64px; width:min(320px,calc(100vw - 32px)); padding:8px; background:var(--panel); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow-overlay); z-index:10; }
|
|
428
|
+
.utility-menu button { display:block; width:100%; text-align:left; border:0; background:transparent; color:var(--text); padding:12px; border-radius:8px; }
|
|
429
|
+
.utility-menu button:hover { background:var(--panel-2); }
|
|
430
|
+
body[data-page="overview"] .panes { display:none; }
|
|
431
|
+
body[data-page="chat"] .overview { display:none; }
|
|
301
432
|
footer {
|
|
302
433
|
display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
|
|
303
434
|
padding: 10px 28px; border-top: 1px solid var(--line);
|
|
304
435
|
color: var(--muted); font-size: 10px; letter-spacing: var(--track); text-transform: uppercase;
|
|
305
436
|
}
|
|
306
437
|
@media (max-width: 1099px) {
|
|
438
|
+
.bar { flex-wrap: wrap; row-gap: 10px; padding: 14px 20px; }
|
|
439
|
+
.overview { padding: 20px 20px 40px; }
|
|
440
|
+
.overview-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
307
441
|
.panes { grid-template-columns: minmax(224px, 288px) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
|
|
308
442
|
.detail-pane {
|
|
309
443
|
grid-column: 1 / -1; border-left: 0; border-top: 1px solid var(--line);
|
|
@@ -311,6 +445,17 @@ export function dashboardPageHtml() {
|
|
|
311
445
|
}
|
|
312
446
|
}
|
|
313
447
|
@media (max-width: 759px) {
|
|
448
|
+
.primary-nav { order:3; width:100%; margin:0; justify-content:space-between; }
|
|
449
|
+
.primary-nav button { flex:1; min-height:44px; }
|
|
450
|
+
.overview { padding:16px 16px calc(90px + env(safe-area-inset-bottom,0px)); }
|
|
451
|
+
.overview-grid, .overview-columns { grid-template-columns:1fr; gap:10px; }
|
|
452
|
+
.settings-shell { grid-template-columns:1fr; grid-template-rows:auto minmax(0,1fr); }
|
|
453
|
+
.settings-rail { border-right:0; border-bottom:1px solid var(--line); padding:10px 12px; }
|
|
454
|
+
.settings-close { position:absolute; right:10px; top:10px; z-index:2; }
|
|
455
|
+
.settings-rail .field { padding-right:46px; }
|
|
456
|
+
.settings-tabs { display:flex; overflow-x:auto; }
|
|
457
|
+
.settings-tab { flex:none; min-height:44px; }
|
|
458
|
+
.provider-grid,.inline-fields { grid-template-columns:1fr; }
|
|
314
459
|
.panes { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
|
|
315
460
|
.pane { display: none; }
|
|
316
461
|
.pane + .pane { border-left: 0; }
|
|
@@ -322,8 +467,17 @@ export function dashboardPageHtml() {
|
|
|
322
467
|
.bar { flex-wrap: wrap; padding: 14px 16px; }
|
|
323
468
|
.bar-right { flex-wrap: wrap; justify-content: flex-end; }
|
|
324
469
|
.brand-sub { display: none; }
|
|
325
|
-
.conversation-head,
|
|
326
|
-
.
|
|
470
|
+
.conversation-head, #inspector { padding-left: 16px; padding-right: 16px; }
|
|
471
|
+
.conversation-actions #attach-top { display: none; }
|
|
472
|
+
.message-scroll { padding: 22px 14px 224px; scroll-padding-bottom: 224px; }
|
|
473
|
+
.message-stream { gap: 22px; }
|
|
474
|
+
.message, .message.user { max-width: 94%; }
|
|
475
|
+
.message { grid-template-columns: 30px minmax(0,1fr); gap: 9px; }
|
|
476
|
+
.message.user { grid-template-columns: minmax(0,1fr) 30px; }
|
|
477
|
+
.message-avatar { width: 30px; height: 30px; }
|
|
478
|
+
.activity-strip { bottom: 168px; width: calc(100% - 28px); }
|
|
479
|
+
.follow-button { right: 14px; bottom: 170px; }
|
|
480
|
+
.composer { bottom: calc(10px + env(safe-area-inset-bottom, 0px)); width: calc(100% - 20px); }
|
|
327
481
|
.composer-runtime { width: 100%; }
|
|
328
482
|
.composer-runtime .field { flex: 1; min-width: 116px; }
|
|
329
483
|
.composer-runtime select { width: 100%; min-width: 0; }
|
|
@@ -341,12 +495,13 @@ export function dashboardPageHtml() {
|
|
|
341
495
|
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; } }
|
|
342
496
|
</style>
|
|
343
497
|
</head>
|
|
344
|
-
<body data-mobile-view="sessions">
|
|
498
|
+
<body data-mobile-view="sessions" data-page="overview">
|
|
345
499
|
<div class="app">
|
|
346
|
-
<header class="bar"><div class="brand"><span class="brand-dot" aria-hidden="true"></span><span class="brand-name">Bizar OMP</span><span class="brand-sub">OMB DASHBOARD</span></div><div class="bar-right"><span class="chip" id="daemon-state"><span class="state-dot"></span><span>Connecting to local daemon</span></span><button class="btn ghost" id="theme-toggle" type="button">Light theme</button><button class="btn ghost" id="
|
|
500
|
+
<header class="bar"><div class="brand"><span class="brand-dot" aria-hidden="true"></span><span class="brand-name">Bizar OMP</span><span class="brand-sub">OMB DASHBOARD</span></div><nav class="primary-nav" aria-label="Dashboard navigation"><button data-page="overview" class="active" type="button">Overview</button><button data-page="chat" type="button">Chat</button></nav><div class="bar-right"><span class="chip" id="daemon-state"><span class="state-dot"></span><span>Connecting to local daemon</span></span><button class="btn ghost" id="theme-toggle" type="button">Light theme</button><button class="btn ghost" id="utility-open" type="button" aria-expanded="false" aria-controls="utility-menu">Menu</button><button class="btn primary" id="new-session-top" type="button">New session</button></div><div class="utility-menu hidden" id="utility-menu" role="menu"><button type="button" role="menuitem" data-page="overview">Overview</button><button type="button" role="menuitem" data-page="chat">Conversation</button><button type="button" role="menuitem" id="settings-open">Settings</button><button type="button" role="menuitem" id="utility-refresh">Refresh status</button></div></header>
|
|
501
|
+
<section class="overview" aria-label="Overview"><div class="label">Operator overview</div><h1 style="margin:6px 0 0">Local runtime</h1><p id="overview-status" class="field-help" role="status">Loading the daemon snapshot.</p><div class="overview-actions"><button class="btn primary" type="button" data-overview-action="new">New session</button><button class="btn" type="button" data-overview-action="chat">Open chat</button><button class="btn" type="button" data-overview-action="settings">Settings</button><button class="btn ghost" type="button" data-overview-action="refresh">Refresh</button></div><div class="overview-grid" id="overview-metrics"><div class="card metric">Loading overview.</div></div><div class="overview-columns"><div class="overview-stack"><section class="card"><div class="label">Current focus</div><div class="overview-list" id="focus-summary"><p class="field-help">Loading selected session.</p></div></section><section class="card"><div class="label">Workspace activity</div><div class="workspace-summary" id="workspace-summary"><p class="field-help">Loading workspaces.</p></div></section><section class="card"><div class="label">Recent sessions</div><div class="overview-list" id="recent-sessions"><p class="field-help">Loading sessions.</p></div></section></div><div class="overview-stack"><section class="card"><div class="label">Needs attention</div><div class="overview-list" id="attention-list"><p class="field-help">Loading sessions.</p></div></section><section class="card"><div class="label">OMP runtime</div><div class="overview-list" id="omp-summary"><p class="field-help">Loading OMP status.</p></div></section></div></div></section>
|
|
347
502
|
<main class="panes">
|
|
348
503
|
<aside class="pane rail" aria-label="Sessions"><div class="pane-head"><span class="label">Workspace</span><span class="pane-title">Sessions <span class="count" id="session-count">0</span></span></div><div class="search-wrap"><input class="search" id="session-search" type="search" placeholder="Find a session" aria-label="Find a session" /></div><div class="filters" id="filters" aria-label="Filter sessions"></div><div class="session-list" id="session-list"><div class="empty"><strong>Loading sessions</strong>Reading the local daemon snapshot.</div></div></aside>
|
|
349
|
-
<section class="pane console-pane" aria-label="Session chat"><header class="conversation-head"><div class="conversation-identity"><div class="state-label" id="session-state"><span class="state-dot"></span><span>No session selected</span></div><
|
|
504
|
+
<section class="pane console-pane" aria-label="Session chat"><header class="conversation-head"><div class="conversation-identity"><div class="state-label" id="session-state"><span class="state-dot"></span><span>No session selected</span></div><h2 class="conversation-title" id="conversation-title">Choose a session</h2></div><div class="conversation-actions"><span class="rpc-pill" id="rpc-status" data-state="idle" role="status" aria-live="polite">Not connected</span><button class="btn ghost" id="console-refresh" type="button" disabled>Refresh messages</button><button class="btn" id="attach-top" type="button" disabled>Open terminal</button></div></header><div class="chat-stage"><div class="message-scroll" id="message-scroll" tabindex="0" aria-label="Conversation messages"><div class="message-stream" id="message-stream"><div class="message-state"><strong>No session open</strong>Select a session to read its conversation and send a message.</div></div></div><div class="activity-strip" id="agent-activity" data-idle="true" role="status" aria-live="polite"><span class="activity-mark" aria-hidden="true"></span><span id="activity-label">Waiting for a session</span></div><button class="follow-button hidden" id="console-follow" type="button">Jump to latest</button><form class="composer" id="composer"><div class="composer-box"><textarea id="composer-input" rows="2" placeholder="Work on anything" aria-label="Message" disabled></textarea><button class="btn primary composer-send" id="composer-send" type="submit" aria-label="Send message" disabled>↑</button></div><div class="composer-meta"><div class="composer-tools"><button class="composer-plus" id="composer-menu-open" type="button" aria-label="Composer actions" aria-expanded="false">+</button><select class="composer-tool" id="workspace-select" aria-label="Workspace filter"><option value="all">All workspaces</option></select><select class="composer-tool" id="composer-model" aria-label="Default model"><option value="">OMP default</option></select><select class="composer-tool" id="composer-thinking" aria-label="Default effort"><option value="">Effort</option></select></div><span id="composer-status" role="status">Select a live session to begin.</span></div><div class="composer-menu hidden" id="composer-menu"><button type="button" data-composer-action="new">New session</button><button type="button" data-composer-action="terminal">Open selected in terminal</button><button type="button" data-composer-action="settings">Open settings</button></div><select class="hidden" id="composer-permission" aria-label="Default permissions"><option value="">OMP default</option><option value="always-ask">Always ask</option><option value="write">Allow workspace writes</option><option value="yolo">Auto approve all</option></select></form></div></section>
|
|
350
505
|
<aside class="pane detail-pane" aria-label="Session details"><div class="pane-head"><span class="label">Selected session</span><span class="pane-title">Details</span></div><div id="inspector"><div class="empty"><strong>Nothing selected</strong>Session identity and controls appear here.</div></div></aside>
|
|
351
506
|
</main>
|
|
352
507
|
<nav class="mobile-nav" aria-label="Dashboard views"><button type="button" data-view="sessions" class="active">Sessions</button><button type="button" data-view="chat">Chat</button><button type="button" data-view="details">Details</button></nav>
|
|
@@ -355,12 +510,20 @@ export function dashboardPageHtml() {
|
|
|
355
510
|
<dialog id="create-dialog" aria-labelledby="create-title"><form method="dialog"><div class="dialog-head"><div><div class="label">Launch</div><h2 id="create-title">New session</h2></div><button class="btn icon ghost" value="cancel" aria-label="Close">×</button></div><div class="dialog-body"><label class="field"><span class="field-label">Project directory</span><input class="field-input" id="create-cwd" list="workspace-list" placeholder="/path/to/project" autocomplete="off" required /><span class="field-help">Must be an existing directory on this machine.</span></label><datalist id="workspace-list"></datalist><label class="field"><span class="field-label">First message</span><textarea class="field-textarea" id="create-task" placeholder="Describe the work for this session"></textarea></label><label class="field"><span class="field-label">Session label</span><input class="field-input" id="create-id" placeholder="Optional, for example review" autocomplete="off" /></label><section class="runtime-grid" aria-labelledby="runtime-title"><div class="runtime-heading"><div class="label">Session runtime</div><strong id="runtime-title">Model and permissions</strong></div><label class="field"><span class="field-label">Model</span><select class="field-select" id="create-model"><option value="">OMP default</option></select></label><label class="field"><span class="field-label">Thinking</span><select class="field-select" id="create-thinking"><option value="">OMP default</option><option>off</option><option>minimal</option><option>low</option><option>medium</option><option>high</option><option>xhigh</option><option>max</option><option>auto</option></select></label><label class="field"><span class="field-label">Permissions</span><select class="field-select" id="create-permission"><option value="">OMP default</option><option value="always-ask">Always ask</option><option value="write">Allow workspace writes</option><option value="yolo">Auto approve all</option></select></label><div class="runtime-note" id="model-status">Loading models from OMP.</div></section></div><div class="dialog-foot"><button class="btn" value="cancel">Cancel</button><button class="btn primary" value="create">Create session</button></div></form></dialog>
|
|
356
511
|
<dialog id="rename-dialog" aria-labelledby="rename-title"><form method="dialog"><div class="dialog-head"><div><div class="label">Identity</div><h2 id="rename-title">Rename session</h2></div><button class="btn icon ghost" value="cancel" aria-label="Close">×</button></div><div class="dialog-body"><label class="field"><span class="field-label">Session label</span><input class="field-input" id="rename-id" autocomplete="off" required /></label></div><div class="dialog-foot"><button class="btn" value="cancel">Cancel</button><button class="btn primary" value="rename">Rename</button></div></form></dialog>
|
|
357
512
|
<dialog id="stop-dialog" aria-labelledby="stop-title"><form method="dialog"><div class="dialog-head"><div><div class="label">Destructive action</div><h2 id="stop-title">Stop session</h2></div><button class="btn icon ghost" value="cancel" aria-label="Close">×</button></div><div class="dialog-body"><p id="stop-text" style="margin:0">This ends the tmux session and its agent work.</p></div><div class="dialog-foot"><button class="btn" value="cancel">Keep running</button><button class="btn danger" value="stop">Stop session</button></div></form></dialog>
|
|
358
|
-
<dialog id="settings-dialog" aria-labelledby="settings-title"><form method="dialog"
|
|
513
|
+
<dialog class="settings-dialog" id="settings-dialog" aria-labelledby="settings-title"><form method="dialog" class="settings-shell"><aside class="settings-rail"><button class="btn icon ghost settings-close" value="cancel" aria-label="Close settings">×</button><label class="field"><span class="field-label">Find settings</span><input id="settings-search" type="search" placeholder="Search settings" autocomplete="off" /></label><nav class="settings-tabs" aria-label="Settings sections"><button class="settings-tab active" type="button" data-settings-tab="general">General</button><button class="settings-tab" type="button" data-settings-tab="runtime">Runtime</button><button class="settings-tab" type="button" data-settings-tab="omp">OMP config</button><button class="settings-tab" type="button" data-settings-tab="providers">Providers</button><button class="settings-tab" type="button" data-settings-tab="security">Security</button></nav></aside><div class="settings-main"><div class="dialog-head"><div><div class="label">Configuration</div><h2 id="settings-title">Settings</h2></div></div><div class="dialog-body" id="settings-content">
|
|
514
|
+
<section class="settings-panel active" data-settings-panel="general"><div class="settings-section"><h3 class="settings-section-title">General</h3><label class="field"><span class="field-label">Projects folder</span><input class="field-input" id="setting-projects" placeholder="/path/to/projects" autocomplete="off" /><span class="field-help">Default workspace for new sessions.</span></label><label class="field"><span class="field-label">Appearance</span><select id="setting-theme"><option value="dark">Dark</option><option value="light">Light</option><option value="system">System</option></select></label><label class="card setting-row"><span><strong>Attach latest session</strong>Reconnect plain omb launches to the latest live session.</span><span class="switch"><input id="setting-attach" type="checkbox" /><span class="switch-track"></span></span></label><label class="card setting-row"><span><strong>Mouse forwarding</strong>Enable scrolling and pointer events in OMP tmux sessions.</span><span class="switch"><input id="setting-mouse" type="checkbox" /><span class="switch-track"></span></span></label><label class="card setting-row"><span><strong>Show stopped sessions</strong>Include recent stopped work in session lists.</span><span class="switch"><input id="setting-stopped" type="checkbox" /><span class="switch-track"></span></span></label><label class="card setting-row"><span><strong>System tray</strong>Keep native quick access available when supported.</span><span class="switch"><input id="setting-tray" type="checkbox" /><span class="switch-track"></span></span></label></div></section>
|
|
515
|
+
<section class="settings-panel" data-settings-panel="runtime"><div class="settings-section"><h3 class="settings-section-title">New session defaults</h3><label class="field"><span class="field-label">Model</span><select id="setting-model"><option value="">OMP default</option></select></label><label class="field"><span class="field-label">Thinking effort</span><select id="setting-thinking"><option value="">OMP default</option></select></label><label class="field"><span class="field-label">Permissions</span><select id="setting-permission"><option value="">OMP default</option><option value="always-ask">Always ask</option><option value="write">Allow workspace writes</option><option value="yolo">Auto approve all</option></select></label><p class="field-help">These defaults apply only to sessions created from the dashboard.</p></div></section>
|
|
516
|
+
<section class="settings-panel" data-settings-panel="omp"><div class="settings-section"><h3 class="settings-section-title">Native OMP configuration</h3><label class="field"><span class="field-label">Filter settings</span><input class="field-input" id="omp-config-filter" type="search" placeholder="Name, type, or description" autocomplete="off" /></label><p class="field-help" id="omp-config-status" role="status">Loading typed configuration.</p><div id="omp-config-list"></div></div></section>
|
|
517
|
+
<section class="settings-panel" data-settings-panel="providers"><div class="settings-section"><h3 class="settings-section-title">Providers</h3><p class="field-help" id="providers-status" role="status">Loading provider state.</p><div class="provider-grid"><div><div id="providers-list"></div><section class="field" aria-labelledby="provider-order-title"><span class="field-label" id="provider-order-title">Routing order</span><div class="provider-order-list" id="provider-order-list"></div><div class="provider-order-actions"><button class="btn" id="provider-order-save" type="button">Save order</button><button class="btn ghost" id="provider-order-reset" type="button">Use default</button></div></section></div><div class="card provider-editor" id="provider-editor"><div><div class="label">Custom provider</div><strong id="provider-editor-title">Add provider</strong></div><label class="field"><span class="field-label">Provider id</span><input id="provider-id" placeholder="company-openai" required pattern="[A-Za-z0-9._-]+" /></label><label class="field"><span class="field-label">API endpoint</span><input id="provider-url" type="url" placeholder="https://api.example.com/v1" required /></label><div class="inline-fields"><label class="field"><span class="field-label">API format</span><select id="provider-api"></select></label><label class="field"><span class="field-label">Authentication</span><select id="provider-auth"><option value="apiKey">API key</option><option value="none">None</option><option value="oauth">OAuth</option></select></label></div><label class="field"><span class="field-label">Model ids</span><textarea id="provider-models" placeholder="model-a model-b" required></textarea><span class="field-help">One model id per line.</span></label><label class="field"><span class="field-label">API key</span><input id="provider-key" type="password" autocomplete="new-password" placeholder="Leave blank to preserve stored key" /><span class="field-help" id="provider-key-state">Keys are write-only and never returned.</span></label><label class="setting-row"><span><strong>Clear stored API key</strong>Remove the existing key when saving.</span><span class="switch"><input id="provider-key-clear" type="checkbox" /><span class="switch-track"></span></span></label><div class="provider-order-actions"><button class="btn primary" id="provider-save" type="button">Save provider</button><button class="btn ghost" id="provider-editor-reset" type="button">New provider</button><button class="btn danger hidden" id="provider-delete" type="button">Delete</button></div></div></div></div></section>
|
|
518
|
+
<section class="settings-panel" data-settings-panel="security"><div class="settings-section"><h3 class="settings-section-title">Security and authentication</h3><div class="card"><strong>Local dashboard boundary</strong><p class="field-help">The server binds to loopback, exchanges a one-time access code for an in-memory token, and never returns provider keys or credential values.</p></div><p class="field-help" id="auth-status" role="status">Auth status is read from OMP. Credentials remain hidden.</p><div class="provider-order-actions"><button class="btn" type="button" data-auth-action="status">Refresh auth status</button><button class="btn" type="button" data-auth-action="list">List auth methods</button></div><p class="field-help">Interactive login, import, migration, and logout remain terminal-only so the dashboard cannot capture credential prompts.</p></div><div class="settings-section"><h3 class="settings-section-title">Collab and live URLs</h3><p class="field-help" id="collab-status" role="status">Loading active collab hosts.</p><div id="collab-list"></div><div class="provider-order-actions"><button class="btn" type="button" data-collab-action="list">Refresh collab hosts</button></div><p class="field-help">Collab relay, share, and stream endpoints can be configured from the native OMP configuration tab; this card shows currently advertised sessions.</p></div></section>
|
|
519
|
+
</div><div class="dialog-foot"><span class="field-help" id="settings-status" role="status">Changes are stored in Bizar OMP and OMP configuration.</span><button class="btn" value="cancel">Close</button><button class="btn primary" id="settings-save" type="button">Save dashboard settings</button></div></div></form></dialog>
|
|
359
520
|
<div class="toast hidden" id="toast" role="status" aria-live="polite"></div>
|
|
360
521
|
<script>
|
|
522
|
+
${GSAP_SOURCE}
|
|
361
523
|
(function(){"use strict";
|
|
362
|
-
var token="",sessions=[],models=[],selectedName="",filter="all",query="",projectsFolder="",runtimeDefaults={model:"",thinking:"",approvalMode:""},refreshTimer,consoleTimer,consoleSessionName="",consoleBusy=false,
|
|
524
|
+
var token="",sessions=[],models=[],messages=[],pendingMessages=[],providers=[],selectedName="",filter="all",query="",workspaceFilter="all",projectsFolder="",runtimeDefaults={model:"",thinking:"",approvalMode:""},providerOrder=[],refreshTimer,consoleTimer,streamAbort=null,rpcState="",rpcLabel="",consoleSessionName="",consoleBusy=false,followConsole=true,lastActivityLabel="",renderedMessageIds=new Set(),reducedMotion=matchMedia("(prefers-reduced-motion: reduce)").matches,THEME_KEY="bizar.dash.theme",SELECTED_KEY="bizar.dash.selected";
|
|
363
525
|
function byId(id){return document.getElementById(id)}
|
|
526
|
+
function setRpcStatus(state,label){rpcState=state;rpcLabel=label;var pill=byId("rpc-status");if(!pill)return;pill.dataset.state=state;pill.textContent=label}
|
|
364
527
|
function esc(value){return String(value==null?"":value).replace(/[&<>"']/g,function(c){if(c==="&")return"&";if(c==="<")return"<";if(c===">")return">";if(c.charCodeAt(0)===34)return""";return"'"})}
|
|
365
528
|
function err(error){return error&&error.message?error.message:"Unexpected error"}
|
|
366
529
|
function toast(message,isError){var n=byId("toast");n.textContent=message;n.setAttribute("role",isError?"alert":"status");n.setAttribute("aria-live",isError?"assertive":"polite");n.classList.toggle("error",Boolean(isError));n.classList.remove("hidden");clearTimeout(n._hide);n._hide=setTimeout(function(){n.classList.add("hidden")},4800)}
|
|
@@ -375,41 +538,122 @@ function title(s){return s.displayName||s.id||s.project||s.name}
|
|
|
375
538
|
function available(s){return Boolean(s&&s.state!=="stopped"&&s.hosted!==false)}
|
|
376
539
|
function tone(state){return state==="working"||state==="connected"?"dot-ok":state==="error"?"dot-err":state==="waiting"||state==="disconnected"?"dot-warn":"dot-muted"}
|
|
377
540
|
function mobile(view){document.body.setAttribute("data-mobile-view",view);document.querySelectorAll("[data-view]").forEach(function(b){b.classList.toggle("active",b.dataset.view===view)})}
|
|
378
|
-
function
|
|
541
|
+
function workspaceOf(s){return s.cwd||s.project||"Unknown workspace"}
|
|
542
|
+
function visible(){var needle=query.toLowerCase();return sessions.filter(function(s){return(filter==="all"||s.state===filter)&&(workspaceFilter==="all"||workspaceOf(s)===workspaceFilter)&&(!needle||[s.displayName,s.name,s.id,s.project,s.cwd,s.state].join(" ").toLowerCase().includes(needle))})}
|
|
543
|
+
function renderWorkspaceSelect(){var select=byId("workspace-select"),values=[...new Set(sessions.map(workspaceOf))].sort();select.innerHTML='<option value="all">All workspaces</option>'+values.map(function(value){return'<option value="'+esc(value)+'">'+esc(value.split("/").filter(Boolean).pop()||value)+'</option>'}).join("");if(workspaceFilter!=="all"&&values.indexOf(workspaceFilter)===-1)workspaceFilter="all";select.value=workspaceFilter;byId("workspace-list").innerHTML=values.map(function(value){return'<option value="'+esc(value)+'"></option>'}).join("")}
|
|
379
544
|
function renderFilters(){var counts={};sessions.forEach(function(s){counts[s.state]=(counts[s.state]||0)+1});var keys=["all"].concat(Object.keys(counts).sort());byId("filters").innerHTML=keys.map(function(key){var count=key==="all"?sessions.length:counts[key];return'<button type="button" class="filter'+(filter===key?' active':'')+'" data-filter="'+esc(key)+'">'+esc(key)+" "+count+"</button>"}).join("")}
|
|
380
545
|
function renderSessions(){var list=visible(),target=byId("session-list");byId("session-count").textContent=String(sessions.length);if(!list.length){target.innerHTML='<div class="empty"><strong>'+(sessions.length?"No matching sessions":"No sessions yet")+'</strong>'+(sessions.length?"Change the search or state filter.":"Create a session to start work from the dashboard.")+"</div>";return}var groups={};list.forEach(function(s){var key=s.cwd||s.project||"Unknown workspace";(groups[key]=groups[key]||[]).push(s)});target.innerHTML=Object.keys(groups).sort().map(function(workspace){return'<div class="workspace-label" title="'+esc(workspace)+'">'+esc(workspace)+"</div>"+groups[workspace].map(function(s){return'<button type="button" class="card session-row'+(s.name===selectedName?' selected':'')+'" data-session="'+esc(s.name)+'"><span class="state-dot '+tone(s.state)+'"></span><span><span class="session-name">'+esc(title(s))+'</span><span class="session-meta"><span>'+esc(s.state)+'</span><span>·</span><span>'+esc(age(s.lastAttachedAt||s.createdAt))+"</span></span></span></button>"}).join("")}).join("")}
|
|
381
546
|
function renderInspector(){var s=selected(),target=byId("inspector");if(!s){target.innerHTML='<div class="empty"><strong>Nothing selected</strong>Session identity and controls appear here.</div>';return}var activity=s.activity&&s.activity.label?s.activity.label:"No structured activity";target.innerHTML='<section class="inspector-section"><h2>Session</h2><dl class="detail-list"><div><dt>Status</dt><dd><span class="state-label"><span class="state-dot '+tone(s.state)+'"></span><span>'+esc(s.state)+'</span></span></dd></div><div><dt>Activity</dt><dd>'+esc(activity)+'</dd></div><div><dt>Workspace</dt><dd class="mono">'+esc(s.cwd||s.project||"Unknown workspace")+'</dd></div><div><dt>Session id</dt><dd class="mono">'+esc(s.name)+'</dd></div><div><dt>Created</dt><dd>'+esc(date(s.createdAt))+'</dd></div><div><dt>Last attached</dt><dd>'+esc(date(s.lastAttachedAt))+'</dd></div></dl></section><section class="inspector-section"><h2>Actions</h2><div class="action-stack"><button class="btn" type="button" data-action="attach"'+(available(s)?'':' disabled')+'>Open in terminal</button><button class="btn" type="button" data-action="rename"'+(available(s)?'':' disabled')+'>Rename session</button><button class="btn danger" type="button" data-action="stop"'+(available(s)?'':' disabled')+'>Stop session</button></div></section>'}
|
|
382
|
-
function
|
|
383
|
-
function
|
|
384
|
-
function
|
|
547
|
+
function safeHref(value){try{var url=new URL(value);return url.protocol==="http:"||url.protocol==="https:"?url.href:""}catch{return""}}
|
|
548
|
+
function inlineMarkdown(value){var source=esc(value);source=source.replace(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^\\s)]+)\\)/g,function(_,label,url){var href=safeHref(url);return href?'<a href="'+esc(href)+'" target="_blank" rel="noreferrer">'+label+"</a>":label});return source.replace(/\\x60([^\\x60]+)\\x60/g,"<code>$1</code>").replace(/\\*\\*([^*]+)\\*\\*/g,"<strong>$1</strong>").replace(/__([^_]+)__/g,"<strong>$1</strong>").replace(/\\*([^*]+)\\*/g,"<em>$1</em>")}
|
|
549
|
+
function markdown(value){var lines=String(value||"").split(/\\r?\\n/),out=[],code=[],paragraph=[],inCode=false,list="",language="",skipUntil=0;function closeList(){if(list){out.push("</"+list+">");list=""}}function flushParagraph(){if(paragraph.length){out.push("<p>"+paragraph.map(inlineMarkdown).join("<br>")+"</p>");paragraph=[]}}function flushCode(){var label=language||"code",content=esc(code.join("\\n"));out.push('<div class="code-block"><div class="code-head"><span>'+esc(label)+'</span><button class="copy-code" type="button">Copy</button></div><pre><code>'+content+"</code></pre></div>");code=[];language=""}function cells(line){var value=line.trim().replace(/^\\|/,"").replace(/\\|$/,"");return value.split("|").map(function(cell){return cell.trim()})}function tableAt(index){var header=cells(lines[index]),divider=cells(lines[index+1]||"");if(header.length<2||header.length!==divider.length||!divider.every(function(cell){return /^:?-{3,}:?$/.test(cell)}))return 0;closeList();flushParagraph();var align=divider.map(function(cell){return cell[0]===":"&&cell[cell.length-1]===":"?"center":cell[cell.length-1]===":"?"right":"left"}),rows=[],cursor=index+2;while(cursor<lines.length&&lines[cursor].includes("|")&&lines[cursor].trim()){var row=cells(lines[cursor]);while(row.length<header.length)row.push("");rows.push(row.slice(0,header.length));cursor++}out.push('<div class="md-table-wrap"><table><thead><tr>'+header.map(function(cell,column){return'<th style="text-align:'+align[column]+'">'+inlineMarkdown(cell)+"</th>"}).join("")+"</tr></thead><tbody>"+rows.map(function(row){return"<tr>"+row.map(function(cell,column){return'<td style="text-align:'+align[column]+'">'+inlineMarkdown(cell)+"</td>"}).join("")+"</tr>"}).join("")+"</tbody></table></div>");return cursor}lines.forEach(function(line,index){if(index<skipUntil)return;var fence=line.match(/^\\x60\\x60\\x60\\s*([^\\s]*)/);if(fence){closeList();flushParagraph();if(inCode)flushCode();else language=fence[1]||"";inCode=!inCode;return}if(inCode){code.push(line);return}if(line.includes("|")){var next=tableAt(index);if(next){skipUntil=next;return}}if(!line.trim()){closeList();flushParagraph();return}var heading=line.match(/^(#{1,3})\\s+(.+)$/);if(heading){closeList();flushParagraph();var level=heading[1].length;out.push("<h"+level+">"+inlineMarkdown(heading[2])+"</h"+level+">");return}if(/^\\s*([-*_])(?:\\s*\\1){2,}\\s*$/.test(line)){closeList();flushParagraph();out.push("<hr>");return}var bullet=line.match(/^\\s*[-*]\\s+(.+)$/),ordered=line.match(/^\\s*\\d+[.)]\\s+(.+)$/);if(bullet||ordered){flushParagraph();var nextList=ordered?"ol":"ul";if(list!==nextList){closeList();list=nextList;out.push("<"+list+">")}out.push("<li>"+inlineMarkdown((bullet||ordered)[1])+"</li>");return}closeList();if(/^>\\s?/.test(line)){flushParagraph();out.push("<blockquote>"+inlineMarkdown(line.replace(/^>\\s?/,""))+"</blockquote>")}else paragraph.push(line)});closeList();flushParagraph();if(inCode||code.length)flushCode();return out.join("")}
|
|
550
|
+
function messageState(head,detail){messages=[];pendingMessages=[];renderedMessageIds.clear();byId("message-stream").innerHTML='<div class="message-state"><strong>'+esc(head)+"</strong>"+esc(detail)+"</div>";byId("console-follow").classList.add("hidden")}
|
|
551
|
+
function messageTime(value){return value?new Date(value).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):"Sending"}
|
|
552
|
+
function messageKey(item){return item.role+"\\n"+String(item.text||"").replace(/\\r\\n/g,"\\n").trim()}
|
|
553
|
+
function renderMessages(animate){var node=byId("message-scroll"),target=byId("message-stream"),confirmed=new Set(messages.map(messageKey)),optimistic=pendingMessages.filter(function(item){return!confirmed.has(messageKey(item))}),all=messages.concat(optimistic),wasNear=followConsole||node.scrollHeight-node.scrollTop-node.clientHeight<100;if(!all.length){target.innerHTML='<div class="message-state"><strong>No messages yet</strong>Send the first message to start this session conversation.</div>';return}target.innerHTML=all.map(function(item){if(item.role==="status")return'<div class="message-status" data-state="'+esc(item.state||"completed")+'" data-message-id="'+esc(item.id)+'"><span class="status-icon" aria-hidden="true"></span><span>'+esc(item.text)+'</span><time>'+esc(messageTime(item.timestamp))+'</time></div>';var user=item.role==="user",pending=item.pending?' · sending':'';return'<article class="message '+item.role+'" data-message-id="'+esc(item.id)+'"><div class="message-avatar" aria-hidden="true">'+(user?'YOU':'OMP')+'</div><div class="message-content"><div class="message-meta"><strong>'+(user?'You':'Assistant')+'</strong><time>'+esc(messageTime(item.timestamp))+esc(pending)+'</time></div><div class="message-bubble">'+markdown(item.text)+'</div></div></article>'}).join("");if(animate&&!reducedMotion&&window.gsap){var fresh=Array.from(target.querySelectorAll("[data-message-id]")).filter(function(element){return!renderedMessageIds.has(element.dataset.messageId)});if(fresh.length)window.gsap.fromTo(fresh,{autoAlpha:0,y:12},{autoAlpha:1,y:0,duration:.28,stagger:.045,ease:"power2.out",clearProps:"transform,opacity"})}all.forEach(function(item){renderedMessageIds.add(item.id)});if(wasNear){node.scrollTop=node.scrollHeight;followConsole=true;byId("console-follow").classList.add("hidden")}}
|
|
554
|
+
function setActivity(s){var activity=s&&s.activity,label=activity&&activity.label?activity.label:s?s.state==="stopped"?"Session stopped":s.state==="disconnected"?"Session detached":"Ready for your message":"Waiting for a session",idle=!s||!activity||activity.awaitingInput||!activity.running,n=byId("agent-activity");byId("activity-label").textContent=label;n.dataset.idle=String(idle);if(label!==lastActivityLabel&&!reducedMotion&&window.gsap){window.gsap.killTweensOf(n);window.gsap.fromTo(n,{autoAlpha:.55},{autoAlpha:1,duration:.3,ease:"power2.out",clearProps:"opacity,visibility"});if(!idle)window.gsap.fromTo(n.querySelector(".activity-mark"),{scale:.72},{scale:1.35,duration:.22,repeat:1,yoyo:true,ease:"power2.inOut",clearProps:"transform"})}lastActivityLabel=label}
|
|
555
|
+
function renderConversation(){var s=selected(),ok=available(s);byId("conversation-title").textContent=s?title(s):"Choose a session";byId("session-state").innerHTML='<span class="state-dot '+(s?tone(s.state):'dot-muted')+'"></span><span>'+esc(s?s.state:"No session selected")+'</span>';byId("console-refresh").disabled=!s;byId("attach-top").disabled=!ok;byId("composer-input").disabled=!ok;byId("composer-send").disabled=!ok;byId("composer-status").textContent=ok?"Messages go directly to this OMP session.":s?"History is readable, but this session cannot accept input.":"Select a live session to begin.";setActivity(s);if(!s)messageState("No session open","Select a session to read its conversation and send a message.")}
|
|
556
|
+
function page(name){var onMobile=window.matchMedia&&window.matchMedia("(max-width: 759px)").matches;if(onMobile){var view=name==="overview"?"sessions":name;if(document.body.getAttribute("data-mobile-view")!==view)mobile(view)}document.body.setAttribute("data-page",name);document.querySelectorAll("[data-page]").forEach(function(button){button.classList.toggle("active",button.dataset.page===name)});if(name==="chat")startConversation();history.replaceState({},"",location.pathname+"#"+name)}
|
|
557
|
+
function render(){renderWorkspaceSelect();renderFilters();renderSessions();renderConversation();renderInspector()}
|
|
385
558
|
function daemonState(body){var n=byId("daemon-state"),dot=n.querySelector(".state-dot");dot.className="state-dot "+(body.scanError||body.stale?"dot-warn":"dot-ok");n.querySelector("span:last-child").textContent=body.scanError?"Scan issue: "+body.scanError:body.stale?"Session data is stale":"Local daemon live · updated "+age(body.collectedAt)}
|
|
386
|
-
function
|
|
387
|
-
function
|
|
388
|
-
function
|
|
389
|
-
function
|
|
559
|
+
function overview(){return apiJson("/overview").then(function(body){var total=body.sessions&&body.sessions.total||0,states=body.sessions&&body.sessions.states||{},modelCount=body.models&&body.models.total||0,providerCount=body.models&&body.models.providers||0;byId("overview-status").textContent=body.stale?"Session snapshot is stale. Refresh to retry.":body.daemon&&body.daemon.ompAvailable?"Daemon and OMP are available.":"OMP information is unavailable.";byId("overview-metrics").innerHTML=[["Sessions",total],["Working",states.working||0],["Waiting",states.waiting||0],["Workspaces",body.sessions&&body.sessions.workspaces||0]].map(function(item){return'<div class="card metric"><span class="label">'+esc(item[0])+'</span><strong class="metric-value">'+esc(item[1])+'</strong></div>'}).join("");var attention=body.sessions&&Array.isArray(body.sessions.attention)?body.sessions.attention:[],focus=selected()||sessions[0];byId("attention-list").innerHTML=attention.length?attention.map(function(s){return'<button class="overview-row" style="width:100%;border:0;background:transparent;color:inherit" type="button" data-session="'+esc(s.name)+'"><span>'+esc(title(s))+'</span><span class="state-label"><span class="state-dot '+tone(s.state)+'"></span>'+esc(s.state)+'</span></button>'}).join(""):'<p class="field-help">No sessions currently need attention.</p>';byId("focus-summary").innerHTML=focus?'<div class="overview-row"><span><strong>'+esc(title(focus))+'</strong><span class="field-help">'+esc(workspaceOf(focus))+'</span></span><span class="state-label"><span class="state-dot '+tone(focus.state)+'"></span>'+esc(focus.state)+'</span></div><button class="btn primary" type="button" data-session="'+esc(focus.name)+'">Continue in chat</button>':'<p class="field-help">No session selected. Create one to begin.</p>';var workspaceMap={};sessions.forEach(function(s){var key=workspaceOf(s),item=workspaceMap[key]||(workspaceMap[key]={total:0,working:0});item.total++;if(s.state==="working")item.working++});byId("workspace-summary").innerHTML=Object.keys(workspaceMap).length?Object.keys(workspaceMap).sort().slice(0,8).map(function(key){var item=workspaceMap[key];return'<button class="overview-row" style="width:100%;border-width:0 0 1px;background:transparent;color:inherit" type="button" data-workspace="'+esc(key)+'"><span>'+esc(key.split("/").filter(Boolean).pop()||key)+'</span><span class="field-help">'+item.total+' sessions · '+item.working+' working</span></button>'}).join(""):'<p class="field-help">Workspace activity appears when sessions exist.</p>';byId("recent-sessions").innerHTML=sessions.length?sessions.slice().sort(function(a,b){return epochMs(b.lastAttachedAt||b.createdAt)-epochMs(a.lastAttachedAt||a.createdAt)}).slice(0,6).map(function(s){return'<button class="overview-row" style="width:100%;border-width:0 0 1px;background:transparent;color:inherit" type="button" data-session="'+esc(s.name)+'"><span>'+esc(title(s))+'</span><span class="field-help">'+esc(age(s.lastAttachedAt||s.createdAt))+'</span></button>'}).join(""):'<p class="field-help">No recent sessions.</p>';byId("omp-summary").innerHTML='<div class="overview-row"><span>Models</span><strong>'+esc(modelCount)+'</strong></div><div class="overview-row"><span>Providers</span><strong>'+esc(providerCount)+'</strong></div><div class="overview-row"><span>Daemon</span><strong>'+esc(body.daemon&&body.daemon.healthy?"Healthy":"Check status")+'</strong></div><div class="overview-row"><span>OMP catalog</span><strong>'+esc(body.daemon&&body.daemon.ompAvailable?"Available":"Unavailable")+'</strong></div><div class="overview-row"><span>Last scan</span><strong>'+esc(age(body.collectedAt))+'</strong></div>';if(!reducedMotion&&window.gsap)window.gsap.fromTo("#overview-metrics .metric",{autoAlpha:0,y:8},{autoAlpha:1,y:0,duration:.24,stagger:.04,ease:"power2.out",clearProps:"transform,opacity"})}).catch(function(error){byId("overview-status").textContent="Could not load overview: "+err(error)})}
|
|
560
|
+
function configInput(setting){var value=setting.value===undefined?"":(typeof setting.value==="string"?setting.value:JSON.stringify(setting.value));if(setting.redacted)return'<div class="overview-row"><span><strong>'+esc(setting.key)+'</strong><span class="field-help">'+esc(setting.description||"Sensitive OMP value")+'</span></span><span class="field-help">Hidden</span></div>';var control=setting.type==="boolean"?'<select data-config-value="'+esc(setting.key)+'"><option value="true"'+(value==="true"?' selected':'')+'>Enabled</option><option value="false"'+(value==="false"?' selected':'')+'>Disabled</option></select>':setting.type==="enum"&&setting.options?'<select data-config-value="'+esc(setting.key)+'">'+setting.options.map(function(option){return'<option value="'+esc(option)+'"'+(option===value?' selected':'')+'>'+esc(option)+'</option>'}).join("")+'</select>':setting.type==="array"||setting.type==="record"?'<textarea data-config-value="'+esc(setting.key)+'" aria-label="'+esc(setting.key)+'">'+esc(value)+'</textarea>':'<input data-config-value="'+esc(setting.key)+'" value="'+esc(value)+'" aria-label="'+esc(setting.key)+'" />';return'<div class="overview-row"><label style="flex:1"><strong>'+esc(setting.key)+'</strong><span class="field-help">'+esc(setting.description||setting.type)+'</span>'+control+'</label><span><button type="button" class="btn" data-config-save="'+esc(setting.key)+'" '+(setting.writable?'':'disabled')+'>Save</button><button type="button" class="btn ghost" data-config-reset="'+esc(setting.key)+'" '+(setting.writable?'':'disabled')+'>Reset</button></span></div>'}
|
|
561
|
+
function decodeConfigValue(setting,input){if(setting.type==="boolean")return input.value==="true";if(setting.type==="number")return Number(input.value);if(setting.type==="array"||setting.type==="record")return JSON.parse(input.value);return input.value}
|
|
562
|
+
function renderConfigSettings(settings){var list=byId("omp-config-list");list._settings=settings;list.innerHTML=settings.length?settings.map(configInput).join(""):'<p class="field-help">OMP returned no browser-safe settings.</p>'}
|
|
563
|
+
function loadOmpConfig(){byId("omp-config-status").textContent="Loading typed configuration.";return apiJson("/omp/config").then(function(body){var settings=Array.isArray(body.settings)?body.settings:[],list=byId("omp-config-list");list._allSettings=settings;renderConfigSettings(settings);byId("omp-config-status").textContent="Values are read from OMP. Redacted values cannot be read or edited here."}).catch(function(error){byId("omp-config-status").textContent="Could not load OMP configuration: "+err(error)})}
|
|
564
|
+
function saveConfig(key,reset){var list=byId("omp-config-list"),setting=(list._settings||[]).find(function(item){return item.key===key}),input=document.querySelector('[data-config-value="'+CSS.escape(key)+'"]');if(!setting||(!reset&&!input))return;var payload={key:key};try{if(!reset)payload.value=decodeConfigValue(setting,input)}catch(error){toast("Enter valid "+setting.type+" JSON.",true);return}post(reset?"/omp/config/reset":"/omp/config",payload,reset?"POST":"PATCH").then(loadOmpConfig).then(function(){toast(reset?"OMP setting reset":"OMP setting saved")}).catch(function(error){toast("OMP setting was not changed: "+err(error),true)})}
|
|
565
|
+
function renderProviderOrder(){var target=byId("provider-order-list");if(!target)return;target.innerHTML=providerOrder.length?providerOrder.map(function(id,index){return'<div class="overview-row"><span class="mono">'+esc(id)+'</span><span><button type="button" class="btn ghost" data-provider-move="up" data-provider-index="'+index+'" '+(index?'':'disabled')+'>Up</button><button type="button" class="btn ghost" data-provider-move="down" data-provider-index="'+index+'" '+(index===providerOrder.length-1?'disabled':'')+'>Down</button></span></div>'}).join(""):'<p class="field-help">No explicit provider order is configured.</p>'}
|
|
566
|
+
function resetProviderEditor(){byId("provider-editor-title").textContent="Add provider";byId("provider-id").value="";byId("provider-id").disabled=false;byId("provider-url").value="";byId("provider-api").value="openai-responses";byId("provider-auth").value="apiKey";byId("provider-models").value="";byId("provider-key").value="";byId("provider-key-clear").checked=false;byId("provider-key-state").textContent="Keys are write-only and never returned.";byId("provider-delete").classList.add("hidden")}
|
|
567
|
+
function editProvider(id){var item=providers.find(function(provider){return provider.id===id}),custom=item&&item.custom;if(!custom)return;byId("provider-editor-title").textContent="Edit "+id;byId("provider-id").value=id;byId("provider-id").disabled=true;byId("provider-url").value=custom.baseUrl||"";byId("provider-api").value=custom.api||"openai-responses";byId("provider-auth").value=custom.auth||"apiKey";byId("provider-models").value=(custom.models||[]).join("\\n");byId("provider-key").value="";byId("provider-key-clear").checked=false;byId("provider-key-state").textContent=custom.hasApiKey?"A key is stored. Leave blank to preserve it.":"No key is stored.";byId("provider-delete").classList.remove("hidden")}
|
|
568
|
+
function loadProviders(){byId("providers-status").textContent="Loading provider state.";return apiJson("/omp/providers").then(function(body){providers=Array.isArray(body.providers)?body.providers:[];var apis=Array.isArray(body.providerApis)?body.providerApis:[];byId("provider-api").innerHTML=apis.map(function(api){return'<option value="'+esc(api)+'">'+esc(api)+'</option>'}).join("");providerOrder=Array.isArray(body.modelProviderOrder)&&body.modelProviderOrder.length?body.modelProviderOrder.slice():providers.map(function(provider){return provider.id});byId("providers-list").innerHTML=providers.length?providers.map(function(provider){return'<div class="card provider-card"><span><strong>'+esc(provider.id)+'</strong><span class="field-help">'+esc(provider.models)+' models · '+esc(provider.enabled?"enabled":"disabled")+(provider.custom?' · custom':'')+'</span></span><span class="provider-order-actions">'+(provider.custom?'<button type="button" class="btn ghost" data-provider-edit="'+esc(provider.id)+'">Edit</button>':'')+'<button type="button" class="btn" data-provider="'+esc(provider.id)+'" data-provider-operation="'+(provider.enabled?'disable':'enable')+'">'+(provider.enabled?'Disable':'Enable')+'</button></span></div>'}).join(""):'<p class="field-help">OMP returned no providers.</p>';renderProviderOrder();if(!byId("provider-api").value&&apis[0])byId("provider-api").value=apis[0];byId("providers-status").textContent="Routing and custom providers are read directly from OMP."}).catch(function(error){byId("providers-status").textContent="Could not load providers: "+err(error)})}
|
|
569
|
+
function saveCustomProvider(){var id=byId("provider-id").value.trim(),url=byId("provider-url").value.trim(),models=byId("provider-models").value.split(/\\r?\\n|,/).map(function(value){return value.trim()}).filter(Boolean);if(!id||!url||!models.length){toast("Provider id, endpoint, and at least one model are required.",true);return}var payload={baseUrl:url,api:byId("provider-api").value,auth:byId("provider-auth").value,models:models,clearApiKey:byId("provider-key-clear").checked};if(byId("provider-key").value)payload.apiKey=byId("provider-key").value;post("/omp/providers/"+encodeURIComponent(id),payload,"PUT").then(function(){toast("Custom provider saved to OMP");return loadProviders()}).then(function(){editProvider(id);return loadModels()}).catch(function(error){toast("Provider was not saved: "+err(error),true)})}
|
|
570
|
+
function deleteProvider(){var id=byId("provider-id").value;if(!id||!confirm("Delete custom provider "+id+" from OMP?"))return;apiJson("/omp/providers/"+encodeURIComponent(id),{method:"DELETE"}).then(function(){toast("Custom provider deleted");resetProviderEditor();return loadProviders()}).then(loadModels).catch(function(error){toast("Provider was not deleted: "+err(error),true)})}
|
|
571
|
+
function saveProviderOrder(order){return post("/omp/providers",{operation:"order",order:order},"PATCH").then(function(){providerOrder=order.slice();renderProviderOrder();toast("OMP provider order saved")}).catch(function(error){toast("Provider order was not changed: "+err(error),true)})}
|
|
572
|
+
function authAction(action){var confirm=action!=="status"&&action!=="list";byId("auth-status").textContent="Running OMP auth-broker "+action+"…";return post("/omp/provider-action",{action:action,confirm:confirm}).then(function(body){byId("auth-status").textContent=body.status==="handoff-required"?"Open an OMP terminal to finish this interactive action.":"OMP auth-broker action completed.";toast(byId("auth-status").textContent)}).catch(function(error){byId("auth-status").textContent="Auth action failed: "+err(error);toast(byId("auth-status").textContent,true)})}
|
|
573
|
+
function loadCollabHosts(){var status=byId("collab-status"),target=byId("collab-list");if(!status||!target)return;status.textContent="Loading active collab hosts.";return apiJson("/omp/collab").then(function(body){var hosts=Array.isArray(body&&body.hosts)?body.hosts:[];if(!hosts.length){target.innerHTML='<p class="field-help">No active collab sessions on this host. Mint a share link with omp collab link in a terminal.</p>';status.textContent="No active collab hosts.";return}target.innerHTML=hosts.map(collabRow).join("");status.textContent=hosts.length+" active collab host"+(hosts.length===1?"":"s")+"."}).catch(function(error){status.textContent="Could not load collab hosts: "+err(error);target.innerHTML=""})}
|
|
574
|
+
function collabRow(host){var instanceId=String(host&&host.instanceId||""),pid=host&&host.pid,model=(host&&host.model)||{},provider=String(model.provider||""),modelId=String(model.id||""),cwd=String(host&&host.cwd||""),sessionName=String(host&&host.sessionName||""),participants=Number(host&&host.participants)||0,relay=Boolean(host&&host.relayConnected),access=String(host&&host.access||""),sep=String.fromCharCode(92),cut=Math.max(cwd.lastIndexOf("/"),cwd.lastIndexOf(sep)),basename=cut>=0?cwd.slice(cut+1):cwd,label=modelId||instanceId||String(pid||"host"),hostId=instanceId||String(pid||"");return '<div class="overview-row"><div><span class="mono">'+esc(provider||label)+'</span><p class="field-help">'+esc(label)+(basename?' · '+esc(basename):'')+(sessionName?' · '+esc(sessionName):'')+' · '+participants+' participant'+(participants===1?'':'s')+(access?' · '+esc(access):'')+'</p></div>'+'<div><span class="state-dot '+(relay?'dot-ok':'dot-warn')+'" title="'+(relay?'relay connected':'relay disconnected')+'"></span>'+'<button class="btn ghost" type="button" data-collab-copy="'+esc(hostId)+'">Copy id</button></div></div>'}
|
|
575
|
+
function refresh(){return apiJson("/sessions").then(function(body){sessions=Array.isArray(body.sessions)?body.sessions:[];if(!selectedName||!sessions.some(function(s){return s.name===selectedName})){var remembered=localStorage.getItem(SELECTED_KEY)||"";selectedName=sessions.some(function(s){return s.name===remembered})?remembered:(sessions[0]?sessions[0].name:"")}daemonState(body);render();if(selectedName)startConversation()}).catch(function(error){var n=byId("daemon-state");n.querySelector(".state-dot").className="state-dot dot-warn";n.querySelector("span:last-child").textContent="Daemon unavailable";toast("Session refresh failed: "+err(error),true)})}
|
|
576
|
+
function loadMessages(force){var s=selected();if(!s||consoleBusy)return Promise.resolve();var requestedName=s.name;consoleBusy=true;if(force&&!messages.length)byId("message-stream").innerHTML='<div class="message-state"><strong>Loading conversation</strong>Reading recent messages from the OMP session journal.</div>';return apiJson("/sessions/"+encodeURIComponent(requestedName)+"/messages").then(function(body){if(selectedName!==requestedName)return;var next=Array.isArray(body.messages)?body.messages:[],keys=new Set(next.map(messageKey));pendingMessages=pendingMessages.filter(function(pending){return!keys.has(messageKey(pending))});messages=next;renderMessages(true)}).catch(function(error){if(selectedName===requestedName&&!messages.length)byId("message-stream").innerHTML='<div class="message-state"><strong>Messages unavailable</strong>'+esc(err(error))+' Refresh to try again.</div>'}).finally(function(){consoleBusy=false})}
|
|
577
|
+
function startConversation(){var s=selected();if(!s){clearInterval(consoleTimer);consoleSessionName="";stopMessageStream();return}if(consoleSessionName===s.name&&(consoleTimer||streamAbort))return;clearInterval(consoleTimer);consoleTimer=undefined;consoleSessionName=s.name;void loadMessages(true);if(available(s))startMessageStream(s.name)}
|
|
578
|
+
function startMessageStream(name){
|
|
579
|
+
stopMessageStream();
|
|
580
|
+
var controller=new AbortController();
|
|
581
|
+
streamAbort=controller;
|
|
582
|
+
setRpcStatus("connecting","Connecting to daemon message stream");
|
|
583
|
+
function handleFrame(frame){
|
|
584
|
+
var event="message",data="";
|
|
585
|
+
frame.split("\\n").forEach(function(line){
|
|
586
|
+
if(line.indexOf(":")===0)return;
|
|
587
|
+
if(line.indexOf("event:")===0){event=line.slice(6).trim();return}
|
|
588
|
+
if(line.indexOf("data:")===0)data+=line.slice(5).trim();
|
|
589
|
+
});
|
|
590
|
+
if(!data)return;
|
|
591
|
+
if(event==="snapshot"){
|
|
592
|
+
var payload;
|
|
593
|
+
try{payload=JSON.parse(data)}catch(error){return}
|
|
594
|
+
if(!payload||!Array.isArray(payload.messages)||selectedName!==name)return;
|
|
595
|
+
messages=payload.messages;renderMessages(true);setRpcStatus("live","Live (Server-Sent Events)");
|
|
596
|
+
}else if(event==="idle"){setRpcStatus("live","Live (idle)")}
|
|
597
|
+
else if(event==="ready"){setRpcStatus("live","Live (Server-Sent Events)")}
|
|
598
|
+
else if(event==="error"){setRpcStatus("offline","Stream reported an error")}
|
|
599
|
+
}
|
|
600
|
+
fetch("/sessions/"+encodeURIComponent(name)+"/messages/stream",{headers:{authorization:"Bearer "+token},signal:controller.signal})
|
|
601
|
+
.then(function(response){
|
|
602
|
+
if(!response.ok||!response.body)throw new Error("stream unavailable");
|
|
603
|
+
setRpcStatus("live","Live (Server-Sent Events)");
|
|
604
|
+
var reader=response.body.getReader(),decoder=new TextDecoder(),buffer="";
|
|
605
|
+
function pump(){
|
|
606
|
+
if(controller.signal.aborted)return Promise.resolve();
|
|
607
|
+
return reader.read().then(function(result){
|
|
608
|
+
if(result.done)return;
|
|
609
|
+
buffer+=decoder.decode(result.value,{stream:true});
|
|
610
|
+
var frames=buffer.split("\\n\\n");
|
|
611
|
+
buffer=frames.pop()||"";
|
|
612
|
+
frames.forEach(handleFrame);
|
|
613
|
+
return pump();
|
|
614
|
+
}).catch(function(error){
|
|
615
|
+
if(controller.signal.aborted)return Promise.resolve();
|
|
616
|
+
throw error;
|
|
617
|
+
}).then(pump);
|
|
618
|
+
}
|
|
619
|
+
return pump();
|
|
620
|
+
})
|
|
621
|
+
.catch(function(){
|
|
622
|
+
if(controller.signal.aborted)return;
|
|
623
|
+
setRpcStatus("polling","Stream unavailable, polling every 1.6s");
|
|
624
|
+
stopMessageStream();
|
|
625
|
+
if(selectedName===name&&available(selected()))consoleTimer=setInterval(function(){if(selectedName===name)void loadMessages(false)},1600);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
function stopMessageStream(){if(streamAbort){try{streamAbort.abort()}catch(error){}streamAbort=null}}
|
|
629
|
+
function choose(name){if(selectedName===name){mobile("chat");page("chat");return}selectedName=name;localStorage.setItem(SELECTED_KEY,name);messages=[];pendingMessages=[];renderedMessageIds.clear();render();startConversation();mobile("chat");page("chat");byId("composer-input").focus()}
|
|
390
630
|
function attach(){var s=selected();if(!s)return;post("/sessions/"+encodeURIComponent(s.name)+"/attach",{}).then(function(body){if(body.spawned)toast("Opened "+body.terminal);else if(body.command){if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(body.command).catch(function(){});toast("No terminal emulator found. Attach command copied when browser access allowed.",true)}}).catch(function(error){toast("Could not open terminal: "+err(error),true)})}
|
|
391
631
|
function modelOptions(select,value){var custom=value&&!models.some(function(model){return model.selector===value})?'<option value="'+esc(value)+'">'+esc(value)+"</option>":"";select.innerHTML='<option value="">OMP default</option>'+custom+models.map(function(model){return'<option value="'+esc(model.selector)+'">'+esc(model.name+" · "+model.provider)+'</option>'}).join("");select.value=value||""}
|
|
392
632
|
var THINKING_LEVELS=["off","minimal","low","medium","high","xhigh","max","auto"],SETTINGS_FIELD={model:"defaultModel",thinking:"defaultThinking",approvalMode:"defaultApprovalMode"};
|
|
393
633
|
function thinkingLevels(selector){var known=models.find(function(model){return model.selector===selector});return known&&Array.isArray(known.thinking)&&known.thinking.length?known.thinking:THINKING_LEVELS}
|
|
394
634
|
function thinkingOptions(select,selector,level){var levels=thinkingLevels(selector),custom=level&&levels.indexOf(level)===-1?'<option value="'+esc(level)+'">'+esc(level)+"</option>":"";select.innerHTML='<option value="">OMP default</option>'+custom+levels.map(function(item){return'<option value="'+esc(item)+'">'+esc(item)+"</option>"}).join("");select.value=level||""}
|
|
395
|
-
function seedRuntime(){modelOptions(byId("composer-model"),runtimeDefaults.model);modelOptions(byId("create-model"),runtimeDefaults.model);thinkingOptions(byId("composer-thinking"),runtimeDefaults.model,runtimeDefaults.thinking);thinkingOptions(byId("create-thinking"),runtimeDefaults.model,runtimeDefaults.thinking);byId("composer-permission").value=runtimeDefaults.approvalMode;byId("create-permission").value=runtimeDefaults.approvalMode}
|
|
635
|
+
function seedRuntime(){modelOptions(byId("composer-model"),runtimeDefaults.model);modelOptions(byId("create-model"),runtimeDefaults.model);modelOptions(byId("setting-model"),runtimeDefaults.model);thinkingOptions(byId("composer-thinking"),runtimeDefaults.model,runtimeDefaults.thinking);thinkingOptions(byId("create-thinking"),runtimeDefaults.model,runtimeDefaults.thinking);thinkingOptions(byId("setting-thinking"),runtimeDefaults.model,runtimeDefaults.thinking);byId("composer-permission").value=runtimeDefaults.approvalMode;byId("create-permission").value=runtimeDefaults.approvalMode;byId("setting-permission").value=runtimeDefaults.approvalMode}
|
|
396
636
|
function saveRuntime(key,value){if(value===runtimeDefaults[key])return;var payload={};payload[SETTINGS_FIELD[key]]=value;post("/settings",payload,"PATCH").then(loadSettings).then(function(){toast("Launch default saved")}).catch(function(error){seedRuntime();toast("Could not save the launch default: "+err(error),true)})}
|
|
397
637
|
function loadModels(){return apiJson("/models").then(function(body){models=Array.isArray(body.models)?body.models:[];seedRuntime();byId("model-status").textContent=models.length?models.length+" available models loaded from OMP.":"OMP returned no available models."}).catch(function(error){byId("model-status").textContent="Model catalog unavailable. OMP default remains available.";models=[];seedRuntime()})}
|
|
398
638
|
function openCreate(){byId("create-cwd").value=projectsFolder;byId("create-task").value="";byId("create-id").value="";seedRuntime();byId("create-dialog").showModal();requestAnimationFrame(function(){byId("create-cwd").focus()})}
|
|
399
639
|
function openRename(){var s=selected();if(!s)return;byId("rename-id").value=s.id||"";byId("rename-dialog").showModal();requestAnimationFrame(function(){byId("rename-id").select()})}
|
|
400
640
|
function openStop(){var s=selected();if(!s)return;byId("stop-text").textContent="Stop "+title(s)+"? This ends its tmux session and agent work.";byId("stop-dialog").showModal()}
|
|
401
|
-
function loadSettings(){return apiJson("/settings").then(function(body){var s=body.settings||{};projectsFolder=s.projectsFolder||"";runtimeDefaults={model:s.defaultModel||"",thinking:s.defaultThinking||"",approvalMode:s.defaultApprovalMode||""};byId("setting-projects").value=projectsFolder;seedRuntime();byId("setting-attach").checked=Boolean(s.autoAttachLatest);byId("setting-mouse").checked=Boolean(s.mouseScrolling);byId("setting-stopped").checked=Boolean(s.showStoppedSessions);byId("setting-tray").checked=Boolean(s.trayEnabled);byId("settings-status").textContent="Changes are stored in
|
|
402
|
-
function
|
|
403
|
-
function
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
byId("
|
|
641
|
+
function loadSettings(){return apiJson("/settings").then(function(body){var s=body.settings||{};projectsFolder=s.projectsFolder||"";runtimeDefaults={model:s.defaultModel||"",thinking:s.defaultThinking||"",approvalMode:s.defaultApprovalMode||""};byId("setting-projects").value=projectsFolder;seedRuntime();byId("setting-attach").checked=Boolean(s.autoAttachLatest);byId("setting-mouse").checked=Boolean(s.mouseScrolling);byId("setting-stopped").checked=Boolean(s.showStoppedSessions);byId("setting-tray").checked=Boolean(s.trayEnabled);byId("setting-theme").value=localStorage.getItem(THEME_KEY)||"system";byId("settings-status").textContent="Changes are stored in Bizar OMP and OMP configuration."})}
|
|
642
|
+
function settingsTab(name){document.querySelectorAll("[data-settings-tab]").forEach(function(tab){tab.classList.toggle("active",tab.dataset.settingsTab===name)});document.querySelectorAll("[data-settings-panel]").forEach(function(panel){panel.classList.toggle("active",panel.dataset.settingsPanel===name)});if(name==="omp")void loadOmpConfig();if(name==="providers")void loadProviders();if(name==="security")void loadCollabHosts()}
|
|
643
|
+
function openSettings(tab){if(!byId("settings-dialog").open)byId("settings-dialog").showModal();settingsTab(tab||"general");byId("settings-status").textContent="Loading settings.";Promise.all([loadSettings(),tab==="providers"?loadProviders():Promise.resolve(),tab==="omp"?loadOmpConfig():Promise.resolve()]).catch(function(error){byId("settings-status").textContent="Could not load settings: "+err(error)})}
|
|
644
|
+
function saveDashboardSettings(){var payload={projectsFolder:byId("setting-projects").value.trim(),autoAttachLatest:byId("setting-attach").checked,mouseScrolling:byId("setting-mouse").checked,showStoppedSessions:byId("setting-stopped").checked,trayEnabled:byId("setting-tray").checked,defaultModel:byId("setting-model").value,defaultThinking:byId("setting-thinking").value,defaultApprovalMode:byId("setting-permission").value};post("/settings",payload,"PATCH").then(function(){var selectedTheme=byId("setting-theme").value;theme(selectedTheme,true);return loadSettings()}).then(function(){toast("Dashboard settings saved");return refresh()}).catch(function(error){toast("Could not save settings: "+err(error),true)})}
|
|
645
|
+
function theme(value,remember){var effective=value==="system"?(matchMedia("(prefers-color-scheme: light)").matches?"light":"dark"):value;document.documentElement.setAttribute("data-theme",effective);byId("theme-toggle").textContent=effective==="dark"?"Light theme":"Dark theme";if(remember)localStorage.setItem(THEME_KEY,value)}
|
|
646
|
+
document.addEventListener("click",function(event){var copy=event.target.closest(".copy-code");if(copy){var code=copy.closest(".code-block").querySelector("code").textContent;navigator.clipboard.writeText(code).then(function(){copy.textContent="Copied";setTimeout(function(){copy.textContent="Copy"},1200)}).catch(function(){toast("Code could not be copied.",true)});return}var target=event.target.closest("button");if(!target)return;if(target.dataset.session)choose(target.dataset.session);if(target.dataset.workspace){workspaceFilter=target.dataset.workspace;render();page("chat")}if(target.dataset.filter){filter=target.dataset.filter;renderFilters();renderSessions()}if(target.dataset.view)mobile(target.dataset.view);if(target.dataset.page){page(target.dataset.page);byId("utility-menu").classList.add("hidden");byId("utility-open").setAttribute("aria-expanded","false")}if(target.dataset.action==="attach")attach();if(target.dataset.action==="rename")openRename();if(target.dataset.action==="stop")openStop();if(target.dataset.configSave)saveConfig(target.dataset.configSave,false);if(target.dataset.configReset)saveConfig(target.dataset.configReset,true);if(target.dataset.settingsTab)settingsTab(target.dataset.settingsTab);if(target.dataset.providerEdit)editProvider(target.dataset.providerEdit);if(target.dataset.provider){post("/omp/providers",{operation:target.dataset.providerOperation,provider:target.dataset.provider},"PATCH").then(loadProviders).then(function(){toast("Provider routing updated")}).catch(function(error){toast("Provider was not changed: "+err(error),true)})}if(target.dataset.providerMove){var index=Number(target.dataset.providerIndex),next=index+(target.dataset.providerMove==="up"?-1:1);if(Number.isInteger(index)&&next>=0&&next<providerOrder.length){var moved=providerOrder[index];providerOrder[index]=providerOrder[next];providerOrder[next]=moved;renderProviderOrder()}}if(target.id==="provider-order-save")saveProviderOrder(providerOrder);if(target.id==="provider-order-reset")saveProviderOrder([]);if(target.id==="provider-save")saveCustomProvider();if(target.id==="provider-editor-reset")resetProviderEditor();if(target.id==="provider-delete")deleteProvider();if(target.id==="settings-save")saveDashboardSettings();if(target.dataset.authAction)authAction(target.dataset.authAction);if(target.dataset.overviewAction==="new")openCreate();if(target.dataset.overviewAction==="chat")page("chat");if(target.dataset.overviewAction==="settings")openSettings("general");if(target.dataset.overviewAction==="refresh"){void refresh();void overview()}if(target.dataset.composerAction==="new")openCreate();if(target.dataset.composerAction==="terminal")attach();if(target.dataset.composerAction==="settings")openSettings("runtime");if(target.dataset.composerAction)byId("composer-menu").classList.add("hidden");if(target.dataset.authAction)authAction(target.dataset.authAction);if(target.dataset.collabAction)void loadCollabHosts();if(target.dataset.collabCopy){navigator.clipboard.writeText(target.dataset.collabCopy).then(function(){toast("Collab id copied")}).catch(function(){toast("Could not copy collab id",true)});return}});
|
|
647
|
+
byId("omp-config-filter").addEventListener("input",function(event){var needle=event.target.value.trim().toLowerCase(),all=byId("omp-config-list")._allSettings||[];renderConfigSettings(all.filter(function(setting){return!needle||[setting.key,setting.type,setting.description||""].join(" ").toLowerCase().indexOf(needle)!==-1}))});
|
|
648
|
+
byId("settings-search").addEventListener("input",function(event){var needle=event.target.value.trim().toLowerCase(),match="";document.querySelectorAll("[data-settings-panel]").forEach(function(panel){var hit=!needle||panel.textContent.toLowerCase().includes(needle);if(hit&&!match)match=panel.dataset.settingsPanel});if(match)settingsTab(match)});
|
|
649
|
+
byId("session-search").addEventListener("input",function(event){query=event.target.value.trim();renderSessions()});byId("workspace-select").addEventListener("change",function(event){workspaceFilter=event.target.value;var list=visible();if(list.length&&!list.some(function(s){return s.name===selectedName}))choose(list[0].name);else renderSessions()});byId("new-session-top").addEventListener("click",openCreate);byId("settings-open").addEventListener("click",function(){openSettings("general")});byId("utility-open").addEventListener("click",function(){var menu=byId("utility-menu"),open=menu.classList.toggle("hidden");byId("utility-open").setAttribute("aria-expanded",String(!open))});byId("utility-refresh").addEventListener("click",function(){void refresh();void overview()});byId("composer-menu-open").addEventListener("click",function(){var menu=byId("composer-menu"),hidden=menu.classList.toggle("hidden");this.setAttribute("aria-expanded",String(!hidden))});document.addEventListener("keydown",function(event){if(event.key==="Escape"){byId("utility-menu").classList.add("hidden");byId("composer-menu").classList.add("hidden");byId("utility-open").setAttribute("aria-expanded","false")}});byId("attach-top").addEventListener("click",attach);byId("console-refresh").addEventListener("click",function(){void loadMessages(true)});byId("theme-toggle").addEventListener("click",function(){theme(document.documentElement.getAttribute("data-theme")==="dark"?"light":"dark",true)});byId("composer-model").addEventListener("change",function(event){saveRuntime("model",event.target.value)});byId("composer-thinking").addEventListener("change",function(event){saveRuntime("thinking",event.target.value)});byId("composer-permission").addEventListener("change",function(event){saveRuntime("approvalMode",event.target.value)});
|
|
650
|
+
byId("message-scroll").addEventListener("scroll",function(event){var n=event.target;followConsole=n.scrollHeight-n.scrollTop-n.clientHeight<100;byId("console-follow").classList.toggle("hidden",followConsole)});byId("console-follow").addEventListener("click",function(){var n=byId("message-scroll");n.scrollTo({top:n.scrollHeight,behavior:reducedMotion?"auto":"smooth"});followConsole=true;byId("console-follow").classList.add("hidden")});byId("composer-input").addEventListener("keydown",function(event){if(event.key==="Enter"&&(event.ctrlKey||event.metaKey)){event.preventDefault();byId("composer").requestSubmit()}});
|
|
651
|
+
byId("composer-input").addEventListener("input",function(event){var input=event.target;input.style.height="auto";input.style.height=Math.min(input.scrollHeight,160)+"px"});byId("composer-input").addEventListener("focus",function(){if(!reducedMotion&&window.gsap)window.gsap.to(byId("composer"),{boxShadow:"0 22px 64px rgba(0,0,0,.42)",duration:.2,ease:"power2.out"})});byId("composer-input").addEventListener("blur",function(){if(!reducedMotion&&window.gsap)window.gsap.to(byId("composer"),{boxShadow:"0 18px 54px rgba(0,0,0,.32)",duration:.2,ease:"power2.out",clearProps:"boxShadow"})});
|
|
652
|
+
byId("composer").addEventListener("submit",function(event){event.preventDefault();var s=selected(),input=byId("composer-input"),message=input.value;if(!s||!message.trim())return;byId("composer-send").disabled=true;byId("composer-status").textContent="Sending to "+title(s)+".";post("/sessions/"+encodeURIComponent(s.name)+"/console",{message:message}).then(function(body){input.value="";input.style.height="auto";pendingMessages.push({id:"pending-"+(body.sentAt||Date.now()),role:"user",text:message,timestamp:body.sentAt||Date.now(),pending:true});byId("composer-status").textContent="Sent. The agent is receiving your message.";followConsole=true;renderMessages(true);void refresh();return new Promise(function(resolve){setTimeout(resolve,220)})}).then(function(){return loadMessages(false)}).catch(function(error){byId("composer-status").textContent="Send failed. Your draft is still here.";toast("Message was not sent: "+err(error),true)}).finally(function(){byId("composer-send").disabled=!available(selected())})});
|
|
408
653
|
byId("create-dialog").addEventListener("close",function(event){if(event.target.returnValue!=="create")return;var cwd=byId("create-cwd").value.trim();if(!cwd)return;post("/sessions/create",{cwd:cwd,task:byId("create-task").value.trim(),sessionId:byId("create-id").value.trim(),model:byId("create-model").value,thinking:byId("create-thinking").value,approvalMode:byId("create-permission").value}).then(function(body){selectedName=body.name||"";toast("Session created in "+cwd);return refresh()}).then(function(){if(selectedName)choose(selectedName)}).catch(function(error){toast("Could not create session: "+err(error),true)})});
|
|
409
654
|
byId("rename-dialog").addEventListener("close",function(event){var s=selected();if(event.target.returnValue!=="rename"||!s)return;var next=byId("rename-id").value.trim();if(!next)return;post("/sessions/"+encodeURIComponent(s.name)+"/rename",{sessionId:next}).then(function(){selectedName="";toast("Session renamed to "+next);return refresh()}).catch(function(error){toast("Could not rename session: "+err(error),true)})});
|
|
410
655
|
byId("stop-dialog").addEventListener("close",function(event){var s=selected();if(event.target.returnValue!=="stop"||!s)return;post("/sessions/"+encodeURIComponent(s.name)+"/delete",{}).then(function(){toast("Stopped "+title(s));selectedName="";return refresh()}).catch(function(error){toast("Could not stop session: "+err(error),true)})});
|
|
411
|
-
|
|
412
|
-
function bootstrap(){var remembered=localStorage.getItem(THEME_KEY);theme(remembered==="light"||remembered==="dark"?remembered:matchMedia("(prefers-color-scheme: light)").matches?"light":"dark",false);var code=new URL(location.href).searchParams.get("oc"),auth=code?fetch("/dash/session",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:code})}).then(function(response){return response.json().then(function(body){if(!response.ok)throw new Error(body.error||"Access code rejected");return body})}):Promise.reject(new Error("Open the dashboard with omb dashboard --open to obtain a fresh access code."));auth.then(function(body){token=body.token;history.replaceState({},"",location.pathname);return loadSettings()}).then(loadModels).then(refresh).then(function(){refreshTimer=setInterval(function(){void refresh()},5000)}).catch(function(error){byId("session-list").innerHTML='<div class="notice"><strong>Dashboard access failed</strong>'+esc(err(error))+"</div>";consoleState("Dashboard locked",err(error));var n=byId("daemon-state");n.querySelector(".state-dot").className="state-dot dot-warn";n.querySelector("span:last-child").textContent="Authentication required"})}
|
|
656
|
+
function bootstrap(){var remembered=localStorage.getItem(THEME_KEY)||"system";theme(remembered,false);resetProviderEditor();var code=new URL(location.href).searchParams.get("oc"),auth=code?fetch("/dash/session",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:code})}).then(function(response){return response.json().then(function(body){if(!response.ok)throw new Error(body.error||"Access code rejected");return body})}):Promise.reject(new Error("Open the dashboard with omb dashboard --open to obtain a fresh access code."));auth.then(function(body){token=body.token;history.replaceState({},"",location.pathname);return loadSettings()}).then(loadModels).then(refresh).then(overview).then(function(){refreshTimer=setInterval(function(){void refresh();void overview()},5000)}).catch(function(error){byId("session-list").innerHTML='<div class="notice"><strong>Dashboard access failed</strong>'+esc(err(error))+"</div>";messageState("Dashboard locked",err(error));var n=byId("daemon-state");n.querySelector(".state-dot").className="state-dot dot-warn";n.querySelector("span:last-child").textContent="Authentication required"})}
|
|
413
657
|
window.addEventListener("beforeunload",function(){clearInterval(refreshTimer);clearInterval(consoleTimer)});bootstrap();
|
|
414
658
|
})();
|
|
415
659
|
</script>
|