@cotal-ai/manager 0.16.0 → 0.17.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 (53) hide show
  1. package/dist/attach-endpoint.d.ts +53 -59
  2. package/dist/attach-endpoint.d.ts.map +1 -1
  3. package/dist/attach-endpoint.js +120 -244
  4. package/dist/attach-endpoint.js.map +1 -1
  5. package/dist/commands.js +9 -4
  6. package/dist/commands.js.map +1 -1
  7. package/dist/console/app.js +68 -30
  8. package/dist/console/index.html +3 -2
  9. package/dist/console/session-bundle.js +9736 -0
  10. package/dist/console-crypto-shim.d.ts +16 -0
  11. package/dist/console-crypto-shim.d.ts.map +1 -0
  12. package/dist/console-crypto-shim.js +20 -0
  13. package/dist/console-crypto-shim.js.map +1 -0
  14. package/dist/console-session-entry.d.ts +2 -0
  15. package/dist/console-session-entry.d.ts.map +1 -0
  16. package/dist/console-session-entry.js +26 -0
  17. package/dist/console-session-entry.js.map +1 -0
  18. package/dist/endpoint-evict.d.ts +29 -0
  19. package/dist/endpoint-evict.d.ts.map +1 -0
  20. package/dist/endpoint-evict.js +80 -0
  21. package/dist/endpoint-evict.js.map +1 -0
  22. package/dist/manager-service-contract.d.ts +132 -0
  23. package/dist/manager-service-contract.d.ts.map +1 -0
  24. package/dist/manager-service-contract.js +332 -0
  25. package/dist/manager-service-contract.js.map +1 -0
  26. package/dist/manager.d.ts +504 -22
  27. package/dist/manager.d.ts.map +1 -1
  28. package/dist/manager.js +2193 -257
  29. package/dist/manager.js.map +1 -1
  30. package/dist/runtime/pty.d.ts.map +1 -1
  31. package/dist/runtime/pty.js +15 -2
  32. package/dist/runtime/pty.js.map +1 -1
  33. package/dist/session/bridge.d.ts +63 -0
  34. package/dist/session/bridge.d.ts.map +1 -0
  35. package/dist/session/bridge.js +157 -0
  36. package/dist/session/bridge.js.map +1 -0
  37. package/dist/session/establish.d.ts +212 -0
  38. package/dist/session/establish.d.ts.map +1 -0
  39. package/dist/session/establish.js +174 -0
  40. package/dist/session/establish.js.map +1 -0
  41. package/dist/session/index.d.ts +12 -0
  42. package/dist/session/index.d.ts.map +1 -0
  43. package/dist/session/index.js +15 -0
  44. package/dist/session/index.js.map +1 -0
  45. package/dist/session/plane.d.ts +120 -0
  46. package/dist/session/plane.d.ts.map +1 -0
  47. package/dist/session/plane.js +327 -0
  48. package/dist/session/plane.js.map +1 -0
  49. package/dist/static-lifecycle.d.ts +97 -0
  50. package/dist/static-lifecycle.d.ts.map +1 -0
  51. package/dist/static-lifecycle.js +262 -0
  52. package/dist/static-lifecycle.js.map +1 -0
  53. package/package.json +9 -5
