@cotal-ai/connector-core 0.18.0 → 0.20.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/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +12 -2
- package/dist/agent.js.map +1 -1
- package/dist/agui-holder.d.ts +89 -0
- package/dist/agui-holder.d.ts.map +1 -0
- package/dist/agui-holder.js +135 -0
- package/dist/agui-holder.js.map +1 -0
- package/dist/agui-render.d.ts +100 -0
- package/dist/agui-render.d.ts.map +1 -0
- package/dist/agui-render.js +283 -0
- package/dist/agui-render.js.map +1 -0
- package/dist/agui-wal-path.d.ts +103 -0
- package/dist/agui-wal-path.d.ts.map +1 -0
- package/dist/agui-wal-path.js +324 -0
- package/dist/agui-wal-path.js.map +1 -0
- package/dist/agui.d.ts +727 -0
- package/dist/agui.d.ts.map +1 -0
- package/dist/agui.js +1114 -0
- package/dist/agui.js.map +1 -0
- package/dist/docs-bundle.generated.d.ts.map +1 -1
- package/dist/docs-bundle.generated.js +16 -9
- package/dist/docs-bundle.generated.js.map +1 -1
- package/dist/durable-source.d.ts +127 -0
- package/dist/durable-source.d.ts.map +1 -0
- package/dist/durable-source.js +219 -0
- package/dist/durable-source.js.map +1 -0
- package/dist/event-wal.d.ts +265 -0
- package/dist/event-wal.d.ts.map +1 -0
- package/dist/event-wal.js +698 -0
- package/dist/event-wal.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/launch.d.ts +78 -2
- package/dist/launch.d.ts.map +1 -1
- package/dist/launch.js +120 -0
- package/dist/launch.js.map +1 -1
- package/dist/tool-specs.d.ts +40 -2
- package/dist/tool-specs.d.ts.map +1 -1
- package/dist/tool-specs.js +51 -1
- package/dist/tool-specs.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +5 -6
- package/dist/tools.js.map +1 -1
- 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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"}
|