@coreplane/switchboard 1.220.1 → 1.221.0
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/assets/deploy/cloudflare-resident/worker.ts +87 -22
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/execution/residentReuse.ts +98 -0
- package/dist/assets/src/execution/residentSteps.ts +1 -0
- package/dist/assets/web/dist/.vite/manifest.json +18 -18
- package/dist/assets/web/dist/assets/{ResidentDetailPage-DvCt96Dk.js → ResidentDetailPage-iqyj3Kpt.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-BZaYja1-.js → ResidentsIndexPage-BiECMcX5.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-DI4vzCUu.js → RunRoutePage-YCWYYZkj.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-Ch9uP4p4.js → RunsIndexPage-BX6231bA.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-DAkAHMCH.js → ScheduledPage-ibRdZaDS.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-CfBonGcV.js → StatusDot-W2x3d782.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-CBD36E3W.js → Tooltip-BLRVgG37.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-DQ1U73LF.js → dist-C3C34ZMu.js} +1 -1
- package/dist/assets/web/dist/assets/{main-CdLnG-yl.js → main-B9dN-Wec.js} +2 -2
- package/dist/cli.js +863 -308
- package/package.json +1 -1
|
@@ -84,6 +84,7 @@ import { BASH_TIMEOUT_MAX_MS, BASH_TIMEOUT_MS, clampBashTimeout } from "../../sr
|
|
|
84
84
|
import { selectBindingsToPurge } from "../../src/execution/bindingPurge.js";
|
|
85
85
|
import { busyAfterKillReason, planForceDetach } from "../../src/execution/residentDetach.js";
|
|
86
86
|
import { parseReadonly, planReadonlyAttach } from "../../src/execution/residentReadonly.js";
|
|
87
|
+
import { decideWorktree, parseReuse, type WorktreeFacts } from "../../src/execution/residentReuse.js";
|
|
87
88
|
import {
|
|
88
89
|
depCacheScript,
|
|
89
90
|
mutableCachePaths,
|
|
@@ -1029,6 +1030,10 @@ interface AttachOk {
|
|
|
1029
1030
|
reconciled: boolean;
|
|
1030
1031
|
/** True when a dirty/stale/missing worktree was wiped and recreated. */
|
|
1031
1032
|
recreated: boolean;
|
|
1033
|
+
/** Which container the tree is in: the kernel's boot id of this resident's
|
|
1034
|
+
* VM (docs/reference/specs/harness-pi.md item 8), so the run's row can name
|
|
1035
|
+
* the container its pi runs in. Absent when the kernel does not say. */
|
|
1036
|
+
container?: string;
|
|
1032
1037
|
deps: ThreadDepsMechanism;
|
|
1033
1038
|
/** `ok` — credential file written; `unavailable` — writable attach but no
|
|
1034
1039
|
* token (see credentialsError); `none` — read-only attach, deliberately no
|
|
@@ -1371,6 +1376,16 @@ class StepError extends Error {
|
|
|
1371
1376
|
}
|
|
1372
1377
|
}
|
|
1373
1378
|
|
|
1379
|
+
/** A reusing attach (item 66) found no tree it can keep: gone, unreadable, or
|
|
1380
|
+
* built for the other mode. Nothing on disk was touched; the attach answers
|
|
1381
|
+
* 409 `needs: "recreate"` and the caller decides what a run without its
|
|
1382
|
+
* workspace does. */
|
|
1383
|
+
class ReuseRefusedError extends Error {
|
|
1384
|
+
constructor(readonly why: string) {
|
|
1385
|
+
super(`reuse-refused: ${why}`);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1374
1389
|
/** Thrown after the resident has ALREADY been transitioned to `down` (reason
|
|
1375
1390
|
* persisted); signals callers the cycle is over without re-flipping. */
|
|
1376
1391
|
class ResidentDownError extends Error {
|
|
@@ -1576,6 +1591,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
1576
1591
|
private readonly hydrationMemoTtlMs = 60_000;
|
|
1577
1592
|
private gitSetupDone = false;
|
|
1578
1593
|
private stageDirsReady = new Set<string>();
|
|
1594
|
+
private containerIdMemo: string | undefined = undefined;
|
|
1579
1595
|
|
|
1580
1596
|
/** The incarnation: one isolate paired with one container runtime
|
|
1581
1597
|
* (docs/reference/specs/resident-repos.md item 22). Minted when the object
|
|
@@ -1604,6 +1620,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
1604
1620
|
this.hydratedVerdictAt = 0;
|
|
1605
1621
|
this.gitSetupDone = false;
|
|
1606
1622
|
this.stageDirsReady.clear();
|
|
1623
|
+
this.containerIdMemo = undefined;
|
|
1607
1624
|
this.depsStoreDirReady = false;
|
|
1608
1625
|
this.depsInstallSlots = null;
|
|
1609
1626
|
}
|
|
@@ -4306,6 +4323,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4306
4323
|
refHint: string | null,
|
|
4307
4324
|
readonly = false,
|
|
4308
4325
|
wantSha: string | null = null,
|
|
4326
|
+
reuse = false,
|
|
4309
4327
|
record?: ResidentRecord,
|
|
4310
4328
|
traceparent?: string,
|
|
4311
4329
|
): Promise<AttachOk | ThreadErr> {
|
|
@@ -4314,7 +4332,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4314
4332
|
const t0 = systemClock();
|
|
4315
4333
|
const trace = createStepTrace(t0);
|
|
4316
4334
|
const res = await this.stepTrace.run(trace, () =>
|
|
4317
|
-
this.attachThreadTraced(threadKey, refHint, readonly, wantSha, record, t0),
|
|
4335
|
+
this.attachThreadTraced(threadKey, refHint, readonly, wantSha, reuse, record, t0),
|
|
4318
4336
|
);
|
|
4319
4337
|
// The same steps as the resident's own `resident.attach` root (item 22).
|
|
4320
4338
|
emitStepRoot("resident.attach", t0, trace.steps(), traceparent, "error" in res ? refusalOutcome(res) : "ok");
|
|
@@ -4327,6 +4345,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4327
4345
|
refHint: string | null,
|
|
4328
4346
|
readonly: boolean,
|
|
4329
4347
|
wantSha: string | null,
|
|
4348
|
+
reuse: boolean,
|
|
4330
4349
|
record: ResidentRecord | undefined,
|
|
4331
4350
|
t0: number,
|
|
4332
4351
|
): Promise<AttachOk | ThreadErr> {
|
|
@@ -4346,7 +4365,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4346
4365
|
// container under it (and isIdle never parks the cycle mid-attach).
|
|
4347
4366
|
this.attachesInFlight++;
|
|
4348
4367
|
try {
|
|
4349
|
-
return await this.attachThreadBody(threadKey, refHint, readonly, wantSha, resourceId, t0, record);
|
|
4368
|
+
return await this.attachThreadBody(threadKey, refHint, readonly, wantSha, reuse, resourceId, t0, record);
|
|
4350
4369
|
} finally {
|
|
4351
4370
|
this.attachesInFlight--;
|
|
4352
4371
|
}
|
|
@@ -4376,6 +4395,8 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4376
4395
|
refHint: string | null,
|
|
4377
4396
|
readonly: boolean,
|
|
4378
4397
|
wantSha: string | null,
|
|
4398
|
+
/** A resumed run's attach (item 66): keep the thread's tree as it stands, or refuse. */
|
|
4399
|
+
reuse: boolean,
|
|
4379
4400
|
resourceId: string,
|
|
4380
4401
|
t0: number,
|
|
4381
4402
|
recordFromRoute?: ResidentRecord,
|
|
@@ -4439,6 +4460,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4439
4460
|
threadKey,
|
|
4440
4461
|
refHint,
|
|
4441
4462
|
wantSha,
|
|
4463
|
+
reuse,
|
|
4442
4464
|
slug,
|
|
4443
4465
|
t0,
|
|
4444
4466
|
facts,
|
|
@@ -4460,6 +4482,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4460
4482
|
threadKey: string;
|
|
4461
4483
|
refHint: string | null;
|
|
4462
4484
|
wantSha: string | null;
|
|
4485
|
+
reuse: boolean;
|
|
4463
4486
|
slug: string;
|
|
4464
4487
|
t0: number;
|
|
4465
4488
|
facts: RepoFacts;
|
|
@@ -4468,7 +4491,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4468
4491
|
mode: ReturnType<typeof planReadonlyAttach>;
|
|
4469
4492
|
rollback: () => Promise<void>;
|
|
4470
4493
|
}): Promise<AttachOk | ThreadErr> {
|
|
4471
|
-
const { threadKey, refHint, wantSha, slug, t0, facts, record, binding, mode, rollback } = input;
|
|
4494
|
+
const { threadKey, refHint, wantSha, reuse, slug, t0, facts, record, binding, mode, rollback } = input;
|
|
4472
4495
|
|
|
4473
4496
|
// Command-level token mint — before the lock so mint latency
|
|
4474
4497
|
// never holds the mutex, and failure never blocks the attach.
|
|
@@ -4545,11 +4568,17 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4545
4568
|
const threadLockKey = await this.lockfileKey(sha);
|
|
4546
4569
|
const recreated = await this.ensureThreadWorktree(binding, sha, mode.originUrl, mode.modeSwitch, {
|
|
4547
4570
|
detached: target.kind === "sha",
|
|
4571
|
+
reuse,
|
|
4548
4572
|
});
|
|
4549
4573
|
return { sha, threadLockKey, recreated };
|
|
4550
4574
|
}, ATTACH_MUTEX_WAIT_MS);
|
|
4551
4575
|
} catch (err) {
|
|
4552
4576
|
await rollback();
|
|
4577
|
+
// A reusing attach found no tree it can keep (item 66): nothing was
|
|
4578
|
+
// wiped, and the caller (not this resident) decides what a run
|
|
4579
|
+
// without its workspace does.
|
|
4580
|
+
if (err instanceof ReuseRefusedError)
|
|
4581
|
+
return { error: `reuse-refused: ${err.why}`, status: 409, needs: "recreate" };
|
|
4553
4582
|
if (err instanceof MirrorBusyError) {
|
|
4554
4583
|
const s = await this.getStatus();
|
|
4555
4584
|
return { error: errMsg(err), status: 503, state: s.state, reason: "mirror-busy" };
|
|
@@ -4617,6 +4646,9 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4617
4646
|
// step counts it — the admission's free-space term is a live `df`, and the
|
|
4618
4647
|
// per-part projection it reads from the sample moves only with a cycle.
|
|
4619
4648
|
|
|
4649
|
+
// Which container the tree is in, for the run's row (harness-pi item 8):
|
|
4650
|
+
// memoized per incarnation, so this is a read after the first attach.
|
|
4651
|
+
const container = await this.containerIdentity();
|
|
4620
4652
|
return {
|
|
4621
4653
|
workspace: binding.worktreePath,
|
|
4622
4654
|
ref: binding.ref,
|
|
@@ -4624,6 +4656,7 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4624
4656
|
user: binding.user,
|
|
4625
4657
|
reconciled: deps.reconciled,
|
|
4626
4658
|
recreated: locked.value.recreated,
|
|
4659
|
+
...(container !== undefined ? { container } : {}),
|
|
4627
4660
|
deps: deps.deps,
|
|
4628
4661
|
credentials,
|
|
4629
4662
|
...(credentialsError ? { credentialsError } : {}),
|
|
@@ -4634,9 +4667,14 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4634
4667
|
};
|
|
4635
4668
|
}
|
|
4636
4669
|
|
|
4637
|
-
/** Ensure the worktree exists
|
|
4638
|
-
*
|
|
4639
|
-
*
|
|
4670
|
+
/** Ensure the worktree exists. A provisioning attach wipes dirty/stale
|
|
4671
|
+
* trees; a reusing attach (`opts.reuse`, item 66) keeps a readable tree
|
|
4672
|
+
* exactly as it stands (the dirt and the HEAD are the resumed run's own
|
|
4673
|
+
* work) and throws `ReuseRefusedError` for one it cannot keep, touching
|
|
4674
|
+
* nothing. The decision is the pure `decideWorktree`; this method measures
|
|
4675
|
+
* the facts and runs the verdict. Returns true when the tree was
|
|
4676
|
+
* (re)created. MUST be called holding the mirror mutex: the clone reads
|
|
4677
|
+
* the mirror.
|
|
4640
4678
|
*
|
|
4641
4679
|
* "Dirty" is tracked-file dirt (`status --porcelain -uno`): untracked
|
|
4642
4680
|
* scratch files are the thread's own state and survive re-attach.
|
|
@@ -4658,8 +4696,9 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4658
4696
|
modeSwitch: boolean,
|
|
4659
4697
|
/** `detached`: the bound ref is gone from the mirror and `sha` is the
|
|
4660
4698
|
* expected commit it still holds (item 51) — the tree is checked out at
|
|
4661
|
-
* that commit, detached, instead of at a branch.
|
|
4662
|
-
|
|
4699
|
+
* that commit, detached, instead of at a branch. `reuse`: a resumed
|
|
4700
|
+
* run's attach (item 66): keep the tree as it stands, or refuse. */
|
|
4701
|
+
opts: { detached: boolean; reuse: boolean } = { detached: false, reuse: false },
|
|
4663
4702
|
): Promise<boolean> {
|
|
4664
4703
|
const wt = binding.worktreePath;
|
|
4665
4704
|
const threadDir = parentDir(wt);
|
|
@@ -4667,32 +4706,38 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4667
4706
|
// 700 + thread-user ownership: other thread users cannot traverse in.
|
|
4668
4707
|
await this.runOk(["install", "-d", "-m", "700", "-o", binding.user, "-g", binding.user, threadDir], "thread-dir");
|
|
4669
4708
|
|
|
4670
|
-
//
|
|
4671
|
-
//
|
|
4672
|
-
//
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4709
|
+
// What is on disk, measured as the thread user. A tree built for the
|
|
4710
|
+
// other mode (item 50) is decided before any probe: a mirror-origin,
|
|
4711
|
+
// credential-less tree must never serve a writable run, and a
|
|
4712
|
+
// GitHub-origin tree must never serve a read-only one. The ancestry probe
|
|
4713
|
+
// is a provisioning attach's alone: a reusing attach never judges the HEAD.
|
|
4714
|
+
const facts: WorktreeFacts = { exists: false };
|
|
4715
|
+
if (!modeSwitch && (await this.run(["test", "-d", `${wt}/.git`])).exitCode === 0) {
|
|
4716
|
+
facts.exists = true;
|
|
4676
4717
|
const status = await this.threadRun(binding.user, wt, "git status --porcelain -uno", DEFAULT_EXEC_TIMEOUT_MS);
|
|
4677
4718
|
const head = await this.threadRun(binding.user, wt, "git rev-parse HEAD", DEFAULT_EXEC_TIMEOUT_MS);
|
|
4678
4719
|
if (status.exitCode !== 0 || head.exitCode !== 0) {
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4720
|
+
// unreadable/corrupt (or owned by a previous pool user)
|
|
4721
|
+
facts.readable = false;
|
|
4722
|
+
facts.detail = (status.exitCode !== 0 ? status.stderr : head.stderr).trim().split("\n")[0]?.slice(0, 200) ?? "";
|
|
4682
4723
|
} else {
|
|
4683
|
-
|
|
4684
|
-
|
|
4724
|
+
facts.readable = true;
|
|
4725
|
+
facts.dirty = status.stdout.trim() !== "";
|
|
4726
|
+
facts.head = head.stdout.trim();
|
|
4727
|
+
if (!opts.reuse && !facts.dirty && facts.head !== sha) {
|
|
4685
4728
|
const anc = await this.threadRun(
|
|
4686
4729
|
binding.user,
|
|
4687
4730
|
wt,
|
|
4688
4731
|
`git merge-base --is-ancestor ${sha} HEAD`,
|
|
4689
4732
|
DEFAULT_EXEC_TIMEOUT_MS,
|
|
4690
4733
|
);
|
|
4691
|
-
|
|
4734
|
+
facts.descendsFromTip = anc.exitCode === 0;
|
|
4692
4735
|
}
|
|
4693
4736
|
}
|
|
4694
|
-
if (!recreate) return false;
|
|
4695
4737
|
}
|
|
4738
|
+
const decision = decideWorktree({ reuse: opts.reuse, modeSwitch, sha, worktreePath: wt, facts });
|
|
4739
|
+
if (decision.kind === "refuse") throw new ReuseRefusedError(decision.why);
|
|
4740
|
+
if (decision.kind === "reuse") return false;
|
|
4696
4741
|
|
|
4697
4742
|
await this.runOk(["rm", "-rf", wt], "worktree-clean");
|
|
4698
4743
|
if (opts.detached) {
|
|
@@ -4727,6 +4772,24 @@ export class ResidentDO extends Sandbox<Env> {
|
|
|
4727
4772
|
return true;
|
|
4728
4773
|
}
|
|
4729
4774
|
|
|
4775
|
+
/** Which container this is: the kernel's boot id, one per VM boot and
|
|
4776
|
+
* world-readable, so the run's pool user reads the same word from inside
|
|
4777
|
+
* (docs/reference/specs/harness-pi.md item 8). Memoized per incarnation (a
|
|
4778
|
+
* replaced runtime clears it with the other memos). Undefined when the
|
|
4779
|
+
* kernel does not say or the command could not run: then the answer names
|
|
4780
|
+
* no container, and nothing is judged by it. */
|
|
4781
|
+
private async containerIdentity(): Promise<string | undefined> {
|
|
4782
|
+
if (this.containerIdMemo !== undefined) return this.containerIdMemo;
|
|
4783
|
+
try {
|
|
4784
|
+
const word = (await this.runOk(["cat", "/proc/sys/kernel/random/boot_id"], "boot-id")).trim();
|
|
4785
|
+
if (!/^[A-Za-z0-9-]{1,64}$/.test(word)) return undefined;
|
|
4786
|
+
this.containerIdMemo = word;
|
|
4787
|
+
return word;
|
|
4788
|
+
} catch {
|
|
4789
|
+
return undefined;
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4730
4793
|
/** Read-only attach (item 50): make sure the tree carries no credential file
|
|
4731
4794
|
* and no credential helper — idempotent, run on every read-only attach. */
|
|
4732
4795
|
private async scrubThreadCredentials(binding: ThreadBinding): Promise<void> {
|
|
@@ -7475,13 +7538,15 @@ async function handleAttach(env: Env, body: Record<string, unknown>, traceparent
|
|
|
7475
7538
|
if ("error" in readonly) return json({ error: readonly.error }, 400);
|
|
7476
7539
|
const want = parseWantSha(body.sha);
|
|
7477
7540
|
if ("error" in want) return json({ error: want.error }, 400);
|
|
7541
|
+
const reuse = parseReuse(body.reuse);
|
|
7542
|
+
if ("error" in reuse) return json({ error: reuse.error }, 400);
|
|
7478
7543
|
// Post-validation, the answer streams like /exec (item 59): heartbeat
|
|
7479
7544
|
// whitespace then ONE JSON document over HTTP 200, so an attach that waits
|
|
7480
7545
|
// on a deps install (minutes) cannot lose the connection the way a plain
|
|
7481
7546
|
// response does (`fetch failed` a few minutes in). A refusal
|
|
7482
7547
|
// carries its `status` in the body; `ResidentExecutor.attach` reads it there.
|
|
7483
7548
|
return streamHeartbeatJson(
|
|
7484
|
-
ctx.stub.attachThread(ctx.threadKey, refHint, readonly.readonly, want.sha, ctx.record, traceparent),
|
|
7549
|
+
ctx.stub.attachThread(ctx.threadKey, refHint, readonly.readonly, want.sha, reuse.reuse, ctx.record, traceparent),
|
|
7485
7550
|
(result) => result,
|
|
7486
7551
|
(err) => ({ error: errMsg(err), status: 500 }),
|
|
7487
7552
|
);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.221.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "switchboard",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.221.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"web",
|
|
@@ -16710,7 +16710,7 @@
|
|
|
16710
16710
|
},
|
|
16711
16711
|
"packages/switchboard": {
|
|
16712
16712
|
"name": "@coreplane/switchboard",
|
|
16713
|
-
"version": "1.
|
|
16713
|
+
"version": "1.221.0",
|
|
16714
16714
|
"license": "Apache-2.0",
|
|
16715
16715
|
"dependencies": {
|
|
16716
16716
|
"@anthropic-ai/sdk": "^0.124.0",
|
package/dist/assets/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.221.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
6
6
|
"license": "Apache-2.0",
|
package/dist/assets/source.json
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** The worktree decision of the resident Worker's attach
|
|
2
|
+
* (deploy/cloudflare-resident/worker.ts `ensureThreadWorktree`), kept pure
|
|
3
|
+
* and dependency-free so it is unit-testable from src/ and imported by the
|
|
4
|
+
* resident Worker like residentReadonly and residentHead: the tested code IS
|
|
5
|
+
* the shipped code.
|
|
6
|
+
*
|
|
7
|
+
* Background: an attach treated the thread's tree as disposable: dirty
|
|
8
|
+
* tracked files or a HEAD off the mirror's tip meant `rm -rf` and a fresh
|
|
9
|
+
* clone. That is the right discipline for a fresh run, whose tree is a
|
|
10
|
+
* leftover of some earlier run in the thread. It is the wrong discipline for
|
|
11
|
+
* a run that comes back after a bot restart: the dirty tree IS that run's
|
|
12
|
+
* work, and the wipe either destroyed it under a still-living process or
|
|
13
|
+
* raced that process's own writes and failed the attach outright.
|
|
14
|
+
*
|
|
15
|
+
* Shape: the caller says whether this attach REUSES (a resumed run) or
|
|
16
|
+
* PROVISIONS (a fresh one). A reusing attach keeps a readable tree exactly
|
|
17
|
+
* as it stands, dirt and stale HEAD included, and refuses by name a tree it
|
|
18
|
+
* cannot keep (gone, unreadable, built for the other mode) without touching
|
|
19
|
+
* it. A provisioning attach keeps the dirty/stale discipline byte for byte. */
|
|
20
|
+
|
|
21
|
+
export type ParsedReuse = { reuse: boolean } | { error: string };
|
|
22
|
+
|
|
23
|
+
/** `/attach` body field `reuse`: absent → false (the body every bot always
|
|
24
|
+
* sent, a fresh attach); a boolean → itself; anything else → a 400-shaped error. */
|
|
25
|
+
export function parseReuse(value: unknown): ParsedReuse {
|
|
26
|
+
if (value === undefined) return { reuse: false };
|
|
27
|
+
if (typeof value === "boolean") return { reuse: value };
|
|
28
|
+
return { error: "reuse must be a boolean when present" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** What the attach measured about the tree on disk, as the thread user. Each
|
|
32
|
+
* probe past `exists` is measured only when the one before it allowed; an
|
|
33
|
+
* unmeasured fact is undefined. */
|
|
34
|
+
export interface WorktreeFacts {
|
|
35
|
+
/** `<worktree>/.git` is a directory. */
|
|
36
|
+
exists: boolean;
|
|
37
|
+
/** `git status --porcelain -uno` and `git rev-parse HEAD` both succeeded. */
|
|
38
|
+
readable?: boolean;
|
|
39
|
+
/** The failing probe's first error line, when one failed. */
|
|
40
|
+
detail?: string;
|
|
41
|
+
/** Tracked files differ from HEAD (untracked scratch files never count). */
|
|
42
|
+
dirty?: boolean;
|
|
43
|
+
/** The tree's HEAD. */
|
|
44
|
+
head?: string;
|
|
45
|
+
/** Whether the target commit is an ancestor of HEAD, measured by a
|
|
46
|
+
* provisioning attach whose HEAD is not the target; never by a reusing one. */
|
|
47
|
+
descendsFromTip?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type WorktreeDecision =
|
|
51
|
+
/** Keep the tree exactly as it stands. */
|
|
52
|
+
| { kind: "reuse" }
|
|
53
|
+
/** Wipe it and clone afresh (a provisioning attach only). */
|
|
54
|
+
| { kind: "recreate"; why: "mode-switch" | "missing" | "unreadable" | "dirty" | "stale" }
|
|
55
|
+
/** A reusing attach cannot keep this tree, and must not replace it. */
|
|
56
|
+
| { kind: "refuse"; why: string };
|
|
57
|
+
|
|
58
|
+
export function decideWorktree(input: {
|
|
59
|
+
/** True for a resumed run's attach: keep the tree, never wipe it. */
|
|
60
|
+
reuse: boolean;
|
|
61
|
+
/** The tree was built for the other mode (read-only against writable). */
|
|
62
|
+
modeSwitch: boolean;
|
|
63
|
+
/** The commit a provisioning attach checks out: the ref's tip, or the expected head. */
|
|
64
|
+
sha: string;
|
|
65
|
+
worktreePath: string;
|
|
66
|
+
facts: WorktreeFacts;
|
|
67
|
+
}): WorktreeDecision {
|
|
68
|
+
const { reuse, modeSwitch, sha, worktreePath, facts } = input;
|
|
69
|
+
if (modeSwitch) {
|
|
70
|
+
return reuse
|
|
71
|
+
? {
|
|
72
|
+
kind: "refuse",
|
|
73
|
+
why: `the worktree at ${worktreePath} was built for the other mode (read-only against writable)`,
|
|
74
|
+
}
|
|
75
|
+
: { kind: "recreate", why: "mode-switch" };
|
|
76
|
+
}
|
|
77
|
+
if (!facts.exists) {
|
|
78
|
+
return reuse
|
|
79
|
+
? {
|
|
80
|
+
kind: "refuse",
|
|
81
|
+
why: `no worktree at ${worktreePath}: the container disk was recycled or the tree was evicted since the run attached`,
|
|
82
|
+
}
|
|
83
|
+
: { kind: "recreate", why: "missing" };
|
|
84
|
+
}
|
|
85
|
+
if (facts.readable !== true) {
|
|
86
|
+
return reuse
|
|
87
|
+
? {
|
|
88
|
+
kind: "refuse",
|
|
89
|
+
why: `the worktree at ${worktreePath} cannot be read (${facts.detail ?? "git probe failed"})`,
|
|
90
|
+
}
|
|
91
|
+
: { kind: "recreate", why: "unreadable" };
|
|
92
|
+
}
|
|
93
|
+
// A reusing attach judges nothing past readability: the dirt and the HEAD are the run's own state.
|
|
94
|
+
if (reuse) return { kind: "reuse" };
|
|
95
|
+
if (facts.dirty) return { kind: "recreate", why: "dirty" };
|
|
96
|
+
if (facts.head !== sha && facts.descendsFromTip !== true) return { kind: "recreate", why: "stale" };
|
|
97
|
+
return { kind: "reuse" };
|
|
98
|
+
}
|
|
@@ -60,6 +60,7 @@ export const RESIDENT_STEP_LABELS = {
|
|
|
60
60
|
"ops-dir": "preparing a directory",
|
|
61
61
|
"stage-dir": "preparing a directory",
|
|
62
62
|
stat: "checking a file",
|
|
63
|
+
"boot-id": "reading the container's identity",
|
|
63
64
|
touch: "touching a marker",
|
|
64
65
|
nproc: "counting CPUs",
|
|
65
66
|
mutex_wait: "waiting for the workspace",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"src": "../node_modules/@fontsource-variable/jetbrains-mono/files/jetbrains-mono-vietnamese-wght-normal.woff2"
|
|
29
29
|
},
|
|
30
30
|
"../node_modules/@pierre/diffs/dist/index.js": {
|
|
31
|
-
"file": "assets/dist-
|
|
31
|
+
"file": "assets/dist-C3C34ZMu.js",
|
|
32
32
|
"name": "dist",
|
|
33
33
|
"src": "../node_modules/@pierre/diffs/dist/index.js",
|
|
34
34
|
"isDynamicEntry": true,
|
|
@@ -2562,16 +2562,16 @@
|
|
|
2562
2562
|
"_seed-DeKSHrt2.js"
|
|
2563
2563
|
]
|
|
2564
2564
|
},
|
|
2565
|
-
"_StatusDot-
|
|
2566
|
-
"file": "assets/StatusDot-
|
|
2565
|
+
"_StatusDot-W2x3d782.js": {
|
|
2566
|
+
"file": "assets/StatusDot-W2x3d782.js",
|
|
2567
2567
|
"name": "StatusDot",
|
|
2568
2568
|
"imports": [
|
|
2569
2569
|
"_seed-DeKSHrt2.js",
|
|
2570
|
-
"_Tooltip-
|
|
2570
|
+
"_Tooltip-BLRVgG37.js"
|
|
2571
2571
|
]
|
|
2572
2572
|
},
|
|
2573
|
-
"_Tooltip-
|
|
2574
|
-
"file": "assets/Tooltip-
|
|
2573
|
+
"_Tooltip-BLRVgG37.js": {
|
|
2574
|
+
"file": "assets/Tooltip-BLRVgG37.js",
|
|
2575
2575
|
"name": "Tooltip",
|
|
2576
2576
|
"imports": [
|
|
2577
2577
|
"_AppShell-lYVcj-k7.js",
|
|
@@ -2789,7 +2789,7 @@
|
|
|
2789
2789
|
]
|
|
2790
2790
|
},
|
|
2791
2791
|
"src/main.ts": {
|
|
2792
|
-
"file": "assets/main-
|
|
2792
|
+
"file": "assets/main-B9dN-Wec.js",
|
|
2793
2793
|
"name": "main",
|
|
2794
2794
|
"src": "src/main.ts",
|
|
2795
2795
|
"isEntry": true,
|
|
@@ -2841,19 +2841,19 @@
|
|
|
2841
2841
|
]
|
|
2842
2842
|
},
|
|
2843
2843
|
"src/pages/ResidentDetailPage.vue": {
|
|
2844
|
-
"file": "assets/ResidentDetailPage-
|
|
2844
|
+
"file": "assets/ResidentDetailPage-iqyj3Kpt.js",
|
|
2845
2845
|
"name": "ResidentDetailPage",
|
|
2846
2846
|
"src": "src/pages/ResidentDetailPage.vue",
|
|
2847
2847
|
"isDynamicEntry": true,
|
|
2848
2848
|
"imports": [
|
|
2849
2849
|
"_AppShell-lYVcj-k7.js",
|
|
2850
2850
|
"_seed-DeKSHrt2.js",
|
|
2851
|
-
"_StatusDot-
|
|
2851
|
+
"_StatusDot-W2x3d782.js",
|
|
2852
2852
|
"_residentDiskBudget-BMBKlYRH.js"
|
|
2853
2853
|
]
|
|
2854
2854
|
},
|
|
2855
2855
|
"src/pages/ResidentsIndexPage.vue": {
|
|
2856
|
-
"file": "assets/ResidentsIndexPage-
|
|
2856
|
+
"file": "assets/ResidentsIndexPage-BiECMcX5.js",
|
|
2857
2857
|
"name": "ResidentsIndexPage",
|
|
2858
2858
|
"src": "src/pages/ResidentsIndexPage.vue",
|
|
2859
2859
|
"isDynamicEntry": true,
|
|
@@ -2861,20 +2861,20 @@
|
|
|
2861
2861
|
"_AppShell-lYVcj-k7.js",
|
|
2862
2862
|
"_seed-DeKSHrt2.js",
|
|
2863
2863
|
"_wallClock-61NpVkY6.js",
|
|
2864
|
-
"_StatusDot-
|
|
2864
|
+
"_StatusDot-W2x3d782.js",
|
|
2865
2865
|
"_residentDiskBudget-BMBKlYRH.js",
|
|
2866
2866
|
"_indexFormat-B-pd4r7Y.js"
|
|
2867
2867
|
]
|
|
2868
2868
|
},
|
|
2869
2869
|
"src/pages/RunRoutePage.vue": {
|
|
2870
|
-
"file": "assets/RunRoutePage-
|
|
2870
|
+
"file": "assets/RunRoutePage-YCWYYZkj.js",
|
|
2871
2871
|
"name": "RunRoutePage",
|
|
2872
2872
|
"src": "src/pages/RunRoutePage.vue",
|
|
2873
2873
|
"isDynamicEntry": true,
|
|
2874
2874
|
"imports": [
|
|
2875
2875
|
"_AppShell-lYVcj-k7.js",
|
|
2876
2876
|
"_seed-DeKSHrt2.js",
|
|
2877
|
-
"_Tooltip-
|
|
2877
|
+
"_Tooltip-BLRVgG37.js",
|
|
2878
2878
|
"src/main.ts",
|
|
2879
2879
|
"_wallClock-61NpVkY6.js",
|
|
2880
2880
|
"_NotFoundPage-BzWS4Ca1.js",
|
|
@@ -2890,31 +2890,31 @@
|
|
|
2890
2890
|
]
|
|
2891
2891
|
},
|
|
2892
2892
|
"src/pages/RunsIndexPage.vue": {
|
|
2893
|
-
"file": "assets/RunsIndexPage-
|
|
2893
|
+
"file": "assets/RunsIndexPage-BX6231bA.js",
|
|
2894
2894
|
"name": "RunsIndexPage",
|
|
2895
2895
|
"src": "src/pages/RunsIndexPage.vue",
|
|
2896
2896
|
"isDynamicEntry": true,
|
|
2897
2897
|
"imports": [
|
|
2898
2898
|
"_AppShell-lYVcj-k7.js",
|
|
2899
2899
|
"_seed-DeKSHrt2.js",
|
|
2900
|
-
"_Tooltip-
|
|
2900
|
+
"_Tooltip-BLRVgG37.js",
|
|
2901
2901
|
"_wallClock-61NpVkY6.js",
|
|
2902
2902
|
"_RunsTabs-DEICQ4FY.js",
|
|
2903
|
-
"_StatusDot-
|
|
2903
|
+
"_StatusDot-W2x3d782.js",
|
|
2904
2904
|
"_indexFormat-B-pd4r7Y.js",
|
|
2905
2905
|
"_favicon-CWPcvWvp.js",
|
|
2906
2906
|
"_localIso-L06jV29p.js"
|
|
2907
2907
|
]
|
|
2908
2908
|
},
|
|
2909
2909
|
"src/pages/ScheduledPage.vue": {
|
|
2910
|
-
"file": "assets/ScheduledPage-
|
|
2910
|
+
"file": "assets/ScheduledPage-ibRdZaDS.js",
|
|
2911
2911
|
"name": "ScheduledPage",
|
|
2912
2912
|
"src": "src/pages/ScheduledPage.vue",
|
|
2913
2913
|
"isDynamicEntry": true,
|
|
2914
2914
|
"imports": [
|
|
2915
2915
|
"_AppShell-lYVcj-k7.js",
|
|
2916
2916
|
"_seed-DeKSHrt2.js",
|
|
2917
|
-
"_Tooltip-
|
|
2917
|
+
"_Tooltip-BLRVgG37.js",
|
|
2918
2918
|
"_wallClock-61NpVkY6.js",
|
|
2919
2919
|
"_RunsTabs-DEICQ4FY.js",
|
|
2920
2920
|
"_indexFormat-B-pd4r7Y.js",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./AppShell-lYVcj-k7.js";import{Lr as t,Xt as n,_n as r,cn as i,gn as a,ir as o,ln as ee,on as s,r as c,sn as l,un as u,ur as d,vi as f,wi as p,yn as te}from"./seed-DeKSHrt2.js";import{t as m}from"./StatusDot-CfBonGcV.js";import{a as ne,c as re,d as ie,f as h,i as g,l as ae,n as oe,o as se,r as ce,s as _,t as le,u as ue}from"./residentDiskBudget-BMBKlYRH.js";var de={class:`mt-4 first:mt-0`},fe={class:`w-full border-collapse font-mono text-[0.8125rem]`},pe={class:`border-t border-muted`},me={class:`px-2 py-1 align-top`},v={class:`ml-1.5 font-medium`},y={class:`border-t border-muted`},b={class:`break-all px-2 py-1 align-top`},x={key:0},S={key:1,class:`text-dimmed`},C={class:`border-t border-muted`},w={class:`break-all px-2 py-1 align-top`},T={key:0},E={key:1,class:`text-dimmed`},D={class:`border-t border-muted`},O={class:`break-all px-2 py-1 align-top`},k={key:0},A={key:1,class:`text-dimmed`},j={class:`border-t border-muted`},M={class:`break-all px-2 py-1 align-top`},N={key:0},P={key:1,class:`text-dimmed`},F={class:`border-t border-muted`},I={class:`break-all px-2 py-1 align-top`},L={key:1,class:`text-dimmed`},R={class:`mt-4`},z={class:`w-full border-collapse font-mono text-[0.8125rem]`},he={class:`border-t border-muted`},ge={class:`break-all px-2 py-1 align-top`},_e=[`href`],ve={key:1},ye={class:`border-t border-muted`},be={class:`break-all px-2 py-1 align-top`},xe={class:`border-t border-muted`},Se={class:`break-all px-2 py-1 align-top`},Ce=[`href`],we={key:1},Te={key:2,class:`text-dimmed`},Ee={class:`border-t border-muted`},De={class:`break-all px-2 py-1 align-top`},Oe={key:0},ke={key:1,class:`text-dimmed`},Ae={class:`border-t border-muted`},je={class:`break-all px-2 py-1 align-top`},Me={key:0},Ne={key:1,class:`text-dimmed`},Pe={class:`border-t border-muted`},Fe={class:`break-all px-2 py-1 align-top`},Ie={key:0},Le={key:1,class:`text-dimmed`},Re={class:`mt-4`},ze={class:`w-full border-collapse font-mono text-[0.8125rem]`},Be={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Ve={class:`break-all px-2 py-1 align-top`},He={class:`w-full border-collapse font-mono text-[0.8125rem]`},Ue={class:`w-32 break-all px-2 py-1 align-top text-muted sm:w-96 sm:break-words`},We={class:`px-2 py-1 align-top`},Ge={key:1,class:`text-xs text-muted`},Ke={class:`mt-4`},qe={key:0,class:`w-full border-collapse font-mono text-[0.8125rem]`},Je={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Ye={class:`break-all px-2 py-1 align-top`},Xe={key:0},B={key:1,class:`text-dimmed`},Ze={key:1,class:`text-xs text-muted`},Qe={class:`mt-4`},$e={class:`mb-1 text-xs text-muted`},et={class:`overflow-x-auto`},tt={class:`w-full border-collapse font-mono text-[0.8125rem]`},nt={class:`break-all px-2 py-1 align-top`},rt={key:0,class:`text-xs text-muted`},it={class:`break-all px-2 py-1 align-top`},at=[`href`],ot={key:1},st={key:2,class:`text-dimmed`},ct={class:`break-all px-2 py-1 align-top`},lt={key:0},ut={key:1,class:`text-dimmed`},dt={key:2},ft={key:3,class:`text-dimmed`},pt={class:`break-all px-2 py-1 align-top`},mt={key:0},ht={key:1,class:`text-dimmed`},gt={key:2},_t={key:3,class:`text-dimmed`},vt={key:1,class:`text-xs text-muted`},yt={class:`mt-4`},bt={class:`w-full border-collapse font-mono text-[0.8125rem]`},xt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},St={class:`px-2 py-1 align-top`},Ct={class:`mt-4`},wt={key:0,class:`w-full border-collapse font-mono text-[0.8125rem]`},Tt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Et={class:`break-all px-2 py-1 align-top`},Dt={class:`text-xs text-muted`},Ot={key:1,class:`text-xs text-muted`},kt={class:`mt-4`},At={class:`w-full border-collapse font-mono text-[0.8125rem]`},jt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Mt={class:`break-all px-2 py-1 align-top`},Nt={key:0},Pt={key:1,class:`text-dimmed`},Ft={class:`mt-4 text-xs text-muted`},It={class:`rounded bg-elevated px-1 py-0.5`},Lt={class:`rounded bg-elevated px-1 py-0.5`},Rt={class:`rounded bg-elevated px-1 py-0.5`},V=te({__name:`ResidentDetailPage`,setup(te){let V=c(`resident`),H=s(()=>V?.record??{}),U=s(()=>ae(H.value)),W=s(()=>ue(H.value)||(V?.slug??``)),G=s(()=>h(U.value.sha)),K=s(()=>se.test(W.value)?`https://github.com/${W.value}`:void 0),q=s(()=>K.value&&/^[0-9a-f]{7,40}$/.test(G.value)?`${K.value}/commit/${G.value}`:void 0),J=s(()=>{let e=U.value.snapshot;return e&&typeof e==`object`?_(e):void 0}),zt=s(()=>_(U.value.schedules)),Y=s(()=>{let e=_(H.value.commands),t=_(H.value.effects);return Object.keys(e).sort().map(n=>({name:n,command:h(e[n]),effect:h(t[n])||`readonly`}))}),X=s(()=>{let e=U.value.threads;return(Array.isArray(e)?e.map(_):[]).map(e=>{let t=h(e.sha);return{threadKey:h(e.threadKey)||`?`,ref:h(e.ref)||`?`,sha:t?t.slice(0,8):``,commitHref:K.value&&/^[0-9a-f]{7,40}$/.test(t)?`${K.value}/commit/${t}`:void 0,user:h(e.user),deps:h(e.deps),boundAt:h(e.boundAt),lastAttachAt:h(e.lastAttachAt),evicted:e.evicted===!0,evictedAt:h(e.evictedAt),evictedWhy:h(e.evictedWhy)}}).sort((e,t)=>t.lastAttachAt.localeCompare(e.lastAttachAt))}),Z=s(()=>X.value.filter(e=>!e.evicted).length),Q=s(()=>{let e=U.value.lastRestore;return e?JSON.stringify(e):``}),$=s(()=>re(H.value)),Bt=s(()=>typeof H.value.diskBudgetMb==`number`?H.value.diskBudgetMb:void 0),Vt=s(()=>{let e=$.value;if(!e)return[];let t=le(e),{freeKiB:n,capped:r,capacityKiB:i}=oe(e,Bt.value),a=n-t.totalKiB,o=t=>{let n=ne(e.parts,t);return n===null?`? (checkout not measured)`:n===0?`?`:`${Math.max(0,Math.floor(a/n))} more (${g(n)} each)`};return[[`used / total`,ce(e)],[`free`,`${g(n)}${r?` under the ${g(i)} diskBudgetMb cap`:``}`],[`reserve`,`${g(t.totalKiB)} (snapshot staging ${g(t.stagingKiB)} + floor ${g(t.floorKiB)})`],[`headroom`,`${g(Math.max(0,a))} — room for ${o(`hardlink`)} hardlinked trees, ${o(`reconcile`)} lockfile-diverged (reconciling)`],[`measured`,e.at||`—`]]}),Ht=s(()=>{let e=$.value;if(!e)return[];let t=[[`mirror`,g(e.parts.mirror)],[`checkout deps (node_modules)`,g(e.parts.deps)],[`checkout (history + tree + build)`,g(e.parts.checkout)]];for(let[n,r]of Object.entries(e.parts.threads).sort((e,t)=>t[1]-e[1]))t.push([`thread ${n}`,g(r)]);for(let[n,r]of Object.entries(e.parts.homes).sort((e,t)=>t[1]-e[1]))r>=1024&&t.push([`home ${n}`,g(r)]);return t.push([`other (image, /tmp, …)`,g(e.parts.other)]),t});return(s,c)=>(o(),i(e,{title:W.value||`Resident`,nav:`residents`},{leading:t(()=>[...c[0]||=[l(`a`,{class:`back text-sm text-muted no-underline hover:text-primary`,href:`/residents`},`← All residents`,-1)]]),default:t(()=>[l(`section`,de,[c[8]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Lifecycle`,-1),l(`table`,fe,[l(`tbody`,null,[l(`tr`,pe,[c[1]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`state`,-1),l(`td`,me,[r(m,{tone:f(ie)(U.value.state),label:U.value.state},null,8,[`tone`,`label`]),l(`span`,v,p(U.value.state),1)])]),l(`tr`,y,[c[2]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`reason`,-1),l(`td`,b,[U.value.reason?(o(),u(`span`,x,p(U.value.reason),1)):(o(),u(`span`,S,`—`))])]),l(`tr`,C,[c[3]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last refresh error`,-1),l(`td`,w,[f(h)(U.value.lastRefreshError)?(o(),u(`span`,T,p(f(h)(U.value.lastRefreshError)),1)):(o(),u(`span`,E,`—`))])]),l(`tr`,D,[c[4]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last restore`,-1),l(`td`,O,[Q.value?(o(),u(`span`,k,p(Q.value),1)):(o(),u(`span`,A,`—`))])]),l(`tr`,j,[c[5]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`state updated`,-1),l(`td`,M,[f(h)(U.value.updatedAt)?(o(),u(`span`,N,p(f(h)(U.value.updatedAt)),1)):(o(),u(`span`,P,`—`))])]),l(`tr`,F,[c[7]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`idle since`,-1),l(`td`,I,[f(h)(U.value.idleSince)?(o(),u(n,{key:0},[a(p(f(h)(U.value.idleSince))+` `,1),c[6]||=l(`span`,{class:`text-xs text-muted`},`(refresh parked; container may sleep)`,-1)],64)):(o(),u(`span`,L,`awake`))])])])])]),l(`section`,R,[c[15]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Pinned facts`,-1),l(`table`,z,[l(`tbody`,null,[l(`tr`,he,[c[9]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`repository`,-1),l(`td`,ge,[K.value?(o(),u(`a`,{key:0,class:`text-primary`,href:K.value},p(K.value),9,_e)):(o(),u(`span`,ve,p(f(h)(H.value.resource)||`—`),1))])]),l(`tr`,ye,[c[10]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`default ref`,-1),l(`td`,be,p(f(h)(U.value.defaultRef)||f(h)(H.value.defaultRef)||`—`),1)]),l(`tr`,xe,[c[11]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`pinned sha`,-1),l(`td`,Se,[q.value?(o(),u(`a`,{key:0,class:`text-primary`,href:q.value},p(G.value),9,Ce)):G.value?(o(),u(`span`,we,p(G.value),1)):(o(),u(`span`,Te,`—`))])]),l(`tr`,Ee,[c[12]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`lockfile hash`,-1),l(`td`,De,[f(h)(U.value.lockfileHash)?(o(),u(`span`,Oe,p(f(h)(U.value.lockfileHash)),1)):(o(),u(`span`,ke,`—`))])]),l(`tr`,Ae,[c[13]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`provisioned`,-1),l(`td`,je,[f(h)(U.value.provisionedAt)?(o(),u(`span`,Me,p(f(h)(U.value.provisionedAt)),1)):(o(),u(`span`,Ne,`—`))])]),l(`tr`,Pe,[c[14]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last refresh`,-1),l(`td`,Fe,[f(h)(U.value.lastRefreshAt)?(o(),u(`span`,Ie,p(f(h)(U.value.lastRefreshAt)),1)):(o(),u(`span`,Le,`—`))])])])])]),l(`section`,Re,[c[17]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Disk`,-1),$.value?(o(),u(n,{key:0},[l(`table`,ze,[l(`tbody`,null,[(o(!0),u(n,null,d(Vt.value,([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Be,p(e),1),l(`td`,Ve,p(t),1)]))),128))])]),c[16]||=l(`p`,{class:`mb-1 mt-2 text-xs text-muted`},` components (one du, hardlinks counted once — a thread tree shows only what it does not share with the checkout) `,-1),l(`table`,He,[l(`tbody`,null,[(o(!0),u(n,null,d(Ht.value,([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Ue,p(e),1),l(`td`,We,p(t),1)]))),128))])])],64)):(o(),u(`p`,Ge,` not measured yet — the first refresh cycle or attach of this container measures it `))]),l(`section`,Ke,[c[18]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Snapshot stamp`,-1),J.value?(o(),u(`table`,qe,[l(`tbody`,null,[(o(),u(n,null,d([`ref`,`sha`,`lockfileHash`,`createdAt`,`mirrorBackupId`,`checkoutBackupId`],e=>l(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Je,p(e),1),l(`td`,Ye,[f(h)(J.value[e])?(o(),u(`span`,Xe,p(f(h)(J.value[e])),1)):(o(),u(`span`,B,`—`))])])),64))])])):(o(),u(`p`,Ze,`no snapshot recorded`))]),l(`section`,Qe,[c[22]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Thread worktrees`,-1),X.value.length>0?(o(),u(n,{key:0},[l(`p`,$e,p(Z.value)+` live · `+p(X.value.length-Z.value)+` evicted`,1),l(`div`,et,[l(`table`,tt,[l(`tbody`,null,[c[21]||=l(`tr`,{class:`text-xs text-muted`},[l(`td`,{class:`px-2 py-1`},`thread`),l(`td`,{class:`px-2 py-1`},`ref · sha`),l(`td`,{class:`px-2 py-1`},`user · deps`),l(`td`,{class:`px-2 py-1`},`bound · last attach`)],-1),(o(!0),u(n,null,d(X.value,e=>(o(),u(`tr`,{key:e.threadKey,class:`border-t border-muted`},[l(`td`,nt,[e.evicted?(o(),u(`span`,rt,[a(`evicted `+p(e.evictedAt||`—`),1),e.evictedWhy?(o(),u(n,{key:0},[a(` · `+p(e.evictedWhy),1)],64)):ee(``,!0)])):(o(),i(m,{key:1,tone:`green`,label:`live`,tip:`live`})),a(` `+p(e.threadKey),1)]),l(`td`,it,[a(p(e.ref)+` · `,1),e.commitHref?(o(),u(`a`,{key:0,class:`text-primary`,href:e.commitHref},p(e.sha),9,at)):e.sha?(o(),u(`span`,ot,p(e.sha),1)):(o(),u(`span`,st,`—`))]),l(`td`,ct,[e.user?(o(),u(`span`,lt,p(e.user),1)):(o(),u(`span`,ut,`—`)),c[19]||=a(` · `,-1),e.deps?(o(),u(`span`,dt,p(e.deps),1)):(o(),u(`span`,ft,`—`))]),l(`td`,pt,[e.boundAt?(o(),u(`span`,mt,p(e.boundAt),1)):(o(),u(`span`,ht,`—`)),c[20]||=a(` · `,-1),e.lastAttachAt?(o(),u(`span`,gt,p(e.lastAttachAt),1)):(o(),u(`span`,_t,`—`))])]))),128))])])])],64)):(o(),u(`p`,vt,`no thread worktrees`))]),l(`section`,yt,[c[23]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Pending schedules`,-1),l(`table`,bt,[l(`tbody`,null,[(o(),u(n,null,d([[`refresh`,`refresh`],[`provision run`,`provisionRun`],[`provision deadline`,`provisionDeadline`]],([e,t])=>l(`tr`,{key:t,class:`border-t border-muted`},[l(`td`,xt,p(e),1),l(`td`,St,p(f(h)(zt.value[t]??0)||`0`),1)])),64))])])]),l(`section`,Ct,[c[25]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Command table`,-1),Y.value.length>0?(o(),u(`table`,wt,[l(`tbody`,null,[(o(!0),u(n,null,d(Y.value,e=>(o(),u(`tr`,{key:e.name,class:`border-t border-muted`},[l(`td`,Tt,p(e.name),1),l(`td`,Et,[l(`code`,null,p(e.command),1),c[24]||=a(),l(`span`,Dt,p(e.effect),1)])]))),128))])])):(o(),u(`p`,Ot,`no command table`))]),l(`section`,kt,[c[26]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Registry settings`,-1),l(`table`,At,[l(`tbody`,null,[(o(!0),u(n,null,d([[`onboarded`,f(h)(H.value.onboardedAt)],[`record updated`,f(h)(H.value.updatedAt)],[`provisioning timeout (ms)`,f(h)(H.value.provisioningTimeoutMs)],[`disk budget (MB)`,f(h)(H.value.diskBudgetMb)],[`worktree TTL (days)`,f(h)(H.value.worktreeTtlDays??7)]],([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,jt,p(e),1),l(`td`,Mt,[t?(o(),u(`span`,Nt,p(t),1)):(o(),u(`span`,Pt,`—`))])]))),128))])])]),l(`p`,Ft,[c[27]||=a(` Manage from chat: `,-1),l(`code`,It,`repo rebuild `+p(W.value),1),c[28]||=a(` · `,-1),l(`code`,Lt,`repo reconfigure `+p(W.value)+` …`,1),c[29]||=a(` · `,-1),l(`code`,Rt,`repo offboard `+p(W.value)+` --dry-run`,1)])]),_:1},8,[`title`]))}});export{V as default};
|
|
1
|
+
import{t as e}from"./AppShell-lYVcj-k7.js";import{Lr as t,Xt as n,_n as r,cn as i,gn as a,ir as o,ln as ee,on as s,r as c,sn as l,un as u,ur as d,vi as f,wi as p,yn as te}from"./seed-DeKSHrt2.js";import{t as m}from"./StatusDot-W2x3d782.js";import{a as ne,c as re,d as ie,f as h,i as g,l as ae,n as oe,o as se,r as ce,s as _,t as le,u as ue}from"./residentDiskBudget-BMBKlYRH.js";var de={class:`mt-4 first:mt-0`},fe={class:`w-full border-collapse font-mono text-[0.8125rem]`},pe={class:`border-t border-muted`},me={class:`px-2 py-1 align-top`},v={class:`ml-1.5 font-medium`},y={class:`border-t border-muted`},b={class:`break-all px-2 py-1 align-top`},x={key:0},S={key:1,class:`text-dimmed`},C={class:`border-t border-muted`},w={class:`break-all px-2 py-1 align-top`},T={key:0},E={key:1,class:`text-dimmed`},D={class:`border-t border-muted`},O={class:`break-all px-2 py-1 align-top`},k={key:0},A={key:1,class:`text-dimmed`},j={class:`border-t border-muted`},M={class:`break-all px-2 py-1 align-top`},N={key:0},P={key:1,class:`text-dimmed`},F={class:`border-t border-muted`},I={class:`break-all px-2 py-1 align-top`},L={key:1,class:`text-dimmed`},R={class:`mt-4`},z={class:`w-full border-collapse font-mono text-[0.8125rem]`},he={class:`border-t border-muted`},ge={class:`break-all px-2 py-1 align-top`},_e=[`href`],ve={key:1},ye={class:`border-t border-muted`},be={class:`break-all px-2 py-1 align-top`},xe={class:`border-t border-muted`},Se={class:`break-all px-2 py-1 align-top`},Ce=[`href`],we={key:1},Te={key:2,class:`text-dimmed`},Ee={class:`border-t border-muted`},De={class:`break-all px-2 py-1 align-top`},Oe={key:0},ke={key:1,class:`text-dimmed`},Ae={class:`border-t border-muted`},je={class:`break-all px-2 py-1 align-top`},Me={key:0},Ne={key:1,class:`text-dimmed`},Pe={class:`border-t border-muted`},Fe={class:`break-all px-2 py-1 align-top`},Ie={key:0},Le={key:1,class:`text-dimmed`},Re={class:`mt-4`},ze={class:`w-full border-collapse font-mono text-[0.8125rem]`},Be={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Ve={class:`break-all px-2 py-1 align-top`},He={class:`w-full border-collapse font-mono text-[0.8125rem]`},Ue={class:`w-32 break-all px-2 py-1 align-top text-muted sm:w-96 sm:break-words`},We={class:`px-2 py-1 align-top`},Ge={key:1,class:`text-xs text-muted`},Ke={class:`mt-4`},qe={key:0,class:`w-full border-collapse font-mono text-[0.8125rem]`},Je={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Ye={class:`break-all px-2 py-1 align-top`},Xe={key:0},B={key:1,class:`text-dimmed`},Ze={key:1,class:`text-xs text-muted`},Qe={class:`mt-4`},$e={class:`mb-1 text-xs text-muted`},et={class:`overflow-x-auto`},tt={class:`w-full border-collapse font-mono text-[0.8125rem]`},nt={class:`break-all px-2 py-1 align-top`},rt={key:0,class:`text-xs text-muted`},it={class:`break-all px-2 py-1 align-top`},at=[`href`],ot={key:1},st={key:2,class:`text-dimmed`},ct={class:`break-all px-2 py-1 align-top`},lt={key:0},ut={key:1,class:`text-dimmed`},dt={key:2},ft={key:3,class:`text-dimmed`},pt={class:`break-all px-2 py-1 align-top`},mt={key:0},ht={key:1,class:`text-dimmed`},gt={key:2},_t={key:3,class:`text-dimmed`},vt={key:1,class:`text-xs text-muted`},yt={class:`mt-4`},bt={class:`w-full border-collapse font-mono text-[0.8125rem]`},xt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},St={class:`px-2 py-1 align-top`},Ct={class:`mt-4`},wt={key:0,class:`w-full border-collapse font-mono text-[0.8125rem]`},Tt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Et={class:`break-all px-2 py-1 align-top`},Dt={class:`text-xs text-muted`},Ot={key:1,class:`text-xs text-muted`},kt={class:`mt-4`},At={class:`w-full border-collapse font-mono text-[0.8125rem]`},jt={class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},Mt={class:`break-all px-2 py-1 align-top`},Nt={key:0},Pt={key:1,class:`text-dimmed`},Ft={class:`mt-4 text-xs text-muted`},It={class:`rounded bg-elevated px-1 py-0.5`},Lt={class:`rounded bg-elevated px-1 py-0.5`},Rt={class:`rounded bg-elevated px-1 py-0.5`},V=te({__name:`ResidentDetailPage`,setup(te){let V=c(`resident`),H=s(()=>V?.record??{}),U=s(()=>ae(H.value)),W=s(()=>ue(H.value)||(V?.slug??``)),G=s(()=>h(U.value.sha)),K=s(()=>se.test(W.value)?`https://github.com/${W.value}`:void 0),q=s(()=>K.value&&/^[0-9a-f]{7,40}$/.test(G.value)?`${K.value}/commit/${G.value}`:void 0),J=s(()=>{let e=U.value.snapshot;return e&&typeof e==`object`?_(e):void 0}),zt=s(()=>_(U.value.schedules)),Y=s(()=>{let e=_(H.value.commands),t=_(H.value.effects);return Object.keys(e).sort().map(n=>({name:n,command:h(e[n]),effect:h(t[n])||`readonly`}))}),X=s(()=>{let e=U.value.threads;return(Array.isArray(e)?e.map(_):[]).map(e=>{let t=h(e.sha);return{threadKey:h(e.threadKey)||`?`,ref:h(e.ref)||`?`,sha:t?t.slice(0,8):``,commitHref:K.value&&/^[0-9a-f]{7,40}$/.test(t)?`${K.value}/commit/${t}`:void 0,user:h(e.user),deps:h(e.deps),boundAt:h(e.boundAt),lastAttachAt:h(e.lastAttachAt),evicted:e.evicted===!0,evictedAt:h(e.evictedAt),evictedWhy:h(e.evictedWhy)}}).sort((e,t)=>t.lastAttachAt.localeCompare(e.lastAttachAt))}),Z=s(()=>X.value.filter(e=>!e.evicted).length),Q=s(()=>{let e=U.value.lastRestore;return e?JSON.stringify(e):``}),$=s(()=>re(H.value)),Bt=s(()=>typeof H.value.diskBudgetMb==`number`?H.value.diskBudgetMb:void 0),Vt=s(()=>{let e=$.value;if(!e)return[];let t=le(e),{freeKiB:n,capped:r,capacityKiB:i}=oe(e,Bt.value),a=n-t.totalKiB,o=t=>{let n=ne(e.parts,t);return n===null?`? (checkout not measured)`:n===0?`?`:`${Math.max(0,Math.floor(a/n))} more (${g(n)} each)`};return[[`used / total`,ce(e)],[`free`,`${g(n)}${r?` under the ${g(i)} diskBudgetMb cap`:``}`],[`reserve`,`${g(t.totalKiB)} (snapshot staging ${g(t.stagingKiB)} + floor ${g(t.floorKiB)})`],[`headroom`,`${g(Math.max(0,a))} — room for ${o(`hardlink`)} hardlinked trees, ${o(`reconcile`)} lockfile-diverged (reconciling)`],[`measured`,e.at||`—`]]}),Ht=s(()=>{let e=$.value;if(!e)return[];let t=[[`mirror`,g(e.parts.mirror)],[`checkout deps (node_modules)`,g(e.parts.deps)],[`checkout (history + tree + build)`,g(e.parts.checkout)]];for(let[n,r]of Object.entries(e.parts.threads).sort((e,t)=>t[1]-e[1]))t.push([`thread ${n}`,g(r)]);for(let[n,r]of Object.entries(e.parts.homes).sort((e,t)=>t[1]-e[1]))r>=1024&&t.push([`home ${n}`,g(r)]);return t.push([`other (image, /tmp, …)`,g(e.parts.other)]),t});return(s,c)=>(o(),i(e,{title:W.value||`Resident`,nav:`residents`},{leading:t(()=>[...c[0]||=[l(`a`,{class:`back text-sm text-muted no-underline hover:text-primary`,href:`/residents`},`← All residents`,-1)]]),default:t(()=>[l(`section`,de,[c[8]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Lifecycle`,-1),l(`table`,fe,[l(`tbody`,null,[l(`tr`,pe,[c[1]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`state`,-1),l(`td`,me,[r(m,{tone:f(ie)(U.value.state),label:U.value.state},null,8,[`tone`,`label`]),l(`span`,v,p(U.value.state),1)])]),l(`tr`,y,[c[2]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`reason`,-1),l(`td`,b,[U.value.reason?(o(),u(`span`,x,p(U.value.reason),1)):(o(),u(`span`,S,`—`))])]),l(`tr`,C,[c[3]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last refresh error`,-1),l(`td`,w,[f(h)(U.value.lastRefreshError)?(o(),u(`span`,T,p(f(h)(U.value.lastRefreshError)),1)):(o(),u(`span`,E,`—`))])]),l(`tr`,D,[c[4]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last restore`,-1),l(`td`,O,[Q.value?(o(),u(`span`,k,p(Q.value),1)):(o(),u(`span`,A,`—`))])]),l(`tr`,j,[c[5]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`state updated`,-1),l(`td`,M,[f(h)(U.value.updatedAt)?(o(),u(`span`,N,p(f(h)(U.value.updatedAt)),1)):(o(),u(`span`,P,`—`))])]),l(`tr`,F,[c[7]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`idle since`,-1),l(`td`,I,[f(h)(U.value.idleSince)?(o(),u(n,{key:0},[a(p(f(h)(U.value.idleSince))+` `,1),c[6]||=l(`span`,{class:`text-xs text-muted`},`(refresh parked; container may sleep)`,-1)],64)):(o(),u(`span`,L,`awake`))])])])])]),l(`section`,R,[c[15]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Pinned facts`,-1),l(`table`,z,[l(`tbody`,null,[l(`tr`,he,[c[9]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`repository`,-1),l(`td`,ge,[K.value?(o(),u(`a`,{key:0,class:`text-primary`,href:K.value},p(K.value),9,_e)):(o(),u(`span`,ve,p(f(h)(H.value.resource)||`—`),1))])]),l(`tr`,ye,[c[10]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`default ref`,-1),l(`td`,be,p(f(h)(U.value.defaultRef)||f(h)(H.value.defaultRef)||`—`),1)]),l(`tr`,xe,[c[11]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`pinned sha`,-1),l(`td`,Se,[q.value?(o(),u(`a`,{key:0,class:`text-primary`,href:q.value},p(G.value),9,Ce)):G.value?(o(),u(`span`,we,p(G.value),1)):(o(),u(`span`,Te,`—`))])]),l(`tr`,Ee,[c[12]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`lockfile hash`,-1),l(`td`,De,[f(h)(U.value.lockfileHash)?(o(),u(`span`,Oe,p(f(h)(U.value.lockfileHash)),1)):(o(),u(`span`,ke,`—`))])]),l(`tr`,Ae,[c[13]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`provisioned`,-1),l(`td`,je,[f(h)(U.value.provisionedAt)?(o(),u(`span`,Me,p(f(h)(U.value.provisionedAt)),1)):(o(),u(`span`,Ne,`—`))])]),l(`tr`,Pe,[c[14]||=l(`td`,{class:`w-32 px-2 py-1 align-top text-muted sm:w-48 sm:whitespace-nowrap`},`last refresh`,-1),l(`td`,Fe,[f(h)(U.value.lastRefreshAt)?(o(),u(`span`,Ie,p(f(h)(U.value.lastRefreshAt)),1)):(o(),u(`span`,Le,`—`))])])])])]),l(`section`,Re,[c[17]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Disk`,-1),$.value?(o(),u(n,{key:0},[l(`table`,ze,[l(`tbody`,null,[(o(!0),u(n,null,d(Vt.value,([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Be,p(e),1),l(`td`,Ve,p(t),1)]))),128))])]),c[16]||=l(`p`,{class:`mb-1 mt-2 text-xs text-muted`},` components (one du, hardlinks counted once — a thread tree shows only what it does not share with the checkout) `,-1),l(`table`,He,[l(`tbody`,null,[(o(!0),u(n,null,d(Ht.value,([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Ue,p(e),1),l(`td`,We,p(t),1)]))),128))])])],64)):(o(),u(`p`,Ge,` not measured yet — the first refresh cycle or attach of this container measures it `))]),l(`section`,Ke,[c[18]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Snapshot stamp`,-1),J.value?(o(),u(`table`,qe,[l(`tbody`,null,[(o(),u(n,null,d([`ref`,`sha`,`lockfileHash`,`createdAt`,`mirrorBackupId`,`checkoutBackupId`],e=>l(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,Je,p(e),1),l(`td`,Ye,[f(h)(J.value[e])?(o(),u(`span`,Xe,p(f(h)(J.value[e])),1)):(o(),u(`span`,B,`—`))])])),64))])])):(o(),u(`p`,Ze,`no snapshot recorded`))]),l(`section`,Qe,[c[22]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Thread worktrees`,-1),X.value.length>0?(o(),u(n,{key:0},[l(`p`,$e,p(Z.value)+` live · `+p(X.value.length-Z.value)+` evicted`,1),l(`div`,et,[l(`table`,tt,[l(`tbody`,null,[c[21]||=l(`tr`,{class:`text-xs text-muted`},[l(`td`,{class:`px-2 py-1`},`thread`),l(`td`,{class:`px-2 py-1`},`ref · sha`),l(`td`,{class:`px-2 py-1`},`user · deps`),l(`td`,{class:`px-2 py-1`},`bound · last attach`)],-1),(o(!0),u(n,null,d(X.value,e=>(o(),u(`tr`,{key:e.threadKey,class:`border-t border-muted`},[l(`td`,nt,[e.evicted?(o(),u(`span`,rt,[a(`evicted `+p(e.evictedAt||`—`),1),e.evictedWhy?(o(),u(n,{key:0},[a(` · `+p(e.evictedWhy),1)],64)):ee(``,!0)])):(o(),i(m,{key:1,tone:`green`,label:`live`,tip:`live`})),a(` `+p(e.threadKey),1)]),l(`td`,it,[a(p(e.ref)+` · `,1),e.commitHref?(o(),u(`a`,{key:0,class:`text-primary`,href:e.commitHref},p(e.sha),9,at)):e.sha?(o(),u(`span`,ot,p(e.sha),1)):(o(),u(`span`,st,`—`))]),l(`td`,ct,[e.user?(o(),u(`span`,lt,p(e.user),1)):(o(),u(`span`,ut,`—`)),c[19]||=a(` · `,-1),e.deps?(o(),u(`span`,dt,p(e.deps),1)):(o(),u(`span`,ft,`—`))]),l(`td`,pt,[e.boundAt?(o(),u(`span`,mt,p(e.boundAt),1)):(o(),u(`span`,ht,`—`)),c[20]||=a(` · `,-1),e.lastAttachAt?(o(),u(`span`,gt,p(e.lastAttachAt),1)):(o(),u(`span`,_t,`—`))])]))),128))])])])],64)):(o(),u(`p`,vt,`no thread worktrees`))]),l(`section`,yt,[c[23]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Pending schedules`,-1),l(`table`,bt,[l(`tbody`,null,[(o(),u(n,null,d([[`refresh`,`refresh`],[`provision run`,`provisionRun`],[`provision deadline`,`provisionDeadline`]],([e,t])=>l(`tr`,{key:t,class:`border-t border-muted`},[l(`td`,xt,p(e),1),l(`td`,St,p(f(h)(zt.value[t]??0)||`0`),1)])),64))])])]),l(`section`,Ct,[c[25]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Command table`,-1),Y.value.length>0?(o(),u(`table`,wt,[l(`tbody`,null,[(o(!0),u(n,null,d(Y.value,e=>(o(),u(`tr`,{key:e.name,class:`border-t border-muted`},[l(`td`,Tt,p(e.name),1),l(`td`,Et,[l(`code`,null,p(e.command),1),c[24]||=a(),l(`span`,Dt,p(e.effect),1)])]))),128))])])):(o(),u(`p`,Ot,`no command table`))]),l(`section`,kt,[c[26]||=l(`h2`,{class:`mb-1.5 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Registry settings`,-1),l(`table`,At,[l(`tbody`,null,[(o(!0),u(n,null,d([[`onboarded`,f(h)(H.value.onboardedAt)],[`record updated`,f(h)(H.value.updatedAt)],[`provisioning timeout (ms)`,f(h)(H.value.provisioningTimeoutMs)],[`disk budget (MB)`,f(h)(H.value.diskBudgetMb)],[`worktree TTL (days)`,f(h)(H.value.worktreeTtlDays??7)]],([e,t])=>(o(),u(`tr`,{key:e,class:`border-t border-muted`},[l(`td`,jt,p(e),1),l(`td`,Mt,[t?(o(),u(`span`,Nt,p(t),1)):(o(),u(`span`,Pt,`—`))])]))),128))])])]),l(`p`,Ft,[c[27]||=a(` Manage from chat: `,-1),l(`code`,It,`repo rebuild `+p(W.value),1),c[28]||=a(` · `,-1),l(`code`,Lt,`repo reconfigure `+p(W.value)+` …`,1),c[29]||=a(` · `,-1),l(`code`,Rt,`repo offboard `+p(W.value)+` --dry-run`,1)])]),_:1},8,[`title`]))}});export{V as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./AppShell-lYVcj-k7.js";import{Lr as t,Xt as n,_n as r,cn as i,gn as a,ir as o,ln as s,mr as c,on as l,r as u,sn as d,un as f,ur as p,wi as m,xi as h,yn as g}from"./seed-DeKSHrt2.js";import{n as _}from"./wallClock-61NpVkY6.js";import{t as v}from"./StatusDot-
|
|
1
|
+
import{t as e}from"./AppShell-lYVcj-k7.js";import{Lr as t,Xt as n,_n as r,cn as i,gn as a,ir as o,ln as s,mr as c,on as l,r as u,sn as d,un as f,ur as p,wi as m,xi as h,yn as g}from"./seed-DeKSHrt2.js";import{n as _}from"./wallClock-61NpVkY6.js";import{t as v}from"./StatusDot-W2x3d782.js";import{c as y,d as b,f as x,l as S,o as C,r as w,u as T}from"./residentDiskBudget-BMBKlYRH.js";import{n as E}from"./indexFormat-B-pd4r7Y.js";var D={class:`mb-2 text-xs text-muted`},O={class:`m-0 list-none p-0`},k={class:`font-mono font-medium text-primary`},A={class:`font-medium`},j=[`title`],M=[`title`],N={key:0,class:`basis-full pl-5 text-xs text-warn`},P={key:1,class:`px-2 py-1.5 text-muted`},F=g({__name:`ResidentsIndexPage`,setup(g){let F=u(`residents`),I=_(),L=l(()=>(F?.residents??[]).map((e,t)=>{let n=e,r=T(n),i=S(n),a=x(i.sha),o=x(i.lastRefreshAt),s=o?Date.parse(o):NaN,c=y(n);return{key:`${r||`?`}-${t}`,display:r||x(n.resource)||`?`,state:i.state,tone:b(i.state),reason:i.reason,ref:x(n.defaultRef)||`?`,sha:a?a.slice(0,8):``,refreshed:o,refreshedLabel:Number.isFinite(s)?E(s,I):o,disk:c?w(c):``,diskAt:c?.at??``,href:C.test(r)?`/residents/${r}`:null}})),R=l(()=>x(F?.cap)||`?`),z=l(()=>x(F?.count)||String(L.value.length));return(l,u)=>(o(),i(e,{title:`Resident repos`,nav:`residents`},{default:t(()=>[L.value.length>0?(o(),f(n,{key:0},[d(`p`,D,m(z.value)+`/`+m(R.value)+` resident slots in use · live registry read, not cached `,1),d(`ul`,O,[(o(!0),f(n,null,p(L.value,e=>(o(),f(`li`,{key:e.key,class:`border-b border-muted first:border-t`},[(o(),i(c(e.href?`a`:`span`),{class:h([`row flex flex-wrap items-center gap-2.5 rounded-md px-2 py-1.5 text-inherit no-underline`,e.href?`hover:bg-elevated`:``]),href:e.href??void 0},{default:t(()=>[r(v,{tone:e.tone,label:e.state,tip:e.state},null,8,[`tone`,`label`,`tip`]),d(`span`,k,m(e.display),1),d(`span`,A,m(e.state),1),d(`span`,{class:`font-mono text-xs text-muted max-sm:basis-full max-sm:pl-5`,title:e.refreshed||void 0},[a(` ref `+m(e.ref),1),e.sha?(o(),f(n,{key:0},[a(` · sha `+m(e.sha),1)],64)):s(``,!0),e.refreshedLabel?(o(),f(n,{key:1},[a(` · refreshed `+m(e.refreshedLabel),1)],64)):s(``,!0),e.disk?(o(),f(n,{key:2},[u[0]||=a(` · `,-1),d(`span`,{title:e.diskAt?`measured ${e.diskAt}`:void 0},`disk `+m(e.disk),9,M)],64)):s(``,!0)],8,j),e.reason?(o(),f(`span`,N,m(e.reason),1)):s(``,!0)]),_:2},1032,[`class`,`href`]))]))),128))])],64)):(o(),f(`p`,P,[a(` No repos onboarded (0/`+m(R.value)+`). Onboard one from chat: `,1),u[1]||=d(`code`,{class:`rounded bg-elevated px-1.5 py-0.5`},`repo onboard <owner/name>`,-1),u[2]||=a(`. `,-1)]))]),_:1}))}});export{F as default};
|