@coreplane/switchboard 1.267.0 → 1.267.1

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 (43) hide show
  1. package/dist/assets/deploy/cloudflare-resident/gc.ts +1 -0
  2. package/dist/assets/deploy/cloudflare-resident/keyedAsyncLock.ts +20 -0
  3. package/dist/assets/deploy/cloudflare-resident/legacyCredentials.ts +57 -0
  4. package/dist/assets/deploy/cloudflare-resident/orphanThreadUsers.ts +14 -0
  5. package/dist/assets/deploy/cloudflare-resident/worker.ts +646 -204
  6. package/dist/assets/package-lock.json +3 -3
  7. package/dist/assets/package.json +1 -1
  8. package/dist/assets/source.json +3 -3
  9. package/dist/assets/src/core/budgets.ts +10 -0
  10. package/dist/assets/src/core/coordinator/contract.ts +29 -0
  11. package/dist/assets/src/core/coordinator/driver.ts +15 -2
  12. package/dist/assets/src/core/runRecord.ts +32 -0
  13. package/dist/assets/src/core/ship/coordinator.ts +42 -4
  14. package/dist/assets/src/execution/githubMintScope.ts +49 -0
  15. package/dist/assets/src/execution/residentCredentials.ts +9 -37
  16. package/dist/assets/src/execution/residentDestroyGate.ts +12 -0
  17. package/dist/assets/src/execution/residentPoolSpends.ts +96 -0
  18. package/dist/assets/src/execution/residentRecreateAdmission.ts +41 -0
  19. package/dist/assets/src/execution/residentSteps.ts +1 -0
  20. package/dist/assets/web/dist/.vite/manifest.json +67 -67
  21. package/dist/assets/web/dist/assets/{DeliveryPage-BUJckSuW.js → DeliveryPage-QyS6_Q0m.js} +1 -1
  22. package/dist/assets/web/dist/assets/{HomePage-BfpIrKDX.js → HomePage-Bm40r0wF.js} +1 -1
  23. package/dist/assets/web/dist/assets/{PendingTurnRow-C6hroa00.js → PendingTurnRow-BqY-EaZR.js} +1 -1
  24. package/dist/assets/web/dist/assets/{PlanePage-C2Cb1mkT.js → PlanePage-VmzjNLAz.js} +1 -1
  25. package/dist/assets/web/dist/assets/{ResidentDetailPage-Bd9_Q87l.js → ResidentDetailPage-hjX3tRCh.js} +1 -1
  26. package/dist/assets/web/dist/assets/{ResidentsIndexPage-C8eS7hxp.js → ResidentsIndexPage-BKGnlCEh.js} +1 -1
  27. package/dist/assets/web/dist/assets/{RunFoldRow-DrfFauYJ.js → RunFoldRow-BOWvSoIv.js} +1 -1
  28. package/dist/assets/web/dist/assets/{RunRoutePage-B_eXfNAF.js → RunRoutePage-D9ztf-uE.js} +3 -3
  29. package/dist/assets/web/dist/assets/{RunsIndexPage-BpQu36Dm.js → RunsIndexPage-DTYQbhtr.js} +1 -1
  30. package/dist/assets/web/dist/assets/{ScheduledPage-DGHcjcSt.js → ScheduledPage-BAYR0tuv.js} +1 -1
  31. package/dist/assets/web/dist/assets/{SettingsPage-IfQ71QjN.js → SettingsPage-BlYBmCG9.js} +1 -1
  32. package/dist/assets/web/dist/assets/{SilentTurn-D9ON15a8.js → SilentTurn-CHfzRQW8.js} +1 -1
  33. package/dist/assets/web/dist/assets/{StatusDot-DyFjGg4V.js → StatusDot-BMkUFVE8.js} +1 -1
  34. package/dist/assets/web/dist/assets/{Tooltip-BvPkV4kZ.js → Tooltip-Dfot16IA.js} +1 -1
  35. package/dist/assets/web/dist/assets/{UnitRoutePage-BNe3nBIG.js → UnitRoutePage-BdZoT-4d.js} +1 -1
  36. package/dist/assets/web/dist/assets/budgets-CJHiTZmM.js +1 -0
  37. package/dist/assets/web/dist/assets/{dist-v3Py3_QR.js → dist-XRrc0hhm.js} +1 -1
  38. package/dist/assets/web/dist/assets/{indexRow-BsWcHHVh.js → indexRow-BGjjLnN5.js} +1 -1
  39. package/dist/assets/web/dist/assets/{main-ks3kBojV.js → main-B32N1vUh.js} +2 -2
  40. package/dist/assets/web/dist/assets/{sseReplay-DuALaBPq.js → sseReplay-BsNQPLmJ.js} +2 -2
  41. package/dist/cli.js +928 -346
  42. package/package.json +1 -1
  43. package/dist/assets/web/dist/assets/budgets-BQgcCyvb.js +0 -1
