pi-central 0.5.0 → 0.6.1

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.
@@ -38,8 +38,8 @@
38
38
  `disconnected`. The manifest says `display: standalone`, not "works offline".
39
39
  -->
40
40
  <link rel="manifest" href="/manifest.webmanifest" />
41
- <script type="module" crossorigin src="/assets/index-CxdjMFJ5.js"></script>
42
- <link rel="stylesheet" crossorigin href="/assets/index-Cg14LRiC.css">
41
+ <script type="module" crossorigin src="/assets/index-BXDFZiai.js"></script>
42
+ <link rel="stylesheet" crossorigin href="/assets/index-BA5r5TxA.css">
43
43
  </head>
44
44
  <body>
45
45
  <div id="root"></div>
package/dist/ui/sw.js CHANGED
@@ -8,7 +8,19 @@
8
8
  * "worked offline" would install, open, and be useless while implying otherwise, so it deliberately does
9
9
  * not try.
10
10
  *
11
- * ## The one rule that matters: `index.html` is NEVER cached
11
+ * ## The rule: ONLY fingerprinted assets are cached
12
+ *
13
+ * `static-ui.ts` marks exactly one kind of response immutable — anything under `assets/`, whose name changes with its
14
+ * content. Everything else it serves `no-cache`.
15
+ *
16
+ * The worker used to apply the opposite test: it cached EVERY same-origin GET that was not a document and not `/ws`.
17
+ * That included `manifest.webmanifest` and the icons — both served `no-cache` and neither fingerprinted — so an
18
+ * installed app could keep a stale manifest indefinitely while the document it launched from was always fresh.
19
+ *
20
+ * The fix is to invert the test into an allow-list: cache `/assets/` and nothing else. A future stable-path file is
21
+ * then network-only by default, which is the safe direction to be wrong in.
22
+ *
23
+ * ## And `index.html` is NEVER cached
12
24
  *
13
25
  * `index.html` names the current fingerprint set, which is exactly what `static-ui.ts` says in its
14
26
  * `Cache-Control`:
@@ -17,9 +29,8 @@
17
29
  * // serves a stale app after a rebuild.
18
30
  *
19
31
  * A worker that cached it would make a stale build **permanent and invisible** — no reload button, no URL
