@coreplane/switchboard 1.211.0 → 1.213.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.
Files changed (35) hide show
  1. package/README.md +5 -3
  2. package/dist/assets/config/config.example.yaml +44 -0
  3. package/dist/assets/deploy/cloudflare/worker.ts +6 -0
  4. package/dist/assets/deploy/cloudflare-resident/Dockerfile +24 -0
  5. package/dist/assets/deploy/cloudflare-resident/worker.ts +421 -38
  6. package/dist/assets/deploy/cloudflare-resident/wrangler.template.jsonc +9 -1
  7. package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +18 -0
  8. package/dist/assets/deploy/cloudflare-sandbox/worker.ts +19 -5
  9. package/dist/assets/deploy/secrets.manifest.json +18 -0
  10. package/dist/assets/package-lock.json +5 -3
  11. package/dist/assets/package.json +2 -1
  12. package/dist/assets/source.json +3 -3
  13. package/dist/assets/src/agents/registry.ts +50 -7
  14. package/dist/assets/src/core/redact.ts +11 -1
  15. package/dist/assets/src/core/runEvents.ts +60 -6
  16. package/dist/assets/src/core/runFriction.ts +6 -4
  17. package/dist/assets/src/core/trace/workerTrace.ts +4 -0
  18. package/dist/assets/src/execution/binaryRead.ts +56 -14
  19. package/dist/assets/src/execution/residentRefresh.ts +151 -5
  20. package/dist/assets/src/execution/residentStepReport.ts +4 -0
  21. package/dist/assets/web/dist/.vite/manifest.json +19 -19
  22. package/dist/assets/web/dist/assets/{ResidentDetailPage-CM5nWw-Z.js → ResidentDetailPage-CvwjhjlG.js} +1 -1
  23. package/dist/assets/web/dist/assets/{ResidentsIndexPage-BKBnuvp3.js → ResidentsIndexPage-DoN6XuNx.js} +1 -1
  24. package/dist/assets/web/dist/assets/RunRoutePage-FzLNexjF.js +12 -0
  25. package/dist/assets/web/dist/assets/{RunsIndexPage-w2jJP5xu.js → RunsIndexPage-DhSUbF9k.js} +1 -1
  26. package/dist/assets/web/dist/assets/{ScheduledPage-D3-k9DPz.js → ScheduledPage-Bq0Yg4nT.js} +1 -1
  27. package/dist/assets/web/dist/assets/{StatusDot-BmFHnV8m.js → StatusDot-D8Wwt1KC.js} +1 -1
  28. package/dist/assets/web/dist/assets/{Tooltip-DoThP2fW.js → Tooltip-DpDK7jWZ.js} +1 -1
  29. package/dist/assets/web/dist/assets/{dist-YrRKtxsS.js → dist-B7BVkB7x.js} +1 -1
  30. package/dist/assets/web/dist/assets/{main-D6nzMf0k.js → main-BFkEOy3K.js} +2 -2
  31. package/dist/assets/web/dist/assets/main-DCH3Mezs.css +1 -0
  32. package/dist/cli.js +2704 -603
  33. package/package.json +2 -1
  34. package/dist/assets/web/dist/assets/RunRoutePage-Bu4CwEzt.js +0 -12
  35. package/dist/assets/web/dist/assets/main-CuENKPdD.css +0 -1
@@ -117,6 +117,10 @@ export function checkoutUpdateCommand(sha: string, clean: CleanScope): string {
117
117
  * step at all.) The kill surfaces either as the shell's
118
118
  * own death (SIGTERM, exit 143, "Session terminated") or, past the shell, as
119
119
  * the SDK's replacement errors (stale process handle, closed supervisor).
120
+ * `runtimeUnreachable` is the other outcome that says nothing about the
121
+ * repository: the container's control port never answered the SDK's connect
122
+ * (`runtimeUnreachableReason`), so no command ran at all — the resident
123
+ * escalates on its persisted count instead of recording a command failure.
120
124
  * Everything else is the repo's own build failing. */
