supipowers 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/README.md +14 -8
  2. package/bin/install.mjs +20 -5
  3. package/bin/install.ts +95 -0
  4. package/package.json +8 -4
  5. package/skills/context-mode/SKILL.md +17 -10
  6. package/skills/harness/SKILL.md +94 -0
  7. package/skills/ui-design/SKILL.md +63 -0
  8. package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
  9. package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
  10. package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
  11. package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
  12. package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
  13. package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
  14. package/skills/ultraplan-discover/SKILL.md +96 -0
  15. package/skills/ultraplan-intake/SKILL.md +89 -0
  16. package/skills/ultraplan-research/SKILL.md +129 -0
  17. package/skills/ultraplan-review/SKILL.md +86 -0
  18. package/skills/ultraplan-review-scope/SKILL.md +111 -0
  19. package/skills/ultraplan-review-structure/SKILL.md +120 -0
  20. package/skills/ultraplan-review-tdd/SKILL.md +142 -0
  21. package/skills/ultraplan-scout/SKILL.md +110 -0
  22. package/skills/ultraplan-synthesize/SKILL.md +124 -0
  23. package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
  24. package/src/ai/schema-text.ts +129 -0
  25. package/src/ai/structured-output.ts +274 -0
  26. package/src/ai/template.ts +27 -0
  27. package/src/bootstrap.ts +63 -28
  28. package/src/commands/agents.ts +149 -45
  29. package/src/commands/ai-review.ts +251 -30
  30. package/src/commands/clear.ts +434 -0
  31. package/src/commands/commit.ts +1 -0
  32. package/src/commands/config.ts +242 -44
  33. package/src/commands/context.ts +55 -28
  34. package/src/commands/doctor.ts +234 -6
  35. package/src/commands/fix-pr.ts +306 -131
  36. package/src/commands/generate.ts +111 -21
  37. package/src/commands/memory.ts +192 -0
  38. package/src/commands/model-picker.ts +28 -21
  39. package/src/commands/model.ts +19 -9
  40. package/src/commands/optimize-context.ts +408 -29
  41. package/src/commands/plan.ts +2 -0
  42. package/src/commands/qa.ts +312 -137
  43. package/src/commands/release.ts +259 -76
  44. package/src/commands/review.ts +293 -59
  45. package/src/commands/status.ts +200 -13
  46. package/src/commands/supi.ts +3 -35
  47. package/src/commands/ui-design.ts +394 -0
  48. package/src/commands/ultraplan.ts +1518 -0
  49. package/src/commands/update.ts +86 -0
  50. package/src/config/defaults.ts +62 -0
  51. package/src/config/loader.ts +448 -60
  52. package/src/config/schema.ts +108 -2
  53. package/src/context/optimizer.ts +25 -33
  54. package/src/context/rule-renderer.ts +223 -0
  55. package/src/context/savings.ts +258 -0
  56. package/src/context/startup-check.ts +380 -0
  57. package/src/context/startup-optimizer.ts +355 -0
  58. package/src/context/tokenignore.ts +146 -0
  59. package/src/context-mode/cache-handle.ts +49 -0
  60. package/src/context-mode/cache-preview.ts +71 -0
  61. package/src/context-mode/cache-store.ts +738 -0
  62. package/src/context-mode/compressor.ts +131 -26
  63. package/src/context-mode/dedup.ts +108 -0
  64. package/src/context-mode/detector.ts +35 -4
  65. package/src/context-mode/event-extractor.ts +14 -12
  66. package/src/context-mode/event-store.ts +91 -36
  67. package/src/context-mode/hooks.ts +798 -56
  68. package/src/context-mode/knowledge/store.ts +255 -11
  69. package/src/context-mode/memory-store.ts +325 -0
  70. package/src/context-mode/metrics-recorder.ts +158 -0
  71. package/src/context-mode/metrics-store.ts +765 -0
  72. package/src/context-mode/model.ts +24 -0
  73. package/src/context-mode/processor-keys.ts +29 -0
  74. package/src/context-mode/processors/build.ts +66 -0
  75. package/src/context-mode/processors/docker.ts +57 -0
  76. package/src/context-mode/processors/git.ts +111 -0
  77. package/src/context-mode/processors/json.ts +112 -0
  78. package/src/context-mode/processors/k8s.ts +67 -0
  79. package/src/context-mode/processors/lint.ts +67 -0
  80. package/src/context-mode/processors/log.ts +86 -0
  81. package/src/context-mode/processors/registry.ts +116 -0
  82. package/src/context-mode/processors/test-runner.ts +102 -0
  83. package/src/context-mode/processors/types.ts +20 -0
  84. package/src/context-mode/repomap.ts +400 -0
  85. package/src/context-mode/routing.ts +97 -24
  86. package/src/context-mode/sandbox/runners.ts +5 -1
  87. package/src/context-mode/snapshot-builder.ts +106 -11
  88. package/src/context-mode/source-hash.ts +173 -0
  89. package/src/context-mode/tool-name.ts +11 -0
  90. package/src/context-mode/tools.ts +654 -22
  91. package/src/context-mode/web/fetcher.ts +31 -12
  92. package/src/debug/logger.ts +2 -1
  93. package/src/deps/registry.ts +1 -1
  94. package/src/discipline/failure-summarizer.ts +170 -0
  95. package/src/discipline/failure-taxonomy.ts +131 -0
  96. package/src/discipline/workflow-invariants.ts +125 -0
  97. package/src/discovery/index.ts +31 -0
  98. package/src/discovery/lsp.ts +87 -0
  99. package/src/discovery/rank.ts +144 -0
  100. package/src/discovery/sources.ts +89 -0
  101. package/src/discovery/workflow.ts +87 -0
  102. package/src/docs/contracts.ts +39 -0
  103. package/src/docs/drift.ts +117 -87
  104. package/src/fix-pr/assessment.ts +200 -0
  105. package/src/fix-pr/contracts.ts +47 -0
  106. package/src/fix-pr/fetch-comments.ts +80 -0
  107. package/src/fix-pr/prompt-builder.ts +58 -40
  108. package/src/fix-pr/scripts/exec.ts +34 -0
  109. package/src/fix-pr/scripts/trigger-review.ts +106 -0
  110. package/src/fix-pr/scripts/wait-and-check.ts +108 -0
  111. package/src/fix-pr/types.ts +4 -0
  112. package/src/git/branch-finish.ts +5 -0
  113. package/src/git/commit-contract.ts +83 -0
  114. package/src/git/commit.ts +121 -184
  115. package/src/git/status.ts +62 -8
  116. package/src/harness/anti_slop/architecture-parser.ts +210 -0
  117. package/src/harness/anti_slop/backend-factory.ts +30 -0
  118. package/src/harness/anti_slop/backend.ts +140 -0
  119. package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
  120. package/src/harness/anti_slop/fallow-adapter.ts +305 -0
  121. package/src/harness/anti_slop/installer.ts +227 -0
  122. package/src/harness/anti_slop/queue.ts +216 -0
  123. package/src/harness/anti_slop/recommend.ts +84 -0
  124. package/src/harness/anti_slop/score.ts +180 -0
  125. package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
  126. package/src/harness/artifacts/agents-md.ts +88 -0
  127. package/src/harness/artifacts/checks-wiring.ts +57 -0
  128. package/src/harness/artifacts/docs-tree.ts +79 -0
  129. package/src/harness/artifacts/lint-configs.ts +136 -0
  130. package/src/harness/artifacts/review-agents.ts +67 -0
  131. package/src/harness/bare-entry.ts +108 -0
  132. package/src/harness/command.ts +1010 -0
  133. package/src/harness/default-agents/design.md +23 -0
  134. package/src/harness/default-agents/discover.md +18 -0
  135. package/src/harness/default-agents/implement.md +24 -0
  136. package/src/harness/default-agents/plan.md +19 -0
  137. package/src/harness/default-agents/research.md +21 -0
  138. package/src/harness/default-agents/validate.md +22 -0
  139. package/src/harness/gc/reporter.ts +28 -0
  140. package/src/harness/gc/runner.ts +136 -0
  141. package/src/harness/hooks/layer-context-inject.ts +155 -0
  142. package/src/harness/hooks/post-session-sweep.ts +130 -0
  143. package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
  144. package/src/harness/hooks/register.ts +118 -0
  145. package/src/harness/model.ts +117 -0
  146. package/src/harness/pipeline.ts +348 -0
  147. package/src/harness/project-paths.ts +235 -0
  148. package/src/harness/stage-runner.ts +107 -0
  149. package/src/harness/stages/design.ts +386 -0
  150. package/src/harness/stages/discover.ts +454 -0
  151. package/src/harness/stages/implement.ts +162 -0
  152. package/src/harness/stages/plan.ts +335 -0
  153. package/src/harness/stages/research.ts +263 -0
  154. package/src/harness/stages/validate.ts +684 -0
  155. package/src/harness/storage.ts +467 -0
  156. package/src/harness/tools.ts +426 -0
  157. package/src/lsp/bridge.ts +56 -95
  158. package/src/lsp/capabilities.ts +108 -0
  159. package/src/lsp/contracts.ts +35 -0
  160. package/src/lsp/detector.ts +8 -12
  161. package/src/markdown-frontmatter.ts +68 -0
  162. package/src/mempalace/bridge.ts +129 -0
  163. package/src/mempalace/config.ts +75 -0
  164. package/src/mempalace/format.ts +163 -0
  165. package/src/mempalace/hooks.ts +370 -0
  166. package/src/mempalace/installer-helper.ts +194 -0
  167. package/src/mempalace/python/mempalace_bridge.py +440 -0
  168. package/src/mempalace/runtime.ts +565 -0
  169. package/src/mempalace/schema.ts +264 -0
  170. package/src/mempalace/session-summary.ts +198 -0
  171. package/src/mempalace/tool.ts +186 -0
  172. package/src/mempalace/uv.ts +256 -0
  173. package/src/migrate/runner.ts +354 -0
  174. package/src/planning/approval-flow.ts +206 -9
  175. package/src/planning/plan-writer-prompt.ts +4 -3
  176. package/src/planning/planning-ask-tool.ts +39 -0
  177. package/src/planning/render-markdown.ts +74 -0
  178. package/src/planning/spec.ts +42 -0
  179. package/src/planning/system-prompt.ts +11 -8
  180. package/src/planning/validate.ts +84 -0
  181. package/src/platform/omp.ts +15 -2
  182. package/src/platform/system-prompt.ts +37 -0
  183. package/src/platform/test-utils.ts +3 -0
  184. package/src/platform/types.ts +6 -1
  185. package/src/qa/config.ts +12 -6
  186. package/src/qa/detect-app-type.ts +13 -6
  187. package/src/qa/matrix.ts +12 -6
  188. package/src/qa/prompt-builder.ts +28 -30
  189. package/src/qa/scripts/dev-server-utils.ts +72 -0
  190. package/src/qa/scripts/run-e2e-tests.ts +226 -0
  191. package/src/qa/scripts/start-dev-server.ts +138 -0
  192. package/src/qa/scripts/stop-dev-server.ts +77 -0
  193. package/src/qa/session.ts +13 -7
  194. package/src/quality/ai-setup.ts +27 -25
  195. package/src/quality/contracts.ts +34 -0
  196. package/src/quality/gates/ai-review.ts +20 -58
  197. package/src/quality/gates/command.ts +249 -46
  198. package/src/quality/review-gates.ts +18 -2
  199. package/src/quality/runner.ts +63 -22
  200. package/src/quality/schemas.ts +37 -2
  201. package/src/quality/setup.ts +96 -16
  202. package/src/release/changelog.ts +1 -1
  203. package/src/release/channels/custom.ts +13 -3
  204. package/src/release/channels/types.ts +5 -0
  205. package/src/release/contracts.ts +90 -0
  206. package/src/release/executor.ts +122 -45
  207. package/src/release/prompt.ts +18 -2
  208. package/src/release/targets.ts +86 -0
  209. package/src/release/version.ts +96 -71
  210. package/src/review/agent-loader.ts +298 -127
  211. package/src/review/fixer.ts +10 -6
  212. package/src/review/multi-agent-runner.ts +115 -14
  213. package/src/review/output.ts +12 -139
  214. package/src/review/runner.ts +12 -6
  215. package/src/review/scope.ts +144 -24
  216. package/src/review/types.ts +11 -20
  217. package/src/review/validator.ts +12 -6
  218. package/src/storage/fix-pr-sessions.ts +21 -14
  219. package/src/storage/plans.ts +14 -5
  220. package/src/storage/qa-sessions.ts +25 -19
  221. package/src/storage/reliability-metrics.ts +180 -0
  222. package/src/storage/reports.ts +8 -7
  223. package/src/storage/review-sessions.ts +55 -20
  224. package/src/tool-catalog/active-tool-controller.ts +164 -0
  225. package/src/tool-catalog/active-tool-planner.ts +212 -0
  226. package/src/tool-catalog/tool-groups.ts +102 -0
  227. package/src/types.ts +1401 -5
  228. package/src/ui-design/backend-adapter.ts +78 -0
  229. package/src/ui-design/backends/local-html.ts +82 -0
  230. package/src/ui-design/backends/pencil-mcp.ts +111 -0
  231. package/src/ui-design/components-scanner.ts +124 -0
  232. package/src/ui-design/config.ts +55 -0
  233. package/src/ui-design/pen-scanner.ts +95 -0
  234. package/src/ui-design/pen-selector.ts +72 -0
  235. package/src/ui-design/prompt-builder.ts +73 -0
  236. package/src/ui-design/scanner.ts +136 -0
  237. package/src/ui-design/session.ts +974 -0
  238. package/src/ui-design/system-prompt.ts +312 -0
  239. package/src/ui-design/tokens-scanner.ts +181 -0
  240. package/src/ui-design/types.ts +96 -0
  241. package/src/ultraplan/agent-catalog.ts +522 -0
  242. package/src/ultraplan/authoring/agent-catalog.ts +310 -0
  243. package/src/ultraplan/authoring/authoring-tools.ts +552 -0
  244. package/src/ultraplan/authoring/command-handlers.ts +339 -0
  245. package/src/ultraplan/authoring/markdown.ts +510 -0
  246. package/src/ultraplan/authoring/model.ts +162 -0
  247. package/src/ultraplan/authoring/pipeline.ts +319 -0
  248. package/src/ultraplan/authoring/stage-runner.ts +141 -0
  249. package/src/ultraplan/authoring/stages/approve.ts +249 -0
  250. package/src/ultraplan/authoring/stages/discover.ts +289 -0
  251. package/src/ultraplan/authoring/stages/intake.ts +203 -0
  252. package/src/ultraplan/authoring/stages/research.ts +399 -0
  253. package/src/ultraplan/authoring/stages/review.ts +333 -0
  254. package/src/ultraplan/authoring/stages/scout.ts +188 -0
  255. package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
  256. package/src/ultraplan/authoring/storage.ts +594 -0
  257. package/src/ultraplan/authoring/synth-gate.ts +165 -0
  258. package/src/ultraplan/authoring-draft.ts +653 -0
  259. package/src/ultraplan/authoring-persist.ts +180 -0
  260. package/src/ultraplan/authoring-tool.ts +608 -0
  261. package/src/ultraplan/authoring-wizard.ts +587 -0
  262. package/src/ultraplan/batch/merge.ts +98 -0
  263. package/src/ultraplan/batch/planner.ts +150 -0
  264. package/src/ultraplan/batch/presenter.ts +97 -0
  265. package/src/ultraplan/batch/storage.ts +420 -0
  266. package/src/ultraplan/batch/supervisor.ts +317 -0
  267. package/src/ultraplan/batch/worker.ts +26 -0
  268. package/src/ultraplan/batch/worktree.ts +110 -0
  269. package/src/ultraplan/contracts.ts +1593 -0
  270. package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
  271. package/src/ultraplan/default-agents/authoring/intake.md +12 -0
  272. package/src/ultraplan/default-agents/authoring/planner.md +12 -0
  273. package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
  274. package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
  275. package/src/ultraplan/default-agents/authoring/scout.md +12 -0
  276. package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
  277. package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
  278. package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
  279. package/src/ultraplan/default-agents/backend-executor.md +10 -0
  280. package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
  281. package/src/ultraplan/default-agents/backend-tester.md +10 -0
  282. package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
  283. package/src/ultraplan/default-agents/frontend-executor.md +10 -0
  284. package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
  285. package/src/ultraplan/default-agents/frontend-tester.md +10 -0
  286. package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
  287. package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
  288. package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
  289. package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
  290. package/src/ultraplan/execution/contract.ts +71 -0
  291. package/src/ultraplan/execution/policy.ts +217 -0
  292. package/src/ultraplan/execution/runtime-tools.ts +107 -0
  293. package/src/ultraplan/execution/session-runner.ts +281 -0
  294. package/src/ultraplan/next-router.ts +85 -0
  295. package/src/ultraplan/presenter.ts +359 -0
  296. package/src/ultraplan/project-paths.ts +342 -0
  297. package/src/ultraplan/runtime/active-execution.ts +72 -0
  298. package/src/ultraplan/runtime/apply-mutation.ts +416 -0
  299. package/src/ultraplan/runtime/blockers.ts +243 -0
  300. package/src/ultraplan/runtime/hook-bridge.ts +486 -0
  301. package/src/ultraplan/runtime/launch-context.ts +207 -0
  302. package/src/ultraplan/runtime/migration.ts +524 -0
  303. package/src/ultraplan/runtime/normalize.ts +281 -0
  304. package/src/ultraplan/runtime/proof.ts +260 -0
  305. package/src/ultraplan/runtime/reducer.ts +416 -0
  306. package/src/ultraplan/runtime/repair.ts +251 -0
  307. package/src/ultraplan/runtime/tracker-storage.ts +368 -0
  308. package/src/ultraplan/session-selection.ts +291 -0
  309. package/src/ultraplan/storage.ts +374 -0
  310. package/src/utils/editor.ts +38 -0
  311. package/src/utils/executable.ts +80 -0
  312. package/src/utils/paths.ts +1 -20
  313. package/src/utils/shell.ts +31 -0
  314. package/src/visual/companion.ts +2 -1
  315. package/src/visual/scripts/frame-template.html +60 -0
  316. package/src/visual/scripts/index.js +59 -13
  317. package/src/visual/scripts/package.json +3 -0
  318. package/src/visual/start-server.ts +2 -1
  319. package/src/workspace/git-scope.ts +64 -0
  320. package/src/workspace/locks.ts +23 -0
  321. package/src/workspace/package-manager.ts +117 -0
  322. package/src/workspace/path-mapping.ts +75 -0
  323. package/src/workspace/project-slug.ts +92 -0
  324. package/src/workspace/repo-root.ts +137 -0
  325. package/src/workspace/selector.ts +115 -0
  326. package/src/workspace/state-paths.ts +118 -0
  327. package/src/workspace/targets.ts +313 -0
  328. package/src/fix-pr/scripts/diff-comments.sh +0 -33
  329. package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
  330. package/src/fix-pr/scripts/trigger-review.sh +0 -36
  331. package/src/fix-pr/scripts/wait-and-check.sh +0 -37
  332. package/src/qa/scripts/detect-app-type.sh +0 -68
  333. package/src/qa/scripts/discover-routes.sh +0 -143
  334. package/src/qa/scripts/run-e2e-tests.sh +0 -131
  335. package/src/qa/scripts/start-dev-server.sh +0 -46
  336. package/src/qa/scripts/stop-dev-server.sh +0 -36
  337. package/src/review/prompts/fix-output-schema.md +0 -18
  338. package/src/review/prompts/review-output-schema.md +0 -38
  339. package/src/review/template.ts +0 -15
  340. /package/src/{review → ai}/prompts/invalid-output-retry.md +0 -0
