@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,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE FIRST RENDERER THAT CAN DISPLAY AN AG-UI FRAME.
|
|
3
|
+
*
|
|
4
|
+
* A frame carries **no text part by design** — its content is a list of AG-UI events — so every
|
|
5
|
+
* surface that renders a message as flat text draws one as `[unrenderable part kind "ag-ui.frame"]`.
|
|
6
|
+
* This is the provider that fixes that for the console family: a core {@link PartRenderer} of kind
|
|
7
|
+
* `part-renderer`, named for the part kind it draws, self-registering on import exactly as a
|
|
8
|
+
* terminal-layout provider does.
|
|
9
|
+
*
|
|
10
|
+
* **IT LANDS BEFORE ANY PRODUCER, AND THAT ORDERING IS THE POINT.** At this tip nothing in
|
|
11
|
+
* production publishes a frame: no connector constructs an emitter and every connector still writes
|
|
12
|
+
* its `tr-<name>` text mirror. So this renderer has no live traffic to draw yet, and saying that
|
|
13
|
+
* plainly matters more than it sounds, because the alternative ordering is the one that fails. A
|
|
14
|
+
* cutover shipped first would replace a mirror a human can read with a part every surface shows as a
|
|
15
|
+
* marker, and the regression would be invisible to the change that caused it. Display first, then
|
|
16
|
+
* the producer.
|
|
17
|
+
*
|
|
18
|
+
* **CORE NEVER LEARNS AG-UI.** `partsToText` resolves a renderer by the part's own kind and calls
|
|
19
|
+
* it. The knowledge of what a `TOOL_CALL_ARGS` means lives here, in the package that defined the
|
|
20
|
+
* vocabulary, which is where `AGENTS.md` requires an adapter's concepts to stay. What moved into
|
|
21
|
+
* core is only the frame's IDENTITY (`agui-kind.ts`) and the channel's NAME (`event-channel.ts`),
|
|
22
|
+
* both of which a reader needs to recognise a frame without knowing who produced it.
|
|
23
|
+
*
|
|
24
|
+
* ── WHAT IT DELIBERATELY DOES NOT DO ────────────────────────────────────────────────────────────
|
|
25
|
+
*
|
|
26
|
+
* **It does not print raw event-type tokens.** A reader wants `bash({"cmd":"ls"}) -> ok`, not
|
|
27
|
+
* `TOOL_CALL_START TOOL_CALL_ARGS TOOL_CALL_RESULT`. So the suite must not assert the token either:
|
|
28
|
+
* gating on `TOOL_CALL_ARGS` appearing in the output would fail a correct renderer, which is why the
|
|
29
|
+
* cells assert the FOLD (name, arguments, result) rather than the vocabulary.
|
|
30
|
+
*
|
|
31
|
+
* **It does not validate the frame as a schema.** `parseAguiFrame` checks the envelope and that each
|
|
32
|
+
* event's `type` is in the vocabulary, and nothing else, which is measured rather than assumed. So
|
|
33
|
+
* this renderer treats event fields as untrusted: every field access is guarded and a malformed
|
|
34
|
+
* event degrades to a named marker rather than throwing. A renderer is the wrong place to discover a
|
|
35
|
+
* producer's bug, and a very good place to make one visible.
|
|
36
|
+
*
|
|
37
|
+
* ── WHY IT ROUTES ON THE KIND AND NEVER ON SHAPE ────────────────────────────────────────────────
|
|
38
|
+
*
|
|
39
|
+
* Two formats will share one channel for exactly as long as the cutover takes: `events.<owner>.<actor>`
|
|
40
|
+
* is designed to carry frames, while the connectors that have not cut over still publish plain text
|
|
41
|
+
* parts to their own mirror. Registration is for `ag-ui.frame` ONLY, so a text part renders as the
|
|
42
|
+
* text it is and never as a degenerate frame. The two cannot be confused because the routing is on
|
|
43
|
+
* the part kind and not on a guess about shape.
|
|
44
|
+
*/
|
|
45
|
+
import { AGUI_EVENT_TYPE, AGUI_FRAME_KIND, isAguiFramePart, registry } from "@cotal-ai/core";
|
|
46
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
47
|
+
/**
|
|
48
|
+
* Line prefixes. **Every one of these starts with a non-space glyph within the first three columns,
|
|
49
|
+
* and that is a requirement rather than a style choice.** Leading spaces do not establish a line
|
|
50
|
+
* start, they indent one, so a prefix of spaces alone leaves the payload's first character still the
|
|
51
|
+
* first character of the line. `CONT` therefore carries `·`, and no prefix here may be widened past
|
|
52
|
+
* three leading spaces without re-deriving {@link LINE_START_SAFE}.
|
|
53
|
+
*/
|
|
54
|
+
const CONT = " · ";
|
|
55
|
+
const TEXT_PREFIX = "» ";
|
|
56
|
+
const THINK_PREFIX = "(thinking) ";
|
|
57
|
+
const TOOL_PREFIX = "⚙ ";
|
|
58
|
+
const RESULT_PREFIX = " ↳ ";
|
|
59
|
+
/**
|
|
60
|
+
* Every character markdown can read as BEGINNING a block, so {@link LINE_START_SAFE} never has to
|
|
61
|
+
* know which block: `#` heading, `>` quote, `|` table, `` ` `` and `~` fence, `=` and `-` setext
|
|
62
|
+
* underline, `-` `*` `+` bullet, `*` `_` `-` thematic break, a digit for an ordered list, `[` a link
|
|
63
|
+
* reference definition (which renders as NOTHING, so it deletes the line it is on), and a tab, which
|
|
64
|
+
* counts as up to four columns of indent and so opens code.
|
|
65
|
+
*/
|
|
66
|
+
const BLOCK_START_CHARS = new Set([..."#>|`~=_*+-[<0123456789", "\t"]);
|
|
67
|
+
/**
|
|
68
|
+
* A line this renderer is allowed to emit: one that cannot open a block construct.
|
|
69
|
+
*
|
|
70
|
+
* **Exported so the suite asserts the invariant against the SAME expression the renderer is
|
|
71
|
+
* documented by**, rather than a second copy of it that can drift. It is a property of the emitted
|
|
72
|
+
* lines and nothing more, deliberately not a claim about what any consumer does downstream, which
|
|
73
|
+
* would be an assertion outside this module that no test here could hold up.
|
|
74
|
+
*
|
|
75
|
+
* **IT TESTS THE FIRST CHARACTER, NOT A LIST OF CONSTRUCTS, AND THAT IS THE WHOLE POINT.** The
|
|
76
|
+
* previous version enumerated the openers it knew (ATX heading, bullet, ordered list, blockquote,
|
|
77
|
+
* table row, indented code) and called them "the block-level openers". An enumeration of a syntax
|
|
78
|
+
* someone else defines is incomplete the moment it is written, and this one was: a bare `---`, `***`
|
|
79
|
+
* and a fence line all PASSED it while being a thematic break, a setext underline and a code fence.
|
|
80
|
+
* The suite stayed green because the PREFIXES stop the renderer from emitting such a line at all,
|
|
81
|
+
* which means the predicate was passing for a reason unrelated to what it claimed to check, and a
|
|
82
|
+
* weakened prefix would not have been caught by the thing whose job is to catch exactly that.
|
|
83
|
+
*
|
|
84
|
+
* So the rule is a property of one character: a line is safe when its first non-space character
|
|
85
|
+
* arrives within three columns and is not one markdown can read as beginning a block. That is
|
|
86
|
+
* stricter than the constructs strictly require (`1x` and `-x` open nothing and are refused anyway),
|
|
87
|
+
* and strictness is the correct direction here, because this constrains what THIS renderer emits and
|
|
88
|
+
* every line it emits carries a glyph prefix that is not punctuation at all.
|
|
89
|
+
*/
|
|
90
|
+
export const LINE_START_SAFE = (line) => {
|
|
91
|
+
if (line === "")
|
|
92
|
+
return true; // a blank line opens nothing and separates rather than nests
|
|
93
|
+
const indent = /^ */.exec(line)[0].length;
|
|
94
|
+
if (indent > 3)
|
|
95
|
+
return false; // four columns is an indented code block
|
|
96
|
+
const first = line[indent];
|
|
97
|
+
if (first === undefined)
|
|
98
|
+
return true; // spaces only, same as blank
|
|
99
|
+
return !BLOCK_START_CHARS.has(first);
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Fold a frame's events into display lines.
|
|
103
|
+
*
|
|
104
|
+
* Deltas are ACCUMULATED rather than printed one per line: `TEXT_MESSAGE_CONTENT` arrives as a
|
|
105
|
+
* stream of fragments, and a renderer that printed each one would turn a sentence into a column.
|
|
106
|
+
* They are keyed by `messageId`/`toolCallId` so two interleaved streams do not braid into each
|
|
107
|
+
* other; the ids exist precisely because interleaving is legal.
|
|
108
|
+
*/
|
|
109
|
+
function renderEvents(events) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
const text = new Map();
|
|
112
|
+
const reasoning = new Map();
|
|
113
|
+
const toolName = new Map();
|
|
114
|
+
const toolArgs = new Map();
|
|
115
|
+
/**
|
|
116
|
+
* Emit a payload as lines, prefixing EVERY line, not just the first.
|
|
117
|
+
*
|
|
118
|
+
* **THE STRUCTURAL INVARIANT THIS EXISTS FOR: no emitted line begins with a payload character.**
|
|
119
|
+
* Payload values are multi-line (a tool result is the common case, but pretty-printed args, a
|
|
120
|
+
* multi-paragraph message and an error body all are), and pushing one of them as a single string
|
|
121
|
+
* put its second and later lines at column 0 with nothing of the renderer's in front of them.
|
|
122
|
+
*
|
|
123
|
+
* At that point the payload is no longer inside the scaffolding, it IS scaffolding, and a consumer
|
|
124
|
+
* that reads line starts cannot tell which lines the renderer wrote. **Measured: a tool result
|
|
125
|
+
* whose second line began `- ` captured the frame's own `◂ run … finished` terminator into a list
|
|
126
|
+
* the payload had opened.** The invariant is asserted over this function's output in the suite.
|
|
127
|
+
*
|
|
128
|
+
* `cont` carries a non-space glyph for the same reason `first` does: leading spaces alone do not
|
|
129
|
+
* establish a line start, they only indent one.
|
|
130
|
+
*/
|
|
131
|
+
const emit = (first, cont, body) => {
|
|
132
|
+
const [head, ...rest] = body.split("\n");
|
|
133
|
+
lines.push(first + head);
|
|
134
|
+
for (const l of rest)
|
|
135
|
+
lines.push(cont + l);
|
|
136
|
+
};
|
|
137
|
+
/** Flush an accumulator, if it has anything in it. */
|
|
138
|
+
const flush = (map, id, first, cont, suffix = "") => {
|
|
139
|
+
const acc = map.get(id);
|
|
140
|
+
if (acc !== undefined && acc.length > 0)
|
|
141
|
+
emit(first, cont, acc + suffix);
|
|
142
|
+
map.delete(id);
|
|
143
|
+
};
|
|
144
|
+
for (const e of events) {
|
|
145
|
+
// THE ELEMENT ITSELF IS UNTRUSTED, not just its fields. `events` is an array off the wire and
|
|
146
|
+
// `parseAguiFrame` does not check that each element is an object, so `null` reaches here and a
|
|
147
|
+
// bare `e.type` throws on it. The throw was not fatal (core's dispatcher turns it into a named
|
|
148
|
+
// marker) and that is exactly what made it worth guarding: the whole frame degraded to one
|
|
149
|
+
// failure line, so a single null element deleted every other event in the frame from the
|
|
150
|
+
// reader's view. Named per element instead, so one malformed event costs one line.
|
|
151
|
+
const type = typeof e === "object" && e !== null ? str(e.type) : undefined;
|
|
152
|
+
switch (type) {
|
|
153
|
+
case AGUI_EVENT_TYPE.RUN_STARTED:
|
|
154
|
+
emit("▸ ", CONT, `run ${str(e.runId) ?? "?"} started`);
|
|
155
|
+
break;
|
|
156
|
+
case AGUI_EVENT_TYPE.RUN_FINISHED: {
|
|
157
|
+
// `outcome` is optional by the real schema — a turn that merely ended says nothing more, and
|
|
158
|
+
// manufacturing "success" would assert something the source never said.
|
|
159
|
+
const outcome = str(e.outcome?.type);
|
|
160
|
+
emit("◂ ", CONT, `run ${str(e.runId) ?? "?"} finished${outcome ? ` (${outcome})` : ""}`);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case AGUI_EVENT_TYPE.RUN_ERROR: {
|
|
164
|
+
const code = str(e.code);
|
|
165
|
+
emit("✗ ", CONT, `run error${code ? ` [${code}]` : ""}: ${str(e.message) ?? "(no message)"}`);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case AGUI_EVENT_TYPE.TEXT_MESSAGE_START:
|
|
169
|
+
text.set(str(e.messageId) ?? "", "");
|
|
170
|
+
break;
|
|
171
|
+
case AGUI_EVENT_TYPE.TEXT_MESSAGE_CONTENT: {
|
|
172
|
+
const id = str(e.messageId) ?? "";
|
|
173
|
+
text.set(id, (text.get(id) ?? "") + (str(e.delta) ?? ""));
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case AGUI_EVENT_TYPE.TEXT_MESSAGE_END:
|
|
177
|
+
flush(text, str(e.messageId) ?? "", TEXT_PREFIX, TEXT_PREFIX);
|
|
178
|
+
break;
|
|
179
|
+
case AGUI_EVENT_TYPE.REASONING_MESSAGE_START:
|
|
180
|
+
reasoning.set(str(e.messageId) ?? "", "");
|
|
181
|
+
break;
|
|
182
|
+
case AGUI_EVENT_TYPE.REASONING_MESSAGE_CONTENT: {
|
|
183
|
+
const id = str(e.messageId) ?? "";
|
|
184
|
+
reasoning.set(id, (reasoning.get(id) ?? "") + (str(e.delta) ?? ""));
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case AGUI_EVENT_TYPE.REASONING_MESSAGE_END:
|
|
188
|
+
flush(reasoning, str(e.messageId) ?? "", THINK_PREFIX, CONT);
|
|
189
|
+
break;
|
|
190
|
+
case AGUI_EVENT_TYPE.TOOL_CALL_START: {
|
|
191
|
+
const id = str(e.toolCallId) ?? "";
|
|
192
|
+
toolName.set(id, str(e.toolCallName) ?? "?");
|
|
193
|
+
toolArgs.set(id, "");
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case AGUI_EVENT_TYPE.TOOL_CALL_ARGS: {
|
|
197
|
+
const id = str(e.toolCallId) ?? "";
|
|
198
|
+
toolArgs.set(id, (toolArgs.get(id) ?? "") + (str(e.delta) ?? ""));
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case AGUI_EVENT_TYPE.TOOL_CALL_END: {
|
|
202
|
+
const id = str(e.toolCallId) ?? "";
|
|
203
|
+
emit(TOOL_PREFIX, CONT, `${toolName.get(id) ?? "?"}(${toolArgs.get(id) ?? ""})`);
|
|
204
|
+
toolName.delete(id);
|
|
205
|
+
toolArgs.delete(id);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case AGUI_EVENT_TYPE.TOOL_CALL_RESULT:
|
|
209
|
+
emit(RESULT_PREFIX, CONT, str(e.content) ?? "(no content)");
|
|
210
|
+
break;
|
|
211
|
+
case AGUI_EVENT_TYPE.CUSTOM:
|
|
212
|
+
emit("• ", CONT, `custom ${str(e.name) ?? "(unnamed)"}`);
|
|
213
|
+
break;
|
|
214
|
+
// An event whose `type` this build does not know. NAMED, never skipped — a skipped event is a
|
|
215
|
+
// hole in a transcript that still looks complete, which is `parseAguiFrame`'s own stated
|
|
216
|
+
// reason for refusing one. Here the surface is a reader rather than a parser, so it is shown.
|
|
217
|
+
default:
|
|
218
|
+
emit("• ", CONT, `unrecognised event ${JSON.stringify(type ?? null)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// A stream that ended without its END event still has content a reader needs. Dropping it would
|
|
222
|
+
// make a truncated turn indistinguishable from a silent one, which is the exact failure the mirror
|
|
223
|
+
// had.
|
|
224
|
+
for (const id of [...text.keys()])
|
|
225
|
+
flush(text, id, TEXT_PREFIX, TEXT_PREFIX, " …");
|
|
226
|
+
for (const id of [...reasoning.keys()])
|
|
227
|
+
flush(reasoning, id, THINK_PREFIX, CONT, " …");
|
|
228
|
+
for (const id of [...toolName.keys()])
|
|
229
|
+
emit(TOOL_PREFIX, CONT, `${toolName.get(id) ?? "?"}(${toolArgs.get(id) ?? ""}) …`);
|
|
230
|
+
return lines;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The registered provider. `name` IS the part kind, which is how core resolves it without ever
|
|
234
|
+
* learning what the kind means.
|
|
235
|
+
*/
|
|
236
|
+
export const aguiFramePartRenderer = Object.freeze({
|
|
237
|
+
kind: "part-renderer",
|
|
238
|
+
name: AGUI_FRAME_KIND,
|
|
239
|
+
render(part) {
|
|
240
|
+
// Defensive rather than trusting: core resolved us by kind, but a caller can hand us anything.
|
|
241
|
+
if (!isAguiFramePart(part))
|
|
242
|
+
return `[not an AG-UI frame]`;
|
|
243
|
+
const events = part.events;
|
|
244
|
+
if (!Array.isArray(events) || events.length === 0)
|
|
245
|
+
return `[AG-UI frame carrying no events]`;
|
|
246
|
+
const lines = renderEvents(events);
|
|
247
|
+
// An events array that produced no lines is impossible today (every branch pushes), but if a
|
|
248
|
+
// future branch returns nothing this must not become the silent empty string that the whole
|
|
249
|
+
// exercise exists to remove.
|
|
250
|
+
return lines.length > 0 ? lines.join("\n") : `[AG-UI frame with ${events.length} event(s) and nothing to show]`;
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
/**
|
|
254
|
+
* Register the provider, once, however many copies of this module get loaded.
|
|
255
|
+
*
|
|
256
|
+
* **THIS PACKAGE LEGITIMATELY EXISTS TWICE IN ONE PROCESS, AND A BARE `register` CRASHES THERE.**
|
|
257
|
+
* Measured, not anticipated: `cotal ext add <connector>` failed with
|
|
258
|
+
* `extension already registered: part-renderer:ag-ui.frame`, and the mechanism is the extension
|
|
259
|
+
* prefix's layout. The CLI imports this module from its OWN copy of `connector-core`. Materializing
|
|
260
|
+
* an installed connector imports `connector-core` again, from the extension prefix's `node_modules`,
|
|
261
|
+
* which is a different physical file and therefore a second module instance with its own top-level
|
|
262
|
+
* evaluation. `@cotal-ai/core` is LINKED to the CLI's single copy (`ext add` writes that link on
|
|
263
|
+
* purpose), so both instances see ONE registry, and `registry.register` throws on the duplicate
|
|
264
|
+
* `kind:name`. That throw took down `ext add` for every connector.
|
|
265
|
+
*
|
|
266
|
+
* **WHY THIS IS NOT THE SILENT DEGRADE THE PROJECT REFUSES.** `register`'s refusal exists to catch
|
|
267
|
+
* TWO EXTENSIONS CLAIMING ONE NAME, which is a genuine conflict nobody can adjudicate. This is one
|
|
268
|
+
* extension arriving twice, which is not a conflict: `ag-ui.frame` is defined by this package, no
|
|
269
|
+
* other package may claim it, and every copy of this file registers a provider that draws it the
|
|
270
|
+
* same way. First one wins, deterministically, and the second is a no-op rather than a fatal error
|
|
271
|
+
* on a path a customer runs. Skipping a duplicate self-registration is a different act from
|
|
272
|
+
* swallowing a failure.
|
|
273
|
+
*
|
|
274
|
+
* It is a named function rather than a bare guard so the property is executable: a cell calls it
|
|
275
|
+
* twice and asserts the second call neither throws nor displaces the first.
|
|
276
|
+
*/
|
|
277
|
+
export function registerAguiFramePartRenderer() {
|
|
278
|
+
if (registry.has("part-renderer", AGUI_FRAME_KIND))
|
|
279
|
+
return;
|
|
280
|
+
registry.register(aguiFramePartRenderer);
|
|
281
|
+
}
|
|
282
|
+
registerAguiFramePartRenderer();
|
|
283
|
+
//# sourceMappingURL=agui-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agui-render.js","sourceRoot":"","sources":["../src/agui-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when a session that is going to publish events cannot say where its WAL belongs.
|
|
3
|
+
*
|
|
4
|
+
* A distinct type rather than a bare `Error` so a caller can tell "misconfigured launch" from
|
|
5
|
+
* "filesystem said no" without matching on message text.
|
|
6
|
+
*/
|
|
7
|
+
export declare class EventsStateRootMissing extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The state root for an events-enabled session, or a loud failure.
|
|
12
|
+
*
|
|
13
|
+
* **THE FAILURE THIS PREVENTS IS SILENT, WHICH IS WHY IT IS A THROW AND NOT A DEFAULT.** The
|
|
14
|
+
* tempting fallback is `process.cwd()`. A WAL written there is not an error anyone sees: the emitter
|
|
15
|
+
* starts, frames publish, and the durable state that makes a restart safe sits in whatever directory
|
|
16
|
+
* the launch happened to begin in — a per-agent working directory that "can point at any repo". The
|
|
17
|
+
* next start resolves the real root, finds no WAL, and reads an already-published thread as VIRGIN:
|
|
18
|
+
* `E := 0`, a fresh epoch, a second frame claiming a sequence the stream has already seen. Nothing
|
|
19
|
+
* reports a problem at any point, and an absence is what a clean board looks like.
|
|
20
|
+
*
|
|
21
|
+
* `env` is a PARAMETER and the root resolves PER CALL. A module-level read would freeze whatever the
|
|
22
|
+
* environment was at first import, and none of what this path is keyed on — space, principal,
|
|
23
|
+
* thread — is process-wide.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveEventsStateRoot(env: {
|
|
26
|
+
COTAL_WORKSPACE_ROOT?: string | undefined;
|
|
27
|
+
}): string;
|
|
28
|
+
/** The resolved locations for one `(space, principal, threadId)`. Pure: computes, touches nothing. */
|
|
29
|
+
export interface EventWalLocation {
|
|
30
|
+
/** `<workspaceRoot>/.cotal/events/<h(space)>/<h(principal)>` — the lock's directory. */
|
|
31
|
+
principalDir: string;
|
|
32
|
+
/** The single-emitter-per-principal lock. One emitter per PRINCIPAL, not per thread. */
|
|
33
|
+
lockPath: string;
|
|
34
|
+
/** `<principalDir>/<h(threadId)>` — the directory holding exactly one `wal.json`. */
|
|
35
|
+
threadDir: string;
|
|
36
|
+
/** The WAL document itself. */
|
|
37
|
+
walPath: string;
|
|
38
|
+
}
|
|
39
|
+
/** What {@link ensureEventWalDir} returns: the location, plus the lock it actually took for it. */
|
|
40
|
+
export interface HeldEventWalLocation extends EventWalLocation {
|
|
41
|
+
lock: PrincipalLock;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve where this principal's WAL for this thread lives. Pure — no IO, no side effects.
|
|
45
|
+
*
|
|
46
|
+
* `workspaceRoot` is taken as given rather than defaulted. A default here would be a silent fallback
|
|
47
|
+
* onto whatever directory the process happened to start in, which is precisely the scattering the
|
|
48
|
+
* root exists to prevent; the caller that cannot resolve one must fail loud instead.
|
|
49
|
+
*/
|
|
50
|
+
export declare function eventWalLocation(opts: {
|
|
51
|
+
workspaceRoot: string;
|
|
52
|
+
space: string;
|
|
53
|
+
principal: string;
|
|
54
|
+
threadId: string;
|
|
55
|
+
}): EventWalLocation;
|
|
56
|
+
/** Every refusal on the lock path is one of these, so a caller never mistakes it for an I/O blip. */
|
|
57
|
+
export declare class PrincipalLockError extends Error {
|
|
58
|
+
readonly path: string;
|
|
59
|
+
readonly invariant: string;
|
|
60
|
+
constructor(path: string, invariant: string, detail: string);
|
|
61
|
+
}
|
|
62
|
+
/** A HELD lock. It exists as an object only while this process owns the file. */
|
|
63
|
+
export interface PrincipalLock {
|
|
64
|
+
readonly path: string;
|
|
65
|
+
/** Close the handle and remove the file. Idempotent: releasing twice is not an error. */
|
|
66
|
+
release(): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Take this principal's lock and HOLD IT for the life of the process.
|
|
70
|
+
*
|
|
71
|
+
* The handle stays open deliberately. A lock released at the end of the acquiring function is a
|
|
72
|
+
* lock that was never held, and the layout comment above has claimed single-emitter exclusion since
|
|
73
|
+
* this module was written while `lockPath` was only ever COMPUTED — a path in a struct standing in
|
|
74
|
+
* for a guarantee. This is that claim made real.
|
|
75
|
+
*/
|
|
76
|
+
export declare function acquirePrincipalLock(lockPath: string): Promise<PrincipalLock>;
|
|
77
|
+
/**
|
|
78
|
+
* Create the directory chain for a thread's WAL and make it durable: **once, before the
|
|
79
|
+
* first transition.**
|
|
80
|
+
*
|
|
81
|
+
* The WAL's own replace protocol fsyncs `wal.json` and the thread directory that holds it. That is
|
|
82
|
+
* not sufficient on its own: a newly created `<h(threadId)>/` directory's NAME is an entry in its
|
|
83
|
+
* PARENT, and `ensureDirNoSymlink` only `mkdir`s each missing component with no fsync anywhere. On a
|
|
84
|
+
* filesystem that honours the distinction, a crash after the first transition and after the publish
|
|
85
|
+
* can come back with the directory link itself lost — no WAL, no pending record — and boot then
|
|
86
|
+
* reads a thread that has already published as VIRGIN: `E := 0`, a fresh epoch, and a second frame
|
|
87
|
+
* claiming a sequence the stream has already seen.
|
|
88
|
+
*
|
|
89
|
+
* So every component from the workspace root down is fsynced, parents included, rather than the leaf
|
|
90
|
+
* alone. It runs once at emitter start; the cost is a handful of directory syncs against a session
|
|
91
|
+
* that is about to do real work.
|
|
92
|
+
*
|
|
93
|
+
* Returns the WAL path, so a caller cannot resolve the location by one route and create it by
|
|
94
|
+
* another — and the HELD principal lock with it, for the same reason. Handing back a location whose
|
|
95
|
+
* lock the caller then has to remember to take is how the lock came to be a path and nothing else.
|
|
96
|
+
*/
|
|
97
|
+
export declare function ensureEventWalDir(opts: {
|
|
98
|
+
workspaceRoot: string;
|
|
99
|
+
space: string;
|
|
100
|
+
principal: string;
|
|
101
|
+
threadId: string;
|
|
102
|
+
}): Promise<HeldEventWalLocation>;
|
|
103
|
+
//# sourceMappingURL=agui-wal-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agui-wal-path.d.ts","sourceRoot":"","sources":["../src/agui-wal-path.ts"],"names":[],"mappings":"AAwCA;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAWjG;AAaD,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mGAAmG;AACnG,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,IAAI,EAAE,aAAa,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,gBAAgB,CASnB;AAED,qGAAqG;AACrG,qBAAa,kBAAmB,SAAQ,KAAK;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM;gBAAxC,IAAI,EAAE,MAAM,EAAW,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI9E;AAED,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AA4FD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqCnF;AA8BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqBhC"}
|