@jr2/orchestrator 0.3.0 → 0.4.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 (73) hide show
  1. package/bin/server.ts +7 -4
  2. package/console/canvas.ts +27 -14
  3. package/console/components/app.ts +10 -1
  4. package/console/components/fleet.ts +39 -6
  5. package/console/components/machine-pane.ts +89 -2
  6. package/console/components/nav.ts +1 -1
  7. package/console/components/schema-form.ts +12 -4
  8. package/console/json-field.ts +23 -0
  9. package/console/main.ts +110 -39
  10. package/console/store.ts +221 -17
  11. package/console/style.css +90 -0
  12. package/package.json +4 -4
  13. package/src/actor.ts +502 -49
  14. package/src/ambient.ts +2 -0
  15. package/src/assembly-checks.ts +165 -0
  16. package/src/assembly-tar.ts +494 -0
  17. package/src/assembly.ts +721 -0
  18. package/src/chart.ts +2050 -0
  19. package/src/charts.ts +720 -0
  20. package/src/config.ts +152 -46
  21. package/src/content-hash.ts +105 -0
  22. package/src/custodian.lua +6 -5
  23. package/src/custodian.ts +71 -19
  24. package/src/customize.ts +216 -25
  25. package/src/effect-checks.ts +557 -0
  26. package/src/effect.ts +905 -0
  27. package/src/effector-wire.ts +525 -0
  28. package/src/fingerprint.ts +4 -3
  29. package/src/gate.ts +8 -0
  30. package/src/git-clone.ts +65 -0
  31. package/src/git-push.ts +336 -0
  32. package/src/harness-client.ts +245 -23
  33. package/src/held-secrets.ts +82 -26
  34. package/src/holds.ts +156 -0
  35. package/src/http-effect.ts +981 -0
  36. package/src/http.ts +496 -104
  37. package/src/images.ts +47 -21
  38. package/src/index.ts +43 -2
  39. package/src/instance.ts +444 -58
  40. package/src/kube-client.ts +333 -0
  41. package/src/machine-doc.ts +88 -6
  42. package/src/mount-digest.ts +53 -0
  43. package/src/names.ts +66 -8
  44. package/src/notices.ts +88 -0
  45. package/src/open-body.ts +1444 -0
  46. package/src/open-effect.ts +144 -0
  47. package/src/open.ts +4 -4
  48. package/src/parts.ts +530 -33
  49. package/src/party.ts +468 -0
  50. package/src/pick.ts +309 -0
  51. package/src/pool.ts +1 -1
  52. package/src/registration.ts +301 -17
  53. package/src/repo-fetch.ts +60 -85
  54. package/src/repos.ts +63 -74
  55. package/src/rest.ts +133 -0
  56. package/src/run-host.ts +1832 -98
  57. package/src/sandbox-effect.ts +891 -0
  58. package/src/sandbox-effector.ts +111 -0
  59. package/src/sandbox-kube.ts +1719 -0
  60. package/src/sandbox-watch.ts +260 -0
  61. package/src/secret-placement.ts +494 -0
  62. package/src/server.ts +281 -84
  63. package/src/setup.ts +589 -70
  64. package/src/size.ts +342 -0
  65. package/src/snapshot-store.ts +64 -13
  66. package/src/stub-harness.ts +5 -0
  67. package/src/sync-client.ts +54 -0
  68. package/src/timers.ts +178 -0
  69. package/src/tokens.ts +35 -4
  70. package/src/vocabulary.ts +66 -1
  71. package/src/wire.ts +156 -2
  72. package/src/workspace.ts +529 -194
  73. package/src/sandbox-kubectl.ts +0 -1108