@@ -99,6 +99,7 @@ export type ReclaimWhy =
99
99
  | "busy"
100
100
  | "run-held"
101
101
  | "re-attached"
102
+ | "cleanup-failed"
102
103
  | Extract<RefFate, "gone" | "merged" | "closed">;
103
104
 
104
105
  /** Evict this binding now? A finished ref (gone/merged/closed) is reclaimed
@@ -0,0 +1,20 @@
1
+ /** Serialize one key through the entire operation, including rollback. */
2
+ export class KeyedAsyncLock {
3
+ private readonly tails = new Map<string, Promise<void>>();
4
+
5
+ async run<T>(key: string, action: () => Promise<T>): Promise<T> {
6
+ const prior = this.tails.get(key);
7
+ let release!: () => void;
8
+ const current = new Promise<void>((resolve) => {
9
+ release = resolve;
10
+ });
11
+ this.tails.set(key, current);
12
+ if (prior) await prior;
13
+ try {
14
+ return await action();
15
+ } finally {
16
+ release();
17
+ if (this.tails.get(key) === current) this.tails.delete(key);
18
+ }
19
+ }
20
+ }
@@ -41,3 +41,60 @@ remove(sys.argv[2], 'cred')
41
41
  export function legacyCredentialScrubCommand(worktreePath: string, stageDir: string): string[] {
42
42
  return ["python3", "-c", LEGACY_CREDENTIAL_SCRUB, `${worktreePath}/.git`, stageDir];
43
43
  }
44
+
45
+ /** A free UID must not inherit files left in its old staging directory.
46
+ * Inspect directory components without following links and report only whether
47
+ * content exists. The probe never reads or prints a credential or staged file. */
48
+ export const LEGACY_STAGE_CONTENT_SCAN = `import os, sys
49
+
50
+ flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
51
+ fd = os.open('/', flags)
52
+ try:
53
+ try:
54
+ for part in sys.argv[1].strip('/').split('/'):
55
+ if not part:
56
+ continue
57
+ child = os.open(part, flags, dir_fd=fd)
58
+ os.close(fd)
59
+ fd = child
60
+ except FileNotFoundError:
61
+ print('clean')
62
+ else:
63
+ print('stale' if os.listdir(fd) else 'clean')
64
+ finally:
65
+ os.close(fd)
66
+ `;
67
+
68
+ export function legacyStageContentScanCommand(stageDir: string): string[] {
69
+ return ["python3", "-c", LEGACY_STAGE_CONTENT_SCAN, stageDir];
70
+ }
71
+
72
+ /** Eviction may free this UID only after its known staging files are gone.
73
+ * Unlink through an unfollowed directory descriptor; a linked stage fails. */
74
+ export const LEGACY_STAGE_REUSE_SCRUB = `import os, sys
75
+
76
+ flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
77
+ fd = os.open('/', flags)
78
+ try:
79
+ try:
80
+ for part in sys.argv[1].strip('/').split('/'):
81
+ if not part:
82
+ continue
83
+ child = os.open(part, flags, dir_fd=fd)
84
+ os.close(fd)
85
+ fd = child
86
+ except FileNotFoundError:
87
+ pass
88
+ else:
89
+ for name in ('cred', 'put'):
90
+ try:
91
+ os.unlink(name, dir_fd=fd)
92
+ except FileNotFoundError:
93
+ pass
94
+ finally:
95
+ os.close(fd)
96
+ `;
97
+
98
+ export function legacyStageReuseScrubCommand(stageDir: string): string[] {
99
+ return ["python3", "-c", LEGACY_STAGE_REUSE_SCRUB, stageDir];
100
+ }
@@ -0,0 +1,14 @@
1
+ /** Validate the root-owned scan before a pool UID can be handed to another run.
2
+ * An older release may have removed a binding without removing its tree. */
3
+ export function hasUnexpectedOwnedThreadDir(output: string, root: string, allowed: readonly string[]): boolean {
4
+ const pathOk = (path: string) => {
5
+ if (!path.startsWith(`${root}/`)) return false;
6
+ const name = path.slice(root.length + 1);
7
+ return name.length > 0 && /^[A-Za-z0-9._-]+$/.test(name) && name !== "." && name !== "..";
8
+ };
9
+ if (allowed.some((path) => !pathOk(path))) return true;
10
+ if (output === "") return false;
11
+ if (!output.endsWith("\n")) return true;
12
+ const paths = output.slice(0, -1).split("\n");
13
+ return paths.some((path) => !pathOk(path) || !allowed.includes(path));
14
+ }