@cotal-ai/manager 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/attach-endpoint.d.ts +53 -59
- package/dist/attach-endpoint.d.ts.map +1 -1
- package/dist/attach-endpoint.js +120 -244
- package/dist/attach-endpoint.js.map +1 -1
- package/dist/commands.js +88 -8
- package/dist/commands.js.map +1 -1
- package/dist/console/app.js +68 -30
- package/dist/console/index.html +3 -2
- package/dist/console/session-bundle.js +9736 -0
- package/dist/console-crypto-shim.d.ts +16 -0
- package/dist/console-crypto-shim.d.ts.map +1 -0
- package/dist/console-crypto-shim.js +20 -0
- package/dist/console-crypto-shim.js.map +1 -0
- package/dist/console-session-entry.d.ts +2 -0
- package/dist/console-session-entry.d.ts.map +1 -0
- package/dist/console-session-entry.js +26 -0
- package/dist/console-session-entry.js.map +1 -0
- package/dist/endpoint-evict.d.ts +29 -0
- package/dist/endpoint-evict.d.ts.map +1 -0
- package/dist/endpoint-evict.js +80 -0
- package/dist/endpoint-evict.js.map +1 -0
- package/dist/holder-liveness.d.ts +40 -0
- package/dist/holder-liveness.d.ts.map +1 -0
- package/dist/holder-liveness.js +98 -0
- package/dist/holder-liveness.js.map +1 -0
- package/dist/manager-service-contract.d.ts +132 -0
- package/dist/manager-service-contract.d.ts.map +1 -0
- package/dist/manager-service-contract.js +332 -0
- package/dist/manager-service-contract.js.map +1 -0
- package/dist/manager.d.ts +519 -22
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +2273 -262
- package/dist/manager.js.map +1 -1
- package/dist/reconcile-gate.d.ts +82 -0
- package/dist/reconcile-gate.d.ts.map +1 -0
- package/dist/reconcile-gate.js +118 -0
- package/dist/reconcile-gate.js.map +1 -0
- package/dist/runtime/pty.d.ts.map +1 -1
- package/dist/runtime/pty.js +15 -2
- package/dist/runtime/pty.js.map +1 -1
- package/dist/session/bridge.d.ts +63 -0
- package/dist/session/bridge.d.ts.map +1 -0
- package/dist/session/bridge.js +157 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/establish.d.ts +212 -0
- package/dist/session/establish.d.ts.map +1 -0
- package/dist/session/establish.js +174 -0
- package/dist/session/establish.js.map +1 -0
- package/dist/session/index.d.ts +12 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +15 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/plane.d.ts +120 -0
- package/dist/session/plane.d.ts.map +1 -0
- package/dist/session/plane.js +327 -0
- package/dist/session/plane.js.map +1 -0
- package/dist/static-lifecycle.d.ts +97 -0
- package/dist/static-lifecycle.d.ts.map +1 -0
- package/dist/static-lifecycle.js +262 -0
- package/dist/static-lifecycle.js.map +1 -0
- package/package.json +10 -6
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { KV } from "@nats-io/kv";
|
|
2
|
+
/** Which guard refused. The command prints this verbatim, and the smoke asserts on it, so a refusal
|
|
3
|
+
* can never be confused with a different refusal — the failure mode where an operator reads
|
|
4
|
+
* "refused" and force-retries the wrong thing. */
|
|
5
|
+
export type GateReconcileCondition =
|
|
6
|
+
/** No gate row at the coordinate — nothing to reconcile (a typo'd endpoint/instanceId). */
|
|
7
|
+
"no-gate"
|
|
8
|
+
/** The gate is `open` or `retired`: this repairs a frozen gate only. */
|
|
9
|
+
| "not-frozen"
|
|
10
|
+
/** Frozen under a takeover/activation/retirement op — this completes a REGISTRATION's obligation. */
|
|
11
|
+
| "wrong-op-kind"
|
|
12
|
+
/** The freeze-holder still holds a live connection. The freeze is protecting a live op. */
|
|
13
|
+
| "holder-alive"
|
|
14
|
+
/** The sweep under-reported (no responder, truncation, unproven single-server mode). May be live. */
|
|
15
|
+
| "holder-unknown"
|
|
16
|
+
/** The oracle could not be consulted at all, or answered unusably (unreachable, unprovisioned,
|
|
17
|
+
* garbled, or a reply that did not echo the principal asked about). */
|
|
18
|
+
| "liveness-unestablishable"
|
|
19
|
+
/** A holder's eviction was not VERIFIED gone — the barrier's own fail-closed step. */
|
|
20
|
+
| "eviction-unverified"
|
|
21
|
+
/** The token-pinned reopen lost its CAS: a newer barrier moved the gate. Re-observe. */
|
|
22
|
+
| "raced";
|
|
23
|
+
/** A refusal, carrying the condition as DATA rather than only as prose. */
|
|
24
|
+
export declare class GateReconcileRefused extends Error {
|
|
25
|
+
readonly condition: GateReconcileCondition;
|
|
26
|
+
constructor(condition: GateReconcileCondition, message: string);
|
|
27
|
+
}
|
|
28
|
+
/** The freeze-holder liveness verdict as the reconciler consumes it. `unestablishable` is kept
|
|
29
|
+
* DISTINCT from `unknown`: both refuse, but they tell the operator to fix different things (start
|
|
30
|
+
* the daemon vs. re-observe a mesh that could not be swept completely). */
|
|
31
|
+
export type HolderLiveness = {
|
|
32
|
+
state: "live";
|
|
33
|
+
detail: string;
|
|
34
|
+
} | {
|
|
35
|
+
state: "gone";
|
|
36
|
+
detail: string;
|
|
37
|
+
} | {
|
|
38
|
+
state: "unknown";
|
|
39
|
+
detail: string;
|
|
40
|
+
} | {
|
|
41
|
+
state: "unestablishable";
|
|
42
|
+
detail: string;
|
|
43
|
+
};
|
|
44
|
+
/** What the reconciliation found and did — returned on success, and logged either way. */
|
|
45
|
+
export interface GateReconcileReport {
|
|
46
|
+
endpoint: string;
|
|
47
|
+
instanceId: string;
|
|
48
|
+
holderPrincipal: string;
|
|
49
|
+
opId: string;
|
|
50
|
+
freezeToken: number;
|
|
51
|
+
/** The coordinate before the repair; the reopen advances `generation` by one and NOTHING else. */
|
|
52
|
+
before: {
|
|
53
|
+
generation: number;
|
|
54
|
+
processEpoch: number;
|
|
55
|
+
registrationRevision: number;
|
|
56
|
+
nameAuthorityRevision: number;
|
|
57
|
+
};
|
|
58
|
+
liveness: HolderLiveness;
|
|
59
|
+
familyRows: number;
|
|
60
|
+
revoked: string[];
|
|
61
|
+
evicted: string[];
|
|
62
|
+
reopenedAtGeneration: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Reconcile ONE frozen gate. Every seam the guard depends on is injected, so the command wires the
|
|
66
|
+
* real ones and the smoke drives the real barrier against an ephemeral broker.
|
|
67
|
+
*
|
|
68
|
+
* `probeHolder` is the AFFIRMATIVE check. It must return `gone` only on a proven-absent verdict;
|
|
69
|
+
* everything else — including any form of "we did not hear back" — must be `unknown` or
|
|
70
|
+
* `unestablishable`. It is a parameter and not an inlined call so that this ordering (probe, then
|
|
71
|
+
* refuse, THEN mutate) is structural: the barrier is not even constructed until the probe passed.
|
|
72
|
+
*/
|
|
73
|
+
export declare function reconcileEndpointGate(opts: {
|
|
74
|
+
kv: KV;
|
|
75
|
+
space: string;
|
|
76
|
+
endpoint: string;
|
|
77
|
+
instanceId: string;
|
|
78
|
+
probeHolder: (principal: string) => Promise<HolderLiveness>;
|
|
79
|
+
evict: (holderPrincipal: string) => Promise<boolean>;
|
|
80
|
+
log: (line: string) => void;
|
|
81
|
+
}): Promise<GateReconcileReport>;
|
|
82
|
+
//# sourceMappingURL=reconcile-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile-gate.d.ts","sourceRoot":"","sources":["../src/reconcile-gate.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC;;mDAEmD;AACnD,MAAM,MAAM,sBAAsB;AAChC,2FAA2F;AACzF,SAAS;AACX,wEAAwE;GACtE,YAAY;AACd,qGAAqG;GACnG,eAAe;AACjB,2FAA2F;GACzF,cAAc;AAChB,qGAAqG;GACnG,gBAAgB;AAClB;wEACwE;GACtE,0BAA0B;AAC5B,sFAAsF;GACpF,qBAAqB;AACvB,wFAAwF;GACtF,OAAO,CAAC;AAEZ,2EAA2E;AAC3E,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,SAAS,EAAE,sBAAsB;gBAAjC,SAAS,EAAE,sBAAsB,EAC1C,OAAO,EAAE,MAAM;CAKlB;AAED;;4EAE4E;AAC5E,MAAM,MAAM,cAAc,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,kGAAkG;IAClG,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAA;KAAE,CAAC;IAClH,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,KAAK,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA4F/B"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GUARDED RECONCILIATION of an endpoint issuance gate left FROZEN by a crashed re-registration
|
|
3
|
+
* (Cotal #391; SPEC 13.1 "the gate is left frozen for reconciliation").
|
|
4
|
+
*
|
|
5
|
+
* THE STATE THIS REPAIRS, and the only one it accepts: a manager restart was killed between the
|
|
6
|
+
* barrier's freeze and the successor's completion. The gate is `frozen` under a `registration` op
|
|
7
|
+
* whose holder no longer exists, so the freeze token's owner can never resume. Fail-closed is
|
|
8
|
+
* correct and stays correct — but in THAT state the freeze protects nothing while blocking every
|
|
9
|
+
* restart, and before this the operator's only exits were hand-driving internals or discarding
|
|
10
|
+
* state.
|
|
11
|
+
*
|
|
12
|
+
* The repair itself is not new: it is the SHIPPED composition (`endpointRegistrationBarrier` +
|
|
13
|
+
* a verified evictor), driven in the §13.1 order, with no raw writes. What is new is the GUARD in
|
|
14
|
+
* front of it, which is the whole point of the command:
|
|
15
|
+
*
|
|
16
|
+
* 1. VERIFY THE HOLDER IS GONE, AFFIRMATIVELY. Not "the holder did not answer", not "a timeout
|
|
17
|
+
* elapsed" — a COMPLETE, single-server-proven CONNZ sweep that PROVES no connection attributes
|
|
18
|
+
* to the freeze-holder. Absence of evidence is `unknown`, and `unknown` REFUSES.
|
|
19
|
+
* 2. LOG WHAT WAS FOUND, before mutating anything.
|
|
20
|
+
* 3. REFUSE LOUD, NAMING WHICH CONDITION FAILED — an operator staring at a wedged mesh needs to
|
|
21
|
+
* know whether the holder is alive, whether liveness could not be established, or whether the
|
|
22
|
+
* gate simply is not in the state this repairs. "It refused" is not actionable.
|
|
23
|
+
*
|
|
24
|
+
* The probe sits ON TOP OF the barrier's own fail-closed eviction, never in place of it: BOTH must
|
|
25
|
+
* pass. There is deliberately NO force flag and no path that discards gate state — a recovery path
|
|
26
|
+
* whose failure mode is killing a live manager does not get an override.
|
|
27
|
+
*/
|
|
28
|
+
import { endpointRegistrationBarrier, parseEndpointGate, epgateKey, } from "@cotal-ai/core";
|
|
29
|
+
/** A refusal, carrying the condition as DATA rather than only as prose. */
|
|
30
|
+
export class GateReconcileRefused extends Error {
|
|
31
|
+
condition;
|
|
32
|
+
constructor(condition, message) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.condition = condition;
|
|
35
|
+
this.name = "GateReconcileRefused";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reconcile ONE frozen gate. Every seam the guard depends on is injected, so the command wires the
|
|
40
|
+
* real ones and the smoke drives the real barrier against an ephemeral broker.
|
|
41
|
+
*
|
|
42
|
+
* `probeHolder` is the AFFIRMATIVE check. It must return `gone` only on a proven-absent verdict;
|
|
43
|
+
* everything else — including any form of "we did not hear back" — must be `unknown` or
|
|
44
|
+
* `unestablishable`. It is a parameter and not an inlined call so that this ordering (probe, then
|
|
45
|
+
* refuse, THEN mutate) is structural: the barrier is not even constructed until the probe passed.
|
|
46
|
+
*/
|
|
47
|
+
export async function reconcileEndpointGate(opts) {
|
|
48
|
+
const { kv, space, endpoint, instanceId, log } = opts;
|
|
49
|
+
// ---- 1. Observe the gate RAW: the freeze token IS the row revision, and the dead op's opId is
|
|
50
|
+
// on the row. Both are needed to complete that op's obligation rather than start a new one.
|
|
51
|
+
const key = epgateKey(endpoint, instanceId);
|
|
52
|
+
const entry = await kv.get(key);
|
|
53
|
+
if (!entry || entry.operation !== "PUT")
|
|
54
|
+
throw new GateReconcileRefused("no-gate", `no endpoint gate at ${key} — nothing to reconcile (check the endpoint and instanceId)`);
|
|
55
|
+
const row = parseEndpointGate(entry.value, key);
|
|
56
|
+
const freezeToken = entry.revision;
|
|
57
|
+
log(`gate ${key}: state=${row.state} generation=${row.generation} processEpoch=${row.processEpoch} registrationRevision=${row.registrationRevision} nameAuthorityRevision=${row.nameAuthorityRevision} op=${JSON.stringify(row.op ?? null)} holder=${row.principal} revision=${freezeToken}`);
|
|
58
|
+
if (row.state !== "frozen")
|
|
59
|
+
throw new GateReconcileRefused("not-frozen", `the gate at ${key} is "${row.state}", not "frozen" — this reconciles a frozen gate only, and an open gate needs no repair`);
|
|
60
|
+
if (row.op?.kind !== "registration")
|
|
61
|
+
throw new GateReconcileRefused("wrong-op-kind", `the gate at ${key} is frozen under a "${row.op?.kind}" op, not a registration — this completes a crashed REGISTRATION's §13.1 obligation only; refusing to reinterpret another op's intent`);
|
|
62
|
+
const opId = row.op.opId;
|
|
63
|
+
// ---- 2. THE GUARD. Affirmative liveness, before anything is mutated.
|
|
64
|
+
const liveness = await opts.probeHolder(row.principal);
|
|
65
|
+
log(`freeze-holder ${row.principal}: ${liveness.state} — ${liveness.detail}`);
|
|
66
|
+
if (liveness.state === "live")
|
|
67
|
+
throw new GateReconcileRefused("holder-alive", `the freeze-holder "${row.principal}" is ALIVE (${liveness.detail}) — the freeze is protecting an op that is still running. Refusing: reconciling here would revoke and evict a live incarnation's credential family. Stop that process first, then re-run.`);
|
|
68
|
+
if (liveness.state === "unknown")
|
|
69
|
+
throw new GateReconcileRefused("holder-unknown", `the liveness of freeze-holder "${row.principal}" is UNKNOWN (${liveness.detail}) — the sweep could not prove it absent, and absence of evidence is not evidence of absence. Refusing: a holder that may still be live is treated as live.`);
|
|
70
|
+
if (liveness.state === "unestablishable")
|
|
71
|
+
throw new GateReconcileRefused("liveness-unestablishable", `liveness for freeze-holder "${row.principal}" CANNOT BE ESTABLISHED (${liveness.detail}) — without the oracle this repair has no affirmative check to stand on, and it will not infer death from silence.`);
|
|
72
|
+
// ---- 3. Only now: the shipped composition, in the §13.1 order, over the DEAD op's own id.
|
|
73
|
+
const barrier = endpointRegistrationBarrier(kv, space, { endpoint, instanceId, opId, evict: opts.evict });
|
|
74
|
+
const rows = await barrier.enumerate();
|
|
75
|
+
log(`family: ${rows.length} ledger row(s)`);
|
|
76
|
+
const revoked = [];
|
|
77
|
+
for (const r of rows) {
|
|
78
|
+
if (r.state === "active") {
|
|
79
|
+
await barrier.revoke(r); // deny-new BEFORE kill-live — the precondition eviction's name carries
|
|
80
|
+
revoked.push(r.credentialId);
|
|
81
|
+
log(` revoked ${r.credentialId} (${r.holderPrincipal})`);
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
log(` ${r.state}: ${r.credentialId} (${r.holderPrincipal})`);
|
|
85
|
+
}
|
|
86
|
+
// Evict every distinct family holder, and the freeze-holder itself even when it staged no rows —
|
|
87
|
+
// the probe proved it gone, and the barrier's verify is what makes that durable rather than a
|
|
88
|
+
// snapshot. An unverified eviction aborts and LEAVES THE GATE FROZEN (unchanged §13.1 posture).
|
|
89
|
+
const holders = [...new Set([row.principal, ...rows.map((r) => r.holderPrincipal)])];
|
|
90
|
+
const evicted = [];
|
|
91
|
+
for (const h of holders) {
|
|
92
|
+
if (!(await barrier.evict(h)))
|
|
93
|
+
throw new GateReconcileRefused("eviction-unverified", `eviction of "${h}" was NOT verified gone — the gate stays frozen (fail-closed, SPEC 13.1). Nothing was reopened; the revocations above are deny-new and safe to leave.`);
|
|
94
|
+
evicted.push(h);
|
|
95
|
+
log(` verified evicted: ${h}`);
|
|
96
|
+
}
|
|
97
|
+
// ---- 4. Token-pinned abort-reopen at the UNCHANGED coordinate. The dead op wrote nothing
|
|
98
|
+
// forward, so only `generation` advances; the successor's normal takeover then runs end-to-end.
|
|
99
|
+
const reopenedAtGeneration = row.generation + 1;
|
|
100
|
+
const ok = await barrier.reopen(freezeToken, {
|
|
101
|
+
generation: reopenedAtGeneration,
|
|
102
|
+
processEpoch: row.processEpoch,
|
|
103
|
+
registrationRevision: row.registrationRevision,
|
|
104
|
+
nameAuthorityRevision: row.nameAuthorityRevision,
|
|
105
|
+
});
|
|
106
|
+
if (!ok)
|
|
107
|
+
throw new GateReconcileRefused("raced", `the token-pinned reopen of ${key} lost its CAS — a newer barrier moved the gate while this repair ran. Nothing was reopened; re-observe before retrying.`);
|
|
108
|
+
log(`✓ gate ${key} reopened at generation=${reopenedAtGeneration}, processEpoch unchanged (${row.processEpoch}); family revoked (${revoked.length}) and verify-evicted (${evicted.length} holder(s))`);
|
|
109
|
+
return {
|
|
110
|
+
endpoint, instanceId, holderPrincipal: row.principal, opId, freezeToken,
|
|
111
|
+
before: {
|
|
112
|
+
generation: row.generation, processEpoch: row.processEpoch,
|
|
113
|
+
registrationRevision: row.registrationRevision, nameAuthorityRevision: row.nameAuthorityRevision,
|
|
114
|
+
},
|
|
115
|
+
liveness, familyRows: rows.length, revoked, evicted, reopenedAtGeneration,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=reconcile-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile-gate.js","sourceRoot":"","sources":["../src/reconcile-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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"}
|
package/dist/runtime/pty.js
CHANGED
|
@@ -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
|
-
|
|
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
|
},
|
package/dist/runtime/pty.js.map
CHANGED
|
@@ -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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"}
|