praana 0.5.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 (204) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/bin/praana.js +17 -0
  4. package/bin/pran.js +17 -0
  5. package/dist/app-banner.d.ts +11 -0
  6. package/dist/app-banner.js +161 -0
  7. package/dist/app-controller.d.ts +44 -0
  8. package/dist/app-controller.js +143 -0
  9. package/dist/app-identity.d.ts +18 -0
  10. package/dist/app-identity.js +52 -0
  11. package/dist/auto-compact.d.ts +16 -0
  12. package/dist/auto-compact.js +101 -0
  13. package/dist/cli-args.d.ts +14 -0
  14. package/dist/cli-args.js +69 -0
  15. package/dist/compile-classic.d.ts +21 -0
  16. package/dist/compile-classic.js +106 -0
  17. package/dist/compiler.d.ts +75 -0
  18. package/dist/compiler.js +406 -0
  19. package/dist/config.d.ts +3 -0
  20. package/dist/config.js +433 -0
  21. package/dist/context-engine/activity-log.d.ts +9 -0
  22. package/dist/context-engine/activity-log.js +109 -0
  23. package/dist/context-engine/artifact-store.d.ts +32 -0
  24. package/dist/context-engine/artifact-store.js +272 -0
  25. package/dist/context-engine/bm25.d.ts +3 -0
  26. package/dist/context-engine/bm25.js +32 -0
  27. package/dist/context-engine/checkpoint.d.ts +34 -0
  28. package/dist/context-engine/checkpoint.js +430 -0
  29. package/dist/context-engine/classify.d.ts +3 -0
  30. package/dist/context-engine/classify.js +60 -0
  31. package/dist/context-engine/db.d.ts +73 -0
  32. package/dist/context-engine/db.js +505 -0
  33. package/dist/context-engine/distiller.d.ts +30 -0
  34. package/dist/context-engine/distiller.js +67 -0
  35. package/dist/context-engine/engine-compiler.d.ts +23 -0
  36. package/dist/context-engine/engine-compiler.js +297 -0
  37. package/dist/context-engine/error-tracker.d.ts +21 -0
  38. package/dist/context-engine/error-tracker.js +74 -0
  39. package/dist/context-engine/event-lineage.d.ts +26 -0
  40. package/dist/context-engine/event-lineage.js +120 -0
  41. package/dist/context-engine/extraction.d.ts +26 -0
  42. package/dist/context-engine/extraction.js +83 -0
  43. package/dist/context-engine/index.d.ts +82 -0
  44. package/dist/context-engine/index.js +238 -0
  45. package/dist/context-engine/scoring.d.ts +13 -0
  46. package/dist/context-engine/scoring.js +47 -0
  47. package/dist/context-engine/state-snapshot.d.ts +8 -0
  48. package/dist/context-engine/state-snapshot.js +50 -0
  49. package/dist/context-engine/summarize.d.ts +6 -0
  50. package/dist/context-engine/summarize.js +32 -0
  51. package/dist/context-engine/telemetry.d.ts +25 -0
  52. package/dist/context-engine/telemetry.js +64 -0
  53. package/dist/context-engine/turn-digest.d.ts +50 -0
  54. package/dist/context-engine/turn-digest.js +250 -0
  55. package/dist/context-engine/turn-ledger.d.ts +18 -0
  56. package/dist/context-engine/turn-ledger.js +184 -0
  57. package/dist/context-engine/turn-recorder.d.ts +24 -0
  58. package/dist/context-engine/turn-recorder.js +88 -0
  59. package/dist/context-engine/types.d.ts +201 -0
  60. package/dist/context-engine/types.js +4 -0
  61. package/dist/context-pressure.d.ts +19 -0
  62. package/dist/context-pressure.js +36 -0
  63. package/dist/distillers/generic.d.ts +14 -0
  64. package/dist/distillers/generic.js +93 -0
  65. package/dist/distillers/git-diff.d.ts +8 -0
  66. package/dist/distillers/git-diff.js +119 -0
  67. package/dist/distillers/index.d.ts +2 -0
  68. package/dist/distillers/index.js +16 -0
  69. package/dist/distillers/npm-test.d.ts +8 -0
  70. package/dist/distillers/npm-test.js +50 -0
  71. package/dist/distillers/rg-results.d.ts +8 -0
  72. package/dist/distillers/rg-results.js +28 -0
  73. package/dist/distillers/tsc-errors.d.ts +8 -0
  74. package/dist/distillers/tsc-errors.js +52 -0
  75. package/dist/event-log.d.ts +56 -0
  76. package/dist/event-log.js +214 -0
  77. package/dist/llm.d.ts +29 -0
  78. package/dist/llm.js +155 -0
  79. package/dist/logger.d.ts +94 -0
  80. package/dist/logger.js +287 -0
  81. package/dist/main.d.ts +1 -0
  82. package/dist/main.js +54 -0
  83. package/dist/memory/confidence.d.ts +7 -0
  84. package/dist/memory/confidence.js +37 -0
  85. package/dist/memory/consolidation.d.ts +26 -0
  86. package/dist/memory/consolidation.js +166 -0
  87. package/dist/memory/db.d.ts +40 -0
  88. package/dist/memory/db.js +283 -0
  89. package/dist/memory/dedup.d.ts +6 -0
  90. package/dist/memory/dedup.js +50 -0
  91. package/dist/memory/embedder-factory.d.ts +3 -0
  92. package/dist/memory/embedder-factory.js +81 -0
  93. package/dist/memory/embeddings.d.ts +15 -0
  94. package/dist/memory/embeddings.js +67 -0
  95. package/dist/memory/index.d.ts +9 -0
  96. package/dist/memory/index.js +11 -0
  97. package/dist/memory/ollama-summarizer.d.ts +19 -0
  98. package/dist/memory/ollama-summarizer.js +72 -0
  99. package/dist/memory/openai-summarizer.d.ts +21 -0
  100. package/dist/memory/openai-summarizer.js +51 -0
  101. package/dist/memory/store.d.ts +61 -0
  102. package/dist/memory/store.js +502 -0
  103. package/dist/memory/summarizer-factory.d.ts +3 -0
  104. package/dist/memory/summarizer-factory.js +69 -0
  105. package/dist/memory/summarizer.d.ts +4 -0
  106. package/dist/memory/summarizer.js +112 -0
  107. package/dist/memory/types.d.ts +87 -0
  108. package/dist/memory/types.js +17 -0
  109. package/dist/model-context.d.ts +15 -0
  110. package/dist/model-context.js +212 -0
  111. package/dist/project-detector.d.ts +37 -0
  112. package/dist/project-detector.js +604 -0
  113. package/dist/render.d.ts +15 -0
  114. package/dist/render.js +46 -0
  115. package/dist/session.d.ts +118 -0
  116. package/dist/session.js +809 -0
  117. package/dist/skills/index.d.ts +69 -0
  118. package/dist/skills/index.js +885 -0
  119. package/dist/skills/types.d.ts +93 -0
  120. package/dist/skills/types.js +8 -0
  121. package/dist/slash-commands.d.ts +14 -0
  122. package/dist/slash-commands.js +301 -0
  123. package/dist/state-graph.d.ts +38 -0
  124. package/dist/state-graph.js +255 -0
  125. package/dist/status-bar.d.ts +54 -0
  126. package/dist/status-bar.js +184 -0
  127. package/dist/thinking-display.d.ts +21 -0
  128. package/dist/thinking-display.js +37 -0
  129. package/dist/tool-summary.d.ts +4 -0
  130. package/dist/tool-summary.js +67 -0
  131. package/dist/tools/index.d.ts +925 -0
  132. package/dist/tools/index.js +86 -0
  133. package/dist/tools/knowledge.d.ts +140 -0
  134. package/dist/tools/knowledge.js +260 -0
  135. package/dist/tools/memory.d.ts +39 -0
  136. package/dist/tools/memory.js +300 -0
  137. package/dist/tools/search-code.d.ts +134 -0
  138. package/dist/tools/search-code.js +390 -0
  139. package/dist/tools/system.d.ts +16 -0
  140. package/dist/tools/system.js +499 -0
  141. package/dist/tools/tool-def.d.ts +6 -0
  142. package/dist/tools/tool-def.js +3 -0
  143. package/dist/turn-control.d.ts +51 -0
  144. package/dist/turn-control.js +210 -0
  145. package/dist/turn.d.ts +20 -0
  146. package/dist/turn.js +624 -0
  147. package/dist/types.d.ts +233 -0
  148. package/dist/types.js +4 -0
  149. package/dist/ui/readline-ui.d.ts +2 -0
  150. package/dist/ui/readline-ui.js +176 -0
  151. package/dist/ui/tui/app.d.ts +13 -0
  152. package/dist/ui/tui/app.js +270 -0
  153. package/dist/ui/tui/busy-indicator.d.ts +2 -0
  154. package/dist/ui/tui/busy-indicator.js +13 -0
  155. package/dist/ui/tui/components/gutter-rule.d.ts +5 -0
  156. package/dist/ui/tui/components/gutter-rule.js +9 -0
  157. package/dist/ui/tui/components/inline-tool-row.d.ts +10 -0
  158. package/dist/ui/tui/components/inline-tool-row.js +8 -0
  159. package/dist/ui/tui/components/prompt-input.d.ts +20 -0
  160. package/dist/ui/tui/components/prompt-input.js +120 -0
  161. package/dist/ui/tui/components/system-line.d.ts +5 -0
  162. package/dist/ui/tui/components/system-line.js +6 -0
  163. package/dist/ui/tui/components/thinking-block.d.ts +11 -0
  164. package/dist/ui/tui/components/thinking-block.js +31 -0
  165. package/dist/ui/tui/components/toast-line.d.ts +4 -0
  166. package/dist/ui/tui/components/toast-line.js +8 -0
  167. package/dist/ui/tui/components/tool-result-line.d.ts +5 -0
  168. package/dist/ui/tui/components/tool-result-line.js +6 -0
  169. package/dist/ui/tui/components/turn-footer.d.ts +5 -0
  170. package/dist/ui/tui/components/turn-footer.js +7 -0
  171. package/dist/ui/tui/components/user-block.d.ts +6 -0
  172. package/dist/ui/tui/components/user-block.js +6 -0
  173. package/dist/ui/tui/logo-banner.d.ts +5 -0
  174. package/dist/ui/tui/logo-banner.js +8 -0
  175. package/dist/ui/tui/markdown-render.d.ts +16 -0
  176. package/dist/ui/tui/markdown-render.js +218 -0
  177. package/dist/ui/tui/palette.d.ts +12 -0
  178. package/dist/ui/tui/palette.js +13 -0
  179. package/dist/ui/tui/reasoning-summary.d.ts +12 -0
  180. package/dist/ui/tui/reasoning-summary.js +27 -0
  181. package/dist/ui/tui/reducer.d.ts +92 -0
  182. package/dist/ui/tui/reducer.js +260 -0
  183. package/dist/ui/tui/run.d.ts +3 -0
  184. package/dist/ui/tui/run.js +40 -0
  185. package/dist/ui/tui/sink.d.ts +4 -0
  186. package/dist/ui/tui/sink.js +89 -0
  187. package/dist/ui/tui/status-bar-view.d.ts +5 -0
  188. package/dist/ui/tui/status-bar-view.js +44 -0
  189. package/dist/ui/tui/terminal-height.d.ts +12 -0
  190. package/dist/ui/tui/terminal-height.js +20 -0
  191. package/dist/ui/tui/terminal-width.d.ts +2 -0
  192. package/dist/ui/tui/terminal-width.js +5 -0
  193. package/dist/ui/tui/tool-display.d.ts +23 -0
  194. package/dist/ui/tui/tool-display.js +217 -0
  195. package/dist/ui/tui/transcript-line.d.ts +12 -0
  196. package/dist/ui/tui/transcript-line.js +43 -0
  197. package/dist/ui/tui/transcript-replay.d.ts +12 -0
  198. package/dist/ui/tui/transcript-replay.js +117 -0
  199. package/dist/ui-events.d.ts +39 -0
  200. package/dist/ui-events.js +33 -0
  201. package/dist/ui.d.ts +77 -0
  202. package/dist/ui.js +179 -0
  203. package/package.json +73 -0
  204. package/praana.config.example.toml +231 -0
