lobstah 0.6.7 → 0.6.9
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 +469 -413
- package/dist/runner.js +7 -8
- package/docs/configuration.md +1 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1943,6 +1943,7 @@ var init_config = __esm({
|
|
|
1943
1943
|
DEFAULT_ATTENTION_KINDS = ["question", "decision", "pr:ready", "pr:review", "pr:conflict", "pr:checks"];
|
|
1944
1944
|
DEFAULT_SOAK = {
|
|
1945
1945
|
deferSecs: 90,
|
|
1946
|
+
claimIdleNoticeSecs: 180,
|
|
1946
1947
|
ttlSecs: 1800,
|
|
1947
1948
|
beat: true,
|
|
1948
1949
|
pausedTtlSecs: 86400,
|
|
@@ -2387,253 +2388,9 @@ var init_watch = __esm({
|
|
|
2387
2388
|
}
|
|
2388
2389
|
});
|
|
2389
2390
|
|
|
2390
|
-
// packages/core/dist/
|
|
2391
|
+
// packages/core/dist/activity.js
|
|
2391
2392
|
import * as fs11 from "node:fs";
|
|
2392
2393
|
import * as path11 from "node:path";
|
|
2393
|
-
function helmDir() {
|
|
2394
|
-
return path11.join(lobstahHome(), "helm");
|
|
2395
|
-
}
|
|
2396
|
-
function relievedDir() {
|
|
2397
|
-
return path11.join(helmDir(), ".relieved");
|
|
2398
|
-
}
|
|
2399
|
-
function helmPath(grounds) {
|
|
2400
|
-
return path11.join(helmDir(), `${grounds}.json`);
|
|
2401
|
-
}
|
|
2402
|
-
function atomicWrite(file, content) {
|
|
2403
|
-
fs11.mkdirSync(path11.dirname(file), { recursive: true });
|
|
2404
|
-
const tmp = `${file}.tmp-${process.pid}`;
|
|
2405
|
-
fs11.writeFileSync(tmp, content);
|
|
2406
|
-
fs11.renameSync(tmp, file);
|
|
2407
|
-
}
|
|
2408
|
-
function readHelm(grounds) {
|
|
2409
|
-
try {
|
|
2410
|
-
return JSON.parse(fs11.readFileSync(helmPath(grounds), "utf8"));
|
|
2411
|
-
} catch {
|
|
2412
|
-
return void 0;
|
|
2413
|
-
}
|
|
2414
|
-
}
|
|
2415
|
-
function listHelms() {
|
|
2416
|
-
try {
|
|
2417
|
-
return fs11.readdirSync(helmDir()).filter((f) => f.endsWith(".json")).map((f) => JSON.parse(fs11.readFileSync(path11.join(helmDir(), f), "utf8")));
|
|
2418
|
-
} catch {
|
|
2419
|
-
return [];
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
function helmOf(sessionId) {
|
|
2423
|
-
return listHelms().find((h) => h.sessionId === sessionId);
|
|
2424
|
-
}
|
|
2425
|
-
function liveHelms(ttlMs, now2 = Date.now()) {
|
|
2426
|
-
return listHelms().filter((h) => now2 - (Date.parse(h.heartbeatAt) || 0) <= ttlMs);
|
|
2427
|
-
}
|
|
2428
|
-
function helmGate(live, sessionId, grounds) {
|
|
2429
|
-
if (grounds !== void 0) {
|
|
2430
|
-
const holder = live.find((h) => h.grounds === grounds);
|
|
2431
|
-
if (holder && holder.sessionId !== sessionId) {
|
|
2432
|
-
return `grounds "${grounds}" is helmed by session ${holder.sessionId.slice(0, 8)} \u2014 its verbs are that session's alone. Run this from that session (--session), or take its helm (\`lobstah man helm --take\`).`;
|
|
2433
|
-
}
|
|
2434
|
-
if (holder)
|
|
2435
|
-
return void 0;
|
|
2436
|
-
}
|
|
2437
|
-
if (live.length === 0)
|
|
2438
|
-
return void 0;
|
|
2439
|
-
if (sessionId !== void 0 && live.some((h) => h.sessionId === sessionId))
|
|
2440
|
-
return void 0;
|
|
2441
|
-
const holders = live.map((h) => `${h.grounds}=${h.sessionId.slice(0, 8)}`).join(", ");
|
|
2442
|
-
return `the helm is claimed (${holders}) \u2014 this verb is reserved for the helm session. Run it there with --session <helm-session-id>, or take the helm (\`lobstah man helm --take\`).`;
|
|
2443
|
-
}
|
|
2444
|
-
function helmLabel(h) {
|
|
2445
|
-
if (h.label)
|
|
2446
|
-
return h.label;
|
|
2447
|
-
const where = h.cwd ? path11.basename(h.cwd) : void 0;
|
|
2448
|
-
if (!h.harness && !where)
|
|
2449
|
-
return `session ${h.sessionId.slice(0, 8)}`;
|
|
2450
|
-
return `${h.harness ?? "session"}${where ? ` @ ${where}` : ""}`;
|
|
2451
|
-
}
|
|
2452
|
-
function takeHelm(opts) {
|
|
2453
|
-
const now2 = opts.now ?? Date.now();
|
|
2454
|
-
const existing = readHelm(opts.grounds.name);
|
|
2455
|
-
if (existing && existing.sessionId !== opts.sessionId) {
|
|
2456
|
-
const fresh = now2 - (Date.parse(existing.heartbeatAt) || 0) <= opts.ttlMs;
|
|
2457
|
-
if (fresh && !opts.take)
|
|
2458
|
-
return { held: existing };
|
|
2459
|
-
atomicWrite(path11.join(relievedDir(), `${existing.sessionId}.json`), JSON.stringify({
|
|
2460
|
-
sessionId: existing.sessionId,
|
|
2461
|
-
grounds: opts.grounds.name,
|
|
2462
|
-
by: opts.sessionId,
|
|
2463
|
-
at: new Date(now2).toISOString()
|
|
2464
|
-
}, null, 2));
|
|
2465
|
-
}
|
|
2466
|
-
const iso = new Date(now2).toISOString();
|
|
2467
|
-
const same = existing?.sessionId === opts.sessionId;
|
|
2468
|
-
const live = existing !== void 0 && now2 - (Date.parse(existing.heartbeatAt) || 0) <= opts.ttlMs;
|
|
2469
|
-
const reg = {
|
|
2470
|
-
sessionId: opts.sessionId,
|
|
2471
|
-
grounds: opts.grounds.name,
|
|
2472
|
-
repos: opts.grounds.repos,
|
|
2473
|
-
signedOnAt: same ? existing.signedOnAt : iso,
|
|
2474
|
-
heartbeatAt: iso,
|
|
2475
|
-
// A new helm on empty grounds starts its cursor now: a notice delivered
|
|
2476
|
-
// to nobody while no helm was signed on is not news. A take from a live
|
|
2477
|
-
// helm, or the same session signing on again, keeps the cursor, so
|
|
2478
|
-
// nothing in flight is dropped.
|
|
2479
|
-
wakesFrom: same || live ? existing.wakesFrom : iso,
|
|
2480
|
-
// Identity refreshes on every sign-on; a re-sign without one keeps what
|
|
2481
|
-
// the registration already knows.
|
|
2482
|
-
harness: opts.identity?.harness ?? (same ? existing.harness : void 0),
|
|
2483
|
-
cwd: opts.identity?.cwd ?? (same ? existing.cwd : void 0),
|
|
2484
|
-
host: opts.identity?.host ?? (same ? existing.host : void 0),
|
|
2485
|
-
label: opts.identity?.label ?? (same ? existing.label : void 0),
|
|
2486
|
-
window: opts.identity?.window ?? (same ? existing.window : void 0),
|
|
2487
|
-
tookFrom: existing && existing.sessionId !== opts.sessionId ? { sessionId: existing.sessionId, at: iso } : existing?.tookFrom
|
|
2488
|
-
};
|
|
2489
|
-
atomicWrite(helmPath(opts.grounds.name), JSON.stringify(reg, null, 2));
|
|
2490
|
-
return { ok: reg };
|
|
2491
|
-
}
|
|
2492
|
-
function wakeFloorMs(h) {
|
|
2493
|
-
return h?.wakesFrom ? Date.parse(h.wakesFrom) || 0 : 0;
|
|
2494
|
-
}
|
|
2495
|
-
function noticeStands(n) {
|
|
2496
|
-
switch (n.kind) {
|
|
2497
|
-
case "disk-held":
|
|
2498
|
-
return readHold() !== void 0;
|
|
2499
|
-
case "watch-failing":
|
|
2500
|
-
case "watch-held":
|
|
2501
|
-
return listWatches().some((w) => (w.key === n.refId || w.owner === `dispatch:${n.refId}`) && (n.kind === "watch-failing" ? w.failingNoticed === true : true));
|
|
2502
|
-
case "trap-request":
|
|
2503
|
-
return n.refId !== void 0 && isOpenRequest(n.refId);
|
|
2504
|
-
default:
|
|
2505
|
-
return false;
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
function noticeWakes(h) {
|
|
2509
|
-
const floor = wakeFloorMs(h);
|
|
2510
|
-
if (floor === 0)
|
|
2511
|
-
return void 0;
|
|
2512
|
-
return (n) => (Date.parse(n.at) || 0) >= floor || noticeStands(n);
|
|
2513
|
-
}
|
|
2514
|
-
function relieveHelm(sessionId) {
|
|
2515
|
-
const relieved = [];
|
|
2516
|
-
for (const h of listHelms()) {
|
|
2517
|
-
if (h.sessionId !== sessionId)
|
|
2518
|
-
continue;
|
|
2519
|
-
fs11.rmSync(helmPath(h.grounds), { force: true });
|
|
2520
|
-
relieved.push(h.grounds);
|
|
2521
|
-
}
|
|
2522
|
-
fs11.rmSync(path11.join(relievedDir(), `${sessionId}.json`), { force: true });
|
|
2523
|
-
return relieved;
|
|
2524
|
-
}
|
|
2525
|
-
function heartbeatHelm(sessionId, opts = {}) {
|
|
2526
|
-
const reg = helmOf(sessionId);
|
|
2527
|
-
if (!reg)
|
|
2528
|
-
return void 0;
|
|
2529
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
2530
|
-
const next = { ...reg, heartbeatAt: now2, ...opts.parked ? { parkedAt: now2 } : {} };
|
|
2531
|
-
atomicWrite(helmPath(reg.grounds), JSON.stringify(next, null, 2));
|
|
2532
|
-
return next;
|
|
2533
|
-
}
|
|
2534
|
-
function consumeRelievedNotice(sessionId) {
|
|
2535
|
-
const file = path11.join(relievedDir(), `${sessionId}.json`);
|
|
2536
|
-
try {
|
|
2537
|
-
const notice = JSON.parse(fs11.readFileSync(file, "utf8"));
|
|
2538
|
-
fs11.rmSync(file, { force: true });
|
|
2539
|
-
return notice;
|
|
2540
|
-
} catch {
|
|
2541
|
-
return void 0;
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
function groundsList(cfg) {
|
|
2545
|
-
const entries = Object.entries(cfg.grounds);
|
|
2546
|
-
if (entries.length === 0)
|
|
2547
|
-
return [{ name: "fleet", repos: Object.keys(cfg.repos) }];
|
|
2548
|
-
return entries.map(([name, g]) => ({ name, repos: g.repos }));
|
|
2549
|
-
}
|
|
2550
|
-
function groundsErrors(cfg) {
|
|
2551
|
-
const errors = [];
|
|
2552
|
-
const seen = /* @__PURE__ */ new Map();
|
|
2553
|
-
for (const [name, g] of Object.entries(cfg.grounds)) {
|
|
2554
|
-
for (const repo of g.repos) {
|
|
2555
|
-
if (cfg.repos[repo] === void 0)
|
|
2556
|
-
errors.push(`grounds.${name} names unknown repo "${repo}"`);
|
|
2557
|
-
const other = seen.get(repo);
|
|
2558
|
-
if (other !== void 0)
|
|
2559
|
-
errors.push(`repo "${repo}" is in both grounds.${other} and grounds.${name} \u2014 a repo belongs to at most one grounds`);
|
|
2560
|
-
else
|
|
2561
|
-
seen.set(repo, name);
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
return errors;
|
|
2565
|
-
}
|
|
2566
|
-
function resolveGrounds(cfg, name) {
|
|
2567
|
-
const all = groundsList(cfg);
|
|
2568
|
-
if (name === void 0) {
|
|
2569
|
-
if (all.length === 1)
|
|
2570
|
-
return all[0];
|
|
2571
|
-
throw new Error(`multiple grounds configured \u2014 pass --grounds <${all.map((g) => g.name).join("|")}>`);
|
|
2572
|
-
}
|
|
2573
|
-
const found = all.find((g) => g.name === name);
|
|
2574
|
-
if (!found)
|
|
2575
|
-
throw new Error(`unknown grounds "${name}" (configured: ${all.map((g) => g.name).join(", ")})`);
|
|
2576
|
-
return found;
|
|
2577
|
-
}
|
|
2578
|
-
var isOpenRequest;
|
|
2579
|
-
var init_helm = __esm({
|
|
2580
|
-
"packages/core/dist/helm.js"() {
|
|
2581
|
-
"use strict";
|
|
2582
|
-
init_disk();
|
|
2583
|
-
init_paths();
|
|
2584
|
-
init_watch();
|
|
2585
|
-
init_requests();
|
|
2586
|
-
isOpenRequest = (id) => {
|
|
2587
|
-
const r = readRequest(id);
|
|
2588
|
-
return r !== void 0 && r.closedAt === void 0;
|
|
2589
|
-
};
|
|
2590
|
-
}
|
|
2591
|
-
});
|
|
2592
|
-
|
|
2593
|
-
// packages/core/dist/session-link.js
|
|
2594
|
-
function validSessionLink(value) {
|
|
2595
|
-
if (typeof value !== "string")
|
|
2596
|
-
return false;
|
|
2597
|
-
if (/[\x00-\x1f\x7f]/.test(value))
|
|
2598
|
-
return false;
|
|
2599
|
-
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);
|
|
2600
|
-
}
|
|
2601
|
-
function linkMismatch(link, win) {
|
|
2602
|
-
if (!win)
|
|
2603
|
-
return void 0;
|
|
2604
|
-
const ep = win.entrypoint;
|
|
2605
|
-
const bundle = win.bundleId;
|
|
2606
|
-
if (link.startsWith("vscode://")) {
|
|
2607
|
-
if (ep !== void 0)
|
|
2608
|
-
return ep === "claude-vscode" ? void 0 : `a vscode:// link needs the VS Code extension; this session's entrypoint is ${ep}`;
|
|
2609
|
-
return bundle === void 0 || VSCODE_BUNDLE_RE.test(bundle) ? void 0 : `a vscode:// link needs the VS Code extension; this session runs in ${bundle}`;
|
|
2610
|
-
}
|
|
2611
|
-
if (link.startsWith("claude://")) {
|
|
2612
|
-
if (ep !== void 0) {
|
|
2613
|
-
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;
|
|
2614
|
-
}
|
|
2615
|
-
if (bundle !== void 0 && bundle !== CLAUDE_DESKTOP_BUNDLE)
|
|
2616
|
-
return `a claude:// link needs the Claude desktop app; this session runs in ${bundle}`;
|
|
2617
|
-
return win.termProgram === "claude-desktop" ? "a claude:// link needs the Code tab; this session runs in the Claude desktop app's terminal" : void 0;
|
|
2618
|
-
}
|
|
2619
|
-
if (link.startsWith("codex://")) {
|
|
2620
|
-
return bundle === void 0 || bundle === CODEX_BUNDLE ? void 0 : `a codex:// link needs the Codex app; this session runs in ${bundle}`;
|
|
2621
|
-
}
|
|
2622
|
-
return void 0;
|
|
2623
|
-
}
|
|
2624
|
-
var VSCODE_BUNDLE_RE, CLAUDE_DESKTOP_BUNDLE, CODEX_BUNDLE;
|
|
2625
|
-
var init_session_link = __esm({
|
|
2626
|
-
"packages/core/dist/session-link.js"() {
|
|
2627
|
-
"use strict";
|
|
2628
|
-
VSCODE_BUNDLE_RE = /(?:VSCode|Cursor|windsurf)/;
|
|
2629
|
-
CLAUDE_DESKTOP_BUNDLE = "com.anthropic.claudefordesktop";
|
|
2630
|
-
CODEX_BUNDLE = "com.openai.codex";
|
|
2631
|
-
}
|
|
2632
|
-
});
|
|
2633
|
-
|
|
2634
|
-
// packages/core/dist/activity.js
|
|
2635
|
-
import * as fs12 from "node:fs";
|
|
2636
|
-
import * as path12 from "node:path";
|
|
2637
2394
|
function looksSecret(word) {
|
|
2638
2395
|
if (SECRET_PATTERNS.some((re) => re.test(word)))
|
|
2639
2396
|
return true;
|
|
@@ -2676,7 +2433,7 @@ function relativeTarget(p, root) {
|
|
|
2676
2433
|
if (!root)
|
|
2677
2434
|
return baseName(p);
|
|
2678
2435
|
const win = isWindowsPath(p) || isWindowsPath(root);
|
|
2679
|
-
const lib = win ?
|
|
2436
|
+
const lib = win ? path11.win32 : path11.posix;
|
|
2680
2437
|
if (!lib.isAbsolute(p))
|
|
2681
2438
|
return p.replace(/\\/g, "/");
|
|
2682
2439
|
const rel = lib.relative(win ? root : root.replace(/\\/g, "/"), p);
|
|
@@ -2743,18 +2500,18 @@ function activityFromEvent(ev, root) {
|
|
|
2743
2500
|
return void 0;
|
|
2744
2501
|
}
|
|
2745
2502
|
}
|
|
2746
|
-
function
|
|
2503
|
+
function atomicWrite(file, content) {
|
|
2747
2504
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
2748
|
-
|
|
2749
|
-
|
|
2505
|
+
fs11.writeFileSync(tmp, content);
|
|
2506
|
+
fs11.renameSync(tmp, file);
|
|
2750
2507
|
}
|
|
2751
2508
|
function writeActivity(id, lane, a) {
|
|
2752
2509
|
const safe = { at: a.at, kind: a.kind, summary: redactSummary(a.summary) };
|
|
2753
|
-
|
|
2510
|
+
atomicWrite(activityPath(id, lane), JSON.stringify(safe));
|
|
2754
2511
|
}
|
|
2755
2512
|
function readActivity(id, lane) {
|
|
2756
2513
|
try {
|
|
2757
|
-
const parsed = JSON.parse(
|
|
2514
|
+
const parsed = JSON.parse(fs11.readFileSync(activityPath(id, lane), "utf8"));
|
|
2758
2515
|
if (typeof parsed.at !== "string" || typeof parsed.summary !== "string")
|
|
2759
2516
|
return void 0;
|
|
2760
2517
|
if (!ACTIVITY_KINDS.includes(parsed.kind))
|
|
@@ -2865,7 +2622,7 @@ var init_activity = __esm({
|
|
|
2865
2622
|
});
|
|
2866
2623
|
|
|
2867
2624
|
// packages/core/dist/status.js
|
|
2868
|
-
import * as
|
|
2625
|
+
import * as fs12 from "node:fs";
|
|
2869
2626
|
function isVerb(v) {
|
|
2870
2627
|
return VERBS.includes(v);
|
|
2871
2628
|
}
|
|
@@ -2922,7 +2679,7 @@ function appendStatus(id, lane, verb, note, at, waiting, reported = false) {
|
|
|
2922
2679
|
...extra,
|
|
2923
2680
|
...reported ? { reported: true } : {}
|
|
2924
2681
|
};
|
|
2925
|
-
|
|
2682
|
+
fs12.appendFileSync(statusPath(id, lane), `${JSON.stringify(entry)}
|
|
2926
2683
|
`);
|
|
2927
2684
|
if (verb === "done") {
|
|
2928
2685
|
try {
|
|
@@ -2934,9 +2691,9 @@ function appendStatus(id, lane, verb, note, at, waiting, reported = false) {
|
|
|
2934
2691
|
}
|
|
2935
2692
|
function readStatusLog(id, lane) {
|
|
2936
2693
|
const file = statusPath(id, lane);
|
|
2937
|
-
if (!
|
|
2694
|
+
if (!fs12.existsSync(file))
|
|
2938
2695
|
return [];
|
|
2939
|
-
return
|
|
2696
|
+
return fs12.readFileSync(file, "utf8").split("\n").filter(Boolean).flatMap((line) => {
|
|
2940
2697
|
try {
|
|
2941
2698
|
const parsed = JSON.parse(line);
|
|
2942
2699
|
return isVerb(parsed.verb) ? [parsed] : [];
|
|
@@ -2994,12 +2751,12 @@ var init_status = __esm({
|
|
|
2994
2751
|
});
|
|
2995
2752
|
|
|
2996
2753
|
// packages/core/dist/queue.js
|
|
2997
|
-
import * as
|
|
2998
|
-
import * as
|
|
2999
|
-
function
|
|
2754
|
+
import * as fs13 from "node:fs";
|
|
2755
|
+
import * as path12 from "node:path";
|
|
2756
|
+
function atomicWrite2(file, content) {
|
|
3000
2757
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
3001
|
-
|
|
3002
|
-
|
|
2758
|
+
fs13.writeFileSync(tmp, content);
|
|
2759
|
+
fs13.renameSync(tmp, file);
|
|
3003
2760
|
}
|
|
3004
2761
|
function enqueue(d, lane = "work") {
|
|
3005
2762
|
if (!d.id || !d.repo || !d.brief) {
|
|
@@ -3011,11 +2768,11 @@ function enqueue(d, lane = "work") {
|
|
|
3011
2768
|
...inherited?.length ? { attachments: inherited } : {},
|
|
3012
2769
|
queuedAt: d.queuedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
3013
2770
|
};
|
|
3014
|
-
|
|
2771
|
+
atomicWrite2(path12.join(laneDirs(lane).queue, `${d.id}.json`), JSON.stringify(descriptor, null, 2));
|
|
3015
2772
|
}
|
|
3016
2773
|
function mtimeIfPresent(file) {
|
|
3017
2774
|
try {
|
|
3018
|
-
return
|
|
2775
|
+
return fs13.statSync(file).mtimeMs;
|
|
3019
2776
|
} catch (e) {
|
|
3020
2777
|
if (e.code === "ENOENT")
|
|
3021
2778
|
return void 0;
|
|
@@ -3025,22 +2782,22 @@ function mtimeIfPresent(file) {
|
|
|
3025
2782
|
function pendingIds(lane) {
|
|
3026
2783
|
const dir = laneDirs(lane).queue;
|
|
3027
2784
|
return readDirIfPresent(dir).filter((f) => f.endsWith(".json")).flatMap((f) => {
|
|
3028
|
-
const m = mtimeIfPresent(
|
|
2785
|
+
const m = mtimeIfPresent(path12.join(dir, f));
|
|
3029
2786
|
return m === void 0 ? [] : [{ f, m }];
|
|
3030
2787
|
}).sort((a, b) => a.m - b.m).map(({ f }) => f.slice(0, -".json".length));
|
|
3031
2788
|
}
|
|
3032
2789
|
function queuedDescriptor(id, lane) {
|
|
3033
2790
|
try {
|
|
3034
|
-
return JSON.parse(
|
|
2791
|
+
return JSON.parse(fs13.readFileSync(path12.join(laneDirs(lane).queue, `${id}.json`), "utf8"));
|
|
3035
2792
|
} catch {
|
|
3036
2793
|
return void 0;
|
|
3037
2794
|
}
|
|
3038
2795
|
}
|
|
3039
2796
|
function queuedAt(id, lane) {
|
|
3040
|
-
const file =
|
|
2797
|
+
const file = path12.join(laneDirs(lane).queue, `${id}.json`);
|
|
3041
2798
|
let stat;
|
|
3042
2799
|
try {
|
|
3043
|
-
stat =
|
|
2800
|
+
stat = fs13.statSync(file);
|
|
3044
2801
|
} catch {
|
|
3045
2802
|
return void 0;
|
|
3046
2803
|
}
|
|
@@ -3055,17 +2812,17 @@ function claimNext(lane, skip) {
|
|
|
3055
2812
|
if (!d || skip(d))
|
|
3056
2813
|
continue;
|
|
3057
2814
|
}
|
|
3058
|
-
const activeDir =
|
|
2815
|
+
const activeDir = path12.join(dirs.active, id);
|
|
3059
2816
|
try {
|
|
3060
|
-
|
|
2817
|
+
fs13.mkdirSync(activeDir);
|
|
3061
2818
|
} catch {
|
|
3062
2819
|
continue;
|
|
3063
2820
|
}
|
|
3064
2821
|
try {
|
|
3065
|
-
|
|
2822
|
+
fs13.renameSync(path12.join(dirs.queue, `${id}.json`), path12.join(activeDir, "descriptor.json"));
|
|
3066
2823
|
return id;
|
|
3067
2824
|
} catch {
|
|
3068
|
-
|
|
2825
|
+
fs13.rmdirSync(activeDir, { recursive: true });
|
|
3069
2826
|
continue;
|
|
3070
2827
|
}
|
|
3071
2828
|
}
|
|
@@ -3073,19 +2830,19 @@ function claimNext(lane, skip) {
|
|
|
3073
2830
|
}
|
|
3074
2831
|
function requeue(id, lane) {
|
|
3075
2832
|
const dirs = laneDirs(lane);
|
|
3076
|
-
const activeDir =
|
|
3077
|
-
|
|
3078
|
-
|
|
2833
|
+
const activeDir = path12.join(dirs.active, id);
|
|
2834
|
+
fs13.renameSync(path12.join(activeDir, "descriptor.json"), path12.join(dirs.queue, `${id}.json`));
|
|
2835
|
+
fs13.rmSync(activeDir, { recursive: true, force: true });
|
|
3079
2836
|
}
|
|
3080
2837
|
function storedDescriptor(id, lane) {
|
|
3081
2838
|
const dirs = laneDirs(lane);
|
|
3082
2839
|
for (const file of [
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
2840
|
+
path12.join(dirs.queue, `${id}.json`),
|
|
2841
|
+
path12.join(dirs.active, id, "descriptor.json"),
|
|
2842
|
+
path12.join(dirs.done, id, "descriptor.json")
|
|
3086
2843
|
]) {
|
|
3087
2844
|
try {
|
|
3088
|
-
return JSON.parse(
|
|
2845
|
+
return JSON.parse(fs13.readFileSync(file, "utf8"));
|
|
3089
2846
|
} catch {
|
|
3090
2847
|
}
|
|
3091
2848
|
}
|
|
@@ -3096,44 +2853,85 @@ function activeIds(lane) {
|
|
|
3096
2853
|
}
|
|
3097
2854
|
function complete(id, lane) {
|
|
3098
2855
|
const dirs = laneDirs(lane);
|
|
3099
|
-
|
|
2856
|
+
fs13.renameSync(path12.join(dirs.active, id), path12.join(dirs.done, id));
|
|
3100
2857
|
}
|
|
3101
2858
|
function requestCancel(id, lane) {
|
|
3102
|
-
|
|
2859
|
+
fs13.writeFileSync(path12.join(laneDirs(lane).active, id, "cancel"), (/* @__PURE__ */ new Date()).toISOString());
|
|
3103
2860
|
}
|
|
3104
2861
|
function cancelQueued(id, lane) {
|
|
3105
2862
|
const dirs = laneDirs(lane);
|
|
3106
|
-
const doneDir =
|
|
2863
|
+
const doneDir = path12.join(dirs.done, id);
|
|
3107
2864
|
try {
|
|
3108
|
-
|
|
2865
|
+
fs13.mkdirSync(doneDir);
|
|
3109
2866
|
} catch {
|
|
3110
2867
|
return false;
|
|
3111
2868
|
}
|
|
3112
2869
|
try {
|
|
3113
|
-
|
|
2870
|
+
fs13.renameSync(path12.join(dirs.queue, `${id}.json`), path12.join(doneDir, "descriptor.json"));
|
|
3114
2871
|
} catch {
|
|
3115
|
-
|
|
2872
|
+
fs13.rmdirSync(doneDir, { recursive: true });
|
|
3116
2873
|
return false;
|
|
3117
2874
|
}
|
|
3118
2875
|
appendStatus(id, lane, "failed", "cancelled before claim");
|
|
3119
2876
|
return true;
|
|
3120
2877
|
}
|
|
3121
2878
|
function cancelRequested(id, lane) {
|
|
3122
|
-
return
|
|
2879
|
+
return fs13.existsSync(path12.join(laneDirs(lane).active, id, "cancel"));
|
|
2880
|
+
}
|
|
2881
|
+
var init_queue = __esm({
|
|
2882
|
+
"packages/core/dist/queue.js"() {
|
|
2883
|
+
"use strict";
|
|
2884
|
+
init_paths();
|
|
2885
|
+
init_status();
|
|
2886
|
+
}
|
|
2887
|
+
});
|
|
2888
|
+
|
|
2889
|
+
// packages/core/dist/session-link.js
|
|
2890
|
+
function validSessionLink(value) {
|
|
2891
|
+
if (typeof value !== "string")
|
|
2892
|
+
return false;
|
|
2893
|
+
if (/[\x00-\x1f\x7f]/.test(value))
|
|
2894
|
+
return false;
|
|
2895
|
+
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);
|
|
2896
|
+
}
|
|
2897
|
+
function linkMismatch(link, win) {
|
|
2898
|
+
if (!win)
|
|
2899
|
+
return void 0;
|
|
2900
|
+
const ep = win.entrypoint;
|
|
2901
|
+
const bundle = win.bundleId;
|
|
2902
|
+
if (link.startsWith("vscode://")) {
|
|
2903
|
+
if (ep !== void 0)
|
|
2904
|
+
return ep === "claude-vscode" ? void 0 : `a vscode:// link needs the VS Code extension; this session's entrypoint is ${ep}`;
|
|
2905
|
+
return bundle === void 0 || VSCODE_BUNDLE_RE.test(bundle) ? void 0 : `a vscode:// link needs the VS Code extension; this session runs in ${bundle}`;
|
|
2906
|
+
}
|
|
2907
|
+
if (link.startsWith("claude://")) {
|
|
2908
|
+
if (ep !== void 0) {
|
|
2909
|
+
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;
|
|
2910
|
+
}
|
|
2911
|
+
if (bundle !== void 0 && bundle !== CLAUDE_DESKTOP_BUNDLE)
|
|
2912
|
+
return `a claude:// link needs the Claude desktop app; this session runs in ${bundle}`;
|
|
2913
|
+
return win.termProgram === "claude-desktop" ? "a claude:// link needs the Code tab; this session runs in the Claude desktop app's terminal" : void 0;
|
|
2914
|
+
}
|
|
2915
|
+
if (link.startsWith("codex://")) {
|
|
2916
|
+
return bundle === void 0 || bundle === CODEX_BUNDLE ? void 0 : `a codex:// link needs the Codex app; this session runs in ${bundle}`;
|
|
2917
|
+
}
|
|
2918
|
+
return void 0;
|
|
3123
2919
|
}
|
|
3124
|
-
var
|
|
3125
|
-
|
|
2920
|
+
var VSCODE_BUNDLE_RE, CLAUDE_DESKTOP_BUNDLE, CODEX_BUNDLE;
|
|
2921
|
+
var init_session_link = __esm({
|
|
2922
|
+
"packages/core/dist/session-link.js"() {
|
|
3126
2923
|
"use strict";
|
|
3127
|
-
|
|
3128
|
-
|
|
2924
|
+
VSCODE_BUNDLE_RE = /(?:VSCode|Cursor|windsurf)/;
|
|
2925
|
+
CLAUDE_DESKTOP_BUNDLE = "com.anthropic.claudefordesktop";
|
|
2926
|
+
CODEX_BUNDLE = "com.openai.codex";
|
|
3129
2927
|
}
|
|
3130
2928
|
});
|
|
3131
2929
|
|
|
3132
2930
|
// packages/core/dist/evidence.js
|
|
3133
|
-
import * as
|
|
2931
|
+
import * as fs14 from "node:fs";
|
|
3134
2932
|
function readEvidence(id, lane) {
|
|
3135
2933
|
try {
|
|
3136
|
-
return JSON.parse(
|
|
2934
|
+
return JSON.parse(fs14.readFileSync(evidencePath(id, lane), "utf8"));
|
|
3137
2935
|
} catch {
|
|
3138
2936
|
return {};
|
|
3139
2937
|
}
|
|
@@ -3141,8 +2939,8 @@ function readEvidence(id, lane) {
|
|
|
3141
2939
|
function mergeEvidence(id, lane, patch) {
|
|
3142
2940
|
const file = evidencePath(id, lane);
|
|
3143
2941
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
3144
|
-
|
|
3145
|
-
|
|
2942
|
+
fs14.writeFileSync(tmp, JSON.stringify({ ...readEvidence(id, lane), ...patch }, null, 2));
|
|
2943
|
+
fs14.renameSync(tmp, file);
|
|
3146
2944
|
}
|
|
3147
2945
|
var init_evidence = __esm({
|
|
3148
2946
|
"packages/core/dist/evidence.js"() {
|
|
@@ -3152,8 +2950,8 @@ var init_evidence = __esm({
|
|
|
3152
2950
|
});
|
|
3153
2951
|
|
|
3154
2952
|
// packages/core/dist/pushes.js
|
|
3155
|
-
import * as
|
|
3156
|
-
import * as
|
|
2953
|
+
import * as fs15 from "node:fs";
|
|
2954
|
+
import * as path13 from "node:path";
|
|
3157
2955
|
function words(segment) {
|
|
3158
2956
|
const out = [];
|
|
3159
2957
|
const re = /"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g;
|
|
@@ -3205,18 +3003,18 @@ function gitPushTargets(command) {
|
|
|
3205
3003
|
return found ? [...new Set(targets)] : void 0;
|
|
3206
3004
|
}
|
|
3207
3005
|
function gitDirAt(dir) {
|
|
3208
|
-
let at =
|
|
3006
|
+
let at = path13.resolve(dir);
|
|
3209
3007
|
for (; ; ) {
|
|
3210
|
-
const dotGit =
|
|
3008
|
+
const dotGit = path13.join(at, ".git");
|
|
3211
3009
|
try {
|
|
3212
|
-
const stat =
|
|
3010
|
+
const stat = fs15.statSync(dotGit);
|
|
3213
3011
|
if (stat.isDirectory())
|
|
3214
3012
|
return dotGit;
|
|
3215
|
-
const m = /^gitdir:\s*(.+)$/m.exec(
|
|
3216
|
-
return m ?
|
|
3013
|
+
const m = /^gitdir:\s*(.+)$/m.exec(fs15.readFileSync(dotGit, "utf8"));
|
|
3014
|
+
return m ? path13.resolve(at, m[1].trim()) : void 0;
|
|
3217
3015
|
} catch {
|
|
3218
3016
|
}
|
|
3219
|
-
const up =
|
|
3017
|
+
const up = path13.dirname(at);
|
|
3220
3018
|
if (up === at)
|
|
3221
3019
|
return void 0;
|
|
3222
3020
|
at = up;
|
|
@@ -3227,7 +3025,7 @@ function currentBranchAt(dir) {
|
|
|
3227
3025
|
if (!gitDir)
|
|
3228
3026
|
return void 0;
|
|
3229
3027
|
try {
|
|
3230
|
-
const m = /^ref:\s*refs\/heads\/(.+)$/m.exec(
|
|
3028
|
+
const m = /^ref:\s*refs\/heads\/(.+)$/m.exec(fs15.readFileSync(path13.join(gitDir, "HEAD"), "utf8"));
|
|
3231
3029
|
return m ? m[1].trim() : void 0;
|
|
3232
3030
|
} catch {
|
|
3233
3031
|
return void 0;
|
|
@@ -3256,18 +3054,18 @@ var init_pushes = __esm({
|
|
|
3256
3054
|
});
|
|
3257
3055
|
|
|
3258
3056
|
// packages/core/dist/trap-names.js
|
|
3259
|
-
import * as
|
|
3260
|
-
import * as
|
|
3057
|
+
import * as fs16 from "node:fs";
|
|
3058
|
+
import * as path14 from "node:path";
|
|
3261
3059
|
import { randomInt } from "node:crypto";
|
|
3262
3060
|
function namesDir() {
|
|
3263
|
-
return
|
|
3061
|
+
return path14.join(lobstahHome(), "trap-names");
|
|
3264
3062
|
}
|
|
3265
3063
|
function nameFile(name) {
|
|
3266
|
-
return
|
|
3064
|
+
return path14.join(namesDir(), `${name}.json`);
|
|
3267
3065
|
}
|
|
3268
3066
|
function knownTrapNames() {
|
|
3269
3067
|
try {
|
|
3270
|
-
return
|
|
3068
|
+
return fs16.readdirSync(namesDir()).filter((file) => file.endsWith(".json")).map((file) => file.slice(0, -5)).filter((name) => TRAP_NAME_RE.test(name)).sort();
|
|
3271
3069
|
} catch {
|
|
3272
3070
|
return [];
|
|
3273
3071
|
}
|
|
@@ -3276,7 +3074,7 @@ function trapIdForName(name) {
|
|
|
3276
3074
|
if (!TRAP_NAME_RE.test(name))
|
|
3277
3075
|
return void 0;
|
|
3278
3076
|
try {
|
|
3279
|
-
const id = JSON.parse(
|
|
3077
|
+
const id = JSON.parse(fs16.readFileSync(nameFile(name), "utf8")).trapId;
|
|
3280
3078
|
return typeof id === "string" ? id : void 0;
|
|
3281
3079
|
} catch {
|
|
3282
3080
|
return void 0;
|
|
@@ -3286,7 +3084,7 @@ function trapNameForId(trapId) {
|
|
|
3286
3084
|
return knownTrapNames().find((name) => trapIdForName(name) === trapId);
|
|
3287
3085
|
}
|
|
3288
3086
|
function reserveTrapName(trapId, requested, start = randomInt(TRAP_FIRST_WORDS.length * TRAP_LAST_WORDS.length)) {
|
|
3289
|
-
|
|
3087
|
+
fs16.mkdirSync(namesDir(), { recursive: true });
|
|
3290
3088
|
const old = knownTrapNames().find((name) => trapIdForName(name) === trapId);
|
|
3291
3089
|
if (requested !== void 0 && !TRAP_NAME_RE.test(requested)) {
|
|
3292
3090
|
throw new Error(`invalid trap name "${requested}" \u2014 use two lowercase words of 2\u20138 letters joined by one hyphen`);
|
|
@@ -3302,9 +3100,9 @@ function reserveTrapName(trapId, requested, start = randomInt(TRAP_FIRST_WORDS.l
|
|
|
3302
3100
|
if (name === old)
|
|
3303
3101
|
return name;
|
|
3304
3102
|
try {
|
|
3305
|
-
|
|
3103
|
+
fs16.writeFileSync(nameFile(name), JSON.stringify({ trapId }), { flag: "wx" });
|
|
3306
3104
|
if (old)
|
|
3307
|
-
|
|
3105
|
+
fs16.rmSync(nameFile(old), { force: true });
|
|
3308
3106
|
return name;
|
|
3309
3107
|
} catch (err) {
|
|
3310
3108
|
if (err.code !== "EEXIST")
|
|
@@ -3459,22 +3257,22 @@ var init_trap_names = __esm({
|
|
|
3459
3257
|
});
|
|
3460
3258
|
|
|
3461
3259
|
// packages/core/dist/worktrees.js
|
|
3462
|
-
import * as
|
|
3463
|
-
import * as
|
|
3260
|
+
import * as fs17 from "node:fs";
|
|
3261
|
+
import * as path15 from "node:path";
|
|
3464
3262
|
function worktreePath(id) {
|
|
3465
|
-
return
|
|
3263
|
+
return path15.join(lobstahHome(), "worktrees", id);
|
|
3466
3264
|
}
|
|
3467
3265
|
function readRecord(file) {
|
|
3468
3266
|
try {
|
|
3469
|
-
const r = JSON.parse(
|
|
3267
|
+
const r = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
3470
3268
|
return typeof r.path === "string" ? r : void 0;
|
|
3471
3269
|
} catch {
|
|
3472
3270
|
return void 0;
|
|
3473
3271
|
}
|
|
3474
3272
|
}
|
|
3475
3273
|
function ownerOfPath(p) {
|
|
3476
|
-
const rel =
|
|
3477
|
-
if (!rel || rel.startsWith("..") ||
|
|
3274
|
+
const rel = path15.relative(path15.join(lobstahHome(), "worktrees"), p);
|
|
3275
|
+
if (!rel || rel.startsWith("..") || path15.isAbsolute(rel))
|
|
3478
3276
|
return void 0;
|
|
3479
3277
|
return rel.split(/[\\/]/)[0];
|
|
3480
3278
|
}
|
|
@@ -3487,7 +3285,7 @@ function dispatchWorktree(id, lane) {
|
|
|
3487
3285
|
}
|
|
3488
3286
|
const dirs = laneDirs(l);
|
|
3489
3287
|
for (const dir of [dirs.active, dirs.done]) {
|
|
3490
|
-
const rec = readRecord(
|
|
3288
|
+
const rec = readRecord(path15.join(dir, id, "worktree.json"));
|
|
3491
3289
|
if (rec) {
|
|
3492
3290
|
const owner = rec.of ?? ownerOfPath(rec.path) ?? id;
|
|
3493
3291
|
return { path: rec.path, owner, reused: owner !== id };
|
|
@@ -3499,7 +3297,7 @@ function dispatchWorktree(id, lane) {
|
|
|
3499
3297
|
function laneOf(id) {
|
|
3500
3298
|
for (const l of LANES) {
|
|
3501
3299
|
const d = laneDirs(l);
|
|
3502
|
-
if (
|
|
3300
|
+
if (fs17.existsSync(path15.join(d.queue, `${id}.json`)) || fs17.existsSync(path15.join(d.active, id)) || fs17.existsSync(path15.join(d.done, id))) {
|
|
3503
3301
|
return l;
|
|
3504
3302
|
}
|
|
3505
3303
|
}
|
|
@@ -3519,39 +3317,39 @@ function followUpAncestors(id, lane) {
|
|
|
3519
3317
|
function chainWorktree(followUp) {
|
|
3520
3318
|
for (const id of [followUp, ...followUpAncestors(followUp)]) {
|
|
3521
3319
|
const wt = dispatchWorktree(id, laneOf(id));
|
|
3522
|
-
if (
|
|
3320
|
+
if (fs17.existsSync(wt.path))
|
|
3523
3321
|
return { ...wt, from: id };
|
|
3524
3322
|
}
|
|
3525
3323
|
return void 0;
|
|
3526
3324
|
}
|
|
3527
3325
|
function worktreeGitDir(wt) {
|
|
3528
|
-
const dotGit =
|
|
3326
|
+
const dotGit = path15.join(wt, ".git");
|
|
3529
3327
|
try {
|
|
3530
|
-
const st =
|
|
3328
|
+
const st = fs17.statSync(dotGit);
|
|
3531
3329
|
if (st.isDirectory())
|
|
3532
3330
|
return dotGit;
|
|
3533
|
-
const m = /^gitdir:\s*(.+?)\s*$/m.exec(
|
|
3534
|
-
return m ?
|
|
3331
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(fs17.readFileSync(dotGit, "utf8"));
|
|
3332
|
+
return m ? path15.resolve(wt, m[1]) : void 0;
|
|
3535
3333
|
} catch {
|
|
3536
3334
|
return void 0;
|
|
3537
3335
|
}
|
|
3538
3336
|
}
|
|
3539
3337
|
function worktreeLockFile(wt) {
|
|
3540
3338
|
const gitDir = worktreeGitDir(wt);
|
|
3541
|
-
return gitDir ?
|
|
3339
|
+
return gitDir ? path15.join(gitDir, "lobstah.lock") : void 0;
|
|
3542
3340
|
}
|
|
3543
3341
|
function readWorktreeLock(wt) {
|
|
3544
3342
|
const file = worktreeLockFile(wt);
|
|
3545
3343
|
if (!file)
|
|
3546
3344
|
return void 0;
|
|
3547
3345
|
try {
|
|
3548
|
-
return JSON.parse(
|
|
3346
|
+
return JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
3549
3347
|
} catch {
|
|
3550
3348
|
return void 0;
|
|
3551
3349
|
}
|
|
3552
3350
|
}
|
|
3553
3351
|
function lockIsLive(lock) {
|
|
3554
|
-
return
|
|
3352
|
+
return fs17.existsSync(path15.join(laneDirs(lock.lane).active, lock.id));
|
|
3555
3353
|
}
|
|
3556
3354
|
function worktreeHolder(wt) {
|
|
3557
3355
|
const lock = readWorktreeLock(wt);
|
|
@@ -3564,7 +3362,7 @@ function acquireWorktreeLock(wt, id, lane) {
|
|
|
3564
3362
|
return { id: "(no git dir)", lane, pid: 0, at: mine.at };
|
|
3565
3363
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
3566
3364
|
try {
|
|
3567
|
-
|
|
3365
|
+
fs17.writeFileSync(file, JSON.stringify(mine, null, 2), { flag: "wx" });
|
|
3568
3366
|
return void 0;
|
|
3569
3367
|
} catch (err) {
|
|
3570
3368
|
if (err.code !== "EEXIST")
|
|
@@ -3572,7 +3370,7 @@ function acquireWorktreeLock(wt, id, lane) {
|
|
|
3572
3370
|
}
|
|
3573
3371
|
let raw;
|
|
3574
3372
|
try {
|
|
3575
|
-
raw =
|
|
3373
|
+
raw = fs17.readFileSync(file, "utf8");
|
|
3576
3374
|
} catch {
|
|
3577
3375
|
continue;
|
|
3578
3376
|
}
|
|
@@ -3583,14 +3381,14 @@ function acquireWorktreeLock(wt, id, lane) {
|
|
|
3583
3381
|
held2 = void 0;
|
|
3584
3382
|
}
|
|
3585
3383
|
if (held2?.id === id) {
|
|
3586
|
-
|
|
3384
|
+
fs17.writeFileSync(file, JSON.stringify(mine, null, 2));
|
|
3587
3385
|
return void 0;
|
|
3588
3386
|
}
|
|
3589
3387
|
if (held2 && lockIsLive(held2))
|
|
3590
3388
|
return held2;
|
|
3591
3389
|
try {
|
|
3592
|
-
if (
|
|
3593
|
-
|
|
3390
|
+
if (fs17.readFileSync(file, "utf8") === raw)
|
|
3391
|
+
fs17.rmSync(file, { force: true });
|
|
3594
3392
|
} catch {
|
|
3595
3393
|
}
|
|
3596
3394
|
}
|
|
@@ -3602,20 +3400,20 @@ function releaseWorktreeLock(wt, id) {
|
|
|
3602
3400
|
if (!file)
|
|
3603
3401
|
return;
|
|
3604
3402
|
if (readWorktreeLock(wt)?.id === id)
|
|
3605
|
-
|
|
3403
|
+
fs17.rmSync(file, { force: true });
|
|
3606
3404
|
}
|
|
3607
3405
|
function releaseDispatchLock(dispatchDir, id) {
|
|
3608
|
-
const rec = readRecord(
|
|
3406
|
+
const rec = readRecord(path15.join(dispatchDir, "worktree.json"));
|
|
3609
3407
|
if (rec)
|
|
3610
3408
|
releaseWorktreeLock(rec.path, id);
|
|
3611
3409
|
}
|
|
3612
3410
|
function keptWorktreesPath() {
|
|
3613
|
-
return
|
|
3411
|
+
return path15.join(lobstahHome(), "release-kept.json");
|
|
3614
3412
|
}
|
|
3615
3413
|
function readKeptWorktrees() {
|
|
3616
3414
|
try {
|
|
3617
|
-
const list2 = JSON.parse(
|
|
3618
|
-
return Array.isArray(list2) ? list2.filter((k) =>
|
|
3415
|
+
const list2 = JSON.parse(fs17.readFileSync(keptWorktreesPath(), "utf8"));
|
|
3416
|
+
return Array.isArray(list2) ? list2.filter((k) => fs17.existsSync(worktreePath(k.id))) : [];
|
|
3619
3417
|
} catch {
|
|
3620
3418
|
return [];
|
|
3621
3419
|
}
|
|
@@ -3623,12 +3421,12 @@ function readKeptWorktrees() {
|
|
|
3623
3421
|
function writeKeptWorktrees(list2) {
|
|
3624
3422
|
const file = keptWorktreesPath();
|
|
3625
3423
|
if (list2.length === 0) {
|
|
3626
|
-
|
|
3424
|
+
fs17.rmSync(file, { force: true });
|
|
3627
3425
|
return;
|
|
3628
3426
|
}
|
|
3629
3427
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
3630
|
-
|
|
3631
|
-
|
|
3428
|
+
fs17.writeFileSync(tmp, JSON.stringify(list2, null, 2));
|
|
3429
|
+
fs17.renameSync(tmp, file);
|
|
3632
3430
|
}
|
|
3633
3431
|
var LANES;
|
|
3634
3432
|
var init_worktrees = __esm({
|
|
@@ -3642,8 +3440,8 @@ var init_worktrees = __esm({
|
|
|
3642
3440
|
});
|
|
3643
3441
|
|
|
3644
3442
|
// packages/core/dist/worktree-safety.js
|
|
3645
|
-
import * as
|
|
3646
|
-
import * as
|
|
3443
|
+
import * as fs18 from "node:fs";
|
|
3444
|
+
import * as path16 from "node:path";
|
|
3647
3445
|
import { execFileSync } from "node:child_process";
|
|
3648
3446
|
function git(dir, ...args) {
|
|
3649
3447
|
return execFileSync("git", args, { cwd: dir, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 1e4 });
|
|
@@ -3687,22 +3485,22 @@ function removeGhostWorktree(dir) {
|
|
|
3687
3485
|
const safety = inspectTrapWorktree(dir);
|
|
3688
3486
|
if (safety.reason)
|
|
3689
3487
|
return { ...safety, removed: false };
|
|
3690
|
-
const anchor =
|
|
3488
|
+
const anchor = path16.join(dir, ".lobstah-trap");
|
|
3691
3489
|
let saved;
|
|
3692
3490
|
try {
|
|
3693
3491
|
const common = git(dir, "rev-parse", "--path-format=absolute", "--git-common-dir").trim();
|
|
3694
3492
|
const own = git(dir, "rev-parse", "--path-format=absolute", "--git-dir").trim();
|
|
3695
3493
|
if (common === own)
|
|
3696
3494
|
return { ...safety, removed: false, reason: "not a linked worktree" };
|
|
3697
|
-
if (
|
|
3698
|
-
saved =
|
|
3699
|
-
|
|
3495
|
+
if (fs18.existsSync(anchor)) {
|
|
3496
|
+
saved = fs18.readFileSync(anchor);
|
|
3497
|
+
fs18.unlinkSync(anchor);
|
|
3700
3498
|
}
|
|
3701
|
-
git(
|
|
3499
|
+
git(path16.dirname(common), "--git-dir", common, "worktree", "remove", dir);
|
|
3702
3500
|
return { ...safety, removed: true };
|
|
3703
3501
|
} catch {
|
|
3704
|
-
if (saved &&
|
|
3705
|
-
|
|
3502
|
+
if (saved && fs18.existsSync(dir))
|
|
3503
|
+
fs18.writeFileSync(anchor, saved);
|
|
3706
3504
|
return { ...safety, removed: false, reason: "git worktree remove refused" };
|
|
3707
3505
|
}
|
|
3708
3506
|
}
|
|
@@ -3713,20 +3511,20 @@ var init_worktree_safety = __esm({
|
|
|
3713
3511
|
});
|
|
3714
3512
|
|
|
3715
3513
|
// packages/core/dist/trap-start.js
|
|
3716
|
-
import * as
|
|
3717
|
-
import * as
|
|
3514
|
+
import * as fs19 from "node:fs";
|
|
3515
|
+
import * as path17 from "node:path";
|
|
3718
3516
|
import { createHash as createHash3, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
3719
3517
|
function startPath(trapId) {
|
|
3720
|
-
return
|
|
3518
|
+
return path17.join(soakingDir(), `${trapId}.starting`);
|
|
3721
3519
|
}
|
|
3722
3520
|
function ticketPath(trapId) {
|
|
3723
|
-
return
|
|
3521
|
+
return path17.join(soakingDir(), `${trapId}.ticket`);
|
|
3724
3522
|
}
|
|
3725
3523
|
function readReservationTicket(trapId) {
|
|
3726
3524
|
if (!/^[0-9a-f]{8}$/.test(trapId))
|
|
3727
3525
|
return void 0;
|
|
3728
3526
|
try {
|
|
3729
|
-
const ticket =
|
|
3527
|
+
const ticket = fs19.readFileSync(ticketPath(trapId), "utf8").trim();
|
|
3730
3528
|
return TRAP_TICKET_RE.exec(ticket)?.[1] === trapId ? ticket : void 0;
|
|
3731
3529
|
} catch {
|
|
3732
3530
|
return void 0;
|
|
@@ -3744,17 +3542,17 @@ function trapStartCommands(repoPath, ticket, harness) {
|
|
|
3744
3542
|
return harness === "claude" || harness === "codex" ? all.filter((c) => c.harness === harness) : all;
|
|
3745
3543
|
}
|
|
3746
3544
|
function writeReservation(r) {
|
|
3747
|
-
|
|
3545
|
+
fs19.mkdirSync(soakingDir(), { recursive: true });
|
|
3748
3546
|
const file = startPath(r.trapId);
|
|
3749
3547
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
3750
|
-
|
|
3751
|
-
|
|
3548
|
+
fs19.writeFileSync(tmp, JSON.stringify(r, null, 2));
|
|
3549
|
+
fs19.renameSync(tmp, file);
|
|
3752
3550
|
}
|
|
3753
3551
|
function readReservation(trapId) {
|
|
3754
3552
|
if (!/^[0-9a-f]{8}$/.test(trapId))
|
|
3755
3553
|
return void 0;
|
|
3756
3554
|
try {
|
|
3757
|
-
const parsed = JSON.parse(
|
|
3555
|
+
const parsed = JSON.parse(fs19.readFileSync(startPath(trapId), "utf8"));
|
|
3758
3556
|
return typeof parsed.trapId === "string" && parsed.trapId === trapId ? parsed : void 0;
|
|
3759
3557
|
} catch {
|
|
3760
3558
|
return void 0;
|
|
@@ -3763,7 +3561,7 @@ function readReservation(trapId) {
|
|
|
3763
3561
|
function listReservations() {
|
|
3764
3562
|
let files;
|
|
3765
3563
|
try {
|
|
3766
|
-
files =
|
|
3564
|
+
files = fs19.readdirSync(soakingDir()).filter((f) => f.endsWith(".starting"));
|
|
3767
3565
|
} catch {
|
|
3768
3566
|
return [];
|
|
3769
3567
|
}
|
|
@@ -3794,7 +3592,7 @@ function reserveTrap(opts) {
|
|
|
3794
3592
|
...opts.request ? { request: opts.request } : {}
|
|
3795
3593
|
};
|
|
3796
3594
|
writeReservation(reservation);
|
|
3797
|
-
|
|
3595
|
+
fs19.writeFileSync(ticketPath(trapId), ticket, { mode: 384 });
|
|
3798
3596
|
postNotice({
|
|
3799
3597
|
kind: "trap-starting",
|
|
3800
3598
|
text: `trap ${trapLabel(reservation)} reserved for repo ${opts.repo} \u2014 starting, sign-on due by ${reservation.deadline}; address work with \`--for ${name}\``,
|
|
@@ -3818,8 +3616,8 @@ function reservationForTicket(ticket) {
|
|
|
3818
3616
|
function dropReservation(trapId) {
|
|
3819
3617
|
const r = readReservation(trapId);
|
|
3820
3618
|
if (r)
|
|
3821
|
-
|
|
3822
|
-
|
|
3619
|
+
fs19.rmSync(startPath(trapId), { force: true });
|
|
3620
|
+
fs19.rmSync(ticketPath(trapId), { force: true });
|
|
3823
3621
|
return r;
|
|
3824
3622
|
}
|
|
3825
3623
|
function withdrawReservation(trapId, by) {
|
|
@@ -3875,27 +3673,27 @@ var init_trap_start = __esm({
|
|
|
3875
3673
|
});
|
|
3876
3674
|
|
|
3877
3675
|
// packages/core/dist/soak.js
|
|
3878
|
-
import * as
|
|
3879
|
-
import * as
|
|
3676
|
+
import * as fs20 from "node:fs";
|
|
3677
|
+
import * as path18 from "node:path";
|
|
3880
3678
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
3881
3679
|
function regPath(trapId) {
|
|
3882
|
-
return
|
|
3680
|
+
return path18.join(soakingDir(), `${trapId}.json`);
|
|
3883
3681
|
}
|
|
3884
|
-
function
|
|
3682
|
+
function atomicWrite3(file, content) {
|
|
3885
3683
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
3886
|
-
|
|
3887
|
-
|
|
3684
|
+
fs20.writeFileSync(tmp, content);
|
|
3685
|
+
fs20.renameSync(tmp, file);
|
|
3888
3686
|
}
|
|
3889
3687
|
function readTrapAnchor(worktree) {
|
|
3890
3688
|
try {
|
|
3891
|
-
const parsed = JSON.parse(
|
|
3689
|
+
const parsed = JSON.parse(fs20.readFileSync(path18.join(worktree, TRAP_FILE), "utf8"));
|
|
3892
3690
|
return typeof parsed.trapId === "string" ? parsed : void 0;
|
|
3893
3691
|
} catch {
|
|
3894
3692
|
return void 0;
|
|
3895
3693
|
}
|
|
3896
3694
|
}
|
|
3897
3695
|
function writeTrapAnchor(worktree, anchor) {
|
|
3898
|
-
|
|
3696
|
+
atomicWrite3(path18.join(worktree, TRAP_FILE), `${JSON.stringify(anchor, null, 2)}
|
|
3899
3697
|
`);
|
|
3900
3698
|
}
|
|
3901
3699
|
function trapIdAt(worktree) {
|
|
@@ -3915,12 +3713,12 @@ function newTrapId() {
|
|
|
3915
3713
|
function findAnchored(root, match) {
|
|
3916
3714
|
let names;
|
|
3917
3715
|
try {
|
|
3918
|
-
names =
|
|
3716
|
+
names = fs20.readdirSync(root);
|
|
3919
3717
|
} catch {
|
|
3920
3718
|
return void 0;
|
|
3921
3719
|
}
|
|
3922
3720
|
for (const name of names.sort()) {
|
|
3923
|
-
const dir =
|
|
3721
|
+
const dir = path18.join(root, name);
|
|
3924
3722
|
const anchor = readTrapAnchor(dir);
|
|
3925
3723
|
if (anchor && match(anchor))
|
|
3926
3724
|
return dir;
|
|
@@ -3935,7 +3733,7 @@ function anchoredWorktree(root, trapId) {
|
|
|
3935
3733
|
}
|
|
3936
3734
|
function readTrap(trapId) {
|
|
3937
3735
|
try {
|
|
3938
|
-
return JSON.parse(
|
|
3736
|
+
return JSON.parse(fs20.readFileSync(regPath(trapId), "utf8"));
|
|
3939
3737
|
} catch {
|
|
3940
3738
|
return void 0;
|
|
3941
3739
|
}
|
|
@@ -3976,7 +3774,7 @@ function unknownTrapMessage(address) {
|
|
|
3976
3774
|
}
|
|
3977
3775
|
function listTraps() {
|
|
3978
3776
|
try {
|
|
3979
|
-
return
|
|
3777
|
+
return fs20.readdirSync(soakingDir()).filter((f) => f.endsWith(".json")).map((f) => JSON.parse(fs20.readFileSync(path18.join(soakingDir(), f), "utf8"))).filter((r) => typeof r.trapId === "string");
|
|
3980
3778
|
} catch {
|
|
3981
3779
|
return [];
|
|
3982
3780
|
}
|
|
@@ -4031,12 +3829,12 @@ function signOnTrap(opts) {
|
|
|
4031
3829
|
...sameSession && prior.titleSet ? { titleSet: prior.titleSet, titleSetAt: prior.titleSetAt } : {},
|
|
4032
3830
|
...sameSession && prior.titlePending ? { titlePending: prior.titlePending } : {}
|
|
4033
3831
|
};
|
|
4034
|
-
|
|
3832
|
+
atomicWrite3(regPath(trapId), JSON.stringify(reg, null, 2));
|
|
4035
3833
|
releaseSignedOff(trapId);
|
|
4036
3834
|
if (!prior) {
|
|
4037
3835
|
postNotice({
|
|
4038
3836
|
kind: "trap-signed-on",
|
|
4039
|
-
text: `trap ${trapLabel(reg)} signed on (${opts.harness}, ${opts.repo ?? "no repo"}, ${
|
|
3837
|
+
text: `trap ${trapLabel(reg)} signed on (${opts.harness}, ${opts.repo ?? "no repo"}, ${path18.basename(opts.worktree)}) \u2014 address work with \`--for ${name}\``,
|
|
4040
3838
|
refId: trapId,
|
|
4041
3839
|
repo: opts.repo,
|
|
4042
3840
|
by: opts.sessionId
|
|
@@ -4046,14 +3844,14 @@ function signOnTrap(opts) {
|
|
|
4046
3844
|
}
|
|
4047
3845
|
function readSignedOff(trapId) {
|
|
4048
3846
|
try {
|
|
4049
|
-
return JSON.parse(
|
|
3847
|
+
return JSON.parse(fs20.readFileSync(signedOffPath(trapId), "utf8"));
|
|
4050
3848
|
} catch {
|
|
4051
3849
|
return void 0;
|
|
4052
3850
|
}
|
|
4053
3851
|
}
|
|
4054
3852
|
function listSignedOff() {
|
|
4055
3853
|
try {
|
|
4056
|
-
return
|
|
3854
|
+
return fs20.readdirSync(signedOffDir()).filter((f) => f.endsWith(".json")).flatMap((f) => {
|
|
4057
3855
|
const s = readSignedOff(f.slice(0, -".json".length));
|
|
4058
3856
|
return s ? [s] : [];
|
|
4059
3857
|
});
|
|
@@ -4062,7 +3860,7 @@ function listSignedOff() {
|
|
|
4062
3860
|
}
|
|
4063
3861
|
}
|
|
4064
3862
|
function releaseSignedOff(trapId) {
|
|
4065
|
-
|
|
3863
|
+
fs20.rmSync(signedOffPath(trapId), { force: true });
|
|
4066
3864
|
}
|
|
4067
3865
|
function recentlySignedOff(trapId, graceMs, now2 = Date.now()) {
|
|
4068
3866
|
const s = readSignedOff(trapId);
|
|
@@ -4072,14 +3870,14 @@ function stowTrap(trapId, reason = "signed off", by) {
|
|
|
4072
3870
|
const reg = readTrap(trapId);
|
|
4073
3871
|
if (!reg)
|
|
4074
3872
|
return void 0;
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
3873
|
+
fs20.mkdirSync(signedOffDir(), { recursive: true });
|
|
3874
|
+
atomicWrite3(signedOffPath(trapId), JSON.stringify({ trapId, name: reg.name, worktree: reg.worktree, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
3875
|
+
fs20.rmSync(regPath(trapId), { force: true });
|
|
3876
|
+
fs20.rmSync(beatPath(trapId), { force: true });
|
|
3877
|
+
fs20.rmSync(prProbePath(trapId), { force: true });
|
|
4080
3878
|
postNotice({
|
|
4081
3879
|
kind: "trap-stowed",
|
|
4082
|
-
text: `trap ${trapLabel(reg)} ${reason} (${
|
|
3880
|
+
text: `trap ${trapLabel(reg)} ${reason} (${path18.basename(reg.worktree)}) \u2014 re-soaking that worktree restores the address`,
|
|
4083
3881
|
refId: trapId,
|
|
4084
3882
|
repo: reg.repo,
|
|
4085
3883
|
by
|
|
@@ -4095,7 +3893,7 @@ function askTrapTitle(trapId, title) {
|
|
|
4095
3893
|
delete next.titlePending;
|
|
4096
3894
|
else
|
|
4097
3895
|
next.titlePending = title;
|
|
4098
|
-
|
|
3896
|
+
atomicWrite3(regPath(trapId), JSON.stringify(next, null, 2));
|
|
4099
3897
|
return next;
|
|
4100
3898
|
}
|
|
4101
3899
|
function countTitleReminder(trapId) {
|
|
@@ -4103,7 +3901,7 @@ function countTitleReminder(trapId) {
|
|
|
4103
3901
|
if (!reg?.titlePending)
|
|
4104
3902
|
return void 0;
|
|
4105
3903
|
const n = (reg.titleReminders ?? 0) + 1;
|
|
4106
|
-
|
|
3904
|
+
atomicWrite3(regPath(trapId), JSON.stringify({ ...reg, titleReminders: n }, null, 2));
|
|
4107
3905
|
return n;
|
|
4108
3906
|
}
|
|
4109
3907
|
function confirmTrapTitle(trapId, now2 = Date.now()) {
|
|
@@ -4112,7 +3910,7 @@ function confirmTrapTitle(trapId, now2 = Date.now()) {
|
|
|
4112
3910
|
return void 0;
|
|
4113
3911
|
const { titlePending, titleReminders: _reminders, ...rest } = reg;
|
|
4114
3912
|
const next = { ...rest, titleSet: titlePending ?? reg.titleSet ?? reg.name, titleSetAt: new Date(now2).toISOString() };
|
|
4115
|
-
|
|
3913
|
+
atomicWrite3(regPath(trapId), JSON.stringify(next, null, 2));
|
|
4116
3914
|
return next;
|
|
4117
3915
|
}
|
|
4118
3916
|
function heartbeatTrap(trapId, opts = {}) {
|
|
@@ -4127,7 +3925,7 @@ function heartbeatTrap(trapId, opts = {}) {
|
|
|
4127
3925
|
...opts.parked ? { parkedAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
4128
3926
|
claimed: opts.claimed === null ? void 0 : opts.claimed ?? reg.claimed
|
|
4129
3927
|
};
|
|
4130
|
-
|
|
3928
|
+
atomicWrite3(regPath(trapId), JSON.stringify(next, null, 2));
|
|
4131
3929
|
if (firstPark) {
|
|
4132
3930
|
postNotice({
|
|
4133
3931
|
kind: "trap-listening",
|
|
@@ -4140,11 +3938,11 @@ function heartbeatTrap(trapId, opts = {}) {
|
|
|
4140
3938
|
return next;
|
|
4141
3939
|
}
|
|
4142
3940
|
function claimPath(id, lane) {
|
|
4143
|
-
return
|
|
3941
|
+
return path18.join(laneDirs(lane).active, id, "claim.json");
|
|
4144
3942
|
}
|
|
4145
3943
|
function readSessionClaim(id, lane) {
|
|
4146
3944
|
try {
|
|
4147
|
-
return JSON.parse(
|
|
3945
|
+
return JSON.parse(fs20.readFileSync(claimPath(id, lane), "utf8"));
|
|
4148
3946
|
} catch {
|
|
4149
3947
|
return void 0;
|
|
4150
3948
|
}
|
|
@@ -4156,24 +3954,66 @@ function hasOpenCatch(reg) {
|
|
|
4156
3954
|
if (!reg.claimed)
|
|
4157
3955
|
return false;
|
|
4158
3956
|
const lane = laneOf(reg.claimed);
|
|
4159
|
-
if (!lane || !
|
|
3957
|
+
if (!lane || !fs20.existsSync(path18.join(laneDirs(lane).active, reg.claimed)))
|
|
4160
3958
|
return false;
|
|
4161
3959
|
const last = readStatusLog(reg.claimed, lane).at(-1)?.verb;
|
|
4162
3960
|
return last === void 0 || !TERMINAL_VERBS.includes(last);
|
|
4163
3961
|
}
|
|
3962
|
+
function unreportedTrapBait(reg) {
|
|
3963
|
+
if (!hasOpenCatch(reg))
|
|
3964
|
+
return void 0;
|
|
3965
|
+
const id = reg.claimed;
|
|
3966
|
+
const lane = laneOf(id);
|
|
3967
|
+
const claim = readSessionClaim(id, lane);
|
|
3968
|
+
if (!claim || claim.by !== `wt:${reg.trapId}`)
|
|
3969
|
+
return void 0;
|
|
3970
|
+
const log = readStatusLog(id, lane);
|
|
3971
|
+
let receipt = -1;
|
|
3972
|
+
for (let i = 0; i < log.length; i++) {
|
|
3973
|
+
const s = log[i];
|
|
3974
|
+
if (s.at === claim.at && s.note === `claimed by ${claim.by}` && !s.reported)
|
|
3975
|
+
receipt = i;
|
|
3976
|
+
}
|
|
3977
|
+
const reports = receipt >= 0 ? log.slice(receipt + 1) : log.filter((s) => Date.parse(s.at) >= Date.parse(claim.at));
|
|
3978
|
+
if (reports.some((s) => s.reported))
|
|
3979
|
+
return void 0;
|
|
3980
|
+
try {
|
|
3981
|
+
const descriptor = JSON.parse(fs20.readFileSync(path18.join(laneDirs(lane).active, id, "descriptor.json"), "utf8"));
|
|
3982
|
+
return { id, lane, descriptor, claim };
|
|
3983
|
+
} catch {
|
|
3984
|
+
return void 0;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
function noticeIdleTrapClaims(now2 = Date.now(), graceMs = DEFAULT_SOAK.claimIdleNoticeSecs * 1e3) {
|
|
3988
|
+
for (const reg of listTraps()) {
|
|
3989
|
+
const bait = unreportedTrapBait(reg);
|
|
3990
|
+
if (!bait || cancelRequested(bait.id, bait.lane))
|
|
3991
|
+
continue;
|
|
3992
|
+
const age2 = now2 - Date.parse(bait.claim.at);
|
|
3993
|
+
if (!Number.isFinite(age2) || age2 < graceMs)
|
|
3994
|
+
continue;
|
|
3995
|
+
postNotice({
|
|
3996
|
+
kind: "trap-claim-idle",
|
|
3997
|
+
refId: bait.id,
|
|
3998
|
+
repo: bait.descriptor.repo,
|
|
3999
|
+
text: `${trapLabel(reg)} claimed ${bait.id} ${Math.floor(age2 / 1e3)}s ago but has not reported. The brief will be re-delivered at its next park; check that the session is awake.`,
|
|
4000
|
+
dedupeKey: `trap-claim-idle-${bait.id}-${bait.claim.at}`
|
|
4001
|
+
});
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4164
4004
|
function releaseCatch(reg) {
|
|
4165
4005
|
const id = reg.claimed;
|
|
4166
4006
|
if (!id)
|
|
4167
4007
|
return {};
|
|
4168
4008
|
const lane = laneOf(id);
|
|
4169
|
-
if (!lane || !
|
|
4009
|
+
if (!lane || !fs20.existsSync(path18.join(laneDirs(lane).active, id)))
|
|
4170
4010
|
return {};
|
|
4171
4011
|
const last = readStatusLog(id, lane).at(-1)?.verb;
|
|
4172
4012
|
if (last && TERMINAL_VERBS.includes(last)) {
|
|
4173
4013
|
complete(id, lane);
|
|
4174
4014
|
return { finalized: id };
|
|
4175
4015
|
}
|
|
4176
|
-
|
|
4016
|
+
fs20.rmSync(path18.join(laneDirs(lane).active, id, "claim.json"), { force: true });
|
|
4177
4017
|
if (cancelRequested(id, lane)) {
|
|
4178
4018
|
appendStatus(id, lane, "failed", "cancelled by request; claimant gone, work preserved");
|
|
4179
4019
|
complete(id, lane);
|
|
@@ -4195,7 +4035,7 @@ function claimBait(reg) {
|
|
|
4195
4035
|
const id = claimNext(lane, (d) => !pass(d));
|
|
4196
4036
|
if (!id)
|
|
4197
4037
|
continue;
|
|
4198
|
-
const descriptor = JSON.parse(
|
|
4038
|
+
const descriptor = JSON.parse(fs20.readFileSync(path18.join(laneDirs(lane).active, id, "descriptor.json"), "utf8"));
|
|
4199
4039
|
const claim = {
|
|
4200
4040
|
by: mine,
|
|
4201
4041
|
sessionId: reg.sessionId,
|
|
@@ -4203,7 +4043,7 @@ function claimBait(reg) {
|
|
|
4203
4043
|
worktree: reg.worktree,
|
|
4204
4044
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4205
4045
|
};
|
|
4206
|
-
|
|
4046
|
+
atomicWrite3(claimPath(id, lane), JSON.stringify(claim, null, 2));
|
|
4207
4047
|
appendStatus(id, lane, "working", `claimed by ${mine}`, claim.at);
|
|
4208
4048
|
mergeEvidence(id, lane, { sessionId: reg.sessionId, harness: reg.harness, deliveredTo: mine, deliveredAt: claim.at });
|
|
4209
4049
|
heartbeatTrap(reg.trapId, { claimed: id, parked: true });
|
|
@@ -4258,13 +4098,13 @@ function sweepGhostTraps(ttlMs, now2 = Date.now(), pausedTtlMs = 864e5) {
|
|
|
4258
4098
|
}
|
|
4259
4099
|
}
|
|
4260
4100
|
const released = releaseCatch(reg);
|
|
4261
|
-
const removal = reg.createdWorktree &&
|
|
4101
|
+
const removal = reg.createdWorktree && fs20.existsSync(reg.worktree) ? removeGhostWorktree(reg.worktree) : void 0;
|
|
4262
4102
|
const catchNote = released.requeued ? ", catch requeued" : released.finalized ? ", catch finalized" : "";
|
|
4263
4103
|
const worktreeNote = removal ? `; worktree ${removal.removed ? "removed" : "kept"}: ${reg.worktree}; branch ${removal.branch}; modified files ${removal.modifiedFiles ?? "unknown"}; unpushed commits ${removal.unpushedCommits ?? "unknown"}${removal.reason ? ` (${removal.reason})` : ""}` : "; worktree kept; re-soaking restores the same address";
|
|
4264
4104
|
actions.push({ trapId: reg.trapId, ...released, ...pauseExpired ? { pauseExpired } : {}, ...removal ? { worktree: removal.removed ? "removed" : "kept" } : {} });
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4105
|
+
fs20.rmSync(regPath(reg.trapId), { force: true });
|
|
4106
|
+
fs20.rmSync(beatPath(reg.trapId), { force: true });
|
|
4107
|
+
fs20.rmSync(prProbePath(reg.trapId), { force: true });
|
|
4268
4108
|
postNotice({
|
|
4269
4109
|
kind: "trap-ghosted",
|
|
4270
4110
|
text: (pauseExpired ? `trap ${trapLabel(reg)} ghosted: its pause expired (paused on ${reg.claimed.slice(0, 8)} past --until or [soak].pausedTtlSecs, and quiet since)` : `trap ${trapLabel(reg)} ghosted (went quiet mid-watch)`) + ` \u2014 registration removed${catchNote}${worktreeNote}`,
|
|
@@ -4299,7 +4139,7 @@ function baitBrief(id, d) {
|
|
|
4299
4139
|
`You are a lobstah worker session and have been assigned dispatch ${id}.`,
|
|
4300
4140
|
"",
|
|
4301
4141
|
"Do the work in THIS worktree on a fresh branch (branch first, never on the checked-out state directly).",
|
|
4302
|
-
`
|
|
4142
|
+
`Acknowledge this assignment now with \`lobstah report ${id} working "<note>"\`, then report at milestones, check \`lobstah inbox ${id}\` at natural checkpoints, and finish with \`lobstah report ${id} done "<note>" [--pr <url>]\` (or \`failed\`).`,
|
|
4303
4143
|
"A needs-decision or blocked report queues your question to the human; the answer arrives in this dispatch's inbox.",
|
|
4304
4144
|
`Before you wait on something outside lobstah (a human review, a PR review, a deploy), report \`lobstah report ${id} paused "<note>" --waiting-on review|pr|deploy|person|external --link <url>\`.`,
|
|
4305
4145
|
"After EVERY report, run `lobstah soak --wait` again \u2014 it delivers inbox answers and your next assignment. Never end your turn without it unless you are signing off (`lobstah stow`).",
|
|
@@ -4311,40 +4151,40 @@ function baitBrief(id, d) {
|
|
|
4311
4151
|
].join("\n");
|
|
4312
4152
|
}
|
|
4313
4153
|
function beatPath(trapId) {
|
|
4314
|
-
return
|
|
4154
|
+
return path18.join(soakingDir(), `${trapId}.beat`);
|
|
4315
4155
|
}
|
|
4316
4156
|
function readBeat(trapId) {
|
|
4317
4157
|
try {
|
|
4318
|
-
const parsed = JSON.parse(
|
|
4158
|
+
const parsed = JSON.parse(fs20.readFileSync(beatPath(trapId), "utf8"));
|
|
4319
4159
|
return typeof parsed.at === "string" ? parsed : void 0;
|
|
4320
4160
|
} catch {
|
|
4321
4161
|
return void 0;
|
|
4322
4162
|
}
|
|
4323
4163
|
}
|
|
4324
4164
|
function prProbePath(trapId) {
|
|
4325
|
-
return
|
|
4165
|
+
return path18.join(soakingDir(), `${trapId}.prprobe`);
|
|
4326
4166
|
}
|
|
4327
4167
|
function readTrapPrProbe(trapId) {
|
|
4328
4168
|
try {
|
|
4329
|
-
const parsed = JSON.parse(
|
|
4169
|
+
const parsed = JSON.parse(fs20.readFileSync(prProbePath(trapId), "utf8"));
|
|
4330
4170
|
return typeof parsed.dispatch === "string" && typeof parsed.checkedAt === "string" ? parsed : void 0;
|
|
4331
4171
|
} catch {
|
|
4332
4172
|
return void 0;
|
|
4333
4173
|
}
|
|
4334
4174
|
}
|
|
4335
4175
|
function writeTrapPrProbe(trapId, probe) {
|
|
4336
|
-
|
|
4176
|
+
atomicWrite3(prProbePath(trapId), JSON.stringify(probe));
|
|
4337
4177
|
}
|
|
4338
4178
|
function trapLastSeen(reg) {
|
|
4339
4179
|
return Math.max(msOf(reg.heartbeatAt), msOf(readBeat(reg.trapId)?.at ?? ""));
|
|
4340
4180
|
}
|
|
4341
4181
|
function trapIdAbove(dir) {
|
|
4342
|
-
let at =
|
|
4182
|
+
let at = path18.resolve(dir);
|
|
4343
4183
|
for (; ; ) {
|
|
4344
4184
|
const id = trapIdAt(at);
|
|
4345
4185
|
if (id !== void 0)
|
|
4346
4186
|
return id;
|
|
4347
|
-
const up =
|
|
4187
|
+
const up = path18.dirname(at);
|
|
4348
4188
|
if (up === at)
|
|
4349
4189
|
return void 0;
|
|
4350
4190
|
at = up;
|
|
@@ -4366,7 +4206,7 @@ function beatTrap(input) {
|
|
|
4366
4206
|
if (now2 - last < (input.throttleMs ?? 3e4))
|
|
4367
4207
|
return { beat: false, reason: "throttled" };
|
|
4368
4208
|
const at = new Date(now2).toISOString();
|
|
4369
|
-
|
|
4209
|
+
atomicWrite3(beatPath(trapId), JSON.stringify({ at, sessionId: reg.sessionId }));
|
|
4370
4210
|
if (!hasOpenCatch(reg))
|
|
4371
4211
|
return { beat: true, trapId };
|
|
4372
4212
|
const name = input.toolName || "tool";
|
|
@@ -4391,16 +4231,229 @@ var init_soak = __esm({
|
|
|
4391
4231
|
init_worktrees();
|
|
4392
4232
|
init_worktree_safety();
|
|
4393
4233
|
init_trap_start();
|
|
4234
|
+
init_config();
|
|
4394
4235
|
TRAP_FILE = ".lobstah-trap";
|
|
4395
4236
|
TRAP_ANCHOR_FILE = TRAP_FILE;
|
|
4396
4237
|
TRAP_ADDRESS_RE = /\bwt:([a-z0-9][a-z0-9-]*)/g;
|
|
4397
|
-
signedOffDir = () =>
|
|
4398
|
-
signedOffPath = (trapId) =>
|
|
4238
|
+
signedOffDir = () => path18.join(path18.dirname(soakingDir()), "signed-off");
|
|
4239
|
+
signedOffPath = (trapId) => path18.join(signedOffDir(), `${trapId}.json`);
|
|
4399
4240
|
TITLE_REMINDERS = 3;
|
|
4400
4241
|
msOf = (iso) => Date.parse(iso) || 0;
|
|
4401
4242
|
}
|
|
4402
4243
|
});
|
|
4403
4244
|
|
|
4245
|
+
// packages/core/dist/helm.js
|
|
4246
|
+
import * as fs21 from "node:fs";
|
|
4247
|
+
import * as path19 from "node:path";
|
|
4248
|
+
function helmDir() {
|
|
4249
|
+
return path19.join(lobstahHome(), "helm");
|
|
4250
|
+
}
|
|
4251
|
+
function relievedDir() {
|
|
4252
|
+
return path19.join(helmDir(), ".relieved");
|
|
4253
|
+
}
|
|
4254
|
+
function helmPath(grounds) {
|
|
4255
|
+
return path19.join(helmDir(), `${grounds}.json`);
|
|
4256
|
+
}
|
|
4257
|
+
function atomicWrite4(file, content) {
|
|
4258
|
+
fs21.mkdirSync(path19.dirname(file), { recursive: true });
|
|
4259
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
4260
|
+
fs21.writeFileSync(tmp, content);
|
|
4261
|
+
fs21.renameSync(tmp, file);
|
|
4262
|
+
}
|
|
4263
|
+
function readHelm(grounds) {
|
|
4264
|
+
try {
|
|
4265
|
+
return JSON.parse(fs21.readFileSync(helmPath(grounds), "utf8"));
|
|
4266
|
+
} catch {
|
|
4267
|
+
return void 0;
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
function listHelms() {
|
|
4271
|
+
try {
|
|
4272
|
+
return fs21.readdirSync(helmDir()).filter((f) => f.endsWith(".json")).map((f) => JSON.parse(fs21.readFileSync(path19.join(helmDir(), f), "utf8")));
|
|
4273
|
+
} catch {
|
|
4274
|
+
return [];
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
function helmOf(sessionId) {
|
|
4278
|
+
return listHelms().find((h) => h.sessionId === sessionId);
|
|
4279
|
+
}
|
|
4280
|
+
function liveHelms(ttlMs, now2 = Date.now()) {
|
|
4281
|
+
return listHelms().filter((h) => now2 - (Date.parse(h.heartbeatAt) || 0) <= ttlMs);
|
|
4282
|
+
}
|
|
4283
|
+
function helmGate(live, sessionId, grounds) {
|
|
4284
|
+
if (grounds !== void 0) {
|
|
4285
|
+
const holder = live.find((h) => h.grounds === grounds);
|
|
4286
|
+
if (holder && holder.sessionId !== sessionId) {
|
|
4287
|
+
return `grounds "${grounds}" is helmed by session ${holder.sessionId.slice(0, 8)} \u2014 its verbs are that session's alone. Run this from that session (--session), or take its helm (\`lobstah man helm --take\`).`;
|
|
4288
|
+
}
|
|
4289
|
+
if (holder)
|
|
4290
|
+
return void 0;
|
|
4291
|
+
}
|
|
4292
|
+
if (live.length === 0)
|
|
4293
|
+
return void 0;
|
|
4294
|
+
if (sessionId !== void 0 && live.some((h) => h.sessionId === sessionId))
|
|
4295
|
+
return void 0;
|
|
4296
|
+
const holders = live.map((h) => `${h.grounds}=${h.sessionId.slice(0, 8)}`).join(", ");
|
|
4297
|
+
return `the helm is claimed (${holders}) \u2014 this verb is reserved for the helm session. Run it there with --session <helm-session-id>, or take the helm (\`lobstah man helm --take\`).`;
|
|
4298
|
+
}
|
|
4299
|
+
function helmLabel(h) {
|
|
4300
|
+
if (h.label)
|
|
4301
|
+
return h.label;
|
|
4302
|
+
const where = h.cwd ? path19.basename(h.cwd) : void 0;
|
|
4303
|
+
if (!h.harness && !where)
|
|
4304
|
+
return `session ${h.sessionId.slice(0, 8)}`;
|
|
4305
|
+
return `${h.harness ?? "session"}${where ? ` @ ${where}` : ""}`;
|
|
4306
|
+
}
|
|
4307
|
+
function takeHelm(opts) {
|
|
4308
|
+
const now2 = opts.now ?? Date.now();
|
|
4309
|
+
const existing = readHelm(opts.grounds.name);
|
|
4310
|
+
if (existing && existing.sessionId !== opts.sessionId) {
|
|
4311
|
+
const fresh = now2 - (Date.parse(existing.heartbeatAt) || 0) <= opts.ttlMs;
|
|
4312
|
+
if (fresh && !opts.take)
|
|
4313
|
+
return { held: existing };
|
|
4314
|
+
atomicWrite4(path19.join(relievedDir(), `${existing.sessionId}.json`), JSON.stringify({
|
|
4315
|
+
sessionId: existing.sessionId,
|
|
4316
|
+
grounds: opts.grounds.name,
|
|
4317
|
+
by: opts.sessionId,
|
|
4318
|
+
at: new Date(now2).toISOString()
|
|
4319
|
+
}, null, 2));
|
|
4320
|
+
}
|
|
4321
|
+
const iso = new Date(now2).toISOString();
|
|
4322
|
+
const same = existing?.sessionId === opts.sessionId;
|
|
4323
|
+
const live = existing !== void 0 && now2 - (Date.parse(existing.heartbeatAt) || 0) <= opts.ttlMs;
|
|
4324
|
+
const reg = {
|
|
4325
|
+
sessionId: opts.sessionId,
|
|
4326
|
+
grounds: opts.grounds.name,
|
|
4327
|
+
repos: opts.grounds.repos,
|
|
4328
|
+
signedOnAt: same ? existing.signedOnAt : iso,
|
|
4329
|
+
heartbeatAt: iso,
|
|
4330
|
+
// A new helm on empty grounds starts its cursor now: a notice delivered
|
|
4331
|
+
// to nobody while no helm was signed on is not news. A take from a live
|
|
4332
|
+
// helm, or the same session signing on again, keeps the cursor, so
|
|
4333
|
+
// nothing in flight is dropped.
|
|
4334
|
+
wakesFrom: same || live ? existing.wakesFrom : iso,
|
|
4335
|
+
// Identity refreshes on every sign-on; a re-sign without one keeps what
|
|
4336
|
+
// the registration already knows.
|
|
4337
|
+
harness: opts.identity?.harness ?? (same ? existing.harness : void 0),
|
|
4338
|
+
cwd: opts.identity?.cwd ?? (same ? existing.cwd : void 0),
|
|
4339
|
+
host: opts.identity?.host ?? (same ? existing.host : void 0),
|
|
4340
|
+
label: opts.identity?.label ?? (same ? existing.label : void 0),
|
|
4341
|
+
window: opts.identity?.window ?? (same ? existing.window : void 0),
|
|
4342
|
+
tookFrom: existing && existing.sessionId !== opts.sessionId ? { sessionId: existing.sessionId, at: iso } : existing?.tookFrom
|
|
4343
|
+
};
|
|
4344
|
+
atomicWrite4(helmPath(opts.grounds.name), JSON.stringify(reg, null, 2));
|
|
4345
|
+
return { ok: reg };
|
|
4346
|
+
}
|
|
4347
|
+
function wakeFloorMs(h) {
|
|
4348
|
+
return h?.wakesFrom ? Date.parse(h.wakesFrom) || 0 : 0;
|
|
4349
|
+
}
|
|
4350
|
+
function noticeStands(n) {
|
|
4351
|
+
switch (n.kind) {
|
|
4352
|
+
case "disk-held":
|
|
4353
|
+
return readHold() !== void 0;
|
|
4354
|
+
case "watch-failing":
|
|
4355
|
+
case "watch-held":
|
|
4356
|
+
return listWatches().some((w) => (w.key === n.refId || w.owner === `dispatch:${n.refId}`) && (n.kind === "watch-failing" ? w.failingNoticed === true : true));
|
|
4357
|
+
case "trap-request":
|
|
4358
|
+
return n.refId !== void 0 && isOpenRequest(n.refId);
|
|
4359
|
+
case "trap-claim-idle":
|
|
4360
|
+
return listTraps().some((reg) => {
|
|
4361
|
+
if (reg.claimed !== n.refId)
|
|
4362
|
+
return false;
|
|
4363
|
+
const bait = unreportedTrapBait(reg);
|
|
4364
|
+
return bait !== void 0 && !cancelRequested(bait.id, bait.lane) && Date.parse(bait.claim.at) <= Date.parse(n.at);
|
|
4365
|
+
});
|
|
4366
|
+
default:
|
|
4367
|
+
return false;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
function noticeWakes(h) {
|
|
4371
|
+
const floor = wakeFloorMs(h);
|
|
4372
|
+
if (floor === 0)
|
|
4373
|
+
return void 0;
|
|
4374
|
+
return (n) => (Date.parse(n.at) || 0) >= floor || noticeStands(n);
|
|
4375
|
+
}
|
|
4376
|
+
function relieveHelm(sessionId) {
|
|
4377
|
+
const relieved = [];
|
|
4378
|
+
for (const h of listHelms()) {
|
|
4379
|
+
if (h.sessionId !== sessionId)
|
|
4380
|
+
continue;
|
|
4381
|
+
fs21.rmSync(helmPath(h.grounds), { force: true });
|
|
4382
|
+
relieved.push(h.grounds);
|
|
4383
|
+
}
|
|
4384
|
+
fs21.rmSync(path19.join(relievedDir(), `${sessionId}.json`), { force: true });
|
|
4385
|
+
return relieved;
|
|
4386
|
+
}
|
|
4387
|
+
function heartbeatHelm(sessionId, opts = {}) {
|
|
4388
|
+
const reg = helmOf(sessionId);
|
|
4389
|
+
if (!reg)
|
|
4390
|
+
return void 0;
|
|
4391
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
4392
|
+
const next = { ...reg, heartbeatAt: now2, ...opts.parked ? { parkedAt: now2 } : {} };
|
|
4393
|
+
atomicWrite4(helmPath(reg.grounds), JSON.stringify(next, null, 2));
|
|
4394
|
+
return next;
|
|
4395
|
+
}
|
|
4396
|
+
function consumeRelievedNotice(sessionId) {
|
|
4397
|
+
const file = path19.join(relievedDir(), `${sessionId}.json`);
|
|
4398
|
+
try {
|
|
4399
|
+
const notice = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
4400
|
+
fs21.rmSync(file, { force: true });
|
|
4401
|
+
return notice;
|
|
4402
|
+
} catch {
|
|
4403
|
+
return void 0;
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
function groundsList(cfg) {
|
|
4407
|
+
const entries = Object.entries(cfg.grounds);
|
|
4408
|
+
if (entries.length === 0)
|
|
4409
|
+
return [{ name: "fleet", repos: Object.keys(cfg.repos) }];
|
|
4410
|
+
return entries.map(([name, g]) => ({ name, repos: g.repos }));
|
|
4411
|
+
}
|
|
4412
|
+
function groundsErrors(cfg) {
|
|
4413
|
+
const errors = [];
|
|
4414
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4415
|
+
for (const [name, g] of Object.entries(cfg.grounds)) {
|
|
4416
|
+
for (const repo of g.repos) {
|
|
4417
|
+
if (cfg.repos[repo] === void 0)
|
|
4418
|
+
errors.push(`grounds.${name} names unknown repo "${repo}"`);
|
|
4419
|
+
const other = seen.get(repo);
|
|
4420
|
+
if (other !== void 0)
|
|
4421
|
+
errors.push(`repo "${repo}" is in both grounds.${other} and grounds.${name} \u2014 a repo belongs to at most one grounds`);
|
|
4422
|
+
else
|
|
4423
|
+
seen.set(repo, name);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
return errors;
|
|
4427
|
+
}
|
|
4428
|
+
function resolveGrounds(cfg, name) {
|
|
4429
|
+
const all = groundsList(cfg);
|
|
4430
|
+
if (name === void 0) {
|
|
4431
|
+
if (all.length === 1)
|
|
4432
|
+
return all[0];
|
|
4433
|
+
throw new Error(`multiple grounds configured \u2014 pass --grounds <${all.map((g) => g.name).join("|")}>`);
|
|
4434
|
+
}
|
|
4435
|
+
const found = all.find((g) => g.name === name);
|
|
4436
|
+
if (!found)
|
|
4437
|
+
throw new Error(`unknown grounds "${name}" (configured: ${all.map((g) => g.name).join(", ")})`);
|
|
4438
|
+
return found;
|
|
4439
|
+
}
|
|
4440
|
+
var isOpenRequest;
|
|
4441
|
+
var init_helm = __esm({
|
|
4442
|
+
"packages/core/dist/helm.js"() {
|
|
4443
|
+
"use strict";
|
|
4444
|
+
init_disk();
|
|
4445
|
+
init_paths();
|
|
4446
|
+
init_watch();
|
|
4447
|
+
init_requests();
|
|
4448
|
+
init_queue();
|
|
4449
|
+
init_soak();
|
|
4450
|
+
isOpenRequest = (id) => {
|
|
4451
|
+
const r = readRequest(id);
|
|
4452
|
+
return r !== void 0 && r.closedAt === void 0;
|
|
4453
|
+
};
|
|
4454
|
+
}
|
|
4455
|
+
});
|
|
4456
|
+
|
|
4404
4457
|
// packages/core/dist/inbox.js
|
|
4405
4458
|
import * as fs22 from "node:fs";
|
|
4406
4459
|
import * as path20 from "node:path";
|
|
@@ -8693,6 +8746,7 @@ function tick(log = () => {
|
|
|
8693
8746
|
for (const t of bounceExpiredSignOffs(signOffGraceMs))
|
|
8694
8747
|
log(`trap wt:${t} did not re-soak within the sign-off grace \u2014 its messages bounced to the helm`);
|
|
8695
8748
|
noticeOrphanedBait(Date.now(), signOffGraceMs);
|
|
8749
|
+
noticeIdleTrapClaims(now2, cfg.soak.claimIdleNoticeSecs * 1e3);
|
|
8696
8750
|
const workSkip = daemonSkip(listTraps(), cfg.soak.deferSecs * 1e3);
|
|
8697
8751
|
const choreSkip = (d) => d.for !== void 0 && (!d.systemRepair?.trapWaitUntil || Date.now() < Date.parse(d.systemRepair.trapWaitUntil));
|
|
8698
8752
|
const skipFor = (lane) => lane === "work" ? workSkip : choreSkip;
|
|
@@ -14385,7 +14439,7 @@ import { randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from
|
|
|
14385
14439
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
14386
14440
|
|
|
14387
14441
|
// apps/cli/src/glass-page.generated.ts
|
|
14388
|
-
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}.catchn{white-space:nowrap}.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}.older{padding:8px 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.click{cursor:pointer}.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}.pet-art{display:block;position:relative;width:72px;height:56px}.brand-pet{display:inline-block;width:36px;height:28px;vertical-align:middle}.brand-pet .pet-art{transform:scale(0.5);transform-origin:top left}.pet-art .sprite{width:72px;height:56px;background-position:0 0;background-repeat:no-repeat;background-size:400% 100%;image-rendering:pixelated;animation:step 0.5s steps(4) infinite}.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}.pet-art .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}}#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;max-width:100%;overflow-x:auto;white-space:pre;overflow-wrap:normal}.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{max-width:100%;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;white-space:normal;overflow-wrap:anywhere;min-width:12ch}.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{width:100%;max-width:1100px;margin:0 auto;padding:20px 16px 48px;overflow-wrap:anywhere}.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}@media(max-width:600px){.reportview{padding:12px 0 32px}.reportview .mdpage{padding:8px 12px}}</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 Ee,b,es,ur,U,Qt,ts,ss,rt,Ie,ue,ns,it,at,ot,fr,Ae={},Me=[],mr=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Le=Array.isArray;function L(e,t){for(var s in t)e[s]=t[s];return e}function lt(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Y(e,t,s){var n,a,r,o={};for(r in t)r=="key"?n=t[r]:r=="ref"?a=t[r]:o[r]=t[r];if(arguments.length>2&&(o.children=arguments.length>3?Ee.call(arguments,2):s),typeof e=="function"&&e.defaultProps!=null)for(r in e.defaultProps)o[r]===void 0&&(o[r]=e.defaultProps[r]);return Pe(e,o,n,a,null)}function Pe(e,t,s,n,a){var r={type:e,props:t,key:s,ref:n,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:a??++es,__i:-1,__u:0};return a==null&&b.vnode!=null&&b.vnode(r),r}function X(e){return e.children}function Re(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 hr(e){if(e.__P&&e.__d){var t=e.__v,s=t.__e,n=[],a=[],r=L({},t);r.__v=t.__v+1,b.vnode&&b.vnode(r),ct(e.__P,r,t,e.__n,e.__P.namespaceURI,32&t.__u?[s]:null,n,s??W(t),!!(32&t.__u),a),r.__v=t.__v,r.__.__k[r.__i]=r,ls(n,r,a),t.__e=t.__=null,r.__e!=s&&rs(r)}}function rs(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}),rs(e)}function Yt(e){(!e.__d&&(e.__d=!0)&&U.push(e)&&!Oe.__r++||Qt!=b.debounceRendering)&&((Qt=b.debounceRendering)||ts)(Oe)}function Oe(){try{for(var e,t=1;U.length;)U.length>t&&U.sort(ss),e=U.shift(),t=U.length,hr(e)}finally{U.length=Oe.__r=0}}function as(e,t,s,n,a,r,o,c,u,l,f){var h,d,m,p,g,D,S=n&&n.__k||Me,_=t.length;for(u=gr(s,t,S,u,_),h=0;h<_;h++)(m=s.__k[h])!=null&&(d=m.__i!=-1&&S[m.__i]||Ae,m.__i=h,D=ct(e,m,d,a,r,o,c,u,l,f),p=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&dt(d.ref,null,m),f.push(m.ref,m.__c||p,m)),g==null&&p!=null&&(g=p),4&m.__u?(u=os(m,u,e),d.__e&&(d.__e=null)):typeof m.type=="function"&&D!==void 0?u=D:p&&(u=p.nextSibling),m.__u&=-7);return s.__e=g,u}function gr(e,t,s,n,a){var r,o,c,u,l,f=s.length,h=f,d=0;for(e.__k=new Array(a),r=0;r<a;r++)(o=t[r])!=null&&typeof o!="boolean"&&typeof o!="function"?(typeof o=="string"||typeof o=="number"||typeof o=="bigint"||o.constructor==String?o=e.__k[r]=Pe(null,o,null,null,null):Le(o)?o=e.__k[r]=Pe(X,{children:o},null,null,null):o.constructor===void 0&&o.__b>0?o=e.__k[r]=Pe(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):e.__k[r]=o,u=r+d,o.__=e,o.__b=e.__b+1,c=null,(l=o.__i=vr(o,s,u,h))!=-1&&(h--,(c=s[l])&&(c.__u|=2)),c==null||c.__v==null?(l==-1&&(a>f?d--:a<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[r]=null;if(h)for(r=0;r<f;r++)(c=s[r])!=null&&(2&c.__u)==0&&(c.__e==n&&(n=W(c)),ds(c,c));return n}function os(e,t,s){var n,a;if(typeof e.type=="function"){for(n=e.__k,a=0;n&&a<n.length;a++)n[a]&&(n[a].__=e,t=os(n[a],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 vr(e,t,s,n){var a,r,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(a=s-1,r=s+1;a>=0||r<t.length;)if((l=t[o=a>=0?a--:r++])!=null&&(2&l.__u)==0&&c==l.key&&u==l.type)return o}return-1}function Xt(e,t,s){t[0]=="-"?e.setProperty(t,s??""):e[t]=s==null?"":typeof s!="number"||mr.test(t)?s:s+"px"}function Te(e,t,s,n,a){var r,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||Xt(e.style,t,"");if(s)for(t in s)n&&s[t]==n[t]||Xt(e.style,t,s[t])}else if(t[0]=="o"&&t[1]=="n")r=t!=(t=t.replace(ns,"$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+r]=s,s?n?s[ue]=n[ue]:(s[ue]=it,e.addEventListener(t,r?ot:at,r)):e.removeEventListener(t,r?ot:at,r);else{if(a=="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 Zt(e){return function(t){if(this.l){var s=this.l[t.type+e];if(t[Ie]==null)t[Ie]=it++;else if(t[Ie]<s[ue])return;return s(b.event?b.event(t):t)}}}function ct(e,t,s,n,a,r,o,c,u,l){var f,h,d,m,p,g,D,S,_,A,de,F,pe,Jt,xe,nt,M=t.type;if(t.constructor!==void 0)return null;128&s.__u&&(u=!!(32&s.__u),r=[c=t.__e=s.__e]),(f=b.__b)&&f(t);e:if(typeof M=="function"){h=o.length;try{if(_=t.props,A=M.prototype&&M.prototype.render,de=(f=M.contextType)&&n[f.__c],F=f?de?de.props.value:f.__:n,s.__c?S=(d=t.__c=s.__c).__=d.__E:(A?t.__c=d=new M(_,F):(t.__c=d=new Re(_,F),d.constructor=M,d.render=_r),de&&de.sub(d),d.state||(d.state={}),d.__n=n,m=d.__d=!0,d.__h=[],d._sb=[]),A&&d.__s==null&&(d.__s=d.state),A&&M.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=L({},d.__s)),L(d.__s,M.getDerivedStateFromProps(_,d.__s))),p=d.props,g=d.state,d.__v=t,m)A&&M.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),A&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(A&&M.getDerivedStateFromProps==null&&_!==p&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps(_,F),t.__v==s.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate(_,d.__s,F)===!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(Q){Q&&(Q.__=t)}),Me.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,F),A&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(p,g,D)})}if(d.context=F,d.props=_,d.__P=e,d.__e=!1,pe=b.__r,Jt=0,A)d.state=d.__s,d.__d=!1,pe&&pe(t),f=d.render(d.props,d.state,d.context),Me.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,pe&&pe(t),f=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++Jt<25);d.state=d.__s,d.getChildContext!=null&&(n=L(L({},n),d.getChildContext())),A&&!m&&d.getSnapshotBeforeUpdate!=null&&(D=d.getSnapshotBeforeUpdate(p,g)),xe=f!=null&&f.type===X&&f.key==null?cs(f.props.children):f,c=as(e,Le(xe)?xe:[xe],t,s,n,a,r,o,c,u,l),d.base=t.__e,t.__u&=-161,d.__h.length&&o.push(d),S&&(d.__E=d.__=null)}catch(Q){if(o.length=h,t.__v=null,u||r!=null){if(Q.then){for(t.__u|=u?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;r!=null&&(r[r.indexOf(c)]=null),t.__e=c}else if(r!=null)for(nt=r.length;nt--;)lt(r[nt])}else t.__e=s.__e;t.__k==null&&(t.__k=s.__k||[]),Q.then||is(t),b.__e(Q,t,s)}}else r==null&&t.__v==s.__v?(t.__k=s.__k,t.__e=s.__e):c=t.__e=$r(s.__e,t,s,n,a,r,o,u,l);return(f=b.diffed)&&f(t),128&t.__u?void 0:c}function is(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(is))}function ls(e,t,s){for(var n=0;n<s.length;n++)dt(s[n],s[++n],s[++n]);b.__c&&b.__c(t,e),e.some(function(a){try{e=a.__h,a.__h=[],e.some(function(r){r.call(a)})}catch(r){b.__e(r,a.__v)}})}function cs(e){return typeof e!="object"||e==null||e.__b>0?e:Le(e)?e.map(cs):e.constructor!==void 0?null:L({},e)}function $r(e,t,s,n,a,r,o,c,u){var l,f,h,d,m,p,g,D=s.props||Ae,S=t.props,_=t.type;if(_=="svg"?a="http://www.w3.org/2000/svg":_=="math"?a="http://www.w3.org/1998/Math/MathML":a||(a="http://www.w3.org/1999/xhtml"),r!=null){for(l=0;l<r.length;l++)if((m=r[l])&&"setAttribute"in m==!!_&&(_?m.localName==_:m.nodeType==3)){e=m,r[l]=null;break}}if(e==null){if(_==null)return document.createTextNode(S);e=document.createElementNS(a,_,S.is&&S),c&&(b.__m&&b.__m(t,r),c=!1),r=null}if(_==null)D===S||c&&e.data==S||(e.data=S);else{if(r=_=="textarea"&&S.defaultValue!=null?null:r&&Ee.call(e.childNodes),!c&&r!=null)for(D={},l=0;l<e.attributes.length;l++)D[(m=e.attributes[l]).name]=m.value;for(l in D)m=D[l],l=="dangerouslySetInnerHTML"?h=m:l=="children"||l in S||l=="value"&&"defaultValue"in S||l=="checked"&&"defaultChecked"in S||Te(e,l,null,m,a);for(l in S)m=S[l],l=="children"?d=m:l=="dangerouslySetInnerHTML"?f=m:l=="value"?p=m:l=="checked"?g=m:c&&typeof m!="function"||D[l]===m||Te(e,l,m,D[l],a);if(f)c||h&&(f.__html==h.__html||f.__html==e.innerHTML)||(e.innerHTML=f.__html),t.__k=[];else if(h&&(e.innerHTML=""),as(t.type=="template"?e.content:e,Le(d)?d:[d],t,s,n,_=="foreignObject"?"http://www.w3.org/1999/xhtml":a,r,o,r?r[0]:s.__k&&W(s,0),c,u),r!=null)for(l=r.length;l--;)lt(r[l]);c&&_!="textarea"||(l="value",_=="progress"&&p==null?e.removeAttribute("value"):p!=null&&(p!==e[l]||_=="progress"&&!p||_=="option"&&p!=D[l])&&Te(e,l,p,D[l],a),l="checked",g!=null&&g!=e[l]&&Te(e,l,g,D[l],a))}return e}function dt(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(a){b.__e(a,s)}}function ds(e,t,s){var n,a;if(b.unmount&&b.unmount(e),(n=e.ref)&&(n.current&&n.current!=e.__e||dt(n,null,t)),(n=e.__c)!=null){if(n.componentWillUnmount)try{n.componentWillUnmount()}catch(r){b.__e(r,t)}n.base=n.__P=n.__n=null}if(n=e.__k)for(a=0;a<n.length;a++)n[a]&&ds(n[a],t,s||typeof e.type!="function");s||lt(e.__e),e.__c=e.__=e.__e=void 0}function _r(e,t,s){return this.constructor(e,s)}function pt(e,t,s){var n,a,r,o;t==document&&(t=document.documentElement),b.__&&b.__(e,t),a=(n=typeof s=="function")?null:s&&s.__k||t.__k,r=[],o=[],ct(t,e=(!n&&s||t).__k=Y(X,null,[e]),a||Ae,Ae,t.namespaceURI,!n&&s?[s]:a?null:t.firstChild?Ee.call(t.childNodes):null,r,!n&&s?s:a?a.__e:t.firstChild,n,o),ls(r,e,o),e.props.children=null}Ee=Me.slice,b={__e:function(e,t,s,n){for(var a,r,o;t=t.__;)if((a=t.__c)&&!a.__)try{if((r=a.constructor)&&r.getDerivedStateFromError!=null&&(a.setState(r.getDerivedStateFromError(e)),o=a.__d),a.componentDidCatch!=null&&(a.componentDidCatch(e,n||{}),o=a.__d),o)return a.__E=a}catch(c){e=c}throw e}},es=0,ur=function(e){return e!=null&&e.constructor===void 0},Re.prototype.setState=function(e,t){var s;s=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=L({},this.state),typeof e=="function"&&(e=e(L({},s),this.props)),e&&L(s,e),e!=null&&this.__v&&(t&&this._sb.push(t),Yt(this))},Re.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Yt(this))},Re.prototype.render=X,U=[],ts=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,ss=function(e,t){return e.__v.__b-t.__v.__b},Oe.__r=0,rt=Math.random().toString(8),Ie="__d"+rt,ue="__a"+rt,ns=/(PointerCapture)$|Capture$/i,it=0,at=Zt(!1),ot=Zt(!0),fr=0;var Z=e=>e>999?"999+":String(e);function br(e){return{id:e,lane:"work",bucket:"done",repo:"",title:"",verb:"unknown",sort:0}}var ps=new WeakMap;function ut(e,t){let s=e.dispatches||[],n=ps.get(s);return n||ps.set(s,n=new Map(s.map(a=>[a.id,a]))),{...t,catches:(t.catches||[]).map(a=>n.get(a)??br(a))}}function O(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 ee=["deck","dispatches","traps","prs","reports","notices"];function hs(e){let t=String(e||"").replace(/^#/,"");return ee.includes(t)?t:"deck"}var ft=e=>`#decision/${encodeURIComponent(e)}`;function Ne(e){let t=/^#?decision\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var mt=(e,t,s)=>`/attachment/dispatch/${encodeURIComponent(e)}/${encodeURIComponent(t)}/${encodeURIComponent(s)}`,gs=(e,t)=>`/attachment/trap/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,vs=e=>/\\.(png|jpe?g|gif|webp)$/i.test(e),ht=(e,t)=>`/decision/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function gt(e,t){let s=new Map(t.map(a=>[a.key,a])),n=[];for(let a of e)if(a.kind==="decision"){let r=s.get(a.key);if(!r)continue;n.push({kind:"decision",key:r.key,title:r.title,detail:r.detail,options:r.options,attachments:r.attachments,...r.dispatch?{dispatch:r.dispatch,lane:r.lane??"work"}:{},...r.repo?{repo:r.repo}:{},at:r.askedAt})}else a.kind==="question"&&n.push({kind:"question",key:a.key,verb:a.verb,note:a.note||a.verb,dispatch:a.id,lane:a.lane,...a.repo?{repo:a.repo}:{},at:a.at??""});return n.sort((a,r)=>r.at.localeCompare(a.at)||a.key.localeCompare(r.key))}function $s(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 _s(e,t){return(e.reports||[]).find(s=>s.key===`report:${t.lane}:${t.id}`)}function fe(e){return e.author==="helm"?"":e.trap?e.trap:e.author==="headless"?e.dispatch?e.dispatch.slice(0,8):"":e.author}var us=(e,t)=>+!!e.acked-+!!t.acked||t.filedAt.localeCompare(e.filedAt),C=e=>`/report/${encodeURIComponent(e)}`;function me(e){let t=/^#?report\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}function bs(e){return typeof e!="string"?!1:e===""?!0:e.length>1024||!e.startsWith("#")||/[\\s\\x00-\\x1f\\x7f]/.test(e)?!1:ee.includes(e.slice(1))||Ne(e)!==null||me(e)!==null}function ks(e){let t=/^\\/report\\/([^/?#]+)\\/?$/.exec(e);if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var ys=e=>`/report/${encodeURIComponent(e)}/md`,vt=(e,t)=>`/report/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`,$t={dispatches:[],notices:[],prs:[],stacks:[]};function ws(e,t){if(t.kind==="dispatches"){let a=new Set(e.dispatches.map(r=>r.lane+":"+r.id));return{...e,dispatches:[...e.dispatches,...t.items.filter(r=>!a.has(r.lane+":"+r.id))]}}if(t.kind==="notices"){let a=new Set(e.notices.map(r=>r.seq));return{...e,notices:[...e.notices,...t.items.filter(r=>!a.has(r.seq))]}}let s=new Set(e.prs.map(a=>a.key)),n=new Set(e.stacks.map(a=>a.id));return{...e,prs:[...e.prs,...t.items.filter(a=>!s.has(a.key))],stacks:[...e.stacks,...t.stacks.filter(a=>!n.has(a.id))]}}function Gs(e,t){if(t===$t||!t.dispatches.length&&!t.notices.length&&!t.prs.length)return e;let s=new Set(e.dispatches.map(o=>o.lane+":"+o.id)),n=new Set(e.notices.map(o=>o.seq)),a=new Set(e.prs.map(o=>o.key)),r=new Set(e.stacks.map(o=>o.id));return{...e,dispatches:[...e.dispatches,...t.dispatches.filter(o=>!s.has(o.lane+":"+o.id))],notices:[...e.notices,...t.notices.filter(o=>!n.has(o.seq))],prs:[...e.prs,...t.prs.filter(o=>!a.has(o.key))],stacks:[...e.stacks,...t.stacks.filter(o=>!r.has(o.id))]}}function Ss(e,t,s){return Math.max(0,(e.older?.[s]??0)-t[s].length)}function Ds(e,t){return{...e,now:t.now,daemon:e.daemon&&t.daemon!==void 0?{...e.daemon,heartbeat:t.daemon}:e.daemon,helms:e.helms.map(s=>t.helms[s.grounds]!==void 0?{...s,heartbeatAt:t.helms[s.grounds]}:s),traps:e.traps.map(s=>t.traps[s.trapId]?{...s,...t.traps[s.trapId]}:s)}}function fs(e,t,s){return!!e&&s-Date.parse(e)>t}function ms(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.title||"")+" "+(e.repo||"")+" "+(e.for||"")).toLowerCase().includes(s))return!1}return!0}function te(e,t,s){if(!t)return null;if(t.type==="helm")return e.helms.find(a=>a.grounds===t.key)||null;if(t.type==="dispatch"){let a=e.dispatches.find(o=>o.lane+":"+o.id===t.key),r=s&&s.key===t.key?s.data:void 0;return a&&r?{...a,...r}:a??r??null}if(t.type==="pr")return(e.prs||[]).find(a=>a.key===t.key)||null;if(t.type==="settings")return{attentionKinds:e.attentionKinds||[],attentionError:e.attentionError};let n=e.traps.find(a=>a.trapId===t.key);return n?ut(e,n):null}function Cs(e,t,s){let n=t.st,a=String(n.q||"").toLowerCase(),r=(...p)=>!a||p.join(" ").toLowerCase().includes(a),o=p=>({x:p,stale:fs(p.heartbeatAt,18e5,s)}),c=te(e,t.modal,t.detail),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)))&&r(p.name,p.trapId,p.repo,p.worktree)),m=({ageSecs:p,...g})=>g;return{chips:{daemon:e.daemon,daemonStale:!!e.daemon&&fs(e.daemon.heartbeat,9e4,s),helms:e.helms.map(o),stats:e.stats},deck:{view:n.view,decisions:gt(e.attention||[],e.decisions||[]).filter(p=>p.kind==="decision"?r(p.kind,p.repo,p.title,p.dispatch,p.detail):r(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)&&r(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=>r(p.title,p.author,p.dispatch,p.repo)).sort(us),inflight:e.dispatches.filter(p=>p.bucket!=="done"&&ms(p,{...n,lane:"",repo:"",verb:""})),traps:d.map(p=>o(ut(e,p))),stacks:(e.stacks||[]).filter(p=>p.open&&r(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=>ms(p,n))},traps:{view:n.view,list:h.filter(p=>(!n.repo||p.repo===n.repo)&&r(p.name,p.trapId,p.repo,p.worktree,p.harness)).map(p=>o(ut(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)&&r(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)&&r(p.title,p.author,p.dispatch,p.repo)).sort(us)},notices:{list:(e.notices||[]).filter(p=>(!n.repo||!p.repo||p.repo===n.repo)&&(!n.noticeKind||p.kind===n.noticeKind)&&r(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 xs(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),a=new Map((e.dispatches||[]).map(c=>[c.id,c])),r=(s.dispatchIds||[]).map(c=>{let u=a.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:r,watch:o?{key:o.key,owner:o.owner||"",lastCheckedAt:o.lastCheckedAt||null,lastError:o.lastError||null,cursor:o.cursor}:null}}function Ts(e){return e?{text:e.lastError?"failing":"watching",at:e.lastCheckedAt||null}:{text:"no watch",at:null}}function Is(){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 Ps(e){try{localStorage.setItem("spyglass",JSON.stringify(e))}catch{}}function Rs(){try{return JSON.parse(localStorage.getItem("spyglass-lob-hidden")||"{}")||{}}catch{return{}}}function As(e){try{localStorage.setItem("spyglass-lob-hidden",JSON.stringify(e))}catch{}}var he,He;function ge(e){if(e.snapshot)return(He?.snapshot!==e.snapshot||He.older!==e.older)&&(He={snapshot:e.snapshot,older:e.older,view:Gs(e.snapshot,e.older)}),He.view}var Ms=new Set,$=()=>he;function _t(e){he=e}function y(e){he={...he,...e};for(let t of Ms)t(he)}var bt=e=>{Ms.add(e)};function kr(e,t){let s=ge(e);return s&&te(s,t,e.detail)?!0:t.type==="dispatch"&&e.detail?.key===t.key&&!e.detail.error}function je(e){let{modal:t,drafts:s,older:n,detail:a}=$(),r=new Set(gt(e.attention||[],e.decisions||[]).map(c=>c.key)),o=Object.fromEntries(Object.entries(s).filter(([c])=>r.has(c)));y({snapshot:e,stale:!1,modal:t&&kr({snapshot:e,older:n,detail:a},t)?t:null,...Object.keys(o).length!==Object.keys(s).length?{drafts:o}:{}})}function Os(e){let{snapshot:t}=$();y({stale:!1,...t?{snapshot:Ds(t,e)}:{}})}async function kt(){let{modal:e}=$();if(e?.type!=="dispatch")return;let t=e.key,s=t.slice(t.indexOf(":")+1),n;try{let r=await fetch(`/data/dispatch/${encodeURIComponent(s)}`,{cache:"no-store"});n=r.ok?{data:await r.json()}:{error:r.status===404?"this dispatch is gone":`the detail answered ${r.status}`}}catch{n={error:"the detail could not be read"}}let a=$();a.modal?.type!=="dispatch"||a.modal.key!==t||n.error&&a.detail?.key===t&&a.detail.data||y({detail:{key:t,...n}})}async function Es(e){let{olderLoading:t,older:s}=$();if(!t){y({olderLoading:e,olderError:null});try{let n=await fetch(`/data/older?kind=${e}&offset=${s[e].length}&limit=50`,{cache:"no-store"});if(!n.ok)throw new Error(`/data/older answered ${n.status}`);let a=await n.json();y({older:ws($().older,a),olderLoading:null})}catch{y({olderLoading:null,olderError:{kind:e,text:"older records could not be read"}})}}}var Ls=()=>({text:"",files:[]});function P(e,t){let s=$().drafts;y({drafts:{...s,[e]:{...s[e]??Ls(),...t}}})}function Ns(e,t){let s=$().drafts[e]?.option;P(e,{option:s===t?void 0:t,error:void 0})}var yr=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 yt(e,t){let s=$().snapshot?.answerLimits,n=[...t??[]],a=$().drafts[e]?.files??[],r=[],o=[];for(let c of n){let u=(/\\.[^.]+$/.exec(c.name)?.[0]??"").toLowerCase();if(s&&!s.extensions.includes(u))r.push(`${c.name}: type not accepted`);else if(s&&c.size>s.maxBytes)r.push(`${c.name}: larger than ${s.maxBytes} bytes`);else if(s&&a.length+o.length>=s.maxFiles)r.push(`${c.name}: at most ${s.maxFiles} files`);else try{o.push({name:c.name,bytes:c.size,data:await yr(c)})}catch{r.push(`${c.name}: could not be read`)}}P(e,{files:[...$().drafts[e]?.files??[],...o],error:r.length?r.join("; "):void 0})}var wr={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};async function Hs(e,t){let s=[...t.clipboardData?.items??[]],n=new Date().toISOString().replace(/[:.]/g,"-").replace(/-\\d{3}Z$/,"Z"),a=s.filter(r=>r.kind==="file"&&r.type.startsWith("image/")).map(r=>r.getAsFile()).filter(r=>r!==null).map((r,o,c)=>{let u=`pasted-${n}${c.length>1?`-${o+1}`:""}${wr[r.type]??".png"}`;return new File([r],u,{type:r.type})});a.length&&await yt(e,a)}function js(e,t){let s=($().drafts[e]?.files??[]).filter((n,a)=>a!==t);P(e,{files:s})}async function Bs(e){let t=$().snapshot?.focusToken,s=$().drafts[e]??Ls();if(!(s.sending||s.sent)){if(!s.option&&!s.text.trim()&&s.files.length===0){P(e,{error:"Choose an option, write an answer, or attach a file."});return}if(!t){P(e,{error:"This page has no answer token; reload it."});return}P(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(r=>({name:r.name,data:r.data}))}})}),a=await n.json();if(!n.ok||!a.ok){P(e,{sending:!1,error:a.reason??`The answer was refused (${n.status}).`});return}P(e,{sending:!1,sent:$s({option:s.option,text:s.text,files:s.files.length})})}catch{P(e,{sending:!1,error:"The answer could not be sent."})}}}var Us=()=>y({stale:!0}),qs=(e,t)=>y({lightbox:{src:e,name:t}}),se=()=>y({lightbox:null});function E(e,t){let s=$(),n={type:e,key:t};if(e==="dispatch"){y({modal:n,detail:s.detail?.key===t?s.detail:{key:t}}),kt();return}let a=ge(s);y({modal:!a||te(a,n)?n:null,detail:null})}function ne(){y({modal:null,detail:null})}async function Vs(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();y({focusResults:{...$().focusResults,[e]:n.message??n.reason??"Window focus failed."}})}catch{y({focusResults:{...$().focusResults,[e]:"Window focus failed."}})}}async function Fs(e,t){let s=$().snapshot?.focusToken;if(!s)return"The glass has no page token yet.";try{let a=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(!a.ok)return a.reason??"The request was refused."}catch{return"The request could not be sent."}try{je(await(await fetch("/data")).json())}catch{}}function N(e){let t={...$().prefs,...e};Ps(t),y({prefs:t})}function Ws(e){e!=="table"&&e!=="cards"||N({view:e})}var Ks=e=>N({lobs:e==="on"});function zs(e,t){let s={...$().lobHidden,[e]:t};As(s),setTimeout(()=>y({lobHidden:s}),0)}async function Js(e){try{return await navigator.clipboard.writeText(e),!0}catch{return!1}}var Ys=function(e,t,s,n){var a;t[0]=0;for(var r=1;r<t.length;r++){var o=t[r++],c=t[r]?(t[0]|=o?1:2,s[t[r++]]):t[++r];o===3?n[0]=c:o===4?n[1]=Object.assign(n[1]||{},c):o===5?(n[1]=n[1]||{})[t[++r]]=c:o===6?n[1][t[++r]]+=c+"":o?(a=e.apply(c,Ys(e,c,s,["",null])),n.push(a),c[0]?t[0]|=2:(t[r-2]=0,t[r]=a)):n.push(c)}return n},Qs=new Map;function Xs(e){var t=Qs.get(this);return t||(t=new Map,Qs.set(this,t)),(t=Ys(this,t.get(e)||(t.set(e,t=(function(s){for(var n,a,r=1,o="",c="",u=[0],l=function(d){r===1&&(d||(o=o.replace(/^\\s*\\n\\s*|\\s*\\n\\s*$/g,"")))?u.push(0,d,o):r===3&&(d||o)?(u.push(3,d,o),r=2):r===2&&o==="..."&&d?u.push(4,d,0):r===2&&o&&!d?u.push(5,0,!0,o):r>=5&&((o||!d&&r===5)&&(u.push(r,0,o,a),r=6),d&&(u.push(r,d,0,a),r=6)),o=""},f=0;f<s.length;f++){f&&(r===1&&l(),l(f));for(var h=0;h<s[f].length;h++)n=s[f][h],r===1?n==="<"?(l(),u=[u],r=3):o+=n:r===4?o==="--"&&n===">"?(r=1,o=""):o=n+o[0]:c?n===c?c="":o+=n:n===\'"\'||n==="\'"?c=n:n===">"?(l(),r=1):r&&(n==="="?(r=5,a=o,o=""):n==="/"&&(r<5||s[f][h+1]===">")?(l(),r===3&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):n===" "||n===" "||n===`\n`||n==="\\r"?(l(),r=2):o+=n),r===3&&o==="!--"&&(r=4,u=u[0])}return l(),u})(e)),t),arguments,[])).length>1?t:t[0]}var Zs=e=>Array.isArray(e)?e.map(Zs):e===""?null:e,Gr=(e,t,...s)=>Y(e,t,...s.map(Zs)),i=Xs.bind(Gr);var Ue,w,wt,en,Gt=0,cn=[],G=b,tn=G.__b,sn=G.__r,nn=G.diffed,rn=G.__c,an=G.unmount,on=G.__;function dn(e,t){G.__h&&G.__h(w,e,Gt||t),Gt=0;var s=w.__H||(w.__H={__:[],__h:[]});return e>=s.__.length&&s.__.push({}),s.__[e]}function re(e){return Gt=1,Sr(un,e)}function Sr(e,t,s){var n=dn(Ue++,2);if(n.t=e,!n.__c&&(n.__=[s?s(t):un(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=w,!w.__f)){var a=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)}}),r){var d=r.call(this,c,u,l);return f?d||h:d}return!f||h};w.__f=!0;var r=w.shouldComponentUpdate,o=w.componentWillUpdate;w.componentWillUpdate=function(c,u,l){if(this.__e){var f=r;r=void 0,a(c,u,l),r=f}o&&o.call(this,c,u,l)},w.shouldComponentUpdate=a}return n.__N||n.__}function pn(e,t){var s=dn(Ue++,7);return xr(s.__H,t)&&(s.__=e(),s.__H=t,s.__h=e),s.__}function Dr(){for(var e;e=cn.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(Be),t.__h.some(St),t.__h=[]}catch(s){t.__h=[],G.__e(s,e.__v)}}}G.__b=function(e){w=null,tn&&tn(e)},G.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),on&&on(e,t)},G.__r=function(e){sn&&sn(e),Ue=0;var t=(w=e.__c).__H;t&&(wt===w?(t.__h=[],w.__h=[],t.__.some(function(s){s.__N&&(s.__=s.__N),s.u=s.__N=void 0})):(t.__h.some(Be),t.__h.some(St),t.__h=[],Ue=0)),wt=w},G.diffed=function(e){nn&&nn(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(cn.push(t)!==1&&en===G.requestAnimationFrame||((en=G.requestAnimationFrame)||Cr)(Dr)),t.__H.__.some(function(s){s.u&&(s.__H=s.u,s.u=void 0)})),wt=w=null},G.__c=function(e,t){t.some(function(s){try{s.__h.some(Be),s.__h=s.__h.filter(function(n){return!n.__||St(n)})}catch(n){t.some(function(a){a.__h&&(a.__h=[])}),t=[],G.__e(n,s.__v)}}),rn&&rn(e,t)},G.unmount=function(e){an&&an(e);var t,s=e.__c;s&&s.__H&&(s.__H.__.some(function(n){try{Be(n)}catch(a){t=a}}),s.__H=void 0,t&&G.__e(t,s.__v))};var ln=typeof requestAnimationFrame=="function";function Cr(e){var t,s=function(){clearTimeout(n),ln&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(s,35);ln&&(t=requestAnimationFrame(s))}function Be(e){var t=w,s=e.__c;typeof s=="function"&&(e.__c=void 0,s()),w=t}function St(e){var t=w;e.__c=e.__(),w=t}function xr(e,t){return!e||e.length!==t.length||t.some(function(s,n){return s!==e[n]})}function un(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=>i`<span data-age=${e??""}>${K(e)}</span>`,Ve=e=>e.activity&&i`<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>`,Tr=e=>e&&/^https?:\\/\\//i.test(e)?e:void 0,Fe=e=>{let t=e.waiting;if(!t)return;let s=Tr(t.link),n=s;try{s&&(n=new URL(s).host+new URL(s).pathname.replace(/\\/$/,""))}catch{n=s}return i`<div class="waiting">${e.verb}: waiting on ${t.on} \xB7 ${v(t.since)}${s&&[" \\xB7 ",i`<a href=${s} target="_blank" rel="noopener noreferrer" onClick=${x}>${n}</a>`]}</div>`},Ir=12,fn=e=>e!==void 0&&e.length>Ir,H=e=>fn(e)?e:void 0,j=e=>fn(e)?" long":"",k=(e,t)=>()=>E(e,t),x=e=>e.stopPropagation(),Pr=e=>e.sessionId?(e.harness==="codex"?"codex resume ":"claude --resume ")+e.sessionId:void 0;function z(e){if(e.requested)return i`<span class="dim">Requested \u2014 no window yet</span>`;if(e.starting)return i`<span class="dim">${e.starting.failedAt?"Did not start":"Starting \\u2014 no window yet"}</span>`;if(!e.live){let n=Pr(e);return n?i`<span class="dim">Resume: <code onClick=${x}>${n}</code></span>`:i`<span class="dim">Resume command unavailable</span>`}let t=$();return!t.snapshot?.focusSupported&&!e.link?i`<span class="dim">Window focus is not supported here</span>`:i`<span class="winaction"><button class="btn open" title="open this trap\'s window" onClick=${n=>{x(n),Vs(e.trapId)}}>\u2197 open</button>${e.link&&[" ",i`<a href=${e.link} onClick=${x}>Session link</a>`]}${t.focusResults[e.trapId]&&[" ",i`<span class="dim">${t.focusResults[e.trapId]}</span>`]}</span>`}function R(e,t,s){return t.length?i`<div class="wrap"><table><tbody><tr>${e.map(n=>i`<th>${n}</th>`)}</tr>${t}</tbody></table></div>`:i`<div class="empty">${s}</div>`}function oe({kind:e,more:t}){return!t.left&&!t.error?null:i`<div class="older">${t.left>0&&i`<button class="btn" disabled=${t.loading} onClick=${()=>{Es(e)}}>${t.loading?"loading\\u2026":`show ${Math.min(t.left,50)} older (of ${t.left})`}</button>`}${t.error&&i` <span class="bad">${t.error}</span>`}</div>`}function Rr({text:e}){let[t,s]=re(null),n=a=>async()=>{await Js(e)&&(s(a),setTimeout(()=>s(null),1e3))};return i`<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 T=(e,t)=>i`<${Rr} key=${t} text=${e} />`,ve=(e,t,s="thumb")=>i`<button\n type="button"\n class=${s}\n title=${"view "+t}\n onClick=${n=>{x(n),qs(e,t)}}\n >\n <img src=${e} alt=${t} loading="lazy" />\n </button>`,ae=(e,t)=>e.map(s=>[i`<div class="sub">${s.name} \xB7 ${s.type} \xB7 ${s.bytes} bytes</div>`,t&&vs(s.name)&&ve(t(s.name),s.name),T(s.path)]),mn=/\\bwt:([a-z0-9][a-z0-9-]*)/g,Dt=e=>$().snapshot?.trapNames?.[e],B=e=>e.replace(mn,(t,s,n)=>{let a=Dt(s);return a&&!hn(e,n,t.length,a)?a:t}),hn=(e,t,s,n)=>e.slice(Math.max(0,t-n.length-2),t)===`${n} (`&&e[t+s]===")";function We(e){let t="wt:"+e,s=Dt(e)??t;return $().snapshot?.traps.some(a=>a.trapId===e)?i`<a class="trapname" href="#traps" title=${t} onClick=${a=>{a.preventDefault(),x(a),E("trap",e)}}>${s}</a>`:i`<span class="trapname" title=${t}>${s}</span>`}var qe=e=>{let t=/^wt:([a-z0-9][a-z0-9-]*)$/.exec(e);return t?We(t[1]):e};function I(e,t=1/0){let s=[],n=0;for(let c of e.matchAll(mn)){c.index>n&&s.push({text:e.slice(n,c.index)});let u=Dt(c[1]);s.push(u&&hn(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 a=s.reduce((c,u)=>c+u.text.length,0),r=a>t?t-1:1/0,o=[];for(let c of s){if(r<=0)break;c.text.length<=r?o.push(c.trapId?We(c.trapId):c.text):o.push(c.text.slice(0,r)),r-=c.text.length}return a>t&&o.push("\\u2026"),o}var Ar=e=>e.log.flatMap((t,s)=>[s?`\n`:"",t.at+" "+t.verb,...t.note?[" ",...I(t.note)]:[]]),Mr=e=>"brief"in e;function gn(e,t){let s=[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`),n=i`${e.waiting&&[i`<div class="sec">waiting</div>`,Fe(e)]}${e.activity&&[i`<div class="sec">activity</div>`,Ve(e)]}${s&&[i`<div class="sec">progress</div>`,i`<pre>${s}</pre>`]}`;return Mr(e)?i`${n}<div class="sec">brief</div><pre>${e.brief}</pre>${e.attachments.length>0&&[i`<div class="sec">attachments (${e.attachments.length})</div>`,ae(e.attachments,a=>mt(e.lane,e.id,a))]}${e.messageAttachments.length>0&&[i`<div class="sec">message attachments (${e.messageAttachments.length})</div>`,ae(e.messageAttachments,a=>mt(e.lane,e.id,a))]}${e.followUp&&[i`<div class="sec">forks</div>`,i`<pre>${e.followUp}</pre>`]}<div class="sec">log</div><div class="loglines">${e.log.length?Ar(e):"no entries yet"}</div>${e.inbox.length>0&&[i`<div class="sec">inbox</div>`,i`<div class="loglines">${e.inbox.join(`\n---\n`)}</div>`]}${e.awaitingReply&&[i`<div class="sec">awaiting reply</div>`,i`<div>${e.awaitingReply.line} \xB7 from ${e.awaitingReply.from} \xB7 ${v(e.awaitingReply.sentAt)} ago</div>`]}${e.evidence&&[i`<div class="sec">evidence</div>`,i`<div class="loglines">${JSON.stringify(e.evidence)}</div>`]}`:i`${n}<div class="sec">brief</div><div class=${t?.error?"bad":"dim"}>${t?.error??"loading\\u2026"}</div>${e.followUp&&[i`<div class="sec">forks</div>`,i`<pre>${e.followUp}</pre>`]}${e.note&&[i`<div class="sec">last note</div>`,i`<div class="loglines">${I(e.note)}</div>`]}`}function $e(e){return e.for?[qe(e.for),e.evidence&&e.evidence.deliveredTo?[" ",i`<span class="ok">\u2713delivered</span>`]:[" ",i`<span class="warn">waiting</span>`]]:e.claimedBy?qe(e.claimedBy):""}function ie(e){if(e.prList&&e.prList.length>1)return[e.prList.map((a,r)=>[r?" \\u2192 ":"",i`<a href=${a.url} target="_blank" rel="noopener" onClick=${x}>#${a.number}</a>`,a.badge&&[" ",i`<span class=${"badge "+O(a.badge)}>${a.badge.text}</span>`]]),e.prGate&&[" ",i`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]];let t=e.evidence&&(e.evidence.prUrl||e.evidence.pr&&e.evidence.pr.url);if(!t)return"";let s=e.prBadge,n=e.evidence&&e.evidence.prUrls&&e.evidence.prUrls.length>1?e.evidence.prUrls:void 0;return[n?n.map((a,r)=>[r?" ":"",i`<a href=${a} target="_blank" rel="noopener" onClick=${x}>#${a.split("/").pop()}</a>`]):i`<a href=${t} target="_blank" rel="noopener" onClick=${x}>PR</a>`,s&&[" ",i`<span class=${"badge "+O(s)} title=${"observed "+s.observedAt}>${s.text}</span>`],e.prGate&&[" ",i`<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"},Ct={"pr:review":"bad","pr:checks":"bad","pr:conflict":"pr-conflicts","pr:ready":"ok","pr:draft":"dim",watch:"warn"},vn=e=>Or[e]||"";var Ke=e=>i`<a href=${e.url} target="_blank" rel="noopener" onClick=${x}>#${e.number}</a>`,ze=e=>i`<span class="prname" title=${e.title||void 0}><b>#${e.number}</b>${e.title&&[" ",e.title]}</span>`;function le(e,t,s){return e.flatMap((n,a)=>{let r=t.get(n)||void 0,o=n===s?i`<b title=${r}>#${n}</b>`:i`<span title=${r}>#${n}</span>`;return a?[" \\u2192 ",o]:[o]})}function _e(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 be(e){return[e.mergeStateStatus,e.nextMergeable?[" \\xB7 ",i`<span class="ok">next mergeable</span>`]:e.blockedBy?" \\xB7 blocked by #"+e.blockedBy:""]}function xt(e){let t=Ts(e);return e?[t.text," \\xB7 ",t.at?[v(t.at)," ago"]:"never checked"]:i`<span class="dim">${t.text}</span>`}function ke(e){if(e.requested)return{stale:!1,listen:[i`<span class="dot"></span>`,i`<span class="dim">requested</span>`],hb:i`<span class="dim">\u2014</span>`};if(e.starting)return{stale:!1,listen:e.starting.failedAt?[i`<span class="dot bad"></span>`,i`<span class="bad">start failed</span>`]:[i`<span class="dot warn"></span>`,"starting"],hb:i`<span class="dim">\u2014</span>`};if(!e.live)return{stale:!1,listen:[i`<span class="dot"></span>`,i`<span class="dim">signed off</span>`],hb:i`<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?[i`<span class="dot ok"></span>`,"listening"]:[i`<span class="dot warn"></span>`,"not listening"],hb:i`<span class=${t?"bad":"ok"}>${t&&"stale "}${v(e.heartbeatAt)} ago</span>`}}function Tt(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 Er(e){let t=Tt(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 $n=e=>e.waiting?`waiting on ${e.waiting.on}`:e.note||"waiting",_n=e=>e.title.slice(0,40)||"(no title)";function ye(e){let t=Tt(e),s=i`<span class=${"dot trapdot "+Er(e)}></span>`;if(t.kind==="requested")return[s,i`<span class="dim">${bn(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,i`<span class="bad">start failed</span>`," \\xB7 ",t.reason];if(t.kind==="signed off")return[s,i`<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 ",$n(n)]:[s,"working \\xB7 ",i`<a href="#dispatches" onClick=${r=>{r.preventDefault(),x(r),E("dispatch",`${n.lane}:${n.id}`)}}>${n.id.slice(0,8)}</a>`," \\xB7 ",_n(n),n.activity&&[" \\xB7 ",n.activity.summary," ",v(n.activity.at)," ago"]]}var bn=(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?i`<div class="startcmds" onClick=${x}><div class="dim">start it: run one in a terminal</div>${t.map(s=>T(s.command,s.harness))}</div>`:null}function Qe(){let t=$().snapshot?.repoKeys??[],[s,n]=re(!1),[a,r]=re(""),[o,c]=re("claude"),[u,l]=re(null),f=a||t[0]||"",h=async d=>{d.preventDefault();let m=await Fs(f,o);l(m??null),m||n(!1)};return s?i`<form class="newtrap" onClick=${x} onSubmit=${h}>\n <label>repo <select name="repo" value=${f} onChange=${d=>r(d.target.value)}>${t.map(d=>i`<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&&i`<span class="bad">${u}</span>`}\n </form>`:i`<span class="newtrap"><button class="btn" onClick=${d=>(x(d),n(!0),l(null))}>+ New trap</button></span>`}function Ye(e){let t=Tt(e);if(t.kind==="requested")return bn(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 ${$n(t.current)}`;let s=t.current;return[`working \\xB7 ${s.id.slice(0,8)} \\xB7 ${_n(s)}`,s.activity&&`${s.activity.summary} ${K(s.activity.at)} ago`].filter(Boolean).join(" \\xB7 ")}function It(e){let t=e.messages.filter(s=>s.state==="pending").length;return e.messages.length?["\\u2709 "+e.messages.length,t>0&&[" ",i`<span class="warn">(${t} pending)</span>`]]:null}var Lr=e=>()=>{window.open(C(e.key),"_blank","noopener")};function Pt(e){let t=fe(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 Nr(e){let t=Pt(e);return i`<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 Hr(e){return i`<tr key=${e.key} class=${"rowhead"+(e.acked?" acked":"")} onClick=${Lr(e)}><td class="grow"><a href=${C(e.key)} target="_blank" rel="noopener" onClick=${t=>t.stopPropagation()}>${e.title}</a></td><td>${fe(e)}</td><td>${v(e.filedAt)}</td><td>${e.acked?"acked":""}</td></tr>`}function kn({inp:e}){return e.view==="cards"?e.list.length?i`<div class="cards">${e.list.map(Nr)}</div>`:i`<div class="empty">no reports match</div>`:R(["title","from","filed","acked"],e.list.map(Hr),"no reports match")}function Gn(e){let t=e.trim();return/^(https?:\\/\\/|mailto:|#)/i.test(t)?t:void 0}function Sn(e){let t=e.trim();return/^[^/\\\\:?#]+$/.test(t)&&t!=="."&&t!==".."?t:void 0}function yn(e,t,s,n){let a=0;for(let r=t;r<e.length;r++){if(e[r]==="\\\\"){r++;continue}if(e[r]===s)a++;else if(e[r]===n){if(a===0)return r;a--}}return-1}function wn(e,t){let s=yn(e,t+1,"[","]");if(s<0||e[s+1]!=="(")return;let n=yn(e,s+2,"(",")");if(n<0)return;let a=e.slice(s+2,n).trim().replace(/\\s+"[^"]*"$/,"").replace(/^<(.*)>$/,"$1");return{text:e.slice(t+1,s),target:a,end:n+1}}function q(e){let t=[],s="",n=()=>{s&&t.push({t:"text",v:s}),s=""};for(let a=0;a<e.length;){let r=e[a];if(r==="\\\\"&&a+1<e.length&&/[\\\\`*_{}[\\]()#+\\-.!|<>~]/.test(e[a+1])){s+=e[a+1],a+=2;continue}if(r==="`"){let o=/^`+/.exec(e.slice(a))[0],c=e.indexOf(o,a+o.length);if(c>0){n(),t.push({t:"code",v:e.slice(a+o.length,c).replace(/^ (.*) $/,"$1")}),a=c+o.length;continue}}if(r==="!"&&e[a+1]==="["){let o=wn(e,a+1);if(o){n(),t.push({t:"img",alt:o.text,src:o.target}),a=o.end;continue}}if(r==="["){let o=wn(e,a);if(o){n(),t.push({t:"a",href:o.target,c:q(o.text)}),a=o.end;continue}}if((r==="*"||r==="_")&&e[a+1]===r){let o=e.indexOf(r+r,a+2);if(o>a+2){n(),t.push({t:"b",c:q(e.slice(a+2,o))}),a=o+2;continue}}if(r==="*"||r==="_"&&(a===0||!/\\w/.test(e[a-1]))){let o=a+1;for(;(o=e.indexOf(r,o))>0&&(e[o+1]===r||r==="_"&&/\\w/.test(e[o+1]??""));)o+=2;if(o>a+1&&e[a+1]!==" "){n(),t.push({t:"i",c:q(e.slice(a+1,o))}),a=o+1;continue}}if(r===`\n`){/ {2,}$/.test(s)||s.endsWith("\\\\")?(s=s.replace(/( {2,}|\\\\)$/,""),n(),t.push({t:"br"})):s+=" ",a++;continue}s+=r,a++}return n(),t}var Dn=/^ {0,3}(`{3,}|~{3,})\\s*([^`\\s]*)/,Cn=/^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/,xn=/^ {0,3}([-*_])(\\s*\\1){2,}\\s*$/,Mt=/^( {0,3})([-*+])\\s+(.*)$/,Ot=/^( {0,3})(\\d{1,9})[.)]\\s+(.*)$/,Xe=/^ {0,3}>\\s?(.*)$/,jr=/^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;function Rt(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 a=0;a<t.length;a++)t[a]==="\\\\"&&t[a+1]==="|"?(n+="|",a++):t[a]==="|"?(s.push(n.trim()),n=""):n+=t[a];return s.push(n.trim()),s}var At=e=>Dn.test(e)||Cn.test(e)||xn.test(e)||Mt.test(e)||Ot.test(e)||Xe.test(e);function Ze(e){let t=e.replace(/\\r\\n?/g,`\n`).replace(/\\t/g," ").split(`\n`),s=[],n=0;for(;n<t.length;){let a=t[n];if(!a.trim()){n++;continue}let r=Dn.exec(a);if(r){let f=r[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:r[2]??"",v:h.join(`\n`)});continue}let o=Cn.exec(a);if(o){s.push({t:"h",level:o[1].length,c:q(o[2])}),n++;continue}if(xn.test(a)){s.push({t:"hr"}),n++;continue}if(Xe.test(a)){let f=[];for(;n<t.length&&t[n].trim()&&(Xe.test(t[n])||!At(t[n]));)f.push(Xe.exec(t[n])?.[1]??t[n]),n++;s.push({t:"quote",c:Ze(f.join(`\n`))});continue}let c=Mt.exec(a),u=Ot.exec(a);if(c||u){let f=!c,h=f?Ot:Mt,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(At(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=>Ze(m.join(`\n`)))});continue}if(a.includes("|")&&n+1<t.length&&jr.test(t[n+1])&&t[n+1].includes("-")){let f=Rt(a),h=Rt(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=Rt(t[n++]);d.push(f.map((p,g)=>q(m[g]??"")))}s.push({t:"table",align:f.map((m,p)=>h[p]??""),head:f.map(q),rows:d});continue}let l=[];for(;n<t.length&&t[n].trim()&&!At(t[n])&&!(l.length&&/^ {0,3}(=+|-+)\\s*$/.test(t[n]));)l.push(t[n++].replace(/^ +/,""));if(l.length===0){s.push({t:"p",c:q(a.trim())}),n++;continue}s.push({t:"p",c:q(l.join(`\n`))})}return s}function V(e,t){return t.map(s=>{switch(s.t){case"text":return s.v;case"code":return i`<code>${s.v}</code>`;case"b":return i`<strong>${V(e,s.c)}</strong>`;case"i":return i`<em>${V(e,s.c)}</em>`;case"br":return i`<br />`;case"a":{let n=Gn(s.href);return n?i`<a href=${n} target="_blank" rel="noopener noreferrer">${V(e,s.c)}</a>`:V(e,s.c)}case"img":{let n=Sn(s.src);return n?ve(e(n),s.alt||n,"mdimg"):i`<span class="dim">[image not shown: ${s.alt||s.src}]</span>`}}})}function et(e,t){return t.map(s=>{switch(s.t){case"h":{let n=V(e,s.c);return s.level===1?i`<h1>${n}</h1>`:s.level===2?i`<h2>${n}</h2>`:s.level===3?i`<h3>${n}</h3>`:i`<h4>${n}</h4>`}case"p":return i`<p>${V(e,s.c)}</p>`;case"code":return i`<pre class="mdcode"><code>${s.v}</code></pre>`;case"hr":return i`<hr />`;case"quote":return i`<blockquote>${et(e,s.c)}</blockquote>`;case"list":{let n=s.items.map(a=>i`<li>${et(e,a)}</li>`);return s.ordered?i`<ol start=${s.start}>${n}</ol>`:i`<ul>${n}</ul>`}case"table":return i`<div class="mdtable"><table><thead><tr>${s.head.map((n,a)=>i`<th style=${s.align[a]?"text-align:"+s.align[a]:void 0}>${V(e,n)}</th>`)}</tr></thead><tbody>${s.rows.map(n=>i`<tr>${n.map((a,r)=>i`<td style=${s.align[r]?"text-align:"+s.align[r]:void 0}>${V(e,a)}</td>`)}</tr>`)}</tbody></table></div>`}})}var we=new Map;function Tn(e){let t=we.get(e);return t||(t=Ze(e),we.set(e,t),we.size>8&&we.delete(we.keys().next().value)),t}function Br({r:e,text:t}){let s=t?.text!==void 0?et(n=>vt(e.key,n),Tn(t.text)):t?.error?i`<div class="bad">${t.error}</div>`:i`<div class="dim">loading\u2026</div>`;return i`<div class="mdpage" data-report=${e.key}>${s}</div>`}function In({text:e,fileUrl:t}){return i`<div class="mdpage">${et(t,Tn(e))}</div>`}function Et(e){let t=fe(e);return[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked&&[" \\xB7 ",i`<span class="ok">acked</span>`]]}function Pn({r:e,text:t,heading:s}){return[s&&i`<div class="sec">report \xB7 ${e.title}</div>`,i`<div class="sub">${Et(e)}</div>`,i`<${Br} r=${e} text=${t} />`,e.attachments.length>0&&[i`<div class="sec">report attachments (${e.attachments.length})</div>`,ae(e.attachments,n=>vt(e.key,n))],!e.acked&&[i`<div class="sec">ack</div>`,T("lobstah attention ack "+e.key)]]}var Ur=/\\.(png|jpe?g|gif|webp)$/i,qr=e=>{e.style.height="auto",e.style.height=e.scrollHeight+"px"};function Vr(e,t){return t.length?i`<div class="dfiles">${t.map(s=>Ur.test(s.name)?i`<span key=${s.name}>${ve(ht(e,s.name),s.name,"dimg")}</span>`:i`<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 Fr(e,t,s){let n=e.key,a=e.kind==="decision"?e.options:[],r=t?.text??"",o=t?.files??[],c=!!t?.sending;return[a.length>0&&i`<div class="doptions">${a.map(u=>i`<button key=${u} type="button" class=${"btn dopt"+(t?.option===u?" on":"")} aria-pressed=${t?.option===u?"true":"false"} disabled=${c} onClick=${()=>Ns(n,u)}>${u}</button>`)}</div>`,i`<textarea\n class="danswer"\n rows="2"\n placeholder=${a.length?"Add to your answer, or answer in your own words":"Your answer"}\n value=${r}\n disabled=${c}\n onInput=${u=>{let l=u.currentTarget;qr(l),P(n,{text:l.value,error:void 0})}}\n onPaste=${u=>{Hs(n,u)}}\n ></textarea>`,i`<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;yt(n,l.files).then(()=>{l.value=""})}} /></label>\n ${o.map((u,l)=>i`<span key=${u.name+l} class="dchip">${u.name}<button type="button" class="dx" title="remove" disabled=${c} onClick=${()=>js(n,l)}>\xD7</button></span>`)}\n ${t?.error&&i`<span class="bad derr">${t.error}</span>`}\n <button type="button" class="btn dsend" disabled=${c} onClick=${()=>{Bs(n)}}>${c?"Sending\\u2026":"Send"}</button>\n </div>`]}function Wr(e,t,s,n){let a=e.dispatch,r=e.lane??"work",c=[a&&i`<a class="dlink" href="#" onClick=${l=>{l.preventDefault(),k("dispatch",r+":"+a)()}}>${a.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 i`<div key=${e.key} class=${u} data-decision=${e.key}>\n <div class="dtop">\n ${e.kind==="question"&&i`<span class=${"badge "+(e.verb==="blocked"?"bad":"warn")}>${e.verb}</span>`}\n <b class="dtitle">${e.kind==="decision"?e.title:I(e.note)}</b>\n <span class="dmeta dim">${c}</span>\n </div>\n ${e.kind==="decision"&&e.detail.trim()&&i`<${In} text=${e.detail} fileUrl=${l=>ht(e.key,l)} />`}\n ${e.kind==="decision"&&Vr(e.key,e.attachments)}\n ${t?.sent?i`<div class="danswered ok">answered \xB7 ${t.sent}</div>`:Fr(e,t,n)}\n </div>`}function Rn({cards:e,drafts:t,focus:s,extensions:n}){let a=n.join(","),r=e.length?i`<div class="dcards">${e.map(o=>Wr(o,t[o.key],o.key===s,a))}</div>`:i`<div class="empty">none</div>`;return i`<section class="decisions"><h2>decisions</h2>${r}</section>`}function Qr(e,t){let s=e.badge&&i`<span class=${"badge "+(e.badge.tone||"dim")+j(e.badge.text)} title=${H(e.badge.text)}>${e.badge.text}</span>`;if(e.href){let n=(t==="cards"?"card":"deckline click")+(e.acked?" acked":"");return t==="cards"?i`<a key=${e.key} class=${n} href=${e.href} target="_blank" rel="noopener"><div class="top"><b>${e.title}</b>${s}</div>${e.meta&&i`<div class="meta" title=${e.metaText}>${e.meta}</div>`}</a>`:i`<a key=${e.key} class=${n} href=${e.href} target="_blank" rel="noopener">${s&&[s," "]}<b>${e.title}</b>${e.meta&&[" ",i`<span class="dim">\xB7 ${e.meta}</span>`]}</a>`}return t==="cards"?i`<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&&i`<div class="meta" title=${e.metaText}>${e.meta}</div>`}${e.extra}${e.action&&i`<div class="foot"><span class="footact">${e.action}</span></div>`}</div>`:i`<div key=${e.key} class=${"deckline"+(e.open?" click":"")+(e.acked?" acked":"")} onClick=${e.open}>${s&&[s," "]}<b>${e.title}</b>${e.meta&&[" ",i`<span class="dim">\xB7 ${e.meta}</span>`]}${e.action&&[" ",i`<span class="dim">\xB7 </span>`,e.action]}${e.extra}</div>`}var An=(e,t)=>e>0&&i`<a class="deckmore" href=${"#"+t}>+${e} more \u2192</a>`;function tt(e,t,s,n,a,r){let o=t.slice(0,n),c=o.map(l=>Qr(l,a)),u=o.length?a==="cards"?i`<div class="cards">${c}</div>`:c:i`<div class="empty">none</div>`;return i`<section><h2><a href=${"#"+s}>${e} \u2192</a></h2>${r&&i`<div class="tabhead">${r}</div>`}${u}${An(t.length-o.length,s)}</section>`}function Yr(e,t,s,n){let a=t.find(l=>l.number===e.nextNumber)||t[0],r=le(e.numbers,new Map(t.map(l=>[l.number,l.title]))),o=a?"next #"+a.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=>i`<span class=${"badge "+(Ct[g.kind]||"dim")}>${vn(g.kind)}</span>`):i`<span class=${"badge "+O(f.badge)+j(f.badge.text)} title=${H(f.badge.text)}>${f.badge.text}</span>`,p=`${f.repo} \\xB7 ${f.badge.text}${d?" \\xB7 acked":""}`;return i`<div key=${f.key} class=${"card"+(d?" acked":"")} onClick=${k("pr",f.key)}><div class="top">${ze(f)}${m}</div><div class="meta" title=${p}>${p}</div></div>`};return i`<div key=${e.id} class="deckstack"><div class="dim">${r} \xB7 ${o}</div><div class="cards">${t.map(l)}</div></div>`}let c=t.flatMap(l=>(s.get(l.key)||[]).map(f=>i`<span class=${"badge "+(Ct[f.kind]||O(l.badge))+(f.acked?" acked":"")}>#${l.number} ${l.badge.text}</span>`)),u=c.flatMap((l,f)=>f?[" ",l]:[l]);return i`<div key=${e.id} class=${"deckline"+(a?" click":"")} onClick=${a&&k("pr",a.key)}><b>${r}</b> <span class="dim">\xB7 ${o}</span>${c.length>0&&[" \\xB7 ",u]}</div>`}function Xr(e,t){let s=e.stacks.slice(0,3),n=new Map;for(let r of e.prAttention){let o=n.get(r.key)||[];o.push(r),n.set(r.key,o)}let a=s.length?s.map(r=>Yr(r,e.prs.filter(o=>o.stackId===r.id).sort((o,c)=>o.position-c.position),n,t)):i`<div class="empty">none</div>`;return i`<section><h2><a href="#prs">PRs \u2192</a></h2>${a}${An(e.stacks.length-s.length,"prs")}</section>`}function Mn({inp:e,drafts:t,focus:s,extensions:n}){let a=e.view,r=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:[I(l.note||"",90),l.verbAt&&[" \\xB7 ",v(l.verbAt)," ago"],(l.for||l.claimedBy)&&[" \\xB7 ",qe(l.for||l.claimedBy)]],metaText:[B(l.note||""),l.verbAt&&`${K(l.verbAt)} ago`,B(l.for||l.claimedBy||"")].filter(Boolean).join(" \\xB7 "),open:k("dispatch",l.lane+":"+l.id)})),o=e.landed.map(l=>({key:l.key,title:[l.id.slice(0,8)," ",l.repo||"",l.unreported&&[" ",i`<span class="badge warn unreported">unreported</span>`]],badge:{text:l.verb,tone:l.verb==="failed"?"bad":"ok"},meta:[I(l.note||"",90)," \\xB7 ",v(l.at)," ago"],metaText:`${B(l.note||"")} \\xB7 ${K(l.at)} ago`,open:k("dispatch",l.lane+":"+l.id)})),c=e.reports.map(l=>{let f=Pt(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 ",i`<span class="catchn" title="catches">\u{1F99E} ${Z(l.totalCatches??0)}</span>`," \\xB7 ",ye(l)],metaText:`${l.repo||""} \\xB7 \\u{1F99E} ${Z(l.totalCatches??0)} \\xB7 ${Ye(l)}`,action:z(l),extra:J(l),open:k("trap",l.trapId)}));return i`<div class="deckgrid"><${Rn} cards=${e.decisions} drafts=${t} focus=${s} extensions=${n} />${tt("in flight",r,"dispatches",4,a)}${tt("Landed \\xB7 24h",o,"dispatches",8,a)}${tt("reports",c,"reports",8,a)}${tt("traps",u,"traps",8,a,i`<${Qe} />`)}${Xr(e,a)}</div>`}function Zr(e,t){if(!t)return e;let s=new Map(e.map(r=>[r.id,r])),n=r=>{let o=r,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},a=new Map;for(let r of e){let o=n(r),c=a.get(o)||[];c.push(r),a.set(o,c)}return[...a.values()].sort((r,o)=>o[0].sort-r[0].sort).flatMap(r=>r.sort((o,c)=>o.id===n(o)?-1:c.id===n(c)?1:o.sort-c.sort))}function ea(e,t){let s=e.lane+":"+e.id;return i`<tr key=${s} class="rowhead" onClick=${k("dispatch",s)}><td>${t&&e.followUp&&i`<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">${I(e.note??"",90)}${Fe(e)}${Ve(e)}</td><td>${v(e.verbAt)}</td><td>${$e(e)}</td><td>${ie(e)}</td></tr>`}function ta(e){let t=e.lane+":"+e.id;return i`<div key=${t} class="card" onClick=${k("dispatch",t)}><div class="top"><b>${e.id.slice(0,8)}</b><span class=${"badge v-"+e.verb+j(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&&i`<div class="note" title=${B(e.note)}>${I(e.note)}</div>`}${Fe(e)}${Ve(e)}<div class="foot">${$e(e)} ${ie(e)}</div></div>`}function On({inp:e,more:t}){let s=e.list,n=t&&i`<${oe} kind="dispatches" more=${t} />`;return e.view==="cards"?[s.length?i`<div class="cards">${s.map(ta)}</div>`:i`<div class="empty">no dispatches match</div>`,n]:[R(["id","lane / bucket","repo","verb","note","age","addressed","pr"],Zr(s,e.chain).map(a=>ea(a,e.chain)),"no dispatches match"),n]}var En="data:image/png;base64,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";var Ln="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAA2UlEQVR4nGNgwAPeHo35D8K45JnwaRQS/YXPbAacmkEa/3z/BaZx2c6Ey1YGIgAjLsV8PF/g7E9feMC0sPUSRhTNuPwGcjI28AlqENzZIIUw/O41G8O58z/BkiycbGDFl278R3GRENQyJpBTkE1DtgFkyIMnn+EGwQDIApA+uB9AzgeZCtIEMhlmu54GI1gMFgafvvDA/Y4SADADYABkG7LfPyFpxIgq9IBD1ojsbAZ0zYTiFlvoY00ksFAGYWw2wtWhC4BD/gsiQUBcxAbxEiI4MAE+p2PLYQAGj4EmRoa2cwAAAABJRU5ErkJggg==";var Lt=()=>i`<span class="pet-art" aria-hidden="true"><div class="sprite" style=${{backgroundImage:`url(${En})`}}></div><img class="star" src=${Ln} alt="" /></span>`,Nt=()=>i`<span class="brand-pet">${i`<${Lt} />`}</span>`;var ra={deck:"On deck",dispatches:"Dispatches",traps:"Traps",prs:"PRs",reports:"Reports",notices:"Notices"},aa=["working","needs-decision","blocked","paused","done","failed","unknown"];function oa(e,t){let s=t.daemonStale,n=e.daemon?[i`<span class=${s?"bad":"ok"}>${s&&"stale "}${v(e.daemon.heartbeat)} ago</span>`," ",i`<span class="dim">v${e.daemon.version}</span>`]:i`<span class="bad">down</span>`;return[i`<span class="chip">daemon ${n}</span>`,t.stats&&i`<span class="chip" title="catches today">\u{1F99E} ${t.stats.catchesToday} today</span>`,e.slots&&i`<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:a,stale:r})=>i`<span key=${a.grounds} class="chip click" onClick=${k("helm",a.grounds)}>\u26F5 <b>${a.man}</b> <span class="dim">helm ${a.grounds}</span> <span class=${r?"warn":"ok"}>${r&&"stale "}${v(a.heartbeatAt)} ago</span></span>`)]}var Ht=[];function ia(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!==Ht.length&&(Ht=t),Ht}var jt=[];function la(e){let t=[...new Set(e.notices.map(s=>s.kind))].sort();return t.length!==jt.length&&(jt=t),jt}var Ge=e=>e.currentTarget.value;function ca(e,t,s){let n=o=>t===o?"":"display:none",a=e?ia(e):[],r=e?la(e):[];return i`<div class="controls">\n <select id="f-lane" style=${e&&n("dispatches")} value=${s.lane} onChange=${o=>N({lane:Ge(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=>N({repo:Ge(o)})}>\n <option value="">all repos</option>\n ${a.map(o=>i`<option key=${o}>${o}</option>`)}\n </select>\n <select id="f-verb" style=${e&&n("dispatches")} value=${s.verb} onChange=${o=>N({verb:Ge(o)})}>\n <option value="">all verbs</option>\n ${aa.map(o=>i`<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=>N({chain:o.currentTarget.checked})} /> group by chain</label>\n <select id="f-kind" style=${e&&n("notices")} value=${s.noticeKind} onChange=${o=>N({noticeKind:Ge(o)})}>\n <option value="">all notice kinds</option>\n ${r.map(o=>i`<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=>N({q:Ge(o)})} />\n </div>`}function Nn({d:e,inp:t,tab:s,st:n,stale:a}){return[i`<div class="headerline"><h1><${Nt} /> spyglass<span id="stale" style=${e||a?a?"display:inline":"display:none":void 0}> \xB7 STALE FEED</span></h1><span id="settings-slot"><button id="gearbtn" title="settings" aria-label="settings" onClick=${()=>E("settings","browser")}>\u2699</button></span></div>`,i`<div class="chips"><span id="chips" style="display:contents">${e&&t&&oa(e,t.chips)}</span><span class="chip dim" id="clock">${e&&new Date(e.now).toLocaleTimeString("en-GB")}</span></div>`,i`<nav class="tabs" id="tabs" aria-label="Spyglass views">${ee.map(r=>i`<a href=${"#"+r} data-tab=${r} class=${e?r===s?"on":"":void 0}>${ra[r]}</a>`)}</nav>`,ca(e,s,n)]}var Hn=({d:e})=>e&&[i`<${Nt} />`,"lobstah v"+e.version+" \\xB7 ",i`<a href=${e.repoUrl} target="_blank">${e.repoUrl.replace("https://github.com/","")}</a>`];function jn(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??{},a=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:ft(o.key),...u}:(o.kind??"question")==="question"&&o.key?{key:"question:"+o.key,text:o.note||o.verb,label:c,hash:ft(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}});!a.length&&t.preview&&(a=[{key:"preview",text:"attention questions crawl in here",...t.previewHelm?{open:{type:"helm",key:t.previewHelm}}:{}}]);let r=a.length>4?a.length-4:0;return a=a.slice(0,4),r&&(a[3]={...a[3],text:"\\u2026and "+r+" more \\u2014 see attention",label:""}),a}function da(e,t){let s="animation-duration:"+((innerWidth+180)/(100+t*12)).toFixed(1)+"s;animation-delay:-"+t*9%14+"s",n=()=>{e.hideKey&&zs(e.hideKey,e.hideHash??"")},a=[i`<div class="bub">${e.label&&[i`<span class="badge dim">${e.label}</span>`," "]}<span>${e.text.length>48?e.text.slice(0,47)+"\\u2026":e.text}</span></div>`,i`<${Lt} />`],r=e.open;return e.hash?i`<a key=${e.key} class="lob" style=${s} title="open the decision" href=${e.hash} onClick=${n}>${a}</a>`:e.href?i`<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=${n}>${a}</a>`:i`<div\n key=${e.key}\n class="lob"\n style=${s}\n title="click to open"\n onClick=${()=>{n(),r&&E(r.type,r.key)}}\n >\n ${a}\n </div>`}function Bn({state:e}){let t=e.snapshot,s=jn(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(a=>a.key).join("|");return pn(()=>s.map((a,r)=>da(a,r)),[n])}function st({box:e}){if(!e)return null;let t=s=>{s.target===s.currentTarget&&se()};return i`<div id="lightbox" class="lightbox" role="dialog" aria-label=${e.name} onClick=${t}>\n <button type="button" class="lbclose" title="close" onClick=${se}>\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 ce=i`<span class="x" onClick=${ne}>\xD7</span>`,Un=(e,t,s)=>i`<span class="seg">${t.map(([n,a])=>i`<button class=${n===s?"on":""} onClick=${()=>e(n)}>${a}</button>`)}</span>`;function pa(e,t){let s=Un(Ws,[["table","table"],["cards","cards"]],t.view),n=Un(Ks,[["on","on"],["off","off"]],t.lobs?"on":"off"),a=e.attentionError?e.attentionError:(e.attentionKinds||[]).join(" \\xB7 ");return[ce,i`<h3>\u2699 settings <span class="dim" style="font-weight:normal">\xB7 this browser only</span></h3>`,i`<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">${a}</span></div></div>`]}function ua(e,t){let s=le(t.numbers,new Map(t.numbers.map((a,r)=>[a,t.titles[r]])),e.number),n=t.nextMergeable?[" \\xB7 ",i`<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 fa=e=>t=>{t.preventDefault(),E("dispatch",e)};function ma(e,t){let s=xs(e,t),n=s.pr,a=s.stack,r=s.watch,o=Je(n),c=s.chain.length?s.chain.flatMap((l,f)=>[f?" \\u2192 ":"",l.culled?i`<span class="dim">${l.id.slice(0,8)} (culled)</span>`:[i`<a href="#" onClick=${fa(l.modalKey)}>${l.id.slice(0,8)}</a>`," ",i`<span class="dim">${l.verb}</span>`]]):i`<span class="dim">none</span>`,u=r?[i`<div>${r.key} \xB7 owner ${r.owner||"?"} \xB7 ${r.lastCheckedAt?["checked ",v(r.lastCheckedAt)," ago"]:"never checked"}</div>`,r.lastError&&i`<div class="bad">${r.lastError}</div>`,i`<div class="dim" style="font-size:11px;margin-top:4px">cursor</div>`,T(r.cursor)]:i`<div class="dim">no watch \u2014 <code>lobstah watch add ${n.url}</code> registers one</div>`;return[ce,i`<h3>${Ke(n)} ${n.title||""} <span class=${"badge "+O(n.badge)}>${n.badge.text}</span>${n.draft&&n.badge.text!=="draft"&&[" ",i`<span class="badge pr-draft">draft</span>`]}</h3>`,i`<div class="sub">${n.repo} \xB7 ${n.state} \xB7 observed ${v(n.observedAt)} ago${n.gate&&" \\xB7 gate "+n.gate}</div>`,i`<div class="sec">checks</div><div>${_e(n)}</div><div class="sec">review</div><div>${o||i`<span class="dim">no review yet</span>`}</div><div class="sec">merge</div><div>${be(n)}</div>${n.repairWait&&i`<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>${a?ua(n,a):i`<span class="dim">not stacked</span>`}</div><div class="sec">dispatch chain</div><div>${c}</div><div class="sec">watch</div>`,u]}var qn=(e,t)=>(e==="codex"?"codex resume ":"claude --resume ")+t;function ha(e){let t=Date.now()-Date.parse(e.heartbeatAt)>18e5;return[ce,i`<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&&[i`<div class="sec">open this session</div>`,T(qn(e.harness,e.sessionId))],e.transcript&&[i`<div class="sec">transcript</div>`,T(e.transcript)]]}function ga(e){return[i`<div class="sec">report \xB7 ${e.title}</div>`,i`<div class="sub">${Et(e)} \xB7 <a href=${C(e.key)} target="_blank" rel="noopener">open the report \u2197</a></div>`]}function va(e,t,s){let n=e.claimedBy&&e.claimedBy.startsWith("wt:")?[i`<div class="sec">worked by trap</div>`,i`<div class="claimedby">claimed by ${We(e.claimedBy.slice(3))}</div>`,T(B(e.claimedBy)),i`<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 ${B(e.claimedBy)} "\u2026"</div>`]:[i`<div class="sec">open this session</div>`,T("lobstah attach "+e.id)];return[ce,i`<h3>${e.id.slice(0,8)} <span class=${"badge v-"+e.verb}>${e.verb}</span></h3>`,i`<div class="sub">${e.repo} \xB7 ${e.lane} ${e.bucket} \xB7 ${v(e.verbAt)}${e.for&&[" \\xB7 ",$e(e)]} ${ie(e)}</div>`,n,e.worktree&&[i`<div class="sec">worktree${e.worktreeOf?" (reused from "+e.worktreeOf.slice(0,8)+")":""}</div>`,T(e.worktree),e.worktreeKept&&i`<div class="dim" style="font-size:11px">kept: ${e.worktreeKept}</div>`],e.transcript&&[i`<div class="sec">transcript</div>`,T(e.transcript)],t&&ga(t),gn(e,s)]}function $a(e){let t=ke(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=>i`<div key=${o.seq} class="loglines">${v(o.at)} ago \xB7 <b>${o.kind}</b> \u2014 ${o.text}</div>`):i`<div class="empty">none recorded</div>`,a=e.messages.length?e.messages.map(o=>i`<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"?i`<span class="warn">pending</span>`:i`<span class="ok">delivered</span>`}</div>${o.text}${o.attachments?.length?ae(o.attachments,c=>gs(e.trapId,c)):""}</div>`):i`<div class="empty">none</div>`,r=e.catches.length?e.catches.map(o=>i`<div key=${o.lane+":"+o.id} class="catch click" onClick=${k("dispatch",o.lane+":"+o.id)}><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>${ie(o)}</div>${o.note&&i`<div class="loglines">${I(o.note)}</div>`}</div>`):i`<div class="empty">none yet</div>`;return[ce,i`<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&&i`<div class="sub">${e.worktree}</div>`,i`<div class="sub">${s}</div>`,i`<div class="sec">window</div>`,z(e),J(e),e.live&&e.sessionId&&[i`<div class="sec">open this session</div>`,T(qn(e.harness,e.sessionId)),i`<div class="dim" style="font-size:11px">as registered at sign-on \u2014 a hookless enlistment may hold a made-up id</div>`],i`<div class="sec">lifecycle (${e.notices.length})</div>`,n,i`<div class="sec">messages (${e.messages.length})</div>`,a,i`<div class="sec">catches (${e.catches.length})</div>`,r]}function Vn({snapshot:e,modal:t,prefs:s,detail:n=null}){if(!e||!t)return null;let a=te(e,t,n);if(!a&&t.type==="dispatch"&&n?.key===t.key)return[ce,i`<h3>${t.key.slice(t.key.indexOf(":")+1,t.key.indexOf(":")+9)}</h3>`,i`<div class=${n.error?"bad":"dim"}>${n.error??"loading\\u2026"}</div>`];if(!a)return null;if(t.type==="settings")return pa(a,s);if(t.type==="pr")return ma(e,t.key);if(t.type==="helm")return ha(a);if(t.type==="dispatch"){let r=_s(e,a);return va(a,r,n)}return $a(a)}var _a=e=>i`<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>`,Fn=({inp:e,more:t})=>[R(["at","kind","text","repo"],e.list.map(_a),"no notices"),t&&i`<${oe} kind="notices" more=${t} />`];function Wn(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 Kn=(e,t)=>le(e.numbers,new Map(t.map(s=>[s.number,s.title]))),Bt=e=>e.state+(e.draft?" \\xB7 draft":"")+(e.state==="MERGED"&&e.mergedAt?" \\xB7 "+e.mergedAt:"");function zn(e){let t=n=>{let a=String(n??"");return a.length>24?a.slice(0,23)+"\\u2026":a},s=e.watches.map(n=>i`<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[i`<h2>other watches</h2>`,R(["key","owner","cursor","last check","error"],s,"no other watches")]}function ba(e,t){let s=Wn(e).flatMap(({s:n,prs:a})=>[i`<tr key=${"stack:"+n.id}><th colspan="8">${Kn(n,a)} \xB7 floor ${n.floor}${n.open?" \\xB7 open":" \\xB7 history"}</th></tr>`,...a.map(r=>i`<tr key=${r.key} class="rowhead" onClick=${k("pr",r.key)}><td>${Ke(r)}</td><td class="grow">${r.title||""}</td><td>${Bt(r)}</td><td>${_e(r)}</td><td>${Je(r)}</td><td>${be(r)}</td><td>${xt(r.watch)}</td><td>${r.gate||""}</td></tr>`)]);return[R(["PR","title","state","checks","review","merge","watch","gate"],s,"no PR evidence"),t,zn(e)]}function ka(e,t){let s=Wn(e),n=r=>i`<div key=${r.key} class="card" onClick=${k("pr",r.key)}><div class="top">${ze(r)}<span class=${"badge "+O(r.badge)+j(r.badge.text)} title=${H(r.badge.text)}>${r.badge.text}</span></div><div class="meta" title=${`${r.repo} \\xB7 ${Bt(r)}`}>${r.repo} \xB7 ${Bt(r)} \xB7 ${be(r)}</div><div class="foot"><span>${_e(r)}</span><span>${xt(r.watch)}</span>${r.gate&&i`<span>gate ${r.gate}</span>`}</div></div>`;return[s.length?s.map(({s:r,prs:o})=>i`<${X} key=${"stack:"+r.id}><h2>${Kn(r,o)} \xB7 floor ${r.floor}${r.open?"":" \\xB7 history"}</h2><div class="cards">${o.map(n)}</div><//>`):i`<div class="empty">no PR evidence</div>`,t,zn(e)]}function Jn({inp:e,more:t}){let s=t&&i`<${oe} kind="prs" more=${t} />`;return e.view==="cards"?ka(e,s):ba(e,s)}var Ut=e=>e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??(e.live?"":"signed off"),Qn=e=>e.live||e.starting?"":" dim";function ya(e){let t=ke(e);return i`<tr key=${e.trapId} class=${"rowhead"+Qn(e)} onClick=${k("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>${ye(e)}${J(e)}</td><td>${t.listen}</td><td>${t.hb}</td><td>${It(e)}</td><td class="catchn" title="catches">\u{1F99E} ${Z(e.totalCatches??0)}</td><td>${z(e)}</td></tr>`}function wa(e){let t=ke(e),s=It(e),n=`${e.repo??(e.live?"addressed bait only":"history")}${e.sessionId?" \\xB7 session "+e.sessionId.slice(0,8):""}`;return i`<div key=${e.trapId} class=${"card"+Qn(e)} onClick=${k("trap",e.trapId)}><div class="top"><b>\u{1FAA4} ${e.label??`wt:${e.trapId}`}</b><span class=${"badge"+j(Ut(e))} title=${H(Ut(e))}>${Ut(e)}</span></div><div class="meta" title=${n}>${n}</div>${e.worktree&&i`<div class="note" title=${e.worktree}>${e.worktree}</div>`}<div class="note" title=${Ye(e)}>${ye(e)}</div>${J(e)}<div class="foot"><span>${t.listen}${e.live&&[" \\xB7 heartbeat ",t.hb]} \xB7 <span class="catchn" title="catches">\u{1F99E} ${Z(e.totalCatches??0)}</span>${s&&[" \\xB7 ",s]}</span><span class="footact">${z(e)}</span></div></div>`}function Yn({inp:e}){let t=e.list.map(n=>n.x),s=i`<div class="tabhead"><${Qe} /></div>`;return e.view==="cards"?[s,t.length?i`<div class="cards">${t.map(wa)}</div>`:i`<div class="empty">no traps soaking</div>`]:[s,R(["address","repo","worktree","harness","session","now","listening","heartbeat","mail","catches","window"],t.map(ya),"no traps soaking")]}function Xn({state:e}){let t=ge(e),s=e.route,n=t&&Cs(t,{st:e.prefs,modal:e.modal,detail:e.detail},Date.now()),a=c=>({left:e.snapshot?Ss(e.snapshot,e.older,c):0,loading:e.olderLoading===c,error:e.olderError?.kind===c?e.olderError.text:void 0}),r=c=>!n||c!==s?null:c==="deck"?i`<${Mn} inp=${n.deck} drafts=${e.drafts} focus=${e.focusDecision} extensions=${t?.answerLimits?.extensions??[]} />`:c==="dispatches"?i`<${On} inp=${n.dispatches} more=${a("dispatches")} />`:c==="traps"?i`<${Yn} inp=${n.traps} />`:c==="prs"?i`<${Jn} inp=${n.prs} more=${a("prs")} />`:c==="reports"?i`<${kn} inp=${n.reports} />`:i`<${Fn} inp=${n.notices} more=${a("notices")} />`,o=c=>{c.target===c.currentTarget&&ne()};return[i`<${Nn} d=${t} inp=${n} tab=${s} st=${e.prefs} stale=${e.stale} />`,ee.map(c=>i`<main key=${c} id=${"page-"+c} class=${t&&c===s?"tabpage on":"tabpage"}><div id=${c}>${r(c)}</div></main>`),i`<footer id="foot"><${Hn} d=${t} /></footer>`,i`<div id="lobs"><${Bn} state=${e} /></div>`,i`<${st} box=${e.lightbox} />`,i`<div id="overlay" class=${e.modal&&t?"open":t?"":void 0} onClick=${o}><div class="modal" id="modalbox"><${Vn} snapshot=${t} modal=${e.modal} prefs=${e.prefs} detail=${e.detail} /></div></div>`]}function Ga({view:e}){if(e.state==="loading")return i`<main class="reportview"><div class="dim">loading\u2026</div></main>`;if(e.state==="error")return i`<main class="reportview"><div class="bad">${e.error}</div></main>`;let t=e.report;return i`<main class="reportview">\n <h1>${t.title}</h1>\n <${Pn} r=${t} text=${e.text!==void 0?{text:e.text}:{error:e.error}} />\n </main>`}function Zn({view:e,box:t}){return[i`<${Ga} view=${e} />`,i`<${st} box=${t} />`]}async function er(e){let t=encodeURIComponent(e),s;try{let n=await fetch(`/report/${t}/meta`);if(!n.ok)return{state:"error",error:`report not found (${n.status})`};s=JSON.parse(await n.text())}catch{return{state:"error",error:"report could not be read"}}try{let n=await fetch(ys(e));return n.ok?{state:"ready",report:s,text:await n.text()}:{state:"ready",report:s,error:`report not found (${n.status})`}}catch{return{state:"ready",report:s,error:"report could not be read"}}}var Sa=3e4,tr="lobstah-glass-page",nr="lobstah-glass-shown",Da=20;function Ca(){try{let t=sessionStorage.getItem(tr);if(t&&/^[A-Za-z0-9_-]{8,64}$/.test(t))return t}catch{}let e="";try{e=Array.from(crypto.getRandomValues(new Uint8Array(12)),t=>t.toString(16).padStart(2,"0")).join("")}catch{for(;e.length<24;)e+=Math.random().toString(36).slice(2);e=e.slice(0,24)}try{sessionStorage.setItem(tr,e)}catch{}return e}var sr=null,rr=()=>sr??(sr=Ca()),Vt=[];function ar(){try{let e=JSON.parse(sessionStorage.getItem(nr)??"[]");if(Array.isArray(e))return e.filter(t=>typeof t=="string")}catch{}return Vt}function xa(e){Vt=[...ar(),e].slice(-Da);try{sessionStorage.setItem(nr,JSON.stringify(Vt))}catch{}}function Ta(e){if(!e||typeof e!="object")return!1;let{id:t,hash:s}=e;if(typeof t!="string"||!t||!bs(s)||ar().includes(t))return!1;if(xa(t),s==="")return!0;let n=me(s);return n!==null?location.pathname!==C(n)&&location.assign(C(n)):location.pathname!=="/"?location.assign(`/${s}`):location.hash!==s&&(location.hash=s),!0}var qt=!1;async function Se(){if(!qt){qt=!0;try{let e=document.hidden?"hidden":"visible",t=await fetch(`/api/presence?page=${rr()}&vis=${e}`,{method:"POST",cache:"no-store"});if(!t.ok)return;Ta((await t.json())?.show)}catch{}finally{qt=!1}}}function Ft(e){let t=null,s=0,n=()=>{let a=document.hidden?Sa:e??0;a!==s&&(t&&clearInterval(t),t=a?setInterval(()=>{Se()},a):null,s=a)};document.addEventListener("visibilitychange",()=>{n(),Se()}),window.addEventListener("pagehide",()=>{try{navigator.sendBeacon?.(`/api/presence?page=${rr()}&vis=gone`)}catch{}}),n(),Se()}var Wt=!1,De=null,Ce=null;function Ia(e){let t=e.headers?.get("x-lobstah-beats");if(t)try{return JSON.parse(decodeURIComponent(t))}catch{return}}async function Kt(){if(!Wt){Wt=!0,Se();try{let e=await fetch("/data",{cache:"no-store",headers:Ce?{"if-none-match":Ce}:{}});if(e.status===304){let t=Ia(e);t?Os(t):je(await Pa())}else{if(!e.ok)throw new Error(`/data answered ${e.status}`);Ce=e.headers?.get("etag")??null,je(await e.json())}kt()}catch{Us()}finally{Wt=!1}}}async function Pa(){Ce=null;let e=await fetch("/data",{cache:"no-store"});if(!e.ok)throw new Error(`/data answered ${e.status}`);return Ce=e.headers?.get("etag")??null,await e.json()}var or=()=>{De||(De=setInterval(Kt,2e3))},Ra=()=>{De&&clearInterval(De),De=null};function ir(){document.addEventListener("visibilitychange",()=>{document.hidden?Ra():(Kt(),or())}),Kt(),document.hidden||or()}var zt=()=>hs(location.hash),lr=e=>window.addEventListener("hashchange",()=>e(zt()));function dr(){let e=me(location.hash);return e===null?!1:(location.replace(C(e)),!0)}var pr=()=>({snapshot:void 0,route:zt(),prefs:Is(),modal:null,detail:null,older:$t,olderLoading:null,olderError:null,stale:!1,lobHidden:Rs(),focusResults:{},preview:new URLSearchParams(location.search).has("lob"),drafts:{},focusDecision:Ne(location.hash),lightbox:null}),cr=ks(location.pathname);cr!==null?Aa(cr):dr()||Ma();function Aa(e){_t(pr());let t={state:"loading"},s=()=>pt(Y(Zn,{view:t,box:$().lightbox}),document.body);document.title="report \\xB7 lobstah glass",bt(s),s(),Ft(2e3),er(e).then(n=>{t=n,n.state==="ready"&&(document.title=`${n.report.title} \\xB7 lobstah glass`),s()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&$().lightbox&&se()})}function Ma(){_t(pr());let e,t=!1,s=()=>{let r=$(),o=r.route!==e||!t&&!!r.snapshot;pt(Y(Xn,{state:r}),document.body),e=r.route,t||(t=!!r.snapshot),o&&window.scrollTo(0,0),r.focusDecision||(n=null),a(r.focusDecision)},n=null;function a(r){if(!r||r===n)return;let o=[...document.querySelectorAll("[data-decision]")].find(c=>c.getAttribute("data-decision")===r);o&&(n=r,o.scrollIntoView?.({block:"center"}))}bt(s),s(),lr(r=>{if(dr())return;let o=Ne(location.hash);o!==$().focusDecision&&(n=null),y({route:r,focusDecision:o})}),document.addEventListener("keydown",r=>{r.key==="Escape"&&($().lightbox?se():ne())}),Ft(),ir()}})();</script>\n </body>\n</html>\n';
|
|
14442
|
+
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}.catchn{white-space:nowrap}.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}.older{padding:8px 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.click{cursor:pointer}.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}.pet-art{display:block;position:relative;width:72px;height:56px}.pet-art .sprite{width:72px;height:56px;background-position:0 0;background-repeat:no-repeat;background-size:400% 100%;image-rendering:pixelated;animation:step 0.5s steps(4) infinite}.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}.pet-art .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}}#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;max-width:100%;overflow-x:auto;white-space:pre;overflow-wrap:normal}.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{max-width:100%;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;white-space:normal;overflow-wrap:anywhere;min-width:12ch}.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{width:100%;max-width:1100px;margin:0 auto;padding:20px 16px 48px;overflow-wrap:anywhere}.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}@media(max-width:600px){.reportview{padding:12px 0 32px}.reportview .mdpage{padding:8px 12px}}</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 Ee,b,Xt,pr,B,zt,Zt,es,rt,Ie,ue,ts,it,at,ot,ur,Pe={},Me=[],fr=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Le=Array.isArray;function L(e,t){for(var s in t)e[s]=t[s];return e}function lt(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Y(e,t,s){var n,a,r,o={};for(r in t)r=="key"?n=t[r]:r=="ref"?a=t[r]:o[r]=t[r];if(arguments.length>2&&(o.children=arguments.length>3?Ee.call(arguments,2):s),typeof e=="function"&&e.defaultProps!=null)for(r in e.defaultProps)o[r]===void 0&&(o[r]=e.defaultProps[r]);return Re(e,o,n,a,null)}function Re(e,t,s,n,a){var r={type:e,props:t,key:s,ref:n,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:a??++Xt,__i:-1,__u:0};return a==null&&b.vnode!=null&&b.vnode(r),r}function X(e){return e.children}function Ae(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 mr(e){if(e.__P&&e.__d){var t=e.__v,s=t.__e,n=[],a=[],r=L({},t);r.__v=t.__v+1,b.vnode&&b.vnode(r),ct(e.__P,r,t,e.__n,e.__P.namespaceURI,32&t.__u?[s]:null,n,s??W(t),!!(32&t.__u),a),r.__v=t.__v,r.__.__k[r.__i]=r,os(n,r,a),t.__e=t.__=null,r.__e!=s&&ss(r)}}function ss(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}),ss(e)}function Jt(e){(!e.__d&&(e.__d=!0)&&B.push(e)&&!Oe.__r++||zt!=b.debounceRendering)&&((zt=b.debounceRendering)||Zt)(Oe)}function Oe(){try{for(var e,t=1;B.length;)B.length>t&&B.sort(es),e=B.shift(),t=B.length,mr(e)}finally{B.length=Oe.__r=0}}function ns(e,t,s,n,a,r,o,c,u,l,f){var h,d,m,p,g,D,S=n&&n.__k||Me,_=t.length;for(u=hr(s,t,S,u,_),h=0;h<_;h++)(m=s.__k[h])!=null&&(d=m.__i!=-1&&S[m.__i]||Pe,m.__i=h,D=ct(e,m,d,a,r,o,c,u,l,f),p=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&dt(d.ref,null,m),f.push(m.ref,m.__c||p,m)),g==null&&p!=null&&(g=p),4&m.__u?(u=rs(m,u,e),d.__e&&(d.__e=null)):typeof m.type=="function"&&D!==void 0?u=D:p&&(u=p.nextSibling),m.__u&=-7);return s.__e=g,u}function hr(e,t,s,n,a){var r,o,c,u,l,f=s.length,h=f,d=0;for(e.__k=new Array(a),r=0;r<a;r++)(o=t[r])!=null&&typeof o!="boolean"&&typeof o!="function"?(typeof o=="string"||typeof o=="number"||typeof o=="bigint"||o.constructor==String?o=e.__k[r]=Re(null,o,null,null,null):Le(o)?o=e.__k[r]=Re(X,{children:o},null,null,null):o.constructor===void 0&&o.__b>0?o=e.__k[r]=Re(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):e.__k[r]=o,u=r+d,o.__=e,o.__b=e.__b+1,c=null,(l=o.__i=gr(o,s,u,h))!=-1&&(h--,(c=s[l])&&(c.__u|=2)),c==null||c.__v==null?(l==-1&&(a>f?d--:a<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[r]=null;if(h)for(r=0;r<f;r++)(c=s[r])!=null&&(2&c.__u)==0&&(c.__e==n&&(n=W(c)),ls(c,c));return n}function rs(e,t,s){var n,a;if(typeof e.type=="function"){for(n=e.__k,a=0;n&&a<n.length;a++)n[a]&&(n[a].__=e,t=rs(n[a],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 gr(e,t,s,n){var a,r,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(a=s-1,r=s+1;a>=0||r<t.length;)if((l=t[o=a>=0?a--:r++])!=null&&(2&l.__u)==0&&c==l.key&&u==l.type)return o}return-1}function Qt(e,t,s){t[0]=="-"?e.setProperty(t,s??""):e[t]=s==null?"":typeof s!="number"||fr.test(t)?s:s+"px"}function Te(e,t,s,n,a){var r,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||Qt(e.style,t,"");if(s)for(t in s)n&&s[t]==n[t]||Qt(e.style,t,s[t])}else if(t[0]=="o"&&t[1]=="n")r=t!=(t=t.replace(ts,"$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+r]=s,s?n?s[ue]=n[ue]:(s[ue]=it,e.addEventListener(t,r?ot:at,r)):e.removeEventListener(t,r?ot:at,r);else{if(a=="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 Yt(e){return function(t){if(this.l){var s=this.l[t.type+e];if(t[Ie]==null)t[Ie]=it++;else if(t[Ie]<s[ue])return;return s(b.event?b.event(t):t)}}}function ct(e,t,s,n,a,r,o,c,u,l){var f,h,d,m,p,g,D,S,_,P,de,F,pe,Kt,xe,nt,M=t.type;if(t.constructor!==void 0)return null;128&s.__u&&(u=!!(32&s.__u),r=[c=t.__e=s.__e]),(f=b.__b)&&f(t);e:if(typeof M=="function"){h=o.length;try{if(_=t.props,P=M.prototype&&M.prototype.render,de=(f=M.contextType)&&n[f.__c],F=f?de?de.props.value:f.__:n,s.__c?S=(d=t.__c=s.__c).__=d.__E:(P?t.__c=d=new M(_,F):(t.__c=d=new Ae(_,F),d.constructor=M,d.render=$r),de&&de.sub(d),d.state||(d.state={}),d.__n=n,m=d.__d=!0,d.__h=[],d._sb=[]),P&&d.__s==null&&(d.__s=d.state),P&&M.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=L({},d.__s)),L(d.__s,M.getDerivedStateFromProps(_,d.__s))),p=d.props,g=d.state,d.__v=t,m)P&&M.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),P&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(P&&M.getDerivedStateFromProps==null&&_!==p&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps(_,F),t.__v==s.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate(_,d.__s,F)===!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(Q){Q&&(Q.__=t)}),Me.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,F),P&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(p,g,D)})}if(d.context=F,d.props=_,d.__P=e,d.__e=!1,pe=b.__r,Kt=0,P)d.state=d.__s,d.__d=!1,pe&&pe(t),f=d.render(d.props,d.state,d.context),Me.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,pe&&pe(t),f=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++Kt<25);d.state=d.__s,d.getChildContext!=null&&(n=L(L({},n),d.getChildContext())),P&&!m&&d.getSnapshotBeforeUpdate!=null&&(D=d.getSnapshotBeforeUpdate(p,g)),xe=f!=null&&f.type===X&&f.key==null?is(f.props.children):f,c=ns(e,Le(xe)?xe:[xe],t,s,n,a,r,o,c,u,l),d.base=t.__e,t.__u&=-161,d.__h.length&&o.push(d),S&&(d.__E=d.__=null)}catch(Q){if(o.length=h,t.__v=null,u||r!=null){if(Q.then){for(t.__u|=u?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;r!=null&&(r[r.indexOf(c)]=null),t.__e=c}else if(r!=null)for(nt=r.length;nt--;)lt(r[nt])}else t.__e=s.__e;t.__k==null&&(t.__k=s.__k||[]),Q.then||as(t),b.__e(Q,t,s)}}else r==null&&t.__v==s.__v?(t.__k=s.__k,t.__e=s.__e):c=t.__e=vr(s.__e,t,s,n,a,r,o,u,l);return(f=b.diffed)&&f(t),128&t.__u?void 0:c}function as(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(as))}function os(e,t,s){for(var n=0;n<s.length;n++)dt(s[n],s[++n],s[++n]);b.__c&&b.__c(t,e),e.some(function(a){try{e=a.__h,a.__h=[],e.some(function(r){r.call(a)})}catch(r){b.__e(r,a.__v)}})}function is(e){return typeof e!="object"||e==null||e.__b>0?e:Le(e)?e.map(is):e.constructor!==void 0?null:L({},e)}function vr(e,t,s,n,a,r,o,c,u){var l,f,h,d,m,p,g,D=s.props||Pe,S=t.props,_=t.type;if(_=="svg"?a="http://www.w3.org/2000/svg":_=="math"?a="http://www.w3.org/1998/Math/MathML":a||(a="http://www.w3.org/1999/xhtml"),r!=null){for(l=0;l<r.length;l++)if((m=r[l])&&"setAttribute"in m==!!_&&(_?m.localName==_:m.nodeType==3)){e=m,r[l]=null;break}}if(e==null){if(_==null)return document.createTextNode(S);e=document.createElementNS(a,_,S.is&&S),c&&(b.__m&&b.__m(t,r),c=!1),r=null}if(_==null)D===S||c&&e.data==S||(e.data=S);else{if(r=_=="textarea"&&S.defaultValue!=null?null:r&&Ee.call(e.childNodes),!c&&r!=null)for(D={},l=0;l<e.attributes.length;l++)D[(m=e.attributes[l]).name]=m.value;for(l in D)m=D[l],l=="dangerouslySetInnerHTML"?h=m:l=="children"||l in S||l=="value"&&"defaultValue"in S||l=="checked"&&"defaultChecked"in S||Te(e,l,null,m,a);for(l in S)m=S[l],l=="children"?d=m:l=="dangerouslySetInnerHTML"?f=m:l=="value"?p=m:l=="checked"?g=m:c&&typeof m!="function"||D[l]===m||Te(e,l,m,D[l],a);if(f)c||h&&(f.__html==h.__html||f.__html==e.innerHTML)||(e.innerHTML=f.__html),t.__k=[];else if(h&&(e.innerHTML=""),ns(t.type=="template"?e.content:e,Le(d)?d:[d],t,s,n,_=="foreignObject"?"http://www.w3.org/1999/xhtml":a,r,o,r?r[0]:s.__k&&W(s,0),c,u),r!=null)for(l=r.length;l--;)lt(r[l]);c&&_!="textarea"||(l="value",_=="progress"&&p==null?e.removeAttribute("value"):p!=null&&(p!==e[l]||_=="progress"&&!p||_=="option"&&p!=D[l])&&Te(e,l,p,D[l],a),l="checked",g!=null&&g!=e[l]&&Te(e,l,g,D[l],a))}return e}function dt(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(a){b.__e(a,s)}}function ls(e,t,s){var n,a;if(b.unmount&&b.unmount(e),(n=e.ref)&&(n.current&&n.current!=e.__e||dt(n,null,t)),(n=e.__c)!=null){if(n.componentWillUnmount)try{n.componentWillUnmount()}catch(r){b.__e(r,t)}n.base=n.__P=n.__n=null}if(n=e.__k)for(a=0;a<n.length;a++)n[a]&&ls(n[a],t,s||typeof e.type!="function");s||lt(e.__e),e.__c=e.__=e.__e=void 0}function $r(e,t,s){return this.constructor(e,s)}function pt(e,t,s){var n,a,r,o;t==document&&(t=document.documentElement),b.__&&b.__(e,t),a=(n=typeof s=="function")?null:s&&s.__k||t.__k,r=[],o=[],ct(t,e=(!n&&s||t).__k=Y(X,null,[e]),a||Pe,Pe,t.namespaceURI,!n&&s?[s]:a?null:t.firstChild?Ee.call(t.childNodes):null,r,!n&&s?s:a?a.__e:t.firstChild,n,o),os(r,e,o),e.props.children=null}Ee=Me.slice,b={__e:function(e,t,s,n){for(var a,r,o;t=t.__;)if((a=t.__c)&&!a.__)try{if((r=a.constructor)&&r.getDerivedStateFromError!=null&&(a.setState(r.getDerivedStateFromError(e)),o=a.__d),a.componentDidCatch!=null&&(a.componentDidCatch(e,n||{}),o=a.__d),o)return a.__E=a}catch(c){e=c}throw e}},Xt=0,pr=function(e){return e!=null&&e.constructor===void 0},Ae.prototype.setState=function(e,t){var s;s=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=L({},this.state),typeof e=="function"&&(e=e(L({},s),this.props)),e&&L(s,e),e!=null&&this.__v&&(t&&this._sb.push(t),Jt(this))},Ae.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Jt(this))},Ae.prototype.render=X,B=[],Zt=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,es=function(e,t){return e.__v.__b-t.__v.__b},Oe.__r=0,rt=Math.random().toString(8),Ie="__d"+rt,ue="__a"+rt,ts=/(PointerCapture)$|Capture$/i,it=0,at=Yt(!1),ot=Yt(!0),ur=0;var Z=e=>e>999?"999+":String(e);function _r(e){return{id:e,lane:"work",bucket:"done",repo:"",title:"",verb:"unknown",sort:0}}var cs=new WeakMap;function ut(e,t){let s=e.dispatches||[],n=cs.get(s);return n||cs.set(s,n=new Map(s.map(a=>[a.id,a]))),{...t,catches:(t.catches||[]).map(a=>n.get(a)??_r(a))}}function O(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 ee=["deck","dispatches","traps","prs","reports","notices"];function fs(e){let t=String(e||"").replace(/^#/,"");return ee.includes(t)?t:"deck"}var ft=e=>`#decision/${encodeURIComponent(e)}`;function Ne(e){let t=/^#?decision\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var mt=(e,t,s)=>`/attachment/dispatch/${encodeURIComponent(e)}/${encodeURIComponent(t)}/${encodeURIComponent(s)}`,ms=(e,t)=>`/attachment/trap/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,hs=e=>/\\.(png|jpe?g|gif|webp)$/i.test(e),ht=(e,t)=>`/decision/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`;function gt(e,t){let s=new Map(t.map(a=>[a.key,a])),n=[];for(let a of e)if(a.kind==="decision"){let r=s.get(a.key);if(!r)continue;n.push({kind:"decision",key:r.key,title:r.title,detail:r.detail,options:r.options,attachments:r.attachments,...r.dispatch?{dispatch:r.dispatch,lane:r.lane??"work"}:{},...r.repo?{repo:r.repo}:{},at:r.askedAt})}else a.kind==="question"&&n.push({kind:"question",key:a.key,verb:a.verb,note:a.note||a.verb,dispatch:a.id,lane:a.lane,...a.repo?{repo:a.repo}:{},at:a.at??""});return n.sort((a,r)=>r.at.localeCompare(a.at)||a.key.localeCompare(r.key))}function gs(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 vs(e,t){return(e.reports||[]).find(s=>s.key===`report:${t.lane}:${t.id}`)}function fe(e){return e.author==="helm"?"":e.trap?e.trap:e.author==="headless"?e.dispatch?e.dispatch.slice(0,8):"":e.author}var ds=(e,t)=>+!!e.acked-+!!t.acked||t.filedAt.localeCompare(e.filedAt),C=e=>`/report/${encodeURIComponent(e)}`;function me(e){let t=/^#?report\\/(.+)$/.exec(String(e||""));if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}function $s(e){return typeof e!="string"?!1:e===""?!0:e.length>1024||!e.startsWith("#")||/[\\s\\x00-\\x1f\\x7f]/.test(e)?!1:ee.includes(e.slice(1))||Ne(e)!==null||me(e)!==null}function _s(e){let t=/^\\/report\\/([^/?#]+)\\/?$/.exec(e);if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}var bs=e=>`/report/${encodeURIComponent(e)}/md`,vt=(e,t)=>`/report/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`,$t={dispatches:[],notices:[],prs:[],stacks:[]};function ks(e,t){if(t.kind==="dispatches"){let a=new Set(e.dispatches.map(r=>r.lane+":"+r.id));return{...e,dispatches:[...e.dispatches,...t.items.filter(r=>!a.has(r.lane+":"+r.id))]}}if(t.kind==="notices"){let a=new Set(e.notices.map(r=>r.seq));return{...e,notices:[...e.notices,...t.items.filter(r=>!a.has(r.seq))]}}let s=new Set(e.prs.map(a=>a.key)),n=new Set(e.stacks.map(a=>a.id));return{...e,prs:[...e.prs,...t.items.filter(a=>!s.has(a.key))],stacks:[...e.stacks,...t.stacks.filter(a=>!n.has(a.id))]}}function ys(e,t){if(t===$t||!t.dispatches.length&&!t.notices.length&&!t.prs.length)return e;let s=new Set(e.dispatches.map(o=>o.lane+":"+o.id)),n=new Set(e.notices.map(o=>o.seq)),a=new Set(e.prs.map(o=>o.key)),r=new Set(e.stacks.map(o=>o.id));return{...e,dispatches:[...e.dispatches,...t.dispatches.filter(o=>!s.has(o.lane+":"+o.id))],notices:[...e.notices,...t.notices.filter(o=>!n.has(o.seq))],prs:[...e.prs,...t.prs.filter(o=>!a.has(o.key))],stacks:[...e.stacks,...t.stacks.filter(o=>!r.has(o.id))]}}function ws(e,t,s){return Math.max(0,(e.older?.[s]??0)-t[s].length)}function Gs(e,t){return{...e,now:t.now,daemon:e.daemon&&t.daemon!==void 0?{...e.daemon,heartbeat:t.daemon}:e.daemon,helms:e.helms.map(s=>t.helms[s.grounds]!==void 0?{...s,heartbeatAt:t.helms[s.grounds]}:s),traps:e.traps.map(s=>t.traps[s.trapId]?{...s,...t.traps[s.trapId]}:s)}}function ps(e,t,s){return!!e&&s-Date.parse(e)>t}function us(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.title||"")+" "+(e.repo||"")+" "+(e.for||"")).toLowerCase().includes(s))return!1}return!0}function te(e,t,s){if(!t)return null;if(t.type==="helm")return e.helms.find(a=>a.grounds===t.key)||null;if(t.type==="dispatch"){let a=e.dispatches.find(o=>o.lane+":"+o.id===t.key),r=s&&s.key===t.key?s.data:void 0;return a&&r?{...a,...r}:a??r??null}if(t.type==="pr")return(e.prs||[]).find(a=>a.key===t.key)||null;if(t.type==="settings")return{attentionKinds:e.attentionKinds||[],attentionError:e.attentionError};let n=e.traps.find(a=>a.trapId===t.key);return n?ut(e,n):null}function Ss(e,t,s){let n=t.st,a=String(n.q||"").toLowerCase(),r=(...p)=>!a||p.join(" ").toLowerCase().includes(a),o=p=>({x:p,stale:ps(p.heartbeatAt,18e5,s)}),c=te(e,t.modal,t.detail),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)))&&r(p.name,p.trapId,p.repo,p.worktree)),m=({ageSecs:p,...g})=>g;return{chips:{daemon:e.daemon,daemonStale:!!e.daemon&&ps(e.daemon.heartbeat,9e4,s),helms:e.helms.map(o),stats:e.stats},deck:{view:n.view,decisions:gt(e.attention||[],e.decisions||[]).filter(p=>p.kind==="decision"?r(p.kind,p.repo,p.title,p.dispatch,p.detail):r(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)&&r(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=>r(p.title,p.author,p.dispatch,p.repo)).sort(ds),inflight:e.dispatches.filter(p=>p.bucket!=="done"&&us(p,{...n,lane:"",repo:"",verb:""})),traps:d.map(p=>o(ut(e,p))),stacks:(e.stacks||[]).filter(p=>p.open&&r(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=>us(p,n))},traps:{view:n.view,list:h.filter(p=>(!n.repo||p.repo===n.repo)&&r(p.name,p.trapId,p.repo,p.worktree,p.harness)).map(p=>o(ut(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)&&r(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)&&r(p.title,p.author,p.dispatch,p.repo)).sort(ds)},notices:{list:(e.notices||[]).filter(p=>(!n.repo||!p.repo||p.repo===n.repo)&&(!n.noticeKind||p.kind===n.noticeKind)&&r(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 Ds(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),a=new Map((e.dispatches||[]).map(c=>[c.id,c])),r=(s.dispatchIds||[]).map(c=>{let u=a.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:r,watch:o?{key:o.key,owner:o.owner||"",lastCheckedAt:o.lastCheckedAt||null,lastError:o.lastError||null,cursor:o.cursor}:null}}function Cs(e){return e?{text:e.lastError?"failing":"watching",at:e.lastCheckedAt||null}:{text:"no watch",at:null}}function xs(){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 Ts(e){try{localStorage.setItem("spyglass",JSON.stringify(e))}catch{}}function Is(){try{return JSON.parse(localStorage.getItem("spyglass-lob-hidden")||"{}")||{}}catch{return{}}}function Rs(e){try{localStorage.setItem("spyglass-lob-hidden",JSON.stringify(e))}catch{}}var he,He;function ge(e){if(e.snapshot)return(He?.snapshot!==e.snapshot||He.older!==e.older)&&(He={snapshot:e.snapshot,older:e.older,view:ys(e.snapshot,e.older)}),He.view}var As=new Set,$=()=>he;function _t(e){he=e}function y(e){he={...he,...e};for(let t of As)t(he)}var bt=e=>{As.add(e)};function br(e,t){let s=ge(e);return s&&te(s,t,e.detail)?!0:t.type==="dispatch"&&e.detail?.key===t.key&&!e.detail.error}function je(e){let{modal:t,drafts:s,older:n,detail:a}=$(),r=new Set(gt(e.attention||[],e.decisions||[]).map(c=>c.key)),o=Object.fromEntries(Object.entries(s).filter(([c])=>r.has(c)));y({snapshot:e,stale:!1,modal:t&&br({snapshot:e,older:n,detail:a},t)?t:null,...Object.keys(o).length!==Object.keys(s).length?{drafts:o}:{}})}function Ps(e){let{snapshot:t}=$();y({stale:!1,...t?{snapshot:Gs(t,e)}:{}})}async function kt(){let{modal:e}=$();if(e?.type!=="dispatch")return;let t=e.key,s=t.slice(t.indexOf(":")+1),n;try{let r=await fetch(`/data/dispatch/${encodeURIComponent(s)}`,{cache:"no-store"});n=r.ok?{data:await r.json()}:{error:r.status===404?"this dispatch is gone":`the detail answered ${r.status}`}}catch{n={error:"the detail could not be read"}}let a=$();a.modal?.type!=="dispatch"||a.modal.key!==t||n.error&&a.detail?.key===t&&a.detail.data||y({detail:{key:t,...n}})}async function Ms(e){let{olderLoading:t,older:s}=$();if(!t){y({olderLoading:e,olderError:null});try{let n=await fetch(`/data/older?kind=${e}&offset=${s[e].length}&limit=50`,{cache:"no-store"});if(!n.ok)throw new Error(`/data/older answered ${n.status}`);let a=await n.json();y({older:ks($().older,a),olderLoading:null})}catch{y({olderLoading:null,olderError:{kind:e,text:"older records could not be read"}})}}}var Os=()=>({text:"",files:[]});function R(e,t){let s=$().drafts;y({drafts:{...s,[e]:{...s[e]??Os(),...t}}})}function Es(e,t){let s=$().drafts[e]?.option;R(e,{option:s===t?void 0:t,error:void 0})}var kr=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 yt(e,t){let s=$().snapshot?.answerLimits,n=[...t??[]],a=$().drafts[e]?.files??[],r=[],o=[];for(let c of n){let u=(/\\.[^.]+$/.exec(c.name)?.[0]??"").toLowerCase();if(s&&!s.extensions.includes(u))r.push(`${c.name}: type not accepted`);else if(s&&c.size>s.maxBytes)r.push(`${c.name}: larger than ${s.maxBytes} bytes`);else if(s&&a.length+o.length>=s.maxFiles)r.push(`${c.name}: at most ${s.maxFiles} files`);else try{o.push({name:c.name,bytes:c.size,data:await kr(c)})}catch{r.push(`${c.name}: could not be read`)}}R(e,{files:[...$().drafts[e]?.files??[],...o],error:r.length?r.join("; "):void 0})}var yr={"image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp"};async function Ls(e,t){let s=[...t.clipboardData?.items??[]],n=new Date().toISOString().replace(/[:.]/g,"-").replace(/-\\d{3}Z$/,"Z"),a=s.filter(r=>r.kind==="file"&&r.type.startsWith("image/")).map(r=>r.getAsFile()).filter(r=>r!==null).map((r,o,c)=>{let u=`pasted-${n}${c.length>1?`-${o+1}`:""}${yr[r.type]??".png"}`;return new File([r],u,{type:r.type})});a.length&&await yt(e,a)}function Ns(e,t){let s=($().drafts[e]?.files??[]).filter((n,a)=>a!==t);R(e,{files:s})}async function Hs(e){let t=$().snapshot?.focusToken,s=$().drafts[e]??Os();if(!(s.sending||s.sent)){if(!s.option&&!s.text.trim()&&s.files.length===0){R(e,{error:"Choose an option, write an answer, or attach a file."});return}if(!t){R(e,{error:"This page has no answer token; reload it."});return}R(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(r=>({name:r.name,data:r.data}))}})}),a=await n.json();if(!n.ok||!a.ok){R(e,{sending:!1,error:a.reason??`The answer was refused (${n.status}).`});return}R(e,{sending:!1,sent:gs({option:s.option,text:s.text,files:s.files.length})})}catch{R(e,{sending:!1,error:"The answer could not be sent."})}}}var js=()=>y({stale:!0}),Us=(e,t)=>y({lightbox:{src:e,name:t}}),se=()=>y({lightbox:null});function E(e,t){let s=$(),n={type:e,key:t};if(e==="dispatch"){y({modal:n,detail:s.detail?.key===t?s.detail:{key:t}}),kt();return}let a=ge(s);y({modal:!a||te(a,n)?n:null,detail:null})}function ne(){y({modal:null,detail:null})}async function Bs(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();y({focusResults:{...$().focusResults,[e]:n.message??n.reason??"Window focus failed."}})}catch{y({focusResults:{...$().focusResults,[e]:"Window focus failed."}})}}async function qs(e,t){let s=$().snapshot?.focusToken;if(!s)return"The glass has no page token yet.";try{let a=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(!a.ok)return a.reason??"The request was refused."}catch{return"The request could not be sent."}try{je(await(await fetch("/data")).json())}catch{}}function N(e){let t={...$().prefs,...e};Ts(t),y({prefs:t})}function Vs(e){e!=="table"&&e!=="cards"||N({view:e})}var Fs=e=>N({lobs:e==="on"});function Ws(e,t){let s={...$().lobHidden,[e]:t};Rs(s),setTimeout(()=>y({lobHidden:s}),0)}async function Ks(e){try{return await navigator.clipboard.writeText(e),!0}catch{return!1}}var Js=function(e,t,s,n){var a;t[0]=0;for(var r=1;r<t.length;r++){var o=t[r++],c=t[r]?(t[0]|=o?1:2,s[t[r++]]):t[++r];o===3?n[0]=c:o===4?n[1]=Object.assign(n[1]||{},c):o===5?(n[1]=n[1]||{})[t[++r]]=c:o===6?n[1][t[++r]]+=c+"":o?(a=e.apply(c,Js(e,c,s,["",null])),n.push(a),c[0]?t[0]|=2:(t[r-2]=0,t[r]=a)):n.push(c)}return n},zs=new Map;function Qs(e){var t=zs.get(this);return t||(t=new Map,zs.set(this,t)),(t=Js(this,t.get(e)||(t.set(e,t=(function(s){for(var n,a,r=1,o="",c="",u=[0],l=function(d){r===1&&(d||(o=o.replace(/^\\s*\\n\\s*|\\s*\\n\\s*$/g,"")))?u.push(0,d,o):r===3&&(d||o)?(u.push(3,d,o),r=2):r===2&&o==="..."&&d?u.push(4,d,0):r===2&&o&&!d?u.push(5,0,!0,o):r>=5&&((o||!d&&r===5)&&(u.push(r,0,o,a),r=6),d&&(u.push(r,d,0,a),r=6)),o=""},f=0;f<s.length;f++){f&&(r===1&&l(),l(f));for(var h=0;h<s[f].length;h++)n=s[f][h],r===1?n==="<"?(l(),u=[u],r=3):o+=n:r===4?o==="--"&&n===">"?(r=1,o=""):o=n+o[0]:c?n===c?c="":o+=n:n===\'"\'||n==="\'"?c=n:n===">"?(l(),r=1):r&&(n==="="?(r=5,a=o,o=""):n==="/"&&(r<5||s[f][h+1]===">")?(l(),r===3&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):n===" "||n===" "||n===`\n`||n==="\\r"?(l(),r=2):o+=n),r===3&&o==="!--"&&(r=4,u=u[0])}return l(),u})(e)),t),arguments,[])).length>1?t:t[0]}var Ys=e=>Array.isArray(e)?e.map(Ys):e===""?null:e,wr=(e,t,...s)=>Y(e,t,...s.map(Ys)),i=Qs.bind(wr);var Be,w,wt,Xs,Gt=0,on=[],G=b,Zs=G.__b,en=G.__r,tn=G.diffed,sn=G.__c,nn=G.unmount,rn=G.__;function ln(e,t){G.__h&&G.__h(w,e,Gt||t),Gt=0;var s=w.__H||(w.__H={__:[],__h:[]});return e>=s.__.length&&s.__.push({}),s.__[e]}function re(e){return Gt=1,Gr(dn,e)}function Gr(e,t,s){var n=ln(Be++,2);if(n.t=e,!n.__c&&(n.__=[s?s(t):dn(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=w,!w.__f)){var a=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)}}),r){var d=r.call(this,c,u,l);return f?d||h:d}return!f||h};w.__f=!0;var r=w.shouldComponentUpdate,o=w.componentWillUpdate;w.componentWillUpdate=function(c,u,l){if(this.__e){var f=r;r=void 0,a(c,u,l),r=f}o&&o.call(this,c,u,l)},w.shouldComponentUpdate=a}return n.__N||n.__}function cn(e,t){var s=ln(Be++,7);return Cr(s.__H,t)&&(s.__=e(),s.__H=t,s.__h=e),s.__}function Sr(){for(var e;e=on.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(Ue),t.__h.some(St),t.__h=[]}catch(s){t.__h=[],G.__e(s,e.__v)}}}G.__b=function(e){w=null,Zs&&Zs(e)},G.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),rn&&rn(e,t)},G.__r=function(e){en&&en(e),Be=0;var t=(w=e.__c).__H;t&&(wt===w?(t.__h=[],w.__h=[],t.__.some(function(s){s.__N&&(s.__=s.__N),s.u=s.__N=void 0})):(t.__h.some(Ue),t.__h.some(St),t.__h=[],Be=0)),wt=w},G.diffed=function(e){tn&&tn(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(on.push(t)!==1&&Xs===G.requestAnimationFrame||((Xs=G.requestAnimationFrame)||Dr)(Sr)),t.__H.__.some(function(s){s.u&&(s.__H=s.u,s.u=void 0)})),wt=w=null},G.__c=function(e,t){t.some(function(s){try{s.__h.some(Ue),s.__h=s.__h.filter(function(n){return!n.__||St(n)})}catch(n){t.some(function(a){a.__h&&(a.__h=[])}),t=[],G.__e(n,s.__v)}}),sn&&sn(e,t)},G.unmount=function(e){nn&&nn(e);var t,s=e.__c;s&&s.__H&&(s.__H.__.some(function(n){try{Ue(n)}catch(a){t=a}}),s.__H=void 0,t&&G.__e(t,s.__v))};var an=typeof requestAnimationFrame=="function";function Dr(e){var t,s=function(){clearTimeout(n),an&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(s,35);an&&(t=requestAnimationFrame(s))}function Ue(e){var t=w,s=e.__c;typeof s=="function"&&(e.__c=void 0,s()),w=t}function St(e){var t=w;e.__c=e.__(),w=t}function Cr(e,t){return!e||e.length!==t.length||t.some(function(s,n){return s!==e[n]})}function dn(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=>i`<span data-age=${e??""}>${K(e)}</span>`,Ve=e=>e.activity&&i`<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>`,xr=e=>e&&/^https?:\\/\\//i.test(e)?e:void 0,Fe=e=>{let t=e.waiting;if(!t)return;let s=xr(t.link),n=s;try{s&&(n=new URL(s).host+new URL(s).pathname.replace(/\\/$/,""))}catch{n=s}return i`<div class="waiting">${e.verb}: waiting on ${t.on} \xB7 ${v(t.since)}${s&&[" \\xB7 ",i`<a href=${s} target="_blank" rel="noopener noreferrer" onClick=${x}>${n}</a>`]}</div>`},Tr=12,pn=e=>e!==void 0&&e.length>Tr,H=e=>pn(e)?e:void 0,j=e=>pn(e)?" long":"",k=(e,t)=>()=>E(e,t),x=e=>e.stopPropagation(),Ir=e=>e.sessionId?(e.harness==="codex"?"codex resume ":"claude --resume ")+e.sessionId:void 0;function z(e){if(e.requested)return i`<span class="dim">Requested \u2014 no window yet</span>`;if(e.starting)return i`<span class="dim">${e.starting.failedAt?"Did not start":"Starting \\u2014 no window yet"}</span>`;if(!e.live){let n=Ir(e);return n?i`<span class="dim">Resume: <code onClick=${x}>${n}</code></span>`:i`<span class="dim">Resume command unavailable</span>`}let t=$();return!t.snapshot?.focusSupported&&!e.link?i`<span class="dim">Window focus is not supported here</span>`:i`<span class="winaction"><button class="btn open" title="open this trap\'s window" onClick=${n=>{x(n),Bs(e.trapId)}}>\u2197 open</button>${e.link&&[" ",i`<a href=${e.link} onClick=${x}>Session link</a>`]}${t.focusResults[e.trapId]&&[" ",i`<span class="dim">${t.focusResults[e.trapId]}</span>`]}</span>`}function A(e,t,s){return t.length?i`<div class="wrap"><table><tbody><tr>${e.map(n=>i`<th>${n}</th>`)}</tr>${t}</tbody></table></div>`:i`<div class="empty">${s}</div>`}function oe({kind:e,more:t}){return!t.left&&!t.error?null:i`<div class="older">${t.left>0&&i`<button class="btn" disabled=${t.loading} onClick=${()=>{Ms(e)}}>${t.loading?"loading\\u2026":`show ${Math.min(t.left,50)} older (of ${t.left})`}</button>`}${t.error&&i` <span class="bad">${t.error}</span>`}</div>`}function Rr({text:e}){let[t,s]=re(null),n=a=>async()=>{await Ks(e)&&(s(a),setTimeout(()=>s(null),1e3))};return i`<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 T=(e,t)=>i`<${Rr} key=${t} text=${e} />`,ve=(e,t,s="thumb")=>i`<button\n type="button"\n class=${s}\n title=${"view "+t}\n onClick=${n=>{x(n),Us(e,t)}}\n >\n <img src=${e} alt=${t} loading="lazy" />\n </button>`,ae=(e,t)=>e.map(s=>[i`<div class="sub">${s.name} \xB7 ${s.type} \xB7 ${s.bytes} bytes</div>`,t&&hs(s.name)&&ve(t(s.name),s.name),T(s.path)]),un=/\\bwt:([a-z0-9][a-z0-9-]*)/g,Dt=e=>$().snapshot?.trapNames?.[e],U=e=>e.replace(un,(t,s,n)=>{let a=Dt(s);return a&&!fn(e,n,t.length,a)?a:t}),fn=(e,t,s,n)=>e.slice(Math.max(0,t-n.length-2),t)===`${n} (`&&e[t+s]===")";function We(e){let t="wt:"+e,s=Dt(e)??t;return $().snapshot?.traps.some(a=>a.trapId===e)?i`<a class="trapname" href="#traps" title=${t} onClick=${a=>{a.preventDefault(),x(a),E("trap",e)}}>${s}</a>`:i`<span class="trapname" title=${t}>${s}</span>`}var qe=e=>{let t=/^wt:([a-z0-9][a-z0-9-]*)$/.exec(e);return t?We(t[1]):e};function I(e,t=1/0){let s=[],n=0;for(let c of e.matchAll(un)){c.index>n&&s.push({text:e.slice(n,c.index)});let u=Dt(c[1]);s.push(u&&fn(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 a=s.reduce((c,u)=>c+u.text.length,0),r=a>t?t-1:1/0,o=[];for(let c of s){if(r<=0)break;c.text.length<=r?o.push(c.trapId?We(c.trapId):c.text):o.push(c.text.slice(0,r)),r-=c.text.length}return a>t&&o.push("\\u2026"),o}var Ar=e=>e.log.flatMap((t,s)=>[s?`\n`:"",t.at+" "+t.verb,...t.note?[" ",...I(t.note)]:[]]),Pr=e=>"brief"in e;function mn(e,t){let s=[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`),n=i`${e.waiting&&[i`<div class="sec">waiting</div>`,Fe(e)]}${e.activity&&[i`<div class="sec">activity</div>`,Ve(e)]}${s&&[i`<div class="sec">progress</div>`,i`<pre>${s}</pre>`]}`;return Pr(e)?i`${n}<div class="sec">brief</div><pre>${e.brief}</pre>${e.attachments.length>0&&[i`<div class="sec">attachments (${e.attachments.length})</div>`,ae(e.attachments,a=>mt(e.lane,e.id,a))]}${e.messageAttachments.length>0&&[i`<div class="sec">message attachments (${e.messageAttachments.length})</div>`,ae(e.messageAttachments,a=>mt(e.lane,e.id,a))]}${e.followUp&&[i`<div class="sec">forks</div>`,i`<pre>${e.followUp}</pre>`]}<div class="sec">log</div><div class="loglines">${e.log.length?Ar(e):"no entries yet"}</div>${e.inbox.length>0&&[i`<div class="sec">inbox</div>`,i`<div class="loglines">${e.inbox.join(`\n---\n`)}</div>`]}${e.awaitingReply&&[i`<div class="sec">awaiting reply</div>`,i`<div>${e.awaitingReply.line} \xB7 from ${e.awaitingReply.from} \xB7 ${v(e.awaitingReply.sentAt)} ago</div>`]}${e.evidence&&[i`<div class="sec">evidence</div>`,i`<div class="loglines">${JSON.stringify(e.evidence)}</div>`]}`:i`${n}<div class="sec">brief</div><div class=${t?.error?"bad":"dim"}>${t?.error??"loading\\u2026"}</div>${e.followUp&&[i`<div class="sec">forks</div>`,i`<pre>${e.followUp}</pre>`]}${e.note&&[i`<div class="sec">last note</div>`,i`<div class="loglines">${I(e.note)}</div>`]}`}function $e(e){return e.for?[qe(e.for),e.evidence&&e.evidence.deliveredTo?[" ",i`<span class="ok">\u2713delivered</span>`]:[" ",i`<span class="warn">waiting</span>`]]:e.claimedBy?qe(e.claimedBy):""}function ie(e){if(e.prList&&e.prList.length>1)return[e.prList.map((a,r)=>[r?" \\u2192 ":"",i`<a href=${a.url} target="_blank" rel="noopener" onClick=${x}>#${a.number}</a>`,a.badge&&[" ",i`<span class=${"badge "+O(a.badge)}>${a.badge.text}</span>`]]),e.prGate&&[" ",i`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]];let t=e.evidence&&(e.evidence.prUrl||e.evidence.pr&&e.evidence.pr.url);if(!t)return"";let s=e.prBadge,n=e.evidence&&e.evidence.prUrls&&e.evidence.prUrls.length>1?e.evidence.prUrls:void 0;return[n?n.map((a,r)=>[r?" ":"",i`<a href=${a} target="_blank" rel="noopener" onClick=${x}>#${a.split("/").pop()}</a>`]):i`<a href=${t} target="_blank" rel="noopener" onClick=${x}>PR</a>`,s&&[" ",i`<span class=${"badge "+O(s)} title=${"observed "+s.observedAt}>${s.text}</span>`],e.prGate&&[" ",i`<span class="badge dim" title="merge gate (pick)">${e.prGate}</span>`]]}var Mr={"pr:draft":"draft","pr:review":"review","pr:checks":"checks","pr:conflict":"conflicts","pr:ready":"ready",landed:"landed",watch:"watch"},Ct={"pr:review":"bad","pr:checks":"bad","pr:conflict":"pr-conflicts","pr:ready":"ok","pr:draft":"dim",watch:"warn"},hn=e=>Mr[e]||"";var Ke=e=>i`<a href=${e.url} target="_blank" rel="noopener" onClick=${x}>#${e.number}</a>`,ze=e=>i`<span class="prname" title=${e.title||void 0}><b>#${e.number}</b>${e.title&&[" ",e.title]}</span>`;function le(e,t,s){return e.flatMap((n,a)=>{let r=t.get(n)||void 0,o=n===s?i`<b title=${r}>#${n}</b>`:i`<span title=${r}>#${n}</span>`;return a?[" \\u2192 ",o]:[o]})}function _e(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 be(e){return[e.mergeStateStatus,e.nextMergeable?[" \\xB7 ",i`<span class="ok">next mergeable</span>`]:e.blockedBy?" \\xB7 blocked by #"+e.blockedBy:""]}function xt(e){let t=Cs(e);return e?[t.text," \\xB7 ",t.at?[v(t.at)," ago"]:"never checked"]:i`<span class="dim">${t.text}</span>`}function ke(e){if(e.requested)return{stale:!1,listen:[i`<span class="dot"></span>`,i`<span class="dim">requested</span>`],hb:i`<span class="dim">\u2014</span>`};if(e.starting)return{stale:!1,listen:e.starting.failedAt?[i`<span class="dot bad"></span>`,i`<span class="bad">start failed</span>`]:[i`<span class="dot warn"></span>`,"starting"],hb:i`<span class="dim">\u2014</span>`};if(!e.live)return{stale:!1,listen:[i`<span class="dot"></span>`,i`<span class="dim">signed off</span>`],hb:i`<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?[i`<span class="dot ok"></span>`,"listening"]:[i`<span class="dot warn"></span>`,"not listening"],hb:i`<span class=${t?"bad":"ok"}>${t&&"stale "}${v(e.heartbeatAt)} ago</span>`}}function Tt(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 Or(e){let t=Tt(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 gn=e=>e.waiting?`waiting on ${e.waiting.on}`:e.note||"waiting",vn=e=>e.title.slice(0,40)||"(no title)";function ye(e){let t=Tt(e),s=i`<span class=${"dot trapdot "+Or(e)}></span>`;if(t.kind==="requested")return[s,i`<span class="dim">${$n(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,i`<span class="bad">start failed</span>`," \\xB7 ",t.reason];if(t.kind==="signed off")return[s,i`<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 ",gn(n)]:[s,"working \\xB7 ",i`<a href="#dispatches" onClick=${r=>{r.preventDefault(),x(r),E("dispatch",`${n.lane}:${n.id}`)}}>${n.id.slice(0,8)}</a>`," \\xB7 ",vn(n),n.activity&&[" \\xB7 ",n.activity.summary," ",v(n.activity.at)," ago"]]}var $n=(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?i`<div class="startcmds" onClick=${x}><div class="dim">start it: run one in a terminal</div>${t.map(s=>T(s.command,s.harness))}</div>`:null}function Qe(){let t=$().snapshot?.repoKeys??[],[s,n]=re(!1),[a,r]=re(""),[o,c]=re("claude"),[u,l]=re(null),f=a||t[0]||"",h=async d=>{d.preventDefault();let m=await qs(f,o);l(m??null),m||n(!1)};return s?i`<form class="newtrap" onClick=${x} onSubmit=${h}>\n <label>repo <select name="repo" value=${f} onChange=${d=>r(d.target.value)}>${t.map(d=>i`<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&&i`<span class="bad">${u}</span>`}\n </form>`:i`<span class="newtrap"><button class="btn" onClick=${d=>(x(d),n(!0),l(null))}>+ New trap</button></span>`}function Ye(e){let t=Tt(e);if(t.kind==="requested")return $n(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 ${gn(t.current)}`;let s=t.current;return[`working \\xB7 ${s.id.slice(0,8)} \\xB7 ${vn(s)}`,s.activity&&`${s.activity.summary} ${K(s.activity.at)} ago`].filter(Boolean).join(" \\xB7 ")}function It(e){let t=e.messages.filter(s=>s.state==="pending").length;return e.messages.length?["\\u2709 "+e.messages.length,t>0&&[" ",i`<span class="warn">(${t} pending)</span>`]]:null}var Er=e=>()=>{window.open(C(e.key),"_blank","noopener")};function Rt(e){let t=fe(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 Lr(e){let t=Rt(e);return i`<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 Nr(e){return i`<tr key=${e.key} class=${"rowhead"+(e.acked?" acked":"")} onClick=${Er(e)}><td class="grow"><a href=${C(e.key)} target="_blank" rel="noopener" onClick=${t=>t.stopPropagation()}>${e.title}</a></td><td>${fe(e)}</td><td>${v(e.filedAt)}</td><td>${e.acked?"acked":""}</td></tr>`}function _n({inp:e}){return e.view==="cards"?e.list.length?i`<div class="cards">${e.list.map(Lr)}</div>`:i`<div class="empty">no reports match</div>`:A(["title","from","filed","acked"],e.list.map(Nr),"no reports match")}function yn(e){let t=e.trim();return/^(https?:\\/\\/|mailto:|#)/i.test(t)?t:void 0}function wn(e){let t=e.trim();return/^[^/\\\\:?#]+$/.test(t)&&t!=="."&&t!==".."?t:void 0}function bn(e,t,s,n){let a=0;for(let r=t;r<e.length;r++){if(e[r]==="\\\\"){r++;continue}if(e[r]===s)a++;else if(e[r]===n){if(a===0)return r;a--}}return-1}function kn(e,t){let s=bn(e,t+1,"[","]");if(s<0||e[s+1]!=="(")return;let n=bn(e,s+2,"(",")");if(n<0)return;let a=e.slice(s+2,n).trim().replace(/\\s+"[^"]*"$/,"").replace(/^<(.*)>$/,"$1");return{text:e.slice(t+1,s),target:a,end:n+1}}function q(e){let t=[],s="",n=()=>{s&&t.push({t:"text",v:s}),s=""};for(let a=0;a<e.length;){let r=e[a];if(r==="\\\\"&&a+1<e.length&&/[\\\\`*_{}[\\]()#+\\-.!|<>~]/.test(e[a+1])){s+=e[a+1],a+=2;continue}if(r==="`"){let o=/^`+/.exec(e.slice(a))[0],c=e.indexOf(o,a+o.length);if(c>0){n(),t.push({t:"code",v:e.slice(a+o.length,c).replace(/^ (.*) $/,"$1")}),a=c+o.length;continue}}if(r==="!"&&e[a+1]==="["){let o=kn(e,a+1);if(o){n(),t.push({t:"img",alt:o.text,src:o.target}),a=o.end;continue}}if(r==="["){let o=kn(e,a);if(o){n(),t.push({t:"a",href:o.target,c:q(o.text)}),a=o.end;continue}}if((r==="*"||r==="_")&&e[a+1]===r){let o=e.indexOf(r+r,a+2);if(o>a+2){n(),t.push({t:"b",c:q(e.slice(a+2,o))}),a=o+2;continue}}if(r==="*"||r==="_"&&(a===0||!/\\w/.test(e[a-1]))){let o=a+1;for(;(o=e.indexOf(r,o))>0&&(e[o+1]===r||r==="_"&&/\\w/.test(e[o+1]??""));)o+=2;if(o>a+1&&e[a+1]!==" "){n(),t.push({t:"i",c:q(e.slice(a+1,o))}),a=o+1;continue}}if(r===`\n`){/ {2,}$/.test(s)||s.endsWith("\\\\")?(s=s.replace(/( {2,}|\\\\)$/,""),n(),t.push({t:"br"})):s+=" ",a++;continue}s+=r,a++}return n(),t}var Gn=/^ {0,3}(`{3,}|~{3,})\\s*([^`\\s]*)/,Sn=/^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/,Dn=/^ {0,3}([-*_])(\\s*\\1){2,}\\s*$/,Mt=/^( {0,3})([-*+])\\s+(.*)$/,Ot=/^( {0,3})(\\d{1,9})[.)]\\s+(.*)$/,Xe=/^ {0,3}>\\s?(.*)$/,Hr=/^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;function At(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 a=0;a<t.length;a++)t[a]==="\\\\"&&t[a+1]==="|"?(n+="|",a++):t[a]==="|"?(s.push(n.trim()),n=""):n+=t[a];return s.push(n.trim()),s}var Pt=e=>Gn.test(e)||Sn.test(e)||Dn.test(e)||Mt.test(e)||Ot.test(e)||Xe.test(e);function Ze(e){let t=e.replace(/\\r\\n?/g,`\n`).replace(/\\t/g," ").split(`\n`),s=[],n=0;for(;n<t.length;){let a=t[n];if(!a.trim()){n++;continue}let r=Gn.exec(a);if(r){let f=r[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:r[2]??"",v:h.join(`\n`)});continue}let o=Sn.exec(a);if(o){s.push({t:"h",level:o[1].length,c:q(o[2])}),n++;continue}if(Dn.test(a)){s.push({t:"hr"}),n++;continue}if(Xe.test(a)){let f=[];for(;n<t.length&&t[n].trim()&&(Xe.test(t[n])||!Pt(t[n]));)f.push(Xe.exec(t[n])?.[1]??t[n]),n++;s.push({t:"quote",c:Ze(f.join(`\n`))});continue}let c=Mt.exec(a),u=Ot.exec(a);if(c||u){let f=!c,h=f?Ot:Mt,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(Pt(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=>Ze(m.join(`\n`)))});continue}if(a.includes("|")&&n+1<t.length&&Hr.test(t[n+1])&&t[n+1].includes("-")){let f=At(a),h=At(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=At(t[n++]);d.push(f.map((p,g)=>q(m[g]??"")))}s.push({t:"table",align:f.map((m,p)=>h[p]??""),head:f.map(q),rows:d});continue}let l=[];for(;n<t.length&&t[n].trim()&&!Pt(t[n])&&!(l.length&&/^ {0,3}(=+|-+)\\s*$/.test(t[n]));)l.push(t[n++].replace(/^ +/,""));if(l.length===0){s.push({t:"p",c:q(a.trim())}),n++;continue}s.push({t:"p",c:q(l.join(`\n`))})}return s}function V(e,t){return t.map(s=>{switch(s.t){case"text":return s.v;case"code":return i`<code>${s.v}</code>`;case"b":return i`<strong>${V(e,s.c)}</strong>`;case"i":return i`<em>${V(e,s.c)}</em>`;case"br":return i`<br />`;case"a":{let n=yn(s.href);return n?i`<a href=${n} target="_blank" rel="noopener noreferrer">${V(e,s.c)}</a>`:V(e,s.c)}case"img":{let n=wn(s.src);return n?ve(e(n),s.alt||n,"mdimg"):i`<span class="dim">[image not shown: ${s.alt||s.src}]</span>`}}})}function et(e,t){return t.map(s=>{switch(s.t){case"h":{let n=V(e,s.c);return s.level===1?i`<h1>${n}</h1>`:s.level===2?i`<h2>${n}</h2>`:s.level===3?i`<h3>${n}</h3>`:i`<h4>${n}</h4>`}case"p":return i`<p>${V(e,s.c)}</p>`;case"code":return i`<pre class="mdcode"><code>${s.v}</code></pre>`;case"hr":return i`<hr />`;case"quote":return i`<blockquote>${et(e,s.c)}</blockquote>`;case"list":{let n=s.items.map(a=>i`<li>${et(e,a)}</li>`);return s.ordered?i`<ol start=${s.start}>${n}</ol>`:i`<ul>${n}</ul>`}case"table":return i`<div class="mdtable"><table><thead><tr>${s.head.map((n,a)=>i`<th style=${s.align[a]?"text-align:"+s.align[a]:void 0}>${V(e,n)}</th>`)}</tr></thead><tbody>${s.rows.map(n=>i`<tr>${n.map((a,r)=>i`<td style=${s.align[r]?"text-align:"+s.align[r]:void 0}>${V(e,a)}</td>`)}</tr>`)}</tbody></table></div>`}})}var we=new Map;function Cn(e){let t=we.get(e);return t||(t=Ze(e),we.set(e,t),we.size>8&&we.delete(we.keys().next().value)),t}function jr({r:e,text:t}){let s=t?.text!==void 0?et(n=>vt(e.key,n),Cn(t.text)):t?.error?i`<div class="bad">${t.error}</div>`:i`<div class="dim">loading\u2026</div>`;return i`<div class="mdpage" data-report=${e.key}>${s}</div>`}function xn({text:e,fileUrl:t}){return i`<div class="mdpage">${et(t,Cn(e))}</div>`}function Et(e){let t=fe(e);return[t&&t+" \\xB7 ",v(e.filedAt)," ago",e.acked&&[" \\xB7 ",i`<span class="ok">acked</span>`]]}function Tn({r:e,text:t,heading:s}){return[s&&i`<div class="sec">report \xB7 ${e.title}</div>`,i`<div class="sub">${Et(e)}</div>`,i`<${jr} r=${e} text=${t} />`,e.attachments.length>0&&[i`<div class="sec">report attachments (${e.attachments.length})</div>`,ae(e.attachments,n=>vt(e.key,n))],!e.acked&&[i`<div class="sec">ack</div>`,T("lobstah attention ack "+e.key)]]}var Ur=/\\.(png|jpe?g|gif|webp)$/i,Br=e=>{e.style.height="auto",e.style.height=e.scrollHeight+"px"};function qr(e,t){return t.length?i`<div class="dfiles">${t.map(s=>Ur.test(s.name)?i`<span key=${s.name}>${ve(ht(e,s.name),s.name,"dimg")}</span>`:i`<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 Vr(e,t,s){let n=e.key,a=e.kind==="decision"?e.options:[],r=t?.text??"",o=t?.files??[],c=!!t?.sending;return[a.length>0&&i`<div class="doptions">${a.map(u=>i`<button key=${u} type="button" class=${"btn dopt"+(t?.option===u?" on":"")} aria-pressed=${t?.option===u?"true":"false"} disabled=${c} onClick=${()=>Es(n,u)}>${u}</button>`)}</div>`,i`<textarea\n class="danswer"\n rows="2"\n placeholder=${a.length?"Add to your answer, or answer in your own words":"Your answer"}\n value=${r}\n disabled=${c}\n onInput=${u=>{let l=u.currentTarget;Br(l),R(n,{text:l.value,error:void 0})}}\n onPaste=${u=>{Ls(n,u)}}\n ></textarea>`,i`<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;yt(n,l.files).then(()=>{l.value=""})}} /></label>\n ${o.map((u,l)=>i`<span key=${u.name+l} class="dchip">${u.name}<button type="button" class="dx" title="remove" disabled=${c} onClick=${()=>Ns(n,l)}>\xD7</button></span>`)}\n ${t?.error&&i`<span class="bad derr">${t.error}</span>`}\n <button type="button" class="btn dsend" disabled=${c} onClick=${()=>{Hs(n)}}>${c?"Sending\\u2026":"Send"}</button>\n </div>`]}function Fr(e,t,s,n){let a=e.dispatch,r=e.lane??"work",c=[a&&i`<a class="dlink" href="#" onClick=${l=>{l.preventDefault(),k("dispatch",r+":"+a)()}}>${a.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 i`<div key=${e.key} class=${u} data-decision=${e.key}>\n <div class="dtop">\n ${e.kind==="question"&&i`<span class=${"badge "+(e.verb==="blocked"?"bad":"warn")}>${e.verb}</span>`}\n <b class="dtitle">${e.kind==="decision"?e.title:I(e.note)}</b>\n <span class="dmeta dim">${c}</span>\n </div>\n ${e.kind==="decision"&&e.detail.trim()&&i`<${xn} text=${e.detail} fileUrl=${l=>ht(e.key,l)} />`}\n ${e.kind==="decision"&&qr(e.key,e.attachments)}\n ${t?.sent?i`<div class="danswered ok">answered \xB7 ${t.sent}</div>`:Vr(e,t,n)}\n </div>`}function In({cards:e,drafts:t,focus:s,extensions:n}){let a=n.join(","),r=e.length?i`<div class="dcards">${e.map(o=>Fr(o,t[o.key],o.key===s,a))}</div>`:i`<div class="empty">none</div>`;return i`<section class="decisions"><h2>decisions</h2>${r}</section>`}function Jr(e,t){let s=e.badge&&i`<span class=${"badge "+(e.badge.tone||"dim")+j(e.badge.text)} title=${H(e.badge.text)}>${e.badge.text}</span>`;if(e.href){let n=(t==="cards"?"card":"deckline click")+(e.acked?" acked":"");return t==="cards"?i`<a key=${e.key} class=${n} href=${e.href} target="_blank" rel="noopener"><div class="top"><b>${e.title}</b>${s}</div>${e.meta&&i`<div class="meta" title=${e.metaText}>${e.meta}</div>`}</a>`:i`<a key=${e.key} class=${n} href=${e.href} target="_blank" rel="noopener">${s&&[s," "]}<b>${e.title}</b>${e.meta&&[" ",i`<span class="dim">\xB7 ${e.meta}</span>`]}</a>`}return t==="cards"?i`<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&&i`<div class="meta" title=${e.metaText}>${e.meta}</div>`}${e.extra}${e.action&&i`<div class="foot"><span class="footact">${e.action}</span></div>`}</div>`:i`<div key=${e.key} class=${"deckline"+(e.open?" click":"")+(e.acked?" acked":"")} onClick=${e.open}>${s&&[s," "]}<b>${e.title}</b>${e.meta&&[" ",i`<span class="dim">\xB7 ${e.meta}</span>`]}${e.action&&[" ",i`<span class="dim">\xB7 </span>`,e.action]}${e.extra}</div>`}var Rn=(e,t)=>e>0&&i`<a class="deckmore" href=${"#"+t}>+${e} more \u2192</a>`;function tt(e,t,s,n,a,r){let o=t.slice(0,n),c=o.map(l=>Jr(l,a)),u=o.length?a==="cards"?i`<div class="cards">${c}</div>`:c:i`<div class="empty">none</div>`;return i`<section><h2><a href=${"#"+s}>${e} \u2192</a></h2>${r&&i`<div class="tabhead">${r}</div>`}${u}${Rn(t.length-o.length,s)}</section>`}function Qr(e,t,s,n){let a=t.find(l=>l.number===e.nextNumber)||t[0],r=le(e.numbers,new Map(t.map(l=>[l.number,l.title]))),o=a?"next #"+a.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=>i`<span class=${"badge "+(Ct[g.kind]||"dim")}>${hn(g.kind)}</span>`):i`<span class=${"badge "+O(f.badge)+j(f.badge.text)} title=${H(f.badge.text)}>${f.badge.text}</span>`,p=`${f.repo} \\xB7 ${f.badge.text}${d?" \\xB7 acked":""}`;return i`<div key=${f.key} class=${"card"+(d?" acked":"")} onClick=${k("pr",f.key)}><div class="top">${ze(f)}${m}</div><div class="meta" title=${p}>${p}</div></div>`};return i`<div key=${e.id} class="deckstack"><div class="dim">${r} \xB7 ${o}</div><div class="cards">${t.map(l)}</div></div>`}let c=t.flatMap(l=>(s.get(l.key)||[]).map(f=>i`<span class=${"badge "+(Ct[f.kind]||O(l.badge))+(f.acked?" acked":"")}>#${l.number} ${l.badge.text}</span>`)),u=c.flatMap((l,f)=>f?[" ",l]:[l]);return i`<div key=${e.id} class=${"deckline"+(a?" click":"")} onClick=${a&&k("pr",a.key)}><b>${r}</b> <span class="dim">\xB7 ${o}</span>${c.length>0&&[" \\xB7 ",u]}</div>`}function Yr(e,t){let s=e.stacks.slice(0,3),n=new Map;for(let r of e.prAttention){let o=n.get(r.key)||[];o.push(r),n.set(r.key,o)}let a=s.length?s.map(r=>Qr(r,e.prs.filter(o=>o.stackId===r.id).sort((o,c)=>o.position-c.position),n,t)):i`<div class="empty">none</div>`;return i`<section><h2><a href="#prs">PRs \u2192</a></h2>${a}${Rn(e.stacks.length-s.length,"prs")}</section>`}function An({inp:e,drafts:t,focus:s,extensions:n}){let a=e.view,r=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:[I(l.note||"",90),l.verbAt&&[" \\xB7 ",v(l.verbAt)," ago"],(l.for||l.claimedBy)&&[" \\xB7 ",qe(l.for||l.claimedBy)]],metaText:[U(l.note||""),l.verbAt&&`${K(l.verbAt)} ago`,U(l.for||l.claimedBy||"")].filter(Boolean).join(" \\xB7 "),open:k("dispatch",l.lane+":"+l.id)})),o=e.landed.map(l=>({key:l.key,title:[l.id.slice(0,8)," ",l.repo||"",l.unreported&&[" ",i`<span class="badge warn unreported">unreported</span>`]],badge:{text:l.verb,tone:l.verb==="failed"?"bad":"ok"},meta:[I(l.note||"",90)," \\xB7 ",v(l.at)," ago"],metaText:`${U(l.note||"")} \\xB7 ${K(l.at)} ago`,open:k("dispatch",l.lane+":"+l.id)})),c=e.reports.map(l=>{let f=Rt(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 ",i`<span class="catchn" title="catches">\u{1F99E} ${Z(l.totalCatches??0)}</span>`," \\xB7 ",ye(l)],metaText:`${l.repo||""} \\xB7 \\u{1F99E} ${Z(l.totalCatches??0)} \\xB7 ${Ye(l)}`,action:z(l),extra:J(l),open:k("trap",l.trapId)}));return i`<div class="deckgrid"><${In} cards=${e.decisions} drafts=${t} focus=${s} extensions=${n} />${tt("in flight",r,"dispatches",4,a)}${tt("Landed \\xB7 24h",o,"dispatches",8,a)}${tt("reports",c,"reports",8,a)}${tt("traps",u,"traps",8,a,i`<${Qe} />`)}${Yr(e,a)}</div>`}function Xr(e,t){if(!t)return e;let s=new Map(e.map(r=>[r.id,r])),n=r=>{let o=r,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},a=new Map;for(let r of e){let o=n(r),c=a.get(o)||[];c.push(r),a.set(o,c)}return[...a.values()].sort((r,o)=>o[0].sort-r[0].sort).flatMap(r=>r.sort((o,c)=>o.id===n(o)?-1:c.id===n(c)?1:o.sort-c.sort))}function Zr(e,t){let s=e.lane+":"+e.id;return i`<tr key=${s} class="rowhead" onClick=${k("dispatch",s)}><td>${t&&e.followUp&&i`<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">${I(e.note??"",90)}${Fe(e)}${Ve(e)}</td><td>${v(e.verbAt)}</td><td>${$e(e)}</td><td>${ie(e)}</td></tr>`}function ea(e){let t=e.lane+":"+e.id;return i`<div key=${t} class="card" onClick=${k("dispatch",t)}><div class="top"><b>${e.id.slice(0,8)}</b><span class=${"badge v-"+e.verb+j(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&&i`<div class="note" title=${U(e.note)}>${I(e.note)}</div>`}${Fe(e)}${Ve(e)}<div class="foot">${$e(e)} ${ie(e)}</div></div>`}function Pn({inp:e,more:t}){let s=e.list,n=t&&i`<${oe} kind="dispatches" more=${t} />`;return e.view==="cards"?[s.length?i`<div class="cards">${s.map(ea)}</div>`:i`<div class="empty">no dispatches match</div>`,n]:[A(["id","lane / bucket","repo","verb","note","age","addressed","pr"],Xr(s,e.chain).map(a=>Zr(a,e.chain)),"no dispatches match"),n]}var ta={deck:"On deck",dispatches:"Dispatches",traps:"Traps",prs:"PRs",reports:"Reports",notices:"Notices"},sa=["working","needs-decision","blocked","paused","done","failed","unknown"];function na(e,t){let s=t.daemonStale,n=e.daemon?[i`<span class=${s?"bad":"ok"}>${s&&"stale "}${v(e.daemon.heartbeat)} ago</span>`," ",i`<span class="dim">v${e.daemon.version}</span>`]:i`<span class="bad">down</span>`;return[i`<span class="chip">daemon ${n}</span>`,t.stats&&i`<span class="chip" title="catches today">\u{1F99E} ${t.stats.catchesToday} today</span>`,e.slots&&i`<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:a,stale:r})=>i`<span key=${a.grounds} class="chip click" onClick=${k("helm",a.grounds)}>\u26F5 <b>${a.man}</b> <span class="dim">helm ${a.grounds}</span> <span class=${r?"warn":"ok"}>${r&&"stale "}${v(a.heartbeatAt)} ago</span></span>`)]}var Lt=[];function ra(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!==Lt.length&&(Lt=t),Lt}var Nt=[];function aa(e){let t=[...new Set(e.notices.map(s=>s.kind))].sort();return t.length!==Nt.length&&(Nt=t),Nt}var Ge=e=>e.currentTarget.value;function oa(e,t,s){let n=o=>t===o?"":"display:none",a=e?ra(e):[],r=e?aa(e):[];return i`<div class="controls">\n <select id="f-lane" style=${e&&n("dispatches")} value=${s.lane} onChange=${o=>N({lane:Ge(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=>N({repo:Ge(o)})}>\n <option value="">all repos</option>\n ${a.map(o=>i`<option key=${o}>${o}</option>`)}\n </select>\n <select id="f-verb" style=${e&&n("dispatches")} value=${s.verb} onChange=${o=>N({verb:Ge(o)})}>\n <option value="">all verbs</option>\n ${sa.map(o=>i`<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=>N({chain:o.currentTarget.checked})} /> group by chain</label>\n <select id="f-kind" style=${e&&n("notices")} value=${s.noticeKind} onChange=${o=>N({noticeKind:Ge(o)})}>\n <option value="">all notice kinds</option>\n ${r.map(o=>i`<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=>N({q:Ge(o)})} />\n </div>`}function Mn({d:e,inp:t,tab:s,st:n,stale:a}){return[i`<div class="headerline"><h1>\u{1F99E}\u2728 spyglass<span id="stale" style=${e||a?a?"display:inline":"display:none":void 0}> \xB7 STALE FEED</span></h1><span id="settings-slot"><button id="gearbtn" title="settings" aria-label="settings" onClick=${()=>E("settings","browser")}>\u2699</button></span></div>`,i`<div class="chips"><span id="chips" style="display:contents">${e&&t&&na(e,t.chips)}</span><span class="chip dim" id="clock">${e&&new Date(e.now).toLocaleTimeString("en-GB")}</span></div>`,i`<nav class="tabs" id="tabs" aria-label="Spyglass views">${ee.map(r=>i`<a href=${"#"+r} data-tab=${r} class=${e?r===s?"on":"":void 0}>${ta[r]}</a>`)}</nav>`,oa(e,s,n)]}var On=({d:e})=>e&&["\\u{1F99E}\\u2728 lobstah v"+e.version+" \\xB7 ",i`<a href=${e.repoUrl} target="_blank">${e.repoUrl.replace("https://github.com/","")}</a>`];function En(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??{},a=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:ft(o.key),...u}:(o.kind??"question")==="question"&&o.key?{key:"question:"+o.key,text:o.note||o.verb,label:c,hash:ft(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}});!a.length&&t.preview&&(a=[{key:"preview",text:"attention questions crawl in here",...t.previewHelm?{open:{type:"helm",key:t.previewHelm}}:{}}]);let r=a.length>4?a.length-4:0;return a=a.slice(0,4),r&&(a[3]={...a[3],text:"\\u2026and "+r+" more \\u2014 see attention",label:""}),a}var Ln="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAA4CAYAAABdcSXCAAAVF0lEQVR4nO2d34sc15XHb/fUaGRpsIwky0qbRCiyIZh1NjEKxDixTUge8up9ccKSZSHZf8BP0R/gffI/kCwsLEvWL/FrHmKM88PEYOHsJiYIFGWwQjq2rBk8xpI1mp7p5XOrvj2n71R1V1VXz3RP3yOaaXV1Vd/7rXO/95xzzz3lXJS5kVe++3w/732UKGUk6k8EqDFFeu07l/uRhOIAqyNRfyJAE0uczeIAm0Si/kSAGlWmaA3FAVZXov6UAOjlr/1Df5GUoKpSRCUajU3Un9nUn/Y8DLCXfvFma+Xs2YUMvFbByB1hifpTT6L+jCGgqrO8W0Api9NRtoKi/tSXqD8RoANVIrdgEgfY/OrPgblg49yHrdu3x3b+qLsZZfo+DiNwXDSJ+jO/+jMTBIRceee9UgAtspQh4EWNlUX9mU/9mRkCqmLhLOIAq9L/i71PF3IFKerP7OnPXBGQZNEJZtJBtpasNvqbX3rouCPzel6IKOrPbOnPXBHQIsd5DlsgmHCLBzGBy50T/gURzfrgjvozXzJzBHRYMm9L2E23FfL51qUz7tnLj+871t1quePLieucOdnkTx4pWXT9OXIENE2AipQF33dWbkyZVZ8myQfr5rGLHffnte6+lZDOSt/d2+65Sw8uu2dO9ecCo6g/B6c/Ve5B+Fl7kQBSQJVBFA4kuRqQ0DzEOlitaJJ8sHy2Nzdyj2H9WDKa9aX+qD8Hpz95gt4wtsIxxnvGF27+TBPQNAACFAbO97/8iJ/pu+t3huIFDDTkqS+cGryfddHNDS26qnEQ63adP5mSja4HHq1225PQZ1v33bxI1J+D0x87xuTK/8tXPrfvWprk9d2ZJqCmAYJU/u3bT7qVlcTd7f7NXfv43uCYwGCQnVxq+VjHrLoZwoKZhNfbLz7n3zPb8F7fKWvFoSySfq/n8eEzlEVEvO36rtdO40DIPASjkag/09ef0FpmjDHBf3rrlnvjxvrQcf6iQ1rQQPZs6xlTGuUieHOt96knBQDqrqdxGgaIks/GCZ3XLL995zOXrCwPWTm8Z6a/t73tj2EFbN340M2SqM+y4n7eXfVKw81+7OLe9x7L/v766l48q4iwrZLJ/Vo+ddp1r1/3mIB5u7fter1UcZAHVo455+7O7GpT1J+D0x8rcuOR3Y8YO/tPYWIjligd4vrJrAGE/FNnyb170/kBAEBWAOvZDCAGEKb2OIA0y99fv+UJppUkQ7/J7zDz95ecS3b7rseImyHRjPXst58cfPbMna53I63yWEEZnrp1y717c9PjNI6ssX7ABYzAAxI+0UqDzwgWENhgDc2iRP05PP0ZmuCZyI4tO7fVG7ovjMEvri4N9IkJf627MxsumADCfMN3XD13zn8OQP31j/yg4AWz0kFedBgmHxc05pjiGhJmeURuxhceTNzS/e2h70ziZjTlntiguY3TyFrBlBUeeoEXOPE6tuTc04+f8Te/qE1grOtBQsiF08c9+Vi3C/JBeZZzZrbDlqg/h6c/oUiHmNAxDjTG0CkrH9zp+WO1tInGNGGCW3aUpQMANtiZmmt70t/dHbwnONpLltz7G/fcW5utXEuIG/CvX3vUEwwDill+a6vnmZ2ZHvLpbaWuF4OMa97Z6buf/eHDkS6erC/aLytMfrCySSfBSNhAsiJkBCVJejtjzxdO6nMeRgoYohxyTRFvBbZbg/cI5AMZ/eXTHe/bl3V/i/oW9We+9Od319dz22R1SOQjfWNyE9FpIpMl/dv3P/Fx2PY49rQBYGXKNrFUbQES+RAcpuOQjl6hQBB68V2Ihc6Pyk+BcGT6KdAKs3Me5OOByf6WbTuKgrWG1WY/47rMNpPkFAkbri3l0QxVRnmscLOFUdgmSARSkkUokZLovSwhMJRSlelD1J+joT9Jb8e3izFWdtyTroGb9Y0LD/r/a/ztu35RB3yA6ispOL++en1g5tIQFLaz1nWvnK03k1mARDwoeJ61A9HkiY4Rk0iyAdZdX983uzK7QDjbvT2CkbvlB1o260NAewGy/PbqeohMWqL9YIVVcPmJ0/7a3Gj5uHUFqw3hWr69x5YrKY8Imj7KbcLiW9vM/z795vsDRcksQns9MqKZtcZZP1F/jpr+OH8upJInGBCMYY0lJnm9v5fFghBZ1XZMJ0UAySrBF0Rxr924PQSQj6ts1gMoj3ys2acGFpGPhO8v852sY2pnKBDm0v0PXS8AYojlsxkewT2TaBZSIPut7BAZw2DEKhERf5nOnsTabfe+93H3liHLCjMMQfhBnGqr5060UtLsG8UowkfErL+tZMnd2LjnLpxeypII97eJvkDgS/f33FsIuWfIiV/H+skjn6g/i6A/x93uTkoqVuALSNQlexO5yAfR2KZfHOP/29nPokttWTYAxIv3EAQXhWgEKgChiAxeOkMQqY4AEG6XyM1m2VoQbKwnPBbGgG58klo0RQxNX3aYAVAUM6vb6yC0hWvZWR4sMJXT5cqO+/7FFY+Rgrd+j9RKf8jPpY0cr5oMJzPc+uzkJYWELBe0CKuB/54suf9852/u66/+yv1sbcstn3xgX3AdaxE3DB9fFiAv+qIXmLy9tule+OXVXPKJ+rMY+rOykuQuzsAF/KYIJi+cob7xuzc/6Q3y8NoAhDkIOCyT4WLxI2Jx2Az2wyT0jcouXjYWEAIEyVmALBj2/5aprdjPLUD8zRtg4YwkJvZ9ywiJuYHrcswmT+URGealsjkxSz2xrSz73+Z83hOoBeCq7qnuhSTcGoH8Zu1j99Pff+D/Cg/Ezmp6EQi88s57kD5t8bMibQ+3UtBO2vvff9rw12URgD7w+o//SxPK8sjHtjnqz2LoTyfYkEwbLZlqscJO9Bgt+hyCtosYQzYYXxJA+iHlzPg4iusPVkLqAiTXjmX10ATkZvzXX3seIBoqsglZOgTISh5AtJUZnnMU41HMR32kb1e7d/2sY90M/o+5LAw4bzdZdt+8+JAnQIvRic6jHvg65KzVBCvy2WUOszr3wi+v+j7TJ35/YCobrPgewsTxynef999/7TuX/Wfcv3CriWbOf34iNdshIpREilJ2xSvqz9HXn25O28LxhR7YiZ4YJASbt4LatgAhOomdz2HQCqDu9lu1zEMLEK6XzScRCPirMC0dtjNJaBFZgGBnhPYUBdk4BkiwPucCxiBItt3zRIaLkbfMKBfFA3nqtFce8iOUkAfwejHDaXmxyjK1LDaRs/IxbP99P1aSQX8tadMvCLv98CP+JpNCQD/B4wefT9ztH3/PW7Zck2uFW020R4cBIAIvSzxRfxZLf/KEyUvjC1KzLjzWD30Fo7z0jQSAWFo/f/KWW+086i0TxLsl2fo/F9d2BdyZqjkKClICkF8ODFabrCUEQNaq4RgdU1Y0ZElHiPIDEH+JKQGuKyAgfO7OpTOeOAHXWgDyRUfd8HR3dZqjAQbHzpwbrA5y/rfMtdMZMN9dGSWKiyGjVit8UtjZ5/3KiZR6LdlyL7z6pp+tFLj0md1Krlz/yK82aFXDz2JZ1Tu74x0FKwo0j8Im6s9i6M92ThY8+sPYFDfAFwifyVoSf+Rh5G0//PtUETf9hRSjKQKoztK7ACLhrSjwfHKpPQSQLCMIj9UtZhIBBMhpHlB63rZPgmoVAgR5XTi94a69k25ErdoPwINI/dJo9++DvWr0i6zhxy4+7lMTtMpRRbjW6jm7j6ZghaLX81bfBZO2w/eZpZ558Tn3RrYCCCkrKcyKksoQPYVEqRWoLLOU3aRbVqL+LIj+bKUB9pWzq0N77vCWWmcedu7m5kB/GLNbJSb31qiNfAjKyaoX5hmEVCdDkxlS9WZEQKOWAMP/Y9ZZS0xtCoNospZU01Zp4CRDYWrqGpNk8Ya5Lsoixq1jNvnJ63+sbD6rdIEUogw2eYISKPBYNAuGWIIN1w2Dg3Uk6s/R1p/frH08mLzhCIwVVtmQuvozZIpYYhFAiN8DlO2/uvb6H6tc31/nqU4abCtDPmE0HoFsCNo9e+Zh7yZgGo4CU6s82uIBqJrdmyAfCVYh7L9EYH7jnnMb3cFjTcqSdNrWz+0ljRUoi83NKBKw0Q3N+64vq3HnM/8e8gFTVrwIvjeBTdSfo60/0pvL53bd8WUm9TTsoUm/jv60xwEkJmQAE3+pukkzNQ9Tl07kU5Tjk7csr884B3YvAkaWEkIbf/TV8/7mkujIjI/71iT5SBjABA5hf/ASaZeRMK0dos3rfxMCNvd3nCcbBLcUxWHFq67yjJOoP0dHf8IVZoLVjCtWrCfZtza2HIdmyDoCQMyslM/QCgxSRCCjpAyorKIpZoVJyA2tE++pIgxgER6DHDM6rakyvhYP7YQYcW2xRvLcT/v/KhLmdyQ9536X+ei016/MeOKpHvCsIlF/5lt/wmuhP4PH9jSgP4UnK0BpV8CIjAOQVqJGDWwLENcBoGmJjf+IcCTTLJylPmJp4d5gYWDtCR+kKF1BxaBQHiTEp8jSG5VGnyf6Pm40yj4NSydPov6Ml5ej/hRbQCoPYLfaE8NxLtsHZlZSRg2wbjbAqkiZgJn9LhKmwB+UgIWPrZA/lSwPrRyKYGS6ioxttqpdrhy3L8fOYvxmldo8SrI8KIn6c/T0ZxqSlAEI8lGColZQQoDk7tjSjLhdOoZ5KR+1iGTGmYmjiKlOcuSkwu+xD4aaQsS3fvv+5j5sbILYW//79yE/Gnw4t7ueJleyHBtKnvIgZMzyTxtrpUzh97TClZLzdN2tPIn6c5T0573G9addBiByR8gc1moJKftYRRYgSMcm+Km2DwApPqMOqpOjCMduwdAr3JrBi+X1ultDmhCID9dLbQAb9tT5HcJZGkO4OueD6VlWqfJySOLKi5H5ejzJ0kBRBttHsu9oP5vwsDv9+Q4xmEmX1+tK1J/x0l1w/UnKAASJaAcrAJHFfCcjFGJDqmIo9gYgZTqznV8AEeeQ6SfysdmVtjF5rJ3HzhBb1ezdpgTC8y5ottk13WrS37cBFjx049n5bBVEq4xg982c2E5Yo5p8kVZvx89KKGoodhOgAsDWMrSlMxBV5ZsWflF/iuWlqD+jCUh+fOeT1I2yD6nTABtK2c7E7/DNBpYdYE8T5c9JcILFlXnJubhqDDCIL698hh1g73bv7kXlC2rTTHOAIcr+1C7nkGA+y3YCgx9FvS6tDJ/PeVyD/qj2DjWOwtKovH/7+ron8tTvP+kD4JynkrKSdOPfxmChQLhoW4o17f+81vfF5ZrGKepPObm2wPoz1gKiAUrRxvpJ0/nTmRd/FLJgdmeTHQDZAvC+WuFufwAQuURaMbI/7CuoZQDd3LiX+bXFAO1l7hYDhIuookwA9NpDl31KQNNEpN9W9jiKgj8ua1FWG8RqM06VMq8aPGCHtfL04w84/xycnMJpEDXX/cbursce07jzxOm0DEJWQIxrgVd3/e4QCYRPRbCCIr1RMcG0rET9GS0vLbj+jF1qogEoER3E/Lf5Nlb8ZtCsOBEi4Ng9rzo9CkbbWsMDcHz1tcSDgk8sgLgZtsgRN4LPFHS2AFFlUbVpIB+llYeP9mlaaANWGLMT/bDF2kTOVuS/q0aK9fV9WYPMr0fAAhFW4EjiGn3iPUvr9joQM4qo5EIVzw/rxKjgHCkDpP+HZSSaxCbqz3iM1hZUf9pVAMKCoXMCCGvH1lW2ZqOtB4KFI4B0jVAUC1IxNAHEBlgBpNIZdke+fbY5AjAEwH2N2t6O/wtA08r2tRhBmEqAlLlMu1md8DV1sxXBMJYlUvYlZTNLkTiZLZwmXFUYjn7JZEdhMJn5q+JhmllV/JwqB5yjoljs4VGJhLx8LhWUbwqbqD9Rf/KkdM62Ld05ONkUes/LSVDtExGOrBoNMLFzeA0GIQOl7ACDfEQ6DHYVuIcMYPi8ARY+7rkJgeBon6xDAs4qziTS0TGRqmYmSAHXk/5wDcxgjvsnk2bfEUlzDeVlYKbzf/1umIoQVrLkeuAuogyx0dMswqJlk0rUn/FyZQH1p9KTUWVxKN8HghnM0tl3OPbUTt8dC6wilQL40noK0PkvP+JnYdwpSCoEUatmlCvAChI4lAIIAbKlJ2WyfpDtzs0DyPvbWZZ30yKzlWtDpop54WN3suAhZPrF1VR5bAAeLPUYE4jT1zk6+YBPAKVP3PwTy4lXGo4PbRDsnPAWlx5drWPKzNZvI1yH+FmG2OAZZz5+dqrvLn3+fJr7kVPgfxKJ+jNeriyY/tRyScRwAKQsaRERHbPbEwQQrEnDcdeoHgfAKiRmAeI43w0Lh6ng0aDWSPZAN9wLLB8J59MW5SxZsW0uqtDWlNjSFEoeY9kc/xtRSU7iaaElCRbqq9pLsB/FQ2yhJ0R4I0r4VGW9H/7juX3PZFJA3z/na6s1VNBf6RNNlOcokqg/4+WVBdGfRmq/0Ek1QKadYj5KQBRIcssgIQuQSEzni2TCshoiMwAWieXdAD4TOAJIz4VPTAmBaScv2rQAESAKoH5TTF/Pzeam8znvCd7bXCJJuLn27Ref6+Maaxc1/STorydTQtx6zLIemTLuIYycj6tdVIi+CYn6Ux6no6w/rWkDRENkSqq0Ku/1SGVYUpaO9UEF0O0ff69v98MQ+MZqEkC+Vm1mgiqmZAnJPniwDkBNSvg4nLCsgp0tyn5WdB8kKJAsSxVEFz55yqSHDhQ96rppifozv/qjhaFJ9KdSDChPwviKN2ySVWrMDnX8jZIAhclMZ//9f1qjAJJoMx8SunM22u4B2jAlBQ5Qpjmgw/ug9507xN7SOAAiXOwDGTW7Ienjl+8OakZPW6L+zK/+QD3HJ9SfZFqdODCAsqc2uq3tXMtHAW7tZjjoAVZHRs1UVbACJ/n7BC01Ww2sHrNQoAQ0BScPY+Nq1J/mg9m8qupRWf3xVlG2wlZXf6ZTOi0QATDqwfZVBh0ACST/ULScQveha6HgmJKsDmPj6kGL8m9wcxWABAcfRLSZ5Un6wLi856IdtlTRizJ6hkT9mR39ORACmjZAsC4A6QmTei4RAJFvZAGadfKZ1PoJhb6qMBz9BwfImc3FYMZiAPEwiHzWsWlajqL+1CHkw9SfRl2wuibhJINOCYnsV1MQ3Ep3PV229DGfOVKePKlLSl9/9VctG6PTo42QMOg/S1JHL6q6HkdBf65M2WKdpv60Dkuhit5Pcv3waZ+zPsCijJa6elH3vKg/UaJEieIWR/4fY2sZ1Lh7NyEAAAAASUVORK5CYII=";var Nn="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAA2UlEQVR4nGNgwAPeHo35D8K45JnwaRQS/YXPbAacmkEa/3z/BaZx2c6Ey1YGIgAjLsV8PF/g7E9feMC0sPUSRhTNuPwGcjI28AlqENzZIIUw/O41G8O58z/BkiycbGDFl278R3GRENQyJpBTkE1DtgFkyIMnn+EGwQDIApA+uB9AzgeZCtIEMhlmu54GI1gMFgafvvDA/Y4SADADYABkG7LfPyFpxIgq9IBD1ojsbAZ0zYTiFlvoY00ksFAGYWw2wtWhC4BD/gsiQUBcxAbxEiI4MAE+p2PLYQAGj4EmRoa2cwAAAABJRU5ErkJggg==";var Hn=()=>i`<span class="pet-art" aria-hidden="true"><div class="sprite" style=${{backgroundImage:`url(${Ln})`}}></div><img class="star" src=${Nn} alt="" /></span>`;function ca(e,t){let s="animation-duration:"+((innerWidth+180)/(100+t*12)).toFixed(1)+"s;animation-delay:-"+t*9%14+"s",n=()=>{e.hideKey&&Ws(e.hideKey,e.hideHash??"")},a=[i`<div class="bub">${e.label&&[i`<span class="badge dim">${e.label}</span>`," "]}<span>${e.text.length>48?e.text.slice(0,47)+"\\u2026":e.text}</span></div>`,i`<${Hn} />`],r=e.open;return e.hash?i`<a key=${e.key} class="lob" style=${s} title="open the decision" href=${e.hash} onClick=${n}>${a}</a>`:e.href?i`<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=${n}>${a}</a>`:i`<div\n key=${e.key}\n class="lob"\n style=${s}\n title="click to open"\n onClick=${()=>{n(),r&&E(r.type,r.key)}}\n >\n ${a}\n </div>`}function jn({state:e}){let t=e.snapshot,s=En(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(a=>a.key).join("|");return cn(()=>s.map((a,r)=>ca(a,r)),[n])}function st({box:e}){if(!e)return null;let t=s=>{s.target===s.currentTarget&&se()};return i`<div id="lightbox" class="lightbox" role="dialog" aria-label=${e.name} onClick=${t}>\n <button type="button" class="lbclose" title="close" onClick=${se}>\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 ce=i`<span class="x" onClick=${ne}>\xD7</span>`,Un=(e,t,s)=>i`<span class="seg">${t.map(([n,a])=>i`<button class=${n===s?"on":""} onClick=${()=>e(n)}>${a}</button>`)}</span>`;function da(e,t){let s=Un(Vs,[["table","table"],["cards","cards"]],t.view),n=Un(Fs,[["on","on"],["off","off"]],t.lobs?"on":"off"),a=e.attentionError?e.attentionError:(e.attentionKinds||[]).join(" \\xB7 ");return[ce,i`<h3>\u2699 settings <span class="dim" style="font-weight:normal">\xB7 this browser only</span></h3>`,i`<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">${a}</span></div></div>`]}function pa(e,t){let s=le(t.numbers,new Map(t.numbers.map((a,r)=>[a,t.titles[r]])),e.number),n=t.nextMergeable?[" \\xB7 ",i`<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 ua=e=>t=>{t.preventDefault(),E("dispatch",e)};function fa(e,t){let s=Ds(e,t),n=s.pr,a=s.stack,r=s.watch,o=Je(n),c=s.chain.length?s.chain.flatMap((l,f)=>[f?" \\u2192 ":"",l.culled?i`<span class="dim">${l.id.slice(0,8)} (culled)</span>`:[i`<a href="#" onClick=${ua(l.modalKey)}>${l.id.slice(0,8)}</a>`," ",i`<span class="dim">${l.verb}</span>`]]):i`<span class="dim">none</span>`,u=r?[i`<div>${r.key} \xB7 owner ${r.owner||"?"} \xB7 ${r.lastCheckedAt?["checked ",v(r.lastCheckedAt)," ago"]:"never checked"}</div>`,r.lastError&&i`<div class="bad">${r.lastError}</div>`,i`<div class="dim" style="font-size:11px;margin-top:4px">cursor</div>`,T(r.cursor)]:i`<div class="dim">no watch \u2014 <code>lobstah watch add ${n.url}</code> registers one</div>`;return[ce,i`<h3>${Ke(n)} ${n.title||""} <span class=${"badge "+O(n.badge)}>${n.badge.text}</span>${n.draft&&n.badge.text!=="draft"&&[" ",i`<span class="badge pr-draft">draft</span>`]}</h3>`,i`<div class="sub">${n.repo} \xB7 ${n.state} \xB7 observed ${v(n.observedAt)} ago${n.gate&&" \\xB7 gate "+n.gate}</div>`,i`<div class="sec">checks</div><div>${_e(n)}</div><div class="sec">review</div><div>${o||i`<span class="dim">no review yet</span>`}</div><div class="sec">merge</div><div>${be(n)}</div>${n.repairWait&&i`<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>${a?pa(n,a):i`<span class="dim">not stacked</span>`}</div><div class="sec">dispatch chain</div><div>${c}</div><div class="sec">watch</div>`,u]}var Bn=(e,t)=>(e==="codex"?"codex resume ":"claude --resume ")+t;function ma(e){let t=Date.now()-Date.parse(e.heartbeatAt)>18e5;return[ce,i`<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&&[i`<div class="sec">open this session</div>`,T(Bn(e.harness,e.sessionId))],e.transcript&&[i`<div class="sec">transcript</div>`,T(e.transcript)]]}function ha(e){return[i`<div class="sec">report \xB7 ${e.title}</div>`,i`<div class="sub">${Et(e)} \xB7 <a href=${C(e.key)} target="_blank" rel="noopener">open the report \u2197</a></div>`]}function ga(e,t,s){let n=e.claimedBy&&e.claimedBy.startsWith("wt:")?[i`<div class="sec">worked by trap</div>`,i`<div class="claimedby">claimed by ${We(e.claimedBy.slice(3))}</div>`,T(U(e.claimedBy)),i`<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 ${U(e.claimedBy)} "\u2026"</div>`]:[i`<div class="sec">open this session</div>`,T("lobstah attach "+e.id)];return[ce,i`<h3>${e.id.slice(0,8)} <span class=${"badge v-"+e.verb}>${e.verb}</span></h3>`,i`<div class="sub">${e.repo} \xB7 ${e.lane} ${e.bucket} \xB7 ${v(e.verbAt)}${e.for&&[" \\xB7 ",$e(e)]} ${ie(e)}</div>`,n,e.worktree&&[i`<div class="sec">worktree${e.worktreeOf?" (reused from "+e.worktreeOf.slice(0,8)+")":""}</div>`,T(e.worktree),e.worktreeKept&&i`<div class="dim" style="font-size:11px">kept: ${e.worktreeKept}</div>`],e.transcript&&[i`<div class="sec">transcript</div>`,T(e.transcript)],t&&ha(t),mn(e,s)]}function va(e){let t=ke(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=>i`<div key=${o.seq} class="loglines">${v(o.at)} ago \xB7 <b>${o.kind}</b> \u2014 ${o.text}</div>`):i`<div class="empty">none recorded</div>`,a=e.messages.length?e.messages.map(o=>i`<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"?i`<span class="warn">pending</span>`:i`<span class="ok">delivered</span>`}</div>${o.text}${o.attachments?.length?ae(o.attachments,c=>ms(e.trapId,c)):""}</div>`):i`<div class="empty">none</div>`,r=e.catches.length?e.catches.map(o=>i`<div key=${o.lane+":"+o.id} class="catch click" onClick=${k("dispatch",o.lane+":"+o.id)}><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>${ie(o)}</div>${o.note&&i`<div class="loglines">${I(o.note)}</div>`}</div>`):i`<div class="empty">none yet</div>`;return[ce,i`<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&&i`<div class="sub">${e.worktree}</div>`,i`<div class="sub">${s}</div>`,i`<div class="sec">window</div>`,z(e),J(e),e.live&&e.sessionId&&[i`<div class="sec">open this session</div>`,T(Bn(e.harness,e.sessionId)),i`<div class="dim" style="font-size:11px">as registered at sign-on \u2014 a hookless enlistment may hold a made-up id</div>`],i`<div class="sec">lifecycle (${e.notices.length})</div>`,n,i`<div class="sec">messages (${e.messages.length})</div>`,a,i`<div class="sec">catches (${e.catches.length})</div>`,r]}function qn({snapshot:e,modal:t,prefs:s,detail:n=null}){if(!e||!t)return null;let a=te(e,t,n);if(!a&&t.type==="dispatch"&&n?.key===t.key)return[ce,i`<h3>${t.key.slice(t.key.indexOf(":")+1,t.key.indexOf(":")+9)}</h3>`,i`<div class=${n.error?"bad":"dim"}>${n.error??"loading\\u2026"}</div>`];if(!a)return null;if(t.type==="settings")return da(a,s);if(t.type==="pr")return fa(e,t.key);if(t.type==="helm")return ma(a);if(t.type==="dispatch"){let r=vs(e,a);return ga(a,r,n)}return va(a)}var $a=e=>i`<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>`,Vn=({inp:e,more:t})=>[A(["at","kind","text","repo"],e.list.map($a),"no notices"),t&&i`<${oe} kind="notices" more=${t} />`];function Fn(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 Wn=(e,t)=>le(e.numbers,new Map(t.map(s=>[s.number,s.title]))),Ht=e=>e.state+(e.draft?" \\xB7 draft":"")+(e.state==="MERGED"&&e.mergedAt?" \\xB7 "+e.mergedAt:"");function Kn(e){let t=n=>{let a=String(n??"");return a.length>24?a.slice(0,23)+"\\u2026":a},s=e.watches.map(n=>i`<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[i`<h2>other watches</h2>`,A(["key","owner","cursor","last check","error"],s,"no other watches")]}function _a(e,t){let s=Fn(e).flatMap(({s:n,prs:a})=>[i`<tr key=${"stack:"+n.id}><th colspan="8">${Wn(n,a)} \xB7 floor ${n.floor}${n.open?" \\xB7 open":" \\xB7 history"}</th></tr>`,...a.map(r=>i`<tr key=${r.key} class="rowhead" onClick=${k("pr",r.key)}><td>${Ke(r)}</td><td class="grow">${r.title||""}</td><td>${Ht(r)}</td><td>${_e(r)}</td><td>${Je(r)}</td><td>${be(r)}</td><td>${xt(r.watch)}</td><td>${r.gate||""}</td></tr>`)]);return[A(["PR","title","state","checks","review","merge","watch","gate"],s,"no PR evidence"),t,Kn(e)]}function ba(e,t){let s=Fn(e),n=r=>i`<div key=${r.key} class="card" onClick=${k("pr",r.key)}><div class="top">${ze(r)}<span class=${"badge "+O(r.badge)+j(r.badge.text)} title=${H(r.badge.text)}>${r.badge.text}</span></div><div class="meta" title=${`${r.repo} \\xB7 ${Ht(r)}`}>${r.repo} \xB7 ${Ht(r)} \xB7 ${be(r)}</div><div class="foot"><span>${_e(r)}</span><span>${xt(r.watch)}</span>${r.gate&&i`<span>gate ${r.gate}</span>`}</div></div>`;return[s.length?s.map(({s:r,prs:o})=>i`<${X} key=${"stack:"+r.id}><h2>${Wn(r,o)} \xB7 floor ${r.floor}${r.open?"":" \\xB7 history"}</h2><div class="cards">${o.map(n)}</div><//>`):i`<div class="empty">no PR evidence</div>`,t,Kn(e)]}function zn({inp:e,more:t}){let s=t&&i`<${oe} kind="prs" more=${t} />`;return e.view==="cards"?ba(e,s):_a(e,s)}var jt=e=>e.requested?"requested":e.starting?e.starting.failedAt?"start failed":"starting":e.harness??(e.live?"":"signed off"),Jn=e=>e.live||e.starting?"":" dim";function ka(e){let t=ke(e);return i`<tr key=${e.trapId} class=${"rowhead"+Jn(e)} onClick=${k("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>${ye(e)}${J(e)}</td><td>${t.listen}</td><td>${t.hb}</td><td>${It(e)}</td><td class="catchn" title="catches">\u{1F99E} ${Z(e.totalCatches??0)}</td><td>${z(e)}</td></tr>`}function ya(e){let t=ke(e),s=It(e),n=`${e.repo??(e.live?"addressed bait only":"history")}${e.sessionId?" \\xB7 session "+e.sessionId.slice(0,8):""}`;return i`<div key=${e.trapId} class=${"card"+Jn(e)} onClick=${k("trap",e.trapId)}><div class="top"><b>\u{1FAA4} ${e.label??`wt:${e.trapId}`}</b><span class=${"badge"+j(jt(e))} title=${H(jt(e))}>${jt(e)}</span></div><div class="meta" title=${n}>${n}</div>${e.worktree&&i`<div class="note" title=${e.worktree}>${e.worktree}</div>`}<div class="note" title=${Ye(e)}>${ye(e)}</div>${J(e)}<div class="foot"><span>${t.listen}${e.live&&[" \\xB7 heartbeat ",t.hb]} \xB7 <span class="catchn" title="catches">\u{1F99E} ${Z(e.totalCatches??0)}</span>${s&&[" \\xB7 ",s]}</span><span class="footact">${z(e)}</span></div></div>`}function Qn({inp:e}){let t=e.list.map(n=>n.x),s=i`<div class="tabhead"><${Qe} /></div>`;return e.view==="cards"?[s,t.length?i`<div class="cards">${t.map(ya)}</div>`:i`<div class="empty">no traps soaking</div>`]:[s,A(["address","repo","worktree","harness","session","now","listening","heartbeat","mail","catches","window"],t.map(ka),"no traps soaking")]}function Yn({state:e}){let t=ge(e),s=e.route,n=t&&Ss(t,{st:e.prefs,modal:e.modal,detail:e.detail},Date.now()),a=c=>({left:e.snapshot?ws(e.snapshot,e.older,c):0,loading:e.olderLoading===c,error:e.olderError?.kind===c?e.olderError.text:void 0}),r=c=>!n||c!==s?null:c==="deck"?i`<${An} inp=${n.deck} drafts=${e.drafts} focus=${e.focusDecision} extensions=${t?.answerLimits?.extensions??[]} />`:c==="dispatches"?i`<${Pn} inp=${n.dispatches} more=${a("dispatches")} />`:c==="traps"?i`<${Qn} inp=${n.traps} />`:c==="prs"?i`<${zn} inp=${n.prs} more=${a("prs")} />`:c==="reports"?i`<${_n} inp=${n.reports} />`:i`<${Vn} inp=${n.notices} more=${a("notices")} />`,o=c=>{c.target===c.currentTarget&&ne()};return[i`<${Mn} d=${t} inp=${n} tab=${s} st=${e.prefs} stale=${e.stale} />`,ee.map(c=>i`<main key=${c} id=${"page-"+c} class=${t&&c===s?"tabpage on":"tabpage"}><div id=${c}>${r(c)}</div></main>`),i`<footer id="foot"><${On} d=${t} /></footer>`,i`<div id="lobs"><${jn} state=${e} /></div>`,i`<${st} box=${e.lightbox} />`,i`<div id="overlay" class=${e.modal&&t?"open":t?"":void 0} onClick=${o}><div class="modal" id="modalbox"><${qn} snapshot=${t} modal=${e.modal} prefs=${e.prefs} detail=${e.detail} /></div></div>`]}function wa({view:e}){if(e.state==="loading")return i`<main class="reportview"><div class="dim">loading\u2026</div></main>`;if(e.state==="error")return i`<main class="reportview"><div class="bad">${e.error}</div></main>`;let t=e.report;return i`<main class="reportview">\n <h1>${t.title}</h1>\n <${Tn} r=${t} text=${e.text!==void 0?{text:e.text}:{error:e.error}} />\n </main>`}function Xn({view:e,box:t}){return[i`<${wa} view=${e} />`,i`<${st} box=${t} />`]}async function Zn(e){let t=encodeURIComponent(e),s;try{let n=await fetch(`/report/${t}/meta`);if(!n.ok)return{state:"error",error:`report not found (${n.status})`};s=JSON.parse(await n.text())}catch{return{state:"error",error:"report could not be read"}}try{let n=await fetch(bs(e));return n.ok?{state:"ready",report:s,text:await n.text()}:{state:"ready",report:s,error:`report not found (${n.status})`}}catch{return{state:"ready",report:s,error:"report could not be read"}}}var Ga=3e4,er="lobstah-glass-page",sr="lobstah-glass-shown",Sa=20;function Da(){try{let t=sessionStorage.getItem(er);if(t&&/^[A-Za-z0-9_-]{8,64}$/.test(t))return t}catch{}let e="";try{e=Array.from(crypto.getRandomValues(new Uint8Array(12)),t=>t.toString(16).padStart(2,"0")).join("")}catch{for(;e.length<24;)e+=Math.random().toString(36).slice(2);e=e.slice(0,24)}try{sessionStorage.setItem(er,e)}catch{}return e}var tr=null,nr=()=>tr??(tr=Da()),Bt=[];function rr(){try{let e=JSON.parse(sessionStorage.getItem(sr)??"[]");if(Array.isArray(e))return e.filter(t=>typeof t=="string")}catch{}return Bt}function Ca(e){Bt=[...rr(),e].slice(-Sa);try{sessionStorage.setItem(sr,JSON.stringify(Bt))}catch{}}function xa(e){if(!e||typeof e!="object")return!1;let{id:t,hash:s}=e;if(typeof t!="string"||!t||!$s(s)||rr().includes(t))return!1;if(Ca(t),s==="")return!0;let n=me(s);return n!==null?location.pathname!==C(n)&&location.assign(C(n)):location.pathname!=="/"?location.assign(`/${s}`):location.hash!==s&&(location.hash=s),!0}var Ut=!1;async function Se(){if(!Ut){Ut=!0;try{let e=document.hidden?"hidden":"visible",t=await fetch(`/api/presence?page=${nr()}&vis=${e}`,{method:"POST",cache:"no-store"});if(!t.ok)return;xa((await t.json())?.show)}catch{}finally{Ut=!1}}}function qt(e){let t=null,s=0,n=()=>{let a=document.hidden?Ga:e??0;a!==s&&(t&&clearInterval(t),t=a?setInterval(()=>{Se()},a):null,s=a)};document.addEventListener("visibilitychange",()=>{n(),Se()}),window.addEventListener("pagehide",()=>{try{navigator.sendBeacon?.(`/api/presence?page=${nr()}&vis=gone`)}catch{}}),n(),Se()}var Vt=!1,De=null,Ce=null;function Ta(e){let t=e.headers?.get("x-lobstah-beats");if(t)try{return JSON.parse(decodeURIComponent(t))}catch{return}}async function Ft(){if(!Vt){Vt=!0,Se();try{let e=await fetch("/data",{cache:"no-store",headers:Ce?{"if-none-match":Ce}:{}});if(e.status===304){let t=Ta(e);t?Ps(t):je(await Ia())}else{if(!e.ok)throw new Error(`/data answered ${e.status}`);Ce=e.headers?.get("etag")??null,je(await e.json())}kt()}catch{js()}finally{Vt=!1}}}async function Ia(){Ce=null;let e=await fetch("/data",{cache:"no-store"});if(!e.ok)throw new Error(`/data answered ${e.status}`);return Ce=e.headers?.get("etag")??null,await e.json()}var ar=()=>{De||(De=setInterval(Ft,2e3))},Ra=()=>{De&&clearInterval(De),De=null};function or(){document.addEventListener("visibilitychange",()=>{document.hidden?Ra():(Ft(),ar())}),Ft(),document.hidden||ar()}var Wt=()=>fs(location.hash),ir=e=>window.addEventListener("hashchange",()=>e(Wt()));function cr(){let e=me(location.hash);return e===null?!1:(location.replace(C(e)),!0)}var dr=()=>({snapshot:void 0,route:Wt(),prefs:xs(),modal:null,detail:null,older:$t,olderLoading:null,olderError:null,stale:!1,lobHidden:Is(),focusResults:{},preview:new URLSearchParams(location.search).has("lob"),drafts:{},focusDecision:Ne(location.hash),lightbox:null}),lr=_s(location.pathname);lr!==null?Aa(lr):cr()||Pa();function Aa(e){_t(dr());let t={state:"loading"},s=()=>pt(Y(Xn,{view:t,box:$().lightbox}),document.body);document.title="report \\xB7 lobstah glass",bt(s),s(),qt(2e3),Zn(e).then(n=>{t=n,n.state==="ready"&&(document.title=`${n.report.title} \\xB7 lobstah glass`),s()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&$().lightbox&&se()})}function Pa(){_t(dr());let e,t=!1,s=()=>{let r=$(),o=r.route!==e||!t&&!!r.snapshot;pt(Y(Yn,{state:r}),document.body),e=r.route,t||(t=!!r.snapshot),o&&window.scrollTo(0,0),r.focusDecision||(n=null),a(r.focusDecision)},n=null;function a(r){if(!r||r===n)return;let o=[...document.querySelectorAll("[data-decision]")].find(c=>c.getAttribute("data-decision")===r);o&&(n=r,o.scrollIntoView?.({block:"center"}))}bt(s),s(),ir(r=>{if(cr())return;let o=Ne(location.hash);o!==$().focusDecision&&(n=null),y({route:r,focusDecision:o})}),document.addEventListener("keydown",r=>{r.key==="Escape"&&($().lightbox?se():ne())}),qt(),or()}})();</script>\n </body>\n</html>\n';
|
|
14389
14443
|
|
|
14390
14444
|
// apps/cli/src/glass-snapshot-thread.ts
|
|
14391
14445
|
init_dist2();
|
|
@@ -17156,8 +17210,10 @@ async function soakPark(trapId, timeout, plain = false) {
|
|
|
17156
17210
|
);
|
|
17157
17211
|
return "woke";
|
|
17158
17212
|
}
|
|
17159
|
-
|
|
17160
|
-
|
|
17213
|
+
const pending = unreportedTrapBait(reg);
|
|
17214
|
+
const instruction = unhandled(id, lane).length > 0 ? `New instruction for your dispatch ${id} \u2014 read it with \`lobstah inbox ${id}\`, act on it, and keep reporting.` : void 0;
|
|
17215
|
+
if (pending || instruction) {
|
|
17216
|
+
block([instruction, pending ? baitBrief(id, pending.descriptor) : void 0].filter(Boolean).join("\n\n"));
|
|
17161
17217
|
return "woke";
|
|
17162
17218
|
}
|
|
17163
17219
|
} else {
|