lobstah 0.6.0 → 0.6.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/dist/main.js CHANGED
@@ -450,13 +450,15 @@ function unseenNotices(consume, filter, wakes) {
450
450
  fs4.writeFileSync(cursorFile(), through);
451
451
  }
452
452
  }
453
- return wakes ? owned.filter(wakes) : owned;
453
+ const waking = owned.filter((n) => !QUIET_NOTICE_KINDS.includes(n.kind));
454
+ return wakes ? waking.filter(wakes) : waking;
454
455
  }
455
- var counter;
456
+ var QUIET_NOTICE_KINDS, counter;
456
457
  var init_notices = __esm({
457
458
  "packages/core/dist/notices.js"() {
458
459
  "use strict";
459
460
  init_paths();
461
+ QUIET_NOTICE_KINDS = ["trap-listening"];
460
462
  counter = 0;
461
463
  }
462
464
  });
@@ -2374,9 +2376,36 @@ function validSessionLink(value) {
2374
2376
  return false;
2375
2377
  return /^claude:\/\/claude\.ai\/[A-Za-z0-9_/-]+$/.test(value) || /^vscode:\/\/anthropic\.claude-code\/open\?session=[A-Za-z0-9_-]+$/.test(value) || /^codex:\/\/threads\/[A-Za-z0-9-]+$/.test(value);
2376
2378
  }
2379
+ function linkMismatch(link, win) {
2380
+ if (!win)
2381
+ return void 0;
2382
+ const ep = win.entrypoint;
2383
+ const bundle = win.bundleId;
2384
+ if (link.startsWith("vscode://")) {
2385
+ if (ep !== void 0)
2386
+ return ep === "claude-vscode" ? void 0 : `a vscode:// link needs the VS Code extension; this session's entrypoint is ${ep}`;
2387
+ return bundle === void 0 || VSCODE_BUNDLE_RE.test(bundle) ? void 0 : `a vscode:// link needs the VS Code extension; this session runs in ${bundle}`;
2388
+ }
2389
+ if (link.startsWith("claude://")) {
2390
+ if (ep !== void 0) {
2391
+ return ep === "cli" || ep === "claude-vscode" || ep.startsWith("sdk-") ? `a claude:// link needs the Claude desktop app's Code tab; this session's entrypoint is ${ep}` : void 0;
2392
+ }
2393
+ if (bundle !== void 0 && bundle !== CLAUDE_DESKTOP_BUNDLE)
2394
+ return `a claude:// link needs the Claude desktop app; this session runs in ${bundle}`;
2395
+ return win.termProgram === "claude-desktop" ? "a claude:// link needs the Code tab; this session runs in the Claude desktop app's terminal" : void 0;
2396
+ }
2397
+ if (link.startsWith("codex://")) {
2398
+ return bundle === void 0 || bundle === CODEX_BUNDLE ? void 0 : `a codex:// link needs the Codex app; this session runs in ${bundle}`;
2399
+ }
2400
+ return void 0;
2401
+ }
2402
+ var VSCODE_BUNDLE_RE, CLAUDE_DESKTOP_BUNDLE, CODEX_BUNDLE;
2377
2403
  var init_session_link = __esm({
2378
2404
  "packages/core/dist/session-link.js"() {
2379
2405
  "use strict";
2406
+ VSCODE_BUNDLE_RE = /(?:VSCode|Cursor|windsurf)/;
2407
+ CLAUDE_DESKTOP_BUNDLE = "com.anthropic.claudefordesktop";
2408
+ CODEX_BUNDLE = "com.openai.codex";
2380
2409
  }
2381
2410
  });
2382
2411
 
