lobstah 0.6.1 → 0.6.3

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
@@ -649,6 +649,9 @@ function checkOptions(raw) {
649
649
  return options;
650
650
  }
651
651
  function askDecision(opts) {
652
+ if (opts.replace !== void 0 && !standingDecisions().some((d) => d.key === opts.replace)) {
653
+ throw new DecisionError(`no standing decision ${opts.replace} to replace \u2014 \`lobstah man tend\` lists them`);
654
+ }
652
655
  const title = checkTitle(opts.title);
653
656
  const options = checkOptions(opts.options ?? []);
654
657
  let detail = opts.detailText ?? "";
@@ -709,7 +712,7 @@ ${title}`).digest("hex").slice(0, 16)
709
712
  writeAtomic(path6.join(dir, DETAIL_MD), detail);
710
713
  writeAtomic(path6.join(dir, DECISION_JSON), `${JSON.stringify(meta, null, 2)}
711
714
  `);
712
- const replaced = opts.dispatch && opts.replace !== false ? standingDecisions().filter((d) => d.key !== key && d.dispatch === opts.dispatch && d.lane === opts.lane).map((d) => d.key) : [];
715
+ const replaced = opts.replace !== void 0 && opts.replace !== key ? [opts.replace] : [];
713
716
  for (const old of replaced)
714
717
  fs6.rmSync(decisionDir(old), { recursive: true, force: true });
715
718
  return { meta, replaced };
@@ -2376,9 +2379,36 @@ function validSessionLink(value) {
2376
2379
  return false;
2377
2380
  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);
2378
2381
  }
2382
+ function linkMismatch(link, win) {
2383
+ if (!win)
2384
+ return void 0;
2385
+ const ep = win.entrypoint;
2386
+ const bundle = win.bundleId;
2387
+ if (link.startsWith("vscode://")) {
2388
+ if (ep !== void 0)
2389
+ return ep === "claude-vscode" ? void 0 : `a vscode:// link needs the VS Code extension; this session's entrypoint is ${ep}`;
2390
+ return bundle === void 0 || VSCODE_BUNDLE_RE.test(bundle) ? void 0 : `a vscode:// link needs the VS Code extension; this session runs in ${bundle}`;
2391
+ }
2392
+ if (link.startsWith("claude://")) {
2393
+ if (ep !== void 0) {
2394
+ 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;
2395
+ }
2396
+ if (bundle !== void 0 && bundle !== CLAUDE_DESKTOP_BUNDLE)
2397
+ return `a claude:// link needs the Claude desktop app; this session runs in ${bundle}`;
2398
+ return win.termProgram === "claude-desktop" ? "a claude:// link needs the Code tab; this session runs in the Claude desktop app's terminal" : void 0;
2399
+ }
2400
+ if (link.startsWith("codex://")) {
2401
+ return bundle === void 0 || bundle === CODEX_BUNDLE ? void 0 : `a codex:// link needs the Codex app; this session runs in ${bundle}`;
2402
+ }
2403
+ return void 0;
2404
+ }
2405
+ var VSCODE_BUNDLE_RE, CLAUDE_DESKTOP_BUNDLE, CODEX_BUNDLE;
2379
2406
  var init_session_link = __esm({
2380
2407
  "packages/core/dist/session-link.js"() {
2381
2408
  "use strict";
2409
+ VSCODE_BUNDLE_RE = /(?:VSCode|Cursor|windsurf)/;
2410
+ CLAUDE_DESKTOP_BUNDLE = "com.anthropic.claudefordesktop";
2411
+ CODEX_BUNDLE = "com.openai.codex";
2382
2412
  }
2383
2413
  });
2384
2414
 