@@ -1,5 +1,5 @@
1
1
  // src/context-mode/event-store.ts
2
- import { Database } from "bun:sqlite";
2
+ import { constants, Database } from "bun:sqlite";
3
3
  import { createHash } from "node:crypto";
4
4
 
5
5
  /** Event categories extracted from tool results */
@@ -129,75 +129,117 @@ function computeDataHash(data: string): string {
129
129
  return createHash("sha256").update(data).digest("hex").slice(0, 16);
130
130
  }
131
131
 
132
+
133
+
132
134
  export class EventStore {
133
- private db: Database;
135
+ #db: Database;
136
+ readonly #dbPath: string;
137
+ #closed = false;
134
138
 
135
139
  constructor(dbPath: string) {
136
- this.db = new Database(dbPath);
140
+ this.#dbPath = dbPath;
141
+ this.#db = new Database(dbPath);
137
142
  }
138
143
 
139
144
  init(): void {
140
- this.db.exec("PRAGMA journal_mode = WAL;");
141
- this.migrate();
142
- this.db.exec(SCHEMA);
145
+ try {
146
+ this.#ensureDeleteJournalMode();
147
+ this.#migrate();
148
+ this.#db.exec(SCHEMA);
149
+ } catch (error) {
150
+ this.close();
151
+ throw error;
152
+ }
153
+ }
154
+
155
+ #ensureDeleteJournalMode(): void {
156
+ const journalMode = this.#getJournalMode();
157
+ if (journalMode === "delete") return;
158
+
159
+ if (journalMode === "wal") {
160
+ this.#cleanupWalSidecars();
161
+ }
162
+
163
+ try {
164
+ this.#db.exec("PRAGMA journal_mode = DELETE;");
165
+ } catch {
166
+ // Older WAL-backed databases can stay on WAL for this process.
167
+ // close() still checkpoints them so teardown and the next reopen succeed.
168
+ }
169
+ }
170
+
171
+ #getJournalMode(): string {
172
+ const { journal_mode } = this.#db.prepare("PRAGMA journal_mode").get() as {
173
+ journal_mode: string;
174
+ };
175
+ return journal_mode.toLowerCase();
176
+ }
177
+
178
+ #cleanupWalSidecars(): void {
179
+ try {
180
+ this.#db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
181
+ this.#db.exec("PRAGMA wal_checkpoint(TRUNCATE);");
182
+ } catch {
183
+ // Best effort only: close() still releases the handle in finally.
184
+ }
143
185
  }
