@cotal-ai/manager 0.90.1 → 0.91.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 (48) hide show
  1. package/dist/chat-session.d.ts +165 -0
  2. package/dist/chat-session.d.ts.map +1 -0
  3. package/dist/chat-session.js +281 -0
  4. package/dist/chat-session.js.map +1 -0
  5. package/dist/commands.d.ts +3 -0
  6. package/dist/commands.d.ts.map +1 -1
  7. package/dist/commands.js +374 -163
  8. package/dist/commands.js.map +1 -1
  9. package/dist/endpoint-evict.d.ts +2 -0
  10. package/dist/endpoint-evict.d.ts.map +1 -1
  11. package/dist/endpoint-evict.js +1 -0
  12. package/dist/endpoint-evict.js.map +1 -1
  13. package/dist/holder-liveness.d.ts +1 -0
  14. package/dist/holder-liveness.d.ts.map +1 -1
  15. package/dist/holder-liveness.js.map +1 -1
  16. package/dist/index.d.ts +4 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/manager-service-contract.d.ts +52 -1
  21. package/dist/manager-service-contract.d.ts.map +1 -1
  22. package/dist/manager-service-contract.js +138 -4
  23. package/dist/manager-service-contract.js.map +1 -1
  24. package/dist/manager.d.ts +105 -2
  25. package/dist/manager.d.ts.map +1 -1
  26. package/dist/manager.js +515 -49
  27. package/dist/manager.js.map +1 -1
  28. package/dist/operator-deregister.d.ts +4 -0
  29. package/dist/operator-deregister.d.ts.map +1 -0
  30. package/dist/operator-deregister.js +75 -0
  31. package/dist/operator-deregister.js.map +1 -0
  32. package/dist/service-adapter.d.ts +12 -0
  33. package/dist/service-adapter.d.ts.map +1 -0
  34. package/dist/service-adapter.js +174 -0
  35. package/dist/service-adapter.js.map +1 -0
  36. package/dist/service-child.d.ts +37 -0
  37. package/dist/service-child.d.ts.map +1 -0
  38. package/dist/service-child.js +195 -0
  39. package/dist/service-child.js.map +1 -0
  40. package/dist/service-observation.d.ts +19 -0
  41. package/dist/service-observation.d.ts.map +1 -0
  42. package/dist/service-observation.js +97 -0
  43. package/dist/service-observation.js.map +1 -0
  44. package/dist/static-lifecycle.d.ts +8 -6
  45. package/dist/static-lifecycle.d.ts.map +1 -1
  46. package/dist/static-lifecycle.js +19 -8
  47. package/dist/static-lifecycle.js.map +1 -1
  48. package/package.json +13 -12