@@ -3753,6 +3783,8 @@ function signOnTrap(opts) {
3753
3783
  writeTrapAnchor(opts.worktree, { ...anchor, name });
3754
3784
  const iso = new Date(now2).toISOString();
3755
3785
  const sameSession = prior?.sessionId === opts.sessionId;
3786
+ const window = opts.window ?? (sameSession ? prior.window : void 0);
3787
+ const link = opts.link ?? (sameSession && validSessionLink(prior?.link) ? prior.link : void 0);
3756
3788
  const reg = {
3757
3789
  trapId,
3758
3790
  name,
@@ -3765,8 +3797,8 @@ function signOnTrap(opts) {
3765
3797
  signedOnAt: sameSession ? prior.signedOnAt : iso,
3766
3798
  heartbeatAt: iso,
3767
3799
  firstParkedAt: sameSession ? prior.firstParkedAt : void 0,
3768
- window: opts.window ?? (sameSession ? prior.window : void 0),
3769
- link: opts.link ?? (sameSession && validSessionLink(prior?.link) ? prior.link : void 0),
3800
+ window,
3801
+ link: link !== void 0 && linkMismatch(link, window) === void 0 ? link : void 0,
3770
3802
  claimed: prior?.claimed,
3771
3803
  ...createdWorktree ? { createdWorktree } : {}
3772
3804
  };
@@ -4176,6 +4208,35 @@ function bounceTrapMessages(trapId) {
4176
4208
  }
4177
4209
  return msgs.length;
4178
4210
  }
4211
+ function messageTexts(id, lane) {
4212
+ const dir = inboxDir(id, lane);
4213
+ const texts = [];
4214
+ for (const d of [dir, path19.join(dir, "handled")]) {
4215
+ let files;
4216
+ try {
4217
+ files = fs21.readdirSync(d).filter((f) => f.endsWith(".msg"));
4218
+ } catch {
4219
+ continue;
4220
+ }
4221
+ for (const f of files) {
4222
+ try {
4223
+ texts.push(fs21.readFileSync(path19.join(d, f), "utf8"));
4224
+ } catch {
4225
+ }
4226
+ }
4227
+ }
4228
+ return texts;
4229
+ }
4230
+ function trapMessageTexts(trapId, sinceMs = 0) {
4231
+ return messageTexts(trapKey(trapId), "work").flatMap((raw) => {
4232
+ try {
4233
+ const m = JSON.parse(raw);
4234
+ return (Date.parse(m.at ?? "") || 0) >= sinceMs ? [m.text ?? ""] : [];
4235
+ } catch {
4236
+ return sinceMs > 0 ? [] : [raw];
4237
+ }
4238
+ });
4239
+ }
4179
4240
  var metaName, trapKey;
4180
4241
  var init_inbox = __esm({
4181
4242
  "packages/core/dist/inbox.js"() {
@@ -4510,6 +4571,7 @@ function captureWindow(env = process.env) {
4510
4571
  tmuxPane: env.TMUX_PANE,
4511
4572
  kittyWindow: env.KITTY_WINDOW_ID,
4512
4573
  weztermPane: env.WEZTERM_PANE,
4574
+ entrypoint: env.CLAUDE_CODE_ENTRYPOINT,
4513
4575
  tty: ancestorTty()
4514
4576
  };
4515
4577
  for (const k of Object.keys(ref)) {
@@ -5572,7 +5634,7 @@ var init_dist2 = __esm({
5572
5634
  import * as fs30 from "node:fs";
5573
5635
  import * as path26 from "node:path";
5574
5636
  import { createHash as createHash6 } from "node:crypto";
5575
- import { exec, execFile } from "node:child_process";
5637
+ import { exec, execFile, execFileSync as execFileSync3 } from "node:child_process";
5576
5638
  import { promisify } from "node:util";
5577
5639
  async function git2(cwd, ...args) {
5578
5640
  const { stdout } = await run("git", args, { cwd, env: process.env });
@@ -5602,6 +5664,140 @@ ${gitStderr(err)}`, { cause: err });
5602
5664
  }
5603
5665
  }
5604
5666
  }
5667
+ function pidAlive(pid) {
5668
+ try {
5669
+ process.kill(pid, 0);
5670
+ return true;
5671
+ } catch (err) {
5672
+ return err.code === "EPERM";
5673
+ }
5674
+ }
5675
+ function takeRepoLock(file, mine) {
5676
+ try {
5677
+ fs30.writeFileSync(file, mine, { flag: "wx" });
5678
+ return { state: "held" };
5679
+ } catch (err) {
5680
+ const code = err.code ?? "";
5681
+ if (code !== "EEXIST" && !BUSY.has(code))
5682
+ throw err;
5683
+ }
5684
+ let raw = "";
5685
+ let age2 = 0;
5686
+ try {
5687
+ raw = fs30.readFileSync(file, "utf8");
5688
+ age2 = Date.now() - fs30.statSync(file).mtimeMs;
5689
+ } catch {
5690
+ return { state: "retry" };
5691
+ }
5692
+ let holder;
5693
+ try {
5694
+ holder = JSON.parse(raw);
5695
+ } catch {
5696
+ holder = void 0;
5697
+ }
5698
+ const stale = age2 > REPO_LOCK_WAIT_MS || (holder ? !pidAlive(holder.pid) : age2 > 5e3);
5699
+ if (stale) {
5700
+ try {
5701
+ if (fs30.readFileSync(file, "utf8") === raw)
5702
+ fs30.rmSync(file, { force: true });
5703
+ } catch {
5704
+ }
5705
+ return { state: "retry" };
5706
+ }
5707
+ return { state: "wait", ...holder ? { holder: holder.pid } : {} };
5708
+ }
5709
+ function releaseRepoLock(file, mine) {
5710
+ try {
5711
+ if (fs30.readFileSync(file, "utf8") === mine)
5712
+ fs30.rmSync(file, { force: true, recursive: true, maxRetries: 5 });
5713
+ } catch {
5714
+ }
5715
+ }
5716
+ async function withRepoLock(common, fn) {
5717
+ const file = path26.join(common, "lobstah-git.lock");
5718
+ const mine = JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() });
5719
+ const deadline = Date.now() + REPO_LOCK_WAIT_MS;
5720
+ let held = false;
5721
+ while (Date.now() < deadline) {
5722
+ const took = takeRepoLock(file, mine);
5723
+ if (took.state === "held") {
5724
+ held = true;
5725
+ break;
5726
+ }
5727
+ if (took.state === "wait")
5728
+ await new Promise((r) => setTimeout(r, 50 + Math.random() * 50));
5729
+ }
5730
+ try {
5731
+ await fn();
5732
+ } finally {
5733
+ if (held)
5734
+ releaseRepoLock(file, mine);
5735
+ }
5736
+ }
5737
+ function withRepoLockSync(cwd, fn) {
5738
+ let common;
5739
+ try {
5740
+ common = execFileSync3("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
5741
+ } catch {
5742
+ return fn();
5743
+ }
5744
+ const file = path26.join(common, "lobstah-git.lock");
5745
+ const mine = JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() });
5746
+ const deadline = Date.now() + REPO_LOCK_WAIT_MS;
5747
+ const pause = new Int32Array(new SharedArrayBuffer(4));
5748
+ let held = false;
5749
+ while (Date.now() < deadline) {
5750
+ const took = takeRepoLock(file, mine);
5751
+ if (took.state === "held") {
5752
+ held = true;
5753
+ break;
5754
+ }
5755
+ if (took.state === "wait") {
5756
+ if (took.holder === process.pid)
5757
+ break;
5758
+ Atomics.wait(pause, 0, 0, 50 + Math.random() * 50);
5759
+ }
5760
+ }
5761
+ try {
5762
+ return fn();
5763
+ } finally {
5764
+ if (held)
5765
+ releaseRepoLock(file, mine);
5766
+ }
5767
+ }
5768
+ async function oneAtATime(cwd, fn) {
5769
+ const common = await git2(cwd, "rev-parse", "--path-format=absolute", "--git-common-dir");
5770
+ const key = realpath(common);
5771
+ const run4 = (repoQueues.get(key) ?? Promise.resolve()).then(() => withRepoLock(common, () => fn(common)));
5772
+ const tail = run4.catch(() => {
5773
+ });
5774
+ repoQueues.set(key, tail);
5775
+ try {
5776
+ await run4;
5777
+ } finally {
5778
+ if (repoQueues.get(key) === tail)
5779
+ repoQueues.delete(key);
5780
+ }
5781
+ }
5782
+ function fetchStamps(common) {
5783
+ try {
5784
+ return JSON.parse(fs30.readFileSync(path26.join(common, "lobstah-fetch.json"), "utf8"));
5785
+ } catch {
5786
+ return {};
5787
+ }
5788
+ }
5789
+ async function fetchShared(cwd, remote, ref) {
5790
+ const asked = Date.now();
5791
+ const key = `${remote} ${ref}`;
5792
+ await oneAtATime(cwd, async (common) => {
5793
+ if ((fetchStamps(common)[key] ?? -Infinity) >= asked)
5794
+ return;
5795
+ const started = Date.now();
5796
+ await gitShared(cwd, "fetch", remote, ref);
5797
+ const stamps = { ...fetchStamps(common), [key]: started };
5798
+ fs30.writeFileSync(path26.join(common, "lobstah-fetch.json"), JSON.stringify(stamps, null, 2));
5799
+ });
5800
+ }
5605
5801
  async function allocate(repo, id, fromRemoteBranch = repo.trunk) {
5606
5802
  const dir = worktreePath(id);
5607
5803
  if (fs30.existsSync(dir)) {
@@ -5612,8 +5808,10 @@ async function allocate(repo, id, fromRemoteBranch = repo.trunk) {
5612
5808
  throw new Error(`repo path ${repo.path} missing and no origin configured`);
5613
5809
  await run("git", ["clone", repo.origin, repo.path], { env: process.env });
5614
5810
  }
5615
- await gitShared(repo.path, "fetch", "origin", fromRemoteBranch);
5616
- await gitShared(repo.path, "worktree", "add", "--no-track", dir, "-b", `lobstah/${id}`, `origin/${fromRemoteBranch}`);
5811
+ await fetchShared(repo.path, "origin", fromRemoteBranch);
5812
+ await oneAtATime(repo.path, async () => {
5813
+ await gitShared(repo.path, "worktree", "add", "--no-track", dir, "-b", `lobstah/${id}`, `origin/${fromRemoteBranch}`);
5814
+ });
5617
5815
  await runSetup(repo, dir);
5618
5816
  return dir;
5619
5817
  }
@@ -5730,7 +5928,7 @@ async function chooseWorktree(input) {
5730
5928
  return { reuse: true, path: found.path, owner: found.owner, from: found.from };
5731
5929
  }
5732
5930
  async function prepareReuse(repo, dir) {
5733
- await gitShared(dir, "fetch", "origin", repo.trunk);
5931
+ await fetchShared(dir, "origin", repo.trunk);
5734
5932
  if (!repo.setup?.length)
5735
5933
  return { setupRan: false };
5736
5934
  if (recordedSetupHash(dir) === setupHash(repo, dir))
@@ -5846,7 +6044,7 @@ async function removeIfSafe(dir, opts = {}) {
5846
6044
  }
5847
6045
  return { removed: true, primary, deletedBranches, keptBranches };
5848
6046
  }
5849
- var run, shell, LOCK_CONTENTION, ATTEMPTS, LOCKFILES, short;
6047
+ var run, shell, LOCK_CONTENTION, ATTEMPTS, REPO_LOCK_WAIT_MS, repoQueues, BUSY, LOCKFILES, short;
5850
6048
  var init_dist3 = __esm({
5851
6049
  "packages/worktree/dist/index.js"() {
5852
6050
  "use strict";
@@ -5871,9 +6069,17 @@ var init_dist3 = __esm({
5871
6069
  // held by another process ("fetching ref <ref> failed: reference already
5872
6070
  // exists"). The files backend maps the lock's EEXIST to this reason; older
5873
6071
  // git printed "Unable to create '<ref>.lock': File exists" instead.
5874
- /reference already exists/
6072
+ /reference already exists/,
6073
+ // Windows: two fetches unpack the same loose object, and one cannot write
6074
+ // the file the other holds open ("unable to write file
6075
+ // .git/objects/<xx>/<rest>: Permission denied", then "unpack-objects
6076
+ // failed"). Only an object path matches, not any denied write.
6077
+ /unable to write file \S*objects[\\/][0-9a-f]{2}[\\/][0-9a-f]{38,}: Permission denied/
5875
6078
  ];
5876
6079
  ATTEMPTS = 6;
6080
+ REPO_LOCK_WAIT_MS = 5 * 6e4;
6081
+ repoQueues = /* @__PURE__ */ new Map();
6082
+ BUSY = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
5877
6083
  LOCKFILES = [
5878
6084
  "pnpm-lock.yaml",
5879
6085
  "package-lock.json",
@@ -6783,6 +6989,7 @@ var init_plan = __esm({
6783
6989
  function startWallClock(opts) {
6784
6990
  const now2 = opts.now ?? Date.now;
6785
6991
  const tickMs = Math.max(1, Math.min(opts.tickMs ?? 5e3, opts.limitMs));
6992
+ const sleepGapMs = opts.sleepGapMs ?? Math.max(6e4, tickMs * 6);
6786
6993
  let elapsed = opts.initialElapsedMs ?? 0;
6787
6994
  const maxMs = Math.max(opts.limitMs, opts.maxMs ?? opts.limitMs);
6788
6995
  let windowMs = Math.min(maxMs, Math.max(opts.limitMs, opts.initialWindowMs ?? opts.limitMs));
@@ -6796,8 +7003,9 @@ function startWallClock(opts) {
6796
7003
  } catch {
6797
7004
  paused = false;
6798
7005
  }
7006
+ const step = Math.max(0, t - last);
6799
7007
  if (!paused)
6800
- elapsed += t - last;
7008
+ elapsed += step > sleepGapMs ? Math.min(step, tickMs) : step;
6801
7009
  last = t;
6802
7010
  if (!done && elapsed >= windowMs && elapsed < maxMs) {
6803
7011
  let advanced = false;
@@ -7037,8 +7245,18 @@ var init_remote = __esm({
7037
7245
  // packages/runner/dist/run.js
7038
7246
  import * as fs70 from "node:fs";
7039
7247
  import * as path57 from "node:path";
7040
- import { execFileSync as execFileSync8 } from "node:child_process";
7248
+ import { execFileSync as execFileSync9 } from "node:child_process";
7041
7249
  import { fileURLToPath as fileURLToPath5 } from "node:url";
7250
+ function livePrState(url) {
7251
+ const ref = parsePrRef(url);
7252
+ if (!ref)
7253
+ return void 0;
7254
+ try {
7255
+ return ghPrView(ref).state;
7256
+ } catch {
7257
+ return void 0;
7258
+ }
7259
+ }
7042
7260
  function within(p, ms, fallback) {
7043
7261
  let timer;
7044
7262
  const late = new Promise((resolve13) => timer = setTimeout(() => resolve13(fallback), ms));
@@ -7079,6 +7297,14 @@ async function main(activeDir, lane, seams = {}) {
7079
7297
  attempts
7080
7298
  };
7081
7299
  fs70.writeFileSync(path57.join(activeDir, "runner.json"), JSON.stringify(runnerInfo, null, 2));
7300
+ if (descriptor.systemRepair && descriptor.pr?.url) {
7301
+ const state = deps.prState(descriptor.pr.url) ?? readPr(parsePrRef(descriptor.pr.url)?.key ?? "")?.state;
7302
+ if (state === "MERGED" || state === "CLOSED") {
7303
+ status("failed", `cancelled: ${descriptor.pr.url} is ${state.toLowerCase()}; nothing to repair`);
7304
+ complete(id, lane);
7305
+ return;
7306
+ }
7307
+ }
7082
7308
  const plan = planStart({
7083
7309
  id,
7084
7310
  lane,
@@ -7183,7 +7409,7 @@ async function main(activeDir, lane, seams = {}) {
7183
7409
  })();
7184
7410
  const head = () => {
7185
7411
  try {
7186
- return execFileSync8("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
7412
+ return execFileSync9("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
7187
7413
  } catch {
7188
7414
  return void 0;
7189
7415
  }
@@ -7363,7 +7589,8 @@ var init_run = __esm({
7363
7589
  chooseWorktree,
7364
7590
  prepareReuse,
7365
7591
  collectEvidence,
7366
- reap: async () => 0
7592
+ reap: async () => 0,
7593
+ prState: livePrState
7367
7594
  };
7368
7595
  DONE_WAIT_MS = 2e3;
7369
7596
  short3 = (s) => s.slice(0, 8);
@@ -7371,10 +7598,10 @@ var init_run = __esm({
7371
7598
  });
7372
7599
 
7373
7600
  // packages/runner/dist/reap.js
7374
- import { execFileSync as execFileSync9 } from "node:child_process";
7601
+ import { execFileSync as execFileSync10 } from "node:child_process";
7375
7602
  function listProcesses() {
7376
7603
  if (process.platform === "win32") {
7377
- const out2 = execFileSync9("powershell.exe", [
7604
+ const out2 = execFileSync10("powershell.exe", [
7378
7605
  "-NoProfile",
7379
7606
  "-NonInteractive",
7380
7607
  "-Command",
@@ -7382,7 +7609,7 @@ function listProcesses() {
7382
7609
  ], { encoding: "utf8", windowsHide: true, timeout: 3e4, stdio: ["ignore", "pipe", "ignore"] });
7383
7610
  return out2.split(/\r?\n/).map((l) => l.trim().split(/\s+/).map(Number)).filter(([pid, ppid]) => Number.isInteger(pid) && Number.isInteger(ppid)).map(([pid, ppid]) => ({ pid, ppid }));
7384
7611
  }
7385
- const out = execFileSync9("ps", ["-A", "-o", "pid=,ppid=,pgid="], {
7612
+ const out = execFileSync10("ps", ["-A", "-o", "pid=,ppid=,pgid="], {
7386
7613
  encoding: "utf8",
7387
7614
  timeout: 3e4,
7388
7615
  stdio: ["ignore", "pipe", "ignore"]
@@ -7422,7 +7649,7 @@ async function stopPids(pids, graceMs = 2e3) {
7422
7649
  if (process.platform === "win32") {
7423
7650
  for (const pid of pids) {
7424
7651
  try {
7425
- execFileSync9("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true, timeout: 3e4 });
7652
+ execFileSync10("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true, timeout: 3e4 });
7426
7653
  } catch {
7427
7654
  }
7428
7655
  }
@@ -7526,7 +7753,7 @@ import { fileURLToPath as fileURLToPath6 } from "node:url";
7526
7753
 
7527
7754
  // packages/supervisor/dist/liveness.js
7528
7755
  init_dist2();
7529
- import { execFileSync as execFileSync3 } from "node:child_process";
7756
+ import { execFileSync as execFileSync4 } from "node:child_process";
7530
7757
  function classify(input) {
7531
7758
  const { hasRunner, alive: alive2, lastVerb, lastEventAt: lastEventAt2, startedAt, now: now2, wedgeThresholdMs } = input;
7532
7759
  if (lastVerb && TERMINAL_VERBS.includes(lastVerb))
@@ -7547,15 +7774,15 @@ function classify(input) {
7547
7774
  function processStartTime(pid) {
7548
7775
  try {
7549
7776
  if (process.platform === "win32") {
7550
- const out = execFileSync3("powershell.exe", ["-NoProfile", "-Command", `(Get-Process -Id ${pid}).StartTime.Ticks`], { encoding: "utf8" }).trim();
7777
+ const out = execFileSync4("powershell.exe", ["-NoProfile", "-Command", `(Get-Process -Id ${pid}).StartTime.Ticks`], { encoding: "utf8" }).trim();
7551
7778
  return out || void 0;
7552
7779
  }
7553
- return execFileSync3("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8" }).trim() || void 0;
7780
+ return execFileSync4("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8" }).trim() || void 0;
7554
7781
  } catch {
7555
7782
  return void 0;
7556
7783
  }
7557
7784
  }
7558
- function pidAlive(pid, recordedStart) {
7785
+ function pidAlive2(pid, recordedStart) {
7559
7786
  try {
7560
7787
  process.kill(pid, 0);
7561
7788
  } catch {
@@ -7569,7 +7796,7 @@ function pidAlive(pid, recordedStart) {
7569
7796
  function killGroup(pid, signal = "SIGTERM") {
7570
7797
  if (process.platform === "win32") {
7571
7798
  try {
7572
- execFileSync3("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
7799
+ execFileSync4("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
7573
7800
  } catch {
7574
7801
  }
7575
7802
  return;
@@ -7790,7 +8017,7 @@ function sessionOf(st) {
7790
8017
  return void 0;
7791
8018
  }
7792
8019
  }
7793
- function reconcileOne(st, cfg, log, spawnHeadless = spawnRunner) {
8020
+ function reconcileOne(st, cfg, log, spawnHeadless = spawnRunner, resumeGrace = false) {
7794
8021
  const hasDescriptor = fs32.existsSync(path28.join(st.dir, "descriptor.json"));
7795
8022
  if (!hasDescriptor) {
7796
8023
  const age2 = Date.now() - fs32.statSync(st.dir).mtimeMs;
@@ -7800,7 +8027,7 @@ function reconcileOne(st, cfg, log, spawnHeadless = spawnRunner) {
7800
8027
  }
7801
8028
  const statusLog = readStatusLog(st.id, st.lane);
7802
8029
  const lastVerb = statusLog.at(-1)?.verb;
7803
- const alive2 = st.runner ? pidAlive(st.runner.pid, st.runner.processStartTime) : void 0;
8030
+ const alive2 = st.runner ? pidAlive2(st.runner.pid, st.runner.processStartTime) : void 0;
7804
8031
  const sessionClaim = readSessionClaim(st.id, st.lane);
7805
8032
  if (sessionClaim) {
7806
8033
  if (lastVerb === "done" || lastVerb === "failed") {
@@ -7870,6 +8097,8 @@ function reconcileOne(st, cfg, log, spawnHeadless = spawnRunner) {
7870
8097
  break;
7871
8098
  }
7872
8099
  case "wedged": {
8100
+ if (resumeGrace)
8101
+ break;
7873
8102
  const attempts = (st.runner?.attempts ?? 0) + 1;
7874
8103
  if (st.runner)
7875
8104
  killGroup(st.runner.pid, "SIGKILL");
@@ -7903,7 +8132,7 @@ function wakeReason(id, lane, now2 = Date.now()) {
7903
8132
  }
7904
8133
  function wakeParked(lane, free, log, spawnHeadless = spawnRunner, now2 = Date.now()) {
7905
8134
  let woke = 0;
7906
- const parked = listActive(lane).filter((st) => st.runner && !isTrapCatch(st.id, lane) && isParked(st.id, lane) && !cancelRequested(st.id, lane) && !pidAlive(st.runner.pid, st.runner.processStartTime));
8135
+ const parked = listActive(lane).filter((st) => st.runner && !isTrapCatch(st.id, lane) && isParked(st.id, lane) && !cancelRequested(st.id, lane) && !pidAlive2(st.runner.pid, st.runner.processStartTime));
7907
8136
  for (const st of parked) {
7908
8137
  if (woke >= free)
7909
8138
  break;
@@ -8038,10 +8267,12 @@ function tick(log = () => {
8038
8267
  ensureLayout();
8039
8268
  const now2 = hooks.now?.() ?? Date.now();
8040
8269
  const ttl = cfg.soak.ttlSecs * 1e3;
8270
+ const wedgeMs = cfg.limits.wedgeThresholdSecs * 1e3;
8041
8271
  const home = lobstahHome();
8042
8272
  const timing = tickTimes.get(home);
8043
- const resumed = timing && now2 - timing.last > ttl ? now2 : timing?.resumed;
8273
+ const resumed = timing && now2 - timing.last > Math.min(ttl, wedgeMs) ? now2 : timing?.resumed;
8044
8274
  tickTimes.set(home, { last: now2, resumed });
8275
+ const wedgeGrace = resumed !== void 0 && now2 - resumed <= wedgeMs;
8045
8276
  writeHeartbeat(cfg);
8046
8277
  hooks.prWatches?.(hooks.now?.() ?? Date.now(), log);
8047
8278
  for (const action of resumed !== void 0 && now2 - resumed <= ttl ? [] : sweepGhostTraps(ttl, now2, cfg.soak.pausedTtlSecs * 1e3)) {
@@ -8056,7 +8287,7 @@ function tick(log = () => {
8056
8287
  const skipFor = (lane) => lane === "work" ? workSkip : choreSkip;
8057
8288
  for (const lane of ["chore", "work"]) {
8058
8289
  for (const st of listActive(lane))
8059
- reconcileOne(st, cfg, log, hooks.spawnRunner);
8290
+ reconcileOne(st, cfg, log, hooks.spawnRunner, wedgeGrace);
8060
8291
  }
8061
8292
  retentionPass(cfg, hooks, log);
8062
8293
  const hasHeadlessSlot = (lane) => slotUsage(lane).headless < (lane === "work" ? cfg.limits.maxConcurrent : cfg.limits.choreConcurrent);
@@ -8085,7 +8316,7 @@ function tick(log = () => {
8085
8316
  inFlight++;
8086
8317
  const st = listActive(lane).find((s) => s.id === id);
8087
8318
  if (st)
8088
- reconcileOne(st, cfg, log, hooks.spawnRunner);
8319
+ reconcileOne(st, cfg, log, hooks.spawnRunner, wedgeGrace);
8089
8320
  }
8090
8321
  }
8091
8322
  if (cfg.notifyCommand) {
@@ -8105,7 +8336,7 @@ function acquireDaemonLock() {
8105
8336
  const lockPath = path28.join(lobstahHome(), "daemon.lock");
8106
8337
  try {
8107
8338
  const prior = JSON.parse(fs32.readFileSync(lockPath, "utf8"));
8108
- if (pidAlive(prior.pid, prior.processStartTime)) {
8339
+ if (pidAlive2(prior.pid, prior.processStartTime)) {
8109
8340
  throw new Error(`another daemon (pid ${prior.pid}) already supervises ${lobstahHome()} \u2014 run a second instance against its own LOBSTAH_HOME instead`);
8110
8341
  }
8111
8342
  } catch (err) {
@@ -8832,7 +9063,7 @@ import * as path32 from "node:path";
8832
9063
  init_dist2();
8833
9064
  import * as fs36 from "node:fs";
8834
9065
  import * as path31 from "node:path";
8835
- import { execFileSync as execFileSync4 } from "node:child_process";
9066
+ import { execFileSync as execFileSync5 } from "node:child_process";
8836
9067
  function age(seconds) {
8837
9068
  if (seconds < 60)
8838
9069
  return `${seconds}s`;
@@ -8842,7 +9073,7 @@ function age(seconds) {
8842
9073
  }
8843
9074
  function git3(worktree, ...args) {
8844
9075
  try {
8845
- return execFileSync4("git", args, { cwd: worktree, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
9076
+ return execFileSync5("git", args, { cwd: worktree, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
8846
9077
  } catch {
8847
9078
  return void 0;
8848
9079
  }
@@ -9943,7 +10174,7 @@ function worktreeView(id, lane) {
9943
10174
  init_dist2();
9944
10175
  import * as fs45 from "node:fs";
9945
10176
  import * as path39 from "node:path";
9946
- import { execFileSync as execFileSync5 } from "node:child_process";
10177
+ import { execFileSync as execFileSync6 } from "node:child_process";
9947
10178
  var GIT_CACHE_MS = 6e4;
9948
10179
  var gitCache = /* @__PURE__ */ new Map();
9949
10180
  function headStamp(cwd) {
@@ -9971,7 +10202,7 @@ function git4(cwd, ...args) {
9971
10202
  if (hit && stamp !== "" && hit.stamp === stamp && now2 - hit.at < GIT_CACHE_MS) return hit.out;
9972
10203
  let out;
9973
10204
  try {
9974
- out = execFileSync5("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
10205
+ out = execFileSync6("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
9975
10206
  } catch {
9976
10207
  out = void 0;
9977
10208
  }
@@ -10190,13 +10421,15 @@ function terminal2(id, lane) {
10190
10421
  function liveWorkers() {
10191
10422
  const out = [];
10192
10423
  for (const reg of listTraps()) {
10193
- if (!hasOpenCatch(reg)) continue;
10424
+ const catchId = hasOpenCatch(reg) ? reg.claimed : void 0;
10425
+ const lane = catchId ? laneOf(catchId) ?? "work" : "work";
10194
10426
  out.push({
10195
10427
  label: `wt:${reg.name ?? reg.trapId}`,
10196
- dispatchId: reg.claimed,
10197
- lane: laneOf(reg.claimed) ?? "work",
10428
+ ...catchId ? { dispatchId: catchId } : {},
10429
+ lane,
10198
10430
  worktree: reg.worktree,
10199
- repo: storedDescriptor(reg.claimed, laneOf(reg.claimed) ?? "work")?.repo ?? reg.repo
10431
+ repo: (catchId ? storedDescriptor(catchId, lane)?.repo : void 0) ?? reg.repo,
10432
+ trapId: reg.trapId
10200
10433
  });
10201
10434
  }
10202
10435
  for (const lane of ["work", "chore"]) {
@@ -10224,6 +10457,7 @@ function git5(cwd, args) {
10224
10457
  const res = spawnSync4("git", ["-C", cwd, ...args], { encoding: "utf8", timeout: 1e4 });
10225
10458
  return res.status === 0 && !res.error ? res.stdout.trim() : void 0;
10226
10459
  }
10460
+ var TRAP_MESSAGE_HOLD_MS = 24 * 36e5;
10227
10461
  var GIT_CACHE_MS2 = 6e4;
10228
10462
  var gitCache2 = /* @__PURE__ */ new Map();
10229
10463
  function gitFacts(worktree, branch, now2 = Date.now()) {
@@ -10241,7 +10475,7 @@ function gitFacts(worktree, branch, now2 = Date.now()) {
10241
10475
  function workerHold(worker) {
10242
10476
  const branches = /* @__PURE__ */ new Map();
10243
10477
  const prs = /* @__PURE__ */ new Map();
10244
- const evidence = readEvidence(worker.dispatchId, worker.lane);
10478
+ const evidence = worker.dispatchId ? readEvidence(worker.dispatchId, worker.lane) : {};
10245
10479
  const origin = worker.repo ? loadConfig().repos[worker.repo]?.origin : void 0;
10246
10480
  let forgeRepo = origin ? githubRepoFromOrigin(origin) : void 0;
10247
10481
  if (worker.worktree && fs46.existsSync(worker.worktree)) {
@@ -10262,10 +10496,28 @@ function workerHold(worker) {
10262
10496
  }
10263
10497
  const named = evidence.prUrl ? parsePrRef(evidence.prUrl) : void 0;
10264
10498
  if (named) prs.set(named.key, "works on this PR");
10265
- const owned = chainPr(worker.dispatchId, worker.lane);
10499
+ const owned = worker.dispatchId ? chainPr(worker.dispatchId, worker.lane) : void 0;
10266
10500
  const ownedRef = owned ? parsePrRef(owned.url) : void 0;
10267
10501
  if (ownedRef && !prs.has(ownedRef.key)) prs.set(ownedRef.key, "its chain owns this PR");
10268
- return { label: worker.label, dispatchId: worker.dispatchId, ...forgeRepo ? { forgeRepo } : {}, branches, prs };
10502
+ const said = [
10503
+ ...worker.dispatchId ? [storedDescriptor(worker.dispatchId, worker.lane)?.brief ?? "", ...messageTexts(worker.dispatchId, worker.lane)] : [],
10504
+ ...worker.trapId ? trapMessageTexts(worker.trapId, Date.now() - TRAP_MESSAGE_HOLD_MS) : []
10505
+ ].join("\n");
10506
+ return {
10507
+ label: worker.label,
10508
+ ...worker.dispatchId ? { dispatchId: worker.dispatchId } : {},
10509
+ ...worker.trapId ? { trapId: worker.trapId } : {},
10510
+ ...forgeRepo ? { forgeRepo } : {},
10511
+ branches,
10512
+ prs,
10513
+ said
10514
+ };
10515
+ }
10516
+ function namesPr(text, pr, sameRepo) {
10517
+ if (!pr.repo || pr.number === void 0 || !text) return false;
10518
+ const repo = pr.repo.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10519
+ const n = String(pr.number);
10520
+ return new RegExp(`github\\.com/${repo}/pull/${n}(?![0-9])`, "i").test(text) || new RegExp(`(?<![\\w.-])${repo}#${n}(?![0-9])`, "i").test(text) || sameRepo && new RegExp(`(?<![\\w/#&])#${n}(?![0-9])`).test(text);
10269
10521
  }
10270
10522
  function readWorkerHolds() {
10271
10523
  return liveWorkers().map(workerHold);
@@ -10278,10 +10530,11 @@ function repairHold(pr, records, workers) {
10278
10530
  for (const target of targets) {
10279
10531
  for (const worker of workers) {
10280
10532
  if (worker.forgeRepo && worker.forgeRepo !== target.repo) continue;
10281
- const how = worker.prs.get(target.key) ?? (target.head ? worker.branches.get(target.head) : void 0);
10533
+ const how = worker.prs.get(target.key) ?? (target.head ? worker.branches.get(target.head) : void 0) ?? (namesPr(worker.said, target, worker.forgeRepo === target.repo) ? "was told to work on this PR" : void 0);
10282
10534
  if (!how) continue;
10283
10535
  const where = target.below ? `; #${target.number} is below this PR` : "";
10284
- return { heldBy: worker.label, reason: `${worker.label} (dispatch ${worker.dispatchId.slice(0, 8)}) ${how}${where}` };
10536
+ const dispatch = worker.dispatchId ? ` (dispatch ${worker.dispatchId.slice(0, 8)})` : "";
10537
+ return { heldBy: worker.label, reason: `${worker.label}${dispatch} ${how}${where}` };
10285
10538
  }
10286
10539
  }
10287
10540
  return void 0;
@@ -10433,6 +10686,11 @@ function holdCancelledRepair(id, now2 = /* @__PURE__ */ new Date()) {
10433
10686
  }
10434
10687
  return held;
10435
10688
  }
10689
+ function trapAddressOf(id) {
10690
+ const claim = readSessionClaim(id, "work");
10691
+ const deliveredTo = readEvidence(id, "work").deliveredTo;
10692
+ return claim?.by.startsWith("wt:") ? claim.by : deliveredTo?.startsWith("wt:") ? deliveredTo : void 0;
10693
+ }
10436
10694
  function deliverPrRepairs(log, cap = 3, opts = {}) {
10437
10695
  const config = loadConfig();
10438
10696
  const cfg = config.watch;
@@ -10535,7 +10793,12 @@ function deliverPrRepairs(log, cap = 3, opts = {}) {
10535
10793
  });
10536
10794
  };
10537
10795
  if (watch2.heldAt) return wait(watchHold(watch2));
10538
- const held = repairHold(pr, records ??= readPrs(), workers ??= (opts.workerHolds ?? readWorkerHolds)());
10796
+ const ownerTrap = trapAddressOf(chainState(owner).latest);
10797
+ const held = repairHold(
10798
+ pr,
10799
+ records ??= readPrs(),
10800
+ (workers ??= (opts.workerHolds ?? readWorkerHolds)()).filter((w2) => !(w2.dispatchId === void 0 && w2.trapId !== void 0 && `wt:${w2.trapId}` === ownerTrap))
10801
+ );
10539
10802
  if (held) return wait(held);
10540
10803
  const changed = Math.max(
10541
10804
  Date.parse(pr.headSince ?? pr.observedAt) || now2,
@@ -10562,9 +10825,7 @@ function deliverPrRepairs(log, cap = 3, opts = {}) {
10562
10825
  }
10563
10826
  const target = storedDescriptor(chain.latest, "work");
10564
10827
  if (!target) return;
10565
- const claim = readSessionClaim(chain.latest, "work");
10566
- const deliveredTo = readEvidence(chain.latest, "work").deliveredTo;
10567
- const address = claim?.by.startsWith("wt:") ? claim.by : deliveredTo?.startsWith("wt:") ? deliveredTo : void 0;
10828
+ const address = trapAddressOf(chain.latest);
10568
10829
  const trap = address ? readTrap(address.slice(3)) : void 0;
10569
10830
  const liveTrap2 = trap && now2 - trapLastSeen(trap) <= config.soak.ttlSecs * 1e3 ? trap : void 0;
10570
10831
  const waitSecs = Math.max(0, Number.isFinite(cfg.repairTrapWaitSecs) ? cfg.repairTrapWaitSecs : 600);
@@ -11643,7 +11904,7 @@ function liveState(text) {
11643
11904
  return void 0;
11644
11905
  }
11645
11906
  if (!state || !Number.isInteger(state.pid) || state.pid <= 0 || !Number.isInteger(state.port)) return void 0;
11646
- return pidAlive2(state.pid) ? state : void 0;
11907
+ return pidAlive3(state.pid) ? state : void 0;
11647
11908
  }
11648
11909
  function readGlassState() {
11649
11910
  return liveState(readStateText());
@@ -11671,7 +11932,7 @@ function writeGlassState(state) {
11671
11932
  function removeGlassState() {
11672
11933
  fs51.rmSync(stateFile(), { force: true });
11673
11934
  }
11674
- function pidAlive2(pid) {
11935
+ function pidAlive3(pid) {
11675
11936
  try {
11676
11937
  process.kill(pid, 0);
11677
11938
  return true;
@@ -11772,7 +12033,7 @@ async function terminate(pid, timeoutMs) {
11772
12033
  } catch {
11773
12034
  }
11774
12035
  const deadline = Date.now() + timeoutMs;
11775
- while (pidAlive2(pid)) {
12036
+ while (pidAlive3(pid)) {
11776
12037
  if (Date.now() >= deadline) return false;
11777
12038
  await delay(50);
11778
12039
  }
@@ -11927,7 +12188,7 @@ ${help}`;
11927
12188
  init_dist2();
11928
12189
  import * as fs52 from "node:fs";
11929
12190
  import * as path45 from "node:path";
11930
- import { execFileSync as execFileSync6 } from "node:child_process";
12191
+ import { execFileSync as execFileSync7 } from "node:child_process";
11931
12192
  var DAY = 864e5;
11932
12193
  function walkBytes(target) {
11933
12194
  const stat = fs52.lstatSync(target);
@@ -11946,7 +12207,7 @@ var sizing = {
11946
12207
  worktree(target, platform = process.platform) {
11947
12208
  if (platform !== "win32") {
11948
12209
  try {
11949
- const out = execFileSync6("du", ["-sk", target], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
12210
+ const out = execFileSync7("du", ["-sk", target], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
11950
12211
  const kb = Number(out.trim().split(/\s+/)[0]);
11951
12212
  if (Number.isFinite(kb)) return kb * 1024;
11952
12213
  } catch {
@@ -12172,20 +12433,20 @@ function removeWorktree(id, dir) {
12172
12433
  const desc = JSON.parse(fs52.readFileSync(descFile, "utf8"));
12173
12434
  const repo = loadConfig().repos[desc.repo];
12174
12435
  if (repo) {
12175
- execFileSync6("git", ["worktree", "remove", "--force", dir], { cwd: repo.path, stdio: "ignore" });
12436
+ execFileSync7("git", ["worktree", "remove", "--force", dir], { cwd: repo.path, stdio: "ignore" });
12176
12437
  return;
12177
12438
  }
12178
12439
  } catch {
12179
12440
  }
12180
12441
  }
12181
12442
  try {
12182
- const common = execFileSync6("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
12443
+ const common = execFileSync7("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
12183
12444
  cwd: dir,
12184
12445
  encoding: "utf8",
12185
12446
  stdio: ["ignore", "pipe", "ignore"]
12186
12447
  }).trim();
12187
12448
  if (common) {
12188
- execFileSync6("git", ["--git-dir", common, "worktree", "remove", "--force", dir], { stdio: "ignore" });
12449
+ execFileSync7("git", ["--git-dir", common, "worktree", "remove", "--force", dir], { stdio: "ignore" });
12189
12450
  return;
12190
12451
  }
12191
12452
  } catch {
@@ -12236,8 +12497,9 @@ function runCull(days, apply, freeBytes = statfsFreeBytes, now2 = Date.now()) {
12236
12497
 
12237
12498
  // apps/cli/src/release.ts
12238
12499
  init_dist2();
12500
+ init_dist3();
12239
12501
  import * as fs53 from "node:fs";
12240
- import { execFileSync as execFileSync7 } from "node:child_process";
12502
+ import { execFileSync as execFileSync8 } from "node:child_process";
12241
12503
  var DAY2 = 864e5;
12242
12504
  function listIds(dir) {
12243
12505
  try {
@@ -12316,7 +12578,7 @@ function mergedPrs(all) {
12316
12578
  }
12317
12579
  function git7(cwd, ...args) {
12318
12580
  try {
12319
- return execFileSync7("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
12581
+ return execFileSync8("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
12320
12582
  } catch {
12321
12583
  return void 0;
12322
12584
  }
@@ -12326,7 +12588,7 @@ function unsafe(dir, fetched) {
12326
12588
  if (status === void 0) return "unpushed work: not a readable git checkout";
12327
12589
  if (status !== "") return "unpushed work: uncommitted changes";
12328
12590
  const common = git7(dir, "rev-parse", "--path-format=absolute", "--git-common-dir") ?? dir;
12329
- if (!fetched.has(common)) fetched.set(common, git7(dir, "fetch", "--quiet", "origin") !== void 0);
12591
+ if (!fetched.has(common)) fetched.set(common, withRepoLockSync(dir, () => git7(dir, "fetch", "--quiet", "origin")) !== void 0);
12330
12592
  if (!fetched.get(common)) return "unpushed work: fetch failed, remote state unknown";
12331
12593
  const remote = git7(dir, "branch", "-r", "--contains", "HEAD");
12332
12594
  if (remote === void 0 || remote === "") return "unpushed work: HEAD is not on the remote";
@@ -12555,7 +12817,6 @@ function answerKey(key, req) {
12555
12817
  lane: q.lane,
12556
12818
  ...q.repo ? { repo: q.repo } : {},
12557
12819
  askedBy: "worker",
12558
- replace: false,
12559
12820
  maxBytes
12560
12821
  });
12561
12822
  try {
@@ -13240,7 +13501,7 @@ import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from
13240
13501
  import { fileURLToPath as fileURLToPath3 } from "node:url";
13241
13502
 
13242
13503
  // apps/cli/src/glass-page.generated.ts
13243
- 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,jn,B,Nt,Ut,Ft,Xe,Te,oe,qt,Ze,Je,Qe,Bn,Se={},Ce=[],Un=/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 s in t)e[s]=t[s];return e}function Ye(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function ae(e,t,s){var n,r,i,o={};for(i in t)i=="key"?n=t[i]:i=="ref"?r=t[i]:o[i]=t[i];if(arguments.length>2&&(o.children=arguments.length>3?Ae.call(arguments,2):s),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)o[i]===void 0&&(o[i]=e.defaultProps[i]);return xe(e,o,n,r,null)}function xe(e,t,s,n,r){var i={type:e,props:t,key:s,ref:n,__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 J(e){return e.children}function Ge(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 s;t<e.__k.length;t++)if((s=e.__k[t])!=null&&s.__e!=null)return s.__e;return typeof e.type=="function"?W(e):null}function Fn(e){if(e.__P&&e.__d){var t=e.__v,s=t.__e,n=[],r=[],i=P({},t);i.__v=t.__v+1,b.vnode&&b.vnode(i),et(e.__P,i,t,e.__n,e.__P.namespaceURI,32&t.__u?[s]:null,n,s??W(t),!!(32&t.__u),r),i.__v=t.__v,i.__.__k[i.__i]=i,Xt(n,i,r),t.__e=t.__=null,i.__e!=s&&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)&&B.push(e)&&!De.__r++||Nt!=b.debounceRendering)&&((Nt=b.debounceRendering)||Ut)(De)}function De(){try{for(var e,t=1;B.length;)B.length>t&&B.sort(Ft),e=B.shift(),t=B.length,Fn(e)}finally{B.length=De.__r=0}}function Vt(e,t,s,n,r,i,o,c,u,l,f){var h,d,m,p,g,x,T=n&&n.__k||Ce,$=t.length;for(u=qn(s,t,T,u,$),h=0;h<$;h++)(m=s.__k[h])!=null&&(d=m.__i!=-1&&T[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 s.__e=g,u}function qn(e,t,s,n,r){var i,o,c,u,l,f=s.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(J,{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=Wn(o,s,u,h))!=-1&&(h--,(c=s[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=s[i])!=null&&(2&c.__u)==0&&(c.__e==n&&(n=W(c)),Qt(c,c));return n}function Kt(e,t,s){var n,r;if(typeof e.type=="function"){for(n=e.__k,r=0;n&&r<n.length;r++)n[r]&&(n[r].__=e,t=Kt(n[r],t,s));return t}e.__e!=t&&(t&&e.type&&!t.parentNode&&(t=W(e)),t=s.insertBefore(e.__e,t||null));do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function Wn(e,t,s,n){var r,i,o,c=e.key,u=e.type,l=t[s],f=l!=null&&(2&l.__u)==0;if(l===null&&c==null||f&&c==l.key&&u==l.type)return s;if(n>(f?1:0)){for(r=s-1,i=s+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 Ot(e,t,s){t[0]=="-"?e.setProperty(t,s??""):e[t]=s==null?"":typeof s!="number"||Un.test(t)?s:s+"px"}function we(e,t,s,n,r){var i,o;e:if(t=="style")if(typeof s=="string")e.style.cssText=s;else{if(typeof n=="string"&&(e.style.cssText=n=""),n)for(t in n)s&&t in s||Ot(e.style,t,"");if(s)for(t in s)n&&s[t]==n[t]||Ot(e.style,t,s[t])}else if(t[0]=="o"&&t[1]=="n")i=t!=(t=t.replace(qt,"$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]=s,s?n?s[oe]=n[oe]:(s[oe]=Ze,e.addEventListener(t,i?Qe:Je,i)):e.removeEventListener(t,i?Qe:Je,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]=s??"";break e}catch{}typeof s=="function"||(s==null||s===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&s==1?"":s))}}function jt(e){return function(t){if(this.l){var s=this.l[t.type+e];if(t[Te]==null)t[Te]=Ze++;else if(t[Te]<s[oe])return;return s(b.event?b.event(t):t)}}}function et(e,t,s,n,r,i,o,c,u,l){var f,h,d,m,p,g,x,T,$,I,re,q,ie,Lt,ye,ze,M=t.type;if(t.constructor!==void 0)return null;128&s.__u&&(u=!!(32&s.__u),i=[c=t.__e=s.__e]),(f=b.__b)&&f(t);e:if(typeof M=="function"){h=o.length;try{if($=t.props,I=M.prototype&&M.prototype.render,re=(f=M.contextType)&&n[f.__c],q=f?re?re.props.value:f.__:n,s.__c?T=(d=t.__c=s.__c).__=d.__E:(I?t.__c=d=new M($,q):(t.__c=d=new Ge($,q),d.constructor=M,d.render=Kn),re&&re.sub(d),d.state||(d.state={}),d.__n=n,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==s.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate($,d.__s,q)===!1){t.__v!=s.__v&&(d.props=$,d.state=d.__s,d.__d=!1),t.__e=s.__e,t.__k=s.__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=W(s);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,ie=b.__r,Lt=0,I)d.state=d.__s,d.__d=!1,ie&&ie(t),f=d.render(d.props,d.state,d.context),Ce.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,ie&&ie(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&&(n=P(P({},n),d.getChildContext())),I&&!m&&d.getSnapshotBeforeUpdate!=null&&(x=d.getSnapshotBeforeUpdate(p,g)),ye=f!=null&&f.type===J&&f.key==null?Jt(f.props.children):f,c=Vt(e,Re(ye)?ye:[ye],t,s,n,r,i,o,c,u,l),d.base=t.__e,t.__u&=-161,d.__h.length&&o.push(d),T&&(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=s.__e;t.__k==null&&(t.__k=s.__k||[]),X.then||zt(t),b.__e(X,t,s)}}else i==null&&t.__v==s.__v?(t.__k=s.__k,t.__e=s.__e):c=t.__e=Vn(s.__e,t,s,n,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 Xt(e,t,s){for(var n=0;n<s.length;n++)tt(s[n],s[++n],s[++n]);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 Jt(e){return typeof e!="object"||e==null||e.__b>0?e:Re(e)?e.map(Jt):e.constructor!==void 0?null:P({},e)}function Vn(e,t,s,n,r,i,o,c,u){var l,f,h,d,m,p,g,x=s.props||Se,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"),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(T);e=document.createElementNS(r,$,T.is&&T),c&&(b.__m&&b.__m(t,i),c=!1),i=null}if($==null)x===T||c&&e.data==T||(e.data=T);else{if(i=$=="textarea"&&T.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 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=""),Vt(t.type=="template"?e.content:e,Re(d)?d:[d],t,s,n,$=="foreignObject"?"http://www.w3.org/1999/xhtml":r,i,o,i?i[0]:s.__k&&W(s,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,s){try{if(typeof e=="function"){var n=typeof e.__u=="function";n&&e.__u(),n&&t==null||(e.__u=e(t))}else e.current=t}catch(r){b.__e(r,s)}}function Qt(e,t,s){var n,r;if(b.unmount&&b.unmount(e),(n=e.ref)&&(n.current&&n.current!=e.__e||tt(n,null,t)),(n=e.__c)!=null){if(n.componentWillUnmount)try{n.componentWillUnmount()}catch(i){b.__e(i,t)}n.base=n.__P=n.__n=null}if(n=e.__k)for(r=0;r<n.length;r++)n[r]&&Qt(n[r],t,s||typeof e.type!="function");s||Ye(e.__e),e.__c=e.__=e.__e=void 0}function Kn(e,t,s){return this.constructor(e,s)}function Zt(e,t,s){var n,r,i,o;t==document&&(t=document.documentElement),b.__&&b.__(e,t),r=(n=typeof s=="function")?null:s&&s.__k||t.__k,i=[],o=[],et(t,e=(!n&&s||t).__k=ae(J,null,[e]),r||Se,Se,t.namespaceURI,!n&&s?[s]:r?null:t.firstChild?Ae.call(t.childNodes):null,i,!n&&s?s:r?r.__e:t.firstChild,n,o),Xt(i,e,o),e.props.children=null}Ae=Ce.slice,b={__e:function(e,t,s,n){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,n||{}),o=r.__d),o)return r.__E=r}catch(c){e=c}throw e}},Bt=0,jn=function(e){return e!=null&&e.constructor===void 0},Ge.prototype.setState=function(e,t){var s;s=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=P({},this.state),typeof e=="function"&&(e=e(P({},s),this.props)),e&&P(s,e),e!=null&&this.__v&&(t&&this._sb.push(t),Ht(this))},Ge.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Ht(this))},Ge.prototype.render=J,B=[],Ut=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Ft=function(e,t){return e.__v.__b-t.__v.__b},De.__r=0,Xe=Math.random().toString(8),Te="__d"+Xe,oe="__a"+Xe,qt=/(PointerCapture)$|Capture$/i,Ze=0,Je=jt(!1),Qe=jt(!0),Bn=0;function zn(e){return{id:e,lane:"work",bucket:"done",repo:"",brief:"",attachments:[],messageAttachments:[],verb:"unknown",log:[],inbox:[],sort:0}}var Yt=new WeakMap;function st(e,t){let s=e.dispatches||[],n=Yt.get(s);return n||Yt.set(s,n=new Map(s.map(r=>[r.id,r]))),{...t,catches:(t.catches||[]).map(r=>n.get(r)??zn(r))}}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 ns(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 rs(e){let t=/^#?report\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return ce(decodeURIComponent(t[1]))}catch{return null}}var is=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 rt=(e,t,s)=>`/attachment/dispatch/${encodeURIComponent(e)}/${encodeURIComponent(t)}/${encodeURIComponent(s)}`,os=(e,t)=>`/attachment/trap/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,as=e=>/\\.(png|jpe?g|gif|webp)$/i.test(e),it=(e,t)=>`/decision/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function ot(e,t){let s=new Map(t.map(r=>[r.key,r])),n=[];for(let r of e)if(r.kind==="decision"){let i=s.get(r.key);if(!i)continue;n.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"&&n.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 n.sort((r,i)=>i.at.localeCompare(r.at)||r.key.localeCompare(i.key))}function ls(e){let t=(e.text??"").split(`\n`).map(s=>s.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 cs(e,t){return(e.reports||[]).find(s=>s.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 es=(e,t)=>+!!e.acked-+!!t.acked||t.filedAt.localeCompare(e.filedAt),ds=e=>`/report/${encodeURIComponent(e)}/md`,at=(e,t)=>`/report/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function ts(e,t,s){return!!e&&s-Date.parse(e)>t}function ss(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 s=t.q.toLowerCase();if(!(e.id+" "+(e.note||"")+" "+(e.brief||"")+" "+(e.repo||"")+" "+(e.for||"")).toLowerCase().includes(s))return!1}return!0}function Q(e,t){if(!t)return null;if(t.type==="helm")return e.helms.find(n=>n.grounds===t.key)||null;if(t.type==="dispatch")return e.dispatches.find(n=>n.lane+":"+n.id===t.key)||null;if(t.type==="pr")return(e.prs||[]).find(n=>n.key===t.key)||null;if(t.type==="report")return(e.reports||[]).find(n=>n.key===t.key)||null;if(t.type==="settings")return{attentionKinds:e.attentionKinds||[],attentionError:e.attentionError};let s=e.traps.find(n=>n.trapId===t.key);return s?st(e,s):null}function ps(e,t,s){let n=t.st,r=String(n.q||"").toLowerCase(),i=(...p)=>!r||p.join(" ").toLowerCase().includes(r),o=p=>({x:p,stale:ts(p.heartbeatAt,18e5,s)}),c=Q(e,t.modal),u=(p,g)=>!!p&&s-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&&ts(e.daemon.heartbeat,9e4,s),helms:e.helms.map(o)},deck:{view:n.view,decisions:ot(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(es),inflight:e.dispatches.filter(p=>p.bucket!=="done"&&ss(p,{...n,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:n.view,chain:n.chain,list:e.dispatches.filter(p=>ss(p,n))},traps:{view:n.view,list:h.filter(p=>(!n.repo||p.repo===n.repo)&&i(p.name,p.trapId,p.repo,p.worktree,p.harness)).map(p=>o(st(e,p)))},prs:{view:n.view,stacks:(e.stacks||[]).filter(p=>!n.repo||p.repo===n.repo),prs:(e.prs||[]).filter(p=>(!n.repo||p.repo===n.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:n.view,list:(e.reports||[]).filter(p=>(!n.repo||p.repo===n.repo)&&i(p.title,p.author,p.dispatch,p.repo)).sort(es)},notices:{list:(e.notices||[]).filter(p=>(!n.repo||!p.repo||p.repo===n.repo)&&(!n.noticeKind||p.kind===n.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:n.view,lobs:n.lobs}:void 0}}}function us(e,t){let s=(e.prs||[]).find(c=>c.key===t);if(!s)return null;let n=(e.stacks||[]).find(c=>c.id===s.stackId),r=new Map((e.dispatches||[]).map(c=>[c.id,c])),i=(s.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=s.watch;return{pr:s,stack:n?{numbers:n.numbers,titles:n.numbers.map(c=>(e.prs||[]).find(u=>u.stackId===n.id&&u.number===c)?.title||""),position:s.position+1,size:n.numbers.length,floor:n.floor,nextNumber:n.nextNumber,nextMergeable:!!s.nextMergeable,blockedBy:s.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 fs(e){return e?{text:e.lastError?"failing":"watching",at:e.lastCheckedAt||null}:{text:"no watch",at:null}}function ms(){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 hs(e){try{localStorage.setItem("spyglass",JSON.stringify(e))}catch{}}function gs(){try{return JSON.parse(localStorage.getItem("spyglass-lob-hidden")||"{}")||{}}catch{return{}}}function vs(e){try{localStorage.setItem("spyglass-lob-hidden",JSON.stringify(e))}catch{}}var pe,_s=new Set,_=()=>pe;function $s(e){pe=e}function G(e){pe={...pe,...e};for(let t of _s)t(pe)}var bs=e=>{_s.add(e)};function lt(e){let{modal:t,drafts:s}=_(),n=new Set(ot(e.attention||[],e.decisions||[]).map(i=>i.key)),r=Object.fromEntries(Object.entries(s).filter(([i])=>n.has(i)));G({snapshot:e,stale:!1,modal:t&&Q(e,t)?t:null,...Object.keys(r).length!==Object.keys(s).length?{drafts:r}:{}}),Ie()}var ks=()=>({text:"",files:[]});function A(e,t){let s=_().drafts;G({drafts:{...s,[e]:{...s[e]??ks(),...t}}})}function ys(e,t){let s=_().drafts[e]?.option;A(e,{option:s===t?void 0:t,error:void 0})}var Xn=e=>new Promise((t,s)=>{let n=new FileReader;n.onload=()=>t(String(n.result).replace(/^data:[^,]*,/,"")),n.onerror=()=>s(n.error),n.readAsDataURL(e)});async function ct(e,t){let s=_().snapshot?.answerLimits,n=[...t??[]],r=_().drafts[e]?.files??[],i=[],o=[];for(let c of n){let u=(/\\.[^.]+$/.exec(c.name)?.[0]??"").toLowerCase();if(s&&!s.extensions.includes(u))i.push(`${c.name}: type not accepted`);else if(s&&c.size>s.maxBytes)i.push(`${c.name}: larger than ${s.maxBytes} bytes`);else if(s&&r.length+o.length>=s.maxFiles)i.push(`${c.name}: at most ${s.maxFiles} files`);else try{o.push({name:c.name,bytes:c.size,data:await Xn(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 Jn={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};async function ws(e,t){let s=[...t.clipboardData?.items??[]],n=new Date().toISOString().replace(/[:.]/g,"-").replace(/-\\d{3}Z$/,"Z"),r=s.filter(i=>i.kind==="file"&&i.type.startsWith("image/")).map(i=>i.getAsFile()).filter(i=>i!==null).map((i,o,c)=>{let u=`pasted-${n}${c.length>1?`-${o+1}`:""}${Jn[i.type]??".png"}`;return new File([i],u,{type:i.type})});r.length&&await ct(e,r)}function Ts(e,t){let s=(_().drafts[e]?.files??[]).filter((n,r)=>r!==t);A(e,{files:s})}async function xs(e){let t=_().snapshot?.focusToken,s=_().drafts[e]??ks();if(!(s.sending||s.sent)){if(!s.option&&!s.text.trim()&&s.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 n=await fetch("/requests",{method:"POST",headers:{"content-type":"application/json","x-lobstah-token":t},body:JSON.stringify({kind:"decision-answer",payload:{key:e,...s.option?{option:s.option}:{},...s.text.trim()?{text:s.text}:{},files:s.files.map(i=>({name:i.name,data:i.data}))}})}),r=await n.json();if(!n.ok||!r.ok){A(e,{sending:!1,error:r.reason??`The answer was refused (${n.status}).`});return}A(e,{sending:!1,sent:ls({option:s.option,text:s.text,files:s.files.length})})}catch{A(e,{sending:!1,error:"The answer could not be sent."})}}}function Ie(){let{snapshot:e,modal:t,reportText:s}=_();if(!e||!t)return;let n=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(!n||s[n.key]?.hash===n.stateHash)return;let r=n.key,i=n.stateHash,o=c=>G({reportText:{..._().reportText,[r]:{hash:i,...c}}});o({}),fetch(ds(r)).then(async c=>c.ok===!1?o({error:`report not found (${c.status})`}):o({text:await c.text()})).catch(()=>o({error:"report could not be read"}))}var Gs=()=>G({stale:!0}),Ss=(e,t)=>G({lightbox:{src:e,name:t}}),ue=()=>G({lightbox:null});function C(e,t){let{snapshot:s}=_(),n={type:e,key:t};G({modal:!s||Q(s,n)?n:null}),Ie()}function Z(){/^#report\\//.test(location.hash)&&history.replaceState(null,"","#deck"),G({modal:null})}async function Cs(e){let t=_().snapshot?.focusToken;if(t)try{let n=await(await fetch(`/api/focus/${encodeURIComponent(e)}`,{method:"POST",headers:{"x-lobstah-focus-token":t}})).json();G({focusResults:{..._().focusResults,[e]:n.message??n.reason??"Window focus failed."}})}catch{G({focusResults:{..._().focusResults,[e]:"Window focus failed."}})}}async function Ds(e,t){let s=_().snapshot?.focusToken;if(!s)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":s},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{lt(await(await fetch("/data")).json())}catch{}}function L(e){let t={..._().prefs,...e};hs(t),G({prefs:t})}function As(e){e!=="table"&&e!=="cards"||L({view:e})}var Rs=e=>L({lobs:e==="on"});function Is(e,t){let s={..._().lobHidden,[e]:t};vs(s),setTimeout(()=>G({lobHidden:s}),0)}async function Ms(e){try{return await navigator.clipboard.writeText(e),!0}catch{return!1}}var Es=function(e,t,s,n){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,s[t[i++]]):t[++i];o===3?n[0]=c:o===4?n[1]=Object.assign(n[1]||{},c):o===5?(n[1]=n[1]||{})[t[++i]]=c:o===6?n[1][t[++i]]+=c+"":o?(r=e.apply(c,Es(e,c,s,["",null])),n.push(r),c[0]?t[0]|=2:(t[i-2]=0,t[i]=r)):n.push(c)}return n},Ps=new Map;function Ls(e){var t=Ps.get(this);return t||(t=new Map,Ps.set(this,t)),(t=Es(this,t.get(e)||(t.set(e,t=(function(s){for(var n,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<s.length;f++){f&&(i===1&&l(),l(f));for(var h=0;h<s[f].length;h++)n=s[f][h],i===1?n==="<"?(l(),u=[u],i=3):o+=n:i===4?o==="--"&&n===">"?(i=1,o=""):o=n+o[0]:c?n===c?c="":o+=n:n===\'"\'||n==="\'"?c=n:n===">"?(l(),i=1):i&&(n==="="?(i=5,r=o,o=""):n==="/"&&(i<5||s[f][h+1]===">")?(l(),i===3&&(u=u[0]),i=u,(u=u[0]).push(2,0,i),i=0):n===" "||n===" "||n===`\n`||n==="\\r"?(l(),i=2):o+=n),i===3&&o==="!--"&&(i=4,u=u[0])}return l(),u})(e)),t),arguments,[])).length>1?t:t[0]}var Ns=e=>Array.isArray(e)?e.map(Ns):e===""?null:e,Qn=(e,t,...s)=>ae(e,t,...s.map(Ns)),a=Ls.bind(Qn);var Pe,k,dt,Hs,pt=0,Vs=[],y=b,Os=y.__b,js=y.__r,Bs=y.diffed,Us=y.__c,Fs=y.unmount,qs=y.__;function Ks(e,t){y.__h&&y.__h(k,e,pt||t),pt=0;var s=k.__H||(k.__H={__:[],__h:[]});return e>=s.__.length&&s.__.push({}),s.__[e]}function Y(e){return pt=1,Zn(Xs,e)}function Zn(e,t,s){var n=Ks(Pe++,2);if(n.t=e,!n.__c&&(n.__=[s?s(t):Xs(void 0,t),function(c){var u=n.__N?n.__N[0]:n.__[0],l=n.t(u,c);u!==l&&(n.__N=[l,n.__[1]],n.__c.setState({}))}],n.__c=k,!k.__f)){var r=function(c,u,l){if(!n.__c.__H)return!0;var f=!1,h=n.__c.props!==c;if(n.__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 n.__N||n.__}function zs(e,t){var s=Ks(Pe++,7);return tr(s.__H,t)&&(s.__=e(),s.__H=t,s.__h=e),s.__}function Yn(){for(var e;e=Vs.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(Me),t.__h.some(ut),t.__h=[]}catch(s){t.__h=[],y.__e(s,e.__v)}}}y.__b=function(e){k=null,Os&&Os(e)},y.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),qs&&qs(e,t)},y.__r=function(e){js&&js(e),Pe=0;var t=(k=e.__c).__H;t&&(dt===k?(t.__h=[],k.__h=[],t.__.some(function(s){s.__N&&(s.__=s.__N),s.u=s.__N=void 0})):(t.__h.some(Me),t.__h.some(ut),t.__h=[],Pe=0)),dt=k},y.diffed=function(e){Bs&&Bs(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Vs.push(t)!==1&&Hs===y.requestAnimationFrame||((Hs=y.requestAnimationFrame)||er)(Yn)),t.__H.__.some(function(s){s.u&&(s.__H=s.u,s.u=void 0)})),dt=k=null},y.__c=function(e,t){t.some(function(s){try{s.__h.some(Me),s.__h=s.__h.filter(function(n){return!n.__||ut(n)})}catch(n){t.some(function(r){r.__h&&(r.__h=[])}),t=[],y.__e(n,s.__v)}}),Us&&Us(e,t)},y.unmount=function(e){Fs&&Fs(e);var t,s=e.__c;s&&s.__H&&(s.__H.__.some(function(n){try{Me(n)}catch(r){t=r}}),s.__H=void 0,t&&y.__e(t,s.__v))};var Ws=typeof requestAnimationFrame=="function";function er(e){var t,s=function(){clearTimeout(n),Ws&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(s,35);Ws&&(t=requestAnimationFrame(s))}function Me(e){var t=k,s=e.__c;typeof s=="function"&&(e.__c=void 0,s()),k=t}function ut(e){var t=k;e.__c=e.__(),k=t}function tr(e,t){return!e||e.length!==t.length||t.some(function(s,n){return s!==e[n]})}function Xs(e,t){return typeof t=="function"?t(e):t}var V=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??""}>${V(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>`,sr=e=>e&&/^https?:\\/\\//i.test(e)?e:void 0,Ne=e=>{let t=e.waiting;if(!t)return;let s=sr(t.link),n=s;try{s&&(n=new URL(s).host+new URL(s).pathname.replace(/\\/$/,""))}catch{n=s}return a`<div class="waiting">${e.verb}: waiting on ${t.on} \xB7 ${v(t.since)}${s&&[" \\xB7 ",a`<a href=${s} target="_blank" rel="noopener noreferrer" onClick=${D}>${n}</a>`]}</div>`},nr=12,Js=e=>e!==void 0&&e.length>nr,N=e=>Js(e)?e:void 0,H=e=>Js(e)?" long":"",w=(e,t)=>()=>C(e,t),D=e=>e.stopPropagation(),rr=e=>e.sessionId?(e.harness==="codex"?"codex resume ":"claude --resume ")+e.sessionId:void 0;function K(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 n=rr(e);return n?a`<span class="dim">Resume: <code onClick=${D}>${n}</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=${n=>{D(n),Cs(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,s){return t.length?a`<div class="wrap"><table><tbody><tr>${e.map(n=>a`<th>${n}</th>`)}</tr>${t}</tbody></table></div>`:a`<div class="empty">${s}</div>`}function ir({text:e}){let[t,s]=Y(null),n=r=>async()=>{await Ms(e)&&(s(r),setTimeout(()=>s(null),1e3))};return a`<div class="cmd"><code class=${t==="code"?"copied":void 0} title="click to copy" onClick=${n("code")}>${e}</code><button title="copy" onClick=${n("button")}>${t==="button"?"\\u2713":"\\u29C9"}</button></div>`}var S=(e,t)=>a`<${ir} key=${t} text=${e} />`,fe=(e,t,s="thumb")=>a`<button\n type="button"\n class=${s}\n title=${"view "+t}\n onClick=${n=>{D(n),Ss(e,t)}}\n >\n <img src=${e} alt=${t} loading="lazy" />\n </button>`,ee=(e,t)=>e.map(s=>[a`<div class="sub">${s.name} \xB7 ${s.type} \xB7 ${s.bytes} bytes</div>`,t&&as(s.name)&&fe(t(s.name),s.name),S(s.path)]),Qs=/\\bwt:([a-z0-9][a-z0-9-]*)/g,ft=e=>_().snapshot?.trapNames?.[e],O=e=>e.replace(Qs,(t,s,n)=>{let r=ft(s);return r&&!Zs(e,n,t.length,r)?r:t}),Zs=(e,t,s,n)=>e.slice(Math.max(0,t-n.length-2),t)===`${n} (`&&e[t+s]===")";function He(e){let t="wt:"+e,s=ft(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)}}>${s}</a>`:a`<span class="trapname" title=${t}>${s}</span>`}var Ee=e=>{let t=/^wt:([a-z0-9][a-z0-9-]*)$/.exec(e);return t?He(t[1]):e};function j(e,t=1/0){let s=[],n=0;for(let c of e.matchAll(Qs)){c.index>n&&s.push({text:e.slice(n,c.index)});let u=ft(c[1]);s.push(u&&Zs(e,c.index,c[0].length,u)?{text:c[0]}:{text:u??c[0],trapId:c[1]}),n=c.index+c[0].length}n<e.length&&s.push({text:e.slice(n)});let r=s.reduce((c,u)=>c+u.text.length,0),i=r>t?t-1:1/0,o=[];for(let c of s){if(i<=0)break;c.text.length<=i?o.push(c.trapId?He(c.trapId):c.text):o.push(c.text.slice(0,i)),i-=c.text.length}return r>t&&o.push("\\u2026"),o}var mt=e=>e.log.flatMap((t,s)=>[s?`\n`:"",t.at+" "+t.verb,...t.note?[" ",...j(t.note)]:[]]);function Ys(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,s=>rt(e.lane,e.id,s))]}${e.messageAttachments.length>0&&[a`<div class="sec">message attachments (${e.messageAttachments.length})</div>`,ee(e.messageAttachments,s=>rt(e.lane,e.id,s))]}${e.followUp&&[a`<div class="sec">forks</div>`,a`<pre>${e.followUp}</pre>`]}<div class="sec">log</div><div class="loglines">${e.log.length?mt(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 s=e.prBadge;return[a`<a href=${t} target="_blank" rel="noopener" onClick=${D}>PR</a>`,s&&[" ",a`<span class=${"badge "+E(s)} title=${"observed "+s.observedAt}>${s.text}</span>`],e.prGate&&[" ",a`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]]}var or={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch"},ht={"pr:review":"bad","pr:checks":"bad","pr:conflict":"pr-conflicts","pr:ready":"ok","pr:draft":"dim",watch:"warn"},en=e=>or[e]||"";var Oe=e=>a`<a href=${e.url} target="_blank" rel="noopener" onClick=${D}>#${e.number}</a>`,je=e=>a`<span class="prname" title=${e.title||void 0}><b>#${e.number}</b>${e.title&&[" ",e.title]}</span>`;function se(e,t,s){return e.flatMap((n,r)=>{let i=t.get(n)||void 0,o=n===s?a`<b title=${i}>#${n}</b>`:a`<span title=${i}>#${n}</span>`;return r?[" \\u2192 ",o]:[o]})}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 Be(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 gt(e){let t=fs(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,s=e.listening??(!!e.firstParkedAt&&!t);return{stale:t,listen:s?[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 vt(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(s=>s.id===e.claimed&&s.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 ar(e){let t=vt(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 tn=e=>e.waiting?`waiting on ${e.waiting.on}`:e.note||"waiting",sn=e=>e.brief.split(/\\r?\\n/,1)[0]?.trim().slice(0,40)||"(no title)";function _e(e){let t=vt(e),s=a`<span class=${"dot trapdot "+ar(e)}></span>`;if(t.kind==="requested")return[s,a`<span class="dim">${nn(e,t.helmOn)}</span>`];if(t.kind==="starting")return[s,"starting \\xB7 waiting for its session to sign on"];if(t.kind==="start failed")return[s,a`<span class="bad">start failed</span>`," \\xB7 ",t.reason];if(t.kind==="signed off")return[s,a`<span class="dim">signed off</span>`];if(t.kind==="idle")return[s,"idle \\xB7 ",t.listening?"listening":"not listening"];let n=t.current;return t.kind==="parked"?[s,"parked \\xB7 ",tn(n)]:[s,"working \\xB7 ",a`<a href="#dispatches" onClick=${i=>{i.preventDefault(),D(i),C("dispatch",`${n.lane}:${n.id}`)}}>${n.id.slice(0,8)}</a>`," \\xB7 ",sn(n),n.activity&&[" \\xB7 ",n.activity.summary," ",v(n.activity.at)," ago"]]}var nn=(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(s=>S(s.command,s.harness))}</div>`:null}function Ue(){let t=_().snapshot?.repoKeys??[],[s,n]=Y(!1),[r,i]=Y(""),[o,c]=Y("claude"),[u,l]=Y(null),f=r||t[0]||"",h=async d=>{d.preventDefault();let m=await Ds(f,o);l(m??null),m||n(!1)};return s?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=${()=>n(!1)}>Cancel</button>\n ${u&&a`<span class="bad">${u}</span>`}\n </form>`:a`<span class="newtrap"><button class="btn" onClick=${d=>(D(d),n(!0),l(null))}>+ New trap</button></span>`}function Fe(e){let t=vt(e);if(t.kind==="requested")return nn(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 ${tn(t.current)}`;let s=t.current;return[`working \\xB7 ${s.id.slice(0,8)} \\xB7 ${sn(s)}`,s.activity&&`${s.activity.summary} ${V(s.activity.at)} ago`].filter(Boolean).join(" \\xB7 ")}function _t(e){let t=e.messages.filter(s=>s.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,`${V(e.filedAt)} ago`,e.acked?"acked":""].filter(Boolean).join(" \\xB7 ")}}function lr(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 cr(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 rn({inp:e}){return e.view==="cards"?e.list.length?a`<div class="cards">${e.list.map(lr)}</div>`:a`<div class="empty">no reports match</div>`:R(["title","from","filed","acked"],e.list.map(cr),"no reports match")}function ln(e){let t=e.trim();return/^(https?:\\/\\/|mailto:|#)/i.test(t)?t:void 0}function cn(e){let t=e.trim();return/^[^/\\\\:?#]+$/.test(t)&&t!=="."&&t!==".."?t:void 0}function on(e,t,s,n){let r=0;for(let i=t;i<e.length;i++){if(e[i]==="\\\\"){i++;continue}if(e[i]===s)r++;else if(e[i]===n){if(r===0)return i;r--}}return-1}function an(e,t){let s=on(e,t+1,"[","]");if(s<0||e[s+1]!=="(")return;let n=on(e,s+2,"(",")");if(n<0)return;let r=e.slice(s+2,n).trim().replace(/\\s+"[^"]*"$/,"").replace(/^<(.*)>$/,"$1");return{text:e.slice(t+1,s),target:r,end:n+1}}function U(e){let t=[],s="",n=()=>{s&&t.push({t:"text",v:s}),s=""};for(let r=0;r<e.length;){let i=e[r];if(i==="\\\\"&&r+1<e.length&&/[\\\\`*_{}[\\]()#+\\-.!|<>~]/.test(e[r+1])){s+=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){n(),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=an(e,r+1);if(o){n(),t.push({t:"img",alt:o.text,src:o.target}),r=o.end;continue}}if(i==="["){let o=an(e,r);if(o){n(),t.push({t:"a",href:o.target,c:U(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){n(),t.push({t:"b",c:U(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]!==" "){n(),t.push({t:"i",c:U(e.slice(r+1,o))}),r=o+1;continue}}if(i===`\n`){/ {2,}$/.test(s)||s.endsWith("\\\\")?(s=s.replace(/( {2,}|\\\\)$/,""),n(),t.push({t:"br"})):s+=" ",r++;continue}s+=i,r++}return n(),t}var dn=/^ {0,3}(`{3,}|~{3,})\\s*([^`\\s]*)/,pn=/^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/,un=/^ {0,3}([-*_])(\\s*\\1){2,}\\s*$/,yt=/^( {0,3})([-*+])\\s+(.*)$/,wt=/^( {0,3})(\\d{1,9})[.)]\\s+(.*)$/,We=/^ {0,3}>\\s?(.*)$/,dr=/^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;function bt(e){let t=e.trim();t.startsWith("|")&&(t=t.slice(1)),t.endsWith("|")&&!t.endsWith("\\\\|")&&(t=t.slice(0,-1));let s=[],n="";for(let r=0;r<t.length;r++)t[r]==="\\\\"&&t[r+1]==="|"?(n+="|",r++):t[r]==="|"?(s.push(n.trim()),n=""):n+=t[r];return s.push(n.trim()),s}var kt=e=>dn.test(e)||pn.test(e)||un.test(e)||yt.test(e)||wt.test(e)||We.test(e);function $e(e){let t=e.replace(/\\r\\n?/g,`\n`).replace(/\\t/g," ").split(`\n`),s=[],n=0;for(;n<t.length;){let r=t[n];if(!r.trim()){n++;continue}let i=dn.exec(r);if(i){let f=i[1],h=[];for(n++;n<t.length&&!new RegExp(`^ {0,3}${f[0]}{${f.length},}\\\\s*$`).test(t[n]);)h.push(t[n++]);n++,s.push({t:"code",lang:i[2]??"",v:h.join(`\n`)});continue}let o=pn.exec(r);if(o){s.push({t:"h",level:o[1].length,c:U(o[2])}),n++;continue}if(un.test(r)){s.push({t:"hr"}),n++;continue}if(We.test(r)){let f=[];for(;n<t.length&&t[n].trim()&&(We.test(t[n])||!kt(t[n]));)f.push(We.exec(t[n])?.[1]??t[n]);s.push({t:"quote",c:$e(f.join(`\n`))}),n+=f.length;continue}let c=yt.exec(r),u=wt.exec(r);if(c||u){let f=!c,h=f?wt:yt,d=[];for(;n<t.length;){let m=t[n],p=h.exec(m);if(p&&p[1].length<=3){d.push([p[3]]),n++;continue}if(!m.trim()){if(n+1<t.length&&/^ {2,}\\S/.test(t[n+1])){d.at(-1).push(""),n++;continue}break}if(/^ {2,}\\S/.test(m)){d.at(-1).push(m.replace(/^ {2,4}/,"")),n++;continue}if(kt(m))break;d.at(-1).push(m.trim()),n++}s.push({t:"list",ordered:f,start:f?Number(u[2]):1,items:d.map(m=>$e(m.join(`\n`)))});continue}if(r.includes("|")&&n+1<t.length&&dr.test(t[n+1])&&t[n+1].includes("-")){let f=bt(r),h=bt(t[n+1]).map(m=>m.startsWith(":")&&m.endsWith(":")?"center":m.endsWith(":")?"right":m.startsWith(":")?"left":"");n+=2;let d=[];for(;n<t.length&&t[n].trim()&&t[n].includes("|");){let m=bt(t[n++]);d.push(f.map((p,g)=>U(m[g]??"")))}s.push({t:"table",align:f.map((m,p)=>h[p]??""),head:f.map(U),rows:d});continue}let l=[];for(;n<t.length&&t[n].trim()&&!kt(t[n])&&!(l.length&&/^ {0,3}(=+|-+)\\s*$/.test(t[n]));)l.push(t[n++].replace(/^ +/,""));if(l.length===0){s.push({t:"p",c:U(r.trim())}),n++;continue}s.push({t:"p",c:U(l.join(`\n`))})}return s}function F(e,t){return t.map(s=>{switch(s.t){case"text":return s.v;case"code":return a`<code>${s.v}</code>`;case"b":return a`<strong>${F(e,s.c)}</strong>`;case"i":return a`<em>${F(e,s.c)}</em>`;case"br":return a`<br />`;case"a":{let n=ln(s.href);return n?a`<a href=${n} target="_blank" rel="noopener noreferrer">${F(e,s.c)}</a>`:F(e,s.c)}case"img":{let n=cn(s.src);return n?fe(e(n),s.alt||n,"mdimg"):a`<span class="dim">[image not shown: ${s.alt||s.src}]</span>`}}})}function Ve(e,t){return t.map(s=>{switch(s.t){case"h":{let n=F(e,s.c);return s.level===1?a`<h1>${n}</h1>`:s.level===2?a`<h2>${n}</h2>`:s.level===3?a`<h3>${n}</h3>`:a`<h4>${n}</h4>`}case"p":return a`<p>${F(e,s.c)}</p>`;case"code":return a`<pre class="mdcode"><code>${s.v}</code></pre>`;case"hr":return a`<hr />`;case"quote":return a`<blockquote>${Ve(e,s.c)}</blockquote>`;case"list":{let n=s.items.map(r=>a`<li>${Ve(e,r)}</li>`);return s.ordered?a`<ol start=${s.start}>${n}</ol>`:a`<ul>${n}</ul>`}case"table":return a`<div class="mdtable"><table><thead><tr>${s.head.map((n,r)=>a`<th style=${s.align[r]?"text-align:"+s.align[r]:void 0}>${F(e,n)}</th>`)}</tr></thead><tbody>${s.rows.map(n=>a`<tr>${n.map((r,i)=>a`<td style=${s.align[i]?"text-align:"+s.align[i]:void 0}>${F(e,r)}</td>`)}</tr>`)}</tbody></table></div>`}})}function pr({r:e,text:t}){let s=t?.text!==void 0?Ve(n=>at(e.key,n),$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}>${s}</div>`}function fn({text:e,fileUrl:t}){return a`<div class="mdpage">${Ve(t,$e(e))}</div>`}function ur(e){let t=de(e);return[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked&&[" \\xB7 ",a`<span class="ok">acked</span>`]]}function Tt({r:e,text:t,heading:s}){return[s&&a`<div class="sec">report \xB7 ${e.title}</div>`,a`<div class="sub">${ur(e)}</div>`,a`<${pr} r=${e} text=${t} />`,e.attachments.length>0&&[a`<div class="sec">report attachments (${e.attachments.length})</div>`,ee(e.attachments,n=>at(e.key,n))],!e.acked&&[a`<div class="sec">ack</div>`,S("lobstah attention ack "+e.key)]]}var fr=/\\.(png|jpe?g|gif|webp)$/i,mr=e=>{e.style.height="auto",e.style.height=e.scrollHeight+"px"};function hr(e,t){return t.length?a`<div class="dfiles">${t.map(s=>fr.test(s.name)?a`<span key=${s.name}>${fe(it(e,s.name),s.name,"dimg")}</span>`:a`<div key=${s.name} class="dfile"><span>${s.name}</span> <span class="dim">\xB7 ${s.type} \xB7 ${s.bytes} bytes \xB7 </span><code>${s.path}</code></div>`)}</div>`:null}function gr(e,t,s){let n=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=${()=>ys(n,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;mr(l),A(n,{text:l.value,error:void 0})}}\n onPaste=${u=>{ws(n,u)}}\n ></textarea>`,a`<div class="dfoot">\n <label class="btn dattach" title="attach images or files">attach<input type="file" multiple accept=${s} disabled=${c} onChange=${u=>{let l=u.currentTarget;ct(n,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=${()=>Ts(n,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=${()=>{xs(n)}}>${c?"Sending\\u2026":"Send"}</button>\n </div>`]}function vr(e,t,s,n){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":"")+(s?" 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:j(e.note)}</b>\n <span class="dmeta dim">${c}</span>\n </div>\n ${e.kind==="decision"&&e.detail.trim()&&a`<${fn} text=${e.detail} fileUrl=${l=>it(e.key,l)} />`}\n ${e.kind==="decision"&&hr(e.key,e.attachments)}\n ${t?.sent?a`<div class="danswered ok">answered \xB7 ${t.sent}</div>`:gr(e,t,n)}\n </div>`}function mn({cards:e,drafts:t,focus:s,extensions:n}){let r=n.join(","),i=e.length?a`<div class="dcards">${e.map(o=>vr(o,t[o.key],o.key===s,r))}</div>`:a`<div class="empty">none</div>`;return a`<section class="decisions"><h2>decisions</h2>${i}</section>`}function kr(e,t){let s=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>${s}</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}>${s&&[s," "]}<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 hn=(e,t)=>e>0&&a`<a class="deckmore" href=${"#"+t}>+${e} more \u2192</a>`;function Ke(e,t,s,n,r,i){let o=t.slice(0,n),c=o.map(l=>kr(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=${"#"+s}>${e} \u2192</a></h2>${i&&a`<div class="tabhead">${i}</div>`}${u}${hn(t.length-o.length,s)}</section>`}function yr(e,t,s,n){let r=t.find(l=>l.number===e.nextNumber)||t[0],i=se(e.numbers,new Map(t.map(l=>[l.number,l.title]))),o=r?"next #"+r.number:"nothing mergeable";if(n==="cards"){let l=f=>{let h=s.get(f.key)||[],d=h.length>0&&h.every(g=>g.acked),m=h.length?h.map(g=>a`<span class=${"badge "+(ht[g.kind]||"dim")}>${en(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">${je(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=>(s.get(l.key)||[]).map(f=>a`<span class=${"badge "+(ht[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>${i}</b> <span class="dim">\xB7 ${o}</span>${c.length>0&&[" \\xB7 ",u]}</div>`}function wr(e,t){let s=e.stacks.slice(0,3),n=new Map;for(let i of e.prAttention){let o=n.get(i.key)||[];o.push(i),n.set(i.key,o)}let r=s.length?s.map(i=>yr(i,e.prs.filter(o=>o.stackId===i.id).sort((o,c)=>o.position-c.position),n,t)):a`<div class="empty">none</div>`;return a`<section><h2><a href="#prs">PRs \u2192</a></h2>${r}${hn(e.stacks.length-s.length,"prs")}</section>`}function gn({inp:e,drafts:t,focus:s,extensions:n}){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:[j(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&&`${V(l.verbAt)} ago`,O(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:[j(l.note||"",90)," \\xB7 ",v(l.at)," ago"],metaText:`${O(l.note||"")} \\xB7 ${V(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:K(l),extra:z(l),open:w("trap",l.trapId)}));return a`<div class="deckgrid"><${mn} cards=${e.decisions} drafts=${t} focus=${s} extensions=${n} />${Ke("in flight",i,"dispatches",4,r)}${Ke("Landed \\xB7 24h",o,"dispatches",8,r)}${Ke("reports",c,"reports",8,r)}${Ke("traps",u,"traps",8,r,a`<${Ue} />`)}${wr(e,r)}</div>`}function Tr(e,t){if(!t)return e;let s=new Map(e.map(i=>[i.id,i])),n=i=>{let o=i,c=new Set;for(;o.followUp&&s.has(o.followUp)&&!c.has(o.id);)c.add(o.id),o=s.get(o.followUp);return o.id},r=new Map;for(let i of e){let o=n(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===n(o)?-1:c.id===n(c)?1:o.sort-c.sort))}function xr(e,t){let s=e.lane+":"+e.id;return a`<tr key=${s} class="rowhead" onClick=${w("dispatch",s)}><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">${j(e.note??"",90)}${Ne(e)}${Le(e)}</td><td>${v(e.verbAt)}</td><td>${me(e)}</td><td>${te(e)}</td></tr>`}function Gr(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)}>${j(e.note)}</div>`}${Ne(e)}${Le(e)}<div class="foot">${me(e)} ${te(e)}</div></div>`}function vn({inp:e}){let t=e.list;return e.view==="cards"?t.length?a`<div class="cards">${t.map(Gr)}</div>`:a`<div class="empty">no dispatches match</div>`:R(["id","lane / bucket","repo","verb","note","age","addressed","pr"],Tr(t,e.chain).map(s=>xr(s,e.chain)),"no dispatches match")}var Sr={deck:"On deck",dispatches:"Dispatches",traps:"Traps",prs:"PRs",reports:"Reports",notices:"Notices"},Cr=["working","needs-decision","blocked","paused","done","failed","unknown"];function Dr(e,t){let s=t.daemonStale,n=e.daemon?[a`<span class=${s?"bad":"ok"}>${s&&"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 ${n}</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 xt=[];function Ar(e){let t=[...new Set([...e.dispatches.map(s=>s.repo),...e.notices.map(s=>s.repo),...e.prs.map(s=>s.repo)].filter(Boolean))].sort();return t.length!==xt.length&&(xt=t),xt}var Gt=[];function Rr(e){let t=[...new Set(e.notices.map(s=>s.kind))].sort();return t.length!==Gt.length&&(Gt=t),Gt}var be=e=>e.currentTarget.value;function Ir(e,t,s){let n=o=>t===o?"":"display:none",r=e?Ar(e):[],i=e?Rr(e):[];return a`<div class="controls">\n <select id="f-lane" style=${e&&n("dispatches")} value=${s.lane} onChange=${o=>L({lane:be(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=${s.repo} onChange=${o=>L({repo:be(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&&n("dispatches")} value=${s.verb} onChange=${o=>L({verb:be(o)})}>\n <option value="">all verbs</option>\n ${Cr.map(o=>a`<option key=${o}>${o}</option>`)}\n </select>\n <label id="chain-control" style=${e&&n("dispatches")}><input id="f-chain" type="checkbox" checked=${!!s.chain} onChange=${o=>L({chain:o.currentTarget.checked})} /> group by chain</label>\n <select id="f-kind" style=${e&&n("notices")} value=${s.noticeKind} onChange=${o=>L({noticeKind:be(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=${s.q} onInput=${o=>L({q:be(o)})} />\n </div>`}function _n({d:e,inp:t,tab:s,st:n,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&&Dr(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(i=>a`<a href=${"#"+i} data-tab=${i} class=${e?i===s?"on":"":void 0}>${Sr[i]}</a>`)}</nav>`,Ir(e,s,n)]}var $n=({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 bn(e,t){if(!t.lobs)return[];let s={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch",report:"report"},n=t.hidden??{},r=e.filter(o=>!o.acked&&!(o.key!==void 0&&n[o.key]===o.stateHash)).map(o=>{let c=s[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:is(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:o.kind==="report"&&o.key?ce(o.key):{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 kn=!0;function Mr(e,t,s){let n="animation-duration:"+((innerWidth+180)/(100+t*12)).toFixed(1)+"s;animation-delay:-"+t*9%14+"s",r=()=>{e.hideKey&&Is(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>`,s===!1?a`<span class="fallback">\u{1F99E}</span>`:a`<div class="sprite"></div>`,kn&&a`<img\n class="star"\n src="/star.png"\n alt=""\n onError=${c=>{kn=!1,c.currentTarget.remove()}}\n />`],o=e.open;return e.hash?a`<a key=${e.key} class="lob" style=${n} title="open the decision" href=${e.hash} onClick=${r}>${i}</a>`:e.href?a`<a key=${e.key} class="lob" style=${n} title="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=${n}\n title="click to open"\n onClick=${()=>{r(),o&&C(o.type,o.key)}}\n >\n ${i}\n </div>`}function yn({state:e}){let t=e.snapshot,s=bn(t?.attention||[],{lobs:e.prefs.lobs,hidden:e.lobHidden,preview:e.preview,previewHelm:t&&t.helms.length?t.helms[0].grounds:void 0}),n=s.map(r=>r.key).join("|")+(e.spriteOk===null?"?":e.spriteOk?"s":"e");return zs(()=>s.map((r,i)=>Mr(r,i,e.spriteOk)),[n])}function wn({box:e}){if(!e)return null;let t=s=>{s.target===s.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 ne=a`<span class="x" onClick=${Z}>\xD7</span>`,Tn=(e,t,s)=>a`<span class="seg">${t.map(([n,r])=>a`<button class=${n===s?"on":""} onClick=${()=>e(n)}>${r}</button>`)}</span>`;function Pr(e,t){let s=Tn(As,[["table","table"],["cards","cards"]],t.view),n=Tn(Rs,[["on","on"],["off","off"]],t.lobs?"on":"off"),r=e.attentionError?e.attentionError:(e.attentionKinds||[]).join(" \\xB7 ");return[ne,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>${s}</div><div class="row"><span class="lbl">lobs<span class="hint">crawling lobsters in this page</span></span>${n}</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 Er(e,t){let s=se(t.numbers,new Map(t.numbers.map((r,i)=>[r,t.titles[i]])),e.number),n=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[s," \\xB7 ",t.position," of ",t.size," \\xB7 floor ",t.floor,n]}var Lr=e=>t=>{t.preventDefault(),C("dispatch",e)};function Nr(e,t){let s=us(e,t),n=s.pr,r=s.stack,i=s.watch,o=Be(n),c=s.chain.length?s.chain.flatMap((l,f)=>[f?" \\u2192 ":"",l.culled?a`<span class="dim">${l.id.slice(0,8)} (culled)</span>`:[a`<a href="#" onClick=${Lr(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 ${n.url}</code> registers one</div>`;return[ne,a`<h3>${Oe(n)} ${n.title||""} <span class=${"badge "+E(n.badge)}>${n.badge.text}</span>${n.draft&&n.badge.text!=="draft"&&[" ",a`<span class="badge pr-draft">draft</span>`]}</h3>`,a`<div class="sub">${n.repo} \xB7 ${n.state} \xB7 observed ${v(n.observedAt)} ago${n.gate&&" \\xB7 gate "+n.gate}</div>`,a`<div class="sec">checks</div><div>${he(n)}</div><div class="sec">review</div><div>${o||a`<span class="dim">no review yet</span>`}</div><div class="sec">merge</div><div>${ge(n)}</div>${n.repairWait&&a`<div class="sec">repair waits</div><div>${n.repairWait.heldBy}: ${n.repairWait.reason}${n.repairWait.until?" \\xB7 until "+n.repairWait.until:""}</div>`}<div class="sec">refs</div><div>${n.headRefName||"?"} \u2192 ${n.baseRefName||"?"}</div><div class="sec">stack</div><div>${r?Er(n,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 xn=(e,t)=>(e==="codex"?"codex resume ":"claude --resume ")+t;function Hr(e){let t=Date.now()-Date.parse(e.heartbeatAt)>18e5;return[ne,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(xn(e.harness,e.sessionId))],e.transcript&&[a`<div class="sec">transcript</div>`,S(e.transcript)]]}function Or(e,t){return[ne,a`<h3>\u{1F4C4} ${e.title}</h3>`,a`<${Tt} r=${e} text=${t} />`]}function jr(e,t,s){let n=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>`,S(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>`,S("lobstah attach "+e.id)];return[ne,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>`,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&&a`<${Tt} r=${t} text=${s} heading=${!0} />`,Ys(e)]}function Br(e){let t=ve(e),s=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.",n=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?ee(o.attachments,c=>os(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>${te(o)}</div><div class="loglines">${mt(o)}</div></div>`):a`<div class="empty">none yet</div>`;return[ne,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">${s}</div>`,a`<div class="sec">window</div>`,K(e),z(e),e.live&&e.sessionId&&[a`<div class="sec">open this session</div>`,S(xn(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>`,n,a`<div class="sec">messages (${e.messages.length})</div>`,r,a`<div class="sec">catches (${e.catches.length})</div>`,i]}function Gn({snapshot:e,modal:t,prefs:s,reportText:n}){if(!e||!t)return null;let r=Q(e,t);if(!r)return null;if(t.type==="settings")return Pr(r,s);if(t.type==="pr")return Nr(e,t.key);if(t.type==="helm")return Hr(r);if(t.type==="report")return Or(r,n[t.key]);if(t.type==="dispatch"){let i=cs(e,r);return jr(r,i,i&&n[i.key])}return Br(r)}var Ur=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>`,Sn=({inp:e})=>R(["at","kind","text","repo"],e.list.map(Ur),"no notices");function Cn(e){let t=new Map;for(let s of e.prs){let n=t.get(s.stackId)||[];n.push(s),t.set(s.stackId,n)}return e.stacks.map(s=>({s,prs:t.get(s.id)||[]})).filter(s=>s.prs.length)}var Dn=(e,t)=>se(e.numbers,new Map(t.map(s=>[s.number,s.title]))),St=e=>e.state+(e.draft?" \\xB7 draft":"")+(e.state==="MERGED"&&e.mergedAt?" \\xB7 "+e.mergedAt:"");function An(e){let t=n=>{let r=String(n??"");return r.length>24?r.slice(0,23)+"\\u2026":r},s=e.watches.map(n=>a`<tr key=${n.key}><td>${n.key}</td><td>${n.owner}</td><td title=${n.cursor}>${t(n.cursor)}</td><td>${n.lastCheckedAt&&v(n.lastCheckedAt)}</td><td>${n.lastError||""}</td></tr>`);return[a`<h2>other watches</h2>`,R(["key","owner","cursor","last check","error"],s,"no other watches")]}function Fr(e){let t=Cn(e).flatMap(({s,prs:n})=>[a`<tr key=${"stack:"+s.id}><th colspan="8">${Dn(s,n)} \xB7 floor ${s.floor}${s.open?" \\xB7 open":" \\xB7 history"}</th></tr>`,...n.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>${Be(r)}</td><td>${ge(r)}</td><td>${gt(r.watch)}</td><td>${r.gate||""}</td></tr>`)]);return[R(["PR","title","state","checks","review","merge","watch","gate"],t,"no PR evidence"),An(e)]}function qr(e){let t=Cn(e),s=r=>a`<div key=${r.key} class="card" onClick=${w("pr",r.key)}><div class="top">${je(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>${gt(r.watch)}</span>${r.gate&&a`<span>gate ${r.gate}</span>`}</div></div>`;return[t.length?t.map(({s:r,prs:i})=>a`<${J} key=${"stack:"+r.id}><h2>${Dn(r,i)} \xB7 floor ${r.floor}${r.open?"":" \\xB7 history"}</h2><div class="cards">${i.map(s)}</div><//>`):a`<div class="empty">no PR evidence</div>`,An(e)]}var Rn=({inp:e})=>e.view==="cards"?qr(e):Fr(e);var Ct=e=>e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??(e.live?"":"signed off"),In=e=>e.live||e.starting?"":" dim";function Wr(e){let t=ve(e);return a`<tr key=${e.trapId} class=${"rowhead"+In(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>${_t(e)}</td><td>${e.catches.length}</td><td>${K(e)}</td></tr>`}function Vr(e){let t=ve(e),s=_t(e),n=`${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"+In(e)} onClick=${w("trap",e.trapId)}><div class="top"><b>\u{1FAA4} ${e.label??`wt:${e.trapId}`}</b><span class=${"badge"+H(Ct(e))} title=${N(Ct(e))}>${Ct(e)}</span></div><div class="meta" title=${n}>${n}</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"}${s&&[" \\xB7 ",s]}</span><span class="footact">${K(e)}</span></div></div>`}function Mn({inp:e}){let t=e.list.map(n=>n.x),s=a`<div class="tabhead"><${Ue} /></div>`;return e.view==="cards"?[s,t.length?a`<div class="cards">${t.map(Vr)}</div>`:a`<div class="empty">no traps soaking</div>`]:[s,R(["address","repo","worktree","harness","session","now","listening","heartbeat","mail","catches","window"],t.map(Wr),"no traps soaking")]}function Pn({state:e}){let t=e.snapshot,s=e.route,n=t&&ps(t,{st:e.prefs,modal:e.modal},Date.now()),r=o=>!n||o!==s?null:o==="deck"?a`<${gn} inp=${n.deck} drafts=${e.drafts} focus=${e.focusDecision} extensions=${t?.answerLimits?.extensions??[]} />`:o==="dispatches"?a`<${vn} inp=${n.dispatches} />`:o==="traps"?a`<${Mn} inp=${n.traps} />`:o==="prs"?a`<${Rn} inp=${n.prs} />`:o==="reports"?a`<${rn} inp=${n.reports} />`:a`<${Sn} inp=${n.notices} />`,i=o=>{o.target===o.currentTarget&&Z()};return[a`<${_n} d=${t} inp=${n} tab=${s} st=${e.prefs} stale=${e.stale} />`,le.map(o=>a`<main key=${o} id=${"page-"+o} class=${t&&o===s?"tabpage on":"tabpage"}><div id=${o}>${r(o)}</div></main>`),a`<footer id="foot"><${$n} d=${t} /></footer>`,a`<div id="lobs"><${yn} state=${e} /></div>`,a`<${wn} box=${e.lightbox} />`,a`<div id="overlay" class=${e.modal&&t?"open":t?"":void 0} onClick=${i}><div class="modal" id="modalbox"><${Gn} snapshot=${t} modal=${e.modal} prefs=${e.prefs} reportText=${e.reportText} /></div></div>`]}var Dt=!1,ke=null;async function At(){if(!Dt){Dt=!0;try{let e=await fetch("/data");if(!e.ok)throw new Error(`/data answered ${e.status}`);lt(await e.json())}catch{Gs()}finally{Dt=!1}}}var En=()=>{ke||(ke=setInterval(At,2e3))},Kr=()=>{ke&&clearInterval(ke),ke=null};function Ln(){document.addEventListener("visibilitychange",()=>{document.hidden?Kr():(At(),En())}),At(),document.hidden||En()}var Rt=()=>ns(location.hash),It=()=>rs(location.hash),Nn=e=>window.addEventListener("hashchange",()=>e(Rt()));$s({snapshot:void 0,route:Rt(),prefs:ms(),modal:It(),stale:!1,lobHidden:gs(),spriteOk:null,focusResults:{},preview:new URLSearchParams(location.search).has("lob"),reportText:{},drafts:{},focusDecision:nt(location.hash),lightbox:null});var Hn,Mt=!1,On=()=>{let e=_(),t=e.route!==Hn||!Mt&&!!e.snapshot;Zt(ae(Pn,{state:e}),document.body),Hn=e.route,Mt||(Mt=!!e.snapshot),t&&window.scrollTo(0,0),zr(e.focusDecision)},Pt=null;function zr(e){if(!e||e===Pt)return;let t=[...document.querySelectorAll("[data-decision]")].find(s=>s.getAttribute("data-decision")===e);t&&(Pt=e,t.scrollIntoView?.({block:"center"}))}bs(On);On();var Et=new Image;Et.onload=()=>G({spriteOk:!0});Et.onerror=()=>G({spriteOk:!1});Et.src="/lob-sprite.png";Nn(e=>{let t=It(),s=nt(location.hash);s!==_().focusDecision&&(Pt=null),G(t?{route:e,modal:t,focusDecision:s}:{route:e,focusDecision:s}),t&&Ie()});document.addEventListener("keydown",e=>{e.key==="Escape"&&(_().lightbox?ue():Z())});Ln();})();</script>\n </body>\n</html>\n';
13504
+ 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';
13244
13505
 
13245
13506
  // apps/cli/src/glass-snapshot-thread.ts
13246
13507
  init_dist2();
@@ -13389,7 +13650,7 @@ async function focusRegistration(reg, options = {}) {
13389
13650
  return { focused: false, reason: "Invalid recorded WezTerm pane." };
13390
13651
  if (win?.bundleId && VSCODE_RE.test(win.bundleId) && !safeWorktree(reg))
13391
13652
  return { focused: false, reason: "Recorded editor worktree does not match this trap." };
13392
- if (validSessionLink(reg.link)) {
13653
+ if (validSessionLink(reg.link) && linkMismatch(reg.link, win) === void 0) {
13393
13654
  const opener = platform === "darwin" ? ["open", [reg.link]] : platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", reg.link]] : ["xdg-open", [reg.link]];
13394
13655
  const result = await attempt(opener[0], opener[1], "link", "Opened the session link.");
13395
13656
  if (result) return result;
@@ -13585,6 +13846,9 @@ function attentionSnapshot() {
13585
13846
  return { attention: [], landed: [], attentionKinds: [], attentionError: err instanceof Error ? err.message : String(err) };
13586
13847
  }
13587
13848
  }
13849
+ function reportRow(key) {
13850
+ return reportRows2().find((r) => r.key === key);
13851
+ }
13588
13852
  function reportRows2() {
13589
13853
  return listReports().map((r) => {
13590
13854
  const acked = reportAck(r);
@@ -13606,6 +13870,7 @@ function reportRows2() {
13606
13870
  };
13607
13871
  });
13608
13872
  }
13873
+ var REPORT_PAGE_RE = /^\/report\/([^/?#]+)(\/meta)?\/?$/;
13609
13874
  var REPORT_IMAGE_TYPES = {
13610
13875
  ".png": "image/png",
13611
13876
  ".jpg": "image/jpeg",
@@ -13751,7 +14016,9 @@ function buildGlassSnapshot(options = {}) {
13751
14016
  ...t,
13752
14017
  name,
13753
14018
  label: trapLabel({ trapId: t.trapId, name }),
13754
- link: validSessionLink(t.link) ? t.link : void 0,
14019
+ // A link that contradicts the trap's window (a vscode:// link on a
14020
+ // terminal session) is not shown; focus falls back to the window.
14021
+ link: validSessionLink(t.link) && linkMismatch(t.link, t.window) === void 0 ? t.link : void 0,
13755
14022
  sessionId: t.sessionId ?? signed?.by,
13756
14023
  harness: t.harness ?? /\((claude|codex),/.exec(signed?.text ?? "")?.[1],
13757
14024
  live: registered,
@@ -13969,6 +14236,27 @@ function serveGlass(port, options = {}) {
13969
14236
  res.writeHead(200, { "content-type": "image/svg+xml", "cache-control": "no-cache" });
13970
14237
  res.end(fallbackIcon);
13971
14238
  }
14239
+ } else if (req.method === "GET" && REPORT_PAGE_RE.test(req.url?.split("?")[0] ?? "")) {
14240
+ if (req.headers.host !== ownHost()) {
14241
+ res.writeHead(403, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" });
14242
+ res.end("Not this glass.");
14243
+ return;
14244
+ }
14245
+ const m = REPORT_PAGE_RE.exec(req.url.split("?")[0]);
14246
+ let key;
14247
+ try {
14248
+ key = decodeURIComponent(m[1]);
14249
+ } catch {
14250
+ key = "";
14251
+ }
14252
+ const row = key ? reportRow(key) : void 0;
14253
+ if (m[2] === "/meta") {
14254
+ res.writeHead(row ? 200 : 404, { "content-type": "application/json", "cache-control": "no-store" });
14255
+ res.end(JSON.stringify(row ?? { error: "report not found" }));
14256
+ return;
14257
+ }
14258
+ res.writeHead(row ? 200 : 404, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
14259
+ res.end(PAGE);
13972
14260
  } else if ((req.url?.startsWith("/report/") || req.url?.startsWith("/decision/")) && req.method === "GET" && serveReport(req.url, res)) {
13973
14261
  return;
13974
14262
  } else if (req.url?.startsWith("/attachment/") && req.method === "GET" && serveAttachment(req.url, res)) {
@@ -14058,7 +14346,7 @@ async function awaitHeartbeat(sinceMs, oldPid, timeoutMs = RESTART_WAIT_MS) {
14058
14346
  }
14059
14347
  return void 0;
14060
14348
  }
14061
- function pidAlive3(pid) {
14349
+ function pidAlive4(pid) {
14062
14350
  try {
14063
14351
  process.kill(pid, 0);
14064
14352
  return true;
@@ -14071,7 +14359,7 @@ function daemonStatus(installed, now2 = Date.now()) {
14071
14359
  const hb = readHeartbeat();
14072
14360
  const ageSecs = hb ? Math.max(0, Math.round((now2 - (Date.parse(hb.heartbeat) || 0)) / 1e3)) : void 0;
14073
14361
  const fresh = ageSecs !== void 0 && ageSecs * 1e3 < HEARTBEAT_STALE_MS3;
14074
- const running = fresh && (hb?.pid === void 0 || pidAlive3(hb.pid));
14362
+ const running = fresh && (hb?.pid === void 0 || pidAlive4(hb.pid));
14075
14363
  const parked = parkedDispatches(now2);
14076
14364
  const cfg = loadConfig();
14077
14365
  const work = slotUsage("work");
@@ -14305,6 +14593,7 @@ function observePr(ref, view, opts = {}) {
14305
14593
  if (id && lane) mergeEvidence(id, lane, { pr });
14306
14594
  const was = before?.state ?? legacyBefore?.state;
14307
14595
  const terminal3 = pr.state === "MERGED" || pr.state === "CLOSED";
14596
+ if (terminal3) cancelQueuedRepairs(ref.key);
14308
14597
  const endedAt = Date.parse(view.mergedAt ?? view.closedAt ?? "");
14309
14598
  const recentEnd = Number.isFinite(endedAt) && now2.getTime() - endedAt <= FIRST_SIGHT_NOTICE_MS;
14310
14599
  if (terminal3 && (was === "OPEN" || was === void 0 && recentEnd)) {
@@ -14321,6 +14610,15 @@ function observePr(ref, view, opts = {}) {
14321
14610
  }
14322
14611
  return after;
14323
14612
  }
14613
+ function cancelQueuedRepairs(key) {
14614
+ const cancelled = [];
14615
+ for (const id of pendingIds("chore")) {
14616
+ const d = queuedDescriptor(id, "chore");
14617
+ if (!d?.systemRepair || !d.pr?.url || parsePrRef(d.pr.url)?.key !== key) continue;
14618
+ if (cancelQueued(id, "chore")) cancelled.push(id);
14619
+ }
14620
+ return cancelled;
14621
+ }
14324
14622
  function rawConfig() {
14325
14623
  try {
14326
14624
  return parse(fs64.readFileSync(configPath(), "utf8"));
@@ -14792,6 +15090,7 @@ var COMMANDS = {
14792
15090
  "--option": { value: "<label>", repeatable: true },
14793
15091
  "--attach": { value: "<file>", repeatable: true },
14794
15092
  "--withdraw": { value: "<key>" },
15093
+ "--replace": { value: "<key>" },
14795
15094
  "--grounds": { value: "<name>" },
14796
15095
  "--session": { value: "<id>" }
14797
15096
  },
@@ -14927,7 +15226,7 @@ work in flight requires a live watcher or the hook blocks with the arm command.
14927
15226
  --attach copies images the page names by bare filename; --title overrides its first # heading.
14928
15227
  The glass shows it on the deck; \`lobstah attention ack <key>\` acks it.`,
14929
15228
  "man:ask": `Put a decision to the human: a card in the glass (decisions/<rid>/) until
14930
- answered or withdrawn. A newer ask on the same dispatch replaces it. The answer
15229
+ answered or withdrawn. Asks stand side by side; --replace <key> replaces one. The answer
14931
15230
  wakes man wait as decision-answer. Reserved for the claimed helm.`,
14932
15231
  "man:answer": `Answer a decision (or a raw question's <lane>:<id>) as the glass does.
14933
15232
  Stores the answer; the helm's man wait receives it as decision-answer.`,
@@ -15258,11 +15557,12 @@ lobstah man (orchestrator sessions \u2014 bare \`lobstah man\` prints the manual
15258
15557
  man file <file.md> [--attach <file> ...] [--title <text>]
15259
15558
  file the helm's own report under its
15260
15559
  grounds; the glass renders it on the deck.
15261
- man ask [<dispatch-id>] --title <q> [--detail <f.md>] [--option <label> ...] [--attach <file> ...]
15560
+ man ask [<dispatch-id>] --title <q> [--detail <f.md>] [--option <label> ...] [--attach <file> ...] [--replace <key>]
15262
15561
  put a decision to the human: a card in the
15263
15562
  glass until answered or withdrawn
15264
- (--withdraw <key>). The answer wakes man
15265
- wait as a decision-answer event.
15563
+ (--withdraw <key>). Asks stand side by side;
15564
+ --replace <key> replaces one. The answer
15565
+ wakes man wait as a decision-answer event.
15266
15566
  man answer <key> [--option <label>] [--text <text>] [--attach <file> ...]
15267
15567
  answer a decision from the terminal.
15268
15568
  man helm [--session <id>] [--grounds <name>] [--take] [--harness claude|codex]
@@ -15549,7 +15849,7 @@ function liveChainMember(member) {
15549
15849
  if (isParked(member.id, member.lane)) return true;
15550
15850
  try {
15551
15851
  const runner = JSON.parse(fs72.readFileSync(path59.join(dir, "runner.json"), "utf8"));
15552
- return pidAlive(runner.pid, runner.processStartTime);
15852
+ return pidAlive2(runner.pid, runner.processStartTime);
15553
15853
  } catch {
15554
15854
  return false;
15555
15855
  }
@@ -16015,6 +16315,19 @@ ${text}`, from);
16015
16315
  ${usageFor("report")}`);
16016
16316
  }
16017
16317
  }
16318
+ if (verb === "done") {
16319
+ const unread = unhandled(id, lane);
16320
+ if (unread.length > 0) {
16321
+ for (const m of unread) {
16322
+ console.log(`--- message ${m.file}`);
16323
+ console.log(m.text);
16324
+ acknowledge(id, lane, m.file);
16325
+ }
16326
+ throw new Error(
16327
+ `not reported done: ${unread.length} unread message(s) for ${id} arrived while you worked. They are printed above and now marked read. Act on them, then report done again.`
16328
+ );
16329
+ }
16330
+ }
16018
16331
  const reportFile = opt("--report");
16019
16332
  const attachFiles = values("--attach");
16020
16333
  if (reportFile !== void 0 && verb !== "done" && verb !== "failed")
@@ -16151,7 +16464,7 @@ ${usageFor("report")}`);
16151
16464
  const runnerFile = path59.join(activeDir, "runner.json");
16152
16465
  if (fs72.existsSync(runnerFile)) {
16153
16466
  const runner = JSON.parse(fs72.readFileSync(runnerFile, "utf8"));
16154
- if (pidAlive(runner.pid, runner.processStartTime)) killGroup(runner.pid, "SIGKILL");
16467
+ if (pidAlive2(runner.pid, runner.processStartTime)) killGroup(runner.pid, "SIGKILL");
16155
16468
  fs72.unlinkSync(runnerFile);
16156
16469
  }
16157
16470
  appendStatus(id, lane, "working", `swapped to ${descriptor.harness ?? "default"} \u2014 awaiting respawn`);
@@ -16324,6 +16637,7 @@ ${usageFor("man:ask")}`);
16324
16637
  ...repo ? { repo } : {},
16325
16638
  ...grounds ? { grounds } : {},
16326
16639
  askedBy: "helm",
16640
+ ...opt("--replace") !== void 0 ? { replace: opt("--replace") } : {},
16327
16641
  maxBytes: loadConfig().limits.attachmentMaxBytes
16328
16642
  });
16329
16643
  } catch (err) {
@@ -16948,6 +17262,9 @@ ${usageFor("soak")}`
16948
17262
  ...reservation ? { trapId: reservation.trapId } : {}
16949
17263
  }) : void 0;
16950
17264
  if (made) worktree = canon(made.dir);
17265
+ const window = captureWindow();
17266
+ const linkFlag = opt("--link");
17267
+ const linkIgnored = linkFlag !== void 0 ? linkMismatch(linkFlag, window) : void 0;
16951
17268
  let res;
16952
17269
  try {
16953
17270
  res = signOnTrap({
@@ -16958,8 +17275,8 @@ ${usageFor("soak")}`
16958
17275
  sessionId,
16959
17276
  one: has("--one") || void 0,
16960
17277
  name: opt("--name"),
16961
- window: captureWindow(),
16962
- link: opt("--link"),
17278
+ window,
17279
+ link: linkIgnored ? void 0 : linkFlag,
16963
17280
  ...reservation ? { trapId: reservation.trapId } : {},
16964
17281
  ttlMs: cfg.soak.ttlSecs * 1e3
16965
17282
  });
@@ -16992,6 +17309,7 @@ ${usageFor("soak")}`
16992
17309
  repo: reg.repo ?? "(none configured \u2014 addressed work only)",
16993
17310
  worktree: reg.worktree,
16994
17311
  ...made ? { created: true, branch: made.branch } : {},
17312
+ ...linkIgnored ? { link: `ignored \u2014 ${linkIgnored}` } : {},
16995
17313
  ...reservation ? { ticket: `redeemed \u2014 signed on as the reserved trap` } : {},
16996
17314
  ...titled?.named ? { terminal: `tab named ${reg.name}` } : {},
16997
17315
  ...reg.one ? { one: true } : {},