package/src/notices.ts ADDED
@@ -0,0 +1,88 @@
1
+ // The Orchestrator's notices (ADR-0062): what happened that the next Turn cannot find out for
2
+ // itself — a memory kill in its Workspace, a conversation that is new — kept as plain data in the
3
+ // run's persisted state (ADR-0007), beside the admission and epoch ledgers, and handed to the next
4
+ // admission in scope. The Harness writes every word; this is only the keeping.
5
+ //
6
+ // Delivered ONCE, and "delivered" means LEDGERED: a notice leaves the pending set in the same save
7
+ // that records the admission it rode. A restart before that save finds it still pending and the
8
+ // restored Turn's admission carries it again; a restart after it does not. Between `take` and that
9
+ // save the notice is RESERVED, in memory only, so a second admission in the same scope cannot carry
10
+ // it too — and a restart forgets reservations along with everything else in memory.
11
+
12
+ import type { Notice } from "./wire.ts";
13
+
14
+ /** Where an admission may hear notices: its continued conversation's base Instance ID (ADR-0057)
15
+ * and its Workspace's Sandbox name. Either may be absent — a fresh Turn has no conversation to be
16
+ * told about, and a Menu-only Agent works in no Workspace. */
17
+ export type NoticeScope = { conversation?: string; workspace?: string };
18
+
19
+ /** One pending notice: the notice, and the conversation or Workspace it goes to. `source` names
20
+ * the event that raised it, so the same event raised twice — two Turns lost to one kernel kill, a
21
+ * stream read replayed after a restore — is one notice. */
22
+ export type PendingNotice = { id: string; notice: Notice; to: string; source?: string };
23
+
24
+ /** The persisted form (`RunBlob.notices`). `seen` is every source ever raised, so a delivered
25
+ * notice is not raised again by a late or replayed witness of the same event. */
26
+ export type NoticeLedgerState = { pending: PendingNotice[]; seen: string[] };
27
+
28
+ /** What one admission takes: the notices it carries, and their ids for the ledger write. */
29
+ export type TakenNotices = { ids: string[]; notices: Notice[] };
30
+
31
+ export class NoticeLedger {
32
+ readonly #pending: PendingNotice[];
33
+ readonly #seen: Set<string>;
34
+ readonly #reserved = new Set<string>();
35
+ readonly #newId: () => string;
36
+
37
+ constructor(state: NoticeLedgerState | undefined, newId: () => string) {
38
+ this.#pending = [...(state?.pending ?? [])];
39
+ this.#seen = new Set(state?.seen ?? []);
40
+ this.#newId = newId;
41
+ }
42
+
43
+ /** Raise a notice for `to` (a conversation's base id, or a Sandbox name — the notice's own
44
+ * `scope` says which). False when `source` was already raised, or the same notice is already
45
+ * pending for `to`. */
46
+ raise(notice: Notice, to: string, source?: string): boolean {
47
+ if (source !== undefined) {
48
+ if (this.#seen.has(source)) return false;
49
+ this.#seen.add(source);
50
+ }
51
+ // The same news, still unheard, is one notice: the guard writes one kill to the stream of
52
+ // every conversation running in the pod, and each Turn following one reads it.
53
+ const same = JSON.stringify(notice);
54
+ if (this.#pending.some((p) => p.to === to && JSON.stringify(p.notice) === same)) return false;
55
+ this.#pending.push({ id: this.#newId(), notice, to, ...(source === undefined ? {} : { source }) });
56
+ return true;
57
+ }
58
+
59
+ /** Reserve every unreserved notice in this admission's scope, in the order raised. */
60
+ take(scope: NoticeScope): TakenNotices {
61
+ const taken = this.#pending.filter(
62
+ (p) =>
63
+ !this.#reserved.has(p.id) &&
64
+ (p.notice.scope === "conversation" ? p.to === scope.conversation : p.to === scope.workspace),
65
+ );
66
+ for (const p of taken) this.#reserved.add(p.id);
67
+ return { ids: taken.map((p) => p.id), notices: taken.map((p) => p.notice) };
68
+ }
69
+
70
+ /** The admission that carried them was ledgered: they are delivered. */
71
+ delivered(ids: readonly string[]): void {
72
+ for (const id of ids) {
73
+ this.#reserved.delete(id);
74
+ const at = this.#pending.findIndex((p) => p.id === id);
75
+ if (at !== -1) this.#pending.splice(at, 1);
76
+ }
77
+ }
78
+
79
+ /** The admission that carried them failed: they are pending again, for the next one. */
80
+ release(ids: readonly string[]): void {
81
+ for (const id of ids) this.#reserved.delete(id);
82
+ }
83
+
84
+ /** The persisted form — reserved notices included, because reserved is not delivered. */
85
+ state(): NoticeLedgerState {
86
+ return { pending: [...this.#pending], seen: [...this.#seen] };
87
+ }
88
+ }