@zelari/core 2.37.2 → 2.38.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 (43) hide show
  1. package/README.md +1 -1
  2. package/dist/core/AgentHarness.d.ts +9 -1
  3. package/dist/core/AgentHarness.d.ts.map +1 -1
  4. package/dist/core/AgentHarness.js +34 -7
  5. package/dist/core/AgentHarness.js.map +1 -1
  6. package/dist/core/requestSnapshot.d.ts +19 -4
  7. package/dist/core/requestSnapshot.d.ts.map +1 -1
  8. package/dist/core/requestSnapshot.js +103 -30
  9. package/dist/core/requestSnapshot.js.map +1 -1
  10. package/dist/runtime/providers.d.ts +8 -0
  11. package/dist/runtime/providers.d.ts.map +1 -1
  12. package/dist/runtime/providers.js.map +1 -1
  13. package/dist/session/index.d.ts +1 -0
  14. package/dist/session/index.d.ts.map +1 -1
  15. package/dist/session/index.js +1 -0
  16. package/dist/session/index.js.map +1 -1
  17. package/dist/session/replay.d.ts +18 -0
  18. package/dist/session/replay.d.ts.map +1 -1
  19. package/dist/session/replay.js +19 -4
  20. package/dist/session/replay.js.map +1 -1
  21. package/dist/session/replayCache.d.ts +76 -0
  22. package/dist/session/replayCache.d.ts.map +1 -0
  23. package/dist/session/replayCache.js +188 -0
  24. package/dist/session/replayCache.js.map +1 -0
  25. package/dist/verification/commandConcurrency.d.ts +34 -0
  26. package/dist/verification/commandConcurrency.d.ts.map +1 -0
  27. package/dist/verification/commandConcurrency.js +45 -0
  28. package/dist/verification/commandConcurrency.js.map +1 -0
  29. package/dist/verification/engine.d.ts +25 -0
  30. package/dist/verification/engine.d.ts.map +1 -1
  31. package/dist/verification/engine.js +58 -6
  32. package/dist/verification/engine.js.map +1 -1
  33. package/dist/verification/index.d.ts +1 -0
  34. package/dist/verification/index.d.ts.map +1 -1
  35. package/dist/verification/index.js +1 -0
  36. package/dist/verification/index.js.map +1 -1
  37. package/dist/verification/runWithLimit.d.ts +24 -0
  38. package/dist/verification/runWithLimit.d.ts.map +1 -0
  39. package/dist/verification/runWithLimit.js +50 -0
  40. package/dist/verification/runWithLimit.js.map +1 -0
  41. package/dist/version.d.ts +1 -1
  42. package/dist/version.js +1 -1
  43. package/package.json +1 -1
@@ -20,12 +20,28 @@
20
20
  * - tools are sorted by `name.localeCompare` — the same canonical order
21
21
  * the OpenAI-compatible provider applies on the wire, so the snapshot
22
22
  * reflects the actual request bytes,
23
- * - snapshots deep-clone their payload: later mutation of the live
24
- * message array must not rewrite history.
23
+ * - snapshots deep-clone their payload in `full` mode: later mutation of
24
+ * the live message array must not rewrite history.
25
+ *
26
+ * Int4b (`ZELARI_REQUEST_SNAPSHOT=full|lite|off`, default `full`):
27
+ * - `full` — current behavior (eager fingerprints, structuredClone).
28
+ * - `lite` — shallow first-level copies; fingerprints are lazy getters
29
+ * (same digest as `full` when read); header fingerprint memoized on
30
+ * tools-array identity + system key. Messages are not mutated after
31
+ * append in the tool loop, so shallow copies are safe on the hot path.
32
+ * - `off` — harness skips snapshot construction (metering stays; audit
33
+ * trail of routed requests is reduced).
25
34
  *
26
35
  * @since v1.36.0 — context/cache upgrade (routed request snapshots)
27
36
  */
28
37
  import { createHash } from 'node:crypto';
