@claudexor/event-log 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 joi-lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @claudexor/event-log
2
+
3
+ Internal package of [Claudexor](https://github.com/razzant/claudexor) — Append-only JSONL run-event log (a projection-friendly evidence ledger).
4
+
5
+ Published as part of the Claudexor toolchain; it follows the monorepo's
6
+ lockstep version and has no separate semver contract. Use the `claudexor`
7
+ CLI (or `@claudexor/cli`) as the supported entry point.
@@ -0,0 +1,71 @@
1
+ import type { RunEvent, RunEventType } from "@claudexor/schema";
2
+ /**
3
+ * Append-only JSONL event log for a single run. Terminal output and human
4
+ * summaries are projections; this file is the canonical event stream.
5
+ *
6
+ * Every emitted event carries a monotonic per-run `seq` stamped here — the
7
+ * durable cursor for SSE resume (Last-Event-ID) and snapshot fencing
8
+ * (detail.lastSeq). The counter initializes from the existing file tail so a
9
+ * re-opened log (or an out-of-band appender like the control-api audit
10
+ * writer) continues the sequence instead of restarting it.
11
+ */
12
+ export declare class EventLog {
13
+ private readonly path;
14
+ private readonly runId;
15
+ private readonly taskId;
16
+ /**
17
+ * Optional in-process sink invoked after each event is persisted. Lets a
18
+ * long-running service / GUI observe the live RunEvent stream without
19
+ * tailing the file. The file remains the canonical log; a throwing sink
20
+ * must never break a run, so sink errors are swallowed.
21
+ */
22
+ private readonly onEmit?;
23
+ /**
24
+ * Thread this run is a turn of, when any. Stamped on every event so the
25
+ * global event multiplex can route live progress to a chat surface without
26
+ * a reverse job lookup.
27
+ */
28
+ private readonly threadId?;
29
+ private nextSeq;
30
+ constructor(path: string, runId: string, taskId: string,
31
+ /**
32
+ * Optional in-process sink invoked after each event is persisted. Lets a
33
+ * long-running service / GUI observe the live RunEvent stream without
34
+ * tailing the file. The file remains the canonical log; a throwing sink
35
+ * must never break a run, so sink errors are swallowed.
36
+ */
37
+ onEmit?: ((event: RunEvent) => void) | undefined,
38
+ /**
39
+ * Thread this run is a turn of, when any. Stamped on every event so the
40
+ * global event multiplex can route live progress to a chat surface without
41
+ * a reverse job lookup.
42
+ */
43
+ threadId?: string | undefined);
44
+ /**
45
+ * Unregister this log as the live writer for its path. Out-of-band
46
+ * appenders fall back to file-tail stamping afterwards, which is safe once
47
+ * the owning run is terminal (nobody else holds an in-memory counter).
48
+ */
49
+ dispose(): void;
50
+ /** Append a typed run event. Validates against the schema before writing. */
51
+ emit(type: RunEventType, payload?: Record<string, unknown>): RunEvent;
52
+ /** Read and parse all events (skipping malformed lines, which are surfaced separately). */
53
+ readAll(): {
54
+ events: RunEvent[];
55
+ malformed: number;
56
+ };
57
+ }
58
+ /**
59
+ * Append an out-of-band event (e.g. a control-api audit record) into a run's
60
+ * canonical log WITHOUT corrupting the seq space: routes through the live
61
+ * EventLog when the run is still active (same counter, same onEmit sink), and
62
+ * falls back to file-tail stamping for terminal runs.
63
+ */
64
+ export declare function appendRunEvent(path: string, runId: string, taskId: string, type: RunEventType, payload?: Record<string, unknown>): RunEvent;
65
+ /**
66
+ * Highest `seq` already present in an events.jsonl file (0 for missing/empty).
67
+ * Legacy lines without seq count by position so a continued log never reuses
68
+ * a line number an SSE replayer may have already served as a fallback id.
69
+ */
70
+ export declare function lastSeqInFile(path: string): number;
71
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;;;;;;;;GASG;AACH,qBAAa,QAAQ;IAIjB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAlB5B,OAAO,CAAC,OAAO,CAAS;gBAGL,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;IAC/B;;;;;OAKG;IACc,MAAM,CAAC,GAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,aAAA;IACnD;;;;OAIG;IACc,QAAQ,CAAC,EAAE,MAAM,YAAA;IAMpC;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAIf,6EAA6E;IAC7E,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ;IA0BzE,2FAA2F;IAC3F,OAAO,IAAI;QAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;CAgBrD;AAUD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,QAAQ,CAaV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBlD"}
package/dist/index.js ADDED
@@ -0,0 +1,170 @@
1
+ import { RunEvent as RunEventSchema } from "@claudexor/schema";
2
+ import { appendLine, nowIso, readTextSafe, redactSecrets } from "@claudexor/util";
3
+ /**
4
+ * Append-only JSONL event log for a single run. Terminal output and human
5
+ * summaries are projections; this file is the canonical event stream.
6
+ *
7
+ * Every emitted event carries a monotonic per-run `seq` stamped here — the
8
+ * durable cursor for SSE resume (Last-Event-ID) and snapshot fencing
9
+ * (detail.lastSeq). The counter initializes from the existing file tail so a
10
+ * re-opened log (or an out-of-band appender like the control-api audit
11
+ * writer) continues the sequence instead of restarting it.
12
+ */
13
+ export class EventLog {
14
+ path;
15
+ runId;
16
+ taskId;
17
+ onEmit;
18
+ threadId;
19
+ nextSeq;
20
+ constructor(path, runId, taskId,
21
+ /**
22
+ * Optional in-process sink invoked after each event is persisted. Lets a
23
+ * long-running service / GUI observe the live RunEvent stream without
24
+ * tailing the file. The file remains the canonical log; a throwing sink
25
+ * must never break a run, so sink errors are swallowed.
26
+ */
27
+ onEmit,
28
+ /**
29
+ * Thread this run is a turn of, when any. Stamped on every event so the
30
+ * global event multiplex can route live progress to a chat surface without
31
+ * a reverse job lookup.
32
+ */
33
+ threadId) {
34
+ this.path = path;
35
+ this.runId = runId;
36
+ this.taskId = taskId;
37
+ this.onEmit = onEmit;
38
+ this.threadId = threadId;
39
+ this.nextSeq = lastSeqInFile(path) + 1;
40
+ activeEventLogs.set(path, this);
41
+ }
42
+ /**
43
+ * Unregister this log as the live writer for its path. Out-of-band
44
+ * appenders fall back to file-tail stamping afterwards, which is safe once
45
+ * the owning run is terminal (nobody else holds an in-memory counter).
46
+ */
47
+ dispose() {
48
+ if (activeEventLogs.get(this.path) === this)
49
+ activeEventLogs.delete(this.path);
50
+ }
51
+ /** Append a typed run event. Validates against the schema before writing. */
52
+ emit(type, payload = {}) {
53
+ const event = RunEventSchema.parse({
54
+ seq: this.nextSeq++,
55
+ ts: nowIso(),
56
+ run_id: this.runId,
57
+ task_id: this.taskId,
58
+ ...(this.threadId ? { thread_id: this.threadId } : {}),
59
+ type,
60
+ payload: redactEventValue(payload),
61
+ });
62
+ appendLine(this.path, JSON.stringify(event));
63
+ if (this.onEmit) {
64
+ try {
65
+ this.onEmit(event);
66
+ }
67
+ catch {
68
+ /* sink errors must never break the canonical run */
69
+ }
70
+ }
71
+ // Terminal events are emitted exactly once, last (output.ready invariant
72
+ // tests pin this). Self-disposing here hands the seq space back to
73
+ // file-tail appenders without requiring every orchestrator mode to
74
+ // remember a finally block.
75
+ if (type === "run.completed" || type === "run.failed" || type === "run.blocked")
76
+ this.dispose();
77
+ return event;
78
+ }
79
+ /** Read and parse all events (skipping malformed lines, which are surfaced separately). */
80
+ readAll() {
81
+ const text = readTextSafe(this.path);
82
+ if (text === null)
83
+ return { events: [], malformed: 0 };
84
+ const events = [];
85
+ let malformed = 0;
86
+ for (const line of text.split("\n")) {
87
+ const trimmed = line.trim();
88
+ if (!trimmed)
89
+ continue;
90
+ try {
91
+ events.push(RunEventSchema.parse(JSON.parse(trimmed)));
92
+ }
93
+ catch {
94
+ malformed += 1;
95
+ }
96
+ }
97
+ return { events, malformed };
98
+ }
99
+ }
100
+ /**
101
+ * Live writers by events.jsonl path (one daemon process hosts the
102
+ * orchestrator AND the control API). While a run is active its EventLog owns
103
+ * the in-memory seq counter; any other same-process appender stamping from
104
+ * the file tail would duplicate ids the moment the live counter is ahead.
105
+ */
106
+ const activeEventLogs = new Map();
107
+ /**
108
+ * Append an out-of-band event (e.g. a control-api audit record) into a run's
109
+ * canonical log WITHOUT corrupting the seq space: routes through the live
110
+ * EventLog when the run is still active (same counter, same onEmit sink), and
111
+ * falls back to file-tail stamping for terminal runs.
112
+ */
113
+ export function appendRunEvent(path, runId, taskId, type, payload = {}) {
114
+ const live = activeEventLogs.get(path);
115
+ if (live)
116
+ return live.emit(type, payload);
117
+ const event = RunEventSchema.parse({
118
+ seq: lastSeqInFile(path) + 1,
119
+ ts: nowIso(),
120
+ run_id: runId,
121
+ task_id: taskId,
122
+ type,
123
+ payload: redactEventValue(payload),
124
+ });
125
+ appendLine(path, JSON.stringify(event));
126
+ return event;
127
+ }
128
+ /**
129
+ * Highest `seq` already present in an events.jsonl file (0 for missing/empty).
130
+ * Legacy lines without seq count by position so a continued log never reuses
131
+ * a line number an SSE replayer may have already served as a fallback id.
132
+ */
133
+ export function lastSeqInFile(path) {
134
+ const text = readTextSafe(path);
135
+ if (text === null)
136
+ return 0;
137
+ let last = 0;
138
+ let lineNo = 0;
139
+ for (const line of text.split("\n")) {
140
+ const trimmed = line.trim();
141
+ if (!trimmed)
142
+ continue;
143
+ lineNo += 1;
144
+ try {
145
+ const parsed = JSON.parse(trimmed);
146
+ const seq = typeof parsed.seq === "number" && Number.isFinite(parsed.seq) ? parsed.seq : lineNo;
147
+ if (seq > last)
148
+ last = seq;
149
+ }
150
+ catch {
151
+ if (lineNo > last)
152
+ last = lineNo;
153
+ }
154
+ }
155
+ return last;
156
+ }
157
+ function redactEventValue(value) {
158
+ if (typeof value === "string")
159
+ return redactSecrets(value);
160
+ if (Array.isArray(value))
161
+ return value.map(redactEventValue);
162
+ if (!value || typeof value !== "object")
163
+ return value;
164
+ const out = {};
165
+ for (const [key, child] of Object.entries(value)) {
166
+ out[key] = redactEventValue(child);
167
+ }
168
+ return out;
169
+ }
170
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@claudexor/event-log",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "description": "Append-only JSONL run-event log (a projection-friendly evidence ledger).",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@claudexor/schema": "1.0.0",
20
+ "@claudexor/util": "1.0.0"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/razzant/claudexor.git",
25
+ "directory": "packages/event-log"
26
+ },
27
+ "homepage": "https://github.com/razzant/claudexor#readme",
28
+ "bugs": {
29
+ "url": "https://github.com/razzant/claudexor/issues"
30
+ },
31
+ "engines": {
32
+ "node": ">=20.19"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "typecheck": "tsc --noEmit"
40
+ }
41
+ }