@@ -0,0 +1,272 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createDefaultDistillerRegistry } from "../distillers/index.js";
3
+ import { classifyContentType } from "./classify.js";
4
+ import { buildPendingSummary } from "./distiller.js";
5
+ import { evictStaleArtifacts, findArtifactByHash, getArtifactById, insertArtifact, insertDistillerStat, openContextEngineDb, touchArtifactAccess, updateArtifactSummary, } from "./db.js";
6
+ import { buildArtifactCard, estimateTokens, } from "./summarize.js";
7
+ function artifactIdFromHash(sha256) {
8
+ return `art_${sha256.slice(0, 12)}`;
9
+ }
10
+ function sha256(text) {
11
+ return createHash("sha256").update(text).digest("hex");
12
+ }
13
+ function sliceByLines(text, lineStart, lineEnd) {
14
+ const lines = text.split("\n");
15
+ const start = Math.max(1, lineStart ?? 1);
16
+ const end = Math.min(lines.length, lineEnd ?? lines.length);
17
+ if (start > end)
18
+ return "";
19
+ return lines.slice(start - 1, end).join("\n");
20
+ }
21
+ function extractJsonPath(text, jsonPath) {
22
+ const parsed = JSON.parse(text);
23
+ const parts = jsonPath.split(".").filter(Boolean);
24
+ let current = parsed;
25
+ for (const part of parts) {
26
+ if (current === null || current === undefined || typeof current !== "object") {
27
+ throw new Error(`Invalid jsonPath segment: ${part}`);
28
+ }
29
+ current = current[part];
30
+ }
31
+ if (typeof current === "string")
32
+ return current;
33
+ return JSON.stringify(current, null, 2);
34
+ }
35
+ function savingsPct(inputTokens, outputTokens) {
36
+ if (inputTokens <= 0)
37
+ return 0;
38
+ return Math.max(0, (1 - outputTokens / inputTokens) * 100);
39
+ }
40
+ function inferContentTypeFromTool(sourceTool, command) {
41
+ if (!command)
42
+ return null;
43
+ const normalized = command.trim();
44
+ if (!normalized)
45
+ return null;
46
+ if (sourceTool === "shell" &&
47
+ /(^|\s)(rg|grep|ag|ack)(\s|$)/.test(normalized)) {
48
+ return "search_results";
49
+ }
50
+ if (sourceTool === "shell" && /(^|\s)git\s+(diff|show)(\s|$)/.test(normalized)) {
51
+ return "diff";
52
+ }
53
+ if (sourceTool === "shell" &&
54
+ /(^|\s)(npm|pnpm|yarn|bun)\s+(run\s+)?(test|vitest|jest)(\s|$|:)/.test(normalized)) {
55
+ return "test_output";
56
+ }
57
+ if (sourceTool === "shell" &&
58
+ /(^|\s)(tsc|vue-tsc|npm\s+run\s+(build|typecheck)|pnpm\s+(build|typecheck))(\s|$)/.test(normalized)) {
59
+ return "build_output";
60
+ }
61
+ return null;
62
+ }
63
+ export class ArtifactStore {
64
+ db;
65
+ sessionId;
66
+ config;
67
+ distillers;
68
+ fileReadIndex = new Map();
69
+ pendingBackfills = [];
70
+ constructor(db, sessionId, config, distillers) {
71
+ this.db = db;
72
+ this.sessionId = sessionId;
73
+ this.config = config;
74
+ this.distillers = distillers;
75
+ }
76
+ static open(dbPath, sessionId, config, distillers = createDefaultDistillerRegistry()) {
77
+ const db = openContextEngineDb(dbPath);
78
+ return new ArtifactStore(db, sessionId, config, distillers);
79
+ }
80
+ close() {
81
+ this.db.close();
82
+ }
83
+ getDb() {
84
+ return this.db;
85
+ }
86
+ runEviction(currentTurn) {
87
+ return evictStaleArtifacts(this.db, currentTurn, this.config.artifact_ttl_turns);
88
+ }
89
+ async flushDeferredDistillation() {
90
+ const jobs = this.pendingBackfills.splice(0);
91
+ for (const job of jobs) {
92
+ let result;
93
+ try {
94
+ result = await job.backfill();
95
+ }
96
+ catch (err) {
97
+ result = {
98
+ summary: `[compression failed: ${err.message ?? "unknown error"}]\n${buildPendingSummary()}`,
99
+ distillerName: "failed-deferred",
100
+ execTimeMs: 0,
101
+ deferred: true,
102
+ };
103
+ }
104
+ updateArtifactSummary(this.db, job.artifactId, result.summary);
105
+ this.recordDistillerStat({
106
+ sourceTool: job.sourceTool,
107
+ contentType: job.contentType,
108
+ distiller: result.distillerName,
109
+ inputTokens: job.inputTokens,
110
+ outputTokens: estimateTokens(result.summary),
111
+ execTimeMs: Math.round(result.execTimeMs),
112
+ turn: job.turn,
113
+ });
114
+ }
115
+ return jobs.length;
116
+ }
117
+ ingestToolResult(input) {
118
+ const contentType = input.contentType ??
119
+ inferContentTypeFromTool(input.sourceTool, input.command) ??
120
+ classifyContentType(input.rawText);
121
+ const rawTokens = estimateTokens(input.rawText);
122
+ const inlineThreshold = this.config.artifact_inline_threshold;
123
+ if (contentType === "error" || rawTokens <= inlineThreshold) {
124
+ return { promptText: input.rawText, inlined: true };
125
+ }
126
+ const fileKey = this.fileReadKey(input.sourceTool, input.command);
127
+ if (fileKey) {
128
+ const existingId = this.fileReadIndex.get(fileKey);
129
+ if (existingId) {
130
+ const existing = getArtifactById(this.db, existingId);
131
+ if (existing) {
132
+ touchArtifactAccess(this.db, existing.id, input.createdTurn);
133
+ return {
134
+ promptText: buildArtifactCard(existing.id, existing.sourceTool, existing.command, existing.rawTokens, existing.summary),
135
+ artifactId: existing.id,
136
+ inlined: false,
137
+ };
138
+ }
139
+ }
140
+ }
141
+ const hash = sha256(input.rawText);
142
+ const deduped = findArtifactByHash(this.db, hash);
143
+ if (deduped) {
144
+ touchArtifactAccess(this.db, deduped.id, input.createdTurn);
145
+ if (fileKey)
146
+ this.fileReadIndex.set(fileKey, deduped.id);
147
+ return {
148
+ promptText: buildArtifactCard(deduped.id, deduped.sourceTool, deduped.command ?? input.command, deduped.rawTokens, deduped.summary),
149
+ artifactId: deduped.id,
150
+ inlined: false,
151
+ };
152
+ }
153
+ const intensity = this.distillers.selectIntensity(rawTokens, this.config.distiller.default_intensity);
154
+ const distilled = this.distillers.distillForIngestion(input.rawText, contentType, intensity);
155
+ let summary;
156
+ if ("backfill" in distilled) {
157
+ const deferred = distilled;
158
+ summary = deferred.pendingSummary;
159
+ const artifactId = artifactIdFromHash(hash);
160
+ this.pendingBackfills.push({
161
+ artifactId,
162
+ backfill: deferred.backfill,
163
+ sourceTool: input.sourceTool,
164
+ contentType,
165
+ inputTokens: rawTokens,
166
+ turn: input.createdTurn,
167
+ });
168
+ }
169
+ else {
170
+ const sync = distilled;
171
+ summary = sync.summary;
172
+ this.recordDistillerStat({
173
+ sourceTool: input.sourceTool,
174
+ contentType,
175
+ distiller: sync.distillerName,
176
+ inputTokens: rawTokens,
177
+ outputTokens: estimateTokens(sync.summary),
178
+ execTimeMs: Math.round(sync.execTimeMs),
179
+ turn: input.createdTurn,
180
+ });
181
+ }
182
+ const artifact = {
183
+ id: artifactIdFromHash(hash),
184
+ sha256: hash,
185
+ sessionId: this.sessionId,
186
+ sourceTool: input.sourceTool,
187
+ command: input.command,
188
+ createdTurn: input.createdTurn,
189
+ rawTokens,
190
+ rawText: input.rawText,
191
+ summary,
192
+ contentType,
193
+ lastAccessedTurn: input.createdTurn,
194
+ accessCount: 0,
195
+ };
196
+ insertArtifact(this.db, artifact);
197
+ if (fileKey)
198
+ this.fileReadIndex.set(fileKey, artifact.id);
199
+ return {
200
+ promptText: buildArtifactCard(artifact.id, artifact.sourceTool, artifact.command, artifact.rawTokens, artifact.summary),
201
+ artifactId: artifact.id,
202
+ inlined: false,
203
+ };
204
+ }
205
+ retrieve(id, currentTurn, options) {
206
+ const artifact = getArtifactById(this.db, id);
207
+ if (!artifact) {
208
+ return { ok: false, error: `Artifact ${id} not found` };
209
+ }
210
+ if (artifact.sessionId !== this.sessionId) {
211
+ return { ok: false, error: `Artifact ${id} belongs to another session` };
212
+ }
213
+ touchArtifactAccess(this.db, id, currentTurn);
214
+ let content = artifact.rawText;
215
+ try {
216
+ if (options?.jsonPath) {
217
+ content = extractJsonPath(content, options.jsonPath);
218
+ }
219
+ if (options?.lineStart !== undefined || options?.lineEnd !== undefined) {
220
+ content = sliceByLines(content, options.lineStart, options.lineEnd);
221
+ }
222
+ if (options?.grep) {
223
+ const re = new RegExp(options.grep, "m");
224
+ const matched = content.split("\n").filter((line) => re.test(line));
225
+ content = matched.join("\n");
226
+ }
227
+ }
228
+ catch (err) {
229
+ return {
230
+ ok: false,
231
+ error: err.message ?? "Failed to slice artifact content",
232
+ };
233
+ }
234
+ return { ok: true, content };
235
+ }
236
+ getArtifact(id) {
237
+ const artifact = getArtifactById(this.db, id);
238
+ if (!artifact || artifact.sessionId !== this.sessionId)
239
+ return null;
240
+ return artifact;
241
+ }
242
+ getSessionId() {
243
+ return this.sessionId;
244
+ }
245
+ countArtifacts() {
246
+ const row = this.db
247
+ .prepare("SELECT COUNT(*) AS count FROM context_artifacts WHERE session_id = ?")
248
+ .get(this.sessionId);
249
+ return row.count;
250
+ }
251
+ touchAccess(id, currentTurn) {
252
+ touchArtifactAccess(this.db, id, currentTurn);
253
+ }
254
+ recordDistillerStat(input) {
255
+ insertDistillerStat(this.db, {
256
+ sessionId: this.sessionId,
257
+ tool: input.sourceTool,
258
+ contentType: input.contentType,
259
+ distiller: input.distiller,
260
+ inputTokens: input.inputTokens,
261
+ outputTokens: input.outputTokens,
262
+ savingsPct: savingsPct(input.inputTokens, input.outputTokens),
263
+ execTimeMs: input.execTimeMs,
264
+ turn: input.turn,
265
+ });
266
+ }
267
+ fileReadKey(sourceTool, command) {
268
+ if (sourceTool !== "read_file" || !command)
269
+ return null;
270
+ return command;
271
+ }
272
+ }
@@ -0,0 +1,3 @@
1
+ export declare function tokenize(text: string): string[];
2
+ export declare function bm25Score(queryTokens: string[], docTokens: string[], avgDocLen: number, totalDocs: number, docFreq: Map<string, number>): number;
3
+ export declare function bm25Relevance(query: string, content: string): number;
@@ -0,0 +1,32 @@
1
+ export function tokenize(text) {
2
+ return text.toLowerCase().match(/[a-z0-9_./-]+/g) ?? [];
3
+ }
4
+ export function bm25Score(queryTokens, docTokens, avgDocLen, totalDocs, docFreq) {
5
+ const k1 = 1.5;
6
+ const b = 0.75;
7
+ const docLen = docTokens.length;
8
+ const tf = new Map();
9
+ for (const t of docTokens)
10
+ tf.set(t, (tf.get(t) ?? 0) + 1);
11
+ let score = 0;
12
+ for (const qt of queryTokens) {
13
+ const freq = tf.get(qt) ?? 0;
14
+ if (freq === 0)
15
+ continue;
16
+ const df = docFreq.get(qt) ?? 1;
17
+ const idf = Math.log(1 + (totalDocs - df + 0.5) / (df + 0.5));
18
+ const numerator = freq * (k1 + 1);
19
+ const denominator = freq + k1 * (1 - b + b * (docLen / avgDocLen));
20
+ score += idf * (numerator / denominator);
21
+ }
22
+ return score;
23
+ }
24
+ export function bm25Relevance(query, content) {
25
+ const queryTokens = tokenize(query);
26
+ if (queryTokens.length === 0)
27
+ return 0;
28
+ const docTokens = tokenize(content);
29
+ if (docTokens.length === 0)
30
+ return 0;
31
+ return bm25Score(queryTokens, docTokens, docTokens.length, 1, new Map());
32
+ }
@@ -0,0 +1,34 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { ActivityEntry, CheckpointDraft, CheckpointState, SessionCheckpoint, TurnDigest } from "./types.js";
3
+ type LegacyCheckpointState = CheckpointState & {
4
+ plan?: string;
5
+ volatile?: string;
6
+ };
7
+ export declare function createEmptyCheckpointState(): CheckpointState;
8
+ export declare function normalizeCheckpointState(raw: Partial<LegacyCheckpointState>): CheckpointState;
9
+ export declare function createEmptyCheckpoint(): SessionCheckpoint;
10
+ export declare function reconcileCheckpoint(state: CheckpointState, digest: TurnDigest, draft: CheckpointDraft, turn: number): CheckpointState;
11
+ export declare function replayCheckpointFromDigests(digests: TurnDigest[], activityEntries: ActivityEntry[]): CheckpointState;
12
+ export declare function renderCheckpoint(checkpoint: SessionCheckpoint): string;
13
+ export declare function renderContextSummary(checkpoint: SessionCheckpoint, stats?: {
14
+ artifactCount?: number;
15
+ }): string;
16
+ export declare function checkpointTokenEstimate(checkpoint: SessionCheckpoint): {
17
+ text: string;
18
+ tokens: number;
19
+ };
20
+ export declare class CheckpointStore {
21
+ private readonly db;
22
+ private readonly sessionId;
23
+ private checkpoint;
24
+ private constructor();
25
+ static open(db: Database.Database, sessionId: string): CheckpointStore;
26
+ reconcile(digest: TurnDigest, draft: CheckpointDraft, turn: number): void;
27
+ persist(): void;
28
+ getCheckpoint(): SessionCheckpoint;
29
+ render(): string;
30
+ renderContextSummary(stats?: {
31
+ artifactCount?: number;
32
+ }): string;
33
+ }
34
+ export {};