38
+ /** Default stays `full` until lite is dogfooded (Int4b). Unknown values → full. */
39
+ export function resolveRequestSnapshotMode(env = process.env) {
40
+ const raw = env.ZELARI_REQUEST_SNAPSHOT?.trim().toLowerCase();
41
+ if (raw === 'lite' || raw === 'off')
42
+ return raw;
43
+ return 'full';
44
+ }
29
45
  /**
30
46
  * Deterministic JSON: object keys sorted recursively, arrays in order.
31
47
  * No external deps (AGENTS.MD: zero new heavy dependencies).
@@ -48,52 +64,109 @@ export function stableStringify(value) {
48
64
  export function sha256Hex(input) {
49
65
  return createHash('sha256').update(input, 'utf8').digest('hex').slice(0, 32);
50
66
  }
51
- function cloneMessages(messages) {
67
+ function cloneMessagesDeep(messages) {
52
68
  return structuredClone(messages);
53
69
  }
70
+ function cloneMessagesLite(messages) {
71
+ return messages.map((m) => ({ ...m }));
72
+ }
54
73
  /** Canonical tool order — must match the wire order (openai-compatible.ts). */
55
74
  export function canonicalTools(tools) {
56
75
  return [...tools].sort((a, b) => a.name.localeCompare(b.name));
57
76
  }
77
+ function cloneToolsDeep(tools) {
78
+ return canonicalTools(tools).map((t) => structuredClone(t));
79
+ }
80
+ function cloneToolsLite(tools) {
81
+ return canonicalTools(tools).map((t) => ({ ...t }));
82
+ }
83
+ let headerMemo = null;
84
+ /** Test-only: drop the lite header memo. */
85
+ export function __resetRequestSnapshotMemoForTests() {
86
+ headerMemo = null;
87
+ }
58
88
  /**
59
89
  * Build a snapshot from the parameters of a provider call.
60
- * The snapshot owns deep clones — mutating `messages`/`tools` afterwards
61
- * does not affect it.
90
+ * `full` (default): the snapshot owns deep clones.
91
+ * `lite`: shallow first-level copies + lazy fingerprints (same digest).
62
92
  */