144
186
 
145
187
  // ── Schema migration ────────────────────────────────────────
146
188
 
147
- private migrate(): void {
148
- const { user_version } = this.db.prepare("PRAGMA user_version").get() as { user_version: number };
189
+ #migrate(): void {
190
+ const { user_version } = this.#db.prepare("PRAGMA user_version").get() as { user_version: number };
149
191
  if (user_version >= SCHEMA_VERSION) return;
150
192
 
151
193
  // Upgrade from v0: session_events exists but lacks data_hash column
152
- const tableExists = this.db.prepare(
194
+ const tableExists = this.#db.prepare(
153
195
  "SELECT name FROM sqlite_master WHERE type='table' AND name='session_events'",
154
196
  ).get();
155
197
 
156
198
  if (tableExists) {
157
199
  try {
158
- this.db.exec("ALTER TABLE session_events ADD COLUMN data_hash TEXT NOT NULL DEFAULT ''");
200
+ this.#db.exec("ALTER TABLE session_events ADD COLUMN data_hash TEXT NOT NULL DEFAULT ''");
159
201
  } catch {
160
202
  // Column already exists (fresh install ran SCHEMA first somehow)
161
203
  }
162
204
  }
163
205
 
164
- this.db.exec(`PRAGMA user_version = ${SCHEMA_VERSION};`);
206
+ this.#db.exec(`PRAGMA user_version = ${SCHEMA_VERSION};`);
165
207
  }
