ds4-context-core 0.1.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 (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/dist/artifacts/artifact-manager.d.ts +58 -0
  4. package/dist/artifacts/artifact-manager.d.ts.map +1 -0
  5. package/dist/artifacts/artifact-manager.js +445 -0
  6. package/dist/artifacts/artifact-manager.js.map +1 -0
  7. package/dist/artifacts/artifact-store.d.ts +33 -0
  8. package/dist/artifacts/artifact-store.d.ts.map +1 -0
  9. package/dist/artifacts/artifact-store.js +116 -0
  10. package/dist/artifacts/artifact-store.js.map +1 -0
  11. package/dist/compaction/compaction-record.d.ts +74 -0
  12. package/dist/compaction/compaction-record.d.ts.map +1 -0
  13. package/dist/compaction/compaction-record.js +113 -0
  14. package/dist/compaction/compaction-record.js.map +1 -0
  15. package/dist/compaction/summary-contract.d.ts +68 -0
  16. package/dist/compaction/summary-contract.d.ts.map +1 -0
  17. package/dist/compaction/summary-contract.js +315 -0
  18. package/dist/compaction/summary-contract.js.map +1 -0
  19. package/dist/compaction/summary-graph.d.ts +48 -0
  20. package/dist/compaction/summary-graph.d.ts.map +1 -0
  21. package/dist/compaction/summary-graph.js +123 -0
  22. package/dist/compaction/summary-graph.js.map +1 -0
  23. package/dist/config/config-loader.d.ts +18 -0
  24. package/dist/config/config-loader.d.ts.map +1 -0
  25. package/dist/config/config-loader.js +305 -0
  26. package/dist/config/config-loader.js.map +1 -0
  27. package/dist/config/config.d.ts +113 -0
  28. package/dist/config/config.d.ts.map +1 -0
  29. package/dist/config/config.js +89 -0
  30. package/dist/config/config.js.map +1 -0
  31. package/dist/continuation/native-continuation.d.ts +107 -0
  32. package/dist/continuation/native-continuation.d.ts.map +1 -0
  33. package/dist/continuation/native-continuation.js +374 -0
  34. package/dist/continuation/native-continuation.js.map +1 -0
  35. package/dist/core/budget-manager.d.ts +26 -0
  36. package/dist/core/budget-manager.d.ts.map +1 -0
  37. package/dist/core/budget-manager.js +42 -0
  38. package/dist/core/budget-manager.js.map +1 -0
  39. package/dist/core/canonical-message.d.ts +69 -0
  40. package/dist/core/canonical-message.d.ts.map +1 -0
  41. package/dist/core/canonical-message.js +2 -0
  42. package/dist/core/canonical-message.js.map +1 -0
  43. package/dist/core/model-awareness.d.ts +59 -0
  44. package/dist/core/model-awareness.d.ts.map +1 -0
  45. package/dist/core/model-awareness.js +177 -0
  46. package/dist/core/model-awareness.js.map +1 -0
  47. package/dist/core/model-profile.d.ts +27 -0
  48. package/dist/core/model-profile.d.ts.map +1 -0
  49. package/dist/core/model-profile.js +29 -0
  50. package/dist/core/model-profile.js.map +1 -0
  51. package/dist/core/token-estimator.d.ts +4 -0
  52. package/dist/core/token-estimator.d.ts.map +1 -0
  53. package/dist/core/token-estimator.js +64 -0
  54. package/dist/core/token-estimator.js.map +1 -0
  55. package/dist/index.d.ts +37 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +37 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/manifest/context-manifest.d.ts +163 -0
  60. package/dist/manifest/context-manifest.d.ts.map +1 -0
  61. package/dist/manifest/context-manifest.js +2 -0
  62. package/dist/manifest/context-manifest.js.map +1 -0
  63. package/dist/manifest/observer.d.ts +63 -0
  64. package/dist/manifest/observer.d.ts.map +1 -0
  65. package/dist/manifest/observer.js +150 -0
  66. package/dist/manifest/observer.js.map +1 -0
  67. package/dist/memory/memory-manager.d.ts +112 -0
  68. package/dist/memory/memory-manager.d.ts.map +1 -0
  69. package/dist/memory/memory-manager.js +499 -0
  70. package/dist/memory/memory-manager.js.map +1 -0
  71. package/dist/memory/memory-types.d.ts +126 -0
  72. package/dist/memory/memory-types.d.ts.map +1 -0
  73. package/dist/memory/memory-types.js +73 -0
  74. package/dist/memory/memory-types.js.map +1 -0
  75. package/dist/persistence/migrations.d.ts +17 -0
  76. package/dist/persistence/migrations.d.ts.map +1 -0
  77. package/dist/persistence/migrations.js +588 -0
  78. package/dist/persistence/migrations.js.map +1 -0
  79. package/dist/persistence/repositories/artifact-repository.d.ts +50 -0
  80. package/dist/persistence/repositories/artifact-repository.d.ts.map +1 -0
  81. package/dist/persistence/repositories/artifact-repository.js +186 -0
  82. package/dist/persistence/repositories/artifact-repository.js.map +1 -0
  83. package/dist/persistence/repositories/context-manifest-repository.d.ts +19 -0
  84. package/dist/persistence/repositories/context-manifest-repository.d.ts.map +1 -0
  85. package/dist/persistence/repositories/context-manifest-repository.js +144 -0
  86. package/dist/persistence/repositories/context-manifest-repository.js.map +1 -0
  87. package/dist/persistence/repositories/memory-repository.d.ts +33 -0
  88. package/dist/persistence/repositories/memory-repository.d.ts.map +1 -0
  89. package/dist/persistence/repositories/memory-repository.js +429 -0
  90. package/dist/persistence/repositories/memory-repository.js.map +1 -0
  91. package/dist/persistence/repositories/project-knowledge-repository.d.ts +65 -0
  92. package/dist/persistence/repositories/project-knowledge-repository.d.ts.map +1 -0
  93. package/dist/persistence/repositories/project-knowledge-repository.js +248 -0
  94. package/dist/persistence/repositories/project-knowledge-repository.js.map +1 -0
  95. package/dist/persistence/repositories/session-index-repository.d.ts +81 -0
  96. package/dist/persistence/repositories/session-index-repository.d.ts.map +1 -0
  97. package/dist/persistence/repositories/session-index-repository.js +220 -0
  98. package/dist/persistence/repositories/session-index-repository.js.map +1 -0
  99. package/dist/persistence/repositories/summary-repository.d.ts +16 -0
  100. package/dist/persistence/repositories/summary-repository.d.ts.map +1 -0
  101. package/dist/persistence/repositories/summary-repository.js +242 -0
  102. package/dist/persistence/repositories/summary-repository.js.map +1 -0
  103. package/dist/persistence/sqlite.d.ts +45 -0
  104. package/dist/persistence/sqlite.d.ts.map +1 -0
  105. package/dist/persistence/sqlite.js +137 -0
  106. package/dist/persistence/sqlite.js.map +1 -0
  107. package/dist/planner/atomic-groups.d.ts +15 -0
  108. package/dist/planner/atomic-groups.d.ts.map +1 -0
  109. package/dist/planner/atomic-groups.js +177 -0
  110. package/dist/planner/atomic-groups.js.map +1 -0
  111. package/dist/planner/context-planner.d.ts +49 -0
  112. package/dist/planner/context-planner.d.ts.map +1 -0
  113. package/dist/planner/context-planner.js +367 -0
  114. package/dist/planner/context-planner.js.map +1 -0
  115. package/dist/privacy/privacy-policy.d.ts +58 -0
  116. package/dist/privacy/privacy-policy.d.ts.map +1 -0
  117. package/dist/privacy/privacy-policy.js +412 -0
  118. package/dist/privacy/privacy-policy.js.map +1 -0
  119. package/dist/project/file-indexer.d.ts +32 -0
  120. package/dist/project/file-indexer.d.ts.map +1 -0
  121. package/dist/project/file-indexer.js +374 -0
  122. package/dist/project/file-indexer.js.map +1 -0
  123. package/dist/project/git-state.d.ts +12 -0
  124. package/dist/project/git-state.d.ts.map +1 -0
  125. package/dist/project/git-state.js +109 -0
  126. package/dist/project/git-state.js.map +1 -0
  127. package/dist/project/project-knowledge.d.ts +63 -0
  128. package/dist/project/project-knowledge.d.ts.map +1 -0
  129. package/dist/project/project-knowledge.js +332 -0
  130. package/dist/project/project-knowledge.js.map +1 -0
  131. package/dist/retrieval/retrieval-engine.d.ts +55 -0
  132. package/dist/retrieval/retrieval-engine.d.ts.map +1 -0
  133. package/dist/retrieval/retrieval-engine.js +290 -0
  134. package/dist/retrieval/retrieval-engine.js.map +1 -0
  135. package/dist/retrieval/task-descriptor.d.ts +17 -0
  136. package/dist/retrieval/task-descriptor.d.ts.map +1 -0
  137. package/dist/retrieval/task-descriptor.js +107 -0
  138. package/dist/retrieval/task-descriptor.js.map +1 -0
  139. package/dist/shared/hash.d.ts +2 -0
  140. package/dist/shared/hash.d.ts.map +1 -0
  141. package/dist/shared/hash.js +5 -0
  142. package/dist/shared/hash.js.map +1 -0
  143. package/dist/shared/logging.d.ts +27 -0
  144. package/dist/shared/logging.d.ts.map +1 -0
  145. package/dist/shared/logging.js +83 -0
  146. package/dist/shared/logging.js.map +1 -0
  147. package/dist/shared/stable-json.d.ts +2 -0
  148. package/dist/shared/stable-json.d.ts.map +1 -0
  149. package/dist/shared/stable-json.js +38 -0
  150. package/dist/shared/stable-json.js.map +1 -0
  151. package/package.json +56 -0
@@ -0,0 +1,242 @@
1
+ import { parseDs4CompactionDetails, } from "../../compaction/compaction-record.js";
2
+ const SELECT_SUMMARY = `
3
+ SELECT summary_id, session_id, summary_kind, content, source_hash, created_at,
4
+ validation_status, provider, model, first_kept_entry_id, tokens_before,
5
+ compaction_reason, lifecycle_status, pi_compaction_entry_id, metadata_json,
6
+ graph_level
7
+ FROM summaries
8
+ `;
9
+ function parseKind(value) {
10
+ if (!["segment", "aggregate", "task-state", "branch"].includes(value)) {
11
+ throw new Error(`Unsupported summary kind in database: ${value}`);
12
+ }
13
+ return value;
14
+ }
15
+ function rowToRecord(database, row) {
16
+ const parsed = JSON.parse(row.metadata_json);
17
+ const metadata = parseDs4CompactionDetails({
18
+ readFiles: [],
19
+ modifiedFiles: [],
20
+ ds4ContextEngine: parsed,
21
+ })?.ds4ContextEngine;
22
+ if (!metadata)
23
+ throw new Error(`Summary ${row.summary_id} contains invalid DS4 metadata`);
24
+ if (metadata.summaryId !== row.summary_id
25
+ || metadata.summaryKind !== row.summary_kind
26
+ || metadata.sourceHash !== row.source_hash
27
+ || metadata.graphLevel !== row.graph_level) {
28
+ throw new Error(`Summary ${row.summary_id} metadata does not match graph columns`);
29
+ }
30
+ const sourceRows = database.prepare(`
31
+ SELECT entry.entry_id
32
+ FROM summary_sources AS source
33
+ JOIN entries AS entry ON entry.entry_key = source.entry_key
34
+ WHERE source.summary_id = ?
35
+ ORDER BY entry.created_at, entry.entry_id
36
+ `).all(row.summary_id);
37
+ const childRows = database.prepare(`
38
+ SELECT child_summary_id
39
+ FROM summary_edges
40
+ WHERE parent_summary_id = ?
41
+ ORDER BY child_order, child_summary_id
42
+ `).all(row.summary_id);
43
+ const sourceEntryIds = sourceRows.map((source) => source.entry_id);
44
+ const childSummaryIds = childRows.map((child) => child.child_summary_id);
45
+ const sorted = (values) => [...values].sort((left, right) => left.localeCompare(right));
46
+ if (JSON.stringify(sorted(sourceEntryIds)) !== JSON.stringify(sorted(metadata.sourceEntryIds))) {
47
+ throw new Error(`Summary ${row.summary_id} source links do not match metadata`);
48
+ }
49
+ if (JSON.stringify(childSummaryIds) !== JSON.stringify(metadata.childSummaryIds)) {
50
+ throw new Error(`Summary ${row.summary_id} child order does not match metadata`);
51
+ }
52
+ return {
53
+ id: row.summary_id,
54
+ sessionId: row.session_id,
55
+ kind: parseKind(row.summary_kind),
56
+ content: row.content,
57
+ sourceHash: row.source_hash,
58
+ sourceEntryIds,
59
+ childSummaryIds,
60
+ graphLevel: row.graph_level,
61
+ createdAt: row.created_at,
62
+ validationStatus: metadata.validationStatus,
63
+ ...(row.provider ? { provider: row.provider } : {}),
64
+ ...(row.model ? { model: row.model } : {}),
65
+ firstKeptEntryId: row.first_kept_entry_id ?? metadata.firstKeptEntryId,
66
+ tokensBefore: row.tokens_before ?? metadata.tokensBefore,
67
+ reason: metadata.reason,
68
+ lifecycleStatus: row.lifecycle_status,
69
+ ...(row.pi_compaction_entry_id ? { piCompactionEntryId: row.pi_compaction_entry_id } : {}),
70
+ metadata,
71
+ };
72
+ }
73
+ function assertImmutable(database, record) {
74
+ const existing = database.prepare(`
75
+ SELECT session_id, summary_kind, content, source_hash, created_at, graph_level
76
+ FROM summaries WHERE summary_id = ?
77
+ `).get(record.id);
78
+ if (!existing)
79
+ return;
80
+ if (existing.session_id !== record.sessionId
81
+ || existing.summary_kind !== record.kind
82
+ || existing.content !== record.content
83
+ || existing.source_hash !== record.sourceHash
84
+ || existing.created_at !== record.createdAt
85
+ || existing.graph_level !== record.graphLevel) {
86
+ throw new Error(`Summary node is immutable and conflicts with existing node: ${record.id}`);
87
+ }
88
+ }
89
+ export class SummaryRepository {
90
+ database;
91
+ constructor(database) {
92
+ this.database = database;
93
+ }
94
+ save(record) {
95
+ this.saveGraph([record]);
96
+ }
97
+ saveGraph(records) {
98
+ if (records.length === 0)
99
+ return;
100
+ const ids = new Set();
101
+ for (const record of records) {
102
+ if (ids.has(record.id))
103
+ throw new Error(`Duplicate summary node in graph batch: ${record.id}`);
104
+ ids.add(record.id);
105
+ }
106
+ this.database.exec("BEGIN IMMEDIATE");
107
+ try {
108
+ for (const record of records) {
109
+ assertImmutable(this.database, record);
110
+ this.database.prepare(`
111
+ INSERT INTO summaries(
112
+ summary_id, session_id, summary_kind, content, source_hash, created_at,
113
+ validation_status, provider, model, first_kept_entry_id, tokens_before,
114
+ compaction_reason, lifecycle_status, pi_compaction_entry_id, metadata_json,
115
+ graph_level
116
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
117
+ ON CONFLICT(summary_id) DO UPDATE SET
118
+ validation_status = excluded.validation_status,
119
+ provider = excluded.provider,
120
+ model = excluded.model,
121
+ first_kept_entry_id = excluded.first_kept_entry_id,
122
+ tokens_before = excluded.tokens_before,
123
+ compaction_reason = excluded.compaction_reason,
124
+ lifecycle_status = CASE
125
+ WHEN excluded.lifecycle_status = 'committed' THEN 'committed'
126
+ WHEN summaries.lifecycle_status = 'committed' THEN 'committed'
127
+ ELSE excluded.lifecycle_status
128
+ END,
129
+ pi_compaction_entry_id = COALESCE(excluded.pi_compaction_entry_id, summaries.pi_compaction_entry_id),
130
+ metadata_json = excluded.metadata_json,
131
+ graph_level = excluded.graph_level
132
+ `).run(record.id, record.sessionId, record.kind, record.content, record.sourceHash, record.createdAt, record.validationStatus, record.provider ?? null, record.model ?? null, record.firstKeptEntryId, record.tokensBefore, record.reason, record.lifecycleStatus, record.piCompactionEntryId ?? null, JSON.stringify(record.metadata), record.graphLevel);
133
+ }
134
+ for (const record of records) {
135
+ this.database.prepare("DELETE FROM summary_sources WHERE summary_id = ?").run(record.id);
136
+ this.database.prepare("DELETE FROM summary_edges WHERE parent_summary_id = ?").run(record.id);
137
+ }
138
+ const insertSource = this.database.prepare(`
139
+ INSERT INTO summary_sources(summary_id, entry_key)
140
+ SELECT ?, entry_key FROM entries WHERE session_id = ? AND entry_id = ?
141
+ `);
142
+ const childLookup = this.database.prepare(`
143
+ SELECT session_id, graph_level FROM summaries WHERE summary_id = ?
144
+ `);
145
+ const insertEdge = this.database.prepare(`
146
+ INSERT INTO summary_edges(parent_summary_id, child_summary_id, child_order)
147
+ VALUES (?, ?, ?)
148
+ `);
149
+ for (const record of records) {
150
+ for (const entryId of new Set(record.sourceEntryIds)) {
151
+ const result = insertSource.run(record.id, record.sessionId, entryId);
152
+ if (result.changes !== 1) {
153
+ throw new Error(`Summary source entry is not indexed: ${record.sessionId}:${entryId}`);
154
+ }
155
+ }
156
+ const children = [...new Set(record.childSummaryIds)];
157
+ for (const [order, childId] of children.entries()) {
158
+ if (childId === record.id)
159
+ throw new Error(`Summary node cannot reference itself: ${record.id}`);
160
+ const child = childLookup.get(childId);
161
+ if (!child || child.session_id !== record.sessionId) {
162
+ throw new Error(`Summary child is missing from the same session: ${record.sessionId}:${childId}`);
163
+ }
164
+ if (child.graph_level >= record.graphLevel) {
165
+ throw new Error(`Summary child level must be lower than parent: ${childId} -> ${record.id}`);
166
+ }
167
+ const cycle = this.database.prepare(`
168
+ WITH RECURSIVE descendants(summary_id) AS (
169
+ SELECT child_summary_id FROM summary_edges WHERE parent_summary_id = ?
170
+ UNION
171
+ SELECT edge.child_summary_id
172
+ FROM summary_edges AS edge
173
+ JOIN descendants AS child ON edge.parent_summary_id = child.summary_id
174
+ )
175
+ SELECT 1 AS found FROM descendants WHERE summary_id = ? LIMIT 1
176
+ `).get(childId, record.id);
177
+ if (cycle)
178
+ throw new Error(`Summary edge would create a cycle: ${record.id} -> ${childId}`);
179
+ insertEdge.run(record.id, childId, order);
180
+ }
181
+ }
182
+ this.database.exec("COMMIT");
183
+ }
184
+ catch (error) {
185
+ if (this.database.isTransaction)
186
+ this.database.exec("ROLLBACK");
187
+ throw error;
188
+ }
189
+ }
190
+ markCommitted(summaryId, piCompactionEntryId) {
191
+ const result = this.database.prepare(`
192
+ UPDATE summaries
193
+ SET lifecycle_status = 'committed',
194
+ pi_compaction_entry_id = COALESCE(?, pi_compaction_entry_id)
195
+ WHERE summary_id = ?
196
+ `).run(piCompactionEntryId ?? null, summaryId);
197
+ return result.changes === 1;
198
+ }
199
+ markFailed(summaryId) {
200
+ const result = this.database.prepare(`
201
+ UPDATE summaries SET lifecycle_status = 'failed'
202
+ WHERE summary_id = ? AND lifecycle_status = 'prepared'
203
+ `).run(summaryId);
204
+ return result.changes === 1;
205
+ }
206
+ markFailedMany(summaryIds) {
207
+ let changed = 0;
208
+ for (const summaryId of new Set(summaryIds))
209
+ changed += this.markFailed(summaryId) ? 1 : 0;
210
+ return changed;
211
+ }
212
+ failPreparedForSession(sessionId) {
213
+ const result = this.database.prepare(`
214
+ UPDATE summaries SET lifecycle_status = 'failed'
215
+ WHERE session_id = ? AND lifecycle_status = 'prepared'
216
+ `).run(sessionId);
217
+ return Number(result.changes);
218
+ }
219
+ getById(summaryId) {
220
+ const row = this.database.prepare(`${SELECT_SUMMARY} WHERE summary_id = ? AND metadata_json <> '{}'`)
221
+ .get(summaryId);
222
+ return row ? rowToRecord(this.database, row) : undefined;
223
+ }
224
+ getLatest(sessionId) {
225
+ const row = this.database.prepare(`
226
+ ${SELECT_SUMMARY}
227
+ WHERE session_id = ? AND metadata_json <> '{}'
228
+ ORDER BY created_at DESC, graph_level DESC, rowid DESC
229
+ LIMIT 1
230
+ `).get(sessionId);
231
+ return row ? rowToRecord(this.database, row) : undefined;
232
+ }
233
+ listBySession(sessionId) {
234
+ const rows = this.database.prepare(`
235
+ ${SELECT_SUMMARY}
236
+ WHERE session_id = ? AND metadata_json <> '{}'
237
+ ORDER BY created_at, graph_level, rowid
238
+ `).all(sessionId);
239
+ return rows.map((row) => rowToRecord(this.database, row));
240
+ }
241
+ }
242
+ //# sourceMappingURL=summary-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary-repository.js","sourceRoot":"","sources":["../../../src/persistence/repositories/summary-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { Logger } from "../shared/logging.ts";
2
+ import { type AppliedMigration } from "./migrations.ts";
3
+ import { ArtifactRepository } from "./repositories/artifact-repository.ts";
4
+ import { ContextManifestRepository } from "./repositories/context-manifest-repository.ts";
5
+ import { MemoryRepository } from "./repositories/memory-repository.ts";
6
+ import { ProjectKnowledgeRepository } from "./repositories/project-knowledge-repository.ts";
7
+ import { SessionIndexRepository, type SessionIdentity, type SessionIndexStats } from "./repositories/session-index-repository.ts";
8
+ import { SummaryRepository } from "./repositories/summary-repository.ts";
9
+ export type SessionRecord = SessionIdentity;
10
+ export type { SessionIndexStats } from "./repositories/session-index-repository.ts";
11
+ export interface DatabaseHealth {
12
+ ok: boolean;
13
+ quickCheck: string;
14
+ journalMode: string;
15
+ foreignKeys: boolean;
16
+ schemaVersion: number;
17
+ appliedMigrations: number;
18
+ }
19
+ export interface OpenDatabaseOptions {
20
+ logger?: Logger;
21
+ now?: number;
22
+ }
23
+ export declare class ContextDatabase {
24
+ readonly path: string;
25
+ private readonly database;
26
+ private readonly logger;
27
+ readonly schemaVersion: number;
28
+ readonly migrations: readonly AppliedMigration[];
29
+ readonly sessionIndex: SessionIndexRepository;
30
+ readonly artifacts: ArtifactRepository;
31
+ readonly manifests: ContextManifestRepository;
32
+ readonly memory: MemoryRepository;
33
+ readonly summaries: SummaryRepository;
34
+ readonly projectKnowledge: ProjectKnowledgeRepository;
35
+ private closed;
36
+ private constructor();
37
+ static open(path: string, options?: OpenDatabaseOptions): ContextDatabase;
38
+ upsertSession(record: SessionIdentity): void;
39
+ getSessionStats(sessionId: string): SessionIndexStats;
40
+ listTables(): string[];
41
+ health(): DatabaseHealth;
42
+ close(): void;
43
+ private assertOpen;
44
+ }
45
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/persistence/sqlite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAA2C,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,yBAAyB,EAAE,MAAM,+CAA+C,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAC5C,YAAY,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAEpF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAoBD,qBAAa,eAAe;IAYxB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbzB,QAAQ,CAAC,aAAa,SAA0B;IAChD,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACjD,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,yBAAyB,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,0BAA0B,CAAC;IACtD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;IAeP,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,eAAe;IAwC7E,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAK5C,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB;IAKrD,UAAU,IAAI,MAAM,EAAE;IAUtB,MAAM,IAAI,cAAc;IAiBxB,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,UAAU;CAGnB"}
@@ -0,0 +1,137 @@
1
+ import { chmodSync, mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { silentLogger } from "../shared/logging.js";
5
+ import { applyMigrations, CURRENT_SCHEMA_VERSION } from "./migrations.js";
6
+ import { ArtifactRepository } from "./repositories/artifact-repository.js";
7
+ import { ContextManifestRepository } from "./repositories/context-manifest-repository.js";
8
+ import { MemoryRepository } from "./repositories/memory-repository.js";
9
+ import { ProjectKnowledgeRepository } from "./repositories/project-knowledge-repository.js";
10
+ import { SessionIndexRepository, } from "./repositories/session-index-repository.js";
11
+ import { SummaryRepository } from "./repositories/summary-repository.js";
12
+ function firstColumn(row) {
13
+ if (!row || typeof row !== "object")
14
+ throw new Error("SQLite PRAGMA returned no row");
15
+ const value = Object.values(row)[0];
16
+ if (typeof value !== "string" && typeof value !== "number") {
17
+ throw new Error("SQLite PRAGMA returned an unexpected value");
18
+ }
19
+ return value;
20
+ }
21
+ function bestEffortChmod(path, mode) {
22
+ try {
23
+ chmodSync(path, mode);
24
+ }
25
+ catch (error) {
26
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
27
+ if (code !== "ENOSYS" && code !== "EPERM" && code !== "EINVAL")
28
+ throw error;
29
+ }
30
+ }
31
+ export class ContextDatabase {
32
+ path;
33
+ database;
34
+ logger;
35
+ schemaVersion = CURRENT_SCHEMA_VERSION;
36
+ migrations;
37
+ sessionIndex;
38
+ artifacts;
39
+ manifests;
40
+ memory;
41
+ summaries;
42
+ projectKnowledge;
43
+ closed = false;
44
+ constructor(path, database, logger, migrations) {
45
+ this.path = path;
46
+ this.database = database;
47
+ this.logger = logger;
48
+ this.migrations = migrations;
49
+ this.sessionIndex = new SessionIndexRepository(database);
50
+ this.artifacts = new ArtifactRepository(database);
51
+ this.manifests = new ContextManifestRepository(database);
52
+ this.memory = new MemoryRepository(database);
53
+ this.summaries = new SummaryRepository(database);
54
+ this.projectKnowledge = new ProjectKnowledgeRepository(database);
55
+ }
56
+ static open(path, options = {}) {
57
+ const logger = options.logger ?? silentLogger;
58
+ const memory = path === ":memory:";
59
+ if (!memory) {
60
+ const directory = dirname(path);
61
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
62
+ bestEffortChmod(directory, 0o700);
63
+ }
64
+ const database = new DatabaseSync(path, {
65
+ enableForeignKeyConstraints: true,
66
+ enableDoubleQuotedStringLiterals: false,
67
+ allowExtension: false,
68
+ timeout: 5000,
69
+ });
70
+ try {
71
+ database.exec("PRAGMA foreign_keys = ON");
72
+ database.exec("PRAGMA busy_timeout = 5000");
73
+ database.exec("PRAGMA synchronous = NORMAL");
74
+ database.exec("PRAGMA trusted_schema = OFF");
75
+ database.exec("PRAGMA secure_delete = FAST");
76
+ if (!memory)
77
+ database.exec("PRAGMA journal_mode = WAL");
78
+ const migrations = applyMigrations(database, options.now);
79
+ if (!memory)
80
+ bestEffortChmod(path, 0o600);
81
+ logger.info("database.opened", {
82
+ databasePath: path,
83
+ schemaVersion: CURRENT_SCHEMA_VERSION,
84
+ migrations: migrations.length,
85
+ });
86
+ return new ContextDatabase(path, database, logger, migrations);
87
+ }
88
+ catch (error) {
89
+ database.close();
90
+ throw error;
91
+ }
92
+ }
93
+ upsertSession(record) {
94
+ this.assertOpen();
95
+ this.sessionIndex.upsertSession(record);
96
+ }
97
+ getSessionStats(sessionId) {
98
+ this.assertOpen();
99
+ return this.sessionIndex.getStats(sessionId);
100
+ }
101
+ listTables() {
102
+ this.assertOpen();
103
+ const rows = this.database.prepare(`
104
+ SELECT name FROM sqlite_schema
105
+ WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
106
+ ORDER BY name
107
+ `).all();
108
+ return rows.map((row) => row.name);
109
+ }
110
+ health() {
111
+ this.assertOpen();
112
+ const quickCheck = String(firstColumn(this.database.prepare("PRAGMA quick_check").get()));
113
+ const journalMode = String(firstColumn(this.database.prepare("PRAGMA journal_mode").get()));
114
+ const foreignKeys = Number(firstColumn(this.database.prepare("PRAGMA foreign_keys").get())) === 1;
115
+ const schemaVersion = Number(firstColumn(this.database.prepare("PRAGMA user_version").get()));
116
+ return {
117
+ ok: quickCheck === "ok" && foreignKeys && schemaVersion === CURRENT_SCHEMA_VERSION,
118
+ quickCheck,
119
+ journalMode,
120
+ foreignKeys,
121
+ schemaVersion,
122
+ appliedMigrations: this.migrations.length,
123
+ };
124
+ }
125
+ close() {
126
+ if (this.closed)
127
+ return;
128
+ this.closed = true;
129
+ this.database.close();
130
+ this.logger.info("database.closed", { databasePath: this.path });
131
+ }
132
+ assertOpen() {
133
+ if (this.closed)
134
+ throw new Error("Context database is closed");
135
+ }
136
+ }
137
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/persistence/sqlite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type AtomicGroupKind = "turn" | "summary" | "prefix";
2
+ export interface AtomicMessageGroup {
3
+ id: string;
4
+ kind: AtomicGroupKind;
5
+ messageIndices: number[];
6
+ startIndex: number;
7
+ endIndex: number;
8
+ estimatedTokens: number;
9
+ containsToolExchange: boolean;
10
+ reason: string;
11
+ }
12
+ export declare function messageRole(message: unknown): string | undefined;
13
+ export declare function buildAtomicGroups(messages: readonly unknown[]): AtomicMessageGroup[];
14
+ export declare function validateAtomicSelection(messages: readonly unknown[], selectedIndices: ReadonlySet<number>): string[];
15
+ //# sourceMappingURL=atomic-groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-groups.d.ts","sourceRoot":"","sources":["../../src/planner/atomic-groups.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,eAAe,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAgBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGhE;AA0ED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,kBAAkB,EAAE,CA+EpF;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,GACnC,MAAM,EAAE,CAyBV"}
@@ -0,0 +1,177 @@
1
+ import { estimateMessageTokens } from "../core/token-estimator.js";
2
+ function isRecord(value) {
3
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ export function messageRole(message) {
6
+ if (!isRecord(message))
7
+ return undefined;
8
+ return typeof message.role === "string" ? message.role : undefined;
9
+ }
10
+ function isSummaryMessage(message) {
11
+ const role = messageRole(message);
12
+ return role === "compactionSummary" || role === "branchSummary";
13
+ }
14
+ function toolRelations(messages) {
15
+ const calls = new Map();
16
+ const results = new Map();
17
+ for (let index = 0; index < messages.length; index++) {
18
+ const message = messages[index];
19
+ if (!isRecord(message))
20
+ continue;
21
+ if (message.role === "assistant" && Array.isArray(message.content)) {
22
+ for (const block of message.content) {
23
+ if (!isRecord(block) || block.type !== "toolCall" || typeof block.id !== "string")
24
+ continue;
25
+ calls.set(block.id, index);
26
+ }
27
+ }
28
+ if (message.role === "toolResult" && typeof message.toolCallId === "string") {
29
+ const indices = results.get(message.toolCallId) ?? [];
30
+ indices.push(index);
31
+ results.set(message.toolCallId, indices);
32
+ }
33
+ }
34
+ return { calls, results };
35
+ }
36
+ function initialGroups(messages) {
37
+ const groups = [];
38
+ let activeTurn;
39
+ let activePrefix;
40
+ for (let index = 0; index < messages.length; index++) {
41
+ const message = messages[index];
42
+ if (isSummaryMessage(message)) {
43
+ groups.push({ kind: "summary", messageIndices: [index] });
44
+ activeTurn = undefined;
45
+ activePrefix = undefined;
46
+ continue;
47
+ }
48
+ if (messageRole(message) === "user") {
49
+ activeTurn = { kind: "turn", messageIndices: [index] };
50
+ groups.push(activeTurn);
51
+ activePrefix = undefined;
52
+ continue;
53
+ }
54
+ if (activeTurn) {
55
+ activeTurn.messageIndices.push(index);
56
+ continue;
57
+ }
58
+ if (!activePrefix) {
59
+ activePrefix = { kind: "prefix", messageIndices: [] };
60
+ groups.push(activePrefix);
61
+ }
62
+ activePrefix.messageIndices.push(index);
63
+ }
64
+ return groups;
65
+ }
66
+ function mergedKind(groups, members) {
67
+ if (members.some((index) => groups[index]?.kind === "turn"))
68
+ return "turn";
69
+ if (members.every((index) => groups[index]?.kind === "summary"))
70
+ return "summary";
71
+ return "prefix";
72
+ }
73
+ export function buildAtomicGroups(messages) {
74
+ const drafts = initialGroups(messages);
75
+ if (drafts.length === 0)
76
+ return [];
77
+ const parents = drafts.map((_, index) => index);
78
+ const messageGroups = new Map();
79
+ drafts.forEach((group, groupIndex) => {
80
+ for (const messageIndex of group.messageIndices)
81
+ messageGroups.set(messageIndex, groupIndex);
82
+ });
83
+ const find = (index) => {
84
+ let root = index;
85
+ while (parents[root] !== root)
86
+ root = parents[root] ?? root;
87
+ while (parents[index] !== index) {
88
+ const parent = parents[index] ?? index;
89
+ parents[index] = root;
90
+ index = parent;
91
+ }
92
+ return root;
93
+ };
94
+ const union = (left, right) => {
95
+ const leftRoot = find(left);
96
+ const rightRoot = find(right);
97
+ if (leftRoot !== rightRoot)
98
+ parents[Math.max(leftRoot, rightRoot)] = Math.min(leftRoot, rightRoot);
99
+ };
100
+ const relations = toolRelations(messages);
101
+ for (const [toolCallId, resultIndices] of relations.results) {
102
+ const callIndex = relations.calls.get(toolCallId);
103
+ if (callIndex === undefined)
104
+ continue;
105
+ const callGroup = messageGroups.get(callIndex);
106
+ if (callGroup === undefined)
107
+ continue;
108
+ for (const resultIndex of resultIndices) {
109
+ const resultGroup = messageGroups.get(resultIndex);
110
+ if (resultGroup !== undefined)
111
+ union(callGroup, resultGroup);
112
+ }
113
+ }
114
+ const merged = new Map();
115
+ drafts.forEach((group, groupIndex) => {
116
+ const root = find(groupIndex);
117
+ const aggregate = merged.get(root) ?? { draftIndices: [], messageIndices: [] };
118
+ aggregate.draftIndices.push(groupIndex);
119
+ aggregate.messageIndices.push(...group.messageIndices);
120
+ merged.set(root, aggregate);
121
+ });
122
+ return [...merged.values()]
123
+ .map((aggregate) => {
124
+ const messageIndices = [...aggregate.messageIndices].sort((left, right) => left - right);
125
+ const startIndex = messageIndices[0] ?? 0;
126
+ const endIndex = messageIndices.at(-1) ?? startIndex;
127
+ const selected = new Set(messageIndices);
128
+ const containsToolExchange = [...relations.results].some(([id, resultIndices]) => {
129
+ const callIndex = relations.calls.get(id);
130
+ return callIndex !== undefined && selected.has(callIndex) && resultIndices.some((index) => selected.has(index));
131
+ });
132
+ const kind = mergedKind(drafts, aggregate.draftIndices);
133
+ return {
134
+ id: `group:${startIndex}-${endIndex}`,
135
+ kind,
136
+ messageIndices,
137
+ startIndex,
138
+ endIndex,
139
+ estimatedTokens: messageIndices.reduce((total, index) => total + estimateMessageTokens(messages[index]), 0),
140
+ containsToolExchange,
141
+ reason: containsToolExchange
142
+ ? "Atomic conversation turn containing a complete tool call/result batch"
143
+ : kind === "turn"
144
+ ? "Conversation turn boundary"
145
+ : kind === "summary"
146
+ ? "Active Pi summary message"
147
+ : "Messages preceding the first user turn",
148
+ };
149
+ })
150
+ .sort((left, right) => left.startIndex - right.startIndex);
151
+ }
152
+ export function validateAtomicSelection(messages, selectedIndices) {
153
+ const relations = toolRelations(messages);
154
+ const errors = [];
155
+ for (const [toolCallId, callIndex] of relations.calls) {
156
+ if (!selectedIndices.has(callIndex))
157
+ continue;
158
+ const resultIndices = relations.results.get(toolCallId) ?? [];
159
+ if (resultIndices.length === 0) {
160
+ errors.push(`selected tool call ${toolCallId} has no result`);
161
+ continue;
162
+ }
163
+ if (resultIndices.some((index) => !selectedIndices.has(index))) {
164
+ errors.push(`selected tool call ${toolCallId} is missing one or more results`);
165
+ }
166
+ }
167
+ for (const [toolCallId, resultIndices] of relations.results) {
168
+ if (!resultIndices.some((index) => selectedIndices.has(index)))
169
+ continue;
170
+ const callIndex = relations.calls.get(toolCallId);
171
+ if (callIndex === undefined || !selectedIndices.has(callIndex)) {
172
+ errors.push(`selected tool result ${toolCallId} has no selected call`);
173
+ }
174
+ }
175
+ return [...new Set(errors)];
176
+ }
177
+ //# sourceMappingURL=atomic-groups.js.map