@@ -0,0 +1,165 @@
1
+ import { type EpErrorCode, type StaticManagedSlotRow } from "@cotal-ai/core";
2
+ /** Every static chat alias starts with this. An ordinary spawn refuses any name that does. */
3
+ export declare const CHAT_ALIAS_PREFIX = "chat_";
4
+ /** Draw a fresh `chat_<26 base32>` alias (130 random bits). 256 is a multiple of 32, so masking each
5
+ * byte keeps every symbol uniform. */
6
+ export declare function drawChatAlias(): string;
7
+ /** Whether `name` has the exact shape {@link drawChatAlias} produces. */
8
+ export declare function isChatAlias(name: string): boolean;
9
+ /** A `chat-session-open` request, as {@link readChatOpenInput} reads it. */
10
+ export interface ChatSessionOpenInput {
11
+ subscribe?: string[];
12
+ allowSubscribe?: string[];
13
+ allowPublish?: string[];
14
+ label: string;
15
+ ttl: number;
16
+ sealTo: string;
17
+ }
18
+ /** The bounds the served `chat-session-open` schema states. The pure smoke holds them equal. */
19
+ export declare const CHAT_OPEN_BOUNDS: {
20
+ readonly listItems: 64;
21
+ readonly labelLength: 128;
22
+ readonly ttlSec: 900;
23
+ };
24
+ /** Read a `chat-session-open` request from its raw arguments, or the refusal. The ep door checks the
25
+ * served schema first; this reads every field the handler uses again, so no unchecked value reaches
26
+ * it. Channel validity, a blank label and the curve shape of `sealTo` are {@link chatOpenLists}'s. */
27
+ export declare function readChatOpenInput(raw: unknown): ChatSessionOpenInput | {
28
+ error: string;
29
+ };
30
+ /** Read a `chat-session-retire` request from its raw arguments, or the refusal. The alias shape and
31
+ * the slot's ownership are {@link chatRetireRefusal}'s and the handler's. */
32
+ export declare function readChatRetireInput(raw: unknown): {
33
+ alias: string;
34
+ actor: string;
35
+ lifecycleUid: string;
36
+ } | {
37
+ error: string;
38
+ };
39
+ /** The three lists of an open request under a spawn's own rules, or the refusal. Every entry must
40
+ * be a valid channel, as the provisioner and the mint require; the initial channels must lie
41
+ * within the read ceiling, which falls back to them when empty (`resolveReadAcl`); the post list
42
+ * is default-deny. The foreign event-channel rule needs the drawn actor, so the handler applies
43
+ * it. {@link readChatOpenInput} bounds the label, each list and the ttl first. */
44
+ export declare function chatOpenLists(input: {
45
+ subscribe?: readonly string[];
46
+ allowSubscribe?: readonly string[];
47
+ allowPublish?: readonly string[];
48
+ label: string;
49
+ sealTo: string;
50
+ }): {
51
+ subscribe: string[];
52
+ allowSubscribe: string[];
53
+ allowPublish: string[];
54
+ } | {
55
+ error: string;
56
+ };
57
+ /** What `chat-session-open` seals to the caller's `sealTo`: the credential bound to the space,
58
+ * the admitting manager instance and every field of the reply. The client refuses any other key
59
+ * set and any field that differs from the reply or from what it asked. */
60
+ export interface SealedChatAdmission {
61
+ readonly v: 1;
62
+ readonly space: string;
63
+ readonly managerInstanceId: string;
64
+ readonly alias: string;
65
+ readonly actor: string;
66
+ readonly lifecycleUid: string;
67
+ readonly expiresAt: number;
68
+ readonly sealTo: string;
69
+ readonly creds: string;
70
+ }
71
+ /** Seal one admission to its `sealTo` under a one-time sender key. */
72
+ export declare function sealChatAdmission(admission: Omit<SealedChatAdmission, "v">): {
73
+ sealer: string;
74
+ sealed: string;
75
+ };
76
+ /** The ownership guard for `chat-session-retire`, or undefined when the slot may be retired. It
77
+ * ends only a slot `chat-session-open` admitted on THIS logical manager instance, at the
78
+ * requested incarnation: never an ordinary agent's slot, a sibling's, a legacy row with no
79
+ * recorded owner, or another incarnation of the alias. */
80
+ export declare function chatRetireRefusal(row: StaticManagedSlotRow | undefined, request: {
81
+ alias: string;
82
+ actor: string;
83
+ lifecycleUid: string;
84
+ }, managerInstanceId: string): {
85
+ code: EpErrorCode;
86
+ message: string;
87
+ } | undefined;
88
+ /** How many chat retirements one manager process runs at once, at expiry and at stop. Each is a
89
+ * full static terminal (KV round trips, a broker eviction scan and a deprovision), so a burst
90
+ * waits its turn instead of opening that many terminals together. It bounds work in flight, not
91
+ * sessions. */
92
+ export declare const CHAT_EXPIRY_CONCURRENCY = 4;
93
+ /** One session this manager process admitted, or is admitting, as its cleanup needs it. */
94
+ export interface ExpiringChatSession {
95
+ readonly alias: string;
96
+ readonly actor: string;
97
+ readonly lifecycleUid: string;
98
+ /** Its resolved read ceiling; the concrete channels in it name its membership rows for the
99
+ * teardown, and the delivery inventory finds the rest. */
100
+ readonly channels: readonly string[];
101
+ /** The leaf's expiry, epoch ms. */
102
+ readonly expiresAt: number;
103
+ }
104
+ /** The clock the tracker runs on. Production uses the process clock; a smoke drives its own. */
105
+ export interface ChatExpiryTimers {
106
+ readonly now: () => number;
107
+ readonly set: (fn: () => void, ms: number) => unknown;
108
+ readonly clear: (handle: unknown) => void;
109
+ }
110
+ /**
111
+ * The chat sessions this manager process admitted, from before each one's first durable write
112
+ * until a retirement of it is confirmed. It retires each at its leaf's expiry, so a reply lost on
113
+ * the way back or a client that never retires still ends then, and it names to the manager's
114
+ * sweep and stop the exact alias, actor and UID of every session this process holds.
115
+ *
116
+ * It knows only what this process registered and never reads the slot store, so it cannot reach
117
+ * an ordinary agent's slot, a sibling's, a legacy row or a session another process admitted.
118
+ * `retire` runs the exact-owned retirement; a throw is a failure, retried after each of
119
+ * `retryDelaysMs`. A session whose retries are spent stays tracked as `held`, for a later retire
120
+ * or the stop.
121
+ */
122
+ export declare class ChatSessionExpiry {
123
+ private readonly retire;
124
+ private readonly options;
125
+ private readonly sessions;
126
+ private readonly due;
127
+ private running;
128
+ private stopped;
129
+ private readonly timers;
130
+ constructor(retire: (session: ExpiringChatSession) => Promise<void>, options: {
131
+ readonly retryDelaysMs: readonly number[];
132
+ readonly concurrency: number;
133
+ readonly log: (line: string) => void;
134
+ readonly timers?: ChatExpiryTimers;
135
+ });
136
+ /** Register a session the open handler is about to write, before its first durable write. It is
137
+ * not scheduled until {@link arm}. Throws once stopped and for a UID already registered. */
138
+ register(session: ExpiringChatSession): void;
139
+ /** Schedule a registered session's retirement at its expiry: once its opening succeeded, or once
140
+ * a rollback of it did not complete. Throws once stopped, so an opening that finishes after a
141
+ * stop began is rolled back instead of being handed out; the session stays registered for the
142
+ * stop either way. */
143
+ arm(lifecycleUid: string): void;
144
+ /** Whether this process holds a session at this exact alias, actor and UID, in any state. */
145
+ holdsExact(slot: {
146
+ readonly alias: string;
147
+ readonly actor: string;
148
+ readonly lifecycleUid: string;
149
+ }): boolean;
150
+ /** The admitted channels of a tracked session, or undefined once it is not tracked. */
151
+ channels(lifecycleUid: string): readonly string[] | undefined;
152
+ /** Stop tracking a session whose retirement was confirmed. A retirement of it already running
153
+ * finishes, and its outcome is dropped. */
154
+ forget(lifecycleUid: string): void;
155
+ /** Stop scheduling and refuse new sessions. Every tracked session stays tracked for the stop to
156
+ * retire or report, and each one not running becomes `held`. */
157
+ stop(): void;
158
+ /** Every tracked session. One whose expiry retirement is still settling is included: the
159
+ * manager runs one terminal per UID, so a second caller joins it rather than racing it. */
160
+ remaining(): ExpiringChatSession[];
161
+ private schedule;
162
+ private pump;
163
+ private failed;
164
+ }
165
+ //# sourceMappingURL=chat-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-session.d.ts","sourceRoot":"","sources":["../src/chat-session.ts"],"names":[],"mappings":"AAWA,OAAO,EAAkE,KAAK,WAAW,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE7I,8FAA8F;AAC9F,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAKzC;uCACuC;AACvC,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,4EAA4E;AAC5E,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gGAAgG;AAChG,eAAO,MAAM,gBAAgB;;;;CAA4D,CAAC;AAU1F;;uGAEuG;AACvG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAqBxF;AAED;8EAC8E;AAC9E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAW5H;AAED;;;;mFAImF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAWhG;AAED;;2EAE2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IACd,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,mBAAmB,EAAE,GAAG,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAG/G;AAED;;;2DAG2D;AAC3D,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,oBAAoB,GAAG,SAAS,EACrC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EAC/D,iBAAiB,EAAE,MAAM,GACxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAYpD;AAED;;;gBAGgB;AAChB,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,2FAA2F;AAC3F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;+DAC2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,mCAAmC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,gGAAgG;AAChG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACtD,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C;AA0BD;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAQ1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAClE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAGvB,MAAM,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,EACvD,OAAO,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAAE;IAKjL;iGAC6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAM5C;;;2BAGuB;IACvB,GAAG,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAQ/B,6FAA6F;IAC7F,UAAU,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAK5G,uFAAuF;IACvF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS;IAI7D;gDAC4C;IAC5C,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IASlC;qEACiE;IACjE,IAAI,IAAI,IAAI;IAWZ;gGAC4F;IAC5F,SAAS,IAAI,mBAAmB,EAAE;IAIlC,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,IAAI;IAsBZ,OAAO,CAAC,MAAM;CAkBf"}
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Static chat sessions (S mode): the manager-mediated admission for a live human or program
3
+ * session on a static-auth mesh. The manager draws the alias, mints the session's own leaf over the
4
+ * native static activation and provisioning, and retires it through the native static terminal.
5
+ * This module holds the pure rules those two handlers share, the sealed admission payload, and the
6
+ * tracker that retires a session nobody retired; it reads and writes no store itself.
7
+ *
8
+ * The wire authority of a session is its incarnation-unique nkey (`actor`). The `chat_` alias is
9
+ * routing only: it keys the durable slot row and is never a caller input at open.
10
+ */
11
+ import { randomBytes } from "node:crypto";
12
+ import { assertValidChannel, isCurvePublicKey, resolveReadAcl, sealJson } from "@cotal-ai/core";
13
+ /** Every static chat alias starts with this. An ordinary spawn refuses any name that does. */
14
+ export const CHAT_ALIAS_PREFIX = "chat_";
15
+ const BASE32 = "abcdefghijklmnopqrstuvwxyz234567";
16
+ const CHAT_ALIAS = /^chat_[a-z2-7]{26}$/;
17
+ /** Draw a fresh `chat_<26 base32>` alias (130 random bits). 256 is a multiple of 32, so masking each
18
+ * byte keeps every symbol uniform. */
19
+ export function drawChatAlias() {
20
+ return CHAT_ALIAS_PREFIX + Array.from(randomBytes(26), (b) => BASE32[b & 31]).join("");
21
+ }
22
+ /** Whether `name` has the exact shape {@link drawChatAlias} produces. */
23
+ export function isChatAlias(name) {
24
+ return CHAT_ALIAS.test(name);
25
+ }
26
+ /** The bounds the served `chat-session-open` schema states. The pure smoke holds them equal. */
27
+ export const CHAT_OPEN_BOUNDS = { listItems: 64, labelLength: 128, ttlSec: 900 };
28
+ const OPEN_FIELDS = ["subscribe", "allowSubscribe", "allowPublish", "label", "ttl", "sealTo"];
29
+ const RETIRE_FIELDS = ["alias", "actor", "lifecycleUid"];
30
+ /** The raw arguments as a plain object, or undefined. */
31
+ function argObject(raw) {
32
+ return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : undefined;
33
+ }
34
+ /** Read a `chat-session-open` request from its raw arguments, or the refusal. The ep door checks the
35
+ * served schema first; this reads every field the handler uses again, so no unchecked value reaches
36
+ * it. Channel validity, a blank label and the curve shape of `sealTo` are {@link chatOpenLists}'s. */
37
+ export function readChatOpenInput(raw) {
38
+ const bad = (why) => ({ error: `chat-session-open: ${why}` });
39
+ const a = argObject(raw);
40
+ if (!a)
41
+ return bad("the arguments must be an object");
42
+ const extra = Object.keys(a).find((key) => !OPEN_FIELDS.includes(key));
43
+ if (extra !== undefined)
44
+ return bad(`unknown field "${extra}"`);
45
+ const lists = {};
46
+ for (const key of ["subscribe", "allowSubscribe", "allowPublish"]) {
47
+ const list = a[key];
48
+ if (list === undefined)
49
+ continue;
50
+ if (!Array.isArray(list) || list.length > CHAT_OPEN_BOUNDS.listItems || !list.every((c) => typeof c === "string" && c.length > 0) || new Set(list).size !== list.length)
51
+ return bad(`${key} must be a list of at most ${CHAT_OPEN_BOUNDS.listItems} distinct, non-empty channel names`);
52
+ lists[key] = [...list];
53
+ }
54
+ const { label, ttl, sealTo } = a;
55
+ if (typeof label !== "string" || label.length === 0 || label.length > CHAT_OPEN_BOUNDS.labelLength)
56
+ return bad(`label must be a string of 1 to ${CHAT_OPEN_BOUNDS.labelLength} characters`);
57
+ if (typeof ttl !== "number" || !Number.isSafeInteger(ttl) || ttl < 1 || ttl > CHAT_OPEN_BOUNDS.ttlSec)
58
+ return bad(`ttl must be a whole number of seconds from 1 to ${CHAT_OPEN_BOUNDS.ttlSec}`);
59
+ if (typeof sealTo !== "string")
60
+ return bad("sealTo must be a string");
61
+ return { ...lists, label, ttl, sealTo };
62
+ }
63
+ /** Read a `chat-session-retire` request from its raw arguments, or the refusal. The alias shape and
64
+ * the slot's ownership are {@link chatRetireRefusal}'s and the handler's. */
65
+ export function readChatRetireInput(raw) {
66
+ const bad = (why) => ({ error: `chat-session-retire: ${why}` });
67
+ const a = argObject(raw);
68
+ if (!a)
69
+ return bad("the arguments must be an object");
70
+ const extra = Object.keys(a).find((key) => !RETIRE_FIELDS.includes(key));
71
+ if (extra !== undefined)
72
+ return bad(`unknown field "${extra}"`);
73
+ const { alias, actor, lifecycleUid } = a;
74
+ if (typeof alias !== "string" || alias.length === 0)
75
+ return bad("alias must be a non-empty string");
76
+ if (typeof actor !== "string" || actor.length === 0)
77
+ return bad("actor must be a non-empty string");
78
+ if (typeof lifecycleUid !== "string" || lifecycleUid.length === 0)
79
+ return bad("lifecycleUid must be a non-empty string");
80
+ return { alias, actor, lifecycleUid };
81
+ }
82
+ /** The three lists of an open request under a spawn's own rules, or the refusal. Every entry must
83
+ * be a valid channel, as the provisioner and the mint require; the initial channels must lie
84
+ * within the read ceiling, which falls back to them when empty (`resolveReadAcl`); the post list
85
+ * is default-deny. The foreign event-channel rule needs the drawn actor, so the handler applies
86
+ * it. {@link readChatOpenInput} bounds the label, each list and the ttl first. */
87
+ export function chatOpenLists(input) {
88
+ if (!input.label.trim())
89
+ return { error: "chat-session-open: label must not be blank" };
90
+ if (!isCurvePublicKey(input.sealTo))
91
+ return { error: "chat-session-open: sealTo is not a curve public key" };
92
+ const subscribe = [...(input.subscribe ?? [])];
93
+ const allowPublish = [...(input.allowPublish ?? [])];
94
+ try {
95
+ for (const channel of [...subscribe, ...(input.allowSubscribe ?? []), ...allowPublish])
96
+ assertValidChannel(channel);
97
+ return { subscribe, allowSubscribe: resolveReadAcl(subscribe, [...(input.allowSubscribe ?? [])]), allowPublish };
98
+ }
99
+ catch (e) {
100
+ return { error: `chat-session-open: ${e.message}` };
101
+ }
102
+ }
103
+ /** Seal one admission to its `sealTo` under a one-time sender key. */
104
+ export function sealChatAdmission(admission) {
105
+ const payload = { v: 1, ...admission };
106
+ return sealJson(payload, admission.sealTo);
107
+ }
108
+ /** The ownership guard for `chat-session-retire`, or undefined when the slot may be retired. It
109
+ * ends only a slot `chat-session-open` admitted on THIS logical manager instance, at the
110
+ * requested incarnation: never an ordinary agent's slot, a sibling's, a legacy row with no
111
+ * recorded owner, or another incarnation of the alias. */
112
+ export function chatRetireRefusal(row, request, managerInstanceId) {
113
+ if (!isChatAlias(request.alias))
114
+ return { code: "permission-denied", message: `"${request.alias}" is not a chat session alias; chat-session-retire ends only sessions chat-session-open admitted` };
115
+ if (row === undefined)
116
+ return { code: "not-found", message: `no chat session slot exists for "${request.alias}"` };
117
+ if (row.ownerInstanceId !== managerInstanceId)
118
+ return { code: "failed-precondition", message: `the chat session slot "${request.alias}" belongs to manager instance ${row.ownerInstanceId ?? "<unrecorded>"}, not ${managerInstanceId}; only the instance that admitted it retires it` };
119
+ if (row.lifecycleUid !== request.lifecycleUid)
120
+ return { code: "failed-precondition", message: `the chat session slot "${request.alias}" is at uid ${row.lifecycleUid}, not ${request.lifecycleUid}; a retirement never addresses another incarnation` };
121
+ if (row.actor !== request.actor)
122
+ return { code: "failed-precondition", message: `the chat session slot "${request.alias}" names actor ${row.actor}, not ${request.actor}` };
123
+ return undefined;
124
+ }
125
+ /** How many chat retirements one manager process runs at once, at expiry and at stop. Each is a
126
+ * full static terminal (KV round trips, a broker eviction scan and a deprovision), so a burst
127
+ * waits its turn instead of opening that many terminals together. It bounds work in flight, not
128
+ * sessions. */
129
+ export const CHAT_EXPIRY_CONCURRENCY = 4;
130
+ const PROCESS_TIMERS = {
131
+ now: () => Date.now(),
132
+ set: (fn, ms) => {
133
+ const timer = setTimeout(fn, ms);
134
+ timer.unref?.();
135
+ return timer;
136
+ },
137
+ clear: (handle) => clearTimeout(handle),
138
+ };
139
+ /**
140
+ * The chat sessions this manager process admitted, from before each one's first durable write
141
+ * until a retirement of it is confirmed. It retires each at its leaf's expiry, so a reply lost on
142
+ * the way back or a client that never retires still ends then, and it names to the manager's
143
+ * sweep and stop the exact alias, actor and UID of every session this process holds.
144
+ *
145
+ * It knows only what this process registered and never reads the slot store, so it cannot reach
146
+ * an ordinary agent's slot, a sibling's, a legacy row or a session another process admitted.
147
+ * `retire` runs the exact-owned retirement; a throw is a failure, retried after each of
148
+ * `retryDelaysMs`. A session whose retries are spent stays tracked as `held`, for a later retire
149
+ * or the stop.
150
+ */
151
+ export class ChatSessionExpiry {
152
+ retire;
153
+ options;
154
+ sessions = new Map();
155
+ due = [];
156
+ running = 0;
157
+ stopped = false;
158
+ timers;
159
+ constructor(retire, options) {
160
+ this.retire = retire;
161
+ this.options = options;
162
+ this.timers = options.timers ?? PROCESS_TIMERS;
163
+ }
164
+ /** Register a session the open handler is about to write, before its first durable write. It is
165
+ * not scheduled until {@link arm}. Throws once stopped and for a UID already registered. */
166
+ register(session) {
167
+ if (this.stopped)
168
+ throw new Error(`this manager is stopping, so chat session ${session.alias} was not admitted`);
169
+ if (this.sessions.has(session.lifecycleUid))
170
+ throw new Error(`chat session uid ${session.lifecycleUid} is already registered`);
171
+ this.sessions.set(session.lifecycleUid, { session, state: "opening", failures: 0 });
172
+ }
173
+ /** Schedule a registered session's retirement at its expiry: once its opening succeeded, or once
174
+ * a rollback of it did not complete. Throws once stopped, so an opening that finishes after a
175
+ * stop began is rolled back instead of being handed out; the session stays registered for the
176
+ * stop either way. */
177
+ arm(lifecycleUid) {
178
+ const entry = this.sessions.get(lifecycleUid);
179
+ if (!entry)
180
+ throw new Error(`chat session uid ${lifecycleUid} is not registered`);
181
+ if (this.stopped)
182
+ throw new Error(`this manager is stopping, so chat session ${entry.session.alias} is not scheduled for its expiry`);
183
+ if (entry.state !== "opening" && entry.state !== "held")
184
+ return;
185
+ this.schedule(entry, entry.session.expiresAt - this.timers.now());
186
+ }
187
+ /** Whether this process holds a session at this exact alias, actor and UID, in any state. */
188
+ holdsExact(slot) {
189
+ const entry = this.sessions.get(slot.lifecycleUid);
190
+ return entry !== undefined && entry.session.alias === slot.alias && entry.session.actor === slot.actor;
191
+ }
192
+ /** The admitted channels of a tracked session, or undefined once it is not tracked. */
193
+ channels(lifecycleUid) {
194
+ return this.sessions.get(lifecycleUid)?.session.channels;
195
+ }
196
+ /** Stop tracking a session whose retirement was confirmed. A retirement of it already running
197
+ * finishes, and its outcome is dropped. */
198
+ forget(lifecycleUid) {
199
+ const entry = this.sessions.get(lifecycleUid);
200
+ if (!entry)
201
+ return;
202
+ if (entry.timer !== undefined)
203
+ this.timers.clear(entry.timer);
204
+ this.sessions.delete(lifecycleUid);
205
+ const queued = this.due.indexOf(lifecycleUid);
206
+ if (queued >= 0)
207
+ this.due.splice(queued, 1);
208
+ }
209
+ /** Stop scheduling and refuse new sessions. Every tracked session stays tracked for the stop to
210
+ * retire or report, and each one not running becomes `held`. */
211
+ stop() {
212
+ if (this.stopped)
213
+ return;
214
+ this.stopped = true;
215
+ this.due.length = 0;
216
+ for (const entry of this.sessions.values()) {
217
+ if (entry.timer !== undefined)
218
+ this.timers.clear(entry.timer);
219
+ entry.timer = undefined;
220
+ if (entry.state !== "running")
221
+ entry.state = "held";
222
+ }
223
+ }
224
+ /** Every tracked session. One whose expiry retirement is still settling is included: the
225
+ * manager runs one terminal per UID, so a second caller joins it rather than racing it. */
226
+ remaining() {
227
+ return [...this.sessions.values()].map((entry) => entry.session);
228
+ }
229
+ schedule(entry, delayMs) {
230
+ entry.state = "armed";
231
+ const uid = entry.session.lifecycleUid;
232
+ entry.timer = this.timers.set(() => {
233
+ entry.timer = undefined;
234
+ if (this.stopped || this.sessions.get(uid) !== entry)
235
+ return;
236
+ entry.state = "due";
237
+ this.due.push(uid);
238
+ this.pump();
239
+ }, Math.max(0, delayMs));
240
+ }
241
+ pump() {
242
+ while (!this.stopped && this.running < this.options.concurrency && this.due.length > 0) {
243
+ const uid = this.due.shift();
244
+ const entry = this.sessions.get(uid);
245
+ if (!entry)
246
+ continue;
247
+ this.running++;
248
+ entry.state = "running";
249
+ void Promise.resolve()
250
+ .then(() => this.retire(entry.session))
251
+ .then(() => {
252
+ if (this.sessions.get(uid) === entry)
253
+ this.sessions.delete(uid);
254
+ }, (e) => this.failed(entry, e))
255
+ .finally(() => {
256
+ this.running--;
257
+ this.pump();
258
+ });
259
+ }
260
+ }
261
+ failed(entry, e) {
262
+ const uid = entry.session.lifecycleUid;
263
+ if (this.sessions.get(uid) !== entry)
264
+ return;
265
+ if (this.stopped) {
266
+ entry.state = "held";
267
+ return;
268
+ }
269
+ const delayMs = this.options.retryDelaysMs[entry.failures];
270
+ entry.failures++;
271
+ const why = e instanceof Error ? e.message : String(e);
272
+ if (delayMs === undefined) {
273
+ entry.state = "held";
274
+ this.options.log(`! chat session ${entry.session.alias} (uid ${uid}) expired and its retirement failed ${entry.failures} time(s) (${why}); it stays held until a retire, this manager's stop, or the next start of this manager instance`);
275
+ return;
276
+ }
277
+ this.options.log(`! chat session ${entry.session.alias} (uid ${uid}) expiry retirement failed (${why}); retrying in ${delayMs} ms`);
278
+ this.schedule(entry, delayMs);
279
+ }
280
+ }
281
+ //# sourceMappingURL=chat-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-session.js","sourceRoot":"","sources":["../src/chat-session.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { type MeshEntry } from "@cotal-ai/workspace";
2
2
  type Values = Record<string, string | undefined>;
3
+ /** Read the resume commit token from its protected handoff file once, check it against the
4
+ * digest named on argv, then unlink it. Errors name the field only; the value is never echoed. */
5
+ export declare function readResumeCommitFile(path: string, sha256: string): string;
3
6
  /**
4
7
  * RECORD THIS PROCESS as the running manager, and un-record it on a clean exit.
5
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAwBA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAgB7B,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,CA+BxE;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,SAAkB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAAE,CAuDvO"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AA2BA,OAAO,EAKkB,KAAK,SAAS,EACtC,MAAM,qBAAqB,CAAC;AAiB7B,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEjD;mGACmG;AACnG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CASzE;AAaD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,CAgCxE;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,SAAkB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAAE,CAuDvO"}