@worca/app 1.5.0 → 1.6.0-rc.2
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 +8 -2
- package/docker/compose.broker.yml +79 -0
- package/docker/compose.isolation.yml +40 -0
- package/package.json +2 -1
- package/src/broker/config.mjs +200 -0
- package/src/broker/copilot.mjs +124 -0
- package/src/broker/limits.mjs +88 -0
- package/src/broker/main.mjs +129 -0
- package/src/broker/scrub.mjs +45 -0
- package/src/broker/service.mjs +558 -0
- package/src/broker/slots.mjs +180 -0
- package/src/broker/store.mjs +171 -0
- package/src/broker/tokens.mjs +116 -0
- package/src/broker/ui/page.css +54 -0
- package/src/broker/ui/page.html +25 -0
- package/src/broker/ui/page.mjs +202 -0
- package/src/broker/ui-server.mjs +217 -0
- package/src/broker/usage.mjs +108 -0
- package/src/broker/vault.mjs +37 -0
- package/src/cli/models.mjs +46 -14
- package/src/cli/render.mjs +21 -0
- package/src/cli/runs.mjs +296 -0
- package/src/cli/worca-cc.mjs +14 -2
- package/src/core/agent-pool.mjs +76 -0
- package/src/core/artifacts.mjs +40 -8
- package/src/core/ask/events.mjs +11 -0
- package/src/core/ask/html-text.mjs +113 -0
- package/src/core/ask/limits.mjs +5 -0
- package/src/core/ask/mcp-stdio.mjs +74 -20
- package/src/core/ask/prompt.mjs +25 -6
- package/src/core/ask/spawn.mjs +55 -5
- package/src/core/ask/store.mjs +1 -1
- package/src/core/ask/tools.mjs +66 -1
- package/src/core/ask/turn.mjs +56 -3
- package/src/core/ask/web-access.mjs +26 -0
- package/src/core/ask/web-deps.mjs +56 -0
- package/src/core/ask/web-fetch.mjs +271 -0
- package/src/core/ask/web-proposal.mjs +76 -0
- package/src/core/auto/classify.mjs +20 -8
- package/src/core/auto/runnable.mjs +28 -0
- package/src/core/billing.mjs +53 -0
- package/src/core/bridge/errors.mjs +77 -5
- package/src/core/bridge/openrouter.mjs +59 -0
- package/src/core/bridge/provider-ops.mjs +202 -10
- package/src/core/bridge/providers/endpoint.mjs +112 -7
- package/src/core/bridge/registry.mjs +13 -0
- package/src/core/bridge/server.mjs +16 -3
- package/src/core/bridge/telemetry.mjs +44 -12
- package/src/core/bridge/translate/common.mjs +31 -0
- package/src/core/bridge/translate/request.mjs +4 -1
- package/src/core/bridge/translate/response.mjs +3 -0
- package/src/core/bridge/translate/schema-keywords.mjs +75 -0
- package/src/core/bridge/translate/stream.mjs +50 -4
- package/src/core/bridge/upstream.mjs +102 -17
- package/src/core/broker-boot.mjs +57 -0
- package/src/core/broker-client.mjs +206 -0
- package/src/core/broker-guard.mjs +112 -0
- package/src/core/broker-routing.mjs +138 -0
- package/src/core/claude-auth.mjs +29 -0
- package/src/core/claude-runner.mjs +200 -9
- package/src/core/config.mjs +9 -12
- package/src/core/failure-policy.mjs +4 -2
- package/src/core/git-info.mjs +49 -5
- package/src/core/github-credentials.mjs +44 -1
- package/src/core/graph/script-runner.mjs +3 -1
- package/src/core/list-prices.mjs +29 -0
- package/src/core/mcp-secrets.mjs +80 -0
- package/src/core/metrics/sync.mjs +2 -1
- package/src/core/model-env.mjs +72 -0
- package/src/core/model-test.mjs +17 -5
- package/src/core/onboarding.mjs +12 -6
- package/src/core/openrouter-free.mjs +159 -0
- package/src/core/orchestrator.mjs +100 -12
- package/src/core/policy/effective.mjs +18 -1
- package/src/core/policy/local.mjs +4 -1
- package/src/core/policy/registry.mjs +12 -2
- package/src/core/preflight.mjs +116 -0
- package/src/core/recoverable-error.mjs +95 -0
- package/src/core/recovery-backoff.mjs +84 -0
- package/src/core/redact.mjs +25 -0
- package/src/core/run-context.mjs +6 -0
- package/src/core/run-harness.mjs +112 -30
- package/src/core/run-report.mjs +2 -1
- package/src/core/settings.mjs +90 -5
- package/src/core/title.mjs +7 -2
- package/src/core/web-allowlist.mjs +95 -0
- package/ui/public/app.js +271 -54
- package/ui/public/ask-model.mjs +1 -0
- package/ui/public/ask-panel.mjs +160 -23
- package/ui/public/bridge-view.mjs +216 -9
- package/ui/public/chat-settings-view.mjs +52 -1
- package/ui/public/credential-badges.mjs +63 -0
- package/ui/public/credentials-view.mjs +57 -0
- package/ui/public/index.html +303 -244
- package/ui/public/models-view.mjs +19 -1
- package/ui/public/openrouter-free-view.mjs +118 -0
- package/ui/public/stats-view.mjs +56 -0
- package/ui/public/style.css +110 -54
- package/ui/public/team-policy-view.mjs +2 -1
- package/ui/public/ws-seq.mjs +24 -0
- package/ui/server.mjs +319 -23
package/ui/public/style.css
CHANGED
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
--trunc-ink:light-dark(#994466,#E39BBE);
|
|
71
71
|
--chip-ink:light-dark(#555555,#B4B4AE);
|
|
72
72
|
|
|
73
|
-
--r-card:
|
|
74
|
-
--r-ctrl:
|
|
73
|
+
--r-card:14px;
|
|
74
|
+
--r-ctrl:10px;
|
|
75
75
|
--shadow:0 6px 28px light-dark(rgba(25,25,27,.05),rgba(0,0,0,.45)), 0 1px 2px light-dark(rgba(25,25,27,.04),rgba(0,0,0,.35));
|
|
76
76
|
--shadow-soft:0 2px 12px light-dark(rgba(25,25,27,.04),rgba(0,0,0,.35));
|
|
77
77
|
--shadow-pop:0 6px 28px light-dark(rgba(25,25,27,.10),rgba(0,0,0,.55)),0 1px 2px light-dark(rgba(25,25,27,.06),rgba(0,0,0,.4));
|
|
@@ -503,7 +503,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
503
503
|
|
|
504
504
|
/* @-mention popup: attached-file completions anchored under the prompt caret */
|
|
505
505
|
.mention-popup{position:fixed;z-index:70;min-width:180px;max-width:320px;max-height:210px;overflow-y:auto;
|
|
506
|
-
background:var(--panel);border:1px solid var(--line-2);border-radius:
|
|
506
|
+
background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-card);box-shadow:var(--shadow);padding:5px;}
|
|
507
507
|
.mention-item{display:block;width:100%;text-align:left;border:0;background:transparent;color:var(--ink-2);
|
|
508
508
|
font-family:inherit;font-weight:500;font-size:12.5px;padding:7px 10px;border-radius:8px;cursor:pointer;
|
|
509
509
|
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
@@ -622,7 +622,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
622
622
|
One collapsed row per agent showing its effective config; the controls only
|
|
623
623
|
exist once a row is opened, so the page height no longer grows with the
|
|
624
624
|
workflow. (newpipeline-ux-design.md §4.2) */
|
|
625
|
-
.agents-cfg{margin:6px 0 18px;border:1px solid var(--line);border-radius:
|
|
625
|
+
.agents-cfg{margin:6px 0 18px;border:1px solid var(--line);border-radius:var(--r-ctrl);overflow:hidden;background:var(--field);}
|
|
626
626
|
.agents-head{display:flex;align-items:center;gap:10px;padding:11px 14px;border-bottom:1px solid var(--line);}
|
|
627
627
|
.agents-title{font-weight:700;font-size:13px;}
|
|
628
628
|
.agents-wf{flex:0 0 auto;font-size:11.5px;font-weight:600;color:var(--ink-2);
|
|
@@ -727,7 +727,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
727
727
|
.btn-clear{background:var(--field);border:none;border-radius:10px;padding:8px 15px;font-family:inherit;
|
|
728
728
|
font-weight:600;font-size:12.5px;cursor:pointer;color:var(--ink-2);transition:.15s;}
|
|
729
729
|
.btn-clear:hover{background:var(--line-2);}
|
|
730
|
-
.log{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
730
|
+
.log{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);min-height:260px;max-height:380px;overflow-y:auto;
|
|
731
731
|
padding:18px 20px;font-family:var(--mono);font-size:12.5px;line-height:1.85;color:var(--ink-2);
|
|
732
732
|
white-space:pre-wrap;word-break:break-word;}
|
|
733
733
|
.log .t{color:var(--ink-3);}
|
|
@@ -762,7 +762,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
762
762
|
(design D14). Amber family; the circle inverts to --panel so it still reads
|
|
763
763
|
against the pale wash. */
|
|
764
764
|
.run-ask-banner{display:flex;align-items:center;gap:12px;margin:0 0 18px;padding:13px 18px;
|
|
765
|
-
background:var(--amber-wash);border:1px solid var(--amber);border-radius:
|
|
765
|
+
background:var(--amber-wash);border:1px solid var(--amber);border-radius:var(--r-card);}
|
|
766
766
|
.run-ask-banner[hidden]{display:none;} /* author display:flex beats the UA [hidden] rule */
|
|
767
767
|
.run-ask-banner .rab-mark{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
|
|
768
768
|
width:26px;height:26px;border-radius:50%;background:var(--panel);
|
|
@@ -773,7 +773,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
773
773
|
everything, amber like the other "needs you" banners. */
|
|
774
774
|
.session-expired{position:fixed;top:12px;left:50%;transform:translateX(-50%);z-index:10000;
|
|
775
775
|
display:flex;align-items:center;gap:14px;max-width:calc(100vw - 32px);padding:10px 12px 10px 18px;
|
|
776
|
-
background:var(--amber-wash);border:1px solid var(--amber);border-radius:
|
|
776
|
+
background:var(--amber-wash);border:1px solid var(--amber);border-radius:var(--r-card);
|
|
777
777
|
box-shadow:var(--shadow-pop);}
|
|
778
778
|
.session-expired .se-text{font-weight:500;font-size:13px;color:var(--amber-ink);}
|
|
779
779
|
.session-expired .se-reload{font:inherit;font-size:13px;font-weight:600;padding:6px 14px;border-radius:10px;
|
|
@@ -866,7 +866,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
|
|
|
866
866
|
first — keeping the prose free of them means a future sweep that forgets to
|
|
867
867
|
strip still passes. */
|
|
868
868
|
.qpanel{margin-top:18px;padding:14px 16px 13px;background:var(--amber-wash);
|
|
869
|
-
border:1px solid var(--amber-bg);border-radius:
|
|
869
|
+
border:1px solid var(--amber-bg);border-radius:var(--r-ctrl);}
|
|
870
870
|
.qpanel-head{display:flex;align-items:center;gap:11px;}
|
|
871
871
|
.qpanel-head svg{stroke:var(--amber-ink);flex:0 0 auto;}
|
|
872
872
|
.qpanel-head b{flex:1;min-width:0;font-weight:600;font-size:12.5px;color:var(--amber-ink);}
|
|
@@ -1237,7 +1237,7 @@ button.af-gal-card:focus-visible{outline:2px solid var(--ink);outline-offset:2px
|
|
|
1237
1237
|
.hist-head .h-meta b{cursor:pointer;}
|
|
1238
1238
|
.hist-head .h-meta b:hover{text-decoration:underline;}
|
|
1239
1239
|
.retained-banner{margin:0 0 18px;padding:16px 18px;border:1.5px solid var(--amber);
|
|
1240
|
-
border-radius:
|
|
1240
|
+
border-radius:var(--r-card);background:var(--amber-bg);color:var(--amber-ink);font-size:12.5px;line-height:1.55;}
|
|
1241
1241
|
.retained-banner[hidden]{display:none;}
|
|
1242
1242
|
.retained-banner h4{margin:0 0 6px;font-size:14px;color:var(--amber-ink);}
|
|
1243
1243
|
.retained-banner p{margin:5px 0;}
|
|
@@ -1273,7 +1273,7 @@ button.af-gal-card:focus-visible{outline:2px solid var(--ink);outline-offset:2px
|
|
|
1273
1273
|
|
|
1274
1274
|
/* ---------- Saved-markdown viewer ---------- */
|
|
1275
1275
|
.viewer{font-family:var(--mono);font-size:12.5px;line-height:1.7;background:var(--canvas-2);border:1px solid var(--line);
|
|
1276
|
-
border-radius:
|
|
1276
|
+
border-radius:var(--r-card);padding:18px 20px;max-height:480px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:0;}
|
|
1277
1277
|
|
|
1278
1278
|
/* ---------- scrollbars ---------- */
|
|
1279
1279
|
::-webkit-scrollbar{width:10px;height:10px;}
|
|
@@ -1334,7 +1334,7 @@ button.af-gal-card:focus-visible{outline:2px solid var(--ink);outline-offset:2px
|
|
|
1334
1334
|
.topnav{display:none;}
|
|
1335
1335
|
@media (max-width:1080px){
|
|
1336
1336
|
.topnav{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:20px;background:var(--panel);
|
|
1337
|
-
border:1px solid var(--line);border-radius:
|
|
1337
|
+
border:1px solid var(--line);border-radius:var(--r-card);padding:5px;}
|
|
1338
1338
|
.topnav button{flex:1;text-align:center;padding:9px 12px;border:0;border-radius:10px;
|
|
1339
1339
|
background:transparent;color:var(--ink-2);font-family:inherit;font-weight:600;font-size:13px;
|
|
1340
1340
|
cursor:pointer;transition:.15s;}
|
|
@@ -1562,6 +1562,10 @@ button.wd-member:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;
|
|
|
1562
1562
|
.wiz-proj:hover{background:var(--surface);}
|
|
1563
1563
|
.wiz-proj input{margin:0;cursor:pointer;}
|
|
1564
1564
|
.wiz-proj.missing{color:var(--ink-3);cursor:not-allowed;}
|
|
1565
|
+
.wiz-proj-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;}
|
|
1566
|
+
.wiz-select-all{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-2);cursor:pointer;}
|
|
1567
|
+
.wiz-select-all input{margin:0;cursor:pointer;}
|
|
1568
|
+
.wiz-select-all:has(input:disabled){opacity:.5;cursor:not-allowed;}
|
|
1565
1569
|
|
|
1566
1570
|
/* Live scan loader (role=status aria-live=polite). */
|
|
1567
1571
|
.ws-loader{display:flex;flex-direction:column;align-items:center;gap:12px;padding:36px 24px;text-align:center;}
|
|
@@ -1595,7 +1599,7 @@ button.wd-member:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;
|
|
|
1595
1599
|
/* ties `.gv-world .node` and loses on source order — silently killing the v2 */
|
|
1596
1600
|
/* status border colours. */
|
|
1597
1601
|
/* ========================================================================== */
|
|
1598
|
-
.run-flow-wrap{position:relative;margin:0 0 18px;border-radius:
|
|
1602
|
+
.run-flow-wrap{position:relative;margin:0 0 18px;border-radius:var(--r-card);border:1px solid var(--line);overflow-x:auto;overflow-y:hidden;background-color:var(--canvas-2);background-image:radial-gradient(circle, var(--line-2) 1.1px, transparent 1.1px);background-size:22px 22px;}
|
|
1599
1603
|
.run-flow{position:relative;display:flex;align-items:center;gap:44px;padding:66px 30px 52px;width:max-content;min-width:100%;}
|
|
1600
1604
|
/* Status badge (top-right pip). */
|
|
1601
1605
|
.run-flow .nstat{position:absolute;top:-8px;right:-8px;width:21px;height:21px;border-radius:50%;display:grid;place-items:center;box-shadow:var(--shadow-soft);z-index:3;}
|
|
@@ -1874,7 +1878,7 @@ input.bench-case-name{width:100%;padding:9px 12px;font-size:13px;}
|
|
|
1874
1878
|
.wz-pick-line{font-size:14px;color:var(--ink-2);}
|
|
1875
1879
|
.wz-rt-cards{display:flex;gap:20px;width:100%;max-width:1080px;}
|
|
1876
1880
|
@media (max-width:900px){.wz-rt-cards{flex-direction:column;}}
|
|
1877
|
-
.wz .rt{display:flex;flex-direction:column;gap:12px;flex:1 1 0;min-width:0;min-height:250px;padding:22px;border-radius:
|
|
1881
|
+
.wz .rt{display:flex;flex-direction:column;gap:12px;flex:1 1 0;min-width:0;min-height:250px;padding:22px;border-radius:var(--r-card);background:var(--panel);border:2px solid transparent;box-shadow:var(--shadow);cursor:pointer;text-align:left;font-family:inherit;color:var(--ink);}
|
|
1878
1882
|
.wz .rt:hover:not(:disabled){transform:translateY(-1px);}
|
|
1879
1883
|
.wz .rt.sel{border-color:var(--ink);}
|
|
1880
1884
|
.wz .rt:disabled{opacity:.45;cursor:not-allowed;}
|
|
@@ -1890,7 +1894,7 @@ input.bench-case-name{width:100%;padding:9px 12px;font-size:13px;}
|
|
|
1890
1894
|
.wz .panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
|
|
1891
1895
|
.wz-panel-title{font-size:13.5px;font-weight:600;}
|
|
1892
1896
|
.wz-tile{display:flex;align-items:center;gap:14px;padding:14px 16px;}
|
|
1893
|
-
.wz .tile{width:48px;height:48px;border-radius:
|
|
1897
|
+
.wz .tile{width:48px;height:48px;border-radius:var(--r-ctrl);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;}
|
|
1894
1898
|
.wz .tile-green{background:var(--green-bg);color:var(--green-ink);}.wz .tile-peach{background:var(--peach-bg);color:var(--peach-ink);}
|
|
1895
1899
|
.wz .tile-red{background:var(--red-bg);color:var(--red-ink);}.wz .tile-blue{background:var(--blue-bg);color:var(--blue-ink);}
|
|
1896
1900
|
.wz .tile-violet{background:var(--violet-bg);color:var(--violet-ink);}.wz .tile-amber{background:var(--amber-bg);color:var(--amber-ink);}
|
|
@@ -2262,6 +2266,21 @@ button.pd-ov-card:hover{border-color:var(--ink-3);}
|
|
|
2262
2266
|
without this the rows touch while every other gap is 14px. */
|
|
2263
2267
|
.charts-grid + .charts-grid{margin-top:14px;}
|
|
2264
2268
|
.chart-card{padding:20px 22px;}
|
|
2269
|
+
/* Stats › By person (credential broker): one full-width card, a table with a share bar. */
|
|
2270
|
+
.people-grid{grid-template-columns:1fr;}
|
|
2271
|
+
.people-scroll{overflow-x:auto;}
|
|
2272
|
+
.people-table{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums;}
|
|
2273
|
+
.people-table th{text-align:left;font-weight:500;color:var(--ink-3);font-size:12px;padding:6px 10px 6px 0;border-bottom:1px solid var(--line);white-space:nowrap;}
|
|
2274
|
+
.people-table td{padding:8px 10px 8px 0;border-bottom:1px solid var(--line);vertical-align:middle;}
|
|
2275
|
+
.people-table tr:last-child td{border-bottom:none;}
|
|
2276
|
+
.people-table td.num{white-space:nowrap;color:var(--ink-2);}
|
|
2277
|
+
.people-name{overflow-wrap:anywhere;}
|
|
2278
|
+
.people-spend{min-width:160px;}
|
|
2279
|
+
.people-usd{display:inline-block;min-width:64px;font-weight:600;}
|
|
2280
|
+
.people-bar{display:inline-block;vertical-align:middle;width:90px;height:6px;border-radius:3px;background:var(--line);margin-left:8px;overflow:hidden;}
|
|
2281
|
+
.people-bar-fill{display:block;height:100%;background:var(--blue);}
|
|
2282
|
+
.people-slots{color:var(--ink-2);}
|
|
2283
|
+
.people-card > .hint{display:block;margin-top:10px;}
|
|
2265
2284
|
.chart-fig{margin:0;}
|
|
2266
2285
|
.chart-svg{display:block;width:100%;height:auto;}
|
|
2267
2286
|
.chart-empty{display:grid;place-items:center;min-height:180px;}
|
|
@@ -2291,7 +2310,7 @@ button.pd-ov-card:hover{border-color:var(--ink-3);}
|
|
|
2291
2310
|
.tm-sync-error{white-space:pre-wrap;margin:0;}
|
|
2292
2311
|
section[data-view="team-metrics"] .topbar{align-items:flex-start;}
|
|
2293
2312
|
.sync-chip{margin-left:auto;display:flex;align-items:center;}
|
|
2294
|
-
.sync-chip-inner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;padding:8px 12px;border:1px solid var(--line-2);border-radius:
|
|
2313
|
+
.sync-chip-inner{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;padding:8px 12px;border:1px solid var(--line-2);border-radius:var(--r-card);background:var(--surface);font-size:12.5px;max-width:520px;}
|
|
2295
2314
|
.sync-chip-inner .dot.green{background:var(--green);} .sync-chip-inner .dot.amber{background:var(--amber);} .sync-chip-inner .dot.red{background:var(--red);}
|
|
2296
2315
|
.sync-chip-inner .tm-sync-error{flex-basis:100%;color:var(--red-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
2297
2316
|
.tm-filter{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:18px;}
|
|
@@ -2338,6 +2357,13 @@ section[data-view="team-metrics"] .topbar{align-items:flex-start;}
|
|
|
2338
2357
|
/* Actor and Started never wrap: with the Saved column in, Title (ellipsis) and Workflow give way first. */
|
|
2339
2358
|
.tm-run-tbl td:nth-last-child(-n+2){white-space:nowrap;}
|
|
2340
2359
|
.badge.grey{background:var(--field);color:var(--ink-2);}
|
|
2360
|
+
/* The Copilot card's "read the notice first" pill is a button: it opens the notice (bridge-view.mjs). */
|
|
2361
|
+
.mv-cp-terms-pill{border:0;font-family:inherit;cursor:pointer;}
|
|
2362
|
+
.mv-cp-terms-pill:hover{background:var(--line);color:var(--ink);}
|
|
2363
|
+
.mv-cp-terms-pill:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
|
|
2364
|
+
/* With the credential broker, a provider pill for a missing key links to the key page. */
|
|
2365
|
+
.mv-broker-pill{text-decoration:none;cursor:pointer;}
|
|
2366
|
+
.mv-broker-pill:hover{text-decoration:underline;}
|
|
2341
2367
|
.tm-empty{display:grid;grid-template-columns:1fr 1fr;gap:14px;} .tm-empty .card{padding:22px;}
|
|
2342
2368
|
.tm-step{font-size:11px;letter-spacing:.08em;font-weight:700;color:var(--ink-2);}
|
|
2343
2369
|
.tm-empty-foot{display:block;margin-top:14px;}
|
|
@@ -2451,7 +2477,7 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2451
2477
|
.tl-lg-sw .tl-span,.tl-lg-sw .tl-run{height:12px;margin-top:-6px;}
|
|
2452
2478
|
.tl-foot{display:block;color:var(--ink-2);}
|
|
2453
2479
|
|
|
2454
|
-
.tl-pop{position:fixed;z-index:60;width:340px;max-width:calc(100vw - 32px);background:var(--panel);border:1px solid var(--line);border-radius:
|
|
2480
|
+
.tl-pop{position:fixed;z-index:60;width:340px;max-width:calc(100vw - 32px);background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
|
|
2455
2481
|
box-shadow:var(--shadow-sheet);padding:16px 18px;display:flex;flex-direction:column;gap:10px;}
|
|
2456
2482
|
.tl-pop h3{margin:0;font-size:16px;font-weight:600;line-height:1.3;text-wrap:balance;}
|
|
2457
2483
|
.tl-pop-top{display:flex;align-items:center;justify-content:space-between;gap:8px;}
|
|
@@ -2504,7 +2530,7 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2504
2530
|
.tm-dot.green{background:var(--green);} .tm-dot.amber{background:var(--amber);} .tm-dot.red{background:var(--red);} .tm-dot.grey{background:var(--ink-3);}
|
|
2505
2531
|
/* Enable dialog (boards 5/6) */
|
|
2506
2532
|
/* `.field > label` (display:block, margin-bottom) would otherwise beat this and stack the radio above the title */
|
|
2507
|
-
.radio-card,.field > label.radio-card{display:flex;gap:12px;align-items:flex-start;padding:12px 14px;border:1.5px solid var(--line-2);border-radius:var(--r-ctrl,
|
|
2533
|
+
.radio-card,.field > label.radio-card{display:flex;gap:12px;align-items:flex-start;padding:12px 14px;border:1.5px solid var(--line-2);border-radius:var(--r-ctrl,10px);margin:8px 0 0;cursor:pointer;font-weight:500;font-size:13px;}
|
|
2508
2534
|
.radio-card input[type="radio"]{flex:0 0 auto;margin:2px 0 0;}
|
|
2509
2535
|
/* :has(), not a render-time .on class: changing the Attribution radio does not re-render the body */
|
|
2510
2536
|
.radio-card:has(> input:checked){border-color:var(--ink);background:var(--field);}
|
|
@@ -2516,7 +2542,7 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2516
2542
|
.wiz-track{display:flex;gap:18px;list-style:none;padding:0;margin:0 0 18px;font-size:12.5px;color:var(--ink-2);}
|
|
2517
2543
|
.wiz-track li span{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--field);margin-right:6px;font-weight:700;}
|
|
2518
2544
|
.wiz-track li.on{color:var(--ink);font-weight:600;} .wiz-track li.on span{background:var(--ink);color:var(--on-ink);}
|
|
2519
|
-
.wiz-list{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:
|
|
2545
|
+
.wiz-list{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r-ctrl);}
|
|
2520
2546
|
.wiz-row{display:flex;align-items:center;gap:14px;padding:12px 14px;border-top:1px solid var(--line);}
|
|
2521
2547
|
/* The metrics-home picker's radio + slug: the label had no rule, so the radio touched the text. */
|
|
2522
2548
|
.wiz-row-pick{display:flex;align-items:center;gap:10px;min-width:0;cursor:pointer;}
|
|
@@ -2590,6 +2616,8 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2590
2616
|
fill (--line), under verify:theme's 4.5:1. A loss keeps neutral ink (--red-ink is
|
|
2591
2617
|
4.07:1 there); its "−" carries it. */
|
|
2592
2618
|
.spend-ind-saved{margin-top:6px;}
|
|
2619
|
+
/* OpenRouter free-model requests (openrouter-free-view.mjs): a second block under the spend block. */
|
|
2620
|
+
.free-ind{margin-top:8px;}
|
|
2593
2621
|
.spend-ind-saved.pos .spend-ind-label,.spend-ind-saved.pos .spend-ind-amt{color:var(--green-ink-strong);}
|
|
2594
2622
|
.topnav-amt{margin-left:7px;font-family:var(--mono);font-weight:600;}
|
|
2595
2623
|
.topnav-amt.warn{color:var(--amber-ink);}
|
|
@@ -2600,6 +2628,26 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2600
2628
|
/* One width/centering/gap rule for every Settings card. */
|
|
2601
2629
|
.settings-card{max-width:760px;padding:22px;margin-left:auto;margin-right:auto;}
|
|
2602
2630
|
.settings-card + .settings-card{margin-top:18px;}
|
|
2631
|
+
.settings-card[hidden]{display:none;}
|
|
2632
|
+
/* Settings › Models: Title generation + Auto workflow model side by side above the catalog, so two
|
|
2633
|
+
short cards do not push it a screen down; one column once they would squeeze. */
|
|
2634
|
+
.models-helpers{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:18px;margin-bottom:18px;}
|
|
2635
|
+
.models-helpers > .settings-card{max-width:none;margin:0;}
|
|
2636
|
+
|
|
2637
|
+
/* My model credentials (credential broker): one row per slot, a state chip on the right. */
|
|
2638
|
+
.cred-list{list-style:none;margin:0;padding:0;display:grid;gap:8px;}
|
|
2639
|
+
.cred-row{display:flex;justify-content:space-between;align-items:center;gap:12px;font-size:13px;}
|
|
2640
|
+
.cred-name{min-width:0;overflow-wrap:anywhere;}
|
|
2641
|
+
.cred-chip{font-size:12px;font-weight:600;padding:3px 9px;border-radius:999px;white-space:nowrap;}
|
|
2642
|
+
.cred-chip.tone-green{background:var(--green-bg);color:var(--green-ink);}
|
|
2643
|
+
.cred-chip.tone-red{background:var(--red-bg);color:var(--red-ink);}
|
|
2644
|
+
.cred-chip.tone-blue{background:var(--blue-bg);color:var(--blue-ink);}
|
|
2645
|
+
.cred-chip.tone-slate{background:var(--slate-bg);color:var(--slate-ink);}
|
|
2646
|
+
.cred-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:14px;}
|
|
2647
|
+
/* Providers card with the credential broker: keys, sign-in and key tests live on the key page. */
|
|
2648
|
+
.mv-providers--broker .mv-cp-signin,.mv-providers--broker .mv-cp-signout,.mv-providers--broker .mv-cp-quota-refresh,
|
|
2649
|
+
.mv-providers--broker .mv-cp-quota,.mv-providers--broker .mv-pv-test,.mv-providers--broker .mv-field:has(.mv-pv-key){display:none;}
|
|
2650
|
+
.mv-broker-note{display:block;margin:6px 0 12px;}
|
|
2603
2651
|
|
|
2604
2652
|
/* About card rows. .about-val and .about-link share specificity on one anchor, so
|
|
2605
2653
|
.about-link must stay AFTER .about-val (test/ui-settings-about.test.mjs pins it). */
|
|
@@ -2640,6 +2688,9 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2640
2688
|
.pause-error-banner .peb-text{color:var(--ink);font-family:var(--mono);font-size:12px;word-break:break-word;}
|
|
2641
2689
|
.pause-error-banner .peb-hint{color:var(--ink-2);margin-top:6px;}
|
|
2642
2690
|
.hd-banners .pause-error-banner,.rd-banners .pause-error-banner{align-self:stretch;margin:0;}
|
|
2691
|
+
/* In a run card these banners are nested boxes (--r-ctrl); in the page-level banner
|
|
2692
|
+
stacks they sit on .retained-banner, so they take its card radius. */
|
|
2693
|
+
.hd-banners .cost-banner,.hd-banners .pause-error-banner,.rd-banners .cost-banner,.rd-banners .pause-error-banner{border-radius:var(--r-card);}
|
|
2643
2694
|
|
|
2644
2695
|
@media (max-width:1080px){
|
|
2645
2696
|
.stat-row{grid-template-columns:repeat(2,1fr);}
|
|
@@ -2724,6 +2775,9 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2724
2775
|
bridge's copy uses --ink-2 (6.5:1) so the theme proof passes without a new entry. */
|
|
2725
2776
|
.mv-providers .hint,.mv-conn .hint,.mv-degradation,.mvi .hint,.mv-cp-signin-box .hint{color:var(--ink-2);}
|
|
2726
2777
|
.mv-pv-row .input::placeholder,.mv-conn .input::placeholder,.mv-conn .textarea::placeholder{color:var(--ink-2);}
|
|
2778
|
+
/* Settings → Ask Worca → Web access: its fields are new, so their placeholders use --ink-2 like the rule
|
|
2779
|
+
above instead of joining the legacy light contrast baseline (the allowlist textarea failed at 2.58:1). */
|
|
2780
|
+
.ask-web .input::placeholder{color:var(--ink-2);}
|
|
2727
2781
|
.mv-providers .mv-providers-hint{margin:-6px 0 0;}
|
|
2728
2782
|
.mv-pv-row{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);gap:12px 18px;padding:14px 0 0;border-top:1px solid var(--line-2);}
|
|
2729
2783
|
.mv-pv-main{display:grid;gap:6px;align-content:start;min-width:0;}
|
|
@@ -2782,12 +2836,12 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2782
2836
|
.mv-section-head{display:flex;align-items:center;gap:8px;}
|
|
2783
2837
|
.mv-sec-toggle{display:flex;align-items:center;gap:8px;padding:2px 0;border:0;background:transparent;cursor:pointer;color:inherit;font:inherit;}
|
|
2784
2838
|
.mv-sec-toggle .mv-section-title{margin:0;}
|
|
2785
|
-
.mv-sec-caret{
|
|
2839
|
+
.mv-sec-caret{flex:0 0 auto;transform:rotate(90deg);} /* .adv-chev: points right; a group is open unless folded */
|
|
2786
2840
|
.mv-sec-count{padding:1px 8px;border-radius:999px;background:var(--field);color:var(--ink-2);font:600 11px var(--mono);}
|
|
2787
|
-
.mv-section.is-folded .mv-sec-caret{transform:
|
|
2841
|
+
.mv-section.is-folded .mv-sec-caret{transform:none;}
|
|
2788
2842
|
.mv-section.is-folded .mv-sec-body,.mv-section.is-folded .mv-sec-hint{display:none;}
|
|
2789
2843
|
.mv-no-hits{margin-top:6px;}
|
|
2790
|
-
@media (prefers-reduced-motion: reduce){.mv-sec-caret{transition:none;}}
|
|
2844
|
+
@media (prefers-reduced-motion: reduce){.mv-sec-caret,.advanced .adv-chev{transition:none;}}
|
|
2791
2845
|
.mv-pv-btns .btn-ghost,.mv-pv-btns .btn-go{padding:7px 12px;font-size:12px;}
|
|
2792
2846
|
.mv-pv-row .input,.mv-pv-row .select{font-family:var(--mono);font-size:12.5px;padding:9px 12px;}
|
|
2793
2847
|
.mv-pv-row .mv-pv-conc{max-width:120px;}
|
|
@@ -2826,6 +2880,10 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2826
2880
|
.mv-conn-note{margin:0;}
|
|
2827
2881
|
.mvi-tbl{margin-top:8px;}
|
|
2828
2882
|
.mvi-tbl td{vertical-align:top;}
|
|
2883
|
+
/* A hosted catalog's filters (OpenRouter lists hundreds): the shared .chip-select pills, one row. */
|
|
2884
|
+
.mvi-or-filters{margin-top:10px;}
|
|
2885
|
+
.mvi-or-filters .mvi-f-ctx{padding:2px 6px;font-size:12.5px;min-height:0;}
|
|
2886
|
+
.mv-pv-presets{display:block;margin-top:4px;}
|
|
2829
2887
|
.mvi-tbl .mvi-id{display:block;margin:2px 0 0;font-family:var(--mono);}
|
|
2830
2888
|
.mvi-tbl tr.mvi-disabled{opacity:.55;}
|
|
2831
2889
|
.mvi-status{color:var(--ink-3);font-size:12px;}
|
|
@@ -2968,7 +3026,7 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
2968
3026
|
.hd-more:hover,.hd-more[aria-expanded="true"]{background:var(--field);border-color:var(--ink-3);}
|
|
2969
3027
|
.hd-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:5;min-width:214px;
|
|
2970
3028
|
display:flex;flex-direction:column;gap:2px;padding:6px;background:var(--panel);
|
|
2971
|
-
border:1px solid var(--line-2);border-radius:
|
|
3029
|
+
border:1px solid var(--line-2);border-radius:var(--r-card);box-shadow:var(--shadow-menu);}
|
|
2972
3030
|
.hd-menu[hidden]{display:none;}
|
|
2973
3031
|
/* Both items shed their pill dressing in here and become full-width rows. Higher
|
|
2974
3032
|
specificity than the standalone rules above, which still hold nowhere else. */
|
|
@@ -3147,7 +3205,7 @@ button.tl-tile[aria-pressed="true"]{border-color:var(--ink);}
|
|
|
3147
3205
|
reply row draws its own elbow, exactly like `.nav-child` under Running. */
|
|
3148
3206
|
.hd-cmt-thread{position:relative;display:flex;flex-direction:column;max-width:720px;
|
|
3149
3207
|
animation:wr-rise .18s cubic-bezier(.2,.7,.3,1) both;}
|
|
3150
|
-
.hd-cmt-card{background:var(--surface);border:1px solid var(--line);border-radius:
|
|
3208
|
+
.hd-cmt-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--shadow-soft);}
|
|
3151
3209
|
.hd-cmt-block>.hd-cmt-card{max-width:720px;}
|
|
3152
3210
|
.hd-cmt-head{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px;min-height:20px;
|
|
3153
3211
|
padding:12px 14px 0;font-size:11px;color:var(--ink-2);}
|
|
@@ -3443,7 +3501,7 @@ button.hd-mem-chip:focus-visible{outline:2px solid var(--ink);outline-offset:2px
|
|
|
3443
3501
|
view's, and `.run-log .log` keeps its own sizes there (D7 — the Running view is
|
|
3444
3502
|
untouched). Neither rule sets `display`, so `.hd-sec[hidden]` (:1703) still hides
|
|
3445
3503
|
the whole panel and no `[hidden]` twin is needed. */
|
|
3446
|
-
.hd-sec-logs .log{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
3504
|
+
.hd-sec-logs .log{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
|
|
3447
3505
|
min-height:260px;max-height:520px;overflow-y:auto;padding:18px 20px;}
|
|
3448
3506
|
.hd-sec-logs .log-filters{margin-bottom:10px;}
|
|
3449
3507
|
|
|
@@ -3481,7 +3539,7 @@ button.hd-mem-chip:focus-visible{outline:2px solid var(--ink);outline-offset:2px
|
|
|
3481
3539
|
.shipit-card h2{margin:18px 0 0;font:700 20px/1.25 var(--sans);letter-spacing:-.02em;}
|
|
3482
3540
|
.shipit-sub{margin:8px 0 0;font:400 13.5px/1.6 var(--sans);color:var(--ink-2);}
|
|
3483
3541
|
.shipit-summary{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:8px;
|
|
3484
|
-
margin-top:18px;padding:14px;background:var(--field);border-radius:
|
|
3542
|
+
margin-top:18px;padding:14px;background:var(--field);border-radius:var(--r-ctrl);font-size:12px;color:var(--ink-2);}
|
|
3485
3543
|
.shipit-summary[hidden]{display:none;}
|
|
3486
3544
|
/* An empty flex child still eats a `gap`, so a results-less run ("+12 −3", no file
|
|
3487
3545
|
count) would render a stray 8px hole. Hide the value spans by NAME — a blanket
|
|
@@ -3798,7 +3856,7 @@ body.view-running .topnav{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
3798
3856
|
|
|
3799
3857
|
/* ---------- Running detail: pipeline graph ---------- */
|
|
3800
3858
|
/* The dot-grid panel spec §5.3 asks for is already `.run-flow-wrap` —
|
|
3801
|
-
radial-gradient var(--line-2) 1.1px at 22px 22px,
|
|
3859
|
+
radial-gradient var(--line-2) 1.1px at 22px 22px, --r-card radius, horizontal
|
|
3802
3860
|
scroll. This only supplies the margin box; the wrap's own legacy
|
|
3803
3861
|
`margin:0 0 18px` is zeroed so it does not double up with .rd-graph's. */
|
|
3804
3862
|
.rd-graph{margin-top:18px;}
|
|
@@ -3870,12 +3928,12 @@ body.view-running .topnav{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
3870
3928
|
.rd-sec[hidden]{display:none;}
|
|
3871
3929
|
.rd-sec:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
|
|
3872
3930
|
|
|
3873
|
-
/* Live log tab (§5.6): white pane, --line border,
|
|
3931
|
+
/* Live log tab (§5.6): white pane, --line border, --r-card radius, bounded height.
|
|
3874
3932
|
The pane is the shared `.log` markup inside a `.run-log` block, so `.run-log .log`
|
|
3875
3933
|
is (0,2,0) and so is this — source order is what makes it win, which is why the
|
|
3876
3934
|
rule lives at the END of the file and must not be moved above it. */
|
|
3877
3935
|
.rd-sec-logs .log{min-height:300px;max-height:520px;
|
|
3878
|
-
background:var(--panel);border:1px solid var(--line);border-radius:
|
|
3936
|
+
background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
|
|
3879
3937
|
/* §9's fourth keyframe: the blinking green caret at the tail of a LIVE log.
|
|
3880
3938
|
CSS-only (a ::after on the pane) so no JS has to keep an element last after
|
|
3881
3939
|
every append; Task 9 stamps `.rd-terminal` on the screen when the run ends and
|
|
@@ -3984,7 +4042,7 @@ body.view-running .topnav{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
3984
4042
|
.stop-card{padding:24px;animation:wr-rise .28s cubic-bezier(.2,.7,.3,1) both;}
|
|
3985
4043
|
.stop-title{margin:0 0 12px;font:700 17px/1.25 var(--sans);letter-spacing:-.015em;}
|
|
3986
4044
|
.stop-body{margin:0;font:400 13.5px/1.6 var(--sans);color:var(--ink-2);}
|
|
3987
|
-
.stop-ident{margin-top:14px;padding:11px 13px;background:var(--field);border-radius:
|
|
4045
|
+
.stop-ident{margin-top:14px;padding:11px 13px;background:var(--field);border-radius:var(--r-ctrl);
|
|
3988
4046
|
font:400 12px/1.6 var(--mono);color:var(--ink-2);word-break:break-all;}
|
|
3989
4047
|
/* author display rule beats the UA [hidden] rule — a branch-less run must not
|
|
3990
4048
|
leave a blank mono line in the block */
|
|
@@ -4363,7 +4421,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4363
4421
|
attribute from its ledger of rows the transcript has shown before, and on
|
|
4364
4422
|
nothing else. */
|
|
4365
4423
|
.ask-msg[data-ask-enter]{animation:wr-rise .2s cubic-bezier(.2,.7,.3,1) both;}
|
|
4366
|
-
.ask-user-bubble{align-self:flex-end;max-width:78%;padding:10px 14px;border-radius:
|
|
4424
|
+
.ask-user-bubble{align-self:flex-end;max-width:78%;padding:10px 14px;border-radius:var(--r-card) var(--r-card) 4px var(--r-card);
|
|
4367
4425
|
background:var(--field);color:var(--ink);font-size:13.5px;line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere;}
|
|
4368
4426
|
.ask-user-pills{justify-content:flex-end;margin-top:0;}
|
|
4369
4427
|
.ask-attachment-pill{padding-right:12px;}
|
|
@@ -4461,7 +4519,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4461
4519
|
.ask-error-line{font-size:12.5px;color:var(--red-ink);}
|
|
4462
4520
|
|
|
4463
4521
|
.ask-card{margin-top:2px;display:flex;flex-direction:column;gap:10px;padding:13px 15px;
|
|
4464
|
-
border:1.5px solid var(--line);border-radius:
|
|
4522
|
+
border:1.5px solid var(--line);border-radius:var(--r-card);background:var(--panel);}
|
|
4465
4523
|
.ask-card-seg{display:flex;gap:4px;}
|
|
4466
4524
|
.ask-card-seg-btn{padding:5px 12px;border:1px solid var(--line-2);border-radius:999px;background:transparent;
|
|
4467
4525
|
color:var(--ink-2);font-family:inherit;font-weight:600;font-size:11px;cursor:pointer;transition:.15s;}
|
|
@@ -4493,7 +4551,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4493
4551
|
/* ---------- run proposal card v2 (ui/public/ask-panel.mjs buildCardForm; mockup 2026-09-06) ----------
|
|
4494
4552
|
The v1 card rules above still apply to this root (.ask-card); every override below
|
|
4495
4553
|
is written at higher specificity than the rule it replaces. Tokens only. */
|
|
4496
|
-
.ask-card.ask-rp{gap:0;padding:0;overflow:hidden;border-radius:
|
|
4554
|
+
.ask-card.ask-rp{gap:0;padding:0;overflow:hidden;border-radius:var(--r-card);border:1.5px solid var(--line-2);box-shadow:var(--shadow-soft);animation:wr-rise .26s cubic-bezier(.2,.7,.3,1) both;}
|
|
4497
4555
|
.ask-rp>*{min-width:0;}
|
|
4498
4556
|
.ask-rp-head{padding:16px 18px 14px;background:linear-gradient(180deg,var(--violet-wash),var(--panel) 92%);border-bottom:1px solid var(--line);}
|
|
4499
4557
|
.ask-rp-eyebrow{display:flex;align-items:center;gap:8px;height:20px;}
|
|
@@ -4523,7 +4581,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4523
4581
|
.ask-rp .ask-rp-title input:focus-visible{box-shadow:none;outline:none;border-bottom-color:var(--violet);background:transparent;}
|
|
4524
4582
|
.ask-rp-wfdesc{font-size:11.5px;color:var(--ink-3);}
|
|
4525
4583
|
.ask-rp-wfdesc b{font-weight:600;color:var(--ink-2);}
|
|
4526
|
-
.ask-rp-agents{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:
|
|
4584
|
+
.ask-rp-agents{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r-ctrl);overflow:hidden;background:var(--canvas-2);}
|
|
4527
4585
|
.ask-rp-tile{display:flex;flex-direction:column;gap:8px;padding:10px 14px;border-top:1px solid var(--line);background:var(--panel);}
|
|
4528
4586
|
.ask-rp-tile:first-child{border-top:0;}
|
|
4529
4587
|
.ask-rp-tile.mod{background:var(--amber-wash);}
|
|
@@ -4572,7 +4630,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4572
4630
|
.ask-rp-foot .ask-card-start svg{width:11px;height:11px;}
|
|
4573
4631
|
.ask-rp .ask-card-err{padding:0 18px 10px;}
|
|
4574
4632
|
.ask-rp .ask-card-scope-warn{margin:12px 18px 0;}
|
|
4575
|
-
.ask-pop-at{width:288px;padding:6px;border-radius:
|
|
4633
|
+
.ask-pop-at{width:288px;padding:6px;border-radius:var(--r-card);max-height:min(320px,60%);overflow-y:auto;}
|
|
4576
4634
|
@media (max-width:640px){.ask-rp-grid,.ask-rp-grid.two{grid-template-columns:1fr;}}
|
|
4577
4635
|
@media (prefers-reduced-motion: reduce){.ask-card.ask-rp{animation:none;} .ask-rp *{transition:none!important;}}
|
|
4578
4636
|
|
|
@@ -4731,7 +4789,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4731
4789
|
the contrast baseline (scripts/verify-theme-cdp.mjs) it has today. */
|
|
4732
4790
|
.ask-composer{position:relative;flex:0 0 auto;padding:10px 16px 14px;display:flex;flex-direction:column;}
|
|
4733
4791
|
.ask-composer-box{width:100%;max-width:var(--ask-col-max);margin-inline:auto;padding:8px 10px;
|
|
4734
|
-
border:1px solid var(--line-2);border-radius:
|
|
4792
|
+
border:1px solid var(--line-2);border-radius:var(--r-card);background:var(--panel);
|
|
4735
4793
|
display:flex;flex-direction:column;gap:4px;}
|
|
4736
4794
|
.ask-chips{display:flex;flex-wrap:wrap;gap:6px;padding:2px 4px 4px;}
|
|
4737
4795
|
.ask-chips[hidden]{display:none;}
|
|
@@ -4776,19 +4834,19 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4776
4834
|
.ask-wt-btn[hidden]{display:none;}
|
|
4777
4835
|
|
|
4778
4836
|
.ask-pop{position:absolute;z-index:3;background:var(--panel);border:1px solid var(--line-2);
|
|
4779
|
-
padding:6px;box-shadow:var(--shadow-menu);border-radius:
|
|
4837
|
+
padding:6px;box-shadow:var(--shadow-menu);border-radius:var(--r-card);}
|
|
4780
4838
|
.ask-pop-threads{top:46px;right:76px;width:326px;}
|
|
4781
4839
|
/* The composer popovers hug the box (--ask-col-inset, see .ask-sheet) and float
|
|
4782
4840
|
just above it (--ask-box-top); agents/worktrees keep their old offsets left of
|
|
4783
4841
|
the model popover. */
|
|
4784
4842
|
.ask-pop-scope{left:var(--ask-col-inset);bottom:calc(var(--ask-box-top) + 6px);width:300px;max-height:min(420px,70%);overflow-y:auto;}
|
|
4785
|
-
.ask-pop-model{right:var(--ask-col-inset);bottom:calc(var(--ask-box-top) + 6px);width:292px;border-radius:
|
|
4843
|
+
.ask-pop-model{right:var(--ask-col-inset);bottom:calc(var(--ask-box-top) + 6px);width:292px;border-radius:var(--r-card);}
|
|
4786
4844
|
.ask-pop-runinfo{right:calc(var(--ask-col-inset) + 66px);bottom:calc(var(--ask-box-top) + 6px);width:326px;z-index:4;}
|
|
4787
4845
|
/* The chip picker (ask-panel.mjs openChipPicker) is the only JS-positioned panel: a band
|
|
4788
4846
|
chip sits wherever the transcript scrolled it. Its rows are the WHOLE model catalog, so
|
|
4789
4847
|
the menu outgrows the sheet, which clips -- the same cap .ask-pop-scope carries keeps
|
|
4790
4848
|
the Effort row reachable, and chipPickerTop() flips it above the chip when that fits. */
|
|
4791
|
-
.ask-pop-chip{width:288px;padding:6px;border-radius:
|
|
4849
|
+
.ask-pop-chip{width:288px;padding:6px;border-radius:var(--r-card);max-height:min(420px,70%);overflow-y:auto;}
|
|
4792
4850
|
.ask-pop-caption,.ask-pop-caption-row .ask-pop-caption{padding:8px 10px 6px;font-weight:600;font-size:10px;
|
|
4793
4851
|
letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);}
|
|
4794
4852
|
.ask-pop-caption-row{display:flex;align-items:baseline;gap:8px;}
|
|
@@ -4817,6 +4875,7 @@ body.rail-collapsed .ask-dock{left:76px;}
|
|
|
4817
4875
|
border-radius:999px;white-space:nowrap;background:var(--field);color:var(--ink-3);}
|
|
4818
4876
|
.ask-model-tag.is-warn{flex:0 0 auto;max-width:none;background:var(--amber-bg);color:var(--amber-ink);}
|
|
4819
4877
|
.ask-model-tag.is-err{flex:0 0 auto;max-width:none;background:var(--red-bg);color:var(--red-ink);}
|
|
4878
|
+
.ask-model-tag.is-key{flex:0 0 auto;max-width:none;background:var(--green-bg);color:var(--green-ink);}
|
|
4820
4879
|
.ask-model-item .ask-model-name{flex:0 1 auto;min-width:4.5ch;overflow:hidden;text-overflow:ellipsis;
|
|
4821
4880
|
white-space:nowrap;}
|
|
4822
4881
|
/* The threads list is the only scrollport in a popover: /api/ask/threads returns up
|
|
@@ -5244,6 +5303,7 @@ html{scrollbar-color:var(--line-2) transparent;scrollbar-width:thin;}
|
|
|
5244
5303
|
.ob-claude-cmd{margin:12px 0;padding:12px 14px;background:var(--field);border-radius:12px;overflow:auto;}
|
|
5245
5304
|
.ob-claude-cmd code{background:none;padding:0;font-size:12.5px;}
|
|
5246
5305
|
.ob-claude-note a{color:var(--blue-ink-strong);}
|
|
5306
|
+
.ob-claude-step{margin-top:16px;}
|
|
5247
5307
|
.ob-claude-status{min-height:18px;margin-top:12px;font-size:13px;line-height:1.45;}
|
|
5248
5308
|
.ob-claude-status.ok{color:var(--green-ink);}
|
|
5249
5309
|
.ob-claude-status.err{color:var(--red-ink);}
|
|
@@ -5270,14 +5330,14 @@ html{scrollbar-color:var(--line-2) transparent;scrollbar-width:thin;}
|
|
|
5270
5330
|
.select-wrap.guide-lift::after{z-index:46;}
|
|
5271
5331
|
/* The ring never fades — it is the answer to "which control?". The pulse is a
|
|
5272
5332
|
halo radiating OUT of it, so the mark stays solid and the motion draws the eye. */
|
|
5273
|
-
.guide-ring{position:fixed;z-index:46;pointer-events:none;border:2.5px solid var(--violet);border-radius:
|
|
5333
|
+
.guide-ring{position:fixed;z-index:46;pointer-events:none;border:2.5px solid var(--violet);border-radius:calc(var(--r-ctrl) + 6px);
|
|
5274
5334
|
animation:guide-pulse 1.8s ease-out infinite;}
|
|
5275
5335
|
@keyframes guide-pulse{
|
|
5276
5336
|
0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--violet) 55%,transparent);}
|
|
5277
5337
|
100%{box-shadow:0 0 0 14px color-mix(in srgb,var(--violet) 0%,transparent);}
|
|
5278
5338
|
}
|
|
5279
5339
|
.guide-balloon{position:fixed;z-index:47;display:flex;flex-direction:column;align-items:flex-start;gap:6px;
|
|
5280
|
-
max-width:300px;padding:11px 14px 10px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-
|
|
5340
|
+
max-width:300px;padding:11px 14px 10px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-card);
|
|
5281
5341
|
box-shadow:var(--shadow-pop);color:var(--ink);font-size:13px;line-height:1.45;}
|
|
5282
5342
|
.guide-balloon::before{content:'';position:absolute;top:-6px;left:calc(var(--arrow-x,20px) - 5px);width:10px;height:10px;
|
|
5283
5343
|
background:var(--panel);border-left:1px solid var(--line-2);border-top:1px solid var(--line-2);transform:rotate(45deg);}
|
|
@@ -5329,7 +5389,7 @@ html{scrollbar-color:var(--line-2) transparent;scrollbar-width:thin;}
|
|
|
5329
5389
|
.btn-split > .btn-split-more:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
|
|
5330
5390
|
.btn-split > .btn-go:disabled,.btn-split > .btn-split-more:disabled{opacity:.45;cursor:not-allowed;transform:none;filter:none;}
|
|
5331
5391
|
.btn-split-menu{position:absolute;right:0;bottom:calc(100% + 8px);z-index:20;min-width:230px;padding:6px;
|
|
5332
|
-
background:var(--panel);border:1px solid var(--line);border-radius:
|
|
5392
|
+
background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--shadow-menu);}
|
|
5333
5393
|
.btn-split-menu[hidden]{display:none;}
|
|
5334
5394
|
.btn-split-menu button{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;
|
|
5335
5395
|
background:transparent;border:none;border-radius:11px;padding:10px 12px;font-family:inherit;cursor:pointer;color:var(--ink);}
|
|
@@ -5488,10 +5548,6 @@ a.ask-card-task-title:hover{text-decoration-color:currentColor;}
|
|
|
5488
5548
|
:root[data-level="expert"] [data-max-level="simple"],
|
|
5489
5549
|
:root[data-level="expert"] [data-max-level="advanced"]{display:none !important;}
|
|
5490
5550
|
|
|
5491
|
-
/* Simple shows General only: a one-button segmented control is noise, so the bar goes — unless a
|
|
5492
|
-
deep link parked us on a higher tab, whose button is then kept (paintLevelBanner). */
|
|
5493
|
-
:root[data-level="simple"] #settings-tabs:not(:has([data-level-keep])){display:none !important;}
|
|
5494
|
-
|
|
5495
5551
|
/* The icon: a stack of layers, unlit ones ghosted. currentColor, so hover, the
|
|
5496
5552
|
dark active fill and both themes come for free. */
|
|
5497
5553
|
/* An <i>, not a <span>: the collapsed rail visually hides every direct span child of a nav button
|
|
@@ -5516,7 +5572,7 @@ a.ask-card-task-title:hover{text-decoration-color:currentColor;}
|
|
|
5516
5572
|
|
|
5517
5573
|
/* Page-above-the-mode banner. */
|
|
5518
5574
|
.level-banner{display:flex;flex-wrap:wrap;align-items:center;gap:10px 12px;margin:0 0 18px;
|
|
5519
|
-
padding:10px 14px;border-radius:var(--r-
|
|
5575
|
+
padding:10px 14px;border-radius:var(--r-card);background:var(--canvas-2);border:1px solid var(--line-2);
|
|
5520
5576
|
font-size:13px;color:var(--ink-2);}
|
|
5521
5577
|
.level-banner[hidden]{display:none;}
|
|
5522
5578
|
.level-banner-text{flex:1 1 220px;min-width:0;}
|
|
@@ -5554,7 +5610,7 @@ body.view-workspaces .level-banner{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
5554
5610
|
.mode-sub{margin:0 0 16px;font-size:13px;line-height:1.55;color:var(--ink-2);}
|
|
5555
5611
|
.lv-cards{display:flex;flex-direction:column;gap:8px;}
|
|
5556
5612
|
.lv-card{display:grid;grid-template-columns:40px minmax(0,1fr) 20px;align-items:center;gap:14px;width:100%;
|
|
5557
|
-
padding:13px 15px;border:1.5px solid var(--line-2);border-radius:
|
|
5613
|
+
padding:13px 15px;border:1.5px solid var(--line-2);border-radius:var(--r-ctrl);background:var(--panel);color:var(--ink);
|
|
5558
5614
|
font:inherit;text-align:left;cursor:pointer;transition:border-color .15s,background .15s;}
|
|
5559
5615
|
.lv-card:hover{background:var(--field);}
|
|
5560
5616
|
.lv-card:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
|
|
@@ -5637,7 +5693,7 @@ body.view-workspaces .level-banner{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
5637
5693
|
.gv-wires path.ghost.legal{stroke:var(--green);stroke-dasharray:none;}
|
|
5638
5694
|
.gv-wires path.ghost.illegal{stroke:var(--red);}
|
|
5639
5695
|
.gv-world .node{position:absolute;left:0;top:0;display:block;padding:0;gap:0;align-items:stretch;z-index:2;
|
|
5640
|
-
width:var(--gv-node-w);background:var(--panel);border:var(--gv-border) solid var(--line-2);border-radius:calc(
|
|
5696
|
+
width:var(--gv-node-w);background:var(--panel);border:var(--gv-border) solid var(--line-2);border-radius:calc(14px * var(--gv-scale));
|
|
5641
5697
|
box-shadow:var(--shadow-soft);cursor:grab;transition:box-shadow .12s;}
|
|
5642
5698
|
.gv-world .node::before{content:none;}
|
|
5643
5699
|
.gv-world .node:hover{box-shadow:var(--shadow);}
|
|
@@ -5645,7 +5701,7 @@ body.view-workspaces .level-banner{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
5645
5701
|
.gv-world .node.dragging{cursor:grabbing;transition:none;}
|
|
5646
5702
|
.gv-static .node,.gv-static .wbadge{pointer-events:none;}
|
|
5647
5703
|
.gv-world .nhead{height:var(--gv-head-h);display:flex;align-items:center;gap:calc(8px * var(--gv-scale));padding:0 calc(11px * var(--gv-scale));
|
|
5648
|
-
border-radius:calc(
|
|
5704
|
+
border-radius:calc(12.5px * var(--gv-scale)) calc(12.5px * var(--gv-scale)) 0 0;font-size:max(9px,calc(13px * var(--gv-scale)));font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
5649
5705
|
.gv-world .nhead svg{width:calc(15px * var(--gv-scale));height:calc(15px * var(--gv-scale));flex:0 0 auto;stroke-width:1.85;}
|
|
5650
5706
|
.gv-world .nhead .tt{overflow:hidden;text-overflow:ellipsis;}
|
|
5651
5707
|
.gv-world .nhead .chip.rt{margin-left:auto;flex:0 0 auto;font:700 max(8px,calc(10px * var(--gv-scale)))/1.6 var(--mono);text-transform:none;white-space:nowrap;
|
|
@@ -5740,7 +5796,7 @@ body.view-workspaces .level-banner{margin:12px 32px 0;flex:0 0 auto;}
|
|
|
5740
5796
|
lines), and test/ui-graph-css.test.mjs asserts style.css uses the FULL --gv-*
|
|
5741
5797
|
set injectGeometry writes — dropping them fails that assertion. */
|
|
5742
5798
|
.gv-world .xfoot{position:absolute;left:0;right:0;bottom:0;border-top:1px solid var(--line);
|
|
5743
|
-
border-radius:0 0
|
|
5799
|
+
border-radius:0 0 12.5px 12.5px;overflow:hidden;background:var(--panel);}
|
|
5744
5800
|
.gv-world .xfoot>.fan,.gv-world .xfoot>.xtoggle,.gv-world .xfoot>.xresult,.gv-world .xfoot>.xlive{height:var(--gv-exec-row-h);
|
|
5745
5801
|
display:flex;align-items:center;gap:7px;padding:0 11px;width:100%;box-sizing:border-box;}
|
|
5746
5802
|
.gv-world .xfoot>:first-child{height:var(--gv-foot-h);} /* the first line is the tall one nodeSize bills */
|
|
@@ -6087,7 +6143,7 @@ input.gv-name:focus-visible{outline:none;}
|
|
|
6087
6143
|
.gv-archived .pl-chip:hover{border-color:var(--red);color:var(--red-ink);background:var(--red-bg);}
|
|
6088
6144
|
|
|
6089
6145
|
/* ---------- save dialog ---------- */
|
|
6090
|
-
.save-dialog{border:none;border-radius:
|
|
6146
|
+
.save-dialog{border:none;border-radius:var(--r-card);padding:0;box-shadow:var(--shadow);max-width:420px;width:92vw;}
|
|
6091
6147
|
.save-dialog::backdrop{background:var(--scrim-soft);}
|
|
6092
6148
|
.save-dialog .sd-body{padding:20px 22px 18px;display:flex;flex-direction:column;gap:14px;}
|
|
6093
6149
|
.save-dialog .sd-title{margin:0;font-size:16px;font-weight:700;letter-spacing:-.015em;}
|
|
@@ -6181,7 +6237,7 @@ input.gv-name:focus-visible{outline:none;}
|
|
|
6181
6237
|
/* History: node click drives the Logs tab */
|
|
6182
6238
|
.hd-graph.linked .gv-world .node[data-node-id]{cursor:pointer;}
|
|
6183
6239
|
/* quiescence banner (.rd-banners / .hd-banners / History Overview note) */
|
|
6184
|
-
.run-warn{margin:0;padding:11px 15px;border-radius:
|
|
6240
|
+
.run-warn{margin:0;padding:11px 15px;border-radius:var(--r-card);background:var(--amber-bg);color:var(--amber-ink);font-size:12.5px;font-weight:600;border:1px solid color-mix(in srgb, var(--amber) 45%, transparent);align-self:stretch;}
|
|
6185
6241
|
.run-warn[hidden]{display:none;}
|
|
6186
6242
|
/* gesture hint chip (D10) */
|
|
6187
6243
|
.rg-hint{position:absolute;left:12px;bottom:10px;padding:4px 9px;border-radius:999px;background:color-mix(in srgb, var(--ink) 72%, transparent);color:var(--on-ink);font-size:10.5px;font-weight:600;pointer-events:none;opacity:0;transition:opacity .15s;z-index:5;}
|
|
@@ -6472,7 +6528,7 @@ input.gv-name:focus-visible{outline:none;}
|
|
|
6472
6528
|
/* The catalog editor: one bordered item per set / model, its fields on a grid. */
|
|
6473
6529
|
.tp-cat-list{display:flex;flex-direction:column;gap:12px;}
|
|
6474
6530
|
.tp-cat-list:empty::before{content:'None yet.';color:var(--ink-3);font-size:12.5px;}
|
|
6475
|
-
.tp-cat-item{display:flex;flex-direction:column;gap:12px;padding:14px 16px;border:1px solid var(--line);border-radius:
|
|
6531
|
+
.tp-cat-item{display:flex;flex-direction:column;gap:12px;padding:14px 16px;border:1px solid var(--line);border-radius:var(--r-ctrl);background:var(--surface);}
|
|
6476
6532
|
.tp-cat-item-head{display:flex;align-items:center;gap:10px;font-size:13.5px;}
|
|
6477
6533
|
.tp-cat-item-head .tp-cat-rm{margin-left:auto;padding:5px 11px;font-size:12px;}
|
|
6478
6534
|
.tp-cat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px 14px;}
|
|
@@ -6534,7 +6590,7 @@ input.gv-name:focus-visible{outline:none;}
|
|
|
6534
6590
|
/* The pure editor's bar (team-policy-view.mjs): the page dismantles it into the header. */
|
|
6535
6591
|
.tp-publish-bar{display:flex;align-items:center;gap:12px;}
|
|
6536
6592
|
.tp-publish-bar .grow{flex:1;font-size:12.5px;color:var(--ink-2);}
|
|
6537
|
-
.tp-json{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
6593
|
+
.tp-json{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:14px 16px;font-size:12px;line-height:1.5;overflow-x:auto;margin:0;}
|
|
6538
6594
|
.tp-msg{white-space:pre-wrap;}
|
|
6539
6595
|
@media (max-width:900px){ .tp-edit-row{grid-template-columns:1fr;} }
|
|
6540
6596
|
/* workspace card line (board 6) */
|
|
@@ -696,6 +696,7 @@ function valueControl(doc, meta, entry, row) {
|
|
|
696
696
|
case 'bool': {
|
|
697
697
|
const lab = h(doc, 'label', 'switch-row'); const cb = h(doc, 'input', 'sw-input tp-val'); cb.type = 'checkbox'; cb.checked = v === true;
|
|
698
698
|
cb.setAttribute('aria-label', meta.label);
|
|
699
|
+
if (meta.offOnly) cb.disabled = true; // a policy can only switch it off (registry: offOnly)
|
|
699
700
|
lab.append(cb, h(doc, 'span', 'switch switch-sm'), h(doc, 'span', 'txt', v === true ? 'on' : 'off'));
|
|
700
701
|
cb.addEventListener('change', () => { lab.querySelector('.txt').textContent = cb.checked ? 'on' : 'off'; });
|
|
701
702
|
wrap.append(lab); break;
|
|
@@ -713,7 +714,7 @@ function valueControl(doc, meta, entry, row) {
|
|
|
713
714
|
case 'string[]': {
|
|
714
715
|
writeItems(row, Array.isArray(v) ? v : []);
|
|
715
716
|
wrap.append(h(doc, 'div', 'tp-list'));
|
|
716
|
-
const add = h(doc, 'div', 'path-row tp-add-row'); const inp = h(doc, 'input', 'input tp-add'); inp.type = 'text'; inp.placeholder = meta.key === 'plugins.marketplaces' ? 'owner/repo or URL' : meta.key === 'models.allowed' ? 'model id' : 'plugin name';
|
|
717
|
+
const add = h(doc, 'div', 'path-row tp-add-row'); const inp = h(doc, 'input', 'input tp-add'); inp.type = 'text'; inp.placeholder = meta.key === 'plugins.marketplaces' ? 'owner/repo or URL' : meta.key === 'models.allowed' ? 'model id' : meta.key === 'ask.webAllowedDomains' ? 'example.com or *.example.com' : 'plugin name';
|
|
717
718
|
const b = h(doc, 'button', 'btn btn-ghost btn-mini tp-add-btn', '+ add'); b.type = 'button';
|
|
718
719
|
add.append(inp, b); wrap.append(add);
|
|
719
720
|
break;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ui/public/ws-seq.mjs
|
|
2
|
+
// A reconnect re-subscribes to a live run and the server replays that run's buffered events
|
|
3
|
+
// (ui/server.mjs replayEntry). Each buffered event carries a per-run `seq`; one this page has
|
|
4
|
+
// already applied is skipped, so a socket that drops (a proxy's idle timeout) never shows a
|
|
5
|
+
// log line twice. Frames without a seq (state snapshots, other channels) always apply.
|
|
6
|
+
// Pure: no DOM.
|
|
7
|
+
|
|
8
|
+
/** Whether `msg` was already applied to run `r`; records it when it was not. */
|
|
9
|
+
export function alreadyApplied(r, msg) {
|
|
10
|
+
const seq = msg && typeof msg.seq === 'number' ? msg.seq : null;
|
|
11
|
+
if (seq === null || !r) return false;
|
|
12
|
+
if (seq <= (r.lastSeq || 0)) return true;
|
|
13
|
+
r.lastSeq = seq;
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A restarted server numbers from 1 again: forget what was applied when its boot id changes. */
|
|
18
|
+
export function noteBoot(state, bootId, runsMap) {
|
|
19
|
+
if (!bootId) return;
|
|
20
|
+
if (state.serverBootId && state.serverBootId !== bootId) {
|
|
21
|
+
for (const r of runsMap.values()) r.lastSeq = 0;
|
|
22
|
+
}
|
|
23
|
+
state.serverBootId = bootId;
|
|
24
|
+
}
|