121
125
  export interface RefreshFailure {
122
126
  /** The reason. An interruption's is prefixed `refresh-interrupted:` and is
@@ -124,10 +128,13 @@ export interface RefreshFailure {
124
128
  * whose retry re-enters the step, and the row keeps its state (the word
125
129
  * shows on the instance row's `lastStep` and in the log). A full disk is
126
130
  * `disk-full:` (`residentDisk.ts` — the cycle's entry gate and the recycle
127
- * decision key on it); real failures keep `<step>-failed:`. */
131
+ * decision key on it); an unanswered control port is `runtime-unreachable:`
132
+ * with the attempt count (the ladder below decides what the resident does
133
+ * about it); real failures keep `<step>-failed:`. */
128
134
  reason: string;
129
135
  interrupted: boolean;
130
136
  diskFull: boolean;
137
+ runtimeUnreachable: boolean;
131
138
  }
132
139
 
133
140
  /** Root argv that kills every process the build user still owns and waits
@@ -202,7 +209,16 @@ const INTERRUPTION_SIGNATURE = /\bexit 143\b|Session terminated|SIGTERM/;
202
209
  export const RUNTIME_REPLACEMENT_WORDING =
203
210
  /previous runtime incarnation|interrupted because the runtime changed|runtime identity is no longer active|sandbox lifetime is no longer current|platform was updating the sandbox runtime|no longer identifies pid|process supervisor is closed|container is not running, consider calling start/i;
204
211
 
205
- /** `freeKiB` is the `df` probe's answer (`parseDfFreeKiB`), taken AFTER the
212
+ /** `runtimeUnreachable` is the caller's word that the failure was the SDK's
213
+ * connect abort at the exec choke point (the Worker's typed check over the
214
+ * error and its cause chain, `isRuntimeUnreachableSignal`) with the count it
215
+ * persisted: the outcome is decided before anything else — no command ran, so
216
+ * neither the message nor a disk probe is evidence — and the reason is the
217
+ * named one, never the SDK's bare `The operation was aborted`. Without that
218
+ * word the classifier does not guess from the wording: an abort message on
219
+ * its own stays the step's failure, exactly as it did before the ladder.
220
+ *
221
+ * `freeKiB` is the `df` probe's answer (`parseDfFreeKiB`), taken AFTER the
206
222
  * step failed and only consulted when the message itself carries no errno:
207
223
  * a message saying ENOSPC is disk-full outright (the disk is the actionable
208
224
  * fact, whatever else the message says); a kill signature without it is an
@@ -213,23 +229,153 @@ export function classifyRefreshFailure(input: {
213
229
  step: string;
214
230
  message: string;
215
231
  freeKiB?: number | null;
232
+ runtimeUnreachable?: { count: number };
216
233
  }): RefreshFailure {
217
234
  const { step, message } = input;
235
+ if (input.runtimeUnreachable) {
236
+ return {
237
+ interrupted: false,
238
+ diskFull: false,
239
+ runtimeUnreachable: true,
240
+ reason: runtimeUnreachableReason(input.runtimeUnreachable.count),
241
+ };
242
+ }
218
243
  if (isDiskFullMessage(message)) {
219
244
  return {
220
245
  interrupted: false,
221
246
  diskFull: true,
247
+ runtimeUnreachable: false,
222
248
  reason: diskFullReason({ step, message, freeKiB: input.freeKiB ?? null }),
223
249
  };
224
250
  }
225
251
  const timedOut = /\(timed out\)/.test(message);
226
252
  if (!timedOut && (INTERRUPTION_SIGNATURE.test(message) || RUNTIME_REPLACEMENT_WORDING.test(message))) {
227
- return { interrupted: true, diskFull: false, reason: `refresh-interrupted: ${step} ${message}` };
253
+ return {
254
+ interrupted: true,
255
+ diskFull: false,
256
+ runtimeUnreachable: false,
257
+ reason: `refresh-interrupted: ${step} ${message}`,
258
+ };
228
259
  }
229
260
  if (input.freeKiB !== undefined && input.freeKiB !== null && input.freeKiB < DISK_FULL_FREE_KIB) {
230
- return { interrupted: false, diskFull: true, reason: diskFullReason({ step, message, freeKiB: input.freeKiB }) };
261
+ return {
262
+ interrupted: false,
263
+ diskFull: true,
264
+ runtimeUnreachable: false,
265
+ reason: diskFullReason({ step, message, freeKiB: input.freeKiB }),
266
+ };
267
+ }
268
+ return { interrupted: false, diskFull: false, runtimeUnreachable: false, reason: `${step}-failed: ${message}` };
269
+ }
270
+
271
+ // -- the runtime that never answers --------------------------------------------
272
+
273
+ /** The Sandbox SDK's connect timeout (`DEFAULT_CONNECT_TIMEOUT_MS` in its
274
+ * container-control connection, @cloudflare/sandbox@0.13.0-next.751.1): how
275
+ * long ONE WebSocket upgrade to the container's control port 3000 may take
276
+ * before the SDK aborts it. A module constant there, not an option — the
277
+ * 30 s is the SDK's, not ours; pinned by a test that reads the installed
278
+ * dist, so an SDK bump that moves it fails the build, not a reason string. */
279
+ export const SDK_CONNECT_TIMEOUT_MS = 30_000;
280
+
281
+ /** The SDK's env knob for how long the physical start waits for the control
282
+ * port to accept a request before the first connect (`portReadyTimeoutMS`,
283
+ * read from this var, 10 s to 600 s; its default is 90 s). The wake path's
284
+ * first exec after a start is bounded by that wait PLUS one connect timeout:
285
+ * a slow boot (a 2.65 GB image on a cold host) spends its time in the port
286
+ * wait, so a start given `WAKE_PORT_READY_MS` is not mistaken for an
287
+ * unreachable runtime. The value lives in the resident's wrangler template
288
+ * (`vars`), pinned to the constant by a test. */
289
+ export const SDK_PORT_READY_ENV = "SANDBOX_PORT_TIMEOUT_MS";
290
+ export const WAKE_PORT_READY_MS = 3 * 60_000;
291
+
292
+ /** The DO storage key the SDK keeps its runtime identity under
293
+ * (`RUNTIME_RECORD_KEY` in its runtime lifecycle; not exported). The
294
+ * resident forgets it before it destroys a container: the SDK's `destroy()`
295
+ * skips its runtime cleanup when no identity is stored — against a silent
296
+ * control port that cleanup would only wait out its bound — and a destroy
297
+ * that fails midway leaves no identity behind to be re-adopted. `stop()` and
298
+ * `destroy()` delete it themselves (`invalidate`); the explicit delete is the
299
+ * guard for the path where they do not get that far. Pinned to the installed
300
+ * SDK by a test. */
301
+ export const SDK_RUNTIME_RECORD_KEY = "currentRuntimeIdentity";
302
+
303
+ /** The DOMException the SDK's connect abort raises: `AbortError`, message
304
+ * `The operation was aborted`. Anchored on the whole sentence so a command's
305
+ * own `Aborted (core dumped)` never matches. */
306
+ export const RUNTIME_UNREACHABLE_WORDING = /\bThe operation was aborted\b/;
307
+
308
+ /** Is this one link of an error's cause chain the SDK's connect abort? By
309
+ * name first (the DOMException's `AbortError`), by the DOMException's message
310
+ * when a wrapper copied only that. Applied by the Worker to the SPAWN-phase
311
+ * error alone — after its replacement check, since a replaced runtime is a
312
+ * different fact (`RUNTIME_REPLACEMENT_WORDING`, disjoint by construction) —
313
+ * never to a command's own output, which is a `StepError` with an exit code. */
314
+ export function isRuntimeUnreachableSignal(link: unknown): boolean {
315
+ if (link === null || typeof link !== "object") return false;
316
+ const { name, message } = link as { name?: unknown; message?: unknown };
317
+ if (name === "AbortError") return true;
318
+ return typeof message === "string" && RUNTIME_UNREACHABLE_WORDING.test(message);
319
+ }
320
+
321
+ /** The escalation ladder over the resident's persisted count of consecutive
322
+ * unanswered connects (the row is cleared by any exec whose process spawned).
323
+ * Each rung is what the refresh instance does when a step's exec finds the
324
+ * control port silent AGAIN at that count:
325
+ * re-arm (1–2) `degraded(runtime-unreachable …)`, the step thrown to the
326
+ * engine whose retry re-enters it thirty seconds on — the
327
+ * short re-arm a `refresh-interrupted` gets;
328
+ * stop (3) the container is sent SIGTERM (`stop()`), the incarnation
329
+ * swapped, the retry starts it again — cheap, and enough
330
+ * for a runtime that still honours signals;
331
+ * recreate (4–5) the SDK's runtime identity is forgotten
332
+ * (`SDK_RUNTIME_RECORD_KEY`) and the VM destroyed
333
+ * (`destroy()`: SIGKILL, a fresh disk — where `stop()` is a
334
+ * SIGTERM a wedged runtime ignores, as the incident's admin
335
+ * stop showed), every snapshot and entry backup kept, the
336
+ * incarnation swapped; the retry's wake path finds no
337
+ * runtime, flips `restoring` and restores mirror, checkout
338
+ * and deps from R2 — minutes, not the thirty-minute rebuild;
339
+ * down (≥ 6) a recreated container did not answer either: the resident
340
+ * goes `down(runtime-unreachable …)`, a reason the watchdog's
341
+ * auto-rebuild strikes apply to, so the rebuild — destroy
342
+ * plus reprovision from the code host — is the last resort,
343
+ * not the first. */
344
+ export const RUNTIME_UNREACHABLE_STOP_AT = 3;
345
+ export const RUNTIME_UNREACHABLE_RECREATE_AT = 4;
346
+ export const RUNTIME_UNREACHABLE_DOWN_AT = 6;
347
+
348
+ export type RuntimeUnreachableRung = "re-arm" | "stop" | "recreate" | "down";
349
+
350
+ export function runtimeUnreachableRung(count: number): RuntimeUnreachableRung {
351
+ if (!Number.isFinite(count) || count < 1) {
352
+ throw new RangeError(`runtime-unreachable rung needs a count of at least 1, got ${count}`);
231
353
  }
232
- return { interrupted: false, diskFull: false, reason: `${step}-failed: ${message}` };
354
+ if (count >= RUNTIME_UNREACHABLE_DOWN_AT) return "down";
355
+ if (count >= RUNTIME_UNREACHABLE_RECREATE_AT) return "recreate";
356
+ if (count >= RUNTIME_UNREACHABLE_STOP_AT) return "stop";
357
+ return "re-arm";
358
+ }
359
+
360
+ const RUNTIME_UNREACHABLE_ACTION: Readonly<Record<RuntimeUnreachableRung, string>> = {
361
+ "re-arm": "the step is retried",
362
+ stop: "the container was stopped (SIGTERM); the retry starts it again",
363
+ recreate:
364
+ "the container was destroyed and the SDK's runtime identity forgotten, snapshots kept; the retry restores the checkout from the snapshot",
365
+ down: "a recreated container did not answer either; only a rebuild follows",
366
+ };
367
+
368
+ /** The reason a silent control port is recorded under: the port, the SDK's
369
+ * connect timeout and the attempt out of the down threshold — and, when a
370
+ * rung acted, what it did and what the retry does next. Never the SDK's bare
371
+ * `The operation was aborted`. */
372
+ export function runtimeUnreachableReason(count: number, rung?: RuntimeUnreachableRung): string {
373
+ const base = `runtime-unreachable: the container's control port did not answer within ${SDK_CONNECT_TIMEOUT_MS / 1000} s (attempt ${count} of ${RUNTIME_UNREACHABLE_DOWN_AT})`;
374
+ return rung ? `${base} — ${RUNTIME_UNREACHABLE_ACTION[rung]}` : base;
375
+ }
376
+
377
+ export function isRuntimeUnreachableReason(reason: string): boolean {
378
+ return /^runtime-unreachable: /.test(reason);
233
379
  }