@@ -3751,6 +3780,8 @@ function signOnTrap(opts) {
3751
3780
  writeTrapAnchor(opts.worktree, { ...anchor, name });
3752
3781
  const iso = new Date(now2).toISOString();
3753
3782
  const sameSession = prior?.sessionId === opts.sessionId;
3783
+ const window = opts.window ?? (sameSession ? prior.window : void 0);
3784
+ const link = opts.link ?? (sameSession && validSessionLink(prior?.link) ? prior.link : void 0);
3754
3785
  const reg = {
3755
3786
  trapId,
3756
3787
  name,
@@ -3763,8 +3794,8 @@ function signOnTrap(opts) {
3763
3794
  signedOnAt: sameSession ? prior.signedOnAt : iso,
3764
3795
  heartbeatAt: iso,
3765
3796
  firstParkedAt: sameSession ? prior.firstParkedAt : void 0,
3766
- window: opts.window ?? (sameSession ? prior.window : void 0),
3767
- link: opts.link ?? (sameSession && validSessionLink(prior?.link) ? prior.link : void 0),
3797
+ window,
3798
+ link: link !== void 0 && linkMismatch(link, window) === void 0 ? link : void 0,
3768
3799
  claimed: prior?.claimed,
3769
3800
  ...createdWorktree ? { createdWorktree } : {}
3770
3801
  };
@@ -4508,6 +4539,7 @@ function captureWindow(env = process.env) {
4508
4539
  tmuxPane: env.TMUX_PANE,
4509
4540
  kittyWindow: env.KITTY_WINDOW_ID,
4510
4541
  weztermPane: env.WEZTERM_PANE,
4542
+ entrypoint: env.CLAUDE_CODE_ENTRYPOINT,
4511
4543
  tty: ancestorTty()
4512
4544
  };
4513
4545
  for (const k of Object.keys(ref)) {
@@ -13238,7 +13270,7 @@ import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from
13238
13270
  import { fileURLToPath as fileURLToPath3 } from "node:url";
13239
13271
 
13240
13272
  // apps/cli/src/glass-page.generated.ts
13241
- var GLASS_PAGE = '<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width,initial-scale=1" />\n <title>spyglass</title>\n <link rel="icon" type="image/png" href="/icon.png" />\n <style>:root{--bg: #0e1116;--card: #161b22;--line: #2b3240;--line-hover: #3a455a;--row-hover: #1c2330;--inset: #10151c;--seg-on: #26436b;--scrim: rgba(4, 7, 11, 0.72);--fg: #dbe2ea;--dim: #8b96a5;--ok: #4fc17c;--warn: #e2b93d;--bad: #e26d5c;--link: #6cb2e2;--on-fill: #fff;--pr-merged: #8957e5;--pr-merged-fg: #ab7df8;--pr-open: #238636;--pr-draft: #6e7681;--pr-closed: #da3633;--font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;--font-size: 13px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--page-pad-block: 14px;--radius: 6px;--card-radius: 8px;--card-pad: 12px 14px;--card-min: 300px;--deck-card-min: 240px;--badge-radius: 5px;--badge-pad: 1px 7px;--badge-font: 11px;--modal-radius: 10px;--modal-width: 780px}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:var(--font-size)/1.45 var(--font-mono);padding-block:var(--page-pad-block);padding-inline:var(--space-4);display:flex;flex-direction:column;min-height:100vh}h1{font-size:15px;margin:0 0 10px}h1 .dim{color:var(--dim);font-weight:normal}h2{font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.08em;margin:20px 0 6px}.chips,.controls{display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center}.controls{margin:0 0 14px}.chips{margin-bottom:8px}.chip{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:3px 9px}.controls select,.newtrap select,.controls input[type=search]{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);color:var(--fg);font:inherit;padding:4px 8px}.controls input[type=search]{flex:1 1 140px;min-width:120px;max-width:340px}#chain-control{display:inline-flex;align-items:center;gap:7px;white-space:nowrap}#f-chain{margin:0;width:14px;height:14px;accent-color:var(--link)}.tabs{display:flex;gap:var(--space-1);border-bottom:1px solid var(--line);margin:8px 0 10px}.tabs a{color:var(--dim);padding:6px 11px;border-bottom:2px solid transparent}.tabs a.on{color:var(--fg);border-color:var(--link)}.tabpage{display:none}.tabpage.on{display:block;flex:1 0 auto}.headerline{display:flex;align-items:center;gap:var(--space-2)}.headerline h1{flex:1}#settings-slot{min-width:34px;text-align:right;color:var(--dim)}#settings-slot #gearbtn{margin-left:0}.deckgrid{display:flex;flex-direction:column;gap:var(--space-3)}.deckgrid h2{margin:5px 0}.deckgrid section{width:100%;min-width:0}.deckline{padding:2px 0;border-top:1px solid var(--line);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.deckline.acked,.card.acked,.rowhead.acked,.badge.acked{opacity:0.55}.deckmore{color:var(--dim);font-size:11px;display:inline-block;margin-top:4px}.deckline.click{cursor:pointer}.deckline.click:hover{background:var(--row-hover)}.deckgrid h2 a{color:inherit}.deckgrid h2 a:hover{color:var(--fg)}.deckgrid .cards{grid-template-columns:repeat(auto-fill,minmax(min(var(--deck-card-min),100%),1fr));gap:10px}.deckstack{margin-bottom:9px}.deckstack>.dim{font-size:11px;margin:3px 0 5px}.seg{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}.seg button{background:var(--card);border:none;color:var(--dim);font:inherit;padding:4px 11px;cursor:pointer}.seg button.on{background:var(--seg-on);color:var(--fg)}.wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}th,td{text-align:left;padding:4px 9px;border-top:1px solid var(--line);vertical-align:top;white-space:nowrap}td.grow{white-space:normal;word-break:break-word;min-width:140px}th{color:var(--dim);font-weight:normal;border-top:none;font-size:11px}tr.rowhead{cursor:pointer}tr.rowhead:hover{background:var(--row-hover)}.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--card-min),100%),1fr));gap:var(--space-3)}.card{background:var(--card);border:1px solid var(--line);border-radius:var(--card-radius);padding:var(--card-pad);cursor:pointer;min-width:0;overflow:hidden;overflow-wrap:anywhere}.card:hover{border-color:var(--line-hover)}.card .top{display:flex;justify-content:space-between;gap:var(--space-3);align-items:center;min-height:22px}.card .top>b,.card .top>.prname{flex:1 1000000 auto;min-width:min(10ch,100%);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card .top .badge{flex:0 0 auto}.card .top .badge.long{flex:0 1 auto;min-width:min(12ch,100%);max-width:min(26ch,100%);overflow:hidden;text-overflow:ellipsis}.card .meta{color:var(--dim);font-size:12px;margin-top:2px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.card .note{margin-top:6px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.activity{margin-top:4px;font-size:12px;color:var(--fg);opacity:0.85}.waiting{margin-top:4px;font-size:12px;color:var(--dim)}.activity.stale{color:var(--dim);opacity:1}.card .foot{margin-top:8px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;color:var(--dim);font-size:12px}.card .foot>*{min-width:0}.card .foot .footact{margin-left:auto}.btn{background:var(--card);border:1px solid var(--line);border-radius:5px;color:var(--dim);font:inherit;font-size:11px;padding:1px 8px;cursor:pointer;white-space:nowrap}.btn:hover{color:var(--fg);border-color:var(--line-hover)}.badge{border-radius:var(--badge-radius);padding:var(--badge-pad);font-size:var(--badge-font);line-height:1.5;border:1px solid var(--line);white-space:nowrap;display:inline-block}.badge.pr-merged{background:var(--pr-merged);border-color:var(--pr-merged-fg);color:var(--on-fill)}.badge.pr-open{background:var(--pr-open);border-color:var(--pr-open);color:var(--on-fill)}.badge.pr-draft{background:var(--pr-draft);border-color:var(--pr-draft);color:var(--on-fill)}.badge.pr-closed{background:var(--pr-closed);border-color:var(--pr-closed);color:var(--on-fill)}.badge.pr-conflicts{background:var(--pr-closed);border-color:var(--pr-closed);color:var(--on-fill)}.badge.pr-behind{background:var(--pr-draft);border-color:var(--pr-draft);color:var(--on-fill)}.badge.unreported{font-weight:normal;font-size:10px;padding:0 5px;vertical-align:1px}.v-done{color:var(--ok)}.v-working,.v-queued{color:var(--fg)}.v-needs-decision,.v-blocked{color:var(--bad);font-weight:bold}.v-failed{color:var(--bad)}.v-paused,.v-unknown{color:var(--dim)}.dim{color:var(--dim)}.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}.detail{display:none}.detail.open{display:table-row}.detail td{background:var(--inset);white-space:pre-wrap;word-break:break-word;font-size:12px;color:var(--dim)}.detail b{color:var(--fg)}.empty{color:var(--dim);padding:6px 2px}#stale{display:none;color:var(--bad)}a{color:var(--link);text-decoration:none}.dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle}.dot.ok{background:var(--ok)}.dot.warn{background:var(--warn)}.dot.bad{background:var(--bad)}.dot.dim{background:var(--dim)}#overlay{position:fixed;inset:0;background:var(--scrim);display:none;z-index:10;padding:28px 16px;overflow:auto}#overlay.open{display:block}.modal{max-width:var(--modal-width);margin:0 auto;background:var(--card);border:1px solid var(--line);border-radius:var(--modal-radius);padding:16px 18px;position:relative}.modal .x{position:absolute;top:8px;right:12px;cursor:pointer;color:var(--dim);font-size:18px;line-height:1}.modal .x:hover{color:var(--fg)}.modal h3{margin:0 24px 2px 0;font-size:14px}.modal .sub{color:var(--dim);font-size:12px;margin-bottom:10px}.modal .sec{color:var(--dim);text-transform:uppercase;letter-spacing:0.08em;font-size:11px;margin:14px 0 4px}.modal pre{white-space:pre-wrap;word-break:break-word;margin:0;font:inherit;color:var(--fg)}.msg{border-left:3px solid var(--line);padding:3px 10px;margin:8px 0;white-space:pre-wrap;word-break:break-word}.msg.from-helm{border-color:var(--link)}.msg .hdr{color:var(--dim);font-size:11px}.catch{border:1px solid var(--line);border-radius:var(--radius);padding:6px 10px;margin:8px 0}.catch .hdr{display:flex;gap:10px;flex-wrap:wrap;align-items:baseline}.loglines{color:var(--dim);font-size:12px;white-space:pre-wrap;word-break:break-word;margin-top:4px}.cmd{display:flex;gap:var(--space-2);align-items:center;margin:5px 0;flex-wrap:wrap}.cmd code{background:var(--inset);border:1px solid var(--line);border-radius:5px;padding:3px 8px;word-break:break-all;cursor:pointer}.cmd code:hover{border-color:var(--line-hover)}.cmd code.copied{border-color:var(--ok)}.cmd button{background:var(--card);border:1px solid var(--line);border-radius:5px;color:var(--dim);font:inherit;font-size:11px;padding:2px 8px;cursor:pointer}.cmd button:hover{color:var(--fg)}.chip.click{cursor:pointer}.chip.click:hover{border-color:var(--line-hover)}footer{margin-top:26px;padding-top:10px;border-top:1px solid var(--line);color:var(--dim);font-size:12px;display:flex;gap:var(--space-2);flex-wrap:wrap}.lob{position:fixed;bottom:6px;left:0;z-index:5;cursor:pointer;font-size:34px;line-height:1;user-select:none;animation:crawl 18s linear infinite}a.lob{color:inherit}.lob .bub .badge{display:inline-block;margin:0 0 3px}.lob .sprite{width:72px;height:56px;background:url(/lob-sprite.png) 0 0 no-repeat;background-size:400% 100%;image-rendering:pixelated;animation:step 0.5s steps(4) infinite}.lob .fallback{display:inline-block;animation:waddle 0.45s ease-in-out infinite alternate}.lob .bub{display:none;position:absolute;bottom:58px;right:-8px;z-index:2;background:var(--card);border:1px solid var(--line);border-radius:9px;padding:6px 9px 5px;font-size:11px;line-height:1.35;color:var(--fg);width:max-content;max-width:150px;box-shadow:0 2px 8px rgba(0,0,0,0.4)}.lob:hover .bub{display:block}.lob .bub span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;white-space:normal;word-break:break-word}.lob .star{position:absolute;left:56px;top:-9px;height:14px;image-rendering:pixelated;z-index:3}.lob:hover{animation-play-state:paused}@keyframes crawl{0%{transform:translateX(-90px)}100%{transform:translateX(100vw)}}@keyframes step{to{background-position-x:-288px}}@keyframes waddle{from{transform:rotate(-8deg) translateY(0)}to{transform:rotate(8deg) translateY(-3px)}}#gearbtn{background:none;border:1px solid var(--line);border-radius:var(--radius);color:var(--dim);font:inherit;font-size:13px;padding:1px 7px;margin-left:8px;cursor:pointer;vertical-align:1px}#gearbtn:hover,#gearbtn.on{color:var(--fg);border-color:var(--line-hover)}.settings .row{display:flex;justify-content:space-between;align-items:center;gap:14px;margin:12px 0}.settings .lbl{color:var(--fg);font-size:12px}.settings .hint{display:block;color:var(--dim);font-size:11px;margin-top:2px}.dcards{display:flex;flex-direction:column;gap:10px}.dcard{width:100%;background:var(--card);border:1px solid var(--line);border-radius:var(--card-radius);padding:var(--card-pad)}.dcard.focus{border-color:var(--link)}.dcard.answered{opacity:0.7}.dcard .dtop{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-2)}.dcard .dtop .badge{margin-top:0}.dcard .dtitle{white-space:pre-wrap;overflow-wrap:anywhere}.dcard .dmeta{font-size:11px;margin-left:auto}.dcard .dlink{color:var(--link)}.dfiles{display:flex;flex-wrap:wrap;gap:var(--space-2);margin:6px 0}.dfiles .dimg img{max-height:160px;max-width:320px;border:1px solid var(--line);border-radius:var(--radius);display:block}.dfiles .dfile{width:100%;font-size:11px}.doptions{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 6px}.btn.dopt{font-size:12px;padding:3px 12px;color:var(--fg)}.btn.dopt.on{background:var(--seg-on);border-color:var(--link)}.danswer{display:block;width:100%;min-height:3.2em;max-height:50vh;margin:6px 0;padding:6px 8px;resize:vertical;overflow-y:auto;field-sizing:content;background:var(--inset);color:var(--fg);border:1px solid var(--line);border-radius:var(--radius);font:inherit}.danswer:focus{outline:none;border-color:var(--line-hover)}.dfoot{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.dfoot .dattach input{display:none}.dfoot .dchip{font-size:11px;border:1px solid var(--line);border-radius:var(--badge-radius);padding:0 0 0 6px}.dfoot .dx{background:none;border:none;color:var(--dim);cursor:pointer;font:inherit}.dfoot .derr{font-size:11px}.btn.dsend{margin-left:auto;color:var(--fg);padding:2px 14px}.btn:disabled{cursor:default;opacity:0.6}.danswered{margin-top:6px}.thumb,.dimg,.mdimg{background:none;border:none;padding:0;cursor:zoom-in;font:inherit}.thumb{display:block;margin:4px 0}.thumb img{max-height:120px;max-width:240px;border:1px solid var(--line);border-radius:var(--radius);display:block}.lightbox{position:fixed;inset:0;z-index:20;background:rgba(0,0,0,0.85);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2)}.lightbox .lbimg{max-width:90vw;max-height:90vh;object-fit:contain;border-radius:var(--radius);box-shadow:0 8px 40px rgba(0,0,0,0.6)}.lightbox .lbclose{position:absolute;top:12px;right:16px;background:none;border:none;color:var(--fg);font-size:28px;line-height:1;cursor:pointer}.lightbox .lboriginal{color:var(--link);font-size:12px}.mdpage{background:var(--inset);border:1px solid var(--line);border-radius:6px;padding:8px 14px;margin:6px 0;line-height:1.5;overflow-wrap:anywhere}.mdpage h1,.mdpage h2,.mdpage h3,.mdpage h4{margin:12px 0 6px;line-height:1.25}.mdpage h1{font-size:18px}.mdpage h2{font-size:15px}.mdpage h3,.mdpage h4{font-size:13px}.mdpage p,.mdpage ul,.mdpage ol,.mdpage blockquote{margin:6px 0}.mdpage ul,.mdpage ol{padding-left:22px}.mdpage a{color:var(--link)}.mdpage code{background:var(--card);border-radius:3px;padding:0 3px}.mdpage pre.mdcode{background:var(--card);border:1px solid var(--line);border-radius:4px;padding:8px;overflow-x:auto;white-space:pre}.mdpage pre.mdcode code{padding:0;background:none}.mdpage blockquote{border-left:3px solid var(--line);padding-left:10px;color:var(--dim)}.mdpage img{max-width:100%;height:auto;border-radius:4px;display:block;margin:6px 0}.mdpage hr{border:0;border-top:1px solid var(--line)}.mdpage .mdtable{overflow-x:auto}.mdpage table{border-collapse:collapse;margin:6px 0}.mdpage th,.mdpage td{border:1px solid var(--line);padding:3px 8px;text-align:left}.tabhead{margin:0 0 8px}.newtrap{display:inline-flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:12px;font-weight:normal;text-transform:none;letter-spacing:normal}.startcmds{margin:6px 0;font-size:11px;cursor:default}</style>\n </head>\n <body>\n <!-- The page is rendered by Preact (src/components/app.ts): header, tabs, controls, the five tab pages, footer, lobs, modal overlay. -->\n <script>"use strict";(()=>{var Ae,b,Bt,Hs,j,Lt,jt,Ut,Xe,Te,ie,Ft,Ze,Je,Qe,Os,Ge={},Ce=[],Bs=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Re=Array.isArray;function P(e,t){for(var n in t)e[n]=t[n];return e}function Ye(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function ae(e,t,n){var s,r,o,i={};for(o in t)o=="key"?s=t[o]:o=="ref"?r=t[o]:i[o]=t[o];if(arguments.length>2&&(i.children=arguments.length>3?Ae.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)i[o]===void 0&&(i[o]=e.defaultProps[o]);return xe(e,i,s,r,null)}function xe(e,t,n,s,r){var o={type:e,props:t,key:n,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:r??++Bt,__i:-1,__u:0};return r==null&&b.vnode!=null&&b.vnode(o),o}function J(e){return e.children}function Se(e,t){this.props=e,this.context=t}function W(e,t){if(t==null)return e.__?W(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type=="function"?W(e):null}function js(e){if(e.__P&&e.__d){var t=e.__v,n=t.__e,s=[],r=[],o=P({},t);o.__v=t.__v+1,b.vnode&&b.vnode(o),et(e.__P,o,t,e.__n,e.__P.namespaceURI,32&t.__u?[n]:null,s,n??W(t),!!(32&t.__u),r),o.__v=t.__v,o.__.__k[o.__i]=o,zt(s,o,r),t.__e=t.__=null,o.__e!=n&&qt(o)}}function qt(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),qt(e)}function Nt(e){(!e.__d&&(e.__d=!0)&&j.push(e)&&!De.__r++||Lt!=b.debounceRendering)&&((Lt=b.debounceRendering)||jt)(De)}function De(){try{for(var e,t=1;j.length;)j.length>t&&j.sort(Ut),e=j.shift(),t=j.length,js(e)}finally{j.length=De.__r=0}}function Wt(e,t,n,s,r,o,i,c,u,l,f){var h,d,m,p,g,x,T=s&&s.__k||Ce,$=t.length;for(u=Us(n,t,T,u,$),h=0;h<$;h++)(m=n.__k[h])!=null&&(d=m.__i!=-1&&T[m.__i]||Ge,m.__i=h,x=et(e,m,d,r,o,i,c,u,l,f),p=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&tt(d.ref,null,m),f.push(m.ref,m.__c||p,m)),g==null&&p!=null&&(g=p),4&m.__u?(u=Kt(m,u,e),d.__e&&(d.__e=null)):typeof m.type=="function"&&x!==void 0?u=x:p&&(u=p.nextSibling),m.__u&=-7);return n.__e=g,u}function Us(e,t,n,s,r){var o,i,c,u,l,f=n.length,h=f,d=0;for(e.__k=new Array(r),o=0;o<r;o++)(i=t[o])!=null&&typeof i!="boolean"&&typeof i!="function"?(typeof i=="string"||typeof i=="number"||typeof i=="bigint"||i.constructor==String?i=e.__k[o]=xe(null,i,null,null,null):Re(i)?i=e.__k[o]=xe(J,{children:i},null,null,null):i.constructor===void 0&&i.__b>0?i=e.__k[o]=xe(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):e.__k[o]=i,u=o+d,i.__=e,i.__b=e.__b+1,c=null,(l=i.__i=Fs(i,n,u,h))!=-1&&(h--,(c=n[l])&&(c.__u|=2)),c==null||c.__v==null?(l==-1&&(r>f?d--:r<f&&d++),typeof i.type!="function"&&(i.__u|=4)):l!=u&&(l==u-1?d--:l==u+1?d++:(l>u?d--:d++,i.__u|=4))):e.__k[o]=null;if(h)for(o=0;o<f;o++)(c=n[o])!=null&&(2&c.__u)==0&&(c.__e==s&&(s=W(c)),Jt(c,c));return s}function Kt(e,t,n){var s,r;if(typeof e.type=="function"){for(s=e.__k,r=0;s&&r<s.length;r++)s[r]&&(s[r].__=e,t=Kt(s[r],t,n));return t}e.__e!=t&&(t&&e.type&&!t.parentNode&&(t=W(e)),t=n.insertBefore(e.__e,t||null));do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function Fs(e,t,n,s){var r,o,i,c=e.key,u=e.type,l=t[n],f=l!=null&&(2&l.__u)==0;if(l===null&&c==null||f&&c==l.key&&u==l.type)return n;if(s>(f?1:0)){for(r=n-1,o=n+1;r>=0||o<t.length;)if((l=t[i=r>=0?r--:o++])!=null&&(2&l.__u)==0&&c==l.key&&u==l.type)return i}return-1}function Ht(e,t,n){t[0]=="-"?e.setProperty(t,n??""):e[t]=n==null?"":typeof n!="number"||Bs.test(t)?n:n+"px"}function we(e,t,n,s,r){var o,i;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof s=="string"&&(e.style.cssText=s=""),s)for(t in s)n&&t in n||Ht(e.style,t,"");if(n)for(t in n)s&&n[t]==s[t]||Ht(e.style,t,n[t])}else if(t[0]=="o"&&t[1]=="n")o=t!=(t=t.replace(Ft,"$1")),i=t.toLowerCase(),t=i in e||t=="onFocusOut"||t=="onFocusIn"?i.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+o]=n,n?s?n[ie]=s[ie]:(n[ie]=Ze,e.addEventListener(t,o?Qe:Je,o)):e.removeEventListener(t,o?Qe:Je,o);else{if(r=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&n==1?"":n))}}function Ot(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t[Te]==null)t[Te]=Ze++;else if(t[Te]<n[ie])return;return n(b.event?b.event(t):t)}}}function et(e,t,n,s,r,o,i,c,u,l){var f,h,d,m,p,g,x,T,$,I,re,q,oe,Et,ye,ze,M=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(u=!!(32&n.__u),o=[c=t.__e=n.__e]),(f=b.__b)&&f(t);e:if(typeof M=="function"){h=i.length;try{if($=t.props,I=M.prototype&&M.prototype.render,re=(f=M.contextType)&&s[f.__c],q=f?re?re.props.value:f.__:s,n.__c?T=(d=t.__c=n.__c).__=d.__E:(I?t.__c=d=new M($,q):(t.__c=d=new Se($,q),d.constructor=M,d.render=Ws),re&&re.sub(d),d.state||(d.state={}),d.__n=s,m=d.__d=!0,d.__h=[],d._sb=[]),I&&d.__s==null&&(d.__s=d.state),I&&M.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=P({},d.__s)),P(d.__s,M.getDerivedStateFromProps($,d.__s))),p=d.props,g=d.state,d.__v=t,m)I&&M.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),I&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(I&&M.getDerivedStateFromProps==null&&$!==p&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps($,q),t.__v==n.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate($,d.__s,q)===!1){t.__v!=n.__v&&(d.props=$,d.state=d.__s,d.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(X){X&&(X.__=t)}),Ce.push.apply(d.__h,d._sb),d._sb=[],d.__h.length&&i.push(d),c=W(n);break e}d.componentWillUpdate!=null&&d.componentWillUpdate($,d.__s,q),I&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(p,g,x)})}if(d.context=q,d.props=$,d.__P=e,d.__e=!1,oe=b.__r,Et=0,I)d.state=d.__s,d.__d=!1,oe&&oe(t),f=d.render(d.props,d.state,d.context),Ce.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,oe&&oe(t),f=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++Et<25);d.state=d.__s,d.getChildContext!=null&&(s=P(P({},s),d.getChildContext())),I&&!m&&d.getSnapshotBeforeUpdate!=null&&(x=d.getSnapshotBeforeUpdate(p,g)),ye=f!=null&&f.type===J&&f.key==null?Xt(f.props.children):f,c=Wt(e,Re(ye)?ye:[ye],t,n,s,r,o,i,c,u,l),d.base=t.__e,t.__u&=-161,d.__h.length&&i.push(d),T&&(d.__E=d.__=null)}catch(X){if(i.length=h,t.__v=null,u||o!=null){if(X.then){for(t.__u|=u?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;o!=null&&(o[o.indexOf(c)]=null),t.__e=c}else if(o!=null)for(ze=o.length;ze--;)Ye(o[ze])}else t.__e=n.__e;t.__k==null&&(t.__k=n.__k||[]),X.then||Vt(t),b.__e(X,t,n)}}else o==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):c=t.__e=qs(n.__e,t,n,s,r,o,i,u,l);return(f=b.diffed)&&f(t),128&t.__u?void 0:c}function Vt(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(Vt))}function zt(e,t,n){for(var s=0;s<n.length;s++)tt(n[s],n[++s],n[++s]);b.__c&&b.__c(t,e),e.some(function(r){try{e=r.__h,r.__h=[],e.some(function(o){o.call(r)})}catch(o){b.__e(o,r.__v)}})}function Xt(e){return typeof e!="object"||e==null||e.__b>0?e:Re(e)?e.map(Xt):e.constructor!==void 0?null:P({},e)}function qs(e,t,n,s,r,o,i,c,u){var l,f,h,d,m,p,g,x=n.props||Ge,T=t.props,$=t.type;if($=="svg"?r="http://www.w3.org/2000/svg":$=="math"?r="http://www.w3.org/1998/Math/MathML":r||(r="http://www.w3.org/1999/xhtml"),o!=null){for(l=0;l<o.length;l++)if((m=o[l])&&"setAttribute"in m==!!$&&($?m.localName==$:m.nodeType==3)){e=m,o[l]=null;break}}if(e==null){if($==null)return document.createTextNode(T);e=document.createElementNS(r,$,T.is&&T),c&&(b.__m&&b.__m(t,o),c=!1),o=null}if($==null)x===T||c&&e.data==T||(e.data=T);else{if(o=$=="textarea"&&T.defaultValue!=null?null:o&&Ae.call(e.childNodes),!c&&o!=null)for(x={},l=0;l<e.attributes.length;l++)x[(m=e.attributes[l]).name]=m.value;for(l in x)m=x[l],l=="dangerouslySetInnerHTML"?h=m:l=="children"||l in T||l=="value"&&"defaultValue"in T||l=="checked"&&"defaultChecked"in T||we(e,l,null,m,r);for(l in T)m=T[l],l=="children"?d=m:l=="dangerouslySetInnerHTML"?f=m:l=="value"?p=m:l=="checked"?g=m:c&&typeof m!="function"||x[l]===m||we(e,l,m,x[l],r);if(f)c||h&&(f.__html==h.__html||f.__html==e.innerHTML)||(e.innerHTML=f.__html),t.__k=[];else if(h&&(e.innerHTML=""),Wt(t.type=="template"?e.content:e,Re(d)?d:[d],t,n,s,$=="foreignObject"?"http://www.w3.org/1999/xhtml":r,o,i,o?o[0]:n.__k&&W(n,0),c,u),o!=null)for(l=o.length;l--;)Ye(o[l]);c&&$!="textarea"||(l="value",$=="progress"&&p==null?e.removeAttribute("value"):p!=null&&(p!==e[l]||$=="progress"&&!p||$=="option"&&p!=x[l])&&we(e,l,p,x[l],r),l="checked",g!=null&&g!=e[l]&&we(e,l,g,x[l],r))}return e}function tt(e,t,n){try{if(typeof e=="function"){var s=typeof e.__u=="function";s&&e.__u(),s&&t==null||(e.__u=e(t))}else e.current=t}catch(r){b.__e(r,n)}}function Jt(e,t,n){var s,r;if(b.unmount&&b.unmount(e),(s=e.ref)&&(s.current&&s.current!=e.__e||tt(s,null,t)),(s=e.__c)!=null){if(s.componentWillUnmount)try{s.componentWillUnmount()}catch(o){b.__e(o,t)}s.base=s.__P=s.__n=null}if(s=e.__k)for(r=0;r<s.length;r++)s[r]&&Jt(s[r],t,n||typeof e.type!="function");n||Ye(e.__e),e.__c=e.__=e.__e=void 0}function Ws(e,t,n){return this.constructor(e,n)}function Qt(e,t,n){var s,r,o,i;t==document&&(t=document.documentElement),b.__&&b.__(e,t),r=(s=typeof n=="function")?null:n&&n.__k||t.__k,o=[],i=[],et(t,e=(!s&&n||t).__k=ae(J,null,[e]),r||Ge,Ge,t.namespaceURI,!s&&n?[n]:r?null:t.firstChild?Ae.call(t.childNodes):null,o,!s&&n?n:r?r.__e:t.firstChild,s,i),zt(o,e,i),e.props.children=null}Ae=Ce.slice,b={__e:function(e,t,n,s){for(var r,o,i;t=t.__;)if((r=t.__c)&&!r.__)try{if((o=r.constructor)&&o.getDerivedStateFromError!=null&&(r.setState(o.getDerivedStateFromError(e)),i=r.__d),r.componentDidCatch!=null&&(r.componentDidCatch(e,s||{}),i=r.__d),i)return r.__E=r}catch(c){e=c}throw e}},Bt=0,Hs=function(e){return e!=null&&e.constructor===void 0},Se.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=P({},this.state),typeof e=="function"&&(e=e(P({},n),this.props)),e&&P(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),Nt(this))},Se.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Nt(this))},Se.prototype.render=J,j=[],jt=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Ut=function(e,t){return e.__v.__b-t.__v.__b},De.__r=0,Xe=Math.random().toString(8),Te="__d"+Xe,ie="__a"+Xe,Ft=/(PointerCapture)$|Capture$/i,Ze=0,Je=Ot(!1),Qe=Ot(!0),Os=0;function E(e){if(!e)return"dim";let t=e.state||"open";return t==="open"&&e.merge?"pr-"+e.merge:t==="open"&&e.tone&&e.tone!=="ok"?e.tone:"pr-"+t}var le=["deck","dispatches","traps","prs","reports","notices"];function tn(e){let t=String(e||"").replace(/^#/,"");return le.includes(t)?t:"deck"}function ce(e){let t=/^report:(work|chore):(.+)$/.exec(e);return t?{type:"dispatch",key:`${t[1]}:${t[2]}`}:{type:"report",key:e}}function nn(e){let t=/^#?report\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return ce(decodeURIComponent(t[1]))}catch{return null}}var sn=e=>`#decision/${encodeURIComponent(e)}`;function nt(e){let t=/^#?decision\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var st=(e,t,n)=>`/attachment/dispatch/${encodeURIComponent(e)}/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,rn=(e,t)=>`/attachment/trap/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,on=e=>/\\.(png|jpe?g|gif|webp)$/i.test(e),rt=(e,t)=>`/decision/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function ot(e,t){let n=new Map(t.map(r=>[r.key,r])),s=[];for(let r of e)if(r.kind==="decision"){let o=n.get(r.key);if(!o)continue;s.push({kind:"decision",key:o.key,title:o.title,detail:o.detail,options:o.options,attachments:o.attachments,...o.dispatch?{dispatch:o.dispatch,lane:o.lane??"work"}:{},...o.repo?{repo:o.repo}:{},at:o.askedAt})}else r.kind==="question"&&s.push({kind:"question",key:r.key,verb:r.verb,note:r.note||r.verb,dispatch:r.id,lane:r.lane,...r.repo?{repo:r.repo}:{},at:r.at??""});return s.sort((r,o)=>o.at.localeCompare(r.at)||r.key.localeCompare(o.key))}function an(e){let t=(e.text??"").split(`\n`).map(n=>n.trim()).find(Boolean)??"";return[e.option,t&&(t.length>80?t.slice(0,79)+"\\u2026":t),e.files?`${e.files} file${e.files===1?"":"s"}`:""].filter(Boolean).join(" \\xB7 ")}function ln(e,t){return(e.reports||[]).find(n=>n.key===`report:${t.lane}:${t.id}`)}function de(e){return e.author==="helm"?"":e.trap?e.trap:e.author==="headless"?e.dispatch?e.dispatch.slice(0,8):"":e.author}var Zt=(e,t)=>+!!e.acked-+!!t.acked||t.filedAt.localeCompare(e.filedAt),cn=e=>`/report/${encodeURIComponent(e)}/md`,it=(e,t)=>`/report/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function Yt(e,t,n){return!!e&&n-Date.parse(e)>t}function en(e,t){if(t.lane&&e.lane!==t.lane||t.repo&&e.repo!==t.repo||t.verb&&e.verb!==t.verb)return!1;if(t.q){let n=t.q.toLowerCase();if(!(e.id+" "+(e.note||"")+" "+(e.brief||"")+" "+(e.repo||"")+" "+(e.for||"")).toLowerCase().includes(n))return!1}return!0}function Q(e,t){return t?t.type==="helm"?e.helms.find(n=>n.grounds===t.key)||null:t.type==="dispatch"?e.dispatches.find(n=>n.lane+":"+n.id===t.key)||null:t.type==="pr"?(e.prs||[]).find(n=>n.key===t.key)||null:t.type==="report"?(e.reports||[]).find(n=>n.key===t.key)||null:t.type==="settings"?{attentionKinds:e.attentionKinds||[],attentionError:e.attentionError}:e.traps.find(n=>n.trapId===t.key)||null:null}function dn(e,t,n){let s=t.st,r=String(s.q||"").toLowerCase(),o=(...p)=>!r||p.join(" ").toLowerCase().includes(r),i=p=>({x:p,stale:Yt(p.heartbeatAt,18e5,n)}),c=Q(e,t.modal),u=(p,g)=>!!p&&n-Date.parse(p)<=g,l=p=>Math.max(0,...(p.notices||[]).filter(g=>g.kind==="trap-stowed"||g.kind==="trap-ghosted").map(g=>Date.parse(g.at)||0)),f=p=>p.live||!!p.starting||!!p.requested,h=[...e.traps||[]].sort((p,g)=>Number(f(g))-Number(f(p))||Number(g.live)-Number(p.live)||(p.live?(Date.parse(p.signedOnAt||"")||0)-(Date.parse(g.signedOnAt||"")||0):l(g)-l(p))||(p.name??p.trapId).localeCompare(g.name??g.trapId)),d=h.filter(p=>(f(p)||(p.notices||[]).some(g=>(g.kind==="trap-stowed"||g.kind==="trap-ghosted")&&u(g.at,36e5)))&&o(p.name,p.trapId,p.repo,p.worktree)),m=({ageSecs:p,...g})=>g;return{chips:{daemon:e.daemon,daemonStale:!!e.daemon&&Yt(e.daemon.heartbeat,9e4,n),helms:e.helms.map(i)},deck:{view:s.view,decisions:ot(e.attention||[],e.decisions||[]).filter(p=>p.kind==="decision"?o(p.kind,p.repo,p.title,p.dispatch,p.detail):o(p.kind,p.repo,p.note,p.dispatch)),prAttention:(e.attention||[]).filter(p=>p.kind&&p.kind.startsWith("pr:")).map(m),landed:(e.landed||[]).filter(p=>u(p.at,864e5)&&o(p.repo,p.note,p.id)).sort((p,g)=>Date.parse(g.at)-Date.parse(p.at)).slice(0,8),reports:(e.reports||[]).filter(p=>o(p.title,p.author,p.dispatch,p.repo)).sort(Zt),inflight:e.dispatches.filter(p=>p.bucket!=="done"&&en(p,{...s,lane:"",repo:"",verb:""})),traps:d.map(i),stacks:(e.stacks||[]).filter(p=>p.open&&o(p.repo,p.numbers.join(" "))),prs:(e.prs||[]).filter(p=>p.state==="OPEN"),error:e.attentionError},dispatches:{view:s.view,chain:s.chain,list:e.dispatches.filter(p=>en(p,s))},traps:{view:s.view,list:h.filter(p=>(!s.repo||p.repo===s.repo)&&o(p.name,p.trapId,p.repo,p.worktree,p.harness)).map(i)},prs:{view:s.view,stacks:(e.stacks||[]).filter(p=>!s.repo||p.repo===s.repo),prs:(e.prs||[]).filter(p=>(!s.repo||p.repo===s.repo)&&o(p.number,p.title,p.url,p.state,p.baseRefName,p.headRefName)),watches:(e.watches||[]).filter(p=>!String(p.key).startsWith("pr:"))},reports:{view:s.view,list:(e.reports||[]).filter(p=>(!s.repo||p.repo===s.repo)&&o(p.title,p.author,p.dispatch,p.repo)).sort(Zt)},notices:{list:(e.notices||[]).filter(p=>(!s.repo||!p.repo||p.repo===s.repo)&&(!s.noticeKind||p.kind===s.noticeKind)&&o(p.kind,p.text,p.repo))},foot:{version:e.version,repoUrl:e.repoUrl},modal:{modal:t.modal,item:c&&i(c),prefs:t.modal&&t.modal.type==="settings"?{view:s.view,lobs:s.lobs}:void 0}}}function pn(e,t){let n=(e.prs||[]).find(c=>c.key===t);if(!n)return null;let s=(e.stacks||[]).find(c=>c.id===n.stackId),r=new Map((e.dispatches||[]).map(c=>[c.id,c])),o=(n.dispatchIds||[]).map(c=>{let u=r.get(c);return u?{id:c,verb:u.verb,modalKey:u.lane+":"+u.id}:{id:c,culled:!0}}),i=n.watch;return{pr:n,stack:s?{numbers:s.numbers,titles:s.numbers.map(c=>(e.prs||[]).find(u=>u.stackId===s.id&&u.number===c)?.title||""),position:n.position+1,size:s.numbers.length,floor:s.floor,nextNumber:s.nextNumber,nextMergeable:!!n.nextMergeable,blockedBy:n.blockedBy}:null,chain:o,watch:i?{key:i.key,owner:i.owner||"",lastCheckedAt:i.lastCheckedAt||null,lastError:i.lastError||null,cursor:i.cursor}:null}}function un(e){return e?{text:e.lastError?"failing":"watching",at:e.lastCheckedAt||null}:{text:"no watch",at:null}}function fn(){let e={view:"table",lane:"",repo:"",verb:"",q:"",lobs:!0,chain:!1,noticeKind:""};try{Object.assign(e,JSON.parse(localStorage.getItem("spyglass")||"{}"))}catch{}return e.view!=="table"&&e.view!=="cards"&&(e.view="table"),e.lobs=e.lobs!==!1,e}function mn(e){try{localStorage.setItem("spyglass",JSON.stringify(e))}catch{}}function hn(){try{return JSON.parse(localStorage.getItem("spyglass-lob-hidden")||"{}")||{}}catch{return{}}}function gn(e){try{localStorage.setItem("spyglass-lob-hidden",JSON.stringify(e))}catch{}}var pe,vn=new Set,_=()=>pe;function _n(e){pe=e}function S(e){pe={...pe,...e};for(let t of vn)t(pe)}var $n=e=>{vn.add(e)};function at(e){let{modal:t,drafts:n}=_(),s=new Set(ot(e.attention||[],e.decisions||[]).map(o=>o.key)),r=Object.fromEntries(Object.entries(n).filter(([o])=>s.has(o)));S({snapshot:e,stale:!1,modal:t&&Q(e,t)?t:null,...Object.keys(r).length!==Object.keys(n).length?{drafts:r}:{}}),Ie()}var bn=()=>({text:"",files:[]});function A(e,t){let n=_().drafts;S({drafts:{...n,[e]:{...n[e]??bn(),...t}}})}function kn(e,t){let n=_().drafts[e]?.option;A(e,{option:n===t?void 0:t,error:void 0})}var Ks=e=>new Promise((t,n)=>{let s=new FileReader;s.onload=()=>t(String(s.result).replace(/^data:[^,]*,/,"")),s.onerror=()=>n(s.error),s.readAsDataURL(e)});async function lt(e,t){let n=_().snapshot?.answerLimits,s=[...t??[]],r=_().drafts[e]?.files??[],o=[],i=[];for(let c of s){let u=(/\\.[^.]+$/.exec(c.name)?.[0]??"").toLowerCase();if(n&&!n.extensions.includes(u))o.push(`${c.name}: type not accepted`);else if(n&&c.size>n.maxBytes)o.push(`${c.name}: larger than ${n.maxBytes} bytes`);else if(n&&r.length+i.length>=n.maxFiles)o.push(`${c.name}: at most ${n.maxFiles} files`);else try{i.push({name:c.name,bytes:c.size,data:await Ks(c)})}catch{o.push(`${c.name}: could not be read`)}}A(e,{files:[..._().drafts[e]?.files??[],...i],error:o.length?o.join("; "):void 0})}var Vs={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};async function yn(e,t){let n=[...t.clipboardData?.items??[]],s=new Date().toISOString().replace(/[:.]/g,"-").replace(/-\\d{3}Z$/,"Z"),r=n.filter(o=>o.kind==="file"&&o.type.startsWith("image/")).map(o=>o.getAsFile()).filter(o=>o!==null).map((o,i,c)=>{let u=`pasted-${s}${c.length>1?`-${i+1}`:""}${Vs[o.type]??".png"}`;return new File([o],u,{type:o.type})});r.length&&await lt(e,r)}function wn(e,t){let n=(_().drafts[e]?.files??[]).filter((s,r)=>r!==t);A(e,{files:n})}async function Tn(e){let t=_().snapshot?.focusToken,n=_().drafts[e]??bn();if(!(n.sending||n.sent)){if(!n.option&&!n.text.trim()&&n.files.length===0){A(e,{error:"Choose an option, write an answer, or attach a file."});return}if(!t){A(e,{error:"This page has no answer token; reload it."});return}A(e,{sending:!0,error:void 0});try{let s=await fetch("/requests",{method:"POST",headers:{"content-type":"application/json","x-lobstah-token":t},body:JSON.stringify({kind:"decision-answer",payload:{key:e,...n.option?{option:n.option}:{},...n.text.trim()?{text:n.text}:{},files:n.files.map(o=>({name:o.name,data:o.data}))}})}),r=await s.json();if(!s.ok||!r.ok){A(e,{sending:!1,error:r.reason??`The answer was refused (${s.status}).`});return}A(e,{sending:!1,sent:an({option:n.option,text:n.text,files:n.files.length})})}catch{A(e,{sending:!1,error:"The answer could not be sent."})}}}function Ie(){let{snapshot:e,modal:t,reportText:n}=_();if(!e||!t)return;let s=t.type==="report"?(e.reports||[]).find(c=>c.key===t.key):t.type==="dispatch"?(e.reports||[]).find(c=>"report:"+t.key===c.key):void 0;if(!s||n[s.key]?.hash===s.stateHash)return;let r=s.key,o=s.stateHash,i=c=>S({reportText:{..._().reportText,[r]:{hash:o,...c}}});i({}),fetch(cn(r)).then(async c=>c.ok===!1?i({error:`report not found (${c.status})`}):i({text:await c.text()})).catch(()=>i({error:"report could not be read"}))}var xn=()=>S({stale:!0}),Sn=(e,t)=>S({lightbox:{src:e,name:t}}),ue=()=>S({lightbox:null});function C(e,t){let{snapshot:n}=_(),s={type:e,key:t};S({modal:!n||Q(n,s)?s:null}),Ie()}function Z(){/^#report\\//.test(location.hash)&&history.replaceState(null,"","#deck"),S({modal:null})}async function Gn(e){let t=_().snapshot?.focusToken;if(t)try{let s=await(await fetch(`/api/focus/${encodeURIComponent(e)}`,{method:"POST",headers:{"x-lobstah-focus-token":t}})).json();S({focusResults:{..._().focusResults,[e]:s.message??s.reason??"Window focus failed."}})}catch{S({focusResults:{..._().focusResults,[e]:"Window focus failed."}})}}async function Cn(e,t){let n=_().snapshot?.focusToken;if(!n)return"The glass has no page token yet.";try{let r=await(await fetch("/requests",{method:"POST",headers:{"content-type":"application/json","x-lobstah-token":n},body:JSON.stringify({kind:"trap-request",payload:{repo:e,harness:t}})})).json();if(!r.ok)return r.reason??"The request was refused."}catch{return"The request could not be sent."}try{at(await(await fetch("/data")).json())}catch{}}function L(e){let t={..._().prefs,...e};mn(t),S({prefs:t})}function Dn(e){e!=="table"&&e!=="cards"||L({view:e})}var An=e=>L({lobs:e==="on"});function Rn(e,t){let n={..._().lobHidden,[e]:t};gn(n),setTimeout(()=>S({lobHidden:n}),0)}async function In(e){try{return await navigator.clipboard.writeText(e),!0}catch{return!1}}var Pn=function(e,t,n,s){var r;t[0]=0;for(var o=1;o<t.length;o++){var i=t[o++],c=t[o]?(t[0]|=i?1:2,n[t[o++]]):t[++o];i===3?s[0]=c:i===4?s[1]=Object.assign(s[1]||{},c):i===5?(s[1]=s[1]||{})[t[++o]]=c:i===6?s[1][t[++o]]+=c+"":i?(r=e.apply(c,Pn(e,c,n,["",null])),s.push(r),c[0]?t[0]|=2:(t[o-2]=0,t[o]=r)):s.push(c)}return s},Mn=new Map;function En(e){var t=Mn.get(this);return t||(t=new Map,Mn.set(this,t)),(t=Pn(this,t.get(e)||(t.set(e,t=(function(n){for(var s,r,o=1,i="",c="",u=[0],l=function(d){o===1&&(d||(i=i.replace(/^\\s*\\n\\s*|\\s*\\n\\s*$/g,"")))?u.push(0,d,i):o===3&&(d||i)?(u.push(3,d,i),o=2):o===2&&i==="..."&&d?u.push(4,d,0):o===2&&i&&!d?u.push(5,0,!0,i):o>=5&&((i||!d&&o===5)&&(u.push(o,0,i,r),o=6),d&&(u.push(o,d,0,r),o=6)),i=""},f=0;f<n.length;f++){f&&(o===1&&l(),l(f));for(var h=0;h<n[f].length;h++)s=n[f][h],o===1?s==="<"?(l(),u=[u],o=3):i+=s:o===4?i==="--"&&s===">"?(o=1,i=""):i=s+i[0]:c?s===c?c="":i+=s:s===\'"\'||s==="\'"?c=s:s===">"?(l(),o=1):o&&(s==="="?(o=5,r=i,i=""):s==="/"&&(o<5||n[f][h+1]===">")?(l(),o===3&&(u=u[0]),o=u,(u=u[0]).push(2,0,o),o=0):s===" "||s===" "||s===`\n`||s==="\\r"?(l(),o=2):i+=s),o===3&&i==="!--"&&(o=4,u=u[0])}return l(),u})(e)),t),arguments,[])).length>1?t:t[0]}var Ln=e=>Array.isArray(e)?e.map(Ln):e===""?null:e,zs=(e,t,...n)=>ae(e,t,...n.map(Ln)),a=En.bind(zs);var Pe,k,ct,Nn,dt=0,Wn=[],y=b,Hn=y.__b,On=y.__r,Bn=y.diffed,jn=y.__c,Un=y.unmount,Fn=y.__;function Kn(e,t){y.__h&&y.__h(k,e,dt||t),dt=0;var n=k.__H||(k.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function Y(e){return dt=1,Xs(zn,e)}function Xs(e,t,n){var s=Kn(Pe++,2);if(s.t=e,!s.__c&&(s.__=[n?n(t):zn(void 0,t),function(c){var u=s.__N?s.__N[0]:s.__[0],l=s.t(u,c);u!==l&&(s.__N=[l,s.__[1]],s.__c.setState({}))}],s.__c=k,!k.__f)){var r=function(c,u,l){if(!s.__c.__H)return!0;var f=!1,h=s.__c.props!==c;if(s.__c.__H.__.some(function(m){if(m.__N){f=!0;var p=m.__[0];m.__=m.__N,m.__N=void 0,p!==m.__[0]&&(h=!0)}}),o){var d=o.call(this,c,u,l);return f?d||h:d}return!f||h};k.__f=!0;var o=k.shouldComponentUpdate,i=k.componentWillUpdate;k.componentWillUpdate=function(c,u,l){if(this.__e){var f=o;o=void 0,r(c,u,l),o=f}i&&i.call(this,c,u,l)},k.shouldComponentUpdate=r}return s.__N||s.__}function Vn(e,t){var n=Kn(Pe++,7);return Zs(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function Js(){for(var e;e=Wn.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(Me),t.__h.some(pt),t.__h=[]}catch(n){t.__h=[],y.__e(n,e.__v)}}}y.__b=function(e){k=null,Hn&&Hn(e)},y.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),Fn&&Fn(e,t)},y.__r=function(e){On&&On(e),Pe=0;var t=(k=e.__c).__H;t&&(ct===k?(t.__h=[],k.__h=[],t.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.some(Me),t.__h.some(pt),t.__h=[],Pe=0)),ct=k},y.diffed=function(e){Bn&&Bn(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Wn.push(t)!==1&&Nn===y.requestAnimationFrame||((Nn=y.requestAnimationFrame)||Qs)(Js)),t.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),ct=k=null},y.__c=function(e,t){t.some(function(n){try{n.__h.some(Me),n.__h=n.__h.filter(function(s){return!s.__||pt(s)})}catch(s){t.some(function(r){r.__h&&(r.__h=[])}),t=[],y.__e(s,n.__v)}}),jn&&jn(e,t)},y.unmount=function(e){Un&&Un(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(s){try{Me(s)}catch(r){t=r}}),n.__H=void 0,t&&y.__e(t,n.__v))};var qn=typeof requestAnimationFrame=="function";function Qs(e){var t,n=function(){clearTimeout(s),qn&&cancelAnimationFrame(t),setTimeout(e)},s=setTimeout(n,35);qn&&(t=requestAnimationFrame(n))}function Me(e){var t=k,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),k=t}function pt(e){var t=k;e.__c=e.__(),k=t}function Zs(e,t){return!e||e.length!==t.length||t.some(function(n,s){return n!==e[s]})}function zn(e,t){return typeof t=="function"?t(e):t}var K=e=>{if(!e)return"";let t=Math.max(0,(Date.now()-Date.parse(e))/1e3);return t<90?Math.round(t)+"s":t<5400?Math.round(t/60)+"m":t<172800?(t/3600).toFixed(1)+"h":Math.round(t/86400)+"d"},v=e=>a`<span data-age=${e??""}>${K(e)}</span>`,Le=e=>e.activity&&a`<div class=${"activity"+(e.activity.stale?" stale":"")} title=${e.activity.stale?"no activity past the wedge threshold":e.activity.kind}>${e.activity.stale?"stale \\xB7 ":""}${e.activity.summary} \xB7 ${v(e.activity.at)} ago</div>`,Ys=e=>e&&/^https?:\\/\\//i.test(e)?e:void 0,Ne=e=>{let t=e.waiting;if(!t)return;let n=Ys(t.link),s=n;try{n&&(s=new URL(n).host+new URL(n).pathname.replace(/\\/$/,""))}catch{s=n}return a`<div class="waiting">${e.verb}: waiting on ${t.on} \xB7 ${v(t.since)}${n&&[" \\xB7 ",a`<a href=${n} target="_blank" rel="noopener noreferrer" onClick=${D}>${s}</a>`]}</div>`},er=12,Xn=e=>e!==void 0&&e.length>er,N=e=>Xn(e)?e:void 0,H=e=>Xn(e)?" long":"",w=(e,t)=>()=>C(e,t),D=e=>e.stopPropagation(),tr=e=>e.sessionId?(e.harness==="codex"?"codex resume ":"claude --resume ")+e.sessionId:void 0;function V(e){if(e.requested)return a`<span class="dim">Requested \u2014 no window yet</span>`;if(e.starting)return a`<span class="dim">${e.starting.failedAt?"Did not start":"Starting \\u2014 no window yet"}</span>`;if(!e.live){let s=tr(e);return s?a`<span class="dim">Resume: <code onClick=${D}>${s}</code></span>`:a`<span class="dim">Resume command unavailable</span>`}let t=_();return!t.snapshot?.focusSupported&&!e.link?a`<span class="dim">Window focus is not supported here</span>`:a`<span class="winaction"><button class="btn open" title="open this trap\'s window" onClick=${s=>{D(s),Gn(e.trapId)}}>\u2197 open</button>${e.link&&[" ",a`<a href=${e.link} onClick=${D}>Session link</a>`]}${t.focusResults[e.trapId]&&[" ",a`<span class="dim">${t.focusResults[e.trapId]}</span>`]}</span>`}function R(e,t,n){return t.length?a`<div class="wrap"><table><tbody><tr>${e.map(s=>a`<th>${s}</th>`)}</tr>${t}</tbody></table></div>`:a`<div class="empty">${n}</div>`}function nr({text:e}){let[t,n]=Y(null),s=r=>async()=>{await In(e)&&(n(r),setTimeout(()=>n(null),1e3))};return a`<div class="cmd"><code class=${t==="code"?"copied":void 0} title="click to copy" onClick=${s("code")}>${e}</code><button title="copy" onClick=${s("button")}>${t==="button"?"\\u2713":"\\u29C9"}</button></div>`}var G=(e,t)=>a`<${nr} key=${t} text=${e} />`,fe=(e,t,n="thumb")=>a`<button\n type="button"\n class=${n}\n title=${"view "+t}\n onClick=${s=>{D(s),Sn(e,t)}}\n >\n <img src=${e} alt=${t} loading="lazy" />\n </button>`,ee=(e,t)=>e.map(n=>[a`<div class="sub">${n.name} \xB7 ${n.type} \xB7 ${n.bytes} bytes</div>`,t&&on(n.name)&&fe(t(n.name),n.name),G(n.path)]),Jn=/\\bwt:([a-z0-9][a-z0-9-]*)/g,ut=e=>_().snapshot?.trapNames?.[e],O=e=>e.replace(Jn,(t,n,s)=>{let r=ut(n);return r&&!Qn(e,s,t.length,r)?r:t}),Qn=(e,t,n,s)=>e.slice(Math.max(0,t-s.length-2),t)===`${s} (`&&e[t+n]===")";function He(e){let t="wt:"+e,n=ut(e)??t;return _().snapshot?.traps.some(r=>r.trapId===e)?a`<a class="trapname" href="#traps" title=${t} onClick=${r=>{r.preventDefault(),D(r),C("trap",e)}}>${n}</a>`:a`<span class="trapname" title=${t}>${n}</span>`}var Ee=e=>{let t=/^wt:([a-z0-9][a-z0-9-]*)$/.exec(e);return t?He(t[1]):e};function B(e,t=1/0){let n=[],s=0;for(let c of e.matchAll(Jn)){c.index>s&&n.push({text:e.slice(s,c.index)});let u=ut(c[1]);n.push(u&&Qn(e,c.index,c[0].length,u)?{text:c[0]}:{text:u??c[0],trapId:c[1]}),s=c.index+c[0].length}s<e.length&&n.push({text:e.slice(s)});let r=n.reduce((c,u)=>c+u.text.length,0),o=r>t?t-1:1/0,i=[];for(let c of n){if(o<=0)break;c.text.length<=o?i.push(c.trapId?He(c.trapId):c.text):i.push(c.text.slice(0,o)),o-=c.text.length}return r>t&&i.push("\\u2026"),i}var ft=e=>e.log.flatMap((t,n)=>[n?`\n`:"",t.at+" "+t.verb,...t.note?[" ",...B(t.note)]:[]]);function Zn(e){let t=[e.elapsed&&`elapsed: ${e.elapsed}`,e.attempt&&`attempt: ${e.attempt}`,e.branch&&`branch: ${e.branch}`,e.lastCommit&&`last commit: ${e.lastCommit}`,e.aheadTrunk&&`commits: ${e.aheadTrunk}`,e.draftPr&&`draft PR: ${e.draftPr}`,e.updated&&`updated: ${e.updated}`].filter(Boolean).join(`\n`);return a`${e.waiting&&[a`<div class="sec">waiting</div>`,Ne(e)]}${e.activity&&[a`<div class="sec">activity</div>`,Le(e)]}${t&&[a`<div class="sec">progress</div>`,a`<pre>${t}</pre>`]}<div class="sec">brief</div><pre>${e.brief}</pre>${e.attachments.length>0&&[a`<div class="sec">attachments (${e.attachments.length})</div>`,ee(e.attachments,n=>st(e.lane,e.id,n))]}${e.messageAttachments.length>0&&[a`<div class="sec">message attachments (${e.messageAttachments.length})</div>`,ee(e.messageAttachments,n=>st(e.lane,e.id,n))]}${e.followUp&&[a`<div class="sec">forks</div>`,a`<pre>${e.followUp}</pre>`]}<div class="sec">log</div><div class="loglines">${e.log.length?ft(e):"no entries yet"}</div>${e.inbox.length>0&&[a`<div class="sec">inbox</div>`,a`<div class="loglines">${e.inbox.join(`\n---\n`)}</div>`]}${e.awaitingReply&&[a`<div class="sec">awaiting reply</div>`,a`<div>${e.awaitingReply.line} \xB7 from ${e.awaitingReply.from} \xB7 ${v(e.awaitingReply.sentAt)} ago</div>`]}${e.evidence&&[a`<div class="sec">evidence</div>`,a`<div class="loglines">${JSON.stringify(e.evidence)}</div>`]}`}function me(e){return e.for?[Ee(e.for),e.evidence&&e.evidence.deliveredTo?[" ",a`<span class="ok">\u2713delivered</span>`]:[" ",a`<span class="warn">waiting</span>`]]:e.claimedBy?Ee(e.claimedBy):""}function te(e){let t=e.evidence&&(e.evidence.prUrl||e.evidence.pr&&e.evidence.pr.url);if(!t)return"";let n=e.prBadge;return[a`<a href=${t} target="_blank" rel="noopener" onClick=${D}>PR</a>`,n&&[" ",a`<span class=${"badge "+E(n)} title=${"observed "+n.observedAt}>${n.text}</span>`],e.prGate&&[" ",a`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]]}var sr={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch"},mt={"pr:review":"bad","pr:checks":"bad","pr:conflict":"pr-conflicts","pr:ready":"ok","pr:draft":"dim",watch:"warn"},Yn=e=>sr[e]||"";var Oe=e=>a`<a href=${e.url} target="_blank" rel="noopener" onClick=${D}>#${e.number}</a>`,Be=e=>a`<span class="prname" title=${e.title||void 0}><b>#${e.number}</b>${e.title&&[" ",e.title]}</span>`;function ne(e,t,n){return e.flatMap((s,r)=>{let o=t.get(s)||void 0,i=s===n?a`<b title=${o}>#${s}</b>`:a`<span title=${o}>#${s}</span>`;return r?[" \\u2192 ",i]:[i]})}function he(e){let t=e.checks;return t.passed+"/"+t.total+" passed"+(t.failed?" \\xB7 "+t.failed+" failed":"")+(t.pending?" \\xB7 "+t.pending+" pending":"")}function je(e){let t=e.review||{};return(e.reviewDecision||"")+(t.unresolvedThreads?" \\xB7 "+t.unresolvedThreads+" unresolved":"")+(t.changesRequested?" \\xB7 changes requested":"")}function ge(e){return[e.mergeStateStatus,e.nextMergeable?[" \\xB7 ",a`<span class="ok">next mergeable</span>`]:e.blockedBy?" \\xB7 blocked by #"+e.blockedBy:""]}function ht(e){let t=un(e);return e?[t.text," \\xB7 ",t.at?[v(t.at)," ago"]:"never checked"]:a`<span class="dim">${t.text}</span>`}function ve(e){if(e.requested)return{stale:!1,listen:[a`<span class="dot"></span>`,a`<span class="dim">requested</span>`],hb:a`<span class="dim">\u2014</span>`};if(e.starting)return{stale:!1,listen:e.starting.failedAt?[a`<span class="dot bad"></span>`,a`<span class="bad">start failed</span>`]:[a`<span class="dot warn"></span>`,"starting"],hb:a`<span class="dim">\u2014</span>`};if(!e.live)return{stale:!1,listen:[a`<span class="dot"></span>`,a`<span class="dim">signed off</span>`],hb:a`<span class="dim">\u2014</span>`};let t=Date.now()-Date.parse(e.heartbeatAt)>18e5,n=e.listening??(!!e.firstParkedAt&&!t);return{stale:t,listen:n?[a`<span class="dot ok"></span>`,"listening"]:[a`<span class="dot warn"></span>`,"not listening"],hb:a`<span class=${t?"bad":"ok"}>${t&&"stale "}${v(e.heartbeatAt)} ago</span>`}}function gt(e){if(e.requested)return{kind:"requested",helmOn:!!_().snapshot?.helmOn};if(e.starting)return e.starting.failedAt?{kind:"start failed",reason:e.starting.reason??"no session signed on in time"}:{kind:"starting",deadline:e.starting.deadline};if(!e.live)return{kind:"signed off"};let t=e.claimed?e.catches.find(n=>n.id===e.claimed&&n.bucket==="active"):void 0;return t?t.waiting||t.verb==="paused"?{kind:"parked",current:t}:{kind:"working",current:t}:{kind:"idle",listening:e.listening??(!!e.firstParkedAt&&Date.now()-Date.parse(e.heartbeatAt??"")<=18e5)}}function rr(e){let t=gt(e);return t.kind==="working"||t.kind==="idle"&&t.listening?"ok":t.kind==="start failed"?"bad":t.kind==="parked"||t.kind==="starting"?"warn":"dim"}var es=e=>e.waiting?`waiting on ${e.waiting.on}`:e.note||"waiting",ts=e=>e.brief.split(/\\r?\\n/,1)[0]?.trim().slice(0,40)||"(no title)";function _e(e){let t=gt(e),n=a`<span class=${"dot trapdot "+rr(e)}></span>`;if(t.kind==="requested")return[n,a`<span class="dim">${ns(e,t.helmOn)}</span>`];if(t.kind==="starting")return[n,"starting \\xB7 waiting for its session to sign on"];if(t.kind==="start failed")return[n,a`<span class="bad">start failed</span>`," \\xB7 ",t.reason];if(t.kind==="signed off")return[n,a`<span class="dim">signed off</span>`];if(t.kind==="idle")return[n,"idle \\xB7 ",t.listening?"listening":"not listening"];let s=t.current;return t.kind==="parked"?[n,"parked \\xB7 ",es(s)]:[n,"working \\xB7 ",a`<a href="#dispatches" onClick=${o=>{o.preventDefault(),D(o),C("dispatch",`${s.lane}:${s.id}`)}}>${s.id.slice(0,8)}</a>`," \\xB7 ",ts(s),s.activity&&[" \\xB7 ",s.activity.summary," ",v(s.activity.at)," ago"]]}var ns=(e,t)=>`requested \\xB7 ${e.repo??""} \\xB7 ${e.harness??""} \\xB7 ${t?"waiting for the helm":"waiting for a helm"}`;function z(e){let t=e.starting?.commands;return t?.length?a`<div class="startcmds" onClick=${D}><div class="dim">start it: run one in a terminal</div>${t.map(n=>G(n.command,n.harness))}</div>`:null}function Ue(){let t=_().snapshot?.repoKeys??[],[n,s]=Y(!1),[r,o]=Y(""),[i,c]=Y("claude"),[u,l]=Y(null),f=r||t[0]||"",h=async d=>{d.preventDefault();let m=await Cn(f,i);l(m??null),m||s(!1)};return n?a`<form class="newtrap" onClick=${D} onSubmit=${h}>\n <label>repo <select name="repo" value=${f} onChange=${d=>o(d.target.value)}>${t.map(d=>a`<option value=${d}>${d}</option>`)}</select></label>\n <label>harness <select name="harness" value=${i} onChange=${d=>c(d.target.value)}><option value="claude">claude</option><option value="codex">codex</option></select></label>\n <button class="btn" type="submit" disabled=${!f}>Request</button>\n <button class="btn" type="button" onClick=${()=>s(!1)}>Cancel</button>\n ${u&&a`<span class="bad">${u}</span>`}\n </form>`:a`<span class="newtrap"><button class="btn" onClick=${d=>(D(d),s(!0),l(null))}>+ New trap</button></span>`}function Fe(e){let t=gt(e);if(t.kind==="requested")return ns(e,t.helmOn);if(t.kind==="starting")return`starting \\xB7 sign-on due by ${t.deadline}`;if(t.kind==="start failed")return`start failed \\xB7 ${t.reason}`;if(t.kind==="signed off")return"signed off";if(t.kind==="idle")return`idle \\xB7 ${t.listening?"listening":"not listening"}`;if(t.kind==="parked")return`parked \\xB7 ${es(t.current)}`;let n=t.current;return[`working \\xB7 ${n.id.slice(0,8)} \\xB7 ${ts(n)}`,n.activity&&`${n.activity.summary} ${K(n.activity.at)} ago`].filter(Boolean).join(" \\xB7 ")}function vt(e){let t=e.messages.filter(n=>n.state==="pending").length;return e.messages.length?["\\u2709 "+e.messages.length,t>0&&[" ",a`<span class="warn">(${t} pending)</span>`]]:null}var qe=e=>()=>{let t=ce(e.key);C(t.type,t.key)};function _t(e){let t=de(e);return{nodes:[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked?" \\xB7 acked":""],text:[t,`${K(e.filedAt)} ago`,e.acked?"acked":""].filter(Boolean).join(" \\xB7 ")}}function or(e){let t=_t(e);return a`<div key=${e.key} class=${"card"+(e.acked?" acked":"")} onClick=${qe(e)}><div class="top"><b title=${e.title}>${e.title}</b></div><div class="meta" title=${t.text}>${t.nodes}</div></div>`}function ir(e){return a`<tr key=${e.key} class=${"rowhead"+(e.acked?" acked":"")} onClick=${qe(e)}><td class="grow">${e.title}</td><td>${de(e)}</td><td>${v(e.filedAt)}</td><td>${e.acked?"acked":""}</td></tr>`}function ss({inp:e}){return e.view==="cards"?e.list.length?a`<div class="cards">${e.list.map(or)}</div>`:a`<div class="empty">no reports match</div>`:R(["title","from","filed","acked"],e.list.map(ir),"no reports match")}function is(e){let t=e.trim();return/^(https?:\\/\\/|mailto:|#)/i.test(t)?t:void 0}function as(e){let t=e.trim();return/^[^/\\\\:?#]+$/.test(t)&&t!=="."&&t!==".."?t:void 0}function rs(e,t,n,s){let r=0;for(let o=t;o<e.length;o++){if(e[o]==="\\\\"){o++;continue}if(e[o]===n)r++;else if(e[o]===s){if(r===0)return o;r--}}return-1}function os(e,t){let n=rs(e,t+1,"[","]");if(n<0||e[n+1]!=="(")return;let s=rs(e,n+2,"(",")");if(s<0)return;let r=e.slice(n+2,s).trim().replace(/\\s+"[^"]*"$/,"").replace(/^<(.*)>$/,"$1");return{text:e.slice(t+1,n),target:r,end:s+1}}function U(e){let t=[],n="",s=()=>{n&&t.push({t:"text",v:n}),n=""};for(let r=0;r<e.length;){let o=e[r];if(o==="\\\\"&&r+1<e.length&&/[\\\\`*_{}[\\]()#+\\-.!|<>~]/.test(e[r+1])){n+=e[r+1],r+=2;continue}if(o==="`"){let i=/^`+/.exec(e.slice(r))[0],c=e.indexOf(i,r+i.length);if(c>0){s(),t.push({t:"code",v:e.slice(r+i.length,c).replace(/^ (.*) $/,"$1")}),r=c+i.length;continue}}if(o==="!"&&e[r+1]==="["){let i=os(e,r+1);if(i){s(),t.push({t:"img",alt:i.text,src:i.target}),r=i.end;continue}}if(o==="["){let i=os(e,r);if(i){s(),t.push({t:"a",href:i.target,c:U(i.text)}),r=i.end;continue}}if((o==="*"||o==="_")&&e[r+1]===o){let i=e.indexOf(o+o,r+2);if(i>r+2){s(),t.push({t:"b",c:U(e.slice(r+2,i))}),r=i+2;continue}}if(o==="*"||o==="_"&&(r===0||!/\\w/.test(e[r-1]))){let i=r+1;for(;(i=e.indexOf(o,i))>0&&(e[i+1]===o||o==="_"&&/\\w/.test(e[i+1]??""));)i+=2;if(i>r+1&&e[r+1]!==" "){s(),t.push({t:"i",c:U(e.slice(r+1,i))}),r=i+1;continue}}if(o===`\n`){/ {2,}$/.test(n)||n.endsWith("\\\\")?(n=n.replace(/( {2,}|\\\\)$/,""),s(),t.push({t:"br"})):n+=" ",r++;continue}n+=o,r++}return s(),t}var ls=/^ {0,3}(`{3,}|~{3,})\\s*([^`\\s]*)/,cs=/^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/,ds=/^ {0,3}([-*_])(\\s*\\1){2,}\\s*$/,kt=/^( {0,3})([-*+])\\s+(.*)$/,yt=/^( {0,3})(\\d{1,9})[.)]\\s+(.*)$/,We=/^ {0,3}>\\s?(.*)$/,ar=/^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;function $t(e){let t=e.trim();t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&!t.endsWith("\\\\|")&&(t=t.slice(0,-1));let n=[],s="";for(let r=0;r<t.length;r++)t[r]==="\\\\"&&t[r+1]==="|"?(s+="|",r++):t[r]==="|"?(n.push(s.trim()),s=""):s+=t[r];return n.push(s.trim()),n}var bt=e=>ls.test(e)||cs.test(e)||ds.test(e)||kt.test(e)||yt.test(e)||We.test(e);function $e(e){let t=e.replace(/\\r\\n?/g,`\n`).replace(/\\t/g," ").split(`\n`),n=[],s=0;for(;s<t.length;){let r=t[s];if(!r.trim()){s++;continue}let o=ls.exec(r);if(o){let f=o[1],h=[];for(s++;s<t.length&&!new RegExp(`^ {0,3}${f[0]}{${f.length},}\\\\s*$`).test(t[s]);)h.push(t[s++]);s++,n.push({t:"code",lang:o[2]??"",v:h.join(`\n`)});continue}let i=cs.exec(r);if(i){n.push({t:"h",level:i[1].length,c:U(i[2])}),s++;continue}if(ds.test(r)){n.push({t:"hr"}),s++;continue}if(We.test(r)){let f=[];for(;s<t.length&&t[s].trim()&&(We.test(t[s])||!bt(t[s]));)f.push(We.exec(t[s])?.[1]??t[s]);n.push({t:"quote",c:$e(f.join(`\n`))}),s+=f.length;continue}let c=kt.exec(r),u=yt.exec(r);if(c||u){let f=!c,h=f?yt:kt,d=[];for(;s<t.length;){let m=t[s],p=h.exec(m);if(p&&p[1].length<=3){d.push([p[3]]),s++;continue}if(!m.trim()){if(s+1<t.length&&/^ {2,}\\S/.test(t[s+1])){d.at(-1).push(""),s++;continue}break}if(/^ {2,}\\S/.test(m)){d.at(-1).push(m.replace(/^ {2,4}/,"")),s++;continue}if(bt(m))break;d.at(-1).push(m.trim()),s++}n.push({t:"list",ordered:f,start:f?Number(u[2]):1,items:d.map(m=>$e(m.join(`\n`)))});continue}if(r.includes("|")&&s+1<t.length&&ar.test(t[s+1])&&t[s+1].includes("-")){let f=$t(r),h=$t(t[s+1]).map(m=>m.startsWith(":")&&m.endsWith(":")?"center":m.endsWith(":")?"right":m.startsWith(":")?"left":"");s+=2;let d=[];for(;s<t.length&&t[s].trim()&&t[s].includes("|");){let m=$t(t[s++]);d.push(f.map((p,g)=>U(m[g]??"")))}n.push({t:"table",align:f.map((m,p)=>h[p]??""),head:f.map(U),rows:d});continue}let l=[];for(;s<t.length&&t[s].trim()&&!bt(t[s])&&!(l.length&&/^ {0,3}(=+|-+)\\s*$/.test(t[s]));)l.push(t[s++].replace(/^ +/,""));if(l.length===0){n.push({t:"p",c:U(r.trim())}),s++;continue}n.push({t:"p",c:U(l.join(`\n`))})}return n}function F(e,t){return t.map(n=>{switch(n.t){case"text":return n.v;case"code":return a`<code>${n.v}</code>`;case"b":return a`<strong>${F(e,n.c)}</strong>`;case"i":return a`<em>${F(e,n.c)}</em>`;case"br":return a`<br />`;case"a":{let s=is(n.href);return s?a`<a href=${s} target="_blank" rel="noopener noreferrer">${F(e,n.c)}</a>`:F(e,n.c)}case"img":{let s=as(n.src);return s?fe(e(s),n.alt||s,"mdimg"):a`<span class="dim">[image not shown: ${n.alt||n.src}]</span>`}}})}function Ke(e,t){return t.map(n=>{switch(n.t){case"h":{let s=F(e,n.c);return n.level===1?a`<h1>${s}</h1>`:n.level===2?a`<h2>${s}</h2>`:n.level===3?a`<h3>${s}</h3>`:a`<h4>${s}</h4>`}case"p":return a`<p>${F(e,n.c)}</p>`;case"code":return a`<pre class="mdcode"><code>${n.v}</code></pre>`;case"hr":return a`<hr />`;case"quote":return a`<blockquote>${Ke(e,n.c)}</blockquote>`;case"list":{let s=n.items.map(r=>a`<li>${Ke(e,r)}</li>`);return n.ordered?a`<ol start=${n.start}>${s}</ol>`:a`<ul>${s}</ul>`}case"table":return a`<div class="mdtable"><table><thead><tr>${n.head.map((s,r)=>a`<th style=${n.align[r]?"text-align:"+n.align[r]:void 0}>${F(e,s)}</th>`)}</tr></thead><tbody>${n.rows.map(s=>a`<tr>${s.map((r,o)=>a`<td style=${n.align[o]?"text-align:"+n.align[o]:void 0}>${F(e,r)}</td>`)}</tr>`)}</tbody></table></div>`}})}function lr({r:e,text:t}){let n=t?.text!==void 0?Ke(s=>it(e.key,s),$e(t.text)):t?.error?a`<div class="bad">${t.error}</div>`:a`<div class="dim">loading\u2026</div>`;return a`<div class="mdpage" data-report=${e.key}>${n}</div>`}function ps({text:e,fileUrl:t}){return a`<div class="mdpage">${Ke(t,$e(e))}</div>`}function cr(e){let t=de(e);return[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked&&[" \\xB7 ",a`<span class="ok">acked</span>`]]}function wt({r:e,text:t,heading:n}){return[n&&a`<div class="sec">report \xB7 ${e.title}</div>`,a`<div class="sub">${cr(e)}</div>`,a`<${lr} r=${e} text=${t} />`,e.attachments.length>0&&[a`<div class="sec">report attachments (${e.attachments.length})</div>`,ee(e.attachments,s=>it(e.key,s))],!e.acked&&[a`<div class="sec">ack</div>`,G("lobstah attention ack "+e.key)]]}var dr=/\\.(png|jpe?g|gif|webp)$/i,pr=e=>{e.style.height="auto",e.style.height=e.scrollHeight+"px"};function ur(e,t){return t.length?a`<div class="dfiles">${t.map(n=>dr.test(n.name)?a`<span key=${n.name}>${fe(rt(e,n.name),n.name,"dimg")}</span>`:a`<div key=${n.name} class="dfile"><span>${n.name}</span> <span class="dim">\xB7 ${n.type} \xB7 ${n.bytes} bytes \xB7 </span><code>${n.path}</code></div>`)}</div>`:null}function fr(e,t,n){let s=e.key,r=e.kind==="decision"?e.options:[],o=t?.text??"",i=t?.files??[],c=!!t?.sending;return[r.length>0&&a`<div class="doptions">${r.map(u=>a`<button key=${u} type="button" class=${"btn dopt"+(t?.option===u?" on":"")} aria-pressed=${t?.option===u?"true":"false"} disabled=${c} onClick=${()=>kn(s,u)}>${u}</button>`)}</div>`,a`<textarea\n class="danswer"\n rows="2"\n placeholder=${r.length?"Add to your answer, or answer in your own words":"Your answer"}\n value=${o}\n disabled=${c}\n onInput=${u=>{let l=u.currentTarget;pr(l),A(s,{text:l.value,error:void 0})}}\n onPaste=${u=>{yn(s,u)}}\n ></textarea>`,a`<div class="dfoot">\n <label class="btn dattach" title="attach images or files">attach<input type="file" multiple accept=${n} disabled=${c} onChange=${u=>{let l=u.currentTarget;lt(s,l.files).then(()=>{l.value=""})}} /></label>\n ${i.map((u,l)=>a`<span key=${u.name+l} class="dchip">${u.name}<button type="button" class="dx" title="remove" disabled=${c} onClick=${()=>wn(s,l)}>\xD7</button></span>`)}\n ${t?.error&&a`<span class="bad derr">${t.error}</span>`}\n <button type="button" class="btn dsend" disabled=${c} onClick=${()=>{Tn(s)}}>${c?"Sending\\u2026":"Send"}</button>\n </div>`]}function mr(e,t,n,s){let r=e.dispatch,o=e.lane??"work",c=[r&&a`<a class="dlink" href="#" onClick=${l=>{l.preventDefault(),w("dispatch",o+":"+r)()}}>${r.slice(0,8)}</a>`,e.repo,[v(e.at)," ago"]].filter(Boolean).flatMap((l,f)=>f?[" \\xB7 ",l]:[l]),u="dcard"+(e.kind==="question"?" plain":"")+(t?.sent?" answered":"")+(n?" focus":"");return a`<div key=${e.key} class=${u} data-decision=${e.key}>\n <div class="dtop">\n ${e.kind==="question"&&a`<span class=${"badge "+(e.verb==="blocked"?"bad":"warn")}>${e.verb}</span>`}\n <b class="dtitle">${e.kind==="decision"?e.title:B(e.note)}</b>\n <span class="dmeta dim">${c}</span>\n </div>\n ${e.kind==="decision"&&e.detail.trim()&&a`<${ps} text=${e.detail} fileUrl=${l=>rt(e.key,l)} />`}\n ${e.kind==="decision"&&ur(e.key,e.attachments)}\n ${t?.sent?a`<div class="danswered ok">answered \xB7 ${t.sent}</div>`:fr(e,t,s)}\n </div>`}function us({cards:e,drafts:t,focus:n,extensions:s}){let r=s.join(","),o=e.length?a`<div class="dcards">${e.map(i=>mr(i,t[i.key],i.key===n,r))}</div>`:a`<div class="empty">none</div>`;return a`<section class="decisions"><h2>decisions</h2>${o}</section>`}function _r(e,t){let n=e.badge&&a`<span class=${"badge "+(e.badge.tone||"dim")+H(e.badge.text)} title=${N(e.badge.text)}>${e.badge.text}</span>`;return t==="cards"?a`<div key=${e.key} class=${"card"+(e.acked?" acked":"")} onClick=${e.open} style=${e.open?void 0:"cursor:default"}><div class="top"><b>${e.title}</b>${n}</div>${e.meta&&a`<div class="meta" title=${e.metaText}>${e.meta}</div>`}${e.extra}${e.action&&a`<div class="foot"><span class="footact">${e.action}</span></div>`}</div>`:a`<div key=${e.key} class=${"deckline"+(e.open?" click":"")+(e.acked?" acked":"")} onClick=${e.open}>${n&&[n," "]}<b>${e.title}</b>${e.meta&&[" ",a`<span class="dim">\xB7 ${e.meta}</span>`]}${e.action&&[" ",a`<span class="dim">\xB7 </span>`,e.action]}${e.extra}</div>`}var fs=(e,t)=>e>0&&a`<a class="deckmore" href=${"#"+t}>+${e} more \u2192</a>`;function Ve(e,t,n,s,r,o){let i=t.slice(0,s),c=i.map(l=>_r(l,r)),u=i.length?r==="cards"?a`<div class="cards">${c}</div>`:c:a`<div class="empty">none</div>`;return a`<section><h2><a href=${"#"+n}>${e} \u2192</a></h2>${o&&a`<div class="tabhead">${o}</div>`}${u}${fs(t.length-i.length,n)}</section>`}function $r(e,t,n,s){let r=t.find(l=>l.number===e.nextNumber)||t[0],o=ne(e.numbers,new Map(t.map(l=>[l.number,l.title]))),i=r?"next #"+r.number:"nothing mergeable";if(s==="cards"){let l=f=>{let h=n.get(f.key)||[],d=h.length>0&&h.every(g=>g.acked),m=h.length?h.map(g=>a`<span class=${"badge "+(mt[g.kind]||"dim")}>${Yn(g.kind)}</span>`):a`<span class=${"badge "+E(f.badge)+H(f.badge.text)} title=${N(f.badge.text)}>${f.badge.text}</span>`,p=`${f.repo} \\xB7 ${f.badge.text}${d?" \\xB7 acked":""}`;return a`<div key=${f.key} class=${"card"+(d?" acked":"")} onClick=${w("pr",f.key)}><div class="top">${Be(f)}${m}</div><div class="meta" title=${p}>${p}</div></div>`};return a`<div key=${e.id} class="deckstack"><div class="dim">${o} \xB7 ${i}</div><div class="cards">${t.map(l)}</div></div>`}let c=t.flatMap(l=>(n.get(l.key)||[]).map(f=>a`<span class=${"badge "+(mt[f.kind]||E(l.badge))+(f.acked?" acked":"")}>#${l.number} ${l.badge.text}</span>`)),u=c.flatMap((l,f)=>f?[" ",l]:[l]);return a`<div key=${e.id} class=${"deckline"+(r?" click":"")} onClick=${r&&w("pr",r.key)}><b>${o}</b> <span class="dim">\xB7 ${i}</span>${c.length>0&&[" \\xB7 ",u]}</div>`}function br(e,t){let n=e.stacks.slice(0,3),s=new Map;for(let o of e.prAttention){let i=s.get(o.key)||[];i.push(o),s.set(o.key,i)}let r=n.length?n.map(o=>$r(o,e.prs.filter(i=>i.stackId===o.id).sort((i,c)=>i.position-c.position),s,t)):a`<div class="empty">none</div>`;return a`<section><h2><a href="#prs">PRs \u2192</a></h2>${r}${fs(e.stacks.length-n.length,"prs")}</section>`}function ms({inp:e,drafts:t,focus:n,extensions:s}){let r=e.view,o=e.inflight.map(l=>({key:l.lane+":"+l.id,title:[l.id.slice(0,8)," ",l.repo||""],badge:{text:l.verb,tone:l.verb==="needs-decision"||l.verb==="blocked"?"bad":"dim"},meta:[B(l.note||"",90),l.verbAt&&[" \\xB7 ",v(l.verbAt)," ago"],(l.for||l.claimedBy)&&[" \\xB7 ",Ee(l.for||l.claimedBy)]],metaText:[O(l.note||""),l.verbAt&&`${K(l.verbAt)} ago`,O(l.for||l.claimedBy||"")].filter(Boolean).join(" \\xB7 "),open:w("dispatch",l.lane+":"+l.id)})),i=e.landed.map(l=>({key:l.key,title:[l.id.slice(0,8)," ",l.repo||"",l.unreported&&[" ",a`<span class="badge warn unreported">unreported</span>`]],badge:{text:l.verb,tone:l.verb==="failed"?"bad":"ok"},meta:[B(l.note||"",90)," \\xB7 ",v(l.at)," ago"],metaText:`${O(l.note||"")} \\xB7 ${K(l.at)} ago`,open:w("dispatch",l.lane+":"+l.id)})),c=e.reports.map(l=>{let f=_t(l);return{key:l.key,title:l.title,meta:f.nodes,metaText:f.text,open:qe(l),acked:!!l.acked}}),u=e.traps.map(({x:l})=>({key:l.trapId,title:"\\u{1FAA4} "+(l.label??`wt:${l.trapId}`),badge:l.requested?{text:"requested",tone:"dim"}:l.starting?{text:l.starting.failedAt?"start failed":"starting",tone:l.starting.failedAt?"bad":"warn"}:{text:l.live?l.harness||"live":"signed off",tone:l.live?"ok":"dim"},meta:[l.repo||""," \\xB7 ",_e(l)],metaText:`${l.repo||""} \\xB7 ${Fe(l)}`,action:V(l),extra:z(l),open:w("trap",l.trapId)}));return a`<div class="deckgrid"><${us} cards=${e.decisions} drafts=${t} focus=${n} extensions=${s} />${Ve("in flight",o,"dispatches",4,r)}${Ve("Landed \\xB7 24h",i,"dispatches",8,r)}${Ve("reports",c,"reports",8,r)}${Ve("traps",u,"traps",8,r,a`<${Ue} />`)}${br(e,r)}</div>`}function kr(e,t){if(!t)return e;let n=new Map(e.map(o=>[o.id,o])),s=o=>{let i=o,c=new Set;for(;i.followUp&&n.has(i.followUp)&&!c.has(i.id);)c.add(i.id),i=n.get(i.followUp);return i.id},r=new Map;for(let o of e){let i=s(o),c=r.get(i)||[];c.push(o),r.set(i,c)}return[...r.values()].sort((o,i)=>i[0].sort-o[0].sort).flatMap(o=>o.sort((i,c)=>i.id===s(i)?-1:c.id===s(c)?1:i.sort-c.sort))}function yr(e,t){let n=e.lane+":"+e.id;return a`<tr key=${n} class="rowhead" onClick=${w("dispatch",n)}><td>${t&&e.followUp&&a`<span class="dim">\u21B3 </span>`}${e.id.slice(0,8)}</td><td>${e.lane} / ${e.bucket}</td><td>${e.repo}</td><td class=${"v-"+e.verb}>${e.verb}</td><td class="grow">${B(e.note??"",90)}${Ne(e)}${Le(e)}</td><td>${v(e.verbAt)}</td><td>${me(e)}</td><td>${te(e)}</td></tr>`}function wr(e){let t=e.lane+":"+e.id;return a`<div key=${t} class="card" onClick=${w("dispatch",t)}><div class="top"><b>${e.id.slice(0,8)}</b><span class=${"badge v-"+e.verb+H(e.verb)} title=${N(e.verb)}>${e.verb}</span></div><div class="meta" title=${`${e.repo} \\xB7 ${e.lane} ${e.bucket}`}>${e.repo} \xB7 ${e.lane} ${e.bucket}${e.verbAt&&[" \\xB7 ",v(e.verbAt)]}</div>${e.note&&a`<div class="note" title=${O(e.note)}>${B(e.note)}</div>`}${Ne(e)}${Le(e)}<div class="foot">${me(e)} ${te(e)}</div></div>`}function hs({inp:e}){let t=e.list;return e.view==="cards"?t.length?a`<div class="cards">${t.map(wr)}</div>`:a`<div class="empty">no dispatches match</div>`:R(["id","lane / bucket","repo","verb","note","age","addressed","pr"],kr(t,e.chain).map(n=>yr(n,e.chain)),"no dispatches match")}var Tr={deck:"On deck",dispatches:"Dispatches",traps:"Traps",prs:"PRs",reports:"Reports",notices:"Notices"},xr=["working","needs-decision","blocked","paused","done","failed","unknown"];function Sr(e,t){let n=t.daemonStale,s=e.daemon?[a`<span class=${n?"bad":"ok"}>${n&&"stale "}${v(e.daemon.heartbeat)} ago</span>`," ",a`<span class="dim">v${e.daemon.version}</span>`]:a`<span class="bad">down</span>`;return[a`<span class="chip">daemon ${s}</span>`,e.slots&&a`<span class="chip">active headless: ${e.slots.headless} of ${e.slots.limit}; traps: ${e.slots.traps}${e.slots.parked?`; parked: ${e.slots.parked} (no slot)`:""}</span>`,t.helms.map(({x:r,stale:o})=>a`<span key=${r.grounds} class="chip click" onClick=${w("helm",r.grounds)}>\u26F5 <b>${r.man}</b> <span class="dim">helm ${r.grounds}</span> <span class=${o?"warn":"ok"}>${o&&"stale "}${v(r.heartbeatAt)} ago</span></span>`)]}var Tt=[];function Gr(e){let t=[...new Set([...e.dispatches.map(n=>n.repo),...e.notices.map(n=>n.repo),...e.prs.map(n=>n.repo)].filter(Boolean))].sort();return t.length!==Tt.length&&(Tt=t),Tt}var xt=[];function Cr(e){let t=[...new Set(e.notices.map(n=>n.kind))].sort();return t.length!==xt.length&&(xt=t),xt}var be=e=>e.currentTarget.value;function Dr(e,t,n){let s=i=>t===i?"":"display:none",r=e?Gr(e):[],o=e?Cr(e):[];return a`<div class="controls">\n <select id="f-lane" style=${e&&s("dispatches")} value=${n.lane} onChange=${i=>L({lane:be(i)})}>\n <option value="">all lanes</option>\n <option value="work">work</option>\n <option value="chore">chore</option>\n </select>\n <select id="f-repo" value=${n.repo} onChange=${i=>L({repo:be(i)})}>\n <option value="">all repos</option>\n ${r.map(i=>a`<option key=${i}>${i}</option>`)}\n </select>\n <select id="f-verb" style=${e&&s("dispatches")} value=${n.verb} onChange=${i=>L({verb:be(i)})}>\n <option value="">all verbs</option>\n ${xr.map(i=>a`<option key=${i}>${i}</option>`)}\n </select>\n <label id="chain-control" style=${e&&s("dispatches")}><input id="f-chain" type="checkbox" checked=${!!n.chain} onChange=${i=>L({chain:i.currentTarget.checked})} /> group by chain</label>\n <select id="f-kind" style=${e&&s("notices")} value=${n.noticeKind} onChange=${i=>L({noticeKind:be(i)})}>\n <option value="">all notice kinds</option>\n ${o.map(i=>a`<option key=${i}>${i}</option>`)}\n </select>\n <input id="f-q" type="search" placeholder="search id \xB7 note \xB7 brief" value=${n.q} onInput=${i=>L({q:be(i)})} />\n </div>`}function gs({d:e,inp:t,tab:n,st:s,stale:r}){return[a`<div class="headerline"><h1>\u{1F99E}\u2728 spyglass<span id="stale" style=${e||r?r?"display:inline":"display:none":void 0}> \xB7 STALE FEED</span></h1><span id="settings-slot"><button id="gearbtn" title="settings" aria-label="settings" onClick=${()=>C("settings","browser")}>\u2699</button></span></div>`,a`<div class="chips"><span id="chips" style="display:contents">${e&&t&&Sr(e,t.chips)}</span><span class="chip dim" id="clock">${e&&new Date(e.now).toLocaleTimeString("en-GB")}</span></div>`,a`<nav class="tabs" id="tabs" aria-label="Spyglass views">${le.map(o=>a`<a href=${"#"+o} data-tab=${o} class=${e?o===n?"on":"":void 0}>${Tr[o]}</a>`)}</nav>`,Dr(e,n,s)]}var vs=({d:e})=>e&&["\\u{1F99E}\\u2728 lobstah v"+e.version+" \\xB7 ",a`<a href=${e.repoUrl} target="_blank">${e.repoUrl.replace("https://github.com/","")}</a>`];function _s(e,t){if(!t.lobs)return[];let n={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch",report:"report"},s=t.hidden??{},r=e.filter(i=>!i.acked&&!(i.key!==void 0&&s[i.key]===i.stateHash)).map(i=>{let c=n[i.kind??""]??"",u=i.key!==void 0?{hideKey:i.key,hideHash:i.stateHash??""}:{};return i.kind==="decision"&&i.key?{key:"decision:"+i.key,text:i.note||i.verb,label:c,hash:sn(i.key),...u}:typeof i.kind=="string"&&i.kind.startsWith("pr:")&&i.prUrl?{key:i.kind+":"+(i.key??i.prUrl),text:i.note||i.kind,href:i.prUrl,label:c,...u}:{key:(i.kind??"question")+":"+(i.key??i.lane+":"+i.id),text:i.note||i.verb,label:c,...i.kind==="watch"?{}:{open:i.kind==="report"&&i.key?ce(i.key):{type:"dispatch",key:i.lane+":"+i.id}},...u}});!r.length&&t.preview&&(r=[{key:"preview",text:"attention questions crawl in here",...t.previewHelm?{open:{type:"helm",key:t.previewHelm}}:{}}]);let o=r.length>4?r.length-4:0;return r=r.slice(0,4),o&&(r[3]={...r[3],text:"\\u2026and "+o+" more \\u2014 see attention",label:""}),r}var $s=!0;function Ar(e,t,n){let s="animation-duration:"+((innerWidth+180)/(100+t*12)).toFixed(1)+"s;animation-delay:-"+t*9%14+"s",r=()=>{e.hideKey&&Rn(e.hideKey,e.hideHash??"")},o=[a`<div class="bub">${e.label&&[a`<span class="badge dim">${e.label}</span>`," "]}<span>${e.text.length>48?e.text.slice(0,47)+"\\u2026":e.text}</span></div>`,n===!1?a`<span class="fallback">\u{1F99E}</span>`:a`<div class="sprite"></div>`,$s&&a`<img\n class="star"\n src="/star.png"\n alt=""\n onError=${c=>{$s=!1,c.currentTarget.remove()}}\n />`],i=e.open;return e.hash?a`<a key=${e.key} class="lob" style=${s} title="open the decision" href=${e.hash} onClick=${r}>${o}</a>`:e.href?a`<a key=${e.key} class="lob" style=${s} title="open the PR" href=${e.href} target="_blank" rel="noopener" onClick=${r}>${o}</a>`:a`<div\n key=${e.key}\n class="lob"\n style=${s}\n title="click to open"\n onClick=${()=>{r(),i&&C(i.type,i.key)}}\n >\n ${o}\n </div>`}function bs({state:e}){let t=e.snapshot,n=_s(t?.attention||[],{lobs:e.prefs.lobs,hidden:e.lobHidden,preview:e.preview,previewHelm:t&&t.helms.length?t.helms[0].grounds:void 0}),s=n.map(r=>r.key).join("|")+(e.spriteOk===null?"?":e.spriteOk?"s":"e");return Vn(()=>n.map((r,o)=>Ar(r,o,e.spriteOk)),[s])}function ks({box:e}){if(!e)return null;let t=n=>{n.target===n.currentTarget&&ue()};return a`<div id="lightbox" class="lightbox" role="dialog" aria-label=${e.name} onClick=${t}>\n <button type="button" class="lbclose" title="close" onClick=${ue}>\xD7</button>\n <img class="lbimg" src=${e.src} alt=${e.name} />\n <a class="lboriginal" href=${e.src} target="_blank" rel="noopener">open original \xB7 ${e.name}</a>\n </div>`}var se=a`<span class="x" onClick=${Z}>\xD7</span>`,ys=(e,t,n)=>a`<span class="seg">${t.map(([s,r])=>a`<button class=${s===n?"on":""} onClick=${()=>e(s)}>${r}</button>`)}</span>`;function Rr(e,t){let n=ys(Dn,[["table","table"],["cards","cards"]],t.view),s=ys(An,[["on","on"],["off","off"]],t.lobs?"on":"off"),r=e.attentionError?e.attentionError:(e.attentionKinds||[]).join(" \\xB7 ");return[se,a`<h3>\u2699 settings <span class="dim" style="font-weight:normal">\xB7 this browser only</span></h3>`,a`<div class="settings"><div class="row"><span class="lbl">view<span class="hint">cards or table (notices stay a table)</span></span>${n}</div><div class="row"><span class="lbl">lobs<span class="hint">crawling lobsters in this page</span></span>${s}</div><div class="row"><span class="lbl">attention<span class="hint">kinds shown \u2014 attentionKinds in config.toml (read-only here)</span></span><span class="dim" style="font-size:11px;text-align:right;max-width:260px">${r}</span></div></div>`]}function Ir(e,t){let n=ne(t.numbers,new Map(t.numbers.map((r,o)=>[r,t.titles[o]])),e.number),s=t.nextMergeable?[" \\xB7 ",a`<span class="ok">next mergeable</span>`]:t.blockedBy?" \\xB7 blocked by #"+t.blockedBy:t.nextNumber?" \\xB7 next is #"+t.nextNumber:"";return[n," \\xB7 ",t.position," of ",t.size," \\xB7 floor ",t.floor,s]}var Mr=e=>t=>{t.preventDefault(),C("dispatch",e)};function Pr(e,t){let n=pn(e,t),s=n.pr,r=n.stack,o=n.watch,i=je(s),c=n.chain.length?n.chain.flatMap((l,f)=>[f?" \\u2192 ":"",l.culled?a`<span class="dim">${l.id.slice(0,8)} (culled)</span>`:[a`<a href="#" onClick=${Mr(l.modalKey)}>${l.id.slice(0,8)}</a>`," ",a`<span class="dim">${l.verb}</span>`]]):a`<span class="dim">none</span>`,u=o?[a`<div>${o.key} \xB7 owner ${o.owner||"?"} \xB7 ${o.lastCheckedAt?["checked ",v(o.lastCheckedAt)," ago"]:"never checked"}</div>`,o.lastError&&a`<div class="bad">${o.lastError}</div>`,a`<div class="dim" style="font-size:11px;margin-top:4px">cursor</div>`,G(o.cursor)]:a`<div class="dim">no watch \u2014 <code>lobstah watch add ${s.url}</code> registers one</div>`;return[se,a`<h3>${Oe(s)} ${s.title||""} <span class=${"badge "+E(s.badge)}>${s.badge.text}</span>${s.draft&&s.badge.text!=="draft"&&[" ",a`<span class="badge pr-draft">draft</span>`]}</h3>`,a`<div class="sub">${s.repo} \xB7 ${s.state} \xB7 observed ${v(s.observedAt)} ago${s.gate&&" \\xB7 gate "+s.gate}</div>`,a`<div class="sec">checks</div><div>${he(s)}</div><div class="sec">review</div><div>${i||a`<span class="dim">no review yet</span>`}</div><div class="sec">merge</div><div>${ge(s)}</div>${s.repairWait&&a`<div class="sec">repair waits</div><div>${s.repairWait.heldBy}: ${s.repairWait.reason}${s.repairWait.until?" \\xB7 until "+s.repairWait.until:""}</div>`}<div class="sec">refs</div><div>${s.headRefName||"?"} \u2192 ${s.baseRefName||"?"}</div><div class="sec">stack</div><div>${r?Ir(s,r):a`<span class="dim">not stacked</span>`}</div><div class="sec">dispatch chain</div><div>${c}</div><div class="sec">watch</div>`,u]}var ws=(e,t)=>(e==="codex"?"codex resume ":"claude --resume ")+t;function Er(e){let t=Date.now()-Date.parse(e.heartbeatAt)>18e5;return[se,a`<h3>\u26F5 ${e.man}</h3><div class="sub">helm of <b>${e.grounds}</b> (${(e.repos||[]).join(", ")})</div><div class="sub">${e.harness??"?"} \xB7 ${e.cwd??"?"}${e.host&&" \\xB7 "+e.host}</div><div class="sub">session ${e.sessionId??""} \xB7 signed on ${v(e.signedOnAt)} ago \xB7 heartbeat <span class=${t?"warn":"ok"}>${v(e.heartbeatAt)} ago</span></div>`,e.sessionId&&[a`<div class="sec">open this session</div>`,G(ws(e.harness,e.sessionId))],e.transcript&&[a`<div class="sec">transcript</div>`,G(e.transcript)]]}function Lr(e,t){return[se,a`<h3>\u{1F4C4} ${e.title}</h3>`,a`<${wt} r=${e} text=${t} />`]}function Nr(e,t,n){let s=e.claimedBy&&e.claimedBy.startsWith("wt:")?[a`<div class="sec">worked by trap</div>`,a`<div class="claimedby">claimed by ${He(e.claimedBy.slice(3))}</div>`,G(O(e.claimedBy)),a`<div class="dim" style="font-size:11px">an opted-in interactive session mans this seat \u2014 attach would resume someone\'s live thread. Message it instead: lobstah send ${O(e.claimedBy)} "\u2026"</div>`]:[a`<div class="sec">open this session</div>`,G("lobstah attach "+e.id)];return[se,a`<h3>${e.id.slice(0,8)} <span class=${"badge v-"+e.verb}>${e.verb}</span></h3>`,a`<div class="sub">${e.repo} \xB7 ${e.lane} ${e.bucket} \xB7 ${v(e.verbAt)}${e.for&&[" \\xB7 ",me(e)]} ${te(e)}</div>`,s,e.worktree&&[a`<div class="sec">worktree${e.worktreeOf?" (reused from "+e.worktreeOf.slice(0,8)+")":""}</div>`,G(e.worktree),e.worktreeKept&&a`<div class="dim" style="font-size:11px">kept: ${e.worktreeKept}</div>`],e.transcript&&[a`<div class="sec">transcript</div>`,G(e.transcript)],t&&a`<${wt} r=${t} text=${n} heading=${!0} />`,Zn(e)]}function Hr(e){let t=ve(e),n=e.requested?[e.repo??""," \\xB7 ",e.harness??""," \\xB7 requested ",v(e.requested.at)," ago from the glass; the helm reserves it and starts its session."]:e.starting?e.starting.failedAt?[e.repo??""," \\xB7 reserved ",v(e.starting.reservedAt)," ago \\xB7 start failed: ",e.starting.reason??"",". Its addressed work stays queued; a session can still redeem the ticket, or `lobstah stow --wt ",e.name??e.trapId,"` withdraws it."]:[e.repo??""," \\xB7 reserved ",v(e.starting.reservedAt)," ago \\xB7 starting: waiting for a session to redeem the ticket (due by ",e.starting.deadline,")"]:e.live?[e.repo??"addressed bait only"," \\xB7 session ",e.sessionId??""," \\xB7 signed on ",v(e.signedOnAt)," ago \\xB7 ",t.listen," \\xB7 heartbeat ",t.hb]:"signed off \\u2014 registration gone; the lifecycle, messages, and catches are the surviving record. Re-soaking the same worktree restores this address.",s=e.notices.length?e.notices.map(i=>a`<div key=${i.seq} class="loglines">${v(i.at)} ago \xB7 <b>${i.kind}</b> \u2014 ${i.text}</div>`):a`<div class="empty">none recorded</div>`,r=e.messages.length?e.messages.map(i=>a`<div key=${i.file} class=${"msg"+(i.from==="helm"?" from-helm":"")}><div class="hdr">from ${i.from} \xB7 ${i.at&&[v(i.at)," ago"]} \xB7 ${i.state==="pending"?a`<span class="warn">pending</span>`:a`<span class="ok">delivered</span>`}</div>${i.text}${i.attachments?.length?ee(i.attachments,c=>rn(e.trapId,c)):""}</div>`):a`<div class="empty">none</div>`,o=e.catches.length?e.catches.map(i=>a`<div key=${i.lane+":"+i.id} class="catch"><div class="hdr"><b>${i.id.slice(0,8)}</b><span class=${"badge v-"+i.verb}>${i.verb}</span><span class="dim">${v(i.verbAt)}</span>${te(i)}</div><div class="loglines">${ft(i)}</div></div>`):a`<div class="empty">none yet</div>`;return[se,a`<h3>\u{1FAA4} ${e.label??`wt:${e.trapId}`} <span class="badge">${e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??"signed off"}</span></h3>`,e.worktree&&a`<div class="sub">${e.worktree}</div>`,a`<div class="sub">${n}</div>`,a`<div class="sec">window</div>`,V(e),z(e),e.live&&e.sessionId&&[a`<div class="sec">open this session</div>`,G(ws(e.harness,e.sessionId)),a`<div class="dim" style="font-size:11px">as registered at sign-on \u2014 a hookless enlistment may hold a made-up id</div>`],a`<div class="sec">lifecycle (${e.notices.length})</div>`,s,a`<div class="sec">messages (${e.messages.length})</div>`,r,a`<div class="sec">catches (${e.catches.length})</div>`,o]}function Ts({snapshot:e,modal:t,prefs:n,reportText:s}){if(!e||!t)return null;let r=Q(e,t);if(!r)return null;if(t.type==="settings")return Rr(r,n);if(t.type==="pr")return Pr(e,t.key);if(t.type==="helm")return Er(r);if(t.type==="report")return Lr(r,s[t.key]);if(t.type==="dispatch"){let o=ln(e,r);return Nr(r,o,o&&s[o.key])}return Hr(r)}var Or=e=>a`<tr key=${e.seq}><td class="dim">${v(e.at)}</td><td>${e.kind}</td><td class="grow">${e.text}</td><td class="dim">${e.repo??""}</td></tr>`,xs=({inp:e})=>R(["at","kind","text","repo"],e.list.map(Or),"no notices");function Ss(e){let t=new Map;for(let n of e.prs){let s=t.get(n.stackId)||[];s.push(n),t.set(n.stackId,s)}return e.stacks.map(n=>({s:n,prs:t.get(n.id)||[]})).filter(n=>n.prs.length)}var Gs=(e,t)=>ne(e.numbers,new Map(t.map(n=>[n.number,n.title]))),St=e=>e.state+(e.draft?" \\xB7 draft":"")+(e.state==="MERGED"&&e.mergedAt?" \\xB7 "+e.mergedAt:"");function Cs(e){let t=s=>{let r=String(s??"");return r.length>24?r.slice(0,23)+"\\u2026":r},n=e.watches.map(s=>a`<tr key=${s.key}><td>${s.key}</td><td>${s.owner}</td><td title=${s.cursor}>${t(s.cursor)}</td><td>${s.lastCheckedAt&&v(s.lastCheckedAt)}</td><td>${s.lastError||""}</td></tr>`);return[a`<h2>other watches</h2>`,R(["key","owner","cursor","last check","error"],n,"no other watches")]}function Br(e){let t=Ss(e).flatMap(({s:n,prs:s})=>[a`<tr key=${"stack:"+n.id}><th colspan="8">${Gs(n,s)} \xB7 floor ${n.floor}${n.open?" \\xB7 open":" \\xB7 history"}</th></tr>`,...s.map(r=>a`<tr key=${r.key} class="rowhead" onClick=${w("pr",r.key)}><td>${Oe(r)}</td><td class="grow">${r.title||""}</td><td>${St(r)}</td><td>${he(r)}</td><td>${je(r)}</td><td>${ge(r)}</td><td>${ht(r.watch)}</td><td>${r.gate||""}</td></tr>`)]);return[R(["PR","title","state","checks","review","merge","watch","gate"],t,"no PR evidence"),Cs(e)]}function jr(e){let t=Ss(e),n=r=>a`<div key=${r.key} class="card" onClick=${w("pr",r.key)}><div class="top">${Be(r)}<span class=${"badge "+E(r.badge)+H(r.badge.text)} title=${N(r.badge.text)}>${r.badge.text}</span></div><div class="meta" title=${`${r.repo} \\xB7 ${St(r)}`}>${r.repo} \xB7 ${St(r)} \xB7 ${ge(r)}</div><div class="foot"><span>${he(r)}</span><span>${ht(r.watch)}</span>${r.gate&&a`<span>gate ${r.gate}</span>`}</div></div>`;return[t.length?t.map(({s:r,prs:o})=>a`<${J} key=${"stack:"+r.id}><h2>${Gs(r,o)} \xB7 floor ${r.floor}${r.open?"":" \\xB7 history"}</h2><div class="cards">${o.map(n)}</div><//>`):a`<div class="empty">no PR evidence</div>`,Cs(e)]}var Ds=({inp:e})=>e.view==="cards"?jr(e):Br(e);var Gt=e=>e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??(e.live?"":"signed off"),As=e=>e.live||e.starting?"":" dim";function Ur(e){let t=ve(e);return a`<tr key=${e.trapId} class=${"rowhead"+As(e)} onClick=${w("trap",e.trapId)}><td><b>${e.label??`wt:${e.trapId}`}</b></td><td>${e.repo??"\\u2014"}</td><td class="grow">${e.worktree??""}</td><td>${e.harness??""}</td><td>${(e.sessionId??"").slice(0,8)}</td><td>${_e(e)}${z(e)}</td><td>${t.listen}</td><td>${t.hb}</td><td>${vt(e)}</td><td>${e.catches.length}</td><td>${V(e)}</td></tr>`}function Fr(e){let t=ve(e),n=vt(e),s=`${e.repo??(e.live?"addressed bait only":"history")}${e.sessionId?" \\xB7 session "+e.sessionId.slice(0,8):""}`;return a`<div key=${e.trapId} class=${"card"+As(e)} onClick=${w("trap",e.trapId)}><div class="top"><b>\u{1FAA4} ${e.label??`wt:${e.trapId}`}</b><span class=${"badge"+H(Gt(e))} title=${N(Gt(e))}>${Gt(e)}</span></div><div class="meta" title=${s}>${s}</div>${e.worktree&&a`<div class="note" title=${e.worktree}>${e.worktree}</div>`}<div class="note" title=${Fe(e)}>${_e(e)}</div>${z(e)}<div class="foot"><span>${t.listen}${e.live&&[" \\xB7 heartbeat ",t.hb]} \xB7 ${e.catches.length} catch${e.catches.length===1?"":"es"}${n&&[" \\xB7 ",n]}</span><span class="footact">${V(e)}</span></div></div>`}function Rs({inp:e}){let t=e.list.map(s=>s.x),n=a`<div class="tabhead"><${Ue} /></div>`;return e.view==="cards"?[n,t.length?a`<div class="cards">${t.map(Fr)}</div>`:a`<div class="empty">no traps soaking</div>`]:[n,R(["address","repo","worktree","harness","session","now","listening","heartbeat","mail","catches","window"],t.map(Ur),"no traps soaking")]}function Is({state:e}){let t=e.snapshot,n=e.route,s=t&&dn(t,{st:e.prefs,modal:e.modal},Date.now()),r=i=>!s||i!==n?null:i==="deck"?a`<${ms} inp=${s.deck} drafts=${e.drafts} focus=${e.focusDecision} extensions=${t?.answerLimits?.extensions??[]} />`:i==="dispatches"?a`<${hs} inp=${s.dispatches} />`:i==="traps"?a`<${Rs} inp=${s.traps} />`:i==="prs"?a`<${Ds} inp=${s.prs} />`:i==="reports"?a`<${ss} inp=${s.reports} />`:a`<${xs} inp=${s.notices} />`,o=i=>{i.target===i.currentTarget&&Z()};return[a`<${gs} d=${t} inp=${s} tab=${n} st=${e.prefs} stale=${e.stale} />`,le.map(i=>a`<main key=${i} id=${"page-"+i} class=${t&&i===n?"tabpage on":"tabpage"}><div id=${i}>${r(i)}</div></main>`),a`<footer id="foot"><${vs} d=${t} /></footer>`,a`<div id="lobs"><${bs} state=${e} /></div>`,a`<${ks} box=${e.lightbox} />`,a`<div id="overlay" class=${e.modal&&t?"open":t?"":void 0} onClick=${o}><div class="modal" id="modalbox"><${Ts} snapshot=${t} modal=${e.modal} prefs=${e.prefs} reportText=${e.reportText} /></div></div>`]}var Ct=!1,ke=null;async function Dt(){if(!Ct){Ct=!0;try{let e=await fetch("/data");if(!e.ok)throw new Error(`/data answered ${e.status}`);at(await e.json())}catch{xn()}finally{Ct=!1}}}var Ms=()=>{ke||(ke=setInterval(Dt,2e3))},qr=()=>{ke&&clearInterval(ke),ke=null};function Ps(){document.addEventListener("visibilitychange",()=>{document.hidden?qr():(Dt(),Ms())}),Dt(),document.hidden||Ms()}var At=()=>tn(location.hash),Rt=()=>nn(location.hash),Es=e=>window.addEventListener("hashchange",()=>e(At()));_n({snapshot:void 0,route:At(),prefs:fn(),modal:Rt(),stale:!1,lobHidden:hn(),spriteOk:null,focusResults:{},preview:new URLSearchParams(location.search).has("lob"),reportText:{},drafts:{},focusDecision:nt(location.hash),lightbox:null});var Ls,It=!1,Ns=()=>{let e=_(),t=e.route!==Ls||!It&&!!e.snapshot;Qt(ae(Is,{state:e}),document.body),Ls=e.route,It||(It=!!e.snapshot),t&&window.scrollTo(0,0),Wr(e.focusDecision)},Mt=null;function Wr(e){if(!e||e===Mt)return;let t=[...document.querySelectorAll("[data-decision]")].find(n=>n.getAttribute("data-decision")===e);t&&(Mt=e,t.scrollIntoView?.({block:"center"}))}$n(Ns);Ns();var Pt=new Image;Pt.onload=()=>S({spriteOk:!0});Pt.onerror=()=>S({spriteOk:!1});Pt.src="/lob-sprite.png";Es(e=>{let t=Rt(),n=nt(location.hash);n!==_().focusDecision&&(Mt=null),S(t?{route:e,modal:t,focusDecision:n}:{route:e,focusDecision:n}),t&&Ie()});document.addEventListener("keydown",e=>{e.key==="Escape"&&(_().lightbox?ue():Z())});Ps();})();</script>\n </body>\n</html>\n';
13273
+ var GLASS_PAGE = '<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width,initial-scale=1" />\n <title>spyglass</title>\n <link rel="icon" type="image/png" href="/icon.png" />\n <style>:root{--bg: #0e1116;--card: #161b22;--line: #2b3240;--line-hover: #3a455a;--row-hover: #1c2330;--inset: #10151c;--seg-on: #26436b;--scrim: rgba(4, 7, 11, 0.72);--fg: #dbe2ea;--dim: #8b96a5;--ok: #4fc17c;--warn: #e2b93d;--bad: #e26d5c;--link: #6cb2e2;--on-fill: #fff;--pr-merged: #8957e5;--pr-merged-fg: #ab7df8;--pr-open: #238636;--pr-draft: #6e7681;--pr-closed: #da3633;--font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;--font-size: 13px;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--page-pad-block: 14px;--radius: 6px;--card-radius: 8px;--card-pad: 12px 14px;--card-min: 300px;--deck-card-min: 240px;--badge-radius: 5px;--badge-pad: 1px 7px;--badge-font: 11px;--modal-radius: 10px;--modal-width: 780px}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:var(--font-size)/1.45 var(--font-mono);padding-block:var(--page-pad-block);padding-inline:var(--space-4);display:flex;flex-direction:column;min-height:100vh}h1{font-size:15px;margin:0 0 10px}h1 .dim{color:var(--dim);font-weight:normal}h2{font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.08em;margin:20px 0 6px}.chips,.controls{display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center}.controls{margin:0 0 14px}.chips{margin-bottom:8px}.chip{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:3px 9px}.controls select,.newtrap select,.controls input[type=search]{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);color:var(--fg);font:inherit;padding:4px 8px}.controls input[type=search]{flex:1 1 140px;min-width:120px;max-width:340px}#chain-control{display:inline-flex;align-items:center;gap:7px;white-space:nowrap}#f-chain{margin:0;width:14px;height:14px;accent-color:var(--link)}.tabs{display:flex;gap:var(--space-1);border-bottom:1px solid var(--line);margin:8px 0 10px}.tabs a{color:var(--dim);padding:6px 11px;border-bottom:2px solid transparent}.tabs a.on{color:var(--fg);border-color:var(--link)}.tabpage{display:none}.tabpage.on{display:block;flex:1 0 auto}.headerline{display:flex;align-items:center;gap:var(--space-2)}.headerline h1{flex:1}#settings-slot{min-width:34px;text-align:right;color:var(--dim)}#settings-slot #gearbtn{margin-left:0}.deckgrid{display:flex;flex-direction:column;gap:var(--space-3)}.deckgrid h2{margin:5px 0}.deckgrid section{width:100%;min-width:0}.deckline{padding:2px 0;border-top:1px solid var(--line);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.deckline.acked,.card.acked,.rowhead.acked,.badge.acked{opacity:0.55}.deckmore{color:var(--dim);font-size:11px;display:inline-block;margin-top:4px}.deckline.click{cursor:pointer}.deckline.click:hover{background:var(--row-hover)}.deckgrid h2 a{color:inherit}.deckgrid h2 a:hover{color:var(--fg)}.deckgrid .cards{grid-template-columns:repeat(auto-fill,minmax(min(var(--deck-card-min),100%),1fr));gap:10px}.deckstack{margin-bottom:9px}.deckstack>.dim{font-size:11px;margin:3px 0 5px}.seg{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}.seg button{background:var(--card);border:none;color:var(--dim);font:inherit;padding:4px 11px;cursor:pointer}.seg button.on{background:var(--seg-on);color:var(--fg)}.wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}th,td{text-align:left;padding:4px 9px;border-top:1px solid var(--line);vertical-align:top;white-space:nowrap}td.grow{white-space:normal;word-break:break-word;min-width:140px}th{color:var(--dim);font-weight:normal;border-top:none;font-size:11px}tr.rowhead{cursor:pointer}tr.rowhead:hover{background:var(--row-hover)}.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--card-min),100%),1fr));gap:var(--space-3)}.card{background:var(--card);border:1px solid var(--line);border-radius:var(--card-radius);padding:var(--card-pad);cursor:pointer;min-width:0;overflow:hidden;overflow-wrap:anywhere}.card:hover{border-color:var(--line-hover)}.card .top{display:flex;justify-content:space-between;gap:var(--space-3);align-items:center;min-height:22px}.card .top>b,.card .top>.prname{flex:1 1000000 auto;min-width:min(10ch,100%);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card .top .badge{flex:0 0 auto}.card .top .badge.long{flex:0 1 auto;min-width:min(12ch,100%);max-width:min(26ch,100%);overflow:hidden;text-overflow:ellipsis}.card .meta{color:var(--dim);font-size:12px;margin-top:2px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.card .note{margin-top:6px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.activity{margin-top:4px;font-size:12px;color:var(--fg);opacity:0.85}.waiting{margin-top:4px;font-size:12px;color:var(--dim)}.activity.stale{color:var(--dim);opacity:1}.card .foot{margin-top:8px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;color:var(--dim);font-size:12px}.card .foot>*{min-width:0}.card .foot .footact{margin-left:auto}.btn{background:var(--card);border:1px solid var(--line);border-radius:5px;color:var(--dim);font:inherit;font-size:11px;padding:1px 8px;cursor:pointer;white-space:nowrap}.btn:hover{color:var(--fg);border-color:var(--line-hover)}.badge{border-radius:var(--badge-radius);padding:var(--badge-pad);font-size:var(--badge-font);line-height:1.5;border:1px solid var(--line);white-space:nowrap;display:inline-block}.badge.pr-merged{background:var(--pr-merged);border-color:var(--pr-merged-fg);color:var(--on-fill)}.badge.pr-open{background:var(--pr-open);border-color:var(--pr-open);color:var(--on-fill)}.badge.pr-draft{background:var(--pr-draft);border-color:var(--pr-draft);color:var(--on-fill)}.badge.pr-closed{background:var(--pr-closed);border-color:var(--pr-closed);color:var(--on-fill)}.badge.pr-conflicts{background:var(--pr-closed);border-color:var(--pr-closed);color:var(--on-fill)}.badge.pr-behind{background:var(--pr-draft);border-color:var(--pr-draft);color:var(--on-fill)}.badge.unreported{font-weight:normal;font-size:10px;padding:0 5px;vertical-align:1px}.v-done{color:var(--ok)}.v-working,.v-queued{color:var(--fg)}.v-needs-decision,.v-blocked{color:var(--bad);font-weight:bold}.v-failed{color:var(--bad)}.v-paused,.v-unknown{color:var(--dim)}.dim{color:var(--dim)}.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}.detail{display:none}.detail.open{display:table-row}.detail td{background:var(--inset);white-space:pre-wrap;word-break:break-word;font-size:12px;color:var(--dim)}.detail b{color:var(--fg)}.empty{color:var(--dim);padding:6px 2px}#stale{display:none;color:var(--bad)}a{color:var(--link);text-decoration:none}.dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle}.dot.ok{background:var(--ok)}.dot.warn{background:var(--warn)}.dot.bad{background:var(--bad)}.dot.dim{background:var(--dim)}#overlay{position:fixed;inset:0;background:var(--scrim);display:none;z-index:10;padding:28px 16px;overflow:auto}#overlay.open{display:block}.modal{max-width:var(--modal-width);margin:0 auto;background:var(--card);border:1px solid var(--line);border-radius:var(--modal-radius);padding:16px 18px;position:relative}.modal .x{position:absolute;top:8px;right:12px;cursor:pointer;color:var(--dim);font-size:18px;line-height:1}.modal .x:hover{color:var(--fg)}.modal h3{margin:0 24px 2px 0;font-size:14px}.modal .sub{color:var(--dim);font-size:12px;margin-bottom:10px}.modal .sec{color:var(--dim);text-transform:uppercase;letter-spacing:0.08em;font-size:11px;margin:14px 0 4px}.modal pre{white-space:pre-wrap;word-break:break-word;margin:0;font:inherit;color:var(--fg)}.msg{border-left:3px solid var(--line);padding:3px 10px;margin:8px 0;white-space:pre-wrap;word-break:break-word}.msg.from-helm{border-color:var(--link)}.msg .hdr{color:var(--dim);font-size:11px}.catch{border:1px solid var(--line);border-radius:var(--radius);padding:6px 10px;margin:8px 0}.catch .hdr{display:flex;gap:10px;flex-wrap:wrap;align-items:baseline}.loglines{color:var(--dim);font-size:12px;white-space:pre-wrap;word-break:break-word;margin-top:4px}.cmd{display:flex;gap:var(--space-2);align-items:center;margin:5px 0;flex-wrap:wrap}.cmd code{background:var(--inset);border:1px solid var(--line);border-radius:5px;padding:3px 8px;word-break:break-all;cursor:pointer}.cmd code:hover{border-color:var(--line-hover)}.cmd code.copied{border-color:var(--ok)}.cmd button{background:var(--card);border:1px solid var(--line);border-radius:5px;color:var(--dim);font:inherit;font-size:11px;padding:2px 8px;cursor:pointer}.cmd button:hover{color:var(--fg)}.chip.click{cursor:pointer}.chip.click:hover{border-color:var(--line-hover)}footer{margin-top:26px;padding-top:10px;border-top:1px solid var(--line);color:var(--dim);font-size:12px;display:flex;gap:var(--space-2);flex-wrap:wrap}.lob{position:fixed;bottom:6px;left:0;z-index:5;cursor:pointer;font-size:34px;line-height:1;user-select:none;animation:crawl 18s linear infinite}a.lob{color:inherit}.lob .bub .badge{display:inline-block;margin:0 0 3px}.lob .sprite{width:72px;height:56px;background:url(/lob-sprite.png) 0 0 no-repeat;background-size:400% 100%;image-rendering:pixelated;animation:step 0.5s steps(4) infinite}.lob .fallback{display:inline-block;animation:waddle 0.45s ease-in-out infinite alternate}.lob .bub{display:none;position:absolute;bottom:58px;right:-8px;z-index:2;background:var(--card);border:1px solid var(--line);border-radius:9px;padding:6px 9px 5px;font-size:11px;line-height:1.35;color:var(--fg);width:max-content;max-width:150px;box-shadow:0 2px 8px rgba(0,0,0,0.4)}.lob:hover .bub{display:block}.lob .bub span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;white-space:normal;word-break:break-word}.lob .star{position:absolute;left:56px;top:-9px;height:14px;image-rendering:pixelated;z-index:3}.lob:hover{animation-play-state:paused}@keyframes crawl{0%{transform:translateX(-90px)}100%{transform:translateX(100vw)}}@keyframes step{to{background-position-x:-288px}}@keyframes waddle{from{transform:rotate(-8deg) translateY(0)}to{transform:rotate(8deg) translateY(-3px)}}#gearbtn{background:none;border:1px solid var(--line);border-radius:var(--radius);color:var(--dim);font:inherit;font-size:13px;padding:1px 7px;margin-left:8px;cursor:pointer;vertical-align:1px}#gearbtn:hover,#gearbtn.on{color:var(--fg);border-color:var(--line-hover)}.settings .row{display:flex;justify-content:space-between;align-items:center;gap:14px;margin:12px 0}.settings .lbl{color:var(--fg);font-size:12px}.settings .hint{display:block;color:var(--dim);font-size:11px;margin-top:2px}.dcards{display:flex;flex-direction:column;gap:10px}.dcard{width:100%;background:var(--card);border:1px solid var(--line);border-radius:var(--card-radius);padding:var(--card-pad)}.dcard.focus{animation:dflash 1.6s ease-out 1}@keyframes dflash{0%,35%{border-color:var(--link);box-shadow:0 0 0 3px var(--link)}100%{border-color:var(--line);box-shadow:0 0 0 0 transparent}}.dcard.answered{opacity:0.7}.dcard .dtop{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-2)}.dcard .dtop .badge{margin-top:0}.dcard .dtitle{white-space:pre-wrap;overflow-wrap:anywhere}.dcard .dmeta{font-size:11px;margin-left:auto}.dcard .dlink{color:var(--link)}.dfiles{display:flex;flex-wrap:wrap;gap:var(--space-2);margin:6px 0}.dfiles .dimg img{max-height:160px;max-width:320px;border:1px solid var(--line);border-radius:var(--radius);display:block}.dfiles .dfile{width:100%;font-size:11px}.doptions{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 6px}.btn.dopt{font-size:12px;padding:3px 12px;color:var(--fg)}.btn.dopt.on{background:var(--seg-on);border-color:var(--link)}.danswer{display:block;width:100%;min-height:3.2em;max-height:50vh;margin:6px 0;padding:6px 8px;resize:vertical;overflow-y:auto;field-sizing:content;background:var(--inset);color:var(--fg);border:1px solid var(--line);border-radius:var(--radius);font:inherit}.danswer:focus{outline:none;border-color:var(--line-hover)}.dfoot{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.dfoot .dattach input{display:none}.dfoot .dchip{font-size:11px;border:1px solid var(--line);border-radius:var(--badge-radius);padding:0 0 0 6px}.dfoot .dx{background:none;border:none;color:var(--dim);cursor:pointer;font:inherit}.dfoot .derr{font-size:11px}.btn.dsend{margin-left:auto;color:var(--fg);padding:2px 14px}.btn:disabled{cursor:default;opacity:0.6}.danswered{margin-top:6px}.thumb,.dimg,.mdimg{background:none;border:none;padding:0;cursor:zoom-in;font:inherit}.thumb{display:block;margin:4px 0}.thumb img{max-height:120px;max-width:240px;border:1px solid var(--line);border-radius:var(--radius);display:block}.lightbox{position:fixed;inset:0;z-index:20;background:rgba(0,0,0,0.85);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2)}.lightbox .lbimg{max-width:90vw;max-height:90vh;object-fit:contain;border-radius:var(--radius);box-shadow:0 8px 40px rgba(0,0,0,0.6)}.lightbox .lbclose{position:absolute;top:12px;right:16px;background:none;border:none;color:var(--fg);font-size:28px;line-height:1;cursor:pointer}.lightbox .lboriginal{color:var(--link);font-size:12px}.mdpage{background:var(--inset);border:1px solid var(--line);border-radius:6px;padding:8px 14px;margin:6px 0;line-height:1.5;overflow-wrap:anywhere}.mdpage h1,.mdpage h2,.mdpage h3,.mdpage h4{margin:12px 0 6px;line-height:1.25}.mdpage h1{font-size:18px}.mdpage h2{font-size:15px}.mdpage h3,.mdpage h4{font-size:13px}.mdpage p,.mdpage ul,.mdpage ol,.mdpage blockquote{margin:6px 0}.mdpage ul,.mdpage ol{padding-left:22px}.mdpage a{color:var(--link)}.mdpage code{background:var(--card);border-radius:3px;padding:0 3px}.mdpage pre.mdcode{background:var(--card);border:1px solid var(--line);border-radius:4px;padding:8px;overflow-x:auto;white-space:pre}.mdpage pre.mdcode code{padding:0;background:none}.mdpage blockquote{border-left:3px solid var(--line);padding-left:10px;color:var(--dim)}.mdpage img{max-width:100%;height:auto;border-radius:4px;display:block;margin:6px 0}.mdpage hr{border:0;border-top:1px solid var(--line)}.mdpage .mdtable{overflow-x:auto}.mdpage table{border-collapse:collapse;margin:6px 0}.mdpage th,.mdpage td{border:1px solid var(--line);padding:3px 8px;text-align:left}.tabhead{margin:0 0 8px}.newtrap{display:inline-flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:12px;font-weight:normal;text-transform:none;letter-spacing:normal}.startcmds{margin:6px 0;font-size:11px;cursor:default}.reportview{max-width:1100px;margin:0 auto;padding:20px 16px 48px}.reportview h1{font-size:18px;margin:0 0 4px}.reportview .sub{color:var(--dim);font-size:12px;margin-bottom:10px}.reportview .sec{color:var(--dim);text-transform:uppercase;letter-spacing:0.08em;font-size:11px;margin:14px 0 4px}.reportview .mdpage{padding:12px 20px}</style>\n </head>\n <body>\n <!-- The page is rendered by Preact (src/components/app.ts): header, tabs, controls, the five tab pages, footer, lobs, modal overlay. -->\n <script>"use strict";(()=>{var Ae,b,Bt,Bs,O,Nt,Ot,qt,Je,Ge,le,Ft,Ze,Xe,Qe,Os,Se={},Ce=[],qs=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Re=Array.isArray;function E(e,t){for(var n in t)e[n]=t[n];return e}function Ye(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Q(e,t,n){var s,r,i,o={};for(i in t)i=="key"?s=t[i]:i=="ref"?r=t[i]:o[i]=t[i];if(arguments.length>2&&(o.children=arguments.length>3?Ae.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)o[i]===void 0&&(o[i]=e.defaultProps[i]);return xe(e,o,s,r,null)}function xe(e,t,n,s,r){var i={type:e,props:t,key:n,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:r??++Bt,__i:-1,__u:0};return r==null&&b.vnode!=null&&b.vnode(i),i}function Z(e){return e.children}function Te(e,t){this.props=e,this.context=t}function V(e,t){if(t==null)return e.__?V(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type=="function"?V(e):null}function Fs(e){if(e.__P&&e.__d){var t=e.__v,n=t.__e,s=[],r=[],i=E({},t);i.__v=t.__v+1,b.vnode&&b.vnode(i),et(e.__P,i,t,e.__n,e.__P.namespaceURI,32&t.__u?[n]:null,s,n??V(t),!!(32&t.__u),r),i.__v=t.__v,i.__.__k[i.__i]=i,Jt(s,i,r),t.__e=t.__=null,i.__e!=n&&Wt(i)}}function Wt(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),Wt(e)}function Ht(e){(!e.__d&&(e.__d=!0)&&O.push(e)&&!De.__r++||Nt!=b.debounceRendering)&&((Nt=b.debounceRendering)||Ot)(De)}function De(){try{for(var e,t=1;O.length;)O.length>t&&O.sort(qt),e=O.shift(),t=O.length,Fs(e)}finally{O.length=De.__r=0}}function Vt(e,t,n,s,r,i,o,c,u,l,f){var h,d,m,p,g,x,G=s&&s.__k||Ce,$=t.length;for(u=Ws(n,t,G,u,$),h=0;h<$;h++)(m=n.__k[h])!=null&&(d=m.__i!=-1&&G[m.__i]||Se,m.__i=h,x=et(e,m,d,r,i,o,c,u,l,f),p=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&tt(d.ref,null,m),f.push(m.ref,m.__c||p,m)),g==null&&p!=null&&(g=p),4&m.__u?(u=Kt(m,u,e),d.__e&&(d.__e=null)):typeof m.type=="function"&&x!==void 0?u=x:p&&(u=p.nextSibling),m.__u&=-7);return n.__e=g,u}function Ws(e,t,n,s,r){var i,o,c,u,l,f=n.length,h=f,d=0;for(e.__k=new Array(r),i=0;i<r;i++)(o=t[i])!=null&&typeof o!="boolean"&&typeof o!="function"?(typeof o=="string"||typeof o=="number"||typeof o=="bigint"||o.constructor==String?o=e.__k[i]=xe(null,o,null,null,null):Re(o)?o=e.__k[i]=xe(Z,{children:o},null,null,null):o.constructor===void 0&&o.__b>0?o=e.__k[i]=xe(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):e.__k[i]=o,u=i+d,o.__=e,o.__b=e.__b+1,c=null,(l=o.__i=Vs(o,n,u,h))!=-1&&(h--,(c=n[l])&&(c.__u|=2)),c==null||c.__v==null?(l==-1&&(r>f?d--:r<f&&d++),typeof o.type!="function"&&(o.__u|=4)):l!=u&&(l==u-1?d--:l==u+1?d++:(l>u?d--:d++,o.__u|=4))):e.__k[i]=null;if(h)for(i=0;i<f;i++)(c=n[i])!=null&&(2&c.__u)==0&&(c.__e==s&&(s=V(c)),Qt(c,c));return s}function Kt(e,t,n){var s,r;if(typeof e.type=="function"){for(s=e.__k,r=0;s&&r<s.length;r++)s[r]&&(s[r].__=e,t=Kt(s[r],t,n));return t}e.__e!=t&&(t&&e.type&&!t.parentNode&&(t=V(e)),t=n.insertBefore(e.__e,t||null));do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function Vs(e,t,n,s){var r,i,o,c=e.key,u=e.type,l=t[n],f=l!=null&&(2&l.__u)==0;if(l===null&&c==null||f&&c==l.key&&u==l.type)return n;if(s>(f?1:0)){for(r=n-1,i=n+1;r>=0||i<t.length;)if((l=t[o=r>=0?r--:i++])!=null&&(2&l.__u)==0&&c==l.key&&u==l.type)return o}return-1}function Ut(e,t,n){t[0]=="-"?e.setProperty(t,n??""):e[t]=n==null?"":typeof n!="number"||qs.test(t)?n:n+"px"}function we(e,t,n,s,r){var i,o;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof s=="string"&&(e.style.cssText=s=""),s)for(t in s)n&&t in n||Ut(e.style,t,"");if(n)for(t in n)s&&n[t]==s[t]||Ut(e.style,t,n[t])}else if(t[0]=="o"&&t[1]=="n")i=t!=(t=t.replace(Ft,"$1")),o=t.toLowerCase(),t=o in e||t=="onFocusOut"||t=="onFocusIn"?o.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=n,n?s?n[le]=s[le]:(n[le]=Ze,e.addEventListener(t,i?Qe:Xe,i)):e.removeEventListener(t,i?Qe:Xe,i);else{if(r=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&n==1?"":n))}}function jt(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t[Ge]==null)t[Ge]=Ze++;else if(t[Ge]<n[le])return;return n(b.event?b.event(t):t)}}}function et(e,t,n,s,r,i,o,c,u,l){var f,h,d,m,p,g,x,G,$,P,ie,W,ae,Lt,ye,ze,I=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(u=!!(32&n.__u),i=[c=t.__e=n.__e]),(f=b.__b)&&f(t);e:if(typeof I=="function"){h=o.length;try{if($=t.props,P=I.prototype&&I.prototype.render,ie=(f=I.contextType)&&s[f.__c],W=f?ie?ie.props.value:f.__:s,n.__c?G=(d=t.__c=n.__c).__=d.__E:(P?t.__c=d=new I($,W):(t.__c=d=new Te($,W),d.constructor=I,d.render=zs),ie&&ie.sub(d),d.state||(d.state={}),d.__n=s,m=d.__d=!0,d.__h=[],d._sb=[]),P&&d.__s==null&&(d.__s=d.state),P&&I.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=E({},d.__s)),E(d.__s,I.getDerivedStateFromProps($,d.__s))),p=d.props,g=d.state,d.__v=t,m)P&&I.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),P&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(P&&I.getDerivedStateFromProps==null&&$!==p&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps($,W),t.__v==n.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate($,d.__s,W)===!1){t.__v!=n.__v&&(d.props=$,d.state=d.__s,d.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(X){X&&(X.__=t)}),Ce.push.apply(d.__h,d._sb),d._sb=[],d.__h.length&&o.push(d),c=V(n);break e}d.componentWillUpdate!=null&&d.componentWillUpdate($,d.__s,W),P&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(p,g,x)})}if(d.context=W,d.props=$,d.__P=e,d.__e=!1,ae=b.__r,Lt=0,P)d.state=d.__s,d.__d=!1,ae&&ae(t),f=d.render(d.props,d.state,d.context),Ce.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,ae&&ae(t),f=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++Lt<25);d.state=d.__s,d.getChildContext!=null&&(s=E(E({},s),d.getChildContext())),P&&!m&&d.getSnapshotBeforeUpdate!=null&&(x=d.getSnapshotBeforeUpdate(p,g)),ye=f!=null&&f.type===Z&&f.key==null?Xt(f.props.children):f,c=Vt(e,Re(ye)?ye:[ye],t,n,s,r,i,o,c,u,l),d.base=t.__e,t.__u&=-161,d.__h.length&&o.push(d),G&&(d.__E=d.__=null)}catch(X){if(o.length=h,t.__v=null,u||i!=null){if(X.then){for(t.__u|=u?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;i!=null&&(i[i.indexOf(c)]=null),t.__e=c}else if(i!=null)for(ze=i.length;ze--;)Ye(i[ze])}else t.__e=n.__e;t.__k==null&&(t.__k=n.__k||[]),X.then||zt(t),b.__e(X,t,n)}}else i==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):c=t.__e=Ks(n.__e,t,n,s,r,i,o,u,l);return(f=b.diffed)&&f(t),128&t.__u?void 0:c}function zt(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(zt))}function Jt(e,t,n){for(var s=0;s<n.length;s++)tt(n[s],n[++s],n[++s]);b.__c&&b.__c(t,e),e.some(function(r){try{e=r.__h,r.__h=[],e.some(function(i){i.call(r)})}catch(i){b.__e(i,r.__v)}})}function Xt(e){return typeof e!="object"||e==null||e.__b>0?e:Re(e)?e.map(Xt):e.constructor!==void 0?null:E({},e)}function Ks(e,t,n,s,r,i,o,c,u){var l,f,h,d,m,p,g,x=n.props||Se,G=t.props,$=t.type;if($=="svg"?r="http://www.w3.org/2000/svg":$=="math"?r="http://www.w3.org/1998/Math/MathML":r||(r="http://www.w3.org/1999/xhtml"),i!=null){for(l=0;l<i.length;l++)if((m=i[l])&&"setAttribute"in m==!!$&&($?m.localName==$:m.nodeType==3)){e=m,i[l]=null;break}}if(e==null){if($==null)return document.createTextNode(G);e=document.createElementNS(r,$,G.is&&G),c&&(b.__m&&b.__m(t,i),c=!1),i=null}if($==null)x===G||c&&e.data==G||(e.data=G);else{if(i=$=="textarea"&&G.defaultValue!=null?null:i&&Ae.call(e.childNodes),!c&&i!=null)for(x={},l=0;l<e.attributes.length;l++)x[(m=e.attributes[l]).name]=m.value;for(l in x)m=x[l],l=="dangerouslySetInnerHTML"?h=m:l=="children"||l in G||l=="value"&&"defaultValue"in G||l=="checked"&&"defaultChecked"in G||we(e,l,null,m,r);for(l in G)m=G[l],l=="children"?d=m:l=="dangerouslySetInnerHTML"?f=m:l=="value"?p=m:l=="checked"?g=m:c&&typeof m!="function"||x[l]===m||we(e,l,m,x[l],r);if(f)c||h&&(f.__html==h.__html||f.__html==e.innerHTML)||(e.innerHTML=f.__html),t.__k=[];else if(h&&(e.innerHTML=""),Vt(t.type=="template"?e.content:e,Re(d)?d:[d],t,n,s,$=="foreignObject"?"http://www.w3.org/1999/xhtml":r,i,o,i?i[0]:n.__k&&V(n,0),c,u),i!=null)for(l=i.length;l--;)Ye(i[l]);c&&$!="textarea"||(l="value",$=="progress"&&p==null?e.removeAttribute("value"):p!=null&&(p!==e[l]||$=="progress"&&!p||$=="option"&&p!=x[l])&&we(e,l,p,x[l],r),l="checked",g!=null&&g!=e[l]&&we(e,l,g,x[l],r))}return e}function tt(e,t,n){try{if(typeof e=="function"){var s=typeof e.__u=="function";s&&e.__u(),s&&t==null||(e.__u=e(t))}else e.current=t}catch(r){b.__e(r,n)}}function Qt(e,t,n){var s,r;if(b.unmount&&b.unmount(e),(s=e.ref)&&(s.current&&s.current!=e.__e||tt(s,null,t)),(s=e.__c)!=null){if(s.componentWillUnmount)try{s.componentWillUnmount()}catch(i){b.__e(i,t)}s.base=s.__P=s.__n=null}if(s=e.__k)for(r=0;r<s.length;r++)s[r]&&Qt(s[r],t,n||typeof e.type!="function");n||Ye(e.__e),e.__c=e.__=e.__e=void 0}function zs(e,t,n){return this.constructor(e,n)}function nt(e,t,n){var s,r,i,o;t==document&&(t=document.documentElement),b.__&&b.__(e,t),r=(s=typeof n=="function")?null:n&&n.__k||t.__k,i=[],o=[],et(t,e=(!s&&n||t).__k=Q(Z,null,[e]),r||Se,Se,t.namespaceURI,!s&&n?[n]:r?null:t.firstChild?Ae.call(t.childNodes):null,i,!s&&n?n:r?r.__e:t.firstChild,s,o),Jt(i,e,o),e.props.children=null}Ae=Ce.slice,b={__e:function(e,t,n,s){for(var r,i,o;t=t.__;)if((r=t.__c)&&!r.__)try{if((i=r.constructor)&&i.getDerivedStateFromError!=null&&(r.setState(i.getDerivedStateFromError(e)),o=r.__d),r.componentDidCatch!=null&&(r.componentDidCatch(e,s||{}),o=r.__d),o)return r.__E=r}catch(c){e=c}throw e}},Bt=0,Bs=function(e){return e!=null&&e.constructor===void 0},Te.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=E({},this.state),typeof e=="function"&&(e=e(E({},n),this.props)),e&&E(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),Ht(this))},Te.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Ht(this))},Te.prototype.render=Z,O=[],Ot=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,qt=function(e,t){return e.__v.__b-t.__v.__b},De.__r=0,Je=Math.random().toString(8),Ge="__d"+Je,le="__a"+Je,Ft=/(PointerCapture)$|Capture$/i,Ze=0,Xe=jt(!1),Qe=jt(!0),Os=0;function Js(e){return{id:e,lane:"work",bucket:"done",repo:"",brief:"",attachments:[],messageAttachments:[],verb:"unknown",log:[],inbox:[],sort:0}}var Zt=new WeakMap;function st(e,t){let n=e.dispatches||[],s=Zt.get(n);return s||Zt.set(n,s=new Map(n.map(r=>[r.id,r]))),{...t,catches:(t.catches||[]).map(r=>s.get(r)??Js(r))}}function L(e){if(!e)return"dim";let t=e.state||"open";return t==="open"&&e.merge?"pr-"+e.merge:t==="open"&&e.tone&&e.tone!=="ok"?e.tone:"pr-"+t}var ce=["deck","dispatches","traps","prs","reports","notices"];function nn(e){let t=String(e||"").replace(/^#/,"");return ce.includes(t)?t:"deck"}var rt=e=>`#decision/${encodeURIComponent(e)}`;function ot(e){let t=/^#?decision\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var it=(e,t,n)=>`/attachment/dispatch/${encodeURIComponent(e)}/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,sn=(e,t)=>`/attachment/trap/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,rn=e=>/\\.(png|jpe?g|gif|webp)$/i.test(e),at=(e,t)=>`/decision/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function lt(e,t){let n=new Map(t.map(r=>[r.key,r])),s=[];for(let r of e)if(r.kind==="decision"){let i=n.get(r.key);if(!i)continue;s.push({kind:"decision",key:i.key,title:i.title,detail:i.detail,options:i.options,attachments:i.attachments,...i.dispatch?{dispatch:i.dispatch,lane:i.lane??"work"}:{},...i.repo?{repo:i.repo}:{},at:i.askedAt})}else r.kind==="question"&&s.push({kind:"question",key:r.key,verb:r.verb,note:r.note||r.verb,dispatch:r.id,lane:r.lane,...r.repo?{repo:r.repo}:{},at:r.at??""});return s.sort((r,i)=>i.at.localeCompare(r.at)||r.key.localeCompare(i.key))}function on(e){let t=(e.text??"").split(`\n`).map(n=>n.trim()).find(Boolean)??"";return[e.option,t&&(t.length>80?t.slice(0,79)+"\\u2026":t),e.files?`${e.files} file${e.files===1?"":"s"}`:""].filter(Boolean).join(" \\xB7 ")}function an(e,t){return(e.reports||[]).find(n=>n.key===`report:${t.lane}:${t.id}`)}function de(e){return e.author==="helm"?"":e.trap?e.trap:e.author==="headless"?e.dispatch?e.dispatch.slice(0,8):"":e.author}var Yt=(e,t)=>+!!e.acked-+!!t.acked||t.filedAt.localeCompare(e.filedAt),C=e=>`/report/${encodeURIComponent(e)}`;function ln(e){let t=/^#?report\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}function cn(e){let t=/^\\/report\\/([^/?#]+)\\/?$/.exec(e);if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var dn=e=>`/report/${encodeURIComponent(e)}/md`,ct=(e,t)=>`/report/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function en(e,t,n){return!!e&&n-Date.parse(e)>t}function tn(e,t){if(t.lane&&e.lane!==t.lane||t.repo&&e.repo!==t.repo||t.verb&&e.verb!==t.verb)return!1;if(t.q){let n=t.q.toLowerCase();if(!(e.id+" "+(e.note||"")+" "+(e.brief||"")+" "+(e.repo||"")+" "+(e.for||"")).toLowerCase().includes(n))return!1}return!0}function Y(e,t){if(!t)return null;if(t.type==="helm")return e.helms.find(s=>s.grounds===t.key)||null;if(t.type==="dispatch")return e.dispatches.find(s=>s.lane+":"+s.id===t.key)||null;if(t.type==="pr")return(e.prs||[]).find(s=>s.key===t.key)||null;if(t.type==="settings")return{attentionKinds:e.attentionKinds||[],attentionError:e.attentionError};let n=e.traps.find(s=>s.trapId===t.key);return n?st(e,n):null}function pn(e,t,n){let s=t.st,r=String(s.q||"").toLowerCase(),i=(...p)=>!r||p.join(" ").toLowerCase().includes(r),o=p=>({x:p,stale:en(p.heartbeatAt,18e5,n)}),c=Y(e,t.modal),u=(p,g)=>!!p&&n-Date.parse(p)<=g,l=p=>Math.max(0,...(p.notices||[]).filter(g=>g.kind==="trap-stowed"||g.kind==="trap-ghosted").map(g=>Date.parse(g.at)||0)),f=p=>p.live||!!p.starting||!!p.requested,h=[...e.traps||[]].sort((p,g)=>Number(f(g))-Number(f(p))||Number(g.live)-Number(p.live)||(p.live?(Date.parse(p.signedOnAt||"")||0)-(Date.parse(g.signedOnAt||"")||0):l(g)-l(p))||(p.name??p.trapId).localeCompare(g.name??g.trapId)),d=h.filter(p=>(f(p)||(p.notices||[]).some(g=>(g.kind==="trap-stowed"||g.kind==="trap-ghosted")&&u(g.at,36e5)))&&i(p.name,p.trapId,p.repo,p.worktree)),m=({ageSecs:p,...g})=>g;return{chips:{daemon:e.daemon,daemonStale:!!e.daemon&&en(e.daemon.heartbeat,9e4,n),helms:e.helms.map(o)},deck:{view:s.view,decisions:lt(e.attention||[],e.decisions||[]).filter(p=>p.kind==="decision"?i(p.kind,p.repo,p.title,p.dispatch,p.detail):i(p.kind,p.repo,p.note,p.dispatch)),prAttention:(e.attention||[]).filter(p=>p.kind&&p.kind.startsWith("pr:")).map(m),landed:(e.landed||[]).filter(p=>u(p.at,864e5)&&i(p.repo,p.note,p.id)).sort((p,g)=>Date.parse(g.at)-Date.parse(p.at)).slice(0,8),reports:(e.reports||[]).filter(p=>i(p.title,p.author,p.dispatch,p.repo)).sort(Yt),inflight:e.dispatches.filter(p=>p.bucket!=="done"&&tn(p,{...s,lane:"",repo:"",verb:""})),traps:d.map(p=>o(st(e,p))),stacks:(e.stacks||[]).filter(p=>p.open&&i(p.repo,p.numbers.join(" "))),prs:(e.prs||[]).filter(p=>p.state==="OPEN"),error:e.attentionError},dispatches:{view:s.view,chain:s.chain,list:e.dispatches.filter(p=>tn(p,s))},traps:{view:s.view,list:h.filter(p=>(!s.repo||p.repo===s.repo)&&i(p.name,p.trapId,p.repo,p.worktree,p.harness)).map(p=>o(st(e,p)))},prs:{view:s.view,stacks:(e.stacks||[]).filter(p=>!s.repo||p.repo===s.repo),prs:(e.prs||[]).filter(p=>(!s.repo||p.repo===s.repo)&&i(p.number,p.title,p.url,p.state,p.baseRefName,p.headRefName)),watches:(e.watches||[]).filter(p=>!String(p.key).startsWith("pr:"))},reports:{view:s.view,list:(e.reports||[]).filter(p=>(!s.repo||p.repo===s.repo)&&i(p.title,p.author,p.dispatch,p.repo)).sort(Yt)},notices:{list:(e.notices||[]).filter(p=>(!s.repo||!p.repo||p.repo===s.repo)&&(!s.noticeKind||p.kind===s.noticeKind)&&i(p.kind,p.text,p.repo))},foot:{version:e.version,repoUrl:e.repoUrl},modal:{modal:t.modal,item:c&&o(c),prefs:t.modal&&t.modal.type==="settings"?{view:s.view,lobs:s.lobs}:void 0}}}function un(e,t){let n=(e.prs||[]).find(c=>c.key===t);if(!n)return null;let s=(e.stacks||[]).find(c=>c.id===n.stackId),r=new Map((e.dispatches||[]).map(c=>[c.id,c])),i=(n.dispatchIds||[]).map(c=>{let u=r.get(c);return u?{id:c,verb:u.verb,modalKey:u.lane+":"+u.id}:{id:c,culled:!0}}),o=n.watch;return{pr:n,stack:s?{numbers:s.numbers,titles:s.numbers.map(c=>(e.prs||[]).find(u=>u.stackId===s.id&&u.number===c)?.title||""),position:n.position+1,size:s.numbers.length,floor:s.floor,nextNumber:s.nextNumber,nextMergeable:!!n.nextMergeable,blockedBy:n.blockedBy}:null,chain:i,watch:o?{key:o.key,owner:o.owner||"",lastCheckedAt:o.lastCheckedAt||null,lastError:o.lastError||null,cursor:o.cursor}:null}}function fn(e){return e?{text:e.lastError?"failing":"watching",at:e.lastCheckedAt||null}:{text:"no watch",at:null}}function mn(){let e={view:"table",lane:"",repo:"",verb:"",q:"",lobs:!0,chain:!1,noticeKind:""};try{Object.assign(e,JSON.parse(localStorage.getItem("spyglass")||"{}"))}catch{}return e.view!=="table"&&e.view!=="cards"&&(e.view="table"),e.lobs=e.lobs!==!1,e}function hn(e){try{localStorage.setItem("spyglass",JSON.stringify(e))}catch{}}function gn(){try{return JSON.parse(localStorage.getItem("spyglass-lob-hidden")||"{}")||{}}catch{return{}}}function vn(e){try{localStorage.setItem("spyglass-lob-hidden",JSON.stringify(e))}catch{}}var pe,_n=new Set,_=()=>pe;function dt(e){pe=e}function T(e){pe={...pe,...e};for(let t of _n)t(pe)}var pt=e=>{_n.add(e)};function ut(e){let{modal:t,drafts:n}=_(),s=new Set(lt(e.attention||[],e.decisions||[]).map(i=>i.key)),r=Object.fromEntries(Object.entries(n).filter(([i])=>s.has(i)));T({snapshot:e,stale:!1,modal:t&&Y(e,t)?t:null,...Object.keys(r).length!==Object.keys(n).length?{drafts:r}:{}})}var $n=()=>({text:"",files:[]});function A(e,t){let n=_().drafts;T({drafts:{...n,[e]:{...n[e]??$n(),...t}}})}function bn(e,t){let n=_().drafts[e]?.option;A(e,{option:n===t?void 0:t,error:void 0})}var Xs=e=>new Promise((t,n)=>{let s=new FileReader;s.onload=()=>t(String(s.result).replace(/^data:[^,]*,/,"")),s.onerror=()=>n(s.error),s.readAsDataURL(e)});async function ft(e,t){let n=_().snapshot?.answerLimits,s=[...t??[]],r=_().drafts[e]?.files??[],i=[],o=[];for(let c of s){let u=(/\\.[^.]+$/.exec(c.name)?.[0]??"").toLowerCase();if(n&&!n.extensions.includes(u))i.push(`${c.name}: type not accepted`);else if(n&&c.size>n.maxBytes)i.push(`${c.name}: larger than ${n.maxBytes} bytes`);else if(n&&r.length+o.length>=n.maxFiles)i.push(`${c.name}: at most ${n.maxFiles} files`);else try{o.push({name:c.name,bytes:c.size,data:await Xs(c)})}catch{i.push(`${c.name}: could not be read`)}}A(e,{files:[..._().drafts[e]?.files??[],...o],error:i.length?i.join("; "):void 0})}var Qs={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};async function kn(e,t){let n=[...t.clipboardData?.items??[]],s=new Date().toISOString().replace(/[:.]/g,"-").replace(/-\\d{3}Z$/,"Z"),r=n.filter(i=>i.kind==="file"&&i.type.startsWith("image/")).map(i=>i.getAsFile()).filter(i=>i!==null).map((i,o,c)=>{let u=`pasted-${s}${c.length>1?`-${o+1}`:""}${Qs[i.type]??".png"}`;return new File([i],u,{type:i.type})});r.length&&await ft(e,r)}function yn(e,t){let n=(_().drafts[e]?.files??[]).filter((s,r)=>r!==t);A(e,{files:n})}async function wn(e){let t=_().snapshot?.focusToken,n=_().drafts[e]??$n();if(!(n.sending||n.sent)){if(!n.option&&!n.text.trim()&&n.files.length===0){A(e,{error:"Choose an option, write an answer, or attach a file."});return}if(!t){A(e,{error:"This page has no answer token; reload it."});return}A(e,{sending:!0,error:void 0});try{let s=await fetch("/requests",{method:"POST",headers:{"content-type":"application/json","x-lobstah-token":t},body:JSON.stringify({kind:"decision-answer",payload:{key:e,...n.option?{option:n.option}:{},...n.text.trim()?{text:n.text}:{},files:n.files.map(i=>({name:i.name,data:i.data}))}})}),r=await s.json();if(!s.ok||!r.ok){A(e,{sending:!1,error:r.reason??`The answer was refused (${s.status}).`});return}A(e,{sending:!1,sent:on({option:n.option,text:n.text,files:n.files.length})})}catch{A(e,{sending:!1,error:"The answer could not be sent."})}}}var Gn=()=>T({stale:!0}),xn=(e,t)=>T({lightbox:{src:e,name:t}}),ee=()=>T({lightbox:null});function M(e,t){let{snapshot:n}=_(),s={type:e,key:t};T({modal:!n||Y(n,s)?s:null})}function te(){T({modal:null})}async function Tn(e){let t=_().snapshot?.focusToken;if(t)try{let s=await(await fetch(`/api/focus/${encodeURIComponent(e)}`,{method:"POST",headers:{"x-lobstah-focus-token":t}})).json();T({focusResults:{..._().focusResults,[e]:s.message??s.reason??"Window focus failed."}})}catch{T({focusResults:{..._().focusResults,[e]:"Window focus failed."}})}}async function Sn(e,t){let n=_().snapshot?.focusToken;if(!n)return"The glass has no page token yet.";try{let r=await(await fetch("/requests",{method:"POST",headers:{"content-type":"application/json","x-lobstah-token":n},body:JSON.stringify({kind:"trap-request",payload:{repo:e,harness:t}})})).json();if(!r.ok)return r.reason??"The request was refused."}catch{return"The request could not be sent."}try{ut(await(await fetch("/data")).json())}catch{}}function N(e){let t={..._().prefs,...e};hn(t),T({prefs:t})}function Cn(e){e!=="table"&&e!=="cards"||N({view:e})}var Dn=e=>N({lobs:e==="on"});function An(e,t){let n={..._().lobHidden,[e]:t};vn(n),setTimeout(()=>T({lobHidden:n}),0)}async function Rn(e){try{return await navigator.clipboard.writeText(e),!0}catch{return!1}}var In=function(e,t,n,s){var r;t[0]=0;for(var i=1;i<t.length;i++){var o=t[i++],c=t[i]?(t[0]|=o?1:2,n[t[i++]]):t[++i];o===3?s[0]=c:o===4?s[1]=Object.assign(s[1]||{},c):o===5?(s[1]=s[1]||{})[t[++i]]=c:o===6?s[1][t[++i]]+=c+"":o?(r=e.apply(c,In(e,c,n,["",null])),s.push(r),c[0]?t[0]|=2:(t[i-2]=0,t[i]=r)):s.push(c)}return s},Pn=new Map;function Mn(e){var t=Pn.get(this);return t||(t=new Map,Pn.set(this,t)),(t=In(this,t.get(e)||(t.set(e,t=(function(n){for(var s,r,i=1,o="",c="",u=[0],l=function(d){i===1&&(d||(o=o.replace(/^\\s*\\n\\s*|\\s*\\n\\s*$/g,"")))?u.push(0,d,o):i===3&&(d||o)?(u.push(3,d,o),i=2):i===2&&o==="..."&&d?u.push(4,d,0):i===2&&o&&!d?u.push(5,0,!0,o):i>=5&&((o||!d&&i===5)&&(u.push(i,0,o,r),i=6),d&&(u.push(i,d,0,r),i=6)),o=""},f=0;f<n.length;f++){f&&(i===1&&l(),l(f));for(var h=0;h<n[f].length;h++)s=n[f][h],i===1?s==="<"?(l(),u=[u],i=3):o+=s:i===4?o==="--"&&s===">"?(i=1,o=""):o=s+o[0]:c?s===c?c="":o+=s:s===\'"\'||s==="\'"?c=s:s===">"?(l(),i=1):i&&(s==="="?(i=5,r=o,o=""):s==="/"&&(i<5||n[f][h+1]===">")?(l(),i===3&&(u=u[0]),i=u,(u=u[0]).push(2,0,i),i=0):s===" "||s===" "||s===`\n`||s==="\\r"?(l(),i=2):o+=s),i===3&&o==="!--"&&(i=4,u=u[0])}return l(),u})(e)),t),arguments,[])).length>1?t:t[0]}var En=e=>Array.isArray(e)?e.map(En):e===""?null:e,Zs=(e,t,...n)=>Q(e,t,...n.map(En)),a=Mn.bind(Zs);var Ie,k,mt,Ln,ht=0,Fn=[],y=b,Nn=y.__b,Hn=y.__r,Un=y.diffed,jn=y.__c,Bn=y.unmount,On=y.__;function Wn(e,t){y.__h&&y.__h(k,e,ht||t),ht=0;var n=k.__H||(k.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function ne(e){return ht=1,Ys(Kn,e)}function Ys(e,t,n){var s=Wn(Ie++,2);if(s.t=e,!s.__c&&(s.__=[n?n(t):Kn(void 0,t),function(c){var u=s.__N?s.__N[0]:s.__[0],l=s.t(u,c);u!==l&&(s.__N=[l,s.__[1]],s.__c.setState({}))}],s.__c=k,!k.__f)){var r=function(c,u,l){if(!s.__c.__H)return!0;var f=!1,h=s.__c.props!==c;if(s.__c.__H.__.some(function(m){if(m.__N){f=!0;var p=m.__[0];m.__=m.__N,m.__N=void 0,p!==m.__[0]&&(h=!0)}}),i){var d=i.call(this,c,u,l);return f?d||h:d}return!f||h};k.__f=!0;var i=k.shouldComponentUpdate,o=k.componentWillUpdate;k.componentWillUpdate=function(c,u,l){if(this.__e){var f=i;i=void 0,r(c,u,l),i=f}o&&o.call(this,c,u,l)},k.shouldComponentUpdate=r}return s.__N||s.__}function Vn(e,t){var n=Wn(Ie++,7);return nr(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function er(){for(var e;e=Fn.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(Pe),t.__h.some(gt),t.__h=[]}catch(n){t.__h=[],y.__e(n,e.__v)}}}y.__b=function(e){k=null,Nn&&Nn(e)},y.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),On&&On(e,t)},y.__r=function(e){Hn&&Hn(e),Ie=0;var t=(k=e.__c).__H;t&&(mt===k?(t.__h=[],k.__h=[],t.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.some(Pe),t.__h.some(gt),t.__h=[],Ie=0)),mt=k},y.diffed=function(e){Un&&Un(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Fn.push(t)!==1&&Ln===y.requestAnimationFrame||((Ln=y.requestAnimationFrame)||tr)(er)),t.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),mt=k=null},y.__c=function(e,t){t.some(function(n){try{n.__h.some(Pe),n.__h=n.__h.filter(function(s){return!s.__||gt(s)})}catch(s){t.some(function(r){r.__h&&(r.__h=[])}),t=[],y.__e(s,n.__v)}}),jn&&jn(e,t)},y.unmount=function(e){Bn&&Bn(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(s){try{Pe(s)}catch(r){t=r}}),n.__H=void 0,t&&y.__e(t,n.__v))};var qn=typeof requestAnimationFrame=="function";function tr(e){var t,n=function(){clearTimeout(s),qn&&cancelAnimationFrame(t),setTimeout(e)},s=setTimeout(n,35);qn&&(t=requestAnimationFrame(n))}function Pe(e){var t=k,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),k=t}function gt(e){var t=k;e.__c=e.__(),k=t}function nr(e,t){return!e||e.length!==t.length||t.some(function(n,s){return n!==e[s]})}function Kn(e,t){return typeof t=="function"?t(e):t}var K=e=>{if(!e)return"";let t=Math.max(0,(Date.now()-Date.parse(e))/1e3);return t<90?Math.round(t)+"s":t<5400?Math.round(t/60)+"m":t<172800?(t/3600).toFixed(1)+"h":Math.round(t/86400)+"d"},v=e=>a`<span data-age=${e??""}>${K(e)}</span>`,Ee=e=>e.activity&&a`<div class=${"activity"+(e.activity.stale?" stale":"")} title=${e.activity.stale?"no activity past the wedge threshold":e.activity.kind}>${e.activity.stale?"stale \\xB7 ":""}${e.activity.summary} \xB7 ${v(e.activity.at)} ago</div>`,sr=e=>e&&/^https?:\\/\\//i.test(e)?e:void 0,Le=e=>{let t=e.waiting;if(!t)return;let n=sr(t.link),s=n;try{n&&(s=new URL(n).host+new URL(n).pathname.replace(/\\/$/,""))}catch{s=n}return a`<div class="waiting">${e.verb}: waiting on ${t.on} \xB7 ${v(t.since)}${n&&[" \\xB7 ",a`<a href=${n} target="_blank" rel="noopener noreferrer" onClick=${D}>${s}</a>`]}</div>`},rr=12,zn=e=>e!==void 0&&e.length>rr,H=e=>zn(e)?e:void 0,U=e=>zn(e)?" long":"",w=(e,t)=>()=>M(e,t),D=e=>e.stopPropagation(),or=e=>e.sessionId?(e.harness==="codex"?"codex resume ":"claude --resume ")+e.sessionId:void 0;function z(e){if(e.requested)return a`<span class="dim">Requested \u2014 no window yet</span>`;if(e.starting)return a`<span class="dim">${e.starting.failedAt?"Did not start":"Starting \\u2014 no window yet"}</span>`;if(!e.live){let s=or(e);return s?a`<span class="dim">Resume: <code onClick=${D}>${s}</code></span>`:a`<span class="dim">Resume command unavailable</span>`}let t=_();return!t.snapshot?.focusSupported&&!e.link?a`<span class="dim">Window focus is not supported here</span>`:a`<span class="winaction"><button class="btn open" title="open this trap\'s window" onClick=${s=>{D(s),Tn(e.trapId)}}>\u2197 open</button>${e.link&&[" ",a`<a href=${e.link} onClick=${D}>Session link</a>`]}${t.focusResults[e.trapId]&&[" ",a`<span class="dim">${t.focusResults[e.trapId]}</span>`]}</span>`}function R(e,t,n){return t.length?a`<div class="wrap"><table><tbody><tr>${e.map(s=>a`<th>${s}</th>`)}</tr>${t}</tbody></table></div>`:a`<div class="empty">${n}</div>`}function ir({text:e}){let[t,n]=ne(null),s=r=>async()=>{await Rn(e)&&(n(r),setTimeout(()=>n(null),1e3))};return a`<div class="cmd"><code class=${t==="code"?"copied":void 0} title="click to copy" onClick=${s("code")}>${e}</code><button title="copy" onClick=${s("button")}>${t==="button"?"\\u2713":"\\u29C9"}</button></div>`}var S=(e,t)=>a`<${ir} key=${t} text=${e} />`,ue=(e,t,n="thumb")=>a`<button\n type="button"\n class=${n}\n title=${"view "+t}\n onClick=${s=>{D(s),xn(e,t)}}\n >\n <img src=${e} alt=${t} loading="lazy" />\n </button>`,se=(e,t)=>e.map(n=>[a`<div class="sub">${n.name} \xB7 ${n.type} \xB7 ${n.bytes} bytes</div>`,t&&rn(n.name)&&ue(t(n.name),n.name),S(n.path)]),Jn=/\\bwt:([a-z0-9][a-z0-9-]*)/g,vt=e=>_().snapshot?.trapNames?.[e],j=e=>e.replace(Jn,(t,n,s)=>{let r=vt(n);return r&&!Xn(e,s,t.length,r)?r:t}),Xn=(e,t,n,s)=>e.slice(Math.max(0,t-s.length-2),t)===`${s} (`&&e[t+n]===")";function Ne(e){let t="wt:"+e,n=vt(e)??t;return _().snapshot?.traps.some(r=>r.trapId===e)?a`<a class="trapname" href="#traps" title=${t} onClick=${r=>{r.preventDefault(),D(r),M("trap",e)}}>${n}</a>`:a`<span class="trapname" title=${t}>${n}</span>`}var Me=e=>{let t=/^wt:([a-z0-9][a-z0-9-]*)$/.exec(e);return t?Ne(t[1]):e};function B(e,t=1/0){let n=[],s=0;for(let c of e.matchAll(Jn)){c.index>s&&n.push({text:e.slice(s,c.index)});let u=vt(c[1]);n.push(u&&Xn(e,c.index,c[0].length,u)?{text:c[0]}:{text:u??c[0],trapId:c[1]}),s=c.index+c[0].length}s<e.length&&n.push({text:e.slice(s)});let r=n.reduce((c,u)=>c+u.text.length,0),i=r>t?t-1:1/0,o=[];for(let c of n){if(i<=0)break;c.text.length<=i?o.push(c.trapId?Ne(c.trapId):c.text):o.push(c.text.slice(0,i)),i-=c.text.length}return r>t&&o.push("\\u2026"),o}var _t=e=>e.log.flatMap((t,n)=>[n?`\n`:"",t.at+" "+t.verb,...t.note?[" ",...B(t.note)]:[]]);function Qn(e){let t=[e.elapsed&&`elapsed: ${e.elapsed}`,e.attempt&&`attempt: ${e.attempt}`,e.branch&&`branch: ${e.branch}`,e.lastCommit&&`last commit: ${e.lastCommit}`,e.aheadTrunk&&`commits: ${e.aheadTrunk}`,e.draftPr&&`draft PR: ${e.draftPr}`,e.updated&&`updated: ${e.updated}`].filter(Boolean).join(`\n`);return a`${e.waiting&&[a`<div class="sec">waiting</div>`,Le(e)]}${e.activity&&[a`<div class="sec">activity</div>`,Ee(e)]}${t&&[a`<div class="sec">progress</div>`,a`<pre>${t}</pre>`]}<div class="sec">brief</div><pre>${e.brief}</pre>${e.attachments.length>0&&[a`<div class="sec">attachments (${e.attachments.length})</div>`,se(e.attachments,n=>it(e.lane,e.id,n))]}${e.messageAttachments.length>0&&[a`<div class="sec">message attachments (${e.messageAttachments.length})</div>`,se(e.messageAttachments,n=>it(e.lane,e.id,n))]}${e.followUp&&[a`<div class="sec">forks</div>`,a`<pre>${e.followUp}</pre>`]}<div class="sec">log</div><div class="loglines">${e.log.length?_t(e):"no entries yet"}</div>${e.inbox.length>0&&[a`<div class="sec">inbox</div>`,a`<div class="loglines">${e.inbox.join(`\n---\n`)}</div>`]}${e.awaitingReply&&[a`<div class="sec">awaiting reply</div>`,a`<div>${e.awaitingReply.line} \xB7 from ${e.awaitingReply.from} \xB7 ${v(e.awaitingReply.sentAt)} ago</div>`]}${e.evidence&&[a`<div class="sec">evidence</div>`,a`<div class="loglines">${JSON.stringify(e.evidence)}</div>`]}`}function fe(e){return e.for?[Me(e.for),e.evidence&&e.evidence.deliveredTo?[" ",a`<span class="ok">\u2713delivered</span>`]:[" ",a`<span class="warn">waiting</span>`]]:e.claimedBy?Me(e.claimedBy):""}function re(e){let t=e.evidence&&(e.evidence.prUrl||e.evidence.pr&&e.evidence.pr.url);if(!t)return"";let n=e.prBadge;return[a`<a href=${t} target="_blank" rel="noopener" onClick=${D}>PR</a>`,n&&[" ",a`<span class=${"badge "+L(n)} title=${"observed "+n.observedAt}>${n.text}</span>`],e.prGate&&[" ",a`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]]}var ar={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch"},$t={"pr:review":"bad","pr:checks":"bad","pr:conflict":"pr-conflicts","pr:ready":"ok","pr:draft":"dim",watch:"warn"},Zn=e=>ar[e]||"";var He=e=>a`<a href=${e.url} target="_blank" rel="noopener" onClick=${D}>#${e.number}</a>`,Ue=e=>a`<span class="prname" title=${e.title||void 0}><b>#${e.number}</b>${e.title&&[" ",e.title]}</span>`;function oe(e,t,n){return e.flatMap((s,r)=>{let i=t.get(s)||void 0,o=s===n?a`<b title=${i}>#${s}</b>`:a`<span title=${i}>#${s}</span>`;return r?[" \\u2192 ",o]:[o]})}function me(e){let t=e.checks;return t.passed+"/"+t.total+" passed"+(t.failed?" \\xB7 "+t.failed+" failed":"")+(t.pending?" \\xB7 "+t.pending+" pending":"")}function je(e){let t=e.review||{};return(e.reviewDecision||"")+(t.unresolvedThreads?" \\xB7 "+t.unresolvedThreads+" unresolved":"")+(t.changesRequested?" \\xB7 changes requested":"")}function he(e){return[e.mergeStateStatus,e.nextMergeable?[" \\xB7 ",a`<span class="ok">next mergeable</span>`]:e.blockedBy?" \\xB7 blocked by #"+e.blockedBy:""]}function bt(e){let t=fn(e);return e?[t.text," \\xB7 ",t.at?[v(t.at)," ago"]:"never checked"]:a`<span class="dim">${t.text}</span>`}function ge(e){if(e.requested)return{stale:!1,listen:[a`<span class="dot"></span>`,a`<span class="dim">requested</span>`],hb:a`<span class="dim">\u2014</span>`};if(e.starting)return{stale:!1,listen:e.starting.failedAt?[a`<span class="dot bad"></span>`,a`<span class="bad">start failed</span>`]:[a`<span class="dot warn"></span>`,"starting"],hb:a`<span class="dim">\u2014</span>`};if(!e.live)return{stale:!1,listen:[a`<span class="dot"></span>`,a`<span class="dim">signed off</span>`],hb:a`<span class="dim">\u2014</span>`};let t=Date.now()-Date.parse(e.heartbeatAt)>18e5,n=e.listening??(!!e.firstParkedAt&&!t);return{stale:t,listen:n?[a`<span class="dot ok"></span>`,"listening"]:[a`<span class="dot warn"></span>`,"not listening"],hb:a`<span class=${t?"bad":"ok"}>${t&&"stale "}${v(e.heartbeatAt)} ago</span>`}}function kt(e){if(e.requested)return{kind:"requested",helmOn:!!_().snapshot?.helmOn};if(e.starting)return e.starting.failedAt?{kind:"start failed",reason:e.starting.reason??"no session signed on in time"}:{kind:"starting",deadline:e.starting.deadline};if(!e.live)return{kind:"signed off"};let t=e.claimed?e.catches.find(n=>n.id===e.claimed&&n.bucket==="active"):void 0;return t?t.waiting||t.verb==="paused"?{kind:"parked",current:t}:{kind:"working",current:t}:{kind:"idle",listening:e.listening??(!!e.firstParkedAt&&Date.now()-Date.parse(e.heartbeatAt??"")<=18e5)}}function lr(e){let t=kt(e);return t.kind==="working"||t.kind==="idle"&&t.listening?"ok":t.kind==="start failed"?"bad":t.kind==="parked"||t.kind==="starting"?"warn":"dim"}var Yn=e=>e.waiting?`waiting on ${e.waiting.on}`:e.note||"waiting",es=e=>e.brief.split(/\\r?\\n/,1)[0]?.trim().slice(0,40)||"(no title)";function ve(e){let t=kt(e),n=a`<span class=${"dot trapdot "+lr(e)}></span>`;if(t.kind==="requested")return[n,a`<span class="dim">${ts(e,t.helmOn)}</span>`];if(t.kind==="starting")return[n,"starting \\xB7 waiting for its session to sign on"];if(t.kind==="start failed")return[n,a`<span class="bad">start failed</span>`," \\xB7 ",t.reason];if(t.kind==="signed off")return[n,a`<span class="dim">signed off</span>`];if(t.kind==="idle")return[n,"idle \\xB7 ",t.listening?"listening":"not listening"];let s=t.current;return t.kind==="parked"?[n,"parked \\xB7 ",Yn(s)]:[n,"working \\xB7 ",a`<a href="#dispatches" onClick=${i=>{i.preventDefault(),D(i),M("dispatch",`${s.lane}:${s.id}`)}}>${s.id.slice(0,8)}</a>`," \\xB7 ",es(s),s.activity&&[" \\xB7 ",s.activity.summary," ",v(s.activity.at)," ago"]]}var ts=(e,t)=>`requested \\xB7 ${e.repo??""} \\xB7 ${e.harness??""} \\xB7 ${t?"waiting for the helm":"waiting for a helm"}`;function J(e){let t=e.starting?.commands;return t?.length?a`<div class="startcmds" onClick=${D}><div class="dim">start it: run one in a terminal</div>${t.map(n=>S(n.command,n.harness))}</div>`:null}function Be(){let t=_().snapshot?.repoKeys??[],[n,s]=ne(!1),[r,i]=ne(""),[o,c]=ne("claude"),[u,l]=ne(null),f=r||t[0]||"",h=async d=>{d.preventDefault();let m=await Sn(f,o);l(m??null),m||s(!1)};return n?a`<form class="newtrap" onClick=${D} onSubmit=${h}>\n <label>repo <select name="repo" value=${f} onChange=${d=>i(d.target.value)}>${t.map(d=>a`<option value=${d}>${d}</option>`)}</select></label>\n <label>harness <select name="harness" value=${o} onChange=${d=>c(d.target.value)}><option value="claude">claude</option><option value="codex">codex</option></select></label>\n <button class="btn" type="submit" disabled=${!f}>Request</button>\n <button class="btn" type="button" onClick=${()=>s(!1)}>Cancel</button>\n ${u&&a`<span class="bad">${u}</span>`}\n </form>`:a`<span class="newtrap"><button class="btn" onClick=${d=>(D(d),s(!0),l(null))}>+ New trap</button></span>`}function Oe(e){let t=kt(e);if(t.kind==="requested")return ts(e,t.helmOn);if(t.kind==="starting")return`starting \\xB7 sign-on due by ${t.deadline}`;if(t.kind==="start failed")return`start failed \\xB7 ${t.reason}`;if(t.kind==="signed off")return"signed off";if(t.kind==="idle")return`idle \\xB7 ${t.listening?"listening":"not listening"}`;if(t.kind==="parked")return`parked \\xB7 ${Yn(t.current)}`;let n=t.current;return[`working \\xB7 ${n.id.slice(0,8)} \\xB7 ${es(n)}`,n.activity&&`${n.activity.summary} ${K(n.activity.at)} ago`].filter(Boolean).join(" \\xB7 ")}function yt(e){let t=e.messages.filter(n=>n.state==="pending").length;return e.messages.length?["\\u2709 "+e.messages.length,t>0&&[" ",a`<span class="warn">(${t} pending)</span>`]]:null}var cr=e=>()=>{window.open(C(e.key),"_blank","noopener")};function wt(e){let t=de(e);return{nodes:[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked?" \\xB7 acked":""],text:[t,`${K(e.filedAt)} ago`,e.acked?"acked":""].filter(Boolean).join(" \\xB7 ")}}function dr(e){let t=wt(e);return a`<a key=${e.key} class=${"card"+(e.acked?" acked":"")} href=${C(e.key)} target="_blank" rel="noopener"><div class="top"><b title=${e.title}>${e.title}</b></div><div class="meta" title=${t.text}>${t.nodes}</div></a>`}function pr(e){return a`<tr key=${e.key} class=${"rowhead"+(e.acked?" acked":"")} onClick=${cr(e)}><td class="grow"><a href=${C(e.key)} target="_blank" rel="noopener" onClick=${t=>t.stopPropagation()}>${e.title}</a></td><td>${de(e)}</td><td>${v(e.filedAt)}</td><td>${e.acked?"acked":""}</td></tr>`}function ns({inp:e}){return e.view==="cards"?e.list.length?a`<div class="cards">${e.list.map(dr)}</div>`:a`<div class="empty">no reports match</div>`:R(["title","from","filed","acked"],e.list.map(pr),"no reports match")}function os(e){let t=e.trim();return/^(https?:\\/\\/|mailto:|#)/i.test(t)?t:void 0}function is(e){let t=e.trim();return/^[^/\\\\:?#]+$/.test(t)&&t!=="."&&t!==".."?t:void 0}function ss(e,t,n,s){let r=0;for(let i=t;i<e.length;i++){if(e[i]==="\\\\"){i++;continue}if(e[i]===n)r++;else if(e[i]===s){if(r===0)return i;r--}}return-1}function rs(e,t){let n=ss(e,t+1,"[","]");if(n<0||e[n+1]!=="(")return;let s=ss(e,n+2,"(",")");if(s<0)return;let r=e.slice(n+2,s).trim().replace(/\\s+"[^"]*"$/,"").replace(/^<(.*)>$/,"$1");return{text:e.slice(t+1,n),target:r,end:s+1}}function q(e){let t=[],n="",s=()=>{n&&t.push({t:"text",v:n}),n=""};for(let r=0;r<e.length;){let i=e[r];if(i==="\\\\"&&r+1<e.length&&/[\\\\`*_{}[\\]()#+\\-.!|<>~]/.test(e[r+1])){n+=e[r+1],r+=2;continue}if(i==="`"){let o=/^`+/.exec(e.slice(r))[0],c=e.indexOf(o,r+o.length);if(c>0){s(),t.push({t:"code",v:e.slice(r+o.length,c).replace(/^ (.*) $/,"$1")}),r=c+o.length;continue}}if(i==="!"&&e[r+1]==="["){let o=rs(e,r+1);if(o){s(),t.push({t:"img",alt:o.text,src:o.target}),r=o.end;continue}}if(i==="["){let o=rs(e,r);if(o){s(),t.push({t:"a",href:o.target,c:q(o.text)}),r=o.end;continue}}if((i==="*"||i==="_")&&e[r+1]===i){let o=e.indexOf(i+i,r+2);if(o>r+2){s(),t.push({t:"b",c:q(e.slice(r+2,o))}),r=o+2;continue}}if(i==="*"||i==="_"&&(r===0||!/\\w/.test(e[r-1]))){let o=r+1;for(;(o=e.indexOf(i,o))>0&&(e[o+1]===i||i==="_"&&/\\w/.test(e[o+1]??""));)o+=2;if(o>r+1&&e[r+1]!==" "){s(),t.push({t:"i",c:q(e.slice(r+1,o))}),r=o+1;continue}}if(i===`\n`){/ {2,}$/.test(n)||n.endsWith("\\\\")?(n=n.replace(/( {2,}|\\\\)$/,""),s(),t.push({t:"br"})):n+=" ",r++;continue}n+=i,r++}return s(),t}var as=/^ {0,3}(`{3,}|~{3,})\\s*([^`\\s]*)/,ls=/^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/,cs=/^ {0,3}([-*_])(\\s*\\1){2,}\\s*$/,Tt=/^( {0,3})([-*+])\\s+(.*)$/,St=/^( {0,3})(\\d{1,9})[.)]\\s+(.*)$/,qe=/^ {0,3}>\\s?(.*)$/,ur=/^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;function Gt(e){let t=e.trim();t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&!t.endsWith("\\\\|")&&(t=t.slice(0,-1));let n=[],s="";for(let r=0;r<t.length;r++)t[r]==="\\\\"&&t[r+1]==="|"?(s+="|",r++):t[r]==="|"?(n.push(s.trim()),s=""):s+=t[r];return n.push(s.trim()),n}var xt=e=>as.test(e)||ls.test(e)||cs.test(e)||Tt.test(e)||St.test(e)||qe.test(e);function Fe(e){let t=e.replace(/\\r\\n?/g,`\n`).replace(/\\t/g," ").split(`\n`),n=[],s=0;for(;s<t.length;){let r=t[s];if(!r.trim()){s++;continue}let i=as.exec(r);if(i){let f=i[1],h=[];for(s++;s<t.length&&!new RegExp(`^ {0,3}${f[0]}{${f.length},}\\\\s*$`).test(t[s]);)h.push(t[s++]);s++,n.push({t:"code",lang:i[2]??"",v:h.join(`\n`)});continue}let o=ls.exec(r);if(o){n.push({t:"h",level:o[1].length,c:q(o[2])}),s++;continue}if(cs.test(r)){n.push({t:"hr"}),s++;continue}if(qe.test(r)){let f=[];for(;s<t.length&&t[s].trim()&&(qe.test(t[s])||!xt(t[s]));)f.push(qe.exec(t[s])?.[1]??t[s]),s++;n.push({t:"quote",c:Fe(f.join(`\n`))});continue}let c=Tt.exec(r),u=St.exec(r);if(c||u){let f=!c,h=f?St:Tt,d=[];for(;s<t.length;){let m=t[s],p=h.exec(m);if(p&&p[1].length<=3){d.push([p[3]]),s++;continue}if(!m.trim()){if(s+1<t.length&&/^ {2,}\\S/.test(t[s+1])){d.at(-1).push(""),s++;continue}break}if(/^ {2,}\\S/.test(m)){d.at(-1).push(m.replace(/^ {2,4}/,"")),s++;continue}if(xt(m))break;d.at(-1).push(m.trim()),s++}n.push({t:"list",ordered:f,start:f?Number(u[2]):1,items:d.map(m=>Fe(m.join(`\n`)))});continue}if(r.includes("|")&&s+1<t.length&&ur.test(t[s+1])&&t[s+1].includes("-")){let f=Gt(r),h=Gt(t[s+1]).map(m=>m.startsWith(":")&&m.endsWith(":")?"center":m.endsWith(":")?"right":m.startsWith(":")?"left":"");s+=2;let d=[];for(;s<t.length&&t[s].trim()&&t[s].includes("|");){let m=Gt(t[s++]);d.push(f.map((p,g)=>q(m[g]??"")))}n.push({t:"table",align:f.map((m,p)=>h[p]??""),head:f.map(q),rows:d});continue}let l=[];for(;s<t.length&&t[s].trim()&&!xt(t[s])&&!(l.length&&/^ {0,3}(=+|-+)\\s*$/.test(t[s]));)l.push(t[s++].replace(/^ +/,""));if(l.length===0){n.push({t:"p",c:q(r.trim())}),s++;continue}n.push({t:"p",c:q(l.join(`\n`))})}return n}function F(e,t){return t.map(n=>{switch(n.t){case"text":return n.v;case"code":return a`<code>${n.v}</code>`;case"b":return a`<strong>${F(e,n.c)}</strong>`;case"i":return a`<em>${F(e,n.c)}</em>`;case"br":return a`<br />`;case"a":{let s=os(n.href);return s?a`<a href=${s} target="_blank" rel="noopener noreferrer">${F(e,n.c)}</a>`:F(e,n.c)}case"img":{let s=is(n.src);return s?ue(e(s),n.alt||s,"mdimg"):a`<span class="dim">[image not shown: ${n.alt||n.src}]</span>`}}})}function We(e,t){return t.map(n=>{switch(n.t){case"h":{let s=F(e,n.c);return n.level===1?a`<h1>${s}</h1>`:n.level===2?a`<h2>${s}</h2>`:n.level===3?a`<h3>${s}</h3>`:a`<h4>${s}</h4>`}case"p":return a`<p>${F(e,n.c)}</p>`;case"code":return a`<pre class="mdcode"><code>${n.v}</code></pre>`;case"hr":return a`<hr />`;case"quote":return a`<blockquote>${We(e,n.c)}</blockquote>`;case"list":{let s=n.items.map(r=>a`<li>${We(e,r)}</li>`);return n.ordered?a`<ol start=${n.start}>${s}</ol>`:a`<ul>${s}</ul>`}case"table":return a`<div class="mdtable"><table><thead><tr>${n.head.map((s,r)=>a`<th style=${n.align[r]?"text-align:"+n.align[r]:void 0}>${F(e,s)}</th>`)}</tr></thead><tbody>${n.rows.map(s=>a`<tr>${s.map((r,i)=>a`<td style=${n.align[i]?"text-align:"+n.align[i]:void 0}>${F(e,r)}</td>`)}</tr>`)}</tbody></table></div>`}})}var _e=new Map;function ds(e){let t=_e.get(e);return t||(t=Fe(e),_e.set(e,t),_e.size>8&&_e.delete(_e.keys().next().value)),t}function fr({r:e,text:t}){let n=t?.text!==void 0?We(s=>ct(e.key,s),ds(t.text)):t?.error?a`<div class="bad">${t.error}</div>`:a`<div class="dim">loading\u2026</div>`;return a`<div class="mdpage" data-report=${e.key}>${n}</div>`}function ps({text:e,fileUrl:t}){return a`<div class="mdpage">${We(t,ds(e))}</div>`}function Ct(e){let t=de(e);return[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked&&[" \\xB7 ",a`<span class="ok">acked</span>`]]}function us({r:e,text:t,heading:n}){return[n&&a`<div class="sec">report \xB7 ${e.title}</div>`,a`<div class="sub">${Ct(e)}</div>`,a`<${fr} r=${e} text=${t} />`,e.attachments.length>0&&[a`<div class="sec">report attachments (${e.attachments.length})</div>`,se(e.attachments,s=>ct(e.key,s))],!e.acked&&[a`<div class="sec">ack</div>`,S("lobstah attention ack "+e.key)]]}var mr=/\\.(png|jpe?g|gif|webp)$/i,hr=e=>{e.style.height="auto",e.style.height=e.scrollHeight+"px"};function gr(e,t){return t.length?a`<div class="dfiles">${t.map(n=>mr.test(n.name)?a`<span key=${n.name}>${ue(at(e,n.name),n.name,"dimg")}</span>`:a`<div key=${n.name} class="dfile"><span>${n.name}</span> <span class="dim">\xB7 ${n.type} \xB7 ${n.bytes} bytes \xB7 </span><code>${n.path}</code></div>`)}</div>`:null}function vr(e,t,n){let s=e.key,r=e.kind==="decision"?e.options:[],i=t?.text??"",o=t?.files??[],c=!!t?.sending;return[r.length>0&&a`<div class="doptions">${r.map(u=>a`<button key=${u} type="button" class=${"btn dopt"+(t?.option===u?" on":"")} aria-pressed=${t?.option===u?"true":"false"} disabled=${c} onClick=${()=>bn(s,u)}>${u}</button>`)}</div>`,a`<textarea\n class="danswer"\n rows="2"\n placeholder=${r.length?"Add to your answer, or answer in your own words":"Your answer"}\n value=${i}\n disabled=${c}\n onInput=${u=>{let l=u.currentTarget;hr(l),A(s,{text:l.value,error:void 0})}}\n onPaste=${u=>{kn(s,u)}}\n ></textarea>`,a`<div class="dfoot">\n <label class="btn dattach" title="attach images or files">attach<input type="file" multiple accept=${n} disabled=${c} onChange=${u=>{let l=u.currentTarget;ft(s,l.files).then(()=>{l.value=""})}} /></label>\n ${o.map((u,l)=>a`<span key=${u.name+l} class="dchip">${u.name}<button type="button" class="dx" title="remove" disabled=${c} onClick=${()=>yn(s,l)}>\xD7</button></span>`)}\n ${t?.error&&a`<span class="bad derr">${t.error}</span>`}\n <button type="button" class="btn dsend" disabled=${c} onClick=${()=>{wn(s)}}>${c?"Sending\\u2026":"Send"}</button>\n </div>`]}function _r(e,t,n,s){let r=e.dispatch,i=e.lane??"work",c=[r&&a`<a class="dlink" href="#" onClick=${l=>{l.preventDefault(),w("dispatch",i+":"+r)()}}>${r.slice(0,8)}</a>`,e.repo,[v(e.at)," ago"]].filter(Boolean).flatMap((l,f)=>f?[" \\xB7 ",l]:[l]),u="dcard"+(e.kind==="question"?" plain":"")+(t?.sent?" answered":"")+(n?" focus":"");return a`<div key=${e.key} class=${u} data-decision=${e.key}>\n <div class="dtop">\n ${e.kind==="question"&&a`<span class=${"badge "+(e.verb==="blocked"?"bad":"warn")}>${e.verb}</span>`}\n <b class="dtitle">${e.kind==="decision"?e.title:B(e.note)}</b>\n <span class="dmeta dim">${c}</span>\n </div>\n ${e.kind==="decision"&&e.detail.trim()&&a`<${ps} text=${e.detail} fileUrl=${l=>at(e.key,l)} />`}\n ${e.kind==="decision"&&gr(e.key,e.attachments)}\n ${t?.sent?a`<div class="danswered ok">answered \xB7 ${t.sent}</div>`:vr(e,t,s)}\n </div>`}function fs({cards:e,drafts:t,focus:n,extensions:s}){let r=s.join(","),i=e.length?a`<div class="dcards">${e.map(o=>_r(o,t[o.key],o.key===n,r))}</div>`:a`<div class="empty">none</div>`;return a`<section class="decisions"><h2>decisions</h2>${i}</section>`}function yr(e,t){let n=e.badge&&a`<span class=${"badge "+(e.badge.tone||"dim")+U(e.badge.text)} title=${H(e.badge.text)}>${e.badge.text}</span>`;if(e.href){let s=(t==="cards"?"card":"deckline click")+(e.acked?" acked":"");return t==="cards"?a`<a key=${e.key} class=${s} href=${e.href} target="_blank" rel="noopener"><div class="top"><b>${e.title}</b>${n}</div>${e.meta&&a`<div class="meta" title=${e.metaText}>${e.meta}</div>`}</a>`:a`<a key=${e.key} class=${s} href=${e.href} target="_blank" rel="noopener">${n&&[n," "]}<b>${e.title}</b>${e.meta&&[" ",a`<span class="dim">\xB7 ${e.meta}</span>`]}</a>`}return t==="cards"?a`<div key=${e.key} class=${"card"+(e.acked?" acked":"")} onClick=${e.open} style=${e.open?void 0:"cursor:default"}><div class="top"><b>${e.title}</b>${n}</div>${e.meta&&a`<div class="meta" title=${e.metaText}>${e.meta}</div>`}${e.extra}${e.action&&a`<div class="foot"><span class="footact">${e.action}</span></div>`}</div>`:a`<div key=${e.key} class=${"deckline"+(e.open?" click":"")+(e.acked?" acked":"")} onClick=${e.open}>${n&&[n," "]}<b>${e.title}</b>${e.meta&&[" ",a`<span class="dim">\xB7 ${e.meta}</span>`]}${e.action&&[" ",a`<span class="dim">\xB7 </span>`,e.action]}${e.extra}</div>`}var ms=(e,t)=>e>0&&a`<a class="deckmore" href=${"#"+t}>+${e} more \u2192</a>`;function Ve(e,t,n,s,r,i){let o=t.slice(0,s),c=o.map(l=>yr(l,r)),u=o.length?r==="cards"?a`<div class="cards">${c}</div>`:c:a`<div class="empty">none</div>`;return a`<section><h2><a href=${"#"+n}>${e} \u2192</a></h2>${i&&a`<div class="tabhead">${i}</div>`}${u}${ms(t.length-o.length,n)}</section>`}function wr(e,t,n,s){let r=t.find(l=>l.number===e.nextNumber)||t[0],i=oe(e.numbers,new Map(t.map(l=>[l.number,l.title]))),o=r?"next #"+r.number:"nothing mergeable";if(s==="cards"){let l=f=>{let h=n.get(f.key)||[],d=h.length>0&&h.every(g=>g.acked),m=h.length?h.map(g=>a`<span class=${"badge "+($t[g.kind]||"dim")}>${Zn(g.kind)}</span>`):a`<span class=${"badge "+L(f.badge)+U(f.badge.text)} title=${H(f.badge.text)}>${f.badge.text}</span>`,p=`${f.repo} \\xB7 ${f.badge.text}${d?" \\xB7 acked":""}`;return a`<div key=${f.key} class=${"card"+(d?" acked":"")} onClick=${w("pr",f.key)}><div class="top">${Ue(f)}${m}</div><div class="meta" title=${p}>${p}</div></div>`};return a`<div key=${e.id} class="deckstack"><div class="dim">${i} \xB7 ${o}</div><div class="cards">${t.map(l)}</div></div>`}let c=t.flatMap(l=>(n.get(l.key)||[]).map(f=>a`<span class=${"badge "+($t[f.kind]||L(l.badge))+(f.acked?" acked":"")}>#${l.number} ${l.badge.text}</span>`)),u=c.flatMap((l,f)=>f?[" ",l]:[l]);return a`<div key=${e.id} class=${"deckline"+(r?" click":"")} onClick=${r&&w("pr",r.key)}><b>${i}</b> <span class="dim">\xB7 ${o}</span>${c.length>0&&[" \\xB7 ",u]}</div>`}function Gr(e,t){let n=e.stacks.slice(0,3),s=new Map;for(let i of e.prAttention){let o=s.get(i.key)||[];o.push(i),s.set(i.key,o)}let r=n.length?n.map(i=>wr(i,e.prs.filter(o=>o.stackId===i.id).sort((o,c)=>o.position-c.position),s,t)):a`<div class="empty">none</div>`;return a`<section><h2><a href="#prs">PRs \u2192</a></h2>${r}${ms(e.stacks.length-n.length,"prs")}</section>`}function hs({inp:e,drafts:t,focus:n,extensions:s}){let r=e.view,i=e.inflight.map(l=>({key:l.lane+":"+l.id,title:[l.id.slice(0,8)," ",l.repo||""],badge:{text:l.verb,tone:l.verb==="needs-decision"||l.verb==="blocked"?"bad":"dim"},meta:[B(l.note||"",90),l.verbAt&&[" \\xB7 ",v(l.verbAt)," ago"],(l.for||l.claimedBy)&&[" \\xB7 ",Me(l.for||l.claimedBy)]],metaText:[j(l.note||""),l.verbAt&&`${K(l.verbAt)} ago`,j(l.for||l.claimedBy||"")].filter(Boolean).join(" \\xB7 "),open:w("dispatch",l.lane+":"+l.id)})),o=e.landed.map(l=>({key:l.key,title:[l.id.slice(0,8)," ",l.repo||"",l.unreported&&[" ",a`<span class="badge warn unreported">unreported</span>`]],badge:{text:l.verb,tone:l.verb==="failed"?"bad":"ok"},meta:[B(l.note||"",90)," \\xB7 ",v(l.at)," ago"],metaText:`${j(l.note||"")} \\xB7 ${K(l.at)} ago`,open:w("dispatch",l.lane+":"+l.id)})),c=e.reports.map(l=>{let f=wt(l);return{key:l.key,title:l.title,meta:f.nodes,metaText:f.text,href:C(l.key),acked:!!l.acked}}),u=e.traps.map(({x:l})=>({key:l.trapId,title:"\\u{1FAA4} "+(l.label??`wt:${l.trapId}`),badge:l.requested?{text:"requested",tone:"dim"}:l.starting?{text:l.starting.failedAt?"start failed":"starting",tone:l.starting.failedAt?"bad":"warn"}:{text:l.live?l.harness||"live":"signed off",tone:l.live?"ok":"dim"},meta:[l.repo||""," \\xB7 ",ve(l)],metaText:`${l.repo||""} \\xB7 ${Oe(l)}`,action:z(l),extra:J(l),open:w("trap",l.trapId)}));return a`<div class="deckgrid"><${fs} cards=${e.decisions} drafts=${t} focus=${n} extensions=${s} />${Ve("in flight",i,"dispatches",4,r)}${Ve("Landed \\xB7 24h",o,"dispatches",8,r)}${Ve("reports",c,"reports",8,r)}${Ve("traps",u,"traps",8,r,a`<${Be} />`)}${Gr(e,r)}</div>`}function xr(e,t){if(!t)return e;let n=new Map(e.map(i=>[i.id,i])),s=i=>{let o=i,c=new Set;for(;o.followUp&&n.has(o.followUp)&&!c.has(o.id);)c.add(o.id),o=n.get(o.followUp);return o.id},r=new Map;for(let i of e){let o=s(i),c=r.get(o)||[];c.push(i),r.set(o,c)}return[...r.values()].sort((i,o)=>o[0].sort-i[0].sort).flatMap(i=>i.sort((o,c)=>o.id===s(o)?-1:c.id===s(c)?1:o.sort-c.sort))}function Tr(e,t){let n=e.lane+":"+e.id;return a`<tr key=${n} class="rowhead" onClick=${w("dispatch",n)}><td>${t&&e.followUp&&a`<span class="dim">\u21B3 </span>`}${e.id.slice(0,8)}</td><td>${e.lane} / ${e.bucket}</td><td>${e.repo}</td><td class=${"v-"+e.verb}>${e.verb}</td><td class="grow">${B(e.note??"",90)}${Le(e)}${Ee(e)}</td><td>${v(e.verbAt)}</td><td>${fe(e)}</td><td>${re(e)}</td></tr>`}function Sr(e){let t=e.lane+":"+e.id;return a`<div key=${t} class="card" onClick=${w("dispatch",t)}><div class="top"><b>${e.id.slice(0,8)}</b><span class=${"badge v-"+e.verb+U(e.verb)} title=${H(e.verb)}>${e.verb}</span></div><div class="meta" title=${`${e.repo} \\xB7 ${e.lane} ${e.bucket}`}>${e.repo} \xB7 ${e.lane} ${e.bucket}${e.verbAt&&[" \\xB7 ",v(e.verbAt)]}</div>${e.note&&a`<div class="note" title=${j(e.note)}>${B(e.note)}</div>`}${Le(e)}${Ee(e)}<div class="foot">${fe(e)} ${re(e)}</div></div>`}function gs({inp:e}){let t=e.list;return e.view==="cards"?t.length?a`<div class="cards">${t.map(Sr)}</div>`:a`<div class="empty">no dispatches match</div>`:R(["id","lane / bucket","repo","verb","note","age","addressed","pr"],xr(t,e.chain).map(n=>Tr(n,e.chain)),"no dispatches match")}var Cr={deck:"On deck",dispatches:"Dispatches",traps:"Traps",prs:"PRs",reports:"Reports",notices:"Notices"},Dr=["working","needs-decision","blocked","paused","done","failed","unknown"];function Ar(e,t){let n=t.daemonStale,s=e.daemon?[a`<span class=${n?"bad":"ok"}>${n&&"stale "}${v(e.daemon.heartbeat)} ago</span>`," ",a`<span class="dim">v${e.daemon.version}</span>`]:a`<span class="bad">down</span>`;return[a`<span class="chip">daemon ${s}</span>`,e.slots&&a`<span class="chip">active headless: ${e.slots.headless} of ${e.slots.limit}; traps: ${e.slots.traps}${e.slots.parked?`; parked: ${e.slots.parked} (no slot)`:""}</span>`,t.helms.map(({x:r,stale:i})=>a`<span key=${r.grounds} class="chip click" onClick=${w("helm",r.grounds)}>\u26F5 <b>${r.man}</b> <span class="dim">helm ${r.grounds}</span> <span class=${i?"warn":"ok"}>${i&&"stale "}${v(r.heartbeatAt)} ago</span></span>`)]}var Dt=[];function Rr(e){let t=[...new Set([...e.dispatches.map(n=>n.repo),...e.notices.map(n=>n.repo),...e.prs.map(n=>n.repo)].filter(Boolean))].sort();return t.length!==Dt.length&&(Dt=t),Dt}var At=[];function Pr(e){let t=[...new Set(e.notices.map(n=>n.kind))].sort();return t.length!==At.length&&(At=t),At}var $e=e=>e.currentTarget.value;function Ir(e,t,n){let s=o=>t===o?"":"display:none",r=e?Rr(e):[],i=e?Pr(e):[];return a`<div class="controls">\n <select id="f-lane" style=${e&&s("dispatches")} value=${n.lane} onChange=${o=>N({lane:$e(o)})}>\n <option value="">all lanes</option>\n <option value="work">work</option>\n <option value="chore">chore</option>\n </select>\n <select id="f-repo" value=${n.repo} onChange=${o=>N({repo:$e(o)})}>\n <option value="">all repos</option>\n ${r.map(o=>a`<option key=${o}>${o}</option>`)}\n </select>\n <select id="f-verb" style=${e&&s("dispatches")} value=${n.verb} onChange=${o=>N({verb:$e(o)})}>\n <option value="">all verbs</option>\n ${Dr.map(o=>a`<option key=${o}>${o}</option>`)}\n </select>\n <label id="chain-control" style=${e&&s("dispatches")}><input id="f-chain" type="checkbox" checked=${!!n.chain} onChange=${o=>N({chain:o.currentTarget.checked})} /> group by chain</label>\n <select id="f-kind" style=${e&&s("notices")} value=${n.noticeKind} onChange=${o=>N({noticeKind:$e(o)})}>\n <option value="">all notice kinds</option>\n ${i.map(o=>a`<option key=${o}>${o}</option>`)}\n </select>\n <input id="f-q" type="search" placeholder="search id \xB7 note \xB7 brief" value=${n.q} onInput=${o=>N({q:$e(o)})} />\n </div>`}function vs({d:e,inp:t,tab:n,st:s,stale:r}){return[a`<div class="headerline"><h1>\u{1F99E}\u2728 spyglass<span id="stale" style=${e||r?r?"display:inline":"display:none":void 0}> \xB7 STALE FEED</span></h1><span id="settings-slot"><button id="gearbtn" title="settings" aria-label="settings" onClick=${()=>M("settings","browser")}>\u2699</button></span></div>`,a`<div class="chips"><span id="chips" style="display:contents">${e&&t&&Ar(e,t.chips)}</span><span class="chip dim" id="clock">${e&&new Date(e.now).toLocaleTimeString("en-GB")}</span></div>`,a`<nav class="tabs" id="tabs" aria-label="Spyglass views">${ce.map(i=>a`<a href=${"#"+i} data-tab=${i} class=${e?i===n?"on":"":void 0}>${Cr[i]}</a>`)}</nav>`,Ir(e,n,s)]}var _s=({d:e})=>e&&["\\u{1F99E}\\u2728 lobstah v"+e.version+" \\xB7 ",a`<a href=${e.repoUrl} target="_blank">${e.repoUrl.replace("https://github.com/","")}</a>`];function $s(e,t){if(!t.lobs)return[];let n={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch",report:"report"},s=t.hidden??{},r=e.filter(o=>!o.acked&&!(o.key!==void 0&&s[o.key]===o.stateHash)).map(o=>{let c=n[o.kind??""]??"",u=o.key!==void 0?{hideKey:o.key,hideHash:o.stateHash??""}:{};return o.kind==="decision"&&o.key?{key:"decision:"+o.key,text:o.note||o.verb,label:c,hash:rt(o.key),...u}:(o.kind??"question")==="question"&&o.key?{key:"question:"+o.key,text:o.note||o.verb,label:c,hash:rt(o.key),...u}:o.kind==="report"&&o.key?{key:"report:"+o.key,text:o.note||o.verb,label:c,href:C(o.key),...u}:typeof o.kind=="string"&&o.kind.startsWith("pr:")&&o.prUrl?{key:o.kind+":"+(o.key??o.prUrl),text:o.note||o.kind,href:o.prUrl,label:c,...u}:{key:(o.kind??"question")+":"+(o.key??o.lane+":"+o.id),text:o.note||o.verb,label:c,...o.kind==="watch"?{}:{open:{type:"dispatch",key:o.lane+":"+o.id}},...u}});!r.length&&t.preview&&(r=[{key:"preview",text:"attention questions crawl in here",...t.previewHelm?{open:{type:"helm",key:t.previewHelm}}:{}}]);let i=r.length>4?r.length-4:0;return r=r.slice(0,4),i&&(r[3]={...r[3],text:"\\u2026and "+i+" more \\u2014 see attention",label:""}),r}var bs=!0;function Mr(e,t,n){let s="animation-duration:"+((innerWidth+180)/(100+t*12)).toFixed(1)+"s;animation-delay:-"+t*9%14+"s",r=()=>{e.hideKey&&An(e.hideKey,e.hideHash??"")},i=[a`<div class="bub">${e.label&&[a`<span class="badge dim">${e.label}</span>`," "]}<span>${e.text.length>48?e.text.slice(0,47)+"\\u2026":e.text}</span></div>`,n===!1?a`<span class="fallback">\u{1F99E}</span>`:a`<div class="sprite"></div>`,bs&&a`<img\n class="star"\n src="/star.png"\n alt=""\n onError=${c=>{bs=!1,c.currentTarget.remove()}}\n />`],o=e.open;return e.hash?a`<a key=${e.key} class="lob" style=${s} title="open the decision" href=${e.hash} onClick=${r}>${i}</a>`:e.href?a`<a key=${e.key} class="lob" style=${s} title=${e.label==="report"?"open the report":"open the PR"} href=${e.href} target="_blank" rel="noopener" onClick=${r}>${i}</a>`:a`<div\n key=${e.key}\n class="lob"\n style=${s}\n title="click to open"\n onClick=${()=>{r(),o&&M(o.type,o.key)}}\n >\n ${i}\n </div>`}function ks({state:e}){let t=e.snapshot,n=$s(t?.attention||[],{lobs:e.prefs.lobs,hidden:e.lobHidden,preview:e.preview,previewHelm:t&&t.helms.length?t.helms[0].grounds:void 0}),s=n.map(r=>r.key).join("|")+(e.spriteOk===null?"?":e.spriteOk?"s":"e");return Vn(()=>n.map((r,i)=>Mr(r,i,e.spriteOk)),[s])}function Ke({box:e}){if(!e)return null;let t=n=>{n.target===n.currentTarget&&ee()};return a`<div id="lightbox" class="lightbox" role="dialog" aria-label=${e.name} onClick=${t}>\n <button type="button" class="lbclose" title="close" onClick=${ee}>\xD7</button>\n <img class="lbimg" src=${e.src} alt=${e.name} />\n <a class="lboriginal" href=${e.src} target="_blank" rel="noopener">open original \xB7 ${e.name}</a>\n </div>`}var be=a`<span class="x" onClick=${te}>\xD7</span>`,ys=(e,t,n)=>a`<span class="seg">${t.map(([s,r])=>a`<button class=${s===n?"on":""} onClick=${()=>e(s)}>${r}</button>`)}</span>`;function Er(e,t){let n=ys(Cn,[["table","table"],["cards","cards"]],t.view),s=ys(Dn,[["on","on"],["off","off"]],t.lobs?"on":"off"),r=e.attentionError?e.attentionError:(e.attentionKinds||[]).join(" \\xB7 ");return[be,a`<h3>\u2699 settings <span class="dim" style="font-weight:normal">\xB7 this browser only</span></h3>`,a`<div class="settings"><div class="row"><span class="lbl">view<span class="hint">cards or table (notices stay a table)</span></span>${n}</div><div class="row"><span class="lbl">lobs<span class="hint">crawling lobsters in this page</span></span>${s}</div><div class="row"><span class="lbl">attention<span class="hint">kinds shown \u2014 attentionKinds in config.toml (read-only here)</span></span><span class="dim" style="font-size:11px;text-align:right;max-width:260px">${r}</span></div></div>`]}function Lr(e,t){let n=oe(t.numbers,new Map(t.numbers.map((r,i)=>[r,t.titles[i]])),e.number),s=t.nextMergeable?[" \\xB7 ",a`<span class="ok">next mergeable</span>`]:t.blockedBy?" \\xB7 blocked by #"+t.blockedBy:t.nextNumber?" \\xB7 next is #"+t.nextNumber:"";return[n," \\xB7 ",t.position," of ",t.size," \\xB7 floor ",t.floor,s]}var Nr=e=>t=>{t.preventDefault(),M("dispatch",e)};function Hr(e,t){let n=un(e,t),s=n.pr,r=n.stack,i=n.watch,o=je(s),c=n.chain.length?n.chain.flatMap((l,f)=>[f?" \\u2192 ":"",l.culled?a`<span class="dim">${l.id.slice(0,8)} (culled)</span>`:[a`<a href="#" onClick=${Nr(l.modalKey)}>${l.id.slice(0,8)}</a>`," ",a`<span class="dim">${l.verb}</span>`]]):a`<span class="dim">none</span>`,u=i?[a`<div>${i.key} \xB7 owner ${i.owner||"?"} \xB7 ${i.lastCheckedAt?["checked ",v(i.lastCheckedAt)," ago"]:"never checked"}</div>`,i.lastError&&a`<div class="bad">${i.lastError}</div>`,a`<div class="dim" style="font-size:11px;margin-top:4px">cursor</div>`,S(i.cursor)]:a`<div class="dim">no watch \u2014 <code>lobstah watch add ${s.url}</code> registers one</div>`;return[be,a`<h3>${He(s)} ${s.title||""} <span class=${"badge "+L(s.badge)}>${s.badge.text}</span>${s.draft&&s.badge.text!=="draft"&&[" ",a`<span class="badge pr-draft">draft</span>`]}</h3>`,a`<div class="sub">${s.repo} \xB7 ${s.state} \xB7 observed ${v(s.observedAt)} ago${s.gate&&" \\xB7 gate "+s.gate}</div>`,a`<div class="sec">checks</div><div>${me(s)}</div><div class="sec">review</div><div>${o||a`<span class="dim">no review yet</span>`}</div><div class="sec">merge</div><div>${he(s)}</div>${s.repairWait&&a`<div class="sec">repair waits</div><div>${s.repairWait.heldBy}: ${s.repairWait.reason}${s.repairWait.until?" \\xB7 until "+s.repairWait.until:""}</div>`}<div class="sec">refs</div><div>${s.headRefName||"?"} \u2192 ${s.baseRefName||"?"}</div><div class="sec">stack</div><div>${r?Lr(s,r):a`<span class="dim">not stacked</span>`}</div><div class="sec">dispatch chain</div><div>${c}</div><div class="sec">watch</div>`,u]}var ws=(e,t)=>(e==="codex"?"codex resume ":"claude --resume ")+t;function Ur(e){let t=Date.now()-Date.parse(e.heartbeatAt)>18e5;return[be,a`<h3>\u26F5 ${e.man}</h3><div class="sub">helm of <b>${e.grounds}</b> (${(e.repos||[]).join(", ")})</div><div class="sub">${e.harness??"?"} \xB7 ${e.cwd??"?"}${e.host&&" \\xB7 "+e.host}</div><div class="sub">session ${e.sessionId??""} \xB7 signed on ${v(e.signedOnAt)} ago \xB7 heartbeat <span class=${t?"warn":"ok"}>${v(e.heartbeatAt)} ago</span></div>`,e.sessionId&&[a`<div class="sec">open this session</div>`,S(ws(e.harness,e.sessionId))],e.transcript&&[a`<div class="sec">transcript</div>`,S(e.transcript)]]}function jr(e){return[a`<div class="sec">report \xB7 ${e.title}</div>`,a`<div class="sub">${Ct(e)} \xB7 <a href=${C(e.key)} target="_blank" rel="noopener">open the report \u2197</a></div>`]}function Br(e,t){let n=e.claimedBy&&e.claimedBy.startsWith("wt:")?[a`<div class="sec">worked by trap</div>`,a`<div class="claimedby">claimed by ${Ne(e.claimedBy.slice(3))}</div>`,S(j(e.claimedBy)),a`<div class="dim" style="font-size:11px">an opted-in interactive session mans this seat \u2014 attach would resume someone\'s live thread. Message it instead: lobstah send ${j(e.claimedBy)} "\u2026"</div>`]:[a`<div class="sec">open this session</div>`,S("lobstah attach "+e.id)];return[be,a`<h3>${e.id.slice(0,8)} <span class=${"badge v-"+e.verb}>${e.verb}</span></h3>`,a`<div class="sub">${e.repo} \xB7 ${e.lane} ${e.bucket} \xB7 ${v(e.verbAt)}${e.for&&[" \\xB7 ",fe(e)]} ${re(e)}</div>`,n,e.worktree&&[a`<div class="sec">worktree${e.worktreeOf?" (reused from "+e.worktreeOf.slice(0,8)+")":""}</div>`,S(e.worktree),e.worktreeKept&&a`<div class="dim" style="font-size:11px">kept: ${e.worktreeKept}</div>`],e.transcript&&[a`<div class="sec">transcript</div>`,S(e.transcript)],t&&jr(t),Qn(e)]}function Or(e){let t=ge(e),n=e.requested?[e.repo??""," \\xB7 ",e.harness??""," \\xB7 requested ",v(e.requested.at)," ago from the glass; the helm reserves it and starts its session."]:e.starting?e.starting.failedAt?[e.repo??""," \\xB7 reserved ",v(e.starting.reservedAt)," ago \\xB7 start failed: ",e.starting.reason??"",". Its addressed work stays queued; a session can still redeem the ticket, or `lobstah stow --wt ",e.name??e.trapId,"` withdraws it."]:[e.repo??""," \\xB7 reserved ",v(e.starting.reservedAt)," ago \\xB7 starting: waiting for a session to redeem the ticket (due by ",e.starting.deadline,")"]:e.live?[e.repo??"addressed bait only"," \\xB7 session ",e.sessionId??""," \\xB7 signed on ",v(e.signedOnAt)," ago \\xB7 ",t.listen," \\xB7 heartbeat ",t.hb]:"signed off \\u2014 registration gone; the lifecycle, messages, and catches are the surviving record. Re-soaking the same worktree restores this address.",s=e.notices.length?e.notices.map(o=>a`<div key=${o.seq} class="loglines">${v(o.at)} ago \xB7 <b>${o.kind}</b> \u2014 ${o.text}</div>`):a`<div class="empty">none recorded</div>`,r=e.messages.length?e.messages.map(o=>a`<div key=${o.file} class=${"msg"+(o.from==="helm"?" from-helm":"")}><div class="hdr">from ${o.from} \xB7 ${o.at&&[v(o.at)," ago"]} \xB7 ${o.state==="pending"?a`<span class="warn">pending</span>`:a`<span class="ok">delivered</span>`}</div>${o.text}${o.attachments?.length?se(o.attachments,c=>sn(e.trapId,c)):""}</div>`):a`<div class="empty">none</div>`,i=e.catches.length?e.catches.map(o=>a`<div key=${o.lane+":"+o.id} class="catch"><div class="hdr"><b>${o.id.slice(0,8)}</b><span class=${"badge v-"+o.verb}>${o.verb}</span><span class="dim">${v(o.verbAt)}</span>${re(o)}</div><div class="loglines">${_t(o)}</div></div>`):a`<div class="empty">none yet</div>`;return[be,a`<h3>\u{1FAA4} ${e.label??`wt:${e.trapId}`} <span class="badge">${e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??"signed off"}</span></h3>`,e.worktree&&a`<div class="sub">${e.worktree}</div>`,a`<div class="sub">${n}</div>`,a`<div class="sec">window</div>`,z(e),J(e),e.live&&e.sessionId&&[a`<div class="sec">open this session</div>`,S(ws(e.harness,e.sessionId)),a`<div class="dim" style="font-size:11px">as registered at sign-on \u2014 a hookless enlistment may hold a made-up id</div>`],a`<div class="sec">lifecycle (${e.notices.length})</div>`,s,a`<div class="sec">messages (${e.messages.length})</div>`,r,a`<div class="sec">catches (${e.catches.length})</div>`,i]}function Gs({snapshot:e,modal:t,prefs:n}){if(!e||!t)return null;let s=Y(e,t);if(!s)return null;if(t.type==="settings")return Er(s,n);if(t.type==="pr")return Hr(e,t.key);if(t.type==="helm")return Ur(s);if(t.type==="dispatch"){let r=an(e,s);return Br(s,r)}return Or(s)}var qr=e=>a`<tr key=${e.seq}><td class="dim">${v(e.at)}</td><td>${e.kind}</td><td class="grow">${e.text}</td><td class="dim">${e.repo??""}</td></tr>`,xs=({inp:e})=>R(["at","kind","text","repo"],e.list.map(qr),"no notices");function Ts(e){let t=new Map;for(let n of e.prs){let s=t.get(n.stackId)||[];s.push(n),t.set(n.stackId,s)}return e.stacks.map(n=>({s:n,prs:t.get(n.id)||[]})).filter(n=>n.prs.length)}var Ss=(e,t)=>oe(e.numbers,new Map(t.map(n=>[n.number,n.title]))),Rt=e=>e.state+(e.draft?" \\xB7 draft":"")+(e.state==="MERGED"&&e.mergedAt?" \\xB7 "+e.mergedAt:"");function Cs(e){let t=s=>{let r=String(s??"");return r.length>24?r.slice(0,23)+"\\u2026":r},n=e.watches.map(s=>a`<tr key=${s.key}><td>${s.key}</td><td>${s.owner}</td><td title=${s.cursor}>${t(s.cursor)}</td><td>${s.lastCheckedAt&&v(s.lastCheckedAt)}</td><td>${s.lastError||""}</td></tr>`);return[a`<h2>other watches</h2>`,R(["key","owner","cursor","last check","error"],n,"no other watches")]}function Fr(e){let t=Ts(e).flatMap(({s:n,prs:s})=>[a`<tr key=${"stack:"+n.id}><th colspan="8">${Ss(n,s)} \xB7 floor ${n.floor}${n.open?" \\xB7 open":" \\xB7 history"}</th></tr>`,...s.map(r=>a`<tr key=${r.key} class="rowhead" onClick=${w("pr",r.key)}><td>${He(r)}</td><td class="grow">${r.title||""}</td><td>${Rt(r)}</td><td>${me(r)}</td><td>${je(r)}</td><td>${he(r)}</td><td>${bt(r.watch)}</td><td>${r.gate||""}</td></tr>`)]);return[R(["PR","title","state","checks","review","merge","watch","gate"],t,"no PR evidence"),Cs(e)]}function Wr(e){let t=Ts(e),n=r=>a`<div key=${r.key} class="card" onClick=${w("pr",r.key)}><div class="top">${Ue(r)}<span class=${"badge "+L(r.badge)+U(r.badge.text)} title=${H(r.badge.text)}>${r.badge.text}</span></div><div class="meta" title=${`${r.repo} \\xB7 ${Rt(r)}`}>${r.repo} \xB7 ${Rt(r)} \xB7 ${he(r)}</div><div class="foot"><span>${me(r)}</span><span>${bt(r.watch)}</span>${r.gate&&a`<span>gate ${r.gate}</span>`}</div></div>`;return[t.length?t.map(({s:r,prs:i})=>a`<${Z} key=${"stack:"+r.id}><h2>${Ss(r,i)} \xB7 floor ${r.floor}${r.open?"":" \\xB7 history"}</h2><div class="cards">${i.map(n)}</div><//>`):a`<div class="empty">no PR evidence</div>`,Cs(e)]}var Ds=({inp:e})=>e.view==="cards"?Wr(e):Fr(e);var Pt=e=>e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??(e.live?"":"signed off"),As=e=>e.live||e.starting?"":" dim";function Vr(e){let t=ge(e);return a`<tr key=${e.trapId} class=${"rowhead"+As(e)} onClick=${w("trap",e.trapId)}><td><b>${e.label??`wt:${e.trapId}`}</b></td><td>${e.repo??"\\u2014"}</td><td class="grow">${e.worktree??""}</td><td>${e.harness??""}</td><td>${(e.sessionId??"").slice(0,8)}</td><td>${ve(e)}${J(e)}</td><td>${t.listen}</td><td>${t.hb}</td><td>${yt(e)}</td><td>${e.catches.length}</td><td>${z(e)}</td></tr>`}function Kr(e){let t=ge(e),n=yt(e),s=`${e.repo??(e.live?"addressed bait only":"history")}${e.sessionId?" \\xB7 session "+e.sessionId.slice(0,8):""}`;return a`<div key=${e.trapId} class=${"card"+As(e)} onClick=${w("trap",e.trapId)}><div class="top"><b>\u{1FAA4} ${e.label??`wt:${e.trapId}`}</b><span class=${"badge"+U(Pt(e))} title=${H(Pt(e))}>${Pt(e)}</span></div><div class="meta" title=${s}>${s}</div>${e.worktree&&a`<div class="note" title=${e.worktree}>${e.worktree}</div>`}<div class="note" title=${Oe(e)}>${ve(e)}</div>${J(e)}<div class="foot"><span>${t.listen}${e.live&&[" \\xB7 heartbeat ",t.hb]} \xB7 ${e.catches.length} catch${e.catches.length===1?"":"es"}${n&&[" \\xB7 ",n]}</span><span class="footact">${z(e)}</span></div></div>`}function Rs({inp:e}){let t=e.list.map(s=>s.x),n=a`<div class="tabhead"><${Be} /></div>`;return e.view==="cards"?[n,t.length?a`<div class="cards">${t.map(Kr)}</div>`:a`<div class="empty">no traps soaking</div>`]:[n,R(["address","repo","worktree","harness","session","now","listening","heartbeat","mail","catches","window"],t.map(Vr),"no traps soaking")]}function Ps({state:e}){let t=e.snapshot,n=e.route,s=t&&pn(t,{st:e.prefs,modal:e.modal},Date.now()),r=o=>!s||o!==n?null:o==="deck"?a`<${hs} inp=${s.deck} drafts=${e.drafts} focus=${e.focusDecision} extensions=${t?.answerLimits?.extensions??[]} />`:o==="dispatches"?a`<${gs} inp=${s.dispatches} />`:o==="traps"?a`<${Rs} inp=${s.traps} />`:o==="prs"?a`<${Ds} inp=${s.prs} />`:o==="reports"?a`<${ns} inp=${s.reports} />`:a`<${xs} inp=${s.notices} />`,i=o=>{o.target===o.currentTarget&&te()};return[a`<${vs} d=${t} inp=${s} tab=${n} st=${e.prefs} stale=${e.stale} />`,ce.map(o=>a`<main key=${o} id=${"page-"+o} class=${t&&o===n?"tabpage on":"tabpage"}><div id=${o}>${r(o)}</div></main>`),a`<footer id="foot"><${_s} d=${t} /></footer>`,a`<div id="lobs"><${ks} state=${e} /></div>`,a`<${Ke} box=${e.lightbox} />`,a`<div id="overlay" class=${e.modal&&t?"open":t?"":void 0} onClick=${i}><div class="modal" id="modalbox"><${Gs} snapshot=${t} modal=${e.modal} prefs=${e.prefs} /></div></div>`]}function zr({view:e}){if(e.state==="loading")return a`<main class="reportview"><div class="dim">loading\u2026</div></main>`;if(e.state==="error")return a`<main class="reportview"><div class="bad">${e.error}</div></main>`;let t=e.report;return a`<main class="reportview">\n <h1>${t.title}</h1>\n <${us} r=${t} text=${e.text!==void 0?{text:e.text}:{error:e.error}} />\n </main>`}function Is({view:e,box:t}){return[a`<${zr} view=${e} />`,a`<${Ke} box=${t} />`]}async function Ms(e){let t=encodeURIComponent(e),n;try{let s=await fetch(`/report/${t}/meta`);if(!s.ok)return{state:"error",error:`report not found (${s.status})`};n=JSON.parse(await s.text())}catch{return{state:"error",error:"report could not be read"}}try{let s=await fetch(dn(e));return s.ok?{state:"ready",report:n,text:await s.text()}:{state:"ready",report:n,error:`report not found (${s.status})`}}catch{return{state:"ready",report:n,error:"report could not be read"}}}var It=!1,ke=null;async function Mt(){if(!It){It=!0;try{let e=await fetch("/data");if(!e.ok)throw new Error(`/data answered ${e.status}`);ut(await e.json())}catch{Gn()}finally{It=!1}}}var Es=()=>{ke||(ke=setInterval(Mt,2e3))},Jr=()=>{ke&&clearInterval(ke),ke=null};function Ls(){document.addEventListener("visibilitychange",()=>{document.hidden?Jr():(Mt(),Es())}),Mt(),document.hidden||Es()}var Et=()=>nn(location.hash),Ns=e=>window.addEventListener("hashchange",()=>e(Et()));function Us(){let e=ln(location.hash);return e===null?!1:(location.replace(C(e)),!0)}var js=()=>({snapshot:void 0,route:Et(),prefs:mn(),modal:null,stale:!1,lobHidden:gn(),spriteOk:null,focusResults:{},preview:new URLSearchParams(location.search).has("lob"),drafts:{},focusDecision:ot(location.hash),lightbox:null}),Hs=cn(location.pathname);Hs!==null?Xr(Hs):Us()||Qr();function Xr(e){dt(js());let t={state:"loading"},n=()=>nt(Q(Is,{view:t,box:_().lightbox}),document.body);document.title="report \\xB7 lobstah glass",pt(n),n(),Ms(e).then(s=>{t=s,s.state==="ready"&&(document.title=`${s.report.title} \\xB7 lobstah glass`),n()}),document.addEventListener("keydown",s=>{s.key==="Escape"&&_().lightbox&&ee()})}function Qr(){dt(js());let e,t=!1,n=()=>{let o=_(),c=o.route!==e||!t&&!!o.snapshot;nt(Q(Ps,{state:o}),document.body),e=o.route,t||(t=!!o.snapshot),c&&window.scrollTo(0,0),o.focusDecision||(s=null),r(o.focusDecision)},s=null;function r(o){if(!o||o===s)return;let c=[...document.querySelectorAll("[data-decision]")].find(u=>u.getAttribute("data-decision")===o);c&&(s=o,c.scrollIntoView?.({block:"center"}))}pt(n),n();let i=new Image;i.onload=()=>T({spriteOk:!0}),i.onerror=()=>T({spriteOk:!1}),i.src="/lob-sprite.png",Ns(o=>{if(Us())return;let c=ot(location.hash);c!==_().focusDecision&&(s=null),T({route:o,focusDecision:c})}),document.addEventListener("keydown",o=>{o.key==="Escape"&&(_().lightbox?ee():te())}),Ls()}})();</script>\n </body>\n</html>\n';
13242
13274
 
13243
13275
  // apps/cli/src/glass-snapshot-thread.ts
13244
13276
  init_dist2();
@@ -13387,7 +13419,7 @@ async function focusRegistration(reg, options = {}) {
13387
13419
  return { focused: false, reason: "Invalid recorded WezTerm pane." };
13388
13420
  if (win?.bundleId && VSCODE_RE.test(win.bundleId) && !safeWorktree(reg))
13389
13421
  return { focused: false, reason: "Recorded editor worktree does not match this trap." };
13390
- if (validSessionLink(reg.link)) {
13422
+ if (validSessionLink(reg.link) && linkMismatch(reg.link, win) === void 0) {
13391
13423
  const opener = platform === "darwin" ? ["open", [reg.link]] : platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", reg.link]] : ["xdg-open", [reg.link]];
13392
13424
  const result = await attempt(opener[0], opener[1], "link", "Opened the session link.");
13393
13425
  if (result) return result;
@@ -13583,6 +13615,9 @@ function attentionSnapshot() {
13583
13615
  return { attention: [], landed: [], attentionKinds: [], attentionError: err instanceof Error ? err.message : String(err) };
13584
13616
  }
13585
13617
  }
13618
+ function reportRow(key) {
13619
+ return reportRows2().find((r) => r.key === key);
13620
+ }
13586
13621
  function reportRows2() {
13587
13622
  return listReports().map((r) => {
13588
13623
  const acked = reportAck(r);
@@ -13604,6 +13639,7 @@ function reportRows2() {
13604
13639
  };
13605
13640
  });
13606
13641
  }
13642
+ var REPORT_PAGE_RE = /^\/report\/([^/?#]+)(\/meta)?\/?$/;
13607
13643
  var REPORT_IMAGE_TYPES = {
13608
13644
  ".png": "image/png",
13609
13645
  ".jpg": "image/jpeg",
@@ -13749,16 +13785,16 @@ function buildGlassSnapshot(options = {}) {
13749
13785
  ...t,
13750
13786
  name,
13751
13787
  label: trapLabel({ trapId: t.trapId, name }),
13752
- link: validSessionLink(t.link) ? t.link : void 0,
13788
+ // A link that contradicts the trap's window (a vscode:// link on a
13789
+ // terminal session) is not shown; focus falls back to the window.
13790
+ link: validSessionLink(t.link) && linkMismatch(t.link, t.window) === void 0 ? t.link : void 0,
13753
13791
  sessionId: t.sessionId ?? signed?.by,
13754
13792
  harness: t.harness ?? /\((claude|codex),/.exec(signed?.text ?? "")?.[1],
13755
13793
  live: registered,
13756
13794
  listening,
13757
13795
  messages: trapMessages(t.trapId),
13758
13796
  notices,
13759
- catches: dispatches.filter(
13760
- (x) => x.claimedBy === `wt:${t.trapId}` || x.evidence?.deliveredTo === `wt:${t.trapId}` || x.for === `wt:${t.trapId}`
13761
- )
13797
+ catches: dispatches.filter((x) => x.claimedBy === `wt:${t.trapId}` || x.evidence?.deliveredTo === `wt:${t.trapId}` || x.for === `wt:${t.trapId}`).map((x) => x.id)
13762
13798
  };
13763
13799
  };
13764
13800
  const traps = [
@@ -13969,6 +14005,27 @@ function serveGlass(port, options = {}) {
13969
14005
  res.writeHead(200, { "content-type": "image/svg+xml", "cache-control": "no-cache" });
13970
14006
  res.end(fallbackIcon);
13971
14007
  }
14008
+ } else if (req.method === "GET" && REPORT_PAGE_RE.test(req.url?.split("?")[0] ?? "")) {
14009
+ if (req.headers.host !== ownHost()) {
14010
+ res.writeHead(403, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" });
14011
+ res.end("Not this glass.");
14012
+ return;
14013
+ }
14014
+ const m = REPORT_PAGE_RE.exec(req.url.split("?")[0]);
14015
+ let key;
14016
+ try {
14017
+ key = decodeURIComponent(m[1]);
14018
+ } catch {
14019
+ key = "";
14020
+ }
14021
+ const row = key ? reportRow(key) : void 0;
14022
+ if (m[2] === "/meta") {
14023
+ res.writeHead(row ? 200 : 404, { "content-type": "application/json", "cache-control": "no-store" });
14024
+ res.end(JSON.stringify(row ?? { error: "report not found" }));
14025
+ return;
14026
+ }
14027
+ res.writeHead(row ? 200 : 404, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
14028
+ res.end(PAGE);
13972
14029
  } else if ((req.url?.startsWith("/report/") || req.url?.startsWith("/decision/")) && req.method === "GET" && serveReport(req.url, res)) {
13973
14030
  return;
13974
14031
  } else if (req.url?.startsWith("/attachment/") && req.method === "GET" && serveAttachment(req.url, res)) {
@@ -16730,8 +16787,9 @@ Handle anything actionable; the Stop hook checks again at turn end.`
16730
16787
  const watched2 = pendingWatchEvents(false, "man", Date.now(), helmFloorMs);
16731
16788
  const notices = unseenNotices(false, helmNoticeFilter, helmWakes).filter((n) => n.by === void 0 || n.by !== hook.session_id);
16732
16789
  const replies2 = takeReplies(false, matchHelm);
16733
- const unanswered2 = dueUnanswered(true, remindMs, Date.now(), matchHelm);
16734
- if (evs2.length || watched2.length || notices.length || replies2.length || unanswered2.length) {
16790
+ const blocking = evs2.length > 0 || watched2.length > 0 || notices.length > 0 || replies2.length > 0;
16791
+ const unanswered2 = blocking ? dueUnanswered(true, remindMs, Date.now(), matchHelm) : [];
16792
+ if (blocking) {
16735
16793
  emit(
16736
16794
  [
16737
16795
  "A lobstah dispatch, watched source, or fleet notice needs attention:",
@@ -16748,8 +16806,12 @@ Handle anything actionable; the Stop hook checks again at turn end.`
16748
16806
  }
16749
16807
  const graceSecs = cfgHaul.helm.armGraceSecs;
16750
16808
  if (await awaitWatcher(hook.session_id, "man", graceSecs * 1e3)) break;
16809
+ const sent = dueUnanswered(true, remindMs, Date.now(), matchHelm);
16751
16810
  emit(
16752
- `Arm the watcher: run \`lobstah man wait --session ${hook.session_id} --timeout 900\` as a background task (it wakes this session when the fleet needs you), then end your turn. ` + armGraceNote(graceSecs)
16811
+ [
16812
+ ...sent.length ? ["A send still waits on its reply:", ...sent.map(sentLine), SENT_HINT] : [],
16813
+ `Arm the watcher: run \`lobstah man wait --session ${hook.session_id} --timeout 900\` as a background task (it wakes this session when the fleet needs you), then end your turn. ` + armGraceNote(graceSecs)
16814
+ ].join("\n")
16753
16815
  );
16754
16816
  break;
16755
16817
  }
@@ -16943,6 +17005,9 @@ ${usageFor("soak")}`
16943
17005
  ...reservation ? { trapId: reservation.trapId } : {}
16944
17006
  }) : void 0;
16945
17007
  if (made) worktree = canon(made.dir);
17008
+ const window = captureWindow();
17009
+ const linkFlag = opt("--link");
17010
+ const linkIgnored = linkFlag !== void 0 ? linkMismatch(linkFlag, window) : void 0;
16946
17011
  let res;
16947
17012
  try {
16948
17013
  res = signOnTrap({
@@ -16953,8 +17018,8 @@ ${usageFor("soak")}`
16953
17018
  sessionId,
16954
17019
  one: has("--one") || void 0,
16955
17020
  name: opt("--name"),
16956
- window: captureWindow(),
16957
- link: opt("--link"),
17021
+ window,
17022
+ link: linkIgnored ? void 0 : linkFlag,
16958
17023
  ...reservation ? { trapId: reservation.trapId } : {},
16959
17024
  ttlMs: cfg.soak.ttlSecs * 1e3
16960
17025
  });
@@ -16987,6 +17052,7 @@ ${usageFor("soak")}`
16987
17052
  repo: reg.repo ?? "(none configured \u2014 addressed work only)",
16988
17053
  worktree: reg.worktree,
16989
17054
  ...made ? { created: true, branch: made.branch } : {},
17055
+ ...linkIgnored ? { link: `ignored \u2014 ${linkIgnored}` } : {},
16990
17056
  ...reservation ? { ticket: `redeemed \u2014 signed on as the reserved trap` } : {},
16991
17057
  ...titled?.named ? { terminal: `tab named ${reg.name}` } : {},
16992
17058
  ...reg.one ? { one: true } : {},
@@ -66,6 +66,8 @@ For the glass's ↗ open button, give the trap its own session link with
66
66
  `claude://claude.ai/...` link in the app; copy that link from the session.
67
67
  Its app id is not the CLI session id. In the VS Code extension, use
68
68
  `vscode://anthropic.claude-code/open?session=<session-id>` with the id above.
69
+ A CLI session in a terminal, including the Claude desktop app's terminal
70
+ panel, passes no link; soak ignores a link that does not fit the session.
69
71
  The glass checks the stored link before showing it. `lobstah focus <trap>`
70
72
  uses the same focus steps from the terminal.
71
73
 
@@ -124,9 +124,10 @@ Codex task ids are UUIDv7 (for example `01a0ceb8-b9bd-7d42-…`); Claude Code
124
124
  session ids are UUIDv4. When both harnesses' variables are set, lobstah uses
125
125
  this format to tell which one signed on.
126
126
 
127
- For the glass's ↗ open button, form `codex://threads/<task-id>` from the
128
- task id in the session-start brief and pass it with
129
- `lobstah soak --link <url>`. The glass checks the stored link before
127
+ For the glass's ↗ open button in the Codex desktop app, form
128
+ `codex://threads/<task-id>` from the task id in the session-start brief and
129
+ pass it with `lobstah soak --link <url>`. A Codex CLI session in a terminal
130
+ passes no link; soak ignores a link that does not fit the session. The glass checks the stored link before
130
131
  showing it. `lobstah focus <trap>` uses the same focus steps from the
131
132
  terminal.
132
133
 
package/docs/man.md CHANGED
@@ -462,9 +462,10 @@ the helm files to keep.
462
462
  unacked first, up to 8, then "+N more", which opens the Reports tab. A
463
463
  report's card or row shows its title, then who filed it (a trap's name, a
464
464
  headless dispatch's id, nothing for the helm), its age, and `acked`. A
465
- dispatch's report renders as a
466
- page at the top of its dispatch modal. A helm report opens in a modal of
467
- its own; `#report/<key>` links to it. The page shows headings, lists,
465
+ report opens on its own page, `/report/<key>`, in a new tab: from its card
466
+ or row, a lob, the desktop pet, or its dispatch's modal. The page renders
467
+ once and does not refresh; opening it does not ack the report.
468
+ `#report/<key>` goes to that page. The page shows headings, lists,
468
469
  tables, fenced code, links (in a new tab), bold, italics, and images.
469
470
  Raw HTML in the markdown shows as text. The glass serves the markdown and
470
471
  the images read-only, and an image only by basename from that report's
@@ -558,9 +559,11 @@ the same rule.
558
559
  [--text <text>] [--attach <file>]...` answers the same way, with the same
559
560
  checks.
560
561
  - **The pet.** The desktop pet shows a decision as its title only. A click
561
- opens the glass at the card and acks the item for the pet
562
- (`lobstah attention ack <key> --by pet`). The card stays in the glass until
563
- the decision is answered or withdrawn.
562
+ brings up the live helm's session through the pet's focus ladder: the
563
+ Claude desktop app for a desktop helm, the exact terminal tab for a terminal
564
+ helm. With no live helm, it opens the glass at the card. Either way it acks
565
+ the item for the pet (`lobstah attention ack <key> --by pet`). The card
566
+ stays in the glass until the decision is answered or withdrawn.
564
567
  - **Cull.** `lobstah cull` removes a decision once its answer is older than
565
568
  the retention window, with the `decision-answer` request and its files. A
566
569
  standing decision is never culled.
@@ -657,8 +660,9 @@ before the worker reads it; `man tend` then shows the dispatch as
657
660
  A newer `needs-decision` from the worker stands again. Set `remindSecs = 0`
658
661
  for pure at-most-once.
659
662
 
660
- A send still waiting on its reply stands in the `man haul` block as
661
- `sent · <id> · <first line> · <age>`. It is listed once, then every
663
+ A send still waiting on its reply is listed in the `man haul` block as
664
+ `sent · <id> · <first line> · <age>`. Alone, it blocks a stop only when no
665
+ watcher is live, beside the arm command. It is listed once, then every
662
666
  `remindSecs` until the worker's next note answers it. `man tend` shows it on
663
667
  the dispatch as `awaiting reply · <age>`, and the glass dispatch modal shows
664
668
  it under the inbox.
@@ -805,7 +809,15 @@ lobstah soak --name amber-gull # choose or change this trap's two-word name
805
809
  a VS Code extension URL of the form
806
810
  `vscode://anthropic.claude-code/open?session=<id>`, or a Codex task URL of
807
811
  the form `codex://threads/<task-id>`. It rejects all other schemes and
808
- malformed links. The glass checks a stored link again before rendering it.
812
+ malformed links. A link must also fit the session's surface, taken from
813
+ Claude Code's `CLAUDE_CODE_ENTRYPOINT` and the recorded window: a `vscode://`
814
+ link only in the VS Code extension (`claude-vscode`), a `claude://` link only
815
+ in the Claude desktop app's Code tab, a `codex://` link only in the Codex app.
816
+ A CLI session in a terminal, including the Claude desktop app's terminal
817
+ panel, has no link: soak ignores one and prints `link: ignored — <why>`. The
818
+ glass and `lobstah focus` skip a stored link that contradicts the trap's
819
+ window and focus the window instead. The glass checks a stored link again
820
+ before rendering it.
809
821
  `lobstah focus <trap>` accepts the trap id with or without `wt:` and reports
810
822
  the focus step or why it could not focus. It does not revive a signed-off trap.
811
823
 
@@ -431,7 +431,7 @@ worktree is refused (the session lock); a stale one is adopted.
431
431
  | defective enlistment | A stale registration that **never parked** — signed on but never listened (usually no Stop hook). Not swept: the helm gets a `trap-defective` notice with the remedy (`soak --wait`), and the registration stays so the address keeps protecting its work. |
432
432
  | reserved trap | A trap `lobstah trap reserve` created before any session signs on as it: a name, a `wt:` id, and a one-time ticket, shown as `starting`. Work addressed to it waits. A session redeems the ticket with `soak --ticket` (or `LOBSTAH_TRAP_TICKET`) and signs on as that trap. Unredeemed past its deadline, it fails with a `trap-start-failed` notice and its work stays queued. `stow --wt <name>` withdraws it. |
433
433
  | trap request | A trap the human asked for from the glass's **+ New trap** button: a `trap-request` request in `requests/<id>.json` with a repo and a harness. It wakes the helm as a `trap-request` event; the helm reserves it with `trap reserve --request <id>`, which closes it. |
434
- | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; tend always shows the recent tail. |
434
+ | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
435
435
 
436
436
  Delivery routes by ownership, same as watches: a continuation for a chain
437
437
  claimed by a live trap is addressed back to that trap and stays sticky.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lobstah",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Harness-agnostic, token-efficient supervision framework for coding agents",
5
5
  "license": "MIT",
6
6
  "author": "aequitas labs LLC",