20
- * to compare, and a worker the browser updates on its own schedule. So this file applies the SERVER's
21
- * rule: hashed assets are immutable and cached forever, and the document is fetched from the network every
22
- * time (issue #120 guards this).
32
+ * to compare, and a worker the browser updates on its own schedule. So this file applies the SERVER's rule: exactly
33
+ * one kind of response is cacheable, and the document is fetched from the network every time (issue #120 guards this).
23
34
  *
24
35
  * ## Why there is no precache list
25
36
  *
@@ -35,7 +46,29 @@
35
46
  * worker waits, and takes over on the next launch — which is the right trade for a tool that is open for
36
47
  * hours at a time.
37
48
  */
38
- const CACHE = "pi-central-v1";
49
+ /*
50
+ * v2, and the bump is load-bearing rather than tidiness.
51
+ *
52
+ * `v1` cached the manifest and the icons as well as the assets. Editing this file cannot repair a client already
53
+ * carrying that cache, because `activate` only deletes caches whose name differs from `CACHE` — with the name unchanged
54
+ * there is nothing to delete, and the stale entries survive the upgrade. Bumping it is what gives `activate` work to do,
55
+ * and it is the only way out of a poisoned cache that does not involve asking the reader to clear site data by hand.
56
+ */
57
+ const CACHE = "pi-central-v2";
58
+
59
+ /**
60
+ * Is this response safe to keep forever?
61
+ *
62
+ * The same test the server applies: Vite fingerprints everything under `assets/`, so its name changes with its content
63
+ * and a cached copy can never be wrong. Nothing else in this app has that property — the manifest, the icons and
64
+ * `sw.js` itself all live at stable paths and are served `no-cache`, and the document is not cached at all.
65
+ *
66
+ * Written as an allow-list rather than a deny-list on purpose: a new stable-path file added later is then network-only
67
+ * by default, which is the safe direction to be wrong in.
68
+ */
69
+ function isFingerprintedAsset(url) {
70
+ return url.pathname.startsWith("/assets/");
71
+ }
39
72
 
40
73
  // A request for the app document, or for a directory that resolves to one.
41
74
  function isDocument(request, url) {
@@ -75,7 +108,16 @@ self.addEventListener("fetch", (event) => {
75
108
  return;
76
109
  }
77
110
 
78
- // Hashed assets: cache-first, because their name cannot change under new content.
111
+ /*
112
+ * Everything that is NOT a fingerprinted asset is left to the browser and the server, untouched.
113
+ *
114
+ * That is `sw.js` (this file — the one that must always be re-checkable), `manifest.webmanifest`, the icons, and any
115
+ * future stable-path file. The rule used to be the inverse, and it pinned all three of those, which is exactly the
116
+ * reported symptom.
117
+ */
118
+ if (!isFingerprintedAsset(url)) return;
119
+
120
+ // Fingerprinted assets: cache-first, because their name cannot change under new content.
79
121
  event.respondWith(
80
122
  caches.match(request).then((cached) => {
81
123
  if (cached !== undefined) return cached;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-central",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "Local dashboard that orchestrates multiple sandboxed Pi coding-agent sessions across working directories.",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- :root{color-scheme:dark;--bg: #0e1116;--panel: #161b22;--panel-2: #1c2230;--panel-3: #222937;--line: #262d3a;--line-strong: #3a4354;--text: #e6edf3;--dim: #8b949e;--accent: #4c9aff;--brand: #3fa383;--accent-text: #a5d6ff;--accent-tint: rgba(76, 154, 255, .15);--ok: #3fb950;--ok-text: #7ee787;--ok-tint: rgba(63, 185, 80, .15);--warn: #d29922;--warn-text: #e3b341;--warn-tint: rgba(210, 153, 34, .15);--danger: #f85149;--danger-text: #ffb4ae;--danger-tint: rgba(248, 81, 73, .15);--quarantine: #586069;--sp-1: 4px;--sp-2: 8px;--sp-3: 12px;--sp-4: 16px;--sp-5: 24px;--sp-6: 32px;--r-1: 4px;--r-2: 6px;--r-3: 8px;--r-pill: 999px;--fs-2xs: 10px;--fs-xs: 11px;--fs-sm: 12px;--fs-base: 13px;--fs-md: 15px;--reading-size: 15px;--reading-measure: 72ch;--fs-lg: 18px;--sh-1: 0 1px 0 rgba(255, 255, 255, .03);--sh-2: 0 12px 32px rgba(0, 0, 0, .55);--focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;--sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}@media(prefers-contrast:more){:root{--dim: #e6edf3;--line: #3a4354}}@media(forced-colors:active){:root{--bg: Canvas;--panel: Canvas;--panel-2: Canvas;--panel-3: Canvas;--text: CanvasText;--dim: CanvasText;--line: ButtonBorder;--line-strong: ButtonBorder}}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--text);font:var(--fs-base) / 1.45 var(--sans);overflow:hidden;-webkit-font-smoothing:antialiased}:focus-visible{outline:none;box-shadow:var(--focus);border-radius:var(--r-1)}:focus:not(:focus-visible){outline:none}button{font:inherit;color:inherit}.mono{font-family:var(--mono)}.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.app{display:grid;grid-template-rows:44px 1fr;height:100%}.panes{display:grid;grid-template-columns:288px 1fr var(--panel-width, 320px);gap:1px;background:var(--line);min-height:0}.panes.is-collapsed{grid-template-columns:288px 1fr}@media(max-width:1023px){.panes,.panes.is-collapsed{grid-template-columns:1fr}.rail{display:none}.rail.open{display:flex}}.topbar{display:flex;align-items:center;gap:var(--sp-4);padding:0 var(--sp-4);background:var(--panel);border-bottom:1px solid var(--line)}.wordmark{font-size:var(--fs-md);font-weight:600;letter-spacing:-.01em;margin:0;display:flex;align-items:center;gap:8px}.wordmark-mark{width:22px;height:22px;flex:none}.tabs{display:flex;gap:2px}.tab{background:none;border:1px solid transparent;border-radius:var(--r-1);padding:4px 10px;color:var(--dim);cursor:pointer;font-size:var(--fs-sm)}.tab:hover{color:var(--text);background:var(--panel-2)}.tab[aria-selected=true]{color:var(--text);background:var(--panel-2);border-color:var(--line-strong)}.topbar-right{margin-left:auto;display:flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-sm);color:var(--dim)}.fleet{display:flex;gap:var(--sp-3)}.fleet-needs{color:var(--warn-text);font-weight:600}.conn{display:inline-flex;align-items:center;gap:6px}.conn-dot{width:7px;height:7px;border-radius:50%;background:var(--dim)}.conn-open .conn-dot{background:var(--ok)}.conn-connecting .conn-dot{background:var(--warn)}.conn-closed .conn-dot{background:var(--danger)}.conn detail,.conn small{font-size:var(--fs-xs)}.direct-banner{background:var(--warn-tint);color:var(--warn-text);border-bottom:1px solid var(--warn);padding:6px var(--sp-4);font-size:var(--fs-sm);display:flex;align-items:center;gap:var(--sp-2)}.rail{background:var(--panel);display:flex;flex-direction:column;min-height:0;overflow:hidden}.rail-start{padding:var(--sp-3);display:flex;flex-direction:column;gap:var(--sp-2)}.btn-primary{width:100%;background:var(--accent);color:#05131f;border:none;border-radius:var(--r-2);padding:9px 12px;font-weight:600;font-size:var(--fs-base);cursor:pointer;text-align:left;display:flex;flex-direction:column;gap:1px}.btn-primary:hover{filter:brightness(1.08)}.btn-primary:disabled{opacity:.55;cursor:not-allowed}.btn-primary small{font-weight:400;font-size:var(--fs-xs);opacity:.8}.btn-quiet{background:none;border:none;color:var(--dim);text-align:left;padding:5px 6px;border-radius:var(--r-1);cursor:pointer;font-size:var(--fs-sm);display:flex;justify-content:space-between;gap:var(--sp-2)}.btn-quiet:hover{color:var(--text);background:var(--panel-2)}.rail-filter{padding:0 var(--sp-3) var(--sp-2)}.rail-filter input,.history-search input{width:100%;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-2);padding:6px 9px;color:var(--text);font-size:var(--fs-sm)}.rail-filter input:focus,.history-search input:focus{border-color:var(--accent)}.rail-list{overflow-y:auto;flex:1;padding-bottom:var(--sp-3)}.group-header{display:flex;align-items:center;gap:var(--sp-2);padding:var(--sp-3) var(--sp-3) var(--sp-1);font-size:var(--fs-xs);color:var(--dim);text-transform:none;position:sticky;top:0;background:var(--panel);z-index:1}.group-header:after{content:"";flex:1;height:1px;background:var(--line)}.group-header .count{font-family:var(--mono)}.rail-row{display:block;width:100%;text-align:left;background:none;border:none;border-left:3px solid var(--line);padding:var(--sp-2) var(--sp-3);cursor:pointer;color:var(--dim)}.rail-row:hover{background:var(--panel-2)}.rail-row[aria-current=true]{background:var(--panel-2);color:var(--text)}.rail-row .r1{display:flex;align-items:center;gap:var(--sp-2)}.rail-row .name{color:var(--text);font-weight:600;font-size:var(--fs-sm);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.rail-row .r2,.rail-row .r3{font-family:var(--mono);font-size:var(--fs-xs);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px}.rail-row .r3{display:flex;gap:var(--sp-2)}.rail-row .ask{color:var(--warn-text)}.rail-row{display:flex;flex-direction:column}.rail-row-main{display:flex;flex-direction:column;background:none;border:0;padding:0;margin:0;font:inherit;color:inherit;text-align:left;cursor:pointer;width:100%}.rail-row-main:focus-visible{outline:none;box-shadow:var(--focus);border-radius:var(--r-1)}.rail-row-forget{align-self:flex-start;background:none;border:0;padding:0 0 2px 2px;font:inherit;font-size:var(--fs-2xs);color:var(--dim);cursor:pointer;opacity:0}.rail-row:hover .rail-row-forget,.rail-row:focus-within .rail-row-forget{opacity:1}.rail-row-forget:hover{color:var(--text);text-decoration:underline}.rail-row-forget:focus-visible{outline:none;box-shadow:var(--focus);opacity:1}.inline-rename{font:inherit;color:var(--text);background:var(--bg);border:1px solid var(--accent);border-radius:var(--r-1);padding:0 4px;min-width:0;max-width:100%}.inline-rename:focus{outline:none;box-shadow:var(--focus)}.rail-row-actions{display:flex;flex-direction:column;gap:2px;align-items:flex-start}.rail-row-retry{background:none;border:0;padding:0 0 2px 2px;font:inherit;font-size:var(--fs-2xs);font-weight:600;color:var(--accent-text);cursor:pointer}.rail-row-retry:hover{text-decoration:underline}.rail-row-retry:focus-visible{outline:none;box-shadow:var(--focus);border-radius:var(--r-1)}.error-more{color:var(--dim);font-weight:400}.rail-row-earlier{font-size:var(--fs-2xs);color:var(--dim);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(prefers-reduced-motion:no-preference){.rail-row-forget{transition:opacity .12s ease}}@media(hover:none){.rail-row-forget{opacity:1}}.state-idle{border-left-color:var(--dim)}.state-starting{border-left-color:var(--accent)}.state-streaming{border-left-color:var(--ok)}.state-awaiting-approval{border-left-color:var(--warn)}.state-failed{border-left-color:var(--danger)}.state-stopped{border-left-color:var(--line-strong)}.rail-empty{padding:var(--sp-4) var(--sp-3);color:var(--dim);font-size:var(--fs-sm)}.chip{font-size:var(--fs-2xs);padding:1px 7px;border-radius:var(--r-pill);border:1px solid transparent;white-space:nowrap;flex-shrink:0}.chip-idle{color:var(--dim);background:var(--panel-2)}.chip-starting{color:var(--accent-text);background:var(--accent-tint)}.chip-streaming{color:var(--ok-text);background:var(--ok-tint)}.chip-awaiting-approval{color:var(--warn-text);background:var(--warn-tint)}.chip-failed{color:var(--danger-text);background:var(--danger-tint)}.chip-stopped{color:var(--dim);background:var(--panel-2)}.chip-scratch{color:var(--accent-text);background:var(--accent-tint)}.chip-no-isolation{color:var(--warn-text);background:var(--warn-tint)}.column{background:var(--bg);display:flex;flex-direction:column;min-height:0;min-width:0}.session-header{display:flex;align-items:flex-start;gap:var(--sp-3);padding:var(--sp-3) 18px var(--sp-2);border-bottom:1px solid var(--line);background:var(--panel)}.session-header .title{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1;overflow:hidden}.session-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;cursor:text}.session-header h2{margin:0;font-size:var(--fs-md);font-weight:600;display:flex;align-items:center;gap:var(--sp-2);min-width:0}.session-header .where{font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pickers{display:flex;gap:var(--sp-2);align-items:center}.metrics{display:flex;gap:0;padding:6px 18px;font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim);border-bottom:1px solid var(--line);background:var(--panel);align-items:center}.metrics .warn{color:var(--warn-text)}.metrics>span+span:before{content:"·";color:var(--line-strong);margin:0 10px}.run-bar{height:2px;background:var(--accent);transition:width .3s linear}.run-track{height:2px;background:var(--line)}.warnings{border-bottom:1px solid var(--line);background:var(--warn-tint);color:var(--warn-text);padding:6px 18px;font-size:var(--fs-sm);display:flex;flex-direction:column;gap:2px}.transcript{flex:1;overflow-y:auto;padding:var(--sp-4) 18px var(--sp-5);min-height:0}.measure{max-width:var(--reading-measure)}.turn{margin-bottom:var(--sp-4)}.turn-user{background:var(--panel-2);border-radius:var(--r-2);padding:var(--sp-3)}.turn-user .role{color:var(--text);font-weight:600;letter-spacing:.06em;text-transform:uppercase}.role{font-size:var(--fs-2xs);color:var(--dim);margin-bottom:var(--sp-1);display:flex;align-items:center;gap:var(--sp-2)}.prose{font-size:var(--reading-size);line-height:1.55}.prose>:first-child{margin-top:0}.prose>:last-child{margin-bottom:0}.prose h1,.prose h2,.prose h3{font-size:1.1em;margin:1em 0 .4em}.prose p{margin:0 0 .7em}.prose ul,.prose ol{margin:0 0 .7em;padding-left:1.4em}.prose li{margin-bottom:.25em}.prose code{font-family:var(--mono);font-size:.88em;background:var(--panel-2);padding:1px 5px;border-radius:var(--r-1)}.prose pre{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-2);padding:var(--sp-3);overflow-x:auto}.prose pre code{background:none;padding:0;font-size:var(--fs-sm)}.prose blockquote{margin:0 0 .7em;padding-left:var(--sp-3);border-left:3px solid var(--line-strong);color:var(--dim)}.prose a{color:var(--accent-text)}.prose table{border-collapse:collapse;margin-bottom:.7em}.prose th,.prose td{border:1px solid var(--line);padding:4px 8px;font-size:var(--fs-sm)}.prose img{max-width:100%}.quarantine{border-left:3px solid var(--quarantine);background:var(--panel);border-radius:0 var(--r-2) var(--r-2) 0;margin:var(--sp-2) 0;overflow:hidden}.quarantine-head{display:flex;align-items:center;gap:var(--sp-2);padding:2px;font-size:var(--fs-2xs);color:var(--dim);background:none;border:none;cursor:pointer;width:100%;text-align:left}.quarantine-head .label{color:var(--quarantine-filter, var(--dim));font-weight:600}.quarantine-state{color:var(--dim);font-weight:400}.quarantine-head:hover{background:var(--panel-2);color:var(--text)}.quarantine-head .tool-name{font-family:var(--mono);color:var(--text)}.quarantine-head .spacer{flex:1}.quarantine-gist{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;opacity:.8;text-align:right}.quarantine-head .err{color:var(--danger-text)}.quarantine-body{padding:var(--sp-3);font-family:var(--mono);font-size:var(--fs-sm);white-space:pre-wrap;word-break:break-word;max-height:420px;overflow-y:auto;color:var(--text)}.quarantine-body.collapsed{display:none}.quarantine-body.error{color:var(--danger-text)}.legend>span:first-child{flex:1}.legend{font-size:var(--fs-xs);color:var(--dim);padding:6px 18px;display:flex;align-items:center;gap:var(--sp-3);border-bottom:1px solid var(--line);background:var(--panel)}.queue{border-top:1px solid var(--line);background:var(--panel);padding:var(--sp-2) 18px;font-size:var(--fs-xs);color:var(--dim)}.queue-head{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:3px}.queue-row{font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.queue button{margin-top:var(--sp-2)}.composer{border-top:1px solid var(--line);background:var(--panel);padding:var(--sp-3) 18px;display:flex;flex-direction:column;gap:var(--sp-2)}.mode-strip{display:flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-xs);background:var(--accent-tint);color:var(--accent-text);border:1px solid var(--accent);border-radius:var(--r-2);padding:5px 9px}.composer-row{display:flex;gap:var(--sp-2);align-items:flex-end}.composer-row .btn-send{flex:none}.composer textarea{flex:1;min-height:72px;max-height:40vh;resize:vertical;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-2);padding:9px 11px;color:var(--text);font:var(--fs-md) / 1.5 var(--sans)}.composer textarea:focus{border-color:var(--accent)}.composer textarea:disabled{opacity:.6}.btn-send{height:34px;padding:0 var(--sp-4);background:var(--accent);color:#05131f;border:none;border-radius:var(--r-2);font-family:inherit;font-size:var(--fs-sm);font-weight:600;cursor:pointer;white-space:nowrap}.btn-send:disabled{opacity:.5;cursor:not-allowed}.hint{font-size:var(--fs-xs);color:var(--dim)}.hint kbd{font-family:var(--mono);background:var(--panel-2);border:1px solid var(--line);border-radius:3px;padding:0 4px}.btn{background:var(--panel-2);border:1px solid var(--line-strong);border-radius:var(--r-2);padding:5px 11px;font-size:var(--fs-sm);cursor:pointer;color:var(--text)}.btn:hover{background:var(--panel-3)}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-danger{color:var(--danger-text);border-color:var(--danger);background:var(--danger-tint)}.btn-ghost{background:none;border-color:transparent;color:var(--dim)}.btn-ghost:hover{color:var(--text);background:var(--panel-2)}select.btn{font-family:var(--sans)}.dialog-dock{margin:var(--sp-3) 18px 0;border:1px solid var(--warn);border-radius:var(--r-3);background:var(--panel-3);box-shadow:var(--sh-2);overflow:hidden}.dialog-head{background:var(--warn-tint);color:var(--warn-text);padding:7px 12px;font-size:var(--fs-xs);font-weight:600;display:flex;align-items:center;gap:var(--sp-2)}.dialog-body{padding:var(--sp-3) var(--sp-4) var(--sp-4)}.dialog-body .question{font-size:var(--fs-md);margin:0 0 var(--sp-1);white-space:pre-wrap}.dialog-body .title{font-size:var(--fs-base);font-weight:600;margin:0 0 var(--sp-1)}.dialog-actions{display:flex;gap:var(--sp-2);margin-top:var(--sp-3);flex-wrap:wrap}.dialog-body input[type=text],.dialog-body textarea{width:100%;background:var(--bg);border:1px solid var(--line-strong);border-radius:var(--r-2);padding:7px 10px;color:var(--text);font:var(--fs-base) / 1.45 var(--mono)}.dialog-body textarea{min-height:120px;resize:vertical}.dialog-options{display:flex;flex-direction:column;gap:3px;margin-top:var(--sp-2)}.dialog-options button{text-align:left;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-2);padding:7px 11px;cursor:pointer;font-size:var(--fs-base)}.dialog-options button:hover{border-color:var(--accent);background:var(--panel-3)}.modal-backdrop{position:fixed;inset:0;background:#0009;display:grid;place-items:center;z-index:100}.modal{background:var(--panel-3);border:1px solid var(--line-strong);border-radius:var(--r-3);box-shadow:var(--sh-2);padding:var(--sp-5);max-width:620px}.modal h3{margin:0 0 var(--sp-2);font-size:var(--fs-md)}.modal p{margin:0;color:var(--dim);font-size:var(--fs-base)}.empty{flex:1;display:flex;flex-direction:column;justify-content:center;padding:var(--sp-6) 18px;max-width:72ch;gap:var(--sp-3)}.empty h2{margin:0;font-size:var(--fs-lg);font-weight:600;letter-spacing:-.01em}.empty p{margin:0;color:var(--dim);font-size:var(--fs-md)}.empty .action{color:var(--text)}.section-label{font-size:var(--fs-xs);color:var(--dim);display:flex;align-items:center;gap:var(--sp-2)}.section-label:after{content:"";flex:1;height:1px;background:var(--line)}.error-card{border:1px solid var(--danger);border-radius:var(--r-3);background:var(--danger-tint);margin:var(--sp-3) 18px 0;padding:var(--sp-3);font-size:var(--fs-sm)}.error-card h3{margin:0 0 var(--sp-1);font-size:var(--fs-base);color:var(--danger-text)}.error-card p{margin:0 0 var(--sp-2);color:var(--text);white-space:pre-wrap}.error-card .detail{font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim)}.error-card .actions{display:flex;gap:var(--sp-2)}.inspector{flex:1;min-height:0;overflow-y:auto;padding:var(--sp-4) 18px;font-size:var(--fs-sm)}.inspector h3{font-size:var(--fs-xs);color:var(--dim);margin:0 0 var(--sp-2);font-weight:600}.inspector section{margin-bottom:var(--sp-5)}.kv{display:grid;grid-template-columns:96px 1fr;gap:4px var(--sp-2)}.kv dt{color:var(--dim);font-size:var(--fs-xs);padding-top:2px}.kv dd{margin:0;font-family:var(--mono);font-size:var(--fs-xs);word-break:break-word;display:flex;gap:6px;align-items:flex-start}.cmd{font-family:var(--mono);font-size:var(--fs-xs);background:var(--bg);border:1px solid var(--line);border-radius:var(--r-2);padding:var(--sp-2);white-space:pre-wrap;word-break:break-all;color:var(--dim);margin:0}.copy{background:none;border:none;color:var(--dim);cursor:pointer;font-size:var(--fs-2xs);padding:1px 5px;border-radius:var(--r-1);border:1px solid var(--line);flex-shrink:0}.copy:hover{color:var(--text);border-color:var(--line-strong)}.actions{display:flex;flex-direction:column;gap:var(--sp-2);align-items:stretch}.history{flex:1;overflow-y:auto;padding:var(--sp-4) 18px;min-height:0}.history-search{display:flex;gap:var(--sp-2);margin-bottom:var(--sp-4);max-width:640px}.history-row{display:block;width:100%;text-align:left;font-family:inherit;font-size:var(--fs-sm);background:var(--panel);border:1px solid var(--line);border-radius:var(--r-2);padding:var(--sp-3);margin-bottom:var(--sp-2);cursor:pointer;color:var(--text);max-width:900px}.history-row:hover{border-color:var(--line-strong);background:var(--panel-2)}.history-row .h1{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:3px}.history-row .h1 strong{font-size:var(--fs-base)}.history-row .project{font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.history-row .first{font-size:var(--fs-sm);color:var(--dim);margin:6px 0 0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.history-row .meta{display:flex;gap:var(--sp-3);font-size:var(--fs-2xs);color:var(--dim);margin-top:6px;font-family:var(--mono)}.history-row .gone{color:var(--warn-text)}.toasts{position:fixed;right:var(--sp-4);bottom:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-2);z-index:90;max-width:400px}.toast{background:var(--panel-3);border:1px solid var(--line-strong);border-left:3px solid var(--accent);border-radius:var(--r-2);box-shadow:var(--sh-2);padding:var(--sp-2) var(--sp-3);font-size:var(--fs-sm);display:flex;gap:var(--sp-2);align-items:flex-start}.toast-error{border-left-color:var(--danger);color:var(--danger-text)}.toast-warn{border-left-color:var(--warn);color:var(--warn-text)}.toast button{background:none;border:none;color:var(--dim);cursor:pointer}@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}.run-bar{transition:none}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.45}}.state-streaming .live-dot{animation:pulse 1.6s ease-in-out infinite}.live-dot{width:6px;height:6px;border-radius:50%;background:var(--ok);display:inline-block}.trace{border-top:1px solid var(--line);background:var(--panel);flex-shrink:0;display:flex;flex-direction:column;min-height:0}.trace-head{display:flex;align-items:center;gap:var(--sp-3);padding:4px 18px;font-size:var(--fs-xs);color:var(--dim);border-bottom:1px solid var(--line)}.trace-toggle{background:none;border:none;color:var(--text);font-size:var(--fs-xs);font-weight:600;cursor:pointer;padding:2px 4px;border-radius:var(--r-1)}.trace-toggle:hover{background:var(--panel-2)}.toggle-chip{background:none;font:inherit;cursor:pointer;border:1px solid var(--line);border-radius:var(--r-pill);padding:1px 8px;font-weight:500;color:var(--text)}.toggle-chip[aria-pressed=true]{color:var(--accent-text);background:var(--accent-tint);border-color:transparent}.trace-count{color:var(--dim)}.trace-running{color:var(--ok-text);display:inline-flex;align-items:center;gap:5px}.trace-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:40ch}.trace-hint{margin-left:auto}.trace-list{max-height:108px;overflow-y:auto;padding:2px 0;background:var(--bg);scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent}.trace-list::-webkit-scrollbar{width:9px}.trace-list::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:5px}.trace-list::-webkit-scrollbar-track{background:transparent}.trace-row{display:flex;align-items:center;gap:var(--sp-2);width:100%;text-align:left;background:none;border:none;border-left:3px solid transparent;padding:2px 15px;cursor:pointer;font-size:var(--fs-xs);color:var(--dim)}.trace-row:hover{background:var(--panel-2)}.trace-row.recent{border-left-color:var(--line-strong)}.trace-row.running{border-left-color:var(--ok);color:var(--text)}.trace-row.failed{border-left-color:var(--danger)}.trace-row.selected{background:var(--panel-3);color:var(--text)}.trace-row .t-status{width:10px;flex-shrink:0}.trace-row.running .t-status{color:var(--ok)}.trace-row.failed .t-status{color:var(--danger-text)}.trace-row .t-name{color:var(--text);flex-shrink:0;min-width:7ch}.trace-row .t-summary{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dim)}.trace-row .t-time{flex-shrink:0;color:var(--dim)}.trace-detail{border-top:1px solid var(--line);background:var(--bg);max-height:34vh;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent}.trace-detail::-webkit-scrollbar{width:9px}.trace-detail::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:5px}.trace-detail::-webkit-scrollbar-track{background:transparent}.trace-detail.is-quarantined{border-left:3px solid var(--quarantine);background:var(--bg)}.trace-detail.is-quarantined .trace-detail-head{background:var(--panel-2)}.trace-detail.is-quarantined .trace-detail-head .label{color:var(--quarantine)}.trace-detail-head{display:flex;align-items:center;gap:var(--sp-2);padding:4px 18px;font-size:var(--fs-xs);color:var(--dim);background:var(--panel-2);position:sticky;top:0}.trace-detail-head .label{color:var(--quarantine);font-weight:600}.trace-detail-head .err{color:var(--danger-text)}.trace-detail-head .spacer{flex:1}.trace-args{margin:0;padding:var(--sp-2) 18px;font-size:var(--fs-xs);color:var(--dim);white-space:pre-wrap;word-break:break-word;border-bottom:1px solid var(--line);max-height:14vh;overflow-y:auto}.trace-output{margin:0;padding:var(--sp-2) 18px;font-size:var(--fs-sm);white-space:pre-wrap;word-break:break-word;color:var(--text)}.trace-output.error{color:var(--danger-text)}.tool-marker{display:block;width:100%;font-size:var(--fs-base);max-width:var(--reading-measure);text-align:left;border-left:3px solid var(--quarantine);background:var(--panel);border-radius:0 var(--r-2) var(--r-2) 0;overflow:hidden;margin:2px 0 var(--sp-3);color:var(--dim)}.tool-marker-summary{font-size:var(--fs-xs);display:flex;align-items:center;gap:var(--sp-2);cursor:pointer;list-style:none;color:var(--quarantine);font-weight:600;background:var(--panel)}.tool-marker-summary::-webkit-details-marker{display:none}.tool-marker-summary:hover{background:var(--panel-2);color:var(--text)}.tool-marker .m-open{margin-left:auto;transition:transform .12s ease}@media(prefers-reduced-motion:reduce){.tool-marker .m-open{transition:none}}.tool-marker[open] .m-open{transform:rotate(180deg)}.tool-detail{font-size:var(--fs-2xs);border-top:1px solid var(--line)}.tool-detail-head{display:flex;align-items:center;gap:var(--sp-2);padding:4px 10px;font-size:var(--fs-xs);color:var(--dim);background:var(--panel-2)}.tool-detail-head .label{color:var(--quarantine);font-weight:600}.tool-detail-head .spacer{flex:1}.tool-detail-head .err{color:var(--danger-text)}.tool-detail-meta{font-family:var(--mono);font-size:var(--fs-2xs)}.tool-detail>:first-child{margin-top:0}.tool-detail-args,.tool-detail-output{margin:0;padding:var(--sp-2) 10px;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:var(--fs-xs)}.tool-detail-args{color:var(--dim);border-bottom:1px solid var(--line)}.tool-detail-output.error{color:var(--danger-text)}.tool-detail-rest>summary{padding:4px 10px;font-size:var(--fs-2xs);color:var(--dim);cursor:pointer}.tool-marker:hover{border-left-color:var(--line-strong)}.tool-marker.has-error{border-left-color:var(--danger)}.tool-marker.running{border-left-color:var(--ok)}.tool-marker .m-count{color:var(--text)}.tool-marker .m-names{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;color:var(--text)}.tool-marker .m-failed{color:var(--danger-text)}.tool-marker .m-running{color:var(--ok-text)}.trace-row.unfinished{border-left-color:var(--warn)}.trace-row.unfinished .t-status{color:var(--warn-text)}.picker{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;justify-content:flex-end}.picker-label{font-size:var(--fs-xs);color:var(--dim);text-transform:none}.picker-grid{display:grid;grid-template-columns:auto auto;align-items:center;gap:2px var(--sp-2);justify-content:end}.picker-grid [data-picker-row=provider]{grid-row:1}.picker-grid [data-picker-row=model]{grid-row:2}.picker-grid [data-picker-row=note]{grid-row:3;grid-column:1 / -1}.picker-grid [data-picker-label]{justify-self:end}.picker-grid [data-picker-row]:not([data-picker-label]){justify-self:start}.picker-controls{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}.picker-provider{font-size:var(--fs-xs);color:var(--text)}.picker-select{font-family:var(--mono);font-size:var(--fs-xs);color:var(--text);background:var(--panel-3);border:1px solid var(--line);border-radius:4px;padding:3px 6px;max-width:30ch}.picker-select:focus-visible{outline:none;box-shadow:var(--focus);border-color:var(--accent)}.picker-select:disabled{opacity:.55;cursor:not-allowed}.picker-field{position:relative;display:inline-flex;align-items:center;flex-shrink:0;max-width:30ch}.picker-display{position:absolute;inset:1px 20px 1px 1px;display:flex;align-items:center;padding-left:6px;background:var(--panel-3);border-radius:4px 0 0 4px;font-size:var(--fs-xs);color:var(--text);white-space:nowrap;overflow:hidden;pointer-events:none}.picker-display.is-disabled{opacity:.55}.picker-note{font-size:var(--fs-xs);color:var(--dim);flex-basis:100%;text-align:right}.picker-note.warn{color:var(--warn-text)}.picker-value{font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim)}.picker-select-narrow{max-width:10ch}.mode-strip{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:6px 0}.mode-choice{display:inline-flex;border:1px solid var(--line);border-radius:6px;overflow:hidden}.mode-option{background:transparent;border:0;color:inherit;font:inherit;padding:3px 10px;cursor:pointer}.mode-option+.mode-option{border-left:1px solid var(--line)}.mode-option-on{background:var(--accent);color:var(--accent-ink)}.mode-consequence{opacity:.85}.queue-strip{padding:4px 0}.queue-head{opacity:.85}.queue-rows{list-style:none;margin:2px 0 0;padding:0}.queue-rows li{opacity:.85;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.queue-unknown{opacity:.7;font-style:italic}.transcript-wrap{position:relative;display:flex;flex-direction:column;flex:1;min-height:0;--jump-strip: 40px;padding-bottom:var(--jump-strip)}.jump-latest{position:absolute;left:50%;transform:translate(-50%);bottom:4px;display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;border:1px solid var(--line);background:var(--bg-raised, var(--bg));color:inherit;font:inherit;cursor:pointer;box-shadow:0 2px 10px #00000040}.jump-latest:hover{border-color:var(--accent)}.code-block{margin:0 0 .7em}.code-lang{font-family:var(--mono);font-size:var(--fs-xs);opacity:.65;padding:0 0 2px;letter-spacing:.02em}.code-lang-note{opacity:.8}.code-body pre,.code-plain{margin:0}.shiki{font-family:var(--mono);font-size:var(--fs-sm);overflow-x:auto}.shiki .line{display:block}.shiki .tk-i{font-style:italic}.shiki .tk-161b22{color:#161b22}.shiki .tk-79c0ff{color:#79c0ff}.shiki .tk-7ee787{color:#7ee787}.shiki .tk-8b949e{color:#8b949e}.shiki .tk-a5d6ff{color:#a5d6ff}.shiki .tk-d2a8ff{color:#d2a8ff}.shiki .tk-e6edf3{color:#e6edf3}.shiki .tk-f0f6fc{color:#f0f6fc}.shiki .tk-ff7b72{color:#ff7b72}.shiki .tk-ffa198{color:#ffa198}.shiki .tk-ffa657{color:#ffa657}.hazard{color:var(--warn-text);font-size:12px;margin:6px 0 0;border-left:3px solid var(--warn-text);padding-left:8px}.run-notices{margin:4px 0 8px;display:flex;flex-direction:column;gap:4px}.run-notice{display:flex;align-items:baseline;gap:8px;font-size:var(--fs-sm);color:var(--dim);border-left:3px solid var(--line-strong);padding:2px 0 2px 10px}.run-notice[data-kind=compaction]{border-left-color:var(--accent-text)}.run-notice[data-kind=retry][data-open],.run-notice[data-kind=summarization]{border-left-color:var(--warn-text)}.notice-glyph{font-family:var(--mono)}.notice-text{flex:1}.notice-note{opacity:.75;font-style:italic}.filetree-head{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);margin-bottom:6px}.filetree-scope{color:var(--dim);font-size:var(--fs-xs)}.filetree-head .btn-quiet{font-size:var(--fs-xs);padding:2px 6px}.filetree-list{list-style:none;margin:0;padding:0}.filetree-node{margin:0}.filetree-row{display:flex;align-items:baseline;gap:6px;width:100%;background:none;border:0;border-radius:4px;padding:2px 4px;margin:0;color:var(--text);font:var(--fs-xs) var(--mono);text-align:left;cursor:pointer}.filetree-row:hover{background:var(--panel-2)}.filetree-row:focus-visible{outline:none;box-shadow:var(--focus)}.filetree-mark{color:var(--dim);width:10px;flex:none}.filetree-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.filetree-name.is-hidden{color:var(--dim)}.filetree-kind{flex:none;font-size:10px;color:var(--dim);border:1px solid var(--line);border-radius:3px;padding:0 3px}.filetree-bad{color:var(--warn-text);border-color:var(--warn-text)}.filetree-size{flex:none;color:var(--dim);font-size:10px}.filetree-note{margin:2px 0;color:var(--dim);font-size:var(--fs-xs)}.filetree-truncated{font-style:italic}.filetree-error{display:flex;flex-direction:column;gap:2px;border-left:3px solid var(--danger-text);padding:2px 0 2px 8px;color:var(--text)}.filetree-error strong{color:var(--danger-text);font-weight:600}.filetree-error-detail{color:var(--dim)}.filepane{display:flex;flex-direction:column;min-height:0}.filepane-head{position:sticky;top:0;background:var(--panel);z-index:1}.filepane-head{display:flex;align-items:baseline;gap:var(--sp-2);padding-bottom:4px;border-bottom:1px solid var(--line);margin-bottom:6px}.filepane-path{flex:1;font-family:var(--mono);font-size:var(--fs-xs);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.filepane-meta{flex:none;color:var(--dim);font-size:10px}.filepane-lines{list-style:none;margin:0;padding:0;font-family:var(--mono);font-size:var(--fs-xs);line-height:1.5}.filepane-lines li{display:flex;gap:8px}.filepane-line-no{flex:none;width:32px;text-align:right;color:var(--dim);opacity:.6;-webkit-user-select:none;user-select:none}.filepane-line-text{white-space:pre;flex:1;min-width:0}.filepane-lines.is-wrapped .filepane-line-text{white-space:pre-wrap;overflow-wrap:anywhere}.imagepane{display:flex;flex-direction:column;gap:var(--sp-2);min-height:0}.imagepane-img{max-width:100%;max-height:60vh;object-fit:contain;border-radius:var(--r-2);background-color:var(--panel-2);background-image:linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%),linear-gradient(45deg,var(--line) 25%,transparent 25%,transparent 75%,var(--line) 75%);background-size:16px 16px;background-position:0 0,8px 8px}.imagepane-meta{margin:0;font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim)}.reading-row{display:grid;grid-template-columns:76px 1fr 44px;align-items:center;gap:var(--sp-2);margin-bottom:6px;font-size:var(--fs-xs);color:var(--dim)}.reading-row input[type=range]{width:100%;accent-color:var(--accent)}.reading-row input[type=range]:disabled{opacity:.4}.reading-value{color:var(--text);text-align:right}.reading-sample span{display:block;font-size:var(--reading-size);line-height:1.55;color:var(--text)}.reading-sample{margin-top:var(--sp-3);padding:var(--sp-2) var(--sp-3);border-left:3px solid var(--line-strong);background:var(--bg);border-radius:0 var(--r-2) var(--r-2) 0}.reading-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-2)}.reading-head h4{margin:0}.reading-head .btn-quiet{font-size:var(--fs-xs);padding:2px 6px}.settings-panes{display:grid;grid-template-columns:108px 1fr;gap:var(--sp-4);min-height:0}.settings-nav{display:flex;flex-direction:column;gap:2px}.settings-nav-item{background:none;border:0;border-radius:var(--r-1);padding:5px 8px;text-align:left;font:inherit;font-size:var(--fs-sm);color:var(--dim);cursor:pointer}.settings-nav-item:hover{background:var(--panel-2);color:var(--text)}.settings-nav-item.is-active{background:var(--panel-2);color:var(--text);font-weight:600}.settings-nav-item:focus-visible{outline:none;box-shadow:var(--focus)}.settings-content{min-width:0}.panel{position:relative;display:flex;flex-direction:column;min-height:0;min-width:0;background:var(--panel);container-type:inline-size;container-name:panel}.panel-head{flex:none;padding:var(--sp-2) var(--sp-3) 0;border-bottom:1px solid var(--line)}.panel-head .tabs{padding-bottom:var(--sp-2)}.panel-body{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}.panel-body:focus-visible{outline:none;box-shadow:var(--focus)}.panel-empty{margin:0;padding:var(--sp-4) 18px;color:var(--dim);font-size:var(--fs-sm)}.panel-resizer{position:absolute;top:0;bottom:0;left:-3px;width:7px;cursor:col-resize;z-index:5;background:transparent;touch-action:none}.panel-resizer:hover,.panel-resizer:focus-visible{background:var(--accent);opacity:.4}.panel-resizer:focus-visible{outline:none;box-shadow:var(--focus)}.files-panel{display:flex;flex-direction:column;min-height:0;flex:1}.files-back{flex:none;display:flex;align-items:baseline;gap:var(--sp-2);padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--line);min-width:0}.files-back-path{flex:1;font-family:var(--mono);font-size:var(--fs-xs);color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.files-body{flex:1;min-height:0;display:grid;grid-template-columns:1fr;grid-template-rows:1fr}.files-body>*{min-height:0;min-width:0}.files-tree{overflow:auto;padding:var(--sp-3) 12px var(--sp-4)}.files-body.has-file .files-tree{display:none}.files-doc{overflow:auto;padding:var(--sp-3) 14px var(--sp-4)}@container panel (min-width: 560px){.files-back{display:none}.files-body.has-file{grid-template-columns:210px 1fr}.files-body.has-file .files-tree{display:block;border-right:1px solid var(--line)}}.settings{max-width:620px;width:min(620px,calc(100vw - 32px))}.settings section{margin-top:var(--sp-4)}.settings h4{margin:0 0 var(--sp-2);font-size:var(--fs-xs);font-weight:600;color:var(--dim);text-transform:uppercase;letter-spacing:.04em}.settings .kv{grid-template-columns:110px 1fr}.settings .kv dd{flex-wrap:wrap}.settings-mono{font-family:var(--mono);font-size:var(--fs-xs);word-break:break-all;-webkit-user-select:text;user-select:text}.settings-note,.settings-absent{color:var(--dim);font-size:var(--fs-xs);font-style:italic}.settings-absent-note{margin:var(--sp-3) 0 0;padding:6px 0 6px 10px;border-left:3px solid var(--warn-text);color:var(--text);font-size:var(--fs-xs);line-height:1.5}.settings-absent-note code{font-family:var(--mono);color:var(--dim)}.settings-updates{margin:0;line-height:1.5}.settings-updates strong{color:var(--text);font-style:normal}.settings .dialog-actions{margin-top:var(--sp-5)}