63
93
  export function createRoutedRequestSnapshot(params) {
64
- // Split at the FIRST non-system message: the system prefix is whatever
65
- // leading run of role:'system' the request carried (1 or 2 messages in
66
- // the current builders — the split must not assume a fixed count).
94
+ const mode = params.mode ?? resolveRequestSnapshotMode();
67
95
  let split = 0;
68
96
  while (split < params.messages.length && params.messages[split].role === 'system') {
69
97
  split++;
70
98
  }
71
- const systemMessages = cloneMessages(params.messages.slice(0, split));
72
- const conversation = cloneMessages(params.messages.slice(split));
73
- const tools = canonicalTools(params.tools).map((t) => structuredClone(t));
74
- const header = stableStringify({
75
- provider: params.provider,
76
- model: params.model,
77
- systemMessages,
78
- tools,
79
- });
80
- const request = stableStringify({
81
- provider: params.provider,
82
- model: params.model,
83
- systemMessages,
84
- tools,
85
- conversation,
86
- });
87
- return {
88
- provider: params.provider,
89
- model: params.model,
99
+ const lite = mode === 'lite';
100
+ const cloneMsg = lite ? cloneMessagesLite : cloneMessagesDeep;
101
+ const systemMessages = cloneMsg(params.messages.slice(0, split));
102
+ const conversation = cloneMsg(params.messages.slice(split));
103
+ const createdAt = Date.now();
104
+ const { provider, model } = params;
105
+ if (!lite) {
106
+ const tools = cloneToolsDeep(params.tools);
107
+ const header = stableStringify({ provider, model, systemMessages, tools });
108
+ const request = stableStringify({
109
+ provider,
110
+ model,
111
+ systemMessages,
112
+ tools,
113
+ conversation,
114
+ });
115
+ return {
116
+ provider,
117
+ model,
118
+ systemMessages,
119
+ conversation,
120
+ tools,
121
+ headerFingerprint: sha256Hex(header),
122
+ requestFingerprint: sha256Hex(request),
123
+ createdAt,
124
+ };
125
+ }
126
+ const systemKey = sha256Hex(stableStringify(systemMessages));
127
+ let tools;
128
+ let headerFp;
129
+ if (headerMemo &&
130
+ headerMemo.toolsRef === params.tools &&
131
+ headerMemo.provider === provider &&
132
+ headerMemo.model === model &&
133
+ headerMemo.systemKey === systemKey) {
134
+ tools = headerMemo.tools;
135
+ headerFp = headerMemo.headerFingerprint;
136
+ }
137
+ else {
138
+ tools = cloneToolsLite(params.tools);
139
+ }
140
+ let requestFp;
141
+ const snap = {
142
+ provider,
143
+ model,
90
144
  systemMessages,
91
145
  conversation,
92
146
  tools,
93
- headerFingerprint: sha256Hex(header),
94
- requestFingerprint: sha256Hex(request),
95
- createdAt: Date.now(),
147
+ createdAt,
148
+ get headerFingerprint() {
149
+ if (headerFp === undefined) {
150
+ headerFp = sha256Hex(stableStringify({ provider, model, systemMessages, tools }));
151
+ headerMemo = {
152
+ toolsRef: params.tools,
153
+ provider,
154
+ model,
155
+ systemKey,
156
+ tools,
157
+ headerFingerprint: headerFp,
158
+ };
159
+ }
160
+ return headerFp;
161
+ },
162
+ get requestFingerprint() {
163
+ if (requestFp === undefined) {
164
+ requestFp = sha256Hex(stableStringify({ provider, model, systemMessages, tools, conversation }));
165
+ }
166
+ return requestFp;
167
+ },
96
168
  };
169
+ return snap;
97
170
  }
98
171
  /**
99
172
  * Best-effort check (P11): is `messages` an exact prefix-extension of the
@@ -1 +1 @@
1
- {"version":3,"file":"requestSnapshot.js","sourceRoot":"","sources":["../../src/core/requestSnapshot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"requestSnapshot.js","sourceRoot":"","sources":["../../src/core/requestSnapshot.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,14 @@ export interface ShellResult {
49
49
  stderr: string;
50
50
  durationMs: number;
51
51
  timedOut: boolean;
52
+ /**
53
+ * Set by caching decorators, not by providers (Int2b): true when this
54
+ * observation was served from a previous identical execution instead of
55
+ * being re-run. Absent on every provider-produced result, so existing
56
+ * consumers are unaffected; verification annotates such observations
57
+ * (`detail` suffix, `cached: true` in the `verification.evidence` payload).
58
+ */
59
+ cached?: boolean;
52
60
  }
