@coreplane/switchboard 1.226.0 → 1.227.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 +238 -8
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +7 -0
- package/dist/assets/deploy/cloudflare-sandbox/runtime-supervisor.sh +67 -0
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +49 -0
- 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/core/authz/policy.ts +8 -0
- package/dist/assets/src/core/runEvents.ts +16 -2
- package/dist/assets/src/core/runRecord.ts +61 -0
- package/dist/assets/src/execution/residentRebind.ts +233 -0
- package/dist/assets/src/execution/residentSteps.ts +1 -0
- package/dist/assets/src/execution/sandboxErrors.ts +99 -0
- package/dist/assets/web/dist/.vite/manifest.json +18 -18
- package/dist/assets/web/dist/assets/{ResidentDetailPage-BBOpejGX.js → ResidentDetailPage-Chvll3wy.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-B8kFWHpB.js → ResidentsIndexPage-B5f8IwGF.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-COWeVtIE.js → RunRoutePage-CRvmCuXh.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-BjH93cKx.js → RunsIndexPage-BTJuKFTv.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-grlNKvCA.js → ScheduledPage-BVfgUBvP.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-BQNoaXO6.js → StatusDot-CFXbAw7S.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-DVCeIzaa.js → Tooltip-DcHMtbHJ.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-B5Wfk-oY.js → dist-DKhqHu0V.js} +1 -1
- package/dist/assets/web/dist/assets/{main-CN0U7d6s.js → main-CveRd2yk.js} +2 -2
- package/dist/cli.js +470 -190
- package/package.json +1 -1
|
@@ -126,6 +126,15 @@ export interface RunRecord {
|
|
|
126
126
|
* (docs/reference/specs/agent-ship.md item 6), the last call's set, redacted;
|
|
127
127
|
* present only on a coding run dispatched as a fix round that submitted one. */
|
|
128
128
|
dispositions?: FindingDisposition[];
|
|
129
|
+
/** The router's decision the run ran under (docs/reference/specs/routing-and-config.md
|
|
130
|
+
* item 21): the preset, the one-line reason and the model that decided —
|
|
131
|
+
* the run's own route, or, on a sticky-by-transcript follow-up that
|
|
132
|
+
* continued a routed thread, the thread's decision carried forward (parts
|
|
133
|
+
* and a collapse are the routed run's alone, never carried). On the record
|
|
134
|
+
* so the next follow-up's card can keep the `routed:` receipt without
|
|
135
|
+
* reading the events. Absent for a preset a person, a scope or the default
|
|
136
|
+
* chose, and on records written before it existed. */
|
|
137
|
+
route?: RunRouteDecision;
|
|
129
138
|
/** The effective profile the run was admitted with (docs/decisions/0026-capability-profiles-and-request-routing.md):
|
|
130
139
|
* the preset, its machine class and identity, the minutes it ran on and —
|
|
131
140
|
* when a boundary clipped the budget — the scope that did, so a reader can
|
|
@@ -181,6 +190,55 @@ export function prOfEvents(events: readonly RunEvent[]): RunPullRequest | undefi
|
|
|
181
190
|
return pr;
|
|
182
191
|
}
|
|
183
192
|
|
|
193
|
+
/** The router's decision as a record carries it — the same fields the
|
|
194
|
+
* `route` event and the ledger row's `meta.route` carry (routing-and-config
|
|
195
|
+
* item 21). */
|
|
196
|
+
export interface RunRouteDecision {
|
|
197
|
+
preset: string;
|
|
198
|
+
reason: string;
|
|
199
|
+
model: string;
|
|
200
|
+
parts?: { preset: string; text: string }[];
|
|
201
|
+
collapsed?: { presets: string[] };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** The route the run's events say it ran under: the `route` event, counted
|
|
205
|
+
* only when `run_meta.agentSource` is `route` — a rejected compound leaves a
|
|
206
|
+
* `route` event on a run that ran on the default, and that is no route
|
|
207
|
+
* (the same rule the boot reclaim applies). */
|
|
208
|
+
export function routeOfEvents(events: readonly RunEvent[]): RunRouteDecision | undefined {
|
|
209
|
+
const meta = events.find((e) => e.type === "run_meta");
|
|
210
|
+
if (meta?.type !== "run_meta" || meta.agentSource !== "route") return undefined;
|
|
211
|
+
const r = events.find((e) => e.type === "route");
|
|
212
|
+
if (r?.type !== "route") return undefined;
|
|
213
|
+
return {
|
|
214
|
+
preset: r.preset,
|
|
215
|
+
reason: r.reason,
|
|
216
|
+
model: r.model,
|
|
217
|
+
...(r.parts ? { parts: r.parts.map((p) => ({ preset: p.preset, text: p.text })) } : {}),
|
|
218
|
+
...(r.collapsed ? { collapsed: { presets: [...r.collapsed.presets] } } : {}),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function isRunRouteShape(v: unknown): v is RunRouteDecision {
|
|
223
|
+
if (typeof v !== "object" || v === null) return false;
|
|
224
|
+
const r = v as Record<string, unknown>;
|
|
225
|
+
if (typeof r.preset !== "string" || typeof r.reason !== "string" || typeof r.model !== "string") return false;
|
|
226
|
+
if (r.parts !== undefined) {
|
|
227
|
+
if (!Array.isArray(r.parts)) return false;
|
|
228
|
+
for (const p of r.parts) {
|
|
229
|
+
if (typeof p !== "object" || p === null) return false;
|
|
230
|
+
const part = p as Record<string, unknown>;
|
|
231
|
+
if (typeof part.preset !== "string" || typeof part.text !== "string") return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (r.collapsed !== undefined) {
|
|
235
|
+
const c = r.collapsed as Record<string, unknown>;
|
|
236
|
+
if (typeof c !== "object" || c === null) return false;
|
|
237
|
+
if (!Array.isArray(c.presets) || !c.presets.every((p) => typeof p === "string")) return false;
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
|
|
184
242
|
function isRunPullRequestShape(v: unknown): v is RunPullRequest {
|
|
185
243
|
if (typeof v !== "object" || v === null) return false;
|
|
186
244
|
const p = v as Record<string, unknown>;
|
|
@@ -606,6 +664,9 @@ export function isRunRecord(v: unknown): v is RunRecord {
|
|
|
606
664
|
return false;
|
|
607
665
|
if (r.dispositions !== undefined && !isFindingDispositionsShape(r.dispositions)) return false;
|
|
608
666
|
if (r.reviewPost !== undefined && !isReviewPostShape(r.reviewPost)) return false;
|
|
667
|
+
// The route the run ran under (routing-and-config item 21): shape only, like
|
|
668
|
+
// the handoff — the reason was redacted and capped when it was decided.
|
|
669
|
+
if (r.route !== undefined && !isRunRouteShape(r.route)) return false;
|
|
609
670
|
if (r.profile !== undefined && !isRunProfileRecord(r.profile)) return false;
|
|
610
671
|
// The pull request the run reached (item 2): a positive integer and a URL, or absent.
|
|
611
672
|
if (r.pr !== undefined && !isRunPullRequestShape(r.pr)) return false;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/** The one exception to the resident's sticky ref binding
|
|
2
|
+
* (deploy/cloudflare-resident/worker.ts `attachThreadBody`), kept pure and
|
|
3
|
+
* dependency-free so it is unit-testable from src/ and imported by the
|
|
4
|
+
* resident Worker like residentReuse and residentHead: the tested code IS the
|
|
5
|
+
* shipped code.
|
|
6
|
+
*
|
|
7
|
+
* Background: a thread's first attach binds a ref, and every later attach in
|
|
8
|
+
* the thread keeps it — a differing hint is ignored, so a stray word can never
|
|
9
|
+
* move a thread onto a stranger's branch. That rule has one blind spot: a
|
|
10
|
+
* thread bound to the repo default because its first message named no branch,
|
|
11
|
+
* whose own run then created a branch, pushed it and opened a pull request.
|
|
12
|
+
* The follow-up's target resolution binds that branch (the thread's own PR,
|
|
13
|
+
* docs/reference/specs/resident-repos.md item 29), the resident ignores it, and
|
|
14
|
+
* the follow-up runs on the default branch while the thread's work sits on
|
|
15
|
+
* the branch it made — a push from there would land on the default.
|
|
16
|
+
*
|
|
17
|
+
* Shape: the caller names the reason for its hint (`ownPr`: the pull request
|
|
18
|
+
* the thread's own run opened and its head branch — never a PR a person
|
|
19
|
+
* named). The resident moves the binding only when all of these hold:
|
|
20
|
+
* - the binding was made by default (the first message named no branch), read
|
|
21
|
+
* off `boundBy`, or, for a binding made before that field, off whether the
|
|
22
|
+
* ref is the default branch — a ref a person named is never moved;
|
|
23
|
+
* - the thread was not rebound before — a thread moves once;
|
|
24
|
+
* - the branch is a local branch of the thread's OWN worktree — the physical
|
|
25
|
+
* fact that this thread's run created it; a branch the tree never made is
|
|
26
|
+
* refused whatever the caller says;
|
|
27
|
+
* - the tree has no uncommitted tracked changes — never at the cost of work.
|
|
28
|
+
* The move is a `git checkout` inside the existing tree: same path, same pool
|
|
29
|
+
* user, deps and snapshot lineage untouched. Every refusal is named in the
|
|
30
|
+
* attach answer so the bot can say why the follow-up runs where it does. */
|
|
31
|
+
|
|
32
|
+
/** The pull request the thread's own run opened, and its head branch — the
|
|
33
|
+
* reason a caller's refHint is that branch. */
|
|
34
|
+
export interface OwnPr {
|
|
35
|
+
number: number;
|
|
36
|
+
ref: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type ParsedOwnPr = { ownPr: OwnPr | null } | { error: string };
|
|
40
|
+
|
|
41
|
+
const OWN_PR_ERROR = "ownPr must be {number: <positive integer>, ref: <branch>} when present";
|
|
42
|
+
|
|
43
|
+
/** `/attach` body field `ownPr`: absent → null (the body every bot always
|
|
44
|
+
* sent); `{number, ref}` with a positive integer and a non-empty string →
|
|
45
|
+
* itself; anything else → a 400-shaped error. The ref's PATTERN is the
|
|
46
|
+
* Worker's to check, where it checks every ref (`parseRef`), before the
|
|
47
|
+
* string can become a git argument. */
|
|
48
|
+
export function parseOwnPr(value: unknown): ParsedOwnPr {
|
|
49
|
+
if (value === undefined) return { ownPr: null };
|
|
50
|
+
if (typeof value !== "object" || value === null) return { error: OWN_PR_ERROR };
|
|
51
|
+
const { number, ref } = value as { number?: unknown; ref?: unknown };
|
|
52
|
+
if (typeof number !== "number" || !Number.isSafeInteger(number) || number <= 0) return { error: OWN_PR_ERROR };
|
|
53
|
+
if (typeof ref !== "string" || ref.length === 0) return { error: OWN_PR_ERROR };
|
|
54
|
+
return { ownPr: { number, ref } };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type ParsedRefByDefault = { refByDefault: boolean } | { error: string };
|
|
58
|
+
|
|
59
|
+
/** `/attach` body field `refByDefault`: the caller bound the resident's own
|
|
60
|
+
* default branch because its message named none (item 30). Absent → false; a
|
|
61
|
+
* boolean → itself; anything else → a 400-shaped error. */
|
|
62
|
+
export function parseRefByDefault(value: unknown): ParsedRefByDefault {
|
|
63
|
+
if (value === undefined) return { refByDefault: false };
|
|
64
|
+
if (typeof value === "boolean") return { refByDefault: value };
|
|
65
|
+
return { error: "refByDefault must be a boolean when present" };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** How a binding's ref was chosen: the repo default for want of a named
|
|
69
|
+
* branch, or a branch someone named. */
|
|
70
|
+
export type BoundBy = "default" | "name";
|
|
71
|
+
|
|
72
|
+
/** What a NEW binding records: `default` only when the caller said it bound
|
|
73
|
+
* the default for want of a name AND the ref is that default — a flag on any
|
|
74
|
+
* other ref is a caller bug, and `name` is the direction that never moves. */
|
|
75
|
+
export function boundByFor(input: { refByDefault: boolean; ref: string; defaultRef: string }): BoundBy {
|
|
76
|
+
return input.refByDefault && input.ref === input.defaultRef ? "default" : "name";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** How an EXISTING binding's ref was chosen: the recorded value, or, for a
|
|
80
|
+
* binding made before the field, `default` iff its ref is the default branch. */
|
|
81
|
+
export function boundByOf(binding: { ref: string; boundBy?: BoundBy }, defaultRef: string): BoundBy {
|
|
82
|
+
return binding.boundBy ?? (binding.ref === defaultRef ? "default" : "name");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The record a rebind leaves on the binding and in the attach answer. */
|
|
86
|
+
export interface Rebound {
|
|
87
|
+
from: string;
|
|
88
|
+
to: string;
|
|
89
|
+
pr: number;
|
|
90
|
+
at: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type RebindRefusal = "named-ref" | "already-rebound" | "branch-absent" | "dirty" | "checkout-failed";
|
|
94
|
+
|
|
95
|
+
/** Why the binding stood, in the attach answer: the branch it was asked to
|
|
96
|
+
* move to, the pull request, the reason and its sentence. */
|
|
97
|
+
export interface RebindRefused {
|
|
98
|
+
to: string;
|
|
99
|
+
pr: number;
|
|
100
|
+
reason: RebindRefusal;
|
|
101
|
+
why: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** What the plan reads off the thread's binding. */
|
|
105
|
+
export interface RebindableBinding {
|
|
106
|
+
ref: string;
|
|
107
|
+
/** "" once evicted: no tree, no user to measure it as. */
|
|
108
|
+
user: string;
|
|
109
|
+
evicted?: boolean;
|
|
110
|
+
boundBy?: BoundBy;
|
|
111
|
+
rebound?: Rebound;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type RebindPlan =
|
|
115
|
+
/** No hint, no binding yet (the hint binds as any refHint), the binding is
|
|
116
|
+
* already on that branch, or a resumed run's attach. */
|
|
117
|
+
| { kind: "none" }
|
|
118
|
+
/** The binding alone rules it out; nothing on disk is consulted. */
|
|
119
|
+
| { kind: "refuse"; refused: RebindRefused }
|
|
120
|
+
/** The binding allows it; the tree decides (`rebindVerdict`). */
|
|
121
|
+
| { kind: "measure"; from: string; to: string; pr: number };
|
|
122
|
+
|
|
123
|
+
export function rebindRefused(plan: { to: string; pr: number }, reason: RebindRefusal, why: string): RebindRefused {
|
|
124
|
+
return { to: plan.to, pr: plan.pr, reason, why };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Whether the binding may move, read off the binding alone. */
|
|
128
|
+
export function rebindPlan(input: {
|
|
129
|
+
ownPr: OwnPr | null;
|
|
130
|
+
/** A resumed run's attach keeps the tree exactly as it stands (item 66): its
|
|
131
|
+
* HEAD is where the run left it and must not move under the run. */
|
|
132
|
+
reuse: boolean;
|
|
133
|
+
binding: RebindableBinding | undefined;
|
|
134
|
+
defaultRef: string;
|
|
135
|
+
}): RebindPlan {
|
|
136
|
+
const { ownPr, reuse, binding, defaultRef } = input;
|
|
137
|
+
if (ownPr === null || reuse || binding === undefined || binding.ref === ownPr.ref) return { kind: "none" };
|
|
138
|
+
const plan = { to: ownPr.ref, pr: ownPr.number };
|
|
139
|
+
if (boundByOf(binding, defaultRef) === "name") {
|
|
140
|
+
return {
|
|
141
|
+
kind: "refuse",
|
|
142
|
+
refused: rebindRefused(
|
|
143
|
+
plan,
|
|
144
|
+
"named-ref",
|
|
145
|
+
`the thread is bound to ${JSON.stringify(binding.ref)} by name; a named branch is never moved`,
|
|
146
|
+
),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (binding.rebound) {
|
|
150
|
+
const r = binding.rebound;
|
|
151
|
+
return {
|
|
152
|
+
kind: "refuse",
|
|
153
|
+
refused: rebindRefused(
|
|
154
|
+
plan,
|
|
155
|
+
"already-rebound",
|
|
156
|
+
`the thread was already rebound from ${JSON.stringify(r.from)} to ${JSON.stringify(r.to)} (its pull request #${r.pr}); a thread moves once`,
|
|
157
|
+
),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (binding.evicted || !binding.user) {
|
|
161
|
+
return {
|
|
162
|
+
kind: "refuse",
|
|
163
|
+
refused: rebindRefused(
|
|
164
|
+
plan,
|
|
165
|
+
"branch-absent",
|
|
166
|
+
"the thread's worktree was evicted; the branch cannot be verified there",
|
|
167
|
+
),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { kind: "measure", from: binding.ref, ...plan };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** What the attach measured about the thread's tree, as the thread user. Each
|
|
174
|
+
* probe past `exists` is measured only when the tree is there. */
|
|
175
|
+
export interface RebindTreeFacts {
|
|
176
|
+
/** `<worktree>/.git` is a directory. */
|
|
177
|
+
exists: boolean;
|
|
178
|
+
/** `git rev-parse --verify --quiet refs/heads/<to>` succeeded in the tree. */
|
|
179
|
+
branchExists?: boolean;
|
|
180
|
+
/** `git status --porcelain -uno` ran: false is a tree git cannot read
|
|
181
|
+
* (corrupt, or owned by an earlier pool user), where nothing is verifiable. */
|
|
182
|
+
readable?: boolean;
|
|
183
|
+
/** `git status --porcelain -uno` listed a tracked change (untracked scratch
|
|
184
|
+
* files are the thread's own state and survive a checkout). */
|
|
185
|
+
dirty?: boolean;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type RebindVerdict = { kind: "rebind" } | { kind: "refuse"; refused: RebindRefused };
|
|
189
|
+
|
|
190
|
+
/** The tree's verdict on a measured plan. */
|
|
191
|
+
export function rebindVerdict(plan: { to: string; pr: number }, tree: RebindTreeFacts): RebindVerdict {
|
|
192
|
+
if (!tree.exists) {
|
|
193
|
+
return {
|
|
194
|
+
kind: "refuse",
|
|
195
|
+
refused: rebindRefused(
|
|
196
|
+
plan,
|
|
197
|
+
"branch-absent",
|
|
198
|
+
"the thread's worktree is missing; the branch cannot be verified there",
|
|
199
|
+
),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (tree.readable === false) {
|
|
203
|
+
return {
|
|
204
|
+
kind: "refuse",
|
|
205
|
+
refused: rebindRefused(
|
|
206
|
+
plan,
|
|
207
|
+
"branch-absent",
|
|
208
|
+
"the thread's worktree cannot be read; the branch cannot be verified there",
|
|
209
|
+
),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (tree.branchExists !== true) {
|
|
213
|
+
return {
|
|
214
|
+
kind: "refuse",
|
|
215
|
+
refused: rebindRefused(
|
|
216
|
+
plan,
|
|
217
|
+
"branch-absent",
|
|
218
|
+
`${JSON.stringify(plan.to)} is not a local branch of the thread's worktree; only a branch this thread's own run made moves it`,
|
|
219
|
+
),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (tree.dirty === true) {
|
|
223
|
+
return {
|
|
224
|
+
kind: "refuse",
|
|
225
|
+
refused: rebindRefused(
|
|
226
|
+
plan,
|
|
227
|
+
"dirty",
|
|
228
|
+
"the worktree has uncommitted changes on the bound branch; the binding stands until they are committed or discarded",
|
|
229
|
+
),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return { kind: "rebind" };
|
|
233
|
+
}
|
|
@@ -18,6 +18,7 @@ export const RESIDENT_STEP_LABELS = {
|
|
|
18
18
|
"for-each-ref": "listing the branches",
|
|
19
19
|
checkout: "checking out the branch",
|
|
20
20
|
"checkout-update": "updating the checkout",
|
|
21
|
+
"rebind-checkout": "checking out the thread's own branch",
|
|
21
22
|
"rev-parse": "reading the commit",
|
|
22
23
|
"cat-file": "checking the mirror for the commit",
|
|
23
24
|
"show-ref": "reading the branch tip",
|
|
@@ -157,3 +157,102 @@ export function thrownText(shape: ThrownShape): string {
|
|
|
157
157
|
"while a Worker/image rollout is in progress — retry in a minute"
|
|
158
158
|
);
|
|
159
159
|
}
|
|
160
|
+
|
|
161
|
+
// ---- A runtime that did not answer (docs/reference/specs/execution.md item 9) ----
|
|
162
|
+
//
|
|
163
|
+
// The SDK proxies every command to the container's port through the
|
|
164
|
+
// `@cloudflare/containers` base class. When nothing answers there — the SDK's
|
|
165
|
+
// server exited (an uncaught exception ends it), or is being started again by
|
|
166
|
+
// the image's PID 1 — that class answers HTTP 500 with a plain-text body, not
|
|
167
|
+
// the JSON the SDK client expects, and the client renders it as the bare
|
|
168
|
+
// `HTTP error! status: 500`: no container, no cause, nothing a card can act
|
|
169
|
+
// on. The Worker reads the body first and names the condition instead.
|
|
170
|
+
|
|
171
|
+
/** The named reason the Worker answers with, like `fleet-busy`: a machine
|
|
172
|
+
* token the executor and the harness match on, never the SDK's text. */
|
|
173
|
+
export const RUNTIME_UNREACHABLE_REASON = "runtime-unreachable" as const;
|
|
174
|
+
|
|
175
|
+
/** The name the Worker's typed error carries across the Durable Object RPC
|
|
176
|
+
* boundary (which keeps `name`/`message` and drops the prototype). */
|
|
177
|
+
export const RUNTIME_UNREACHABLE_ERROR_NAME = "SandboxRuntimeUnreachableError";
|
|
178
|
+
|
|
179
|
+
/** The base class's two plain-text 500 bodies for a failed proxy to the
|
|
180
|
+
* container's port: the fetch itself failed (nothing listening — the server
|
|
181
|
+
* exited, or has not come back yet), and a connection lost mid-request. A
|
|
182
|
+
* JSON 500 from the server itself is neither: that server was alive. */
|
|
183
|
+
const PROXY_FAILURE_BODIES: readonly RegExp[] = [
|
|
184
|
+
/^Error proxying request to container\b/,
|
|
185
|
+
/^Container suddenly disconnected\b/,
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
export function isRuntimeProxyFailure(status: number, body: string): boolean {
|
|
189
|
+
return status === 500 && PROXY_FAILURE_BODIES.some((re) => re.test(body.trim()));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface RuntimeUnreachableFacts {
|
|
193
|
+
/** The Durable Object's id — the same word the `containers` log dataset carries as the container id. */
|
|
194
|
+
containerId: string;
|
|
195
|
+
/** The platform's view at the moment of the failure (`ctx.container.running`). */
|
|
196
|
+
running: boolean | undefined;
|
|
197
|
+
/** The Worker's `@cloudflare/sandbox` pin, which is also the image tag. */
|
|
198
|
+
sdkVersion: string;
|
|
199
|
+
/** The base class's body, verbatim: what the platform said. */
|
|
200
|
+
cause: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** The text that names the condition: the token first (the executor and the
|
|
204
|
+
* harness read it), then the facts a reader needs to find the container in
|
|
205
|
+
* the logs and to judge the command — it may not have run, and the workspace
|
|
206
|
+
* is still there because the container is. */
|
|
207
|
+
export function runtimeUnreachableMessage(f: RuntimeUnreachableFacts): string {
|
|
208
|
+
const platform = f.running === true ? "running" : f.running === false ? "stopped" : "in a state it did not report";
|
|
209
|
+
return (
|
|
210
|
+
`${RUNTIME_UNREACHABLE_REASON}: the sandbox container's runtime did not answer ` +
|
|
211
|
+
`(container ${f.containerId}, sandbox SDK ${f.sdkVersion}; the platform reports the container ${platform}) — ` +
|
|
212
|
+
"its server exited and the image's PID 1 starts it again within seconds; this command may not have run and " +
|
|
213
|
+
`/workspace is intact: wait a moment, check, then retry (${f.cause.trim() || "no detail from the platform"})`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** The Worker's typed error for a failed proxy: thrown from `containerFetch`
|
|
218
|
+
* inside the Durable Object, caught by the Worker's routes on the other side
|
|
219
|
+
* of the RPC boundary, so it is matched by name and by its message token,
|
|
220
|
+
* never by `instanceof`. */
|
|
221
|
+
export class SandboxRuntimeUnreachableError extends Error {
|
|
222
|
+
readonly reason = RUNTIME_UNREACHABLE_REASON;
|
|
223
|
+
constructor(readonly facts: RuntimeUnreachableFacts) {
|
|
224
|
+
super(runtimeUnreachableMessage(facts));
|
|
225
|
+
this.name = RUNTIME_UNREACHABLE_ERROR_NAME;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Name first, token second: the typed error after the RPC boundary, or any
|
|
230
|
+
* message that starts with the token (an executor reading a Worker's text). */
|
|
231
|
+
export function isRuntimeUnreachableError(err: unknown): boolean {
|
|
232
|
+
const s = thrownShape(err);
|
|
233
|
+
return s.name === RUNTIME_UNREACHABLE_ERROR_NAME || !!s.message?.startsWith(`${RUNTIME_UNREACHABLE_REASON}:`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** The `/read` and `/write` answer (sent as HTTP 503): the named reason and the
|
|
237
|
+
* text as the error — a 503 the executor's transport retry re-sends, which is
|
|
238
|
+
* safe: a file op that never reached a server did nothing. */
|
|
239
|
+
export function runtimeUnreachableAnswer(message: string): {
|
|
240
|
+
error: string;
|
|
241
|
+
reason: typeof RUNTIME_UNREACHABLE_REASON;
|
|
242
|
+
} {
|
|
243
|
+
return { error: message, reason: RUNTIME_UNREACHABLE_REASON };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** The `/exec` answer, in-body under the streamed HTTP 200 like every other exec
|
|
247
|
+
* failure: the dual `error` + exit-127/stderr shape (item 3) plus the reason.
|
|
248
|
+
* Never re-sent by anyone: a command in flight when the server died may have
|
|
249
|
+
* run; the text tells the model to check before it retries. */
|
|
250
|
+
export function runtimeUnreachableExecAnswer(message: string): {
|
|
251
|
+
error: string;
|
|
252
|
+
reason: typeof RUNTIME_UNREACHABLE_REASON;
|
|
253
|
+
stdout: "";
|
|
254
|
+
stderr: string;
|
|
255
|
+
exitCode: 127;
|
|
256
|
+
} {
|
|
257
|
+
return { error: message, reason: RUNTIME_UNREACHABLE_REASON, stdout: "", stderr: message, exitCode: 127 };
|
|
258
|
+
}
|
|
@@ -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-DKhqHu0V.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-CFXbAw7S.js": {
|
|
2566
|
+
"file": "assets/StatusDot-CFXbAw7S.js",
|
|
2567
2567
|
"name": "StatusDot",
|
|
2568
2568
|
"imports": [
|
|
2569
2569
|
"_seed-DeKSHrt2.js",
|
|
2570
|
-
"_Tooltip-
|
|
2570
|
+
"_Tooltip-DcHMtbHJ.js"
|
|
2571
2571
|
]
|
|
2572
2572
|
},
|
|
2573
|
-
"_Tooltip-
|
|
2574
|
-
"file": "assets/Tooltip-
|
|
2573
|
+
"_Tooltip-DcHMtbHJ.js": {
|
|
2574
|
+
"file": "assets/Tooltip-DcHMtbHJ.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-CveRd2yk.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-Chvll3wy.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-CFXbAw7S.js",
|
|
2852
2852
|
"_residentDiskBudget-BMBKlYRH.js"
|
|
2853
2853
|
]
|
|
2854
2854
|
},
|
|
2855
2855
|
"src/pages/ResidentsIndexPage.vue": {
|
|
2856
|
-
"file": "assets/ResidentsIndexPage-
|
|
2856
|
+
"file": "assets/ResidentsIndexPage-B5f8IwGF.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-CFXbAw7S.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-CRvmCuXh.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-DcHMtbHJ.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-BTJuKFTv.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-DcHMtbHJ.js",
|
|
2901
2901
|
"_wallClock-61NpVkY6.js",
|
|
2902
2902
|
"_RunsTabs-DEICQ4FY.js",
|
|
2903
|
-
"_StatusDot-
|
|
2903
|
+
"_StatusDot-CFXbAw7S.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-BVfgUBvP.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-DcHMtbHJ.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-BQNoaXO6.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-CFXbAw7S.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-CFXbAw7S.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};
|