234
380
 
235
381
  /** What the wake path does with a failed restore. `down` is the rule: the
@@ -24,6 +24,10 @@ export interface StepResult {
24
24
  stderr: string;
25
25
  exitCode: number;
26
26
  timedOut: boolean;
27
+ /** The sandbox SDK cut the process's output stream past its own retention
28
+ * limit (one its typings do not name; about 2.3 MB observed): what is here
29
+ * is a prefix. Distinct from the DO's char caps, which slice what arrived. */
30
+ truncated?: boolean;
27
31
  }
28
32
 
29
33
  /** Chars kept per stream in the STORED reason — it travels into DO storage,
@@ -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-YrRKtxsS.js",
31
+ "file": "assets/dist-B7BVkB7x.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-BmFHnV8m.js": {
2566
- "file": "assets/StatusDot-BmFHnV8m.js",
2565
+ "_StatusDot-D8Wwt1KC.js": {
2566
+ "file": "assets/StatusDot-D8Wwt1KC.js",
2567
2567
  "name": "StatusDot",
2568
2568
  "imports": [
2569
2569
  "_seed-DeKSHrt2.js",
2570
- "_Tooltip-DoThP2fW.js"
2570
+ "_Tooltip-DpDK7jWZ.js"
2571
2571
  ]
2572
2572
  },
2573
- "_Tooltip-DoThP2fW.js": {
2574
- "file": "assets/Tooltip-DoThP2fW.js",
2573
+ "_Tooltip-DpDK7jWZ.js": {
2574
+ "file": "assets/Tooltip-DpDK7jWZ.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-D6nzMf0k.js",
2792
+ "file": "assets/main-BFkEOy3K.js",
2793
2793
  "name": "main",
2794
2794
  "src": "src/main.ts",
2795
2795
  "isEntry": true,
@@ -2807,7 +2807,7 @@
2807
2807
  "_NotFoundPage-BzWS4Ca1.js"
2808
2808
  ],
2809
2809
  "css": [
2810
- "assets/main-CuENKPdD.css"
2810
+ "assets/main-DCH3Mezs.css"
2811
2811
  ],
2812
2812
  "assets": [
2813
2813
  "assets/instrument-sans-latin-ext-wght-normal-B5bTHO_g.woff2",
@@ -2841,19 +2841,19 @@
2841
2841
  ]
2842
2842
  },
2843
2843
  "src/pages/ResidentDetailPage.vue": {
2844
- "file": "assets/ResidentDetailPage-CM5nWw-Z.js",
2844
+ "file": "assets/ResidentDetailPage-CvwjhjlG.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-BmFHnV8m.js",
2851
+ "_StatusDot-D8Wwt1KC.js",
2852
2852
  "_residentDiskBudget-BMBKlYRH.js"
2853
2853
  ]
2854
2854
  },
2855
2855
  "src/pages/ResidentsIndexPage.vue": {
2856
- "file": "assets/ResidentsIndexPage-BKBnuvp3.js",
2856
+ "file": "assets/ResidentsIndexPage-DoN6XuNx.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-BmFHnV8m.js",
2864
+ "_StatusDot-D8Wwt1KC.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-Bu4CwEzt.js",
2870
+ "file": "assets/RunRoutePage-FzLNexjF.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-DoThP2fW.js",
2877
+ "_Tooltip-DpDK7jWZ.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-w2jJP5xu.js",
2893
+ "file": "assets/RunsIndexPage-DhSUbF9k.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-DoThP2fW.js",
2900
+ "_Tooltip-DpDK7jWZ.js",
2901
2901
  "_wallClock-61NpVkY6.js",
2902
2902
  "_RunsTabs-DEICQ4FY.js",
2903
- "_StatusDot-BmFHnV8m.js",
2903
+ "_StatusDot-D8Wwt1KC.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-D3-k9DPz.js",
2910
+ "file": "assets/ScheduledPage-Bq0Yg4nT.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-DoThP2fW.js",
2917
+ "_Tooltip-DpDK7jWZ.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-BmFHnV8m.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-D8Wwt1KC.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-BmFHnV8m.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};
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-D8Wwt1KC.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};