53
61
  export interface ShellExecOptions {
54
62
  /** Workspace-relative cwd (default: workspace root). */
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,0EAA0E;AAC1E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,IAAI,GAAG,uBAAuB,CAAC;IACxC,YACkB,IAAY,EACZ,SAAiB;QAEjC,KAAK,CAAC,gCAAgC,SAAS,WAAW,IAAI,GAAG,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAQ;QACZ,cAAS,GAAT,SAAS,CAAQ;QAGjC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAYD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW;IACrD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,OAAO,cAAc;IAGJ;IAFZ,IAAI,GAAG,OAAgB,CAAC;IAEjC,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErC,OAAO,CAAC,GAAW;QACjB,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;CACF;AAkDD,+EAA+E;AAC/E,MAAM,OAAO,oBAAoB;IACtB,SAAS,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,OAAO,CAAC,IAAkB;QAC9B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,+DAA+D,IAAI,CAAC,IAAI,IAAI;SACzF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAqB,IAAI,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,0EAA0E;AAC1E,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAG/B;IACA;IAHT,IAAI,GAAG,uBAAuB,CAAC;IACxC,YACkB,IAAY,EACZ,SAAiB;QAEjC,KAAK,CAAC,gCAAgC,SAAS,WAAW,IAAI,GAAG,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAQ;QACZ,cAAS,GAAT,SAAS,CAAQ;QAGjC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAYD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW;IACrD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,OAAO,cAAc;IAGJ;IAFZ,IAAI,GAAG,OAAgB,CAAC;IAEjC,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErC,OAAO,CAAC,GAAW;QACjB,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;CACF;AA0DD,+EAA+E;AAC/E,MAAM,OAAO,oBAAoB;IACtB,SAAS,GAAG,KAAK,CAAC;IAE3B,KAAK,CAAC,OAAO,CAAC,IAAkB;QAC9B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,+DAA+D,IAAI,CAAC,IAAI,IAAI;SACzF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAqB,IAAI,oBAAoB,EAAE,CAAC"}
@@ -11,6 +11,7 @@ export * from './compaction.js';
11
11
  export * from './agentAdapter.js';
12
12
  export * from './writer.js';
13
13
  export * from './replay.js';
14
+ export * from './replayCache.js';
14
15
  export * from './store.js';
15
16
  export * from './lineage.js';
16
17
  export * from './exportSession.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
@@ -11,6 +11,7 @@ export * from './compaction.js';
11
11
  export * from './agentAdapter.js';
12
12
  export * from './writer.js';
13
13
  export * from './replay.js';
14
+ export * from './replayCache.js';
14
15
  export * from './store.js';
15
16
  export * from './lineage.js';
16
17
  export * from './exportSession.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
@@ -24,6 +24,24 @@ export interface ReplayReport {
24
24
  ok: boolean;
25
25
  }
26
26
  export declare function readSessionLog(filePath: string): Promise<ReplayReport>;
27
+ /** Whole-file text → ReplayReport (shared with the incremental reader, Int4a). */
28
+ export declare function parseSessionLogText(filePath: string, content: string): ReplayReport;
29
+ /**
30
+ * Parse ONE batch of raw JSONL lines (as produced by `split('\n')`), carrying
31
+ * the running `expected` seq and the 0-based index of the batch's first line.
32
+ * The full reader above and the incremental byte-append reader (replayCache.ts)
33
+ * share this, so both report the SAME events/issues for the same log — that
34
+ * equivalence is the replay-cache contract.
35
+ */
36
+ export declare function parseSessionLogLines(lines: readonly string[], opts?: {
37
+ expected?: number;
38
+ linesConsumed?: number;
39
+ }): {
40
+ events: SessionEventEnvelope[];
41
+ issues: ReplayIssue[];
42
+ expected: number;
43
+ linesConsumed: number;
44
+ };
27
45
  /** Loose summary of a verification.run event (defensive reads). */
28
46
  export interface VerificationRunSummary {
29
47
  seq: number;
@@ -1 +1 @@
1
- {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/E,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,SAAS,GACT,kBAAkB,CAAC;AAEvB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,4DAA4D;IAC5D,EAAE,EAAE,OAAO,CAAC;CACb;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAoD5E;AAED,mEAAmE;AACnE,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,sBAAsB,EAAE,CAAC;IACxC,aAAa,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,0EAA0E;IAC1E,aAAa,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,uEAAuE;IACvE,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACrC;AAmBD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EAAE,MAAM,GAAE,WAAW,EAAO,GAAG,iBAAiB,CA4DtH"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
@@ -20,15 +20,30 @@ export async function readSessionLog(filePath) {
20
20
  }
21
21
  throw err;
22
22
  }
23
+ return parseSessionLogText(filePath, content);
24
+ }
25
+ /** Whole-file text → ReplayReport (shared with the incremental reader, Int4a). */
26
+ export function parseSessionLogText(filePath, content) {
27
+ const { events, issues } = parseSessionLogLines(content.split('\n'));
28
+ return { path: filePath, events, issues, ok: issues.length === 0 };
29
+ }
30
+ /**
31
+ * Parse ONE batch of raw JSONL lines (as produced by `split('\n')`), carrying
32
+ * the running `expected` seq and the 0-based index of the batch's first line.
33
+ * The full reader above and the incremental byte-append reader (replayCache.ts)
34
+ * share this, so both report the SAME events/issues for the same log — that
35
+ * equivalence is the replay-cache contract.
36
+ */
37
+ export function parseSessionLogLines(lines, opts = {}) {
23
38
  const events = [];
24
39
  const issues = [];
25
- let expected = 1;
26
- const lines = content.split('\n');
40
+ const base = opts.linesConsumed ?? 0;
41
+ let expected = opts.expected ?? 1;
27
42
  for (let i = 0; i < lines.length; i++) {
28
43
  const trimmed = lines[i].trim();
29
44
  if (!trimmed)
30
45
  continue;
31
- const lineNo = i + 1;
46
+ const lineNo = base + i + 1;
32
47
  let parsed;
33
48
  try {
34
49
  parsed = JSON.parse(trimmed);
@@ -65,7 +80,7 @@ export async function readSessionLog(filePath) {
65
80
  expected = envelope.seq + 1;
66
81
  }
67
82
  }
68
- return { path: filePath, events, issues, ok: issues.length === 0 };
83
+ return { events, issues, expected, linesConsumed: base + lines.length };
69
84
  }
70
85
  function parseVerification(e) {
71
86
  const raw = Array.isArray(e.data.results) ? e.data.results : [];
@@ -1 +1 @@
1
- {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * session/replayCache.ts — Int4a incremental replay cache for long sessions.
3
+ *
4
+ * `readSessionLog()` re-reads the WHOLE JSONL and Zod-parses every line on
5
+ * every call, and the spine does it 2–8 times per turn: O(n²) in session
6
+ * length. This cache keeps the parsed events per file and, on a later call,
7
+ * reads only the bytes appended since the last read (COMPLETE lines only).
8
+ *
9
+ * Invariants:
10
+ * - `byteSize` is what the entry OWNS: every complete line consumed plus the
11
+ * bytes held in `partial`. It always sits on a UTF-8 character boundary, so
12
+ * the next read starts exactly there and no byte is ever parsed twice.
13
+ * - A tail without its final '\n' stays in `partial` and is NOT an event yet:
14
+ * it appears exactly once, when the writer completes the line. A tail
15
+ * ending INSIDE a multi-byte character is not consumed at all (re-read from
16
+ * a boundary) — a torn write can never poison the cache with U+FFFD.
17
+ * - Shrink (`size < byteSize`) or a backwards mtime (rotation / in-place
18
+ * rewrite) ⇒ full re-read through the SAME parse path as `readSessionLog`,
19
+ * so a replaced log is never served from stale entries.
20
+ * - The returned ReplayReport is fresh (caller-owned arrays); the envelopes
21
+ * inside are shared and treat-as-immutable — the spine contract.
22
+ * - Known deviation: a COLD read (empty cache / rotation) consumes a
23
+ * non-terminated last line exactly as `readSessionLog` does today; only
24
+ * appends observed while warm are deferred into `partial`. The writer
25
+ * always terminates lines with '\n', so this needs external truncation.
26
+ *
27
+ * Kill switch `ZELARI_SPINE_REPLAY_CACHE`: DEFAULT OFF in this merge (dogfood
28
+ * first) — set `1`/`true`/`yes`/`on` to enable. When unset/0/false/off,
29
+ * `readSessionLogCached` calls the existing `readSessionLog` verbatim.
30
+ */
31
+ import { type ReplayIssue, type ReplayReport } from './replay.js';
32
+ import type { SessionEventEnvelope } from './types.js';
33
+ /** `ZELARI_SPINE_REPLAY_CACHE` (default OFF): truthy spelling = 1/true/yes/on. */
34
+ export declare function isReplayCacheEnabled(env?: NodeJS.ProcessEnv): boolean;
35
+ export interface ReplayCacheEntry {
36
+ /** Bytes owned by this entry: complete lines + the bytes held in `partial`. */
37
+ byteSize: number;
38
+ mtimeMs: number;
39
+ events: SessionEventEnvelope[];
40
+ issues: ReplayIssue[];
41
+ /** Seq the next event must carry to be accepted gap-free. */
42
+ expectedSeq: number;
43
+ /** Tail without a final '\n' (writer crash mid-line) — not yet an event. */
44
+ partial: string;
45
+ /**
46
+ * Lines consumed so far, blank/corrupt ones included, so a new issue keeps
47
+ * its ORIGINAL 1-based file line number (`linesConsumed + index + 1`).
48
+ * Additive to the planned entry shape: without it an incremental read would
49
+ * renumber issues and stop being equivalent to `readSessionLog`.
50
+ */
51
+ linesConsumed: number;
52
+ }
53
+ /**
54
+ * Incremental replay cache. Own ONE instance per session (the spine mirror owns
55
+ * its own); entries are keyed by file path, so concurrent sessions never share
56
+ * decoded state.
57
+ */
58
+ export declare class SessionLogCache {
59
+ private readonly entries;
60
+ /** Files currently cached (diagnostics). */
61
+ get size(): number;
62
+ /** The cached entry for `filePath` (copy; tests + diagnostics), if any. */
63
+ peek(filePath: string): ReplayCacheEntry | undefined;
64
+ /** Read the log, incrementally when a usable entry exists. */
65
+ read(filePath: string): Promise<ReplayReport>;
66
+ /** Append-path read: only the bytes written since the last read are parsed. */
67
+ private extend;
68
+ /** Cold / rotated read: same parse as `readSessionLog`, then seed the entry. */
69
+ private full;
70
+ }
71
+ /**
72
+ * Cached read of a session log. Without a cache — or with the kill switch off
73
+ * (the default in this merge) — this is `readSessionLog` verbatim.
74
+ */
75
+ export declare function readSessionLogCached(filePath: string, cache?: SessionLogCache, env?: NodeJS.ProcessEnv): Promise<ReplayReport>;
76
+ //# sourceMappingURL=replayCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replayCache.d.ts","sourceRoot":"","sources":["../../src/session/replayCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAMvD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGlF;AAED,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAuCD;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAE/D,4CAA4C;IAC5C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,2EAA2E;IAC3E,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAKpD,8DAA8D;IACxD,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAmBnD,+EAA+E;YACjE,MAAM;IAwCpB,gFAAgF;YAClE,IAAI;CA6BnB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,YAAY,CAAC,CAGvB"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * session/replayCache.ts — Int4a incremental replay cache for long sessions.
3
+ *
4
+ * `readSessionLog()` re-reads the WHOLE JSONL and Zod-parses every line on
5
+ * every call, and the spine does it 2–8 times per turn: O(n²) in session
6
+ * length. This cache keeps the parsed events per file and, on a later call,
7
+ * reads only the bytes appended since the last read (COMPLETE lines only).
8
+ *
9
+ * Invariants:
10
+ * - `byteSize` is what the entry OWNS: every complete line consumed plus the
11
+ * bytes held in `partial`. It always sits on a UTF-8 character boundary, so
12
+ * the next read starts exactly there and no byte is ever parsed twice.
13
+ * - A tail without its final '\n' stays in `partial` and is NOT an event yet:
14
+ * it appears exactly once, when the writer completes the line. A tail
15
+ * ending INSIDE a multi-byte character is not consumed at all (re-read from
16
+ * a boundary) — a torn write can never poison the cache with U+FFFD.
17
+ * - Shrink (`size < byteSize`) or a backwards mtime (rotation / in-place
18
+ * rewrite) ⇒ full re-read through the SAME parse path as `readSessionLog`,
19
+ * so a replaced log is never served from stale entries.
20
+ * - The returned ReplayReport is fresh (caller-owned arrays); the envelopes
21
+ * inside are shared and treat-as-immutable — the spine contract.
22
+ * - Known deviation: a COLD read (empty cache / rotation) consumes a
23
+ * non-terminated last line exactly as `readSessionLog` does today; only
24
+ * appends observed while warm are deferred into `partial`. The writer
25
+ * always terminates lines with '\n', so this needs external truncation.
26
+ *
27
+ * Kill switch `ZELARI_SPINE_REPLAY_CACHE`: DEFAULT OFF in this merge (dogfood
28
+ * first) — set `1`/`true`/`yes`/`on` to enable. When unset/0/false/off,
29
+ * `readSessionLogCached` calls the existing `readSessionLog` verbatim.
30
+ */
31
+ import { promises as fs } from 'node:fs';
32
+ import { readSessionLog, parseSessionLogLines, } from './replay.js';
33
+ /** `ZELARI_SPINE_REPLAY_CACHE` (default OFF): truthy spelling = 1/true/yes/on. */
34
+ export function isReplayCacheEnabled(env = process.env) {
35
+ const v = (env.ZELARI_SPINE_REPLAY_CACHE ?? '').trim().toLowerCase();
36
+ return v === '1' || v === 'true' || v === 'yes' || v === 'on';
37
+ }
38
+ const NL = 0x0a;
39
+ /** >0 when `buf` ends inside a multi-byte UTF-8 sequence (bytes to leave unread). */
40
+ function utf8IncompleteTailBytes(buf) {
41
+ const max = Math.min(4, buf.length);
42
+ for (let back = 1; back <= max; back++) {
43
+ const b = buf[buf.length - back];
44
+ if (b < 0x80)
45
+ return 0; // ASCII tail — complete
46
+ if (b >= 0xc0) {
47
+ // Lead byte: it must be followed by (need - 1) continuation bytes.
48
+ const need = b >= 0xf0 ? 4 : b >= 0xe0 ? 3 : 2;
49
+ return back >= need ? 0 : need - back;
50
+ }
51
+ // 0x80..0xbf = continuation byte — walk back to its lead byte.
52
+ }
53
+ return 0; // no lead byte within 4 bytes: malformed anyway, let JSON.parse judge
54
+ }
55
+ /** Read exactly `length` bytes at `position` (a live writer may shorten reads). */
56
+ async function readAt(fh, position, length) {
57
+ const buf = Buffer.allocUnsafe(length);
58
+ let done = 0;
59
+ while (done < length) {
60
+ const { bytesRead } = await fh.read(buf, done, length - done, position + done);
61
+ if (bytesRead === 0)
62
+ break; // truncated under us — parse what we got
63
+ done += bytesRead;
64
+ }
65
+ return done === length ? buf : buf.subarray(0, done);
66
+ }
67
+ /** Fresh report over the cached arrays — a consumer may mutate them freely. */
68
+ function toReport(filePath, entry) {
69
+ const events = entry.events.slice();
70
+ const issues = entry.issues.slice();
71
+ return { path: filePath, events, issues, ok: issues.length === 0 };
72
+ }
73
+ /**
74
+ * Incremental replay cache. Own ONE instance per session (the spine mirror owns
75
+ * its own); entries are keyed by file path, so concurrent sessions never share
76
+ * decoded state.
77
+ */
78
+ export class SessionLogCache {
79
+ entries = new Map();
80
+ /** Files currently cached (diagnostics). */
81
+ get size() {
82
+ return this.entries.size;
83
+ }
84
+ /** The cached entry for `filePath` (copy; tests + diagnostics), if any. */
85
+ peek(filePath) {
86
+ const entry = this.entries.get(filePath);
87
+ return entry ? { ...entry } : undefined;
88
+ }
89
+ /** Read the log, incrementally when a usable entry exists. */
90
+ async read(filePath) {
91
+ const cached = this.entries.get(filePath);
92
+ let stat;
93
+ try {
94
+ stat = await fs.stat(filePath);
95
+ }
96
+ catch (err) {
97
+ if (err.code === 'ENOENT') {
98
+ this.entries.delete(filePath);
99
+ return { path: filePath, events: [], issues: [], ok: true };
100
+ }
101
+ throw err;
102
+ }
103
+ if (cached && stat.size >= cached.byteSize && stat.mtimeMs >= cached.mtimeMs) {
104
+ if (stat.size > cached.byteSize)
105
+ return this.extend(filePath, cached, stat);
106
+ return toReport(filePath, cached); // nothing new — no I/O at all
107
+ }
108
+ return this.full(filePath, stat);
109
+ }
110
+ /** Append-path read: only the bytes written since the last read are parsed. */
111
+ async extend(filePath, cached, stat) {
112
+ const fh = await fs.open(filePath, 'r');
113
+ let chunk;
114
+ try {
115
+ chunk = await readAt(fh, cached.byteSize, stat.size - cached.byteSize);
116
+ }
117
+ finally {
118
+ await fh.close();
119
+ }
120
+ const nl = chunk.lastIndexOf(NL);
121
+ const headEnd = nl === -1 ? 0 : nl + 1; // end of the last COMPLETE line
122
+ const tail = chunk.subarray(headEnd);
123
+ // PERF-4a: bytes of the tail that decode cleanly. A tail ending INSIDE a
124
+ // multi-byte char stays unconsumed and is re-read from a boundary, so
125
+ // `partial` is never a U+FFFD-mangled fragment.
126
+ const keep = tail.subarray(0, tail.length - utf8IncompleteTailBytes(tail));
127
+ // The old `partial` is folded into `head` only once a newline arrives; while
128
+ // no line completes it stays in front of the unconsumed tail.
129
+ const head = cached.partial + chunk.subarray(0, headEnd).toString('utf8');
130
+ const lines = headEnd > 0 ? head.split('\n').slice(0, -1) : [];
131
+ const parsed = parseSessionLogLines(lines, {
132
+ expected: cached.expectedSeq,
133
+ linesConsumed: cached.linesConsumed,
134
+ });
135
+ const entry = {
136
+ byteSize: cached.byteSize + headEnd + keep.length,
137
+ mtimeMs: stat.mtimeMs,
138
+ events: parsed.events.length > 0 ? cached.events.concat(parsed.events) : cached.events,
139
+ issues: parsed.issues.length > 0 ? cached.issues.concat(parsed.issues) : cached.issues,
140
+ expectedSeq: parsed.expected,
141
+ partial: (headEnd > 0 ? '' : cached.partial) + keep.toString('utf8'),
142
+ linesConsumed: parsed.linesConsumed,
143
+ };
144
+ this.entries.set(filePath, entry);
145
+ return toReport(filePath, entry);
146
+ }
147
+ /** Cold / rotated read: same parse as `readSessionLog`, then seed the entry. */
148
+ async full(filePath, stat) {
149
+ let content;
150
+ try {
151
+ content = await fs.readFile(filePath, 'utf-8');
152
+ }
153
+ catch (err) {
154
+ if (err.code === 'ENOENT') {
155
+ this.entries.delete(filePath);
156
+ return { path: filePath, events: [], issues: [], ok: true };
157
+ }
158
+ throw err;
159
+ }
160
+ const lines = content.split('\n');
161
+ const parsed = parseSessionLogLines(lines);
162
+ // Count the lines this read consumed: the split's trailing '' is the
163
+ // artificial piece after the final '\n'; a torn tail is already parsed.
164
+ const linesConsumed = content.length === 0 ? 0 : content.endsWith('\n') ? lines.length - 1 : lines.length;
165
+ const entry = {
166
+ // Bytes actually read (never the pre-read stat: the log may have grown).
167
+ byteSize: Buffer.byteLength(content, 'utf8'),
168
+ mtimeMs: stat.mtimeMs,
169
+ events: parsed.events,
170
+ issues: parsed.issues,
171
+ expectedSeq: parsed.expected,
172
+ partial: '',
173
+ linesConsumed,
174
+ };
175
+ this.entries.set(filePath, entry);
176
+ return { path: filePath, events: entry.events.slice(), issues: entry.issues.slice(), ok: entry.issues.length === 0 };
177
+ }
178
+ }
179
+ /**
180
+ * Cached read of a session log. Without a cache — or with the kill switch off
181
+ * (the default in this merge) — this is `readSessionLog` verbatim.
182
+ */
183
+ export async function readSessionLogCached(filePath, cache, env = process.env) {
184
+ if (!cache || !isReplayCacheEnabled(env))
185
+ return readSessionLog(filePath);
186
+ return cache.read(filePath);
187
+ }
188
+ //# sourceMappingURL=replayCache.js.map