166
208
 
167
209
  // ── Write with dedup + eviction ─────────────────────────────
168
210
 
169
211
  writeEvent(event: Omit<TrackedEvent, "id" | "dataHash">): void {
170
212
  const dataHash = computeDataHash(event.data);
171
- if (this.isDuplicate(event.sessionId, event.category, dataHash)) return;
213
+ if (this.#isDuplicate(event.sessionId, event.category, dataHash)) return;
172
214
 
173
- this.db.prepare(
215
+ this.#db.prepare(
174
216
  "INSERT INTO session_events (session_id, category, data, priority, source, timestamp, data_hash) VALUES (?, ?, ?, ?, ?, ?, ?)",
175
217
  ).run(event.sessionId, event.category, event.data, event.priority, event.source, event.timestamp, dataHash);
176
218
 
177
- this.enforceEventCap(event.sessionId);
219
+ this.#enforceEventCap(event.sessionId);
178
220
  }
179
221
 
180
222
  writeEvents(events: Omit<TrackedEvent, "id" | "dataHash">[]): void {
181
223
  if (events.length === 0) return;
182
224
 
183
- const insert = this.db.prepare(
225
+ const insert = this.#db.prepare(
184
226
  "INSERT INTO session_events (session_id, category, data, priority, source, timestamp, data_hash) VALUES (?, ?, ?, ?, ?, ?, ?)",
185
227
  );
186
- const tx = this.db.transaction(() => {
228
+ const tx = this.#db.transaction(() => {
187
229
  for (const event of events) {
188
230
  const dataHash = computeDataHash(event.data);
189
- if (this.isDuplicate(event.sessionId, event.category, dataHash)) continue;
231
+ if (this.#isDuplicate(event.sessionId, event.category, dataHash)) continue;
190
232
  insert.run(event.sessionId, event.category, event.data, event.priority, event.source, event.timestamp, dataHash);
191
233
  }
192
234
  });
193
235
  tx();
194
236
 
195
- this.enforceEventCap(events[0].sessionId);
237
+ this.#enforceEventCap(events[0].sessionId);
196
238
  }
197
239
 
198
240
  /** Check last DEDUP_WINDOW events for same category + content hash */
199
- private isDuplicate(sessionId: string, category: string, dataHash: string): boolean {
200
- const row = this.db.prepare(
241
+ #isDuplicate(sessionId: string, category: string, dataHash: string): boolean {
242
+ const row = this.#db.prepare(
201
243
  `SELECT 1 FROM (
202
244
  SELECT category, data_hash FROM session_events
203
245
  WHERE session_id = ? ORDER BY id DESC LIMIT ?
@@ -207,15 +249,15 @@ export class EventStore {
207
249
  }
208
250
 
209
251
  /** Delete lowest-priority (highest number), then oldest events to stay at cap */
210
- private enforceEventCap(sessionId: string): void {
211
- const { count } = this.db.prepare(
252
+ #enforceEventCap(sessionId: string): void {
253
+ const { count } = this.#db.prepare(
212
254
  "SELECT COUNT(*) AS count FROM session_events WHERE session_id = ?",
213
255
  ).get(sessionId) as { count: number };
214
256
 
215
257
  if (count <= MAX_EVENTS_PER_SESSION) return;
216
258
 
217
259
  const excess = count - MAX_EVENTS_PER_SESSION;
218
- this.db.prepare(
260
+ this.#db.prepare(
219
261
  `DELETE FROM session_events WHERE id IN (
220
262
  SELECT id FROM session_events WHERE session_id = ?
221
263
  ORDER BY CAST(priority AS INTEGER) DESC, timestamp ASC
@@ -258,7 +300,7 @@ export class EventStore {
258
300
  params.push(filters.limit);
259
301
  }
260
302
 
261
- return this.db.prepare(sql).all(...params) as TrackedEvent[];
303
+ return this.#db.prepare(sql).all(...params) as TrackedEvent[];
262
304
  }
263
305
 
264
306
  searchEvents(sessionId: string, query: string, limit = 20): TrackedEvent[] {
@@ -271,11 +313,11 @@ export class EventStore {
271
313
  ORDER BY rank
272
314
  LIMIT ?
273
315
  `;
274
- return this.db.prepare(sql).all(query, sessionId, limit) as TrackedEvent[];
316
+ return this.#db.prepare(sql).all(query, sessionId, limit) as TrackedEvent[];
275
317
  }
276
318
 
277
319
  getEventCounts(sessionId: string): Record<EventCategory, number> {
278
- const rows = this.db.prepare(
320
+ const rows = this.#db.prepare(
279
321
  "SELECT category, COUNT(*) AS count FROM session_events WHERE session_id = ? GROUP BY category",
280
322
  ).all(sessionId) as Array<{ category: EventCategory; count: number }>;
281
323
 
@@ -288,7 +330,7 @@ export class EventStore {
288
330
  // ── Session metadata ────────────────────────────────────────
289
331
 
290
332
  upsertMeta(sessionId: string, projectDir: string): void {
291
- this.db.prepare(
333
+ this.#db.prepare(
292
334
  `INSERT INTO session_meta (session_id, project_dir, event_count)
293
335
  VALUES (?, ?, 0)
294
336
  ON CONFLICT(session_id) DO UPDATE SET
@@ -298,7 +340,7 @@ export class EventStore {
298
340
  }
299
341
 
300
342
  getMeta(sessionId: string): SessionMeta | null {
301
- const row = this.db.prepare(
343
+ const row = this.#db.prepare(
302
344
  `SELECT session_id AS sessionId, project_dir AS projectDir,
303
345
  started_at AS startedAt, last_event_at AS lastEventAt,
304
346
  event_count AS eventCount, compact_count AS compactCount
@@ -308,7 +350,7 @@ export class EventStore {
308
350
  }
309
351
 
310
352
  incrementCompactCount(sessionId: string): void {
311
- this.db.prepare(
353
+ this.#db.prepare(
312
354
  "UPDATE session_meta SET compact_count = compact_count + 1 WHERE session_id = ?",
313
355
  ).run(sessionId);
314
356
  }
@@ -316,7 +358,7 @@ export class EventStore {
316
358
  // ── Resume snapshots ────────────────────────────────────────
317
359
 
318
360
  upsertResume(sessionId: string, snapshot: string, eventCount: number): void {
319
- this.db.prepare(
361
+ this.#db.prepare(
320
362
  `INSERT INTO session_resume (session_id, snapshot, event_count, consumed)
321
363
  VALUES (?, ?, ?, 0)
322
364
  ON CONFLICT(session_id) DO UPDATE SET
@@ -328,7 +370,7 @@ export class EventStore {
328
370
  }
329
371
 
330
372
  getResume(sessionId: string): SessionResume | null {
331
- const row = this.db.prepare(
373
+ const row = this.#db.prepare(
332
374
  `SELECT session_id AS sessionId, snapshot, event_count AS eventCount,
333
375
  created_at AS createdAt, consumed
334
376
  FROM session_resume WHERE session_id = ? AND consumed = 0`,
@@ -338,7 +380,7 @@ export class EventStore {
338
380
  }
339
381
 
340
382
  consumeResume(sessionId: string): void {
341
- this.db.prepare(
383
+ this.#db.prepare(
342
384
  "UPDATE session_resume SET consumed = 1 WHERE session_id = ?",
343
385
  ).run(sessionId);
344
386
  }
@@ -346,11 +388,11 @@ export class EventStore {
346
388
  // ── Maintenance ─────────────────────────────────────────────
347
389
 
348
390
  pruneEvents(olderThan: number): number {
349
- const countRow = this.db.prepare(
391
+ const countRow = this.#db.prepare(
350
392
  "SELECT COUNT(*) AS count FROM session_events WHERE timestamp < ?",
351
393
  ).get(olderThan) as { count: number };
352
394
  if (countRow.count > 0) {
353
- this.db.prepare("DELETE FROM session_events WHERE timestamp < ?").run(olderThan);
395
+ this.#db.prepare("DELETE FROM session_events WHERE timestamp < ?").run(olderThan);
354
396
  }
355
397
  return countRow.count;
356
398
  }
@@ -359,7 +401,7 @@ export class EventStore {
359
401
  const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
360
402
  const pruned = this.pruneEvents(cutoff);
361
403
  // Remove orphaned metadata for sessions with no remaining events
362
- this.db.exec(`
404
+ this.#db.exec(`
363
405
  DELETE FROM session_meta WHERE session_id NOT IN (
364
406
  SELECT DISTINCT session_id FROM session_events
365
407
  );
@@ -371,6 +413,19 @@ export class EventStore {
371
413
  }
372
414
 
373
415
  close(): void {
374
- this.db.close();
416
+ if (this.#closed) return;
417
+
418
+ try {
419
+ try {
420
+ if (this.#getJournalMode() === "wal") {
421
+ this.#cleanupWalSidecars();
422
+ }
423
+ } catch {
424
+ // The DB path may already be gone during teardown; still close the handle.
425
+ }
426
+ } finally {
427
+ this.#db.close();
428
+ this.#closed = true;
429
+ }
375
430
  }
376
431
  }