@cotal-ai/connector-core 0.18.0 → 0.19.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 (46) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +12 -2
  3. package/dist/agent.js.map +1 -1
  4. package/dist/agui-holder.d.ts +89 -0
  5. package/dist/agui-holder.d.ts.map +1 -0
  6. package/dist/agui-holder.js +135 -0
  7. package/dist/agui-holder.js.map +1 -0
  8. package/dist/agui-render.d.ts +100 -0
  9. package/dist/agui-render.d.ts.map +1 -0
  10. package/dist/agui-render.js +283 -0
  11. package/dist/agui-render.js.map +1 -0
  12. package/dist/agui-wal-path.d.ts +103 -0
  13. package/dist/agui-wal-path.d.ts.map +1 -0
  14. package/dist/agui-wal-path.js +324 -0
  15. package/dist/agui-wal-path.js.map +1 -0
  16. package/dist/agui.d.ts +727 -0
  17. package/dist/agui.d.ts.map +1 -0
  18. package/dist/agui.js +1114 -0
  19. package/dist/agui.js.map +1 -0
  20. package/dist/docs-bundle.generated.d.ts.map +1 -1
  21. package/dist/docs-bundle.generated.js +16 -9
  22. package/dist/docs-bundle.generated.js.map +1 -1
  23. package/dist/durable-source.d.ts +127 -0
  24. package/dist/durable-source.d.ts.map +1 -0
  25. package/dist/durable-source.js +219 -0
  26. package/dist/durable-source.js.map +1 -0
  27. package/dist/event-wal.d.ts +265 -0
  28. package/dist/event-wal.d.ts.map +1 -0
  29. package/dist/event-wal.js +698 -0
  30. package/dist/event-wal.js.map +1 -0
  31. package/dist/index.d.ts +5 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +5 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/launch.d.ts +78 -2
  36. package/dist/launch.d.ts.map +1 -1
  37. package/dist/launch.js +120 -0
  38. package/dist/launch.js.map +1 -1
  39. package/dist/tool-specs.d.ts +40 -2
  40. package/dist/tool-specs.d.ts.map +1 -1
  41. package/dist/tool-specs.js +51 -1
  42. package/dist/tool-specs.js.map +1 -1
  43. package/dist/tools.d.ts.map +1 -1
  44. package/dist/tools.js +5 -6
  45. package/dist/tools.js.map +1 -1
  46. package/package.json +8 -2
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Where a principal's event WAL lives on disk, and making that location durable before it is used.
3
+ *
4
+ * The layout is fixed, and `resolveEventWalPath` below is the only place it is spelled:
5
+ *
6
+ * ```
7
+ * <workspaceRoot>/.cotal/events/<h(space)>/<h(principal)>/
8
+ * .lock one emitter per PRINCIPAL (not per thread), HELD not computed
9
+ * <h(threadId)>/wal.json ONE file per thread, atomically replaced
10
+ * ```
11
+ *
12
+ * **`.lock` IS ACQUIRED, AND THE WORD "HELD" ABOVE IS THERE BECAUSE IT ONCE WAS NOT.** This comment
13
+ * claimed single-emitter exclusion from the day it was written while `lockPath` was only computed:
14
+ * no acquire anywhere, and the suites asserted the path's SHAPE rather than that anyone held it. A
15
+ * reviewer opened two logs on one file and watched the second one's stale handle rewrite the first
16
+ * one's folded frontier to a tip the broker never assigned. {@link acquirePrincipalLock} is the
17
+ * exclusion; the generation guard in `EventWal.write` is what refuses the stale write itself. Both,
18
+ * because a lock cannot see a handle that predates it and a generation cannot tell an operator that
19
+ * a second emitter is already running.
20
+ *
21
+ * **Every path component is hashed, and none of the unhashed values is a trusted path component.**
22
+ * A space, a principal key and a native session id all come from outside this process, and a
23
+ * sanitiser that has to stay correct is a worse guard than a shape that cannot express traversal at
24
+ * all. Hashing makes containment STRUCTURAL. It does not make the location self-describing, which is
25
+ * why {@link EventWal} stores the unhashed `{space, principal, threadId}` tuple inside the document
26
+ * and refuses one that disagrees: the hash keeps a hostile value from escaping the tree, and the
27
+ * stored tuple turns a collision or a mis-resolved directory into a loud mismatch instead of one
28
+ * thread's frontier being adopted as another's.
29
+ *
30
+ * **This module does no policy.** It does not decide whether events are on, whether a root was
31
+ * threaded, or what to do when one was not; those are the connector's decisions and live at its
32
+ * launch site, where a missing root can still fail loud with something a human can act on.
33
+ */
34
+ import { createHash, randomUUID } from "node:crypto";
35
+ import { open, readFile, unlink } from "node:fs/promises";
36
+ import { hostname } from "node:os";
37
+ import { dirname, join } from "node:path";
38
+ import { ensureDirNoSymlink } from "@cotal-ai/core";
39
+ import { openExclusiveNoFollow } from "./event-wal.js";
40
+ /**
41
+ * Thrown when a session that is going to publish events cannot say where its WAL belongs.
42
+ *
43
+ * A distinct type rather than a bare `Error` so a caller can tell "misconfigured launch" from
44
+ * "filesystem said no" without matching on message text.
45
+ */
46
+ export class EventsStateRootMissing extends Error {
47
+ constructor(message) {
48
+ super(message);
49
+ this.name = "EventsStateRootMissing";
50
+ }
51
+ }
52
+ /**
53
+ * The state root for an events-enabled session, or a loud failure.
54
+ *
55
+ * **THE FAILURE THIS PREVENTS IS SILENT, WHICH IS WHY IT IS A THROW AND NOT A DEFAULT.** The
56
+ * tempting fallback is `process.cwd()`. A WAL written there is not an error anyone sees: the emitter
57
+ * starts, frames publish, and the durable state that makes a restart safe sits in whatever directory
58
+ * the launch happened to begin in — a per-agent working directory that "can point at any repo". The
59
+ * next start resolves the real root, finds no WAL, and reads an already-published thread as VIRGIN:
60
+ * `E := 0`, a fresh epoch, a second frame claiming a sequence the stream has already seen. Nothing
61
+ * reports a problem at any point, and an absence is what a clean board looks like.
62
+ *
63
+ * `env` is a PARAMETER and the root resolves PER CALL. A module-level read would freeze whatever the
64
+ * environment was at first import, and none of what this path is keyed on — space, principal,
65
+ * thread — is process-wide.
66
+ */
67
+ export function resolveEventsStateRoot(env) {
68
+ const root = env.COTAL_WORKSPACE_ROOT;
69
+ if (typeof root !== "string" || root.trim() === "")
70
+ throw new EventsStateRootMissing("events are enabled for this session but COTAL_WORKSPACE_ROOT is not set, so there is nowhere " +
71
+ "to put the event write-ahead log. The launcher forwards it from LaunchOpts.workspaceRoot; a " +
72
+ "session started outside a manager has no workspace root and must not publish events. " +
73
+ "Refusing rather than defaulting to the working directory, which would put the WAL somewhere " +
74
+ "no later start looks.");
75
+ return root;
76
+ }
77
+ /**
78
+ * One path component from one untrusted value.
79
+ *
80
+ * 16 hex characters of SHA-256, matching the width the channel mapping and the source cursor
81
+ * already use. The width is a containment and collision property, not a secrecy one — nothing here
82
+ * is trying to hide a space name from someone holding the directory.
83
+ */
84
+ function h(value) {
85
+ return createHash("sha256").update(value).digest("hex").slice(0, 16);
86
+ }
87
+ /**
88
+ * Resolve where this principal's WAL for this thread lives. Pure — no IO, no side effects.
89
+ *
90
+ * `workspaceRoot` is taken as given rather than defaulted. A default here would be a silent fallback
91
+ * onto whatever directory the process happened to start in, which is precisely the scattering the
92
+ * root exists to prevent; the caller that cannot resolve one must fail loud instead.
93
+ */
94
+ export function eventWalLocation(opts) {
95
+ const principalDir = join(opts.workspaceRoot, ".cotal", "events", h(opts.space), h(opts.principal));
96
+ const threadDir = join(principalDir, h(opts.threadId));
97
+ return {
98
+ principalDir,
99
+ lockPath: join(principalDir, ".lock"),
100
+ threadDir,
101
+ walPath: join(threadDir, "wal.json"),
102
+ };
103
+ }
104
+ /** Every refusal on the lock path is one of these, so a caller never mistakes it for an I/O blip. */
105
+ export class PrincipalLockError extends Error {
106
+ path;
107
+ invariant;
108
+ constructor(path, invariant, detail) {
109
+ super(`event WAL principal lock at ${path} (${invariant}): ${detail}`);
110
+ this.path = path;
111
+ this.invariant = invariant;
112
+ this.name = "PrincipalLockError";
113
+ }
114
+ }
115
+ /**
116
+ * Locks this process holds, keyed by path.
117
+ *
118
+ * **Acquiring the same principal's lock twice IN THIS PROCESS returns the SAME lock rather than
119
+ * refusing**, and that is a decision, not an oversight. The lock is per PRINCIPAL while the WAL
120
+ * directory chain is per THREAD, so a session that moves from one thread to the next under one
121
+ * principal calls {@link ensureEventWalDir} again — and the documented shape is one emitter per
122
+ * principal, one thread at a time. Refusing there would break the sequencing the design asks for.
123
+ * What that leaves uncovered inside one process, two `EventWal` objects open on one file, is not
124
+ * covered by a lock at all: it is refused on the write path by the generation guard in
125
+ * `EventWal.write`, which is where it has to be refused anyway, because a lock cannot see a stale
126
+ * handle that already holds it.
127
+ */
128
+ const held = new Map();
129
+ /** Alive means "this pid resolves to a process", INCLUDING one this user may not signal. `EPERM` is
130
+ * a live process owned by somebody else, and reading it as dead would reclaim a held lock. */
131
+ function ownerIsAlive(pid) {
132
+ try {
133
+ process.kill(pid, 0);
134
+ return true;
135
+ }
136
+ catch (e) {
137
+ return e.code !== "ESRCH";
138
+ }
139
+ }
140
+ /** Create the lock file exclusively, or report that somebody already holds it. Never adopts. */
141
+ async function createLockFile(path) {
142
+ try {
143
+ return await openExclusiveNoFollow(path);
144
+ }
145
+ catch (e) {
146
+ if (e.code === "EEXIST")
147
+ return undefined;
148
+ throw e;
149
+ }
150
+ }
151
+ /**
152
+ * Remove a lock whose owner is PROVABLY gone, or refuse.
153
+ *
154
+ * **A CRASH MUST NOT WEDGE THE PRINCIPAL FOREVER, AND A RECLAIM MUST NOT BE A GUESS.** An emitter
155
+ * that dies leaves its lock file behind; a lock that is never reclaimable turns one crash into a
156
+ * permanently unstartable principal, which is a worse failure than the one the lock prevents. So a
157
+ * reclaim is allowed, and it is fenced on three refusals rather than on optimism:
158
+ *
159
+ * - an unreadable or unowned record is refused outright, never reclaimed. A file we cannot read is
160
+ * not evidence that nobody holds it.
161
+ * - a record naming ANOTHER HOST is refused: this process cannot observe liveness on a machine it
162
+ * is not running on, and a shared filesystem is exactly where guessing would be wrong.
163
+ * - a record naming a LIVE pid on this host is refused, which is the ordinary "already running"
164
+ * answer an operator needs to see.
165
+ *
166
+ * The residual is pid reuse: a dead owner's pid can be re-issued to an unrelated process, so
167
+ * liveness is evidence and not proof. That residual is bounded rather than argued away, because the
168
+ * generation guard on the WAL's write path refuses a stale writer's clobber whether or not the lock
169
+ * was judged correctly. The lock decides who STARTS; the generation guard decides who may WRITE.
170
+ */
171
+ async function reclaimIfOwnerIsGone(path) {
172
+ let raw;
173
+ try {
174
+ raw = await readFile(path, "utf8");
175
+ }
176
+ catch (e) {
177
+ // Gone between the failed create and this read: somebody released it. The create that follows
178
+ // is what decides, and it decides by trying, not by assuming.
179
+ if (e.code === "ENOENT")
180
+ return;
181
+ throw e;
182
+ }
183
+ let record;
184
+ try {
185
+ record = JSON.parse(raw);
186
+ }
187
+ catch {
188
+ throw new PrincipalLockError(path, "the lock names its owner", "the file is not readable JSON, so its owner cannot be checked; refusing rather than reclaiming a lock that may be held");
189
+ }
190
+ const r = record;
191
+ if (!Number.isSafeInteger(r.pid) || r.pid <= 0 || typeof r.host !== "string" || r.host.length === 0)
192
+ throw new PrincipalLockError(path, "the lock names its owner", `the record carries pid=${String(r.pid)} host=${String(r.host)}, which names nobody checkable`);
193
+ const here = hostname();
194
+ if (r.host !== here)
195
+ throw new PrincipalLockError(path, "the recorded owner is on THIS host", `held by pid ${r.pid} on ${r.host} while this process runs on ${here}; liveness on another machine is not observable from here`);
196
+ if (ownerIsAlive(r.pid))
197
+ throw new PrincipalLockError(path, "the recorded owner is gone", `pid ${r.pid} on ${here} is still running and holds this principal's emitter`);
198
+ // The owner is gone. Removing the file is the reclaim; whether THIS process gets the lock is
199
+ // decided by the exclusive create that follows, so a second reclaimer racing here loses there.
200
+ await unlink(path).catch((e) => {
201
+ if (e.code !== "ENOENT")
202
+ throw e;
203
+ });
204
+ }
205
+ /**
206
+ * Take this principal's lock and HOLD IT for the life of the process.
207
+ *
208
+ * The handle stays open deliberately. A lock released at the end of the acquiring function is a
209
+ * lock that was never held, and the layout comment above has claimed single-emitter exclusion since
210
+ * this module was written while `lockPath` was only ever COMPUTED — a path in a struct standing in
211
+ * for a guarantee. This is that claim made real.
212
+ */
213
+ export async function acquirePrincipalLock(lockPath) {
214
+ const already = held.get(lockPath);
215
+ if (already)
216
+ return already;
217
+ let fh = await createLockFile(lockPath);
218
+ if (fh === undefined) {
219
+ await reclaimIfOwnerIsGone(lockPath);
220
+ fh = await createLockFile(lockPath);
221
+ if (fh === undefined)
222
+ throw new PrincipalLockError(lockPath, "the reclaimed lock is free when this process takes it", "another process created the lock between the reclaim and this open, and now holds this principal");
223
+ }
224
+ const record = JSON.stringify({ pid: process.pid, host: hostname(), token: randomUUID(), acquiredAt: new Date().toISOString() });
225
+ try {
226
+ await fh.writeFile(record, "utf8");
227
+ await fh.sync();
228
+ }
229
+ catch (e) {
230
+ // A lock whose record never landed names nobody, and the refusals above would then refuse every
231
+ // later start rather than reclaim it. Undo the create before rethrowing.
232
+ await fh.close().catch(() => { });
233
+ await unlink(lockPath).catch(() => { });
234
+ throw e;
235
+ }
236
+ const lock = {
237
+ path: lockPath,
238
+ async release() {
239
+ if (held.get(lockPath) !== lock)
240
+ return;
241
+ held.delete(lockPath);
242
+ await fh.close().catch(() => { });
243
+ await unlink(lockPath).catch((e) => {
244
+ if (e.code !== "ENOENT")
245
+ throw e;
246
+ });
247
+ },
248
+ };
249
+ held.set(lockPath, lock);
250
+ return lock;
251
+ }
252
+ /**
253
+ * `fsync` one directory, so its own entries are durable.
254
+ *
255
+ * Opened read-only: fsync on a directory handle is the portable way to flush the entries, and a
256
+ * directory cannot be opened for writing anyway. `EBADF`/`EINVAL`/`EPERM` are TOLERATED rather than
257
+ * fatal — some filesystems refuse to fsync a directory handle at all, and failing an emitter start
258
+ * on a platform that simply does not offer the guarantee would trade a durability improvement for
259
+ * an availability regression. Every other error propagates.
260
+ */
261
+ async function fsyncDir(dir) {
262
+ let fh;
263
+ try {
264
+ fh = await open(dir, "r");
265
+ }
266
+ catch (e) {
267
+ const code = e.code;
268
+ if (code === "EPERM" || code === "EACCES")
269
+ return;
270
+ throw e;
271
+ }
272
+ try {
273
+ await fh.sync();
274
+ }
275
+ catch (e) {
276
+ const code = e.code;
277
+ if (code !== "EBADF" && code !== "EINVAL" && code !== "EPERM" && code !== "EISDIR")
278
+ throw e;
279
+ }
280
+ finally {
281
+ await fh.close();
282
+ }
283
+ }
284
+ /**
285
+ * Create the directory chain for a thread's WAL and make it durable: **once, before the
286
+ * first transition.**
287
+ *
288
+ * The WAL's own replace protocol fsyncs `wal.json` and the thread directory that holds it. That is
289
+ * not sufficient on its own: a newly created `<h(threadId)>/` directory's NAME is an entry in its
290
+ * PARENT, and `ensureDirNoSymlink` only `mkdir`s each missing component with no fsync anywhere. On a
291
+ * filesystem that honours the distinction, a crash after the first transition and after the publish
292
+ * can come back with the directory link itself lost — no WAL, no pending record — and boot then
293
+ * reads a thread that has already published as VIRGIN: `E := 0`, a fresh epoch, and a second frame
294
+ * claiming a sequence the stream has already seen.
295
+ *
296
+ * So every component from the workspace root down is fsynced, parents included, rather than the leaf
297
+ * alone. It runs once at emitter start; the cost is a handful of directory syncs against a session
298
+ * that is about to do real work.
299
+ *
300
+ * Returns the WAL path, so a caller cannot resolve the location by one route and create it by
301
+ * another — and the HELD principal lock with it, for the same reason. Handing back a location whose
302
+ * lock the caller then has to remember to take is how the lock came to be a path and nothing else.
303
+ */
304
+ export async function ensureEventWalDir(opts) {
305
+ const loc = eventWalLocation(opts);
306
+ // `ensureDirNoSymlink` refuses a symlinked component rather than following it — the WAL is written
307
+ // at 0600 under directories created 0700, and a symlink anywhere in the chain would redirect that
308
+ // write outside the tree the mode bits are protecting.
309
+ ensureDirNoSymlink(opts.workspaceRoot, ".cotal", "events", h(opts.space), h(opts.principal), h(opts.threadId));
310
+ // Bottom-up to the root: each fsync makes THIS directory's entries durable, so the thread dir's
311
+ // own name only becomes durable when its parent is synced. Syncing the leaf alone is the exact
312
+ // gap above.
313
+ for (let dir = loc.threadDir;; dir = dirname(dir)) {
314
+ await fsyncDir(dir);
315
+ if (dir === opts.workspaceRoot || dirname(dir) === dir)
316
+ break;
317
+ }
318
+ // AFTER the chain exists, because the lock is a file inside the principal directory, and BEFORE
319
+ // the caller can open a WAL under it, because a lock taken after the first transition is a lock
320
+ // that was not held when it mattered.
321
+ const lock = await acquirePrincipalLock(loc.lockPath);
322
+ return { ...loc, lock };
323
+ }
324
+ //# sourceMappingURL=agui-wal-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agui-wal-path.js","sourceRoot":"","sources":["../src/agui-wal-path.ts"],"names":[],"mappings":"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"}