@@ -1 +1 @@
1
- {"version":3,"file":"pty.d.ts","sourceRoot":"","sources":["../../src/runtime/pty.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAiB,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoBtF;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,OAAO;IACxC,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW;CAsJhE"}
1
+ {"version":3,"file":"pty.d.ts","sourceRoot":"","sources":["../../src/runtime/pty.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAiB,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoBtF;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,OAAO;IACxC,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW;CAgKhE"}
@@ -163,6 +163,14 @@ export class PtyRuntime {
163
163
  return () => dataSubs.delete(fn);
164
164
  },
165
165
  onExit: (fn) => {
166
+ // Already exited (a session attaching over a just-dead pty): fire on the next tick so the
167
+ // bridge surfaces a `process-exit` end frame instead of a silent zombie. proc.onExit fired
168
+ // ONCE before this listener existed, so a late subscriber would otherwise never hear it
169
+ // (waitForExit carries the same already-dead guard).
170
+ if (!alive) {
171
+ queueMicrotask(fn);
172
+ return () => { };
173
+ }
166
174
  exitSubs.add(fn);
167
175
  return () => exitSubs.delete(fn);
168
176
  },
@@ -171,10 +179,15 @@ export class PtyRuntime {
171
179
  proc.write(data);
172
180
  },
173
181
  resize: (c, r) => {
182
+ // node-pty REJECTS a non-positive dimension (throws), and a console fitting BEFORE its pane
183
+ // is laid out can send a 0. Guard BOTH the mirror and the pty resize so a degenerate geometry
184
+ // is a safe no-op — never a throw that would propagate into and wedge the serving frame
185
+ // handler (the live-e2e "zombie session" class).
186
+ if (c <= 0 || r <= 0)
187
+ return;
174
188
  cols = c;
175
189
  rows = r;
176
- if (c > 0 && r > 0)
177
- term.resize(c, r); // keep the mirror in step so snapshots reconstruct at size
190
+ term.resize(c, r); // keep the mirror in step so snapshots reconstruct at size
178
191
  if (alive)
179
192
  proc.resize(c, r);
180
193
  },
@@ -1 +1 @@
1
- {"version":3,"file":"pty.js","sourceRoot":"","sources":["../../src/runtime/pty.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pty.js","sourceRoot":"","sources":["../../src/runtime/pty.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The serving-side PTY ↔ session-rail bridge (P2 item 6). Given an authenticated §13.6 session
3
+ * (its verified grant + a connection scoped to the two eps rails) and a live pty {@link
4
+ * AttachSession}, it speaks the {@link TerminalFrame} framing over `openSessionRail(role:"serving")`:
5
+ *
6
+ * - the RECONSTRUCTION handshake (PR #158 preserved over the mesh): the caller opens its rail,
7
+ * then sends `ready`; the bridge replays the pty's byte-exact backlog snapshot (which can rebuild
8
+ * a full-screen TUI's alternate-screen buffer) and only then streams live output — so a late or
9
+ * third attach paints correctly without the child having to repaint. Live output that arrives
10
+ * while the snapshot is being built is buffered and flushed after it, in order (no chunk slips
11
+ * ahead of, or is lost before, the image);
12
+ * - duplex byte flow: pty output → `b` frames (serving → caller); caller `b` frames → pty
13
+ * keystrokes; `resize` frames → pty geometry;
14
+ * - BACKPRESSURE (item-6 pin: never silent loss): the core rail's window is bounded and refuses
15
+ * (`resource-exhausted`) rather than buffer; on refusal the bridge DROPS the chunk, accumulates
16
+ * the dropped-byte count, and prepends an explicit `drop` notice to the next frame the reopened
17
+ * window accepts — the caller always learns output was lost;
18
+ * - TERMINATION (item-6 pin 4): every teardown surfaces a DISTINCT end reason (`process-exit` /
19
+ * `closed` / `expired` / `target-despawn` / `manager-restart`) as an `end` frame before the rail
20
+ * closes, so the client can tell "the agent exited" from "you were detached" from "the manager
21
+ * restarted".
22
+ */
23
+ import type { NatsConnection } from "@nats-io/transport-node";
24
+ import { type SessionGrant, type AttachSession } from "@cotal-ai/core";
25
+ /** The reference manager's terminal-cause vocabulary (the `end.reason` tokens it surfaces — a
26
+ * bounded subset of the generic §13.6 terminal-session `end` reason). `process-exit` = the child
27
+ * exited; `closed` = a party closed the rail; `expired` = the offer/session TTL elapsed;
28
+ * `target-despawn` = the attached agent was despawned; `manager-restart` = the serving manager
29
+ * incarnation advanced its epoch (the successor refuses old-epoch sessions, §13.6). */
30
+ export type AttachEndReason = "process-exit" | "closed" | "expired" | "target-despawn" | "manager-restart";
31
+ export interface ServeSessionBridgeOpts {
32
+ /** A connection scoped to this session's two eps rails (the serving side's per-session credential,
33
+ * or — static mode — the manager's instrument connection whose rows cover the subtree). */
34
+ nc: NatsConnection;
35
+ /** The VERIFIED session grant (subjects/window/epoch); the bridge grants nothing, it only frames. */
36
+ grant: SessionGrant;
37
+ /** The live pty to bridge. */
38
+ session: AttachSession;
39
+ /** Fires once with the distinct end reason when the session tears down (either side). */
40
+ onEnd?(reason: AttachEndReason): void;
41
+ /** Passthrough rail timer knobs (testability). */
42
+ idleCreditMs?: number;
43
+ stallTimeoutMs?: number;
44
+ }
45
+ export interface SessionBridge {
46
+ /** Terminate the session with a distinct reason (target despawn / manager restart / expiry): the
47
+ * `end` frame is sent best-effort, then the rail closes and the pty is unsubscribed. Idempotent. */
48
+ end(reason: AttachEndReason): void;
49
+ /** In-memory observability (smoke assertions): the rail's window stats, the dropped-byte count
50
+ * (backpressure), the dropped-FRAME count (caller frames the codec rejected), and whether the
51
+ * reconstruction handshake has gone live. */
52
+ stats(): {
53
+ sent: number;
54
+ ackedThrough: number;
55
+ delivered: number;
56
+ inFlight: number;
57
+ droppedBytes: number;
58
+ droppedFrames: number;
59
+ live: boolean;
60
+ };
61
+ }
62
+ export declare function serveSessionBridge(opts: ServeSessionBridgeOpts): SessionBridge;
63
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/session/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAEL,KAAK,YAAY,EAAoB,KAAK,aAAa,EACxD,MAAM,gBAAgB,CAAC;AAExB;;;;wFAIwF;AACxF,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAE3G,MAAM,WAAW,sBAAsB;IACrC;gGAC4F;IAC5F,EAAE,EAAE,cAAc,CAAC;IACnB,qGAAqG;IACrG,KAAK,EAAE,YAAY,CAAC;IACpB,8BAA8B;IAC9B,OAAO,EAAE,aAAa,CAAC;IACvB,yFAAyF;IACzF,KAAK,CAAC,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACtC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B;yGACqG;IACrG,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC;;kDAE8C;IAC9C,KAAK,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CAClJ;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,aAAa,CAsI9E"}
@@ -0,0 +1,157 @@
1
+ import { EpEnvelopeError, openSessionRail, encodeTerminalData, terminalFrameBytes, decodeTerminalFrame, } from "@cotal-ai/core";
2
+ export function serveSessionBridge(opts) {
3
+ const { session } = opts;
4
+ let live = false; // has `ready` been received (backlog replayed, streaming live)?
5
+ let ended = false;
6
+ let droppedBytes = 0;
7
+ let droppedFrames = 0; // caller frames the codec rejected (observability; NOT a silent black hole)
8
+ const preReadyBuffer = [];
9
+ let rail;
10
+ // Send an application payload down the serving rail. Returns true on success; false when the
11
+ // window is FULL (`resource-exhausted`, the caller-must-drop signal); any OTHER failure
12
+ // (broken/closed rail) terminates the session — a broken transport is a distinct `closed` end.
13
+ const railSend = (p) => {
14
+ try {
15
+ rail.send(p);
16
+ return true;
17
+ }
18
+ catch (e) {
19
+ if (e instanceof EpEnvelopeError && e.code === "resource-exhausted")
20
+ return false;
21
+ end("closed");
22
+ return false;
23
+ }
24
+ };
25
+ // Forward one pty output chunk, honoring backpressure with an explicit drop-notice. A pending
26
+ // drop count is flushed FIRST (the caller must learn output was lost before the resumed stream),
27
+ // and only if that notice lands does the actual chunk go — otherwise the chunk's bytes join the
28
+ // drop count. Nothing is ever buffered unboundedly: a chunk the window can't take is DROPPED,
29
+ // counted, and surfaced, never queued.
30
+ const forwardOutput = (chunk) => {
31
+ if (ended)
32
+ return;
33
+ if (droppedBytes > 0) {
34
+ if (railSend({ k: "drop", bytes: droppedBytes }))
35
+ droppedBytes = 0;
36
+ else {
37
+ droppedBytes += chunk.length;
38
+ return;
39
+ }
40
+ }
41
+ if (!railSend(encodeTerminalData(chunk)))
42
+ droppedBytes += chunk.length;
43
+ };
44
+ const offData = session.onData((chunk) => {
45
+ if (ended)
46
+ return;
47
+ if (live)
48
+ forwardOutput(chunk);
49
+ else
50
+ preReadyBuffer.push(chunk); // hold until the snapshot is replayed, then flush in order
51
+ });
52
+ // The pty exit surfaces `process-exit` — but DEFERRED until the caller is live if it exits before
53
+ // the `ready` handshake (a session established over an already-dead, or a just-dying, pty): EPS is
54
+ // at-most-once, so an `end` frame sent before the caller subscribed to `.out` is lost. goLive sends
55
+ // the deferred exit AFTER the backlog, so the caller always learns the agent exited.
56
+ let pendingExit = false;
57
+ const offExit = session.onExit(() => { if (live)
58
+ end("process-exit");
59
+ else
60
+ pendingExit = true; });
61
+ // The reconstruction handshake: replay the byte-exact backlog snapshot, then flush anything the
62
+ // pty emitted while we built it, then stream live. Subscribing to output BEFORE this (above)
63
+ // means no chunk is lost between the snapshot and going live. A repeat `ready` (an explicit
64
+ // repaint) re-sends a fresh snapshot without re-flushing the already-drained pre-ready buffer.
65
+ const goLive = async () => {
66
+ let snapshot;
67
+ try {
68
+ snapshot = await session.backlog();
69
+ }
70
+ catch (e) {
71
+ end("closed");
72
+ void e;
73
+ return;
74
+ }
75
+ if (ended)
76
+ return;
77
+ if (snapshot.length)
78
+ forwardOutput(snapshot);
79
+ if (!live) {
80
+ for (const chunk of preReadyBuffer.splice(0))
81
+ forwardOutput(chunk);
82
+ live = true;
83
+ }
84
+ // The pty exited before we went live (established over a dead/dying pty): surface `process-exit`
85
+ // NOW, after the backlog reconstruction, so the caller sees the final screen AND the honest end.
86
+ if (pendingExit)
87
+ end("process-exit");
88
+ };
89
+ const onCallerFrame = (data) => {
90
+ // A caller frame must NEVER wedge the serving rail. A GARBLED or DEGENERATE frame — e.g. a console
91
+ // fitting before its pane is laid out sends a 0-dim resize, which the §13.6 codec rejects — is
92
+ // dropped, and each pty side effect is best-effort. One bad frame crashing this handler is exactly
93
+ // the live-e2e "zombie session" class (rail open, no echo, no honest end) that violates pin 4.
94
+ // But a drop is NEVER a black hole: it is COUNTED + LOGGED so a silent inbound failure (a caller
95
+ // whose frames all decode-reject) is diagnosable, not invisible.
96
+ let p;
97
+ try {
98
+ p = decodeTerminalFrame(data);
99
+ }
100
+ catch (e) {
101
+ droppedFrames++;
102
+ console.error(`! session ${opts.grant.sessionId}: dropped an undecodable caller frame #${droppedFrames} (${e.message})`);
103
+ return;
104
+ }
105
+ switch (p.k) {
106
+ case "ready":
107
+ void goLive();
108
+ return;
109
+ case "data":
110
+ try {
111
+ session.write(new TextDecoder().decode(terminalFrameBytes(p)));
112
+ }
113
+ catch { /* pty gone/degenerate; never wedge the rail */ }
114
+ return;
115
+ case "resize":
116
+ try {
117
+ session.resize(p.cols, p.rows);
118
+ }
119
+ catch { /* degenerate geometry; ignore, never wedge */ }
120
+ return;
121
+ // `end`/`drop` are serving → caller only; a caller sending one is out of protocol — ignore it.
122
+ case "end":
123
+ case "drop":
124
+ return;
125
+ }
126
+ };
127
+ function end(reason) {
128
+ if (ended)
129
+ return;
130
+ ended = true;
131
+ offData();
132
+ offExit();
133
+ try {
134
+ rail.send({ k: "end", reason }); // best-effort distinct end-state notice (advisory; may window out)
135
+ }
136
+ catch {
137
+ /* the ledger close/expiry is the authority; the notice is advisory (§13.6) */
138
+ }
139
+ rail.close();
140
+ opts.onEnd?.(reason);
141
+ }
142
+ rail = openSessionRail({
143
+ nc: opts.nc,
144
+ grant: opts.grant,
145
+ role: "serving",
146
+ onData: onCallerFrame,
147
+ onClose: () => end("closed"),
148
+ onProtocolError: () => end("closed"),
149
+ ...(opts.idleCreditMs !== undefined ? { idleCreditMs: opts.idleCreditMs } : {}),
150
+ ...(opts.stallTimeoutMs !== undefined ? { stallTimeoutMs: opts.stallTimeoutMs } : {}),
151
+ });
152
+ return {
153
+ end,
154
+ stats: () => ({ ...rail.stats(), droppedBytes, droppedFrames, live }),
155
+ };
156
+ }
157
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/session/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * The manager-side session ESTABLISHMENT (P2 item 6): mint the holder/target-lifecycle/
3
+ * instance+epoch-bound OFFER, and enforce its ONE-USE redemption through the §13.6 composite.
4
+ *
5
+ * Item 6 owns the offer mint + the STATIC redeem enforcement (this module) + the PTY bridge + the
6
+ * CLI/console clients + restart termination. The auth-service USER-MODE redemption handler
7
+ * (callout-minted per-session credentials) and the barrier session reconciler
8
+ * (implementations/auth/src/service.ts:358) are the #29 auth-trigger slice — OUT of item 6. This
9
+ * module exposes both halves through ONE {@link RedemptionSeam} interface: {@link
10
+ * staticRedemptionSeam} (wired) and {@link userModeRedemptionSeam} (a loud refusal until #29 lands
11
+ * — a user-mode attach must fail, never silently degrade to the static path).
12
+ *
13
+ * TARGET BINDING: the §13.6 grant is a CLOSED schema (holder + serving only), so the attached
14
+ * agent's (name, lifecycleUid) is bound MANAGER-SIDE — recorded in the {@link ManagerSessionRegistry}
15
+ * keyed by the fresh sessionId at mint, and re-checked live before the bridge serves (a despawned
16
+ * or replaced target ends the session with `target-despawn`). The holder + serving signature
17
+ * binding already stops a foreign party from redeeming or serving; the registry adds the target
18
+ * lifecycle the pin requires without widening the core artifact.
19
+ */
20
+ import type { NatsConnection } from "@nats-io/transport-node";
21
+ import { type AnchorResolver, type EpGateState, type LifecycleGatePin, type SessionCredential, type SessionGrant, type SessionLedger, type SessionPresenter } from "@cotal-ai/core";
22
+ /** The attached agent's incarnation coordinate — the "target lifecycle" the offer binds (pin 1). */
23
+ export interface SessionTarget {
24
+ name: string;
25
+ lifecycleUid: string;
26
+ }
27
+ /** The item-6 attach offer: the signed §13.6 grant plus the manager-side target binding. The REPLY
28
+ * to the caller carries the `grant` only (holder-bound, non-bearer — a leak releases nothing);
29
+ * `target` stays server-side (the caller already named it in the attach request). */
30
+ export interface AttachOffer {
31
+ grant: SessionGrant;
32
+ target: SessionTarget;
33
+ }
34
+ export interface MintAttachOfferArgs {
35
+ space: string;
36
+ /** The serving manager incarnation: its lifecycleUid + the current serve-gate epoch (item-3 seam
37
+ * — the §13.1 endpoint gate epoch; a successor incarnation advancing it refuses old sessions). */
38
+ serving: {
39
+ instanceId: string;
40
+ epoch: number;
41
+ };
42
+ /** The redeeming caller's triple, taken from the authenticated attach request (ctx.subject.caller). */
43
+ holder: {
44
+ id: string;
45
+ lifecycleUid: string;
46
+ processEpoch: number;
47
+ };
48
+ /** The attached agent + its incarnation (the target-lifecycle binding, recorded server-side). */
49
+ target: SessionTarget;
50
+ /** The manager's `sessions`-role signer (its own key material; the matching public key is its
51
+ * registered `sessions` trust anchor the redeem/verify path resolves). */
52
+ signer: {
53
+ keyId: string;
54
+ keyPair: {
55
+ sign(input: Uint8Array): Uint8Array;
56
+ };
57
+ };
58
+ /** Session lifetime (§13.6 live-class; bounds the whole session, not just a redeem window). */
59
+ ttlMs: number;
60
+ /** Max in-flight data frames per direction (bounded flow window). */
61
+ window?: number;
62
+ now?: number;
63
+ }
64
+ /** Mint an attach offer: a §13.6 session grant on the `manager` endpoint bound to the holder triple
65
+ * + serving instance/epoch, paired with the manager-side target binding. Pure — signs + returns;
66
+ * the manager records the offer in its {@link ManagerSessionRegistry}. */
67
+ export declare function mintAttachOffer(args: MintAttachOfferArgs): AttachOffer;
68
+ /** The redemption's serving-gate observation, carried WHOLE rather than as a bare revision.
69
+ *
70
+ * The §13.1 fence has to tell two revision moves apart: a BARRIER (which must refuse) and another
71
+ * sibling mint's identical-bytes commit touch (which must not — every per-session credential
72
+ * serializes on this one gate key, so refusing on contention would fail live sessions for no
73
+ * security reason). A revision alone cannot make that distinction, so the pin carries the gate
74
+ * state its revision came from and the fence compares EVERY field of it. */
75
+ export interface ServingGatePin extends LifecycleGatePin {
76
+ /** The observation the revision came from. Absent ONLY on an open mesh, where nothing is minted,
77
+ * nothing is staged, and there is no gate to fence against; the stage refuses loudly if it is
78
+ * ever missing on an auth mesh rather than staging unfenced. */
79
+ gate?: EpGateState;
80
+ }
81
+ /**
82
+ * The manager's per-session SERVING credential, injected because minting one needs the space auth
83
+ * and the §13.1 endpoint gate, which live on the Manager, not in this module.
84
+ *
85
+ * The four calls are the credential's whole life, in the order §13.6 requires: `mint` produces
86
+ * bytes that are NOT yet authority, `stage` writes the gate-checked §13.1 ledger row that makes
87
+ * them revocable, the redemption's finalize CAS is what promotes them, and `revoke` kills the row
88
+ * by name at the session's terminal. `open` is separate from `mint` on purpose: nothing connects
89
+ * until the session row is `active`.
90
+ */
91
+ export interface SessionServing {
92
+ /** Mint the per-session serving credential: exact-subject for THIS session only, expiring no
93
+ * later than the grant. Bytes only — no ledger row yet, so this confers nothing durable. */
94
+ mint(grant: SessionGrant): Promise<SessionCredential>;
95
+ /** Stage its §13.1 credential-ledger row into the serving instance's revocation family, fenced on
96
+ * `pin` — the gate observed during THIS redemption, which stays the authority: the commit CASes
97
+ * on its revision, and a lost CAS is refused unless the gate is still identical in every field
98
+ * but the revision. MUST throw if the gate moved — that loss is the lifecycle fence, and a throw
99
+ * here refuses the whole redemption. */
100
+ stage(grant: SessionGrant, cred: SessionCredential, pin: ServingGatePin): Promise<void>;
101
+ /** Open the serving connection for ONE session with that credential. MUST fail loud: there is no
102
+ * shared connection to fall back to, and serving a session without its own credential is exactly
103
+ * the standing-writer shape this design removes. */
104
+ open(cred: SessionCredential): Promise<NatsConnection>;
105
+ /** Revoke the credential by id, idempotently (§13.6 makes the sweep retry until the mark sticks).
106
+ *
107
+ * RESIDUAL, NAMED: this marks the §13.1 ledger row revoked; it does NOT evict a live connection.
108
+ * The session's own teardown closes its connection first, so in the ordinary path the credential
109
+ * has no connection left to use — but if that close fails, the JWT stays broker-valid until its
110
+ * TTL (bounded by the session exp). Cluster-verified eviction of these holders belongs to the
111
+ * §13.1 takeover barrier, which enumerates the family. So: do not read this as immediate broker
112
+ * death on session close. */
113
+ revoke(credentialId: string): Promise<void>;
114
+ /** LEADER-SERVED observation of the serving instance's §13.1 issuance gate, returned as the pin
115
+ * {@link stage} is CASed against. Real, not a placeholder: it is what makes the stage a fence. */
116
+ observeGate(endpoint: string, instanceId: string): Promise<ServingGatePin>;
117
+ }
118
+ /** The one interface both modes present. `redeem` VERIFIES the presented grant (signature/anchor/
119
+ * currency) then enforces the one-use CAS + presenter-equality; it THROWS on any refusal (a second
120
+ * redeem, a foreign presenter, an expired/forged grant) and returns the sessionId on success.
121
+ * `serving` then hands the SERVING party its own credential — a separate, authenticated retrieval
122
+ * (§13.6 per-party release: no private material crosses between the two parties, so it is never
123
+ * folded into the redemption answer). */
124
+ export interface RedemptionSeam {
125
+ redeem(grant: SessionGrant, presenter: SessionPresenter): Promise<{
126
+ sessionId: string;
127
+ }>;
128
+ serving(sessionId: string, presenter: {
129
+ endpoint: string;
130
+ instanceId: string;
131
+ epoch: number;
132
+ }): Promise<SessionCredential>;
133
+ }
134
+ type MaybePromise<T> = T | Promise<T>;
135
+ /** What {@link staticRedemptionSeam} reads from the manager's durable authority. In production the
136
+ * ledger + gate/epoch reads come from the auth store (leader-served); the smoke supplies an
137
+ * in-memory faithful ledger. */
138
+ export interface StaticRedemptionDeps {
139
+ space: string;
140
+ resolveAnchor: AnchorResolver;
141
+ ledger: SessionLedger;
142
+ /** The per-session serving credential's mint/stage/open/revoke seam (see {@link SessionServing}). */
143
+ serving: SessionServing;
144
+ holderProcessEpoch(holder: {
145
+ id: string;
146
+ lifecycleUid: string;
147
+ }): MaybePromise<number | undefined>;
148
+ servingEpoch(endpoint: string, instanceId: string): MaybePromise<number | undefined>;
149
+ observeHolderGate(holder: {
150
+ id: string;
151
+ lifecycleUid: string;
152
+ }): MaybePromise<LifecycleGatePin>;
153
+ observeServingGate(endpoint: string, instanceId: string): MaybePromise<ServingGatePin>;
154
+ now?(): number;
155
+ }
156
+ /**
157
+ * The STATIC redeem seam (item 6's wired path): the manager runs the §13.6 redemption — verify the
158
+ * signed grant, then `redeemSession` (the one-use `issuing` create-CAS + presenter-equality + the
159
+ * gate-pinned stage + the finalize's fresh epoch re-checks) — and, for the SERVING half, mints,
160
+ * stages, releases and revokes a real per-session credential through {@link SessionServing}.
161
+ *
162
+ * WHAT EACH HALF ACTUALLY GETS, stated exactly, because the two halves are NOT symmetric here and a
163
+ * comment claiming they are would be worse than the asymmetry:
164
+ *
165
+ * - SERVING half (this manager's own): a real `session-serving` credential, exact-subject
166
+ * (`eps.<endpoint>.<sessionId>.<epoch>.{in,out}`), TTL-bound to the session, staged into this
167
+ * instance's §13.1 `epcred.<endpoint>.<instanceId>` family under the open-and-commit fence, and
168
+ * revoked BY NAME at the session's terminal. It replaces a STANDING wildcard credential that
169
+ * reached every live session's bytes at its epoch (SPEC 13.9:2526).
170
+ * - CALLER half: NOT minted, staged, or revoked here, and `releaseCredential` returns a MARKER with
171
+ * no usable bytes for it. The caller's `session-caller` JWT is minted OUT OF BAND from the local
172
+ * space seed — by the console establisher and by CLI attach — after redemption.
173
+ *
174
+ * SPEC 13.6 PAIR-REVOKE IS NOT IMPLEMENTED FOR THE CALLER HALF. Stated exactly, because the
175
+ * difference between this and pair-revoke is the whole residual: that JWT is not written into the
176
+ * session lineage, is not named by the session row's credential material, and is untouched by
177
+ * session close and by takeover reconcile. It dies by TTL alone, at a 24h ceiling
178
+ * (`SESSION_GRANT_MAX_TTL_MS`).
179
+ *
180
+ * Why the window is tolerable for THIS static slice, as reviewed: the caller grant is
181
+ * exact-pinned to one `(endpoint, sessionId, epoch)`, so it can reach neither a sibling session
182
+ * nor a successor epoch; and once the serving half is revoked and its connection closed there is
183
+ * no counterparty on those two subjects. What survives is a broker-valid connection, not reach
184
+ * into another session. Closing it properly means minting the caller half inside redemption,
185
+ * which needs the user-mode (#29) callout exchange. Until that lands, do not describe any part of
186
+ * this as pair teardown.
187
+ * - `revokeCredential` is therefore ONE-SIDED by construction: it revokes an id this seam minted
188
+ * and is an explicit no-op for the caller id, rather than silently appearing to revoke both.
189
+ */
190
+ export declare function staticRedemptionSeam(deps: StaticRedemptionDeps): RedemptionSeam;
191
+ /** The USER-MODE redeem seam: UNWIRED (the #29 auth-trigger slice owns the callout-minted
192
+ * per-session credential path). It REFUSES LOUD, naming the path — a user-mode attach fails rather
193
+ * than degrading to the static seam (item-6 binding no-fallback rule). */
194
+ export declare function userModeRedemptionSeam(): RedemptionSeam;
195
+ /** The manager's in-memory session registry: the sessionId → (target lifecycle, offer) binding the
196
+ * §13.6 grant cannot carry. The serve path looks the target up here and re-checks its liveness
197
+ * before bridging, so a despawned/replaced target ends the session (`target-despawn`). */
198
+ export declare class ManagerSessionRegistry {
199
+ #private;
200
+ /** Record a freshly minted offer. Throws on a sessionId collision (a fresh unguessable id never
201
+ * repeats — a repeat is a mint bug, never silently overwritten). */
202
+ record(offer: AttachOffer): void;
203
+ /** The target bound to a sessionId, or undefined if unknown/removed. */
204
+ target(sessionId: string): SessionTarget | undefined;
205
+ /** Drop a session (redeem-refused, closed, expired, or target gone). Idempotent. */
206
+ remove(sessionId: string): void;
207
+ /** Every sessionId whose target is a given agent incarnation — the set a despawn/restart must end. */
208
+ forTarget(name: string, lifecycleUid: string): string[];
209
+ get size(): number;
210
+ }
211
+ export {};
212
+ //# sourceMappingURL=establish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"establish.d.ts","sourceRoot":"","sources":["../../src/session/establish.ts"],"names":[],"mappings":"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"}