@soleri/core 2.4.0 → 2.6.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 (328) hide show
  1. package/dist/brain/brain.d.ts +7 -0
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +56 -9
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +1 -0
  6. package/dist/brain/intelligence.d.ts.map +1 -1
  7. package/dist/brain/intelligence.js +164 -148
  8. package/dist/brain/intelligence.js.map +1 -1
  9. package/dist/brain/types.d.ts +2 -2
  10. package/dist/brain/types.d.ts.map +1 -1
  11. package/dist/cognee/client.d.ts +3 -0
  12. package/dist/cognee/client.d.ts.map +1 -1
  13. package/dist/cognee/client.js +17 -0
  14. package/dist/cognee/client.js.map +1 -1
  15. package/dist/cognee/sync-manager.d.ts +94 -0
  16. package/dist/cognee/sync-manager.d.ts.map +1 -0
  17. package/dist/cognee/sync-manager.js +293 -0
  18. package/dist/cognee/sync-manager.js.map +1 -0
  19. package/dist/control/identity-manager.d.ts +3 -1
  20. package/dist/control/identity-manager.d.ts.map +1 -1
  21. package/dist/control/identity-manager.js +49 -51
  22. package/dist/control/identity-manager.js.map +1 -1
  23. package/dist/control/intent-router.d.ts +1 -0
  24. package/dist/control/intent-router.d.ts.map +1 -1
  25. package/dist/control/intent-router.js +32 -32
  26. package/dist/control/intent-router.js.map +1 -1
  27. package/dist/curator/curator.d.ts +9 -1
  28. package/dist/curator/curator.d.ts.map +1 -1
  29. package/dist/curator/curator.js +104 -92
  30. package/dist/curator/curator.js.map +1 -1
  31. package/dist/errors/classify.d.ts +13 -0
  32. package/dist/errors/classify.d.ts.map +1 -0
  33. package/dist/errors/classify.js +97 -0
  34. package/dist/errors/classify.js.map +1 -0
  35. package/dist/errors/index.d.ts +6 -0
  36. package/dist/errors/index.d.ts.map +1 -0
  37. package/dist/errors/index.js +4 -0
  38. package/dist/errors/index.js.map +1 -0
  39. package/dist/errors/retry.d.ts +40 -0
  40. package/dist/errors/retry.d.ts.map +1 -0
  41. package/dist/errors/retry.js +97 -0
  42. package/dist/errors/retry.js.map +1 -0
  43. package/dist/errors/types.d.ts +48 -0
  44. package/dist/errors/types.d.ts.map +1 -0
  45. package/dist/errors/types.js +59 -0
  46. package/dist/errors/types.js.map +1 -0
  47. package/dist/governance/governance.d.ts +1 -0
  48. package/dist/governance/governance.d.ts.map +1 -1
  49. package/dist/governance/governance.js +51 -68
  50. package/dist/governance/governance.js.map +1 -1
  51. package/dist/index.d.ts +26 -5
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +22 -3
  54. package/dist/index.js.map +1 -1
  55. package/dist/intake/content-classifier.d.ts +14 -0
  56. package/dist/intake/content-classifier.d.ts.map +1 -0
  57. package/dist/intake/content-classifier.js +125 -0
  58. package/dist/intake/content-classifier.js.map +1 -0
  59. package/dist/intake/dedup-gate.d.ts +17 -0
  60. package/dist/intake/dedup-gate.d.ts.map +1 -0
  61. package/dist/intake/dedup-gate.js +66 -0
  62. package/dist/intake/dedup-gate.js.map +1 -0
  63. package/dist/intake/intake-pipeline.d.ts +63 -0
  64. package/dist/intake/intake-pipeline.d.ts.map +1 -0
  65. package/dist/intake/intake-pipeline.js +373 -0
  66. package/dist/intake/intake-pipeline.js.map +1 -0
  67. package/dist/intake/types.d.ts +65 -0
  68. package/dist/intake/types.d.ts.map +1 -0
  69. package/dist/intake/types.js +3 -0
  70. package/dist/intake/types.js.map +1 -0
  71. package/dist/intelligence/loader.js +1 -1
  72. package/dist/intelligence/loader.js.map +1 -1
  73. package/dist/intelligence/types.d.ts +3 -1
  74. package/dist/intelligence/types.d.ts.map +1 -1
  75. package/dist/loop/loop-manager.d.ts +58 -7
  76. package/dist/loop/loop-manager.d.ts.map +1 -1
  77. package/dist/loop/loop-manager.js +280 -6
  78. package/dist/loop/loop-manager.js.map +1 -1
  79. package/dist/loop/types.d.ts +69 -1
  80. package/dist/loop/types.d.ts.map +1 -1
  81. package/dist/loop/types.js +4 -1
  82. package/dist/loop/types.js.map +1 -1
  83. package/dist/persistence/index.d.ts +4 -0
  84. package/dist/persistence/index.d.ts.map +1 -0
  85. package/dist/persistence/index.js +3 -0
  86. package/dist/persistence/index.js.map +1 -0
  87. package/dist/persistence/postgres-provider.d.ts +46 -0
  88. package/dist/persistence/postgres-provider.d.ts.map +1 -0
  89. package/dist/persistence/postgres-provider.js +115 -0
  90. package/dist/persistence/postgres-provider.js.map +1 -0
  91. package/dist/persistence/sqlite-provider.d.ts +28 -0
  92. package/dist/persistence/sqlite-provider.d.ts.map +1 -0
  93. package/dist/persistence/sqlite-provider.js +97 -0
  94. package/dist/persistence/sqlite-provider.js.map +1 -0
  95. package/dist/persistence/types.d.ts +58 -0
  96. package/dist/persistence/types.d.ts.map +1 -0
  97. package/dist/persistence/types.js +8 -0
  98. package/dist/persistence/types.js.map +1 -0
  99. package/dist/planning/gap-analysis.d.ts +47 -4
  100. package/dist/planning/gap-analysis.d.ts.map +1 -1
  101. package/dist/planning/gap-analysis.js +190 -13
  102. package/dist/planning/gap-analysis.js.map +1 -1
  103. package/dist/planning/gap-types.d.ts +1 -1
  104. package/dist/planning/gap-types.d.ts.map +1 -1
  105. package/dist/planning/gap-types.js.map +1 -1
  106. package/dist/planning/planner.d.ts +277 -9
  107. package/dist/planning/planner.d.ts.map +1 -1
  108. package/dist/planning/planner.js +611 -46
  109. package/dist/planning/planner.js.map +1 -1
  110. package/dist/playbooks/generic/brainstorming.d.ts +9 -0
  111. package/dist/playbooks/generic/brainstorming.d.ts.map +1 -0
  112. package/dist/playbooks/generic/brainstorming.js +105 -0
  113. package/dist/playbooks/generic/brainstorming.js.map +1 -0
  114. package/dist/playbooks/generic/code-review.d.ts +11 -0
  115. package/dist/playbooks/generic/code-review.d.ts.map +1 -0
  116. package/dist/playbooks/generic/code-review.js +176 -0
  117. package/dist/playbooks/generic/code-review.js.map +1 -0
  118. package/dist/playbooks/generic/subagent-execution.d.ts +9 -0
  119. package/dist/playbooks/generic/subagent-execution.d.ts.map +1 -0
  120. package/dist/playbooks/generic/subagent-execution.js +68 -0
  121. package/dist/playbooks/generic/subagent-execution.js.map +1 -0
  122. package/dist/playbooks/generic/systematic-debugging.d.ts +9 -0
  123. package/dist/playbooks/generic/systematic-debugging.d.ts.map +1 -0
  124. package/dist/playbooks/generic/systematic-debugging.js +87 -0
  125. package/dist/playbooks/generic/systematic-debugging.js.map +1 -0
  126. package/dist/playbooks/generic/tdd.d.ts +9 -0
  127. package/dist/playbooks/generic/tdd.d.ts.map +1 -0
  128. package/dist/playbooks/generic/tdd.js +70 -0
  129. package/dist/playbooks/generic/tdd.js.map +1 -0
  130. package/dist/playbooks/generic/verification.d.ts +9 -0
  131. package/dist/playbooks/generic/verification.d.ts.map +1 -0
  132. package/dist/playbooks/generic/verification.js +74 -0
  133. package/dist/playbooks/generic/verification.js.map +1 -0
  134. package/dist/playbooks/index.d.ts +4 -0
  135. package/dist/playbooks/index.d.ts.map +1 -0
  136. package/dist/playbooks/index.js +5 -0
  137. package/dist/playbooks/index.js.map +1 -0
  138. package/dist/playbooks/playbook-registry.d.ts +42 -0
  139. package/dist/playbooks/playbook-registry.d.ts.map +1 -0
  140. package/dist/playbooks/playbook-registry.js +227 -0
  141. package/dist/playbooks/playbook-registry.js.map +1 -0
  142. package/dist/playbooks/playbook-seeder.d.ts +47 -0
  143. package/dist/playbooks/playbook-seeder.d.ts.map +1 -0
  144. package/dist/playbooks/playbook-seeder.js +104 -0
  145. package/dist/playbooks/playbook-seeder.js.map +1 -0
  146. package/dist/playbooks/playbook-types.d.ts +132 -0
  147. package/dist/playbooks/playbook-types.d.ts.map +1 -0
  148. package/dist/playbooks/playbook-types.js +12 -0
  149. package/dist/playbooks/playbook-types.js.map +1 -0
  150. package/dist/project/project-registry.d.ts +4 -4
  151. package/dist/project/project-registry.d.ts.map +1 -1
  152. package/dist/project/project-registry.js +30 -57
  153. package/dist/project/project-registry.js.map +1 -1
  154. package/dist/prompts/index.d.ts +4 -0
  155. package/dist/prompts/index.d.ts.map +1 -0
  156. package/dist/prompts/index.js +3 -0
  157. package/dist/prompts/index.js.map +1 -0
  158. package/dist/prompts/parser.d.ts +17 -0
  159. package/dist/prompts/parser.d.ts.map +1 -0
  160. package/dist/prompts/parser.js +47 -0
  161. package/dist/prompts/parser.js.map +1 -0
  162. package/dist/prompts/template-manager.d.ts +25 -0
  163. package/dist/prompts/template-manager.d.ts.map +1 -0
  164. package/dist/prompts/template-manager.js +71 -0
  165. package/dist/prompts/template-manager.js.map +1 -0
  166. package/dist/prompts/types.d.ts +26 -0
  167. package/dist/prompts/types.d.ts.map +1 -0
  168. package/dist/prompts/types.js +5 -0
  169. package/dist/prompts/types.js.map +1 -0
  170. package/dist/runtime/admin-extra-ops.d.ts +5 -3
  171. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  172. package/dist/runtime/admin-extra-ops.js +348 -11
  173. package/dist/runtime/admin-extra-ops.js.map +1 -1
  174. package/dist/runtime/admin-ops.d.ts.map +1 -1
  175. package/dist/runtime/admin-ops.js +10 -3
  176. package/dist/runtime/admin-ops.js.map +1 -1
  177. package/dist/runtime/capture-ops.d.ts.map +1 -1
  178. package/dist/runtime/capture-ops.js +20 -2
  179. package/dist/runtime/capture-ops.js.map +1 -1
  180. package/dist/runtime/cognee-sync-ops.d.ts +12 -0
  181. package/dist/runtime/cognee-sync-ops.d.ts.map +1 -0
  182. package/dist/runtime/cognee-sync-ops.js +55 -0
  183. package/dist/runtime/cognee-sync-ops.js.map +1 -0
  184. package/dist/runtime/core-ops.d.ts +8 -6
  185. package/dist/runtime/core-ops.d.ts.map +1 -1
  186. package/dist/runtime/core-ops.js +226 -9
  187. package/dist/runtime/core-ops.js.map +1 -1
  188. package/dist/runtime/curator-extra-ops.d.ts +2 -2
  189. package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
  190. package/dist/runtime/curator-extra-ops.js +15 -3
  191. package/dist/runtime/curator-extra-ops.js.map +1 -1
  192. package/dist/runtime/domain-ops.js +2 -2
  193. package/dist/runtime/domain-ops.js.map +1 -1
  194. package/dist/runtime/grading-ops.d.ts.map +1 -1
  195. package/dist/runtime/grading-ops.js.map +1 -1
  196. package/dist/runtime/intake-ops.d.ts +14 -0
  197. package/dist/runtime/intake-ops.d.ts.map +1 -0
  198. package/dist/runtime/intake-ops.js +110 -0
  199. package/dist/runtime/intake-ops.js.map +1 -0
  200. package/dist/runtime/loop-ops.d.ts +5 -4
  201. package/dist/runtime/loop-ops.d.ts.map +1 -1
  202. package/dist/runtime/loop-ops.js +84 -12
  203. package/dist/runtime/loop-ops.js.map +1 -1
  204. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -1
  205. package/dist/runtime/memory-cross-project-ops.js.map +1 -1
  206. package/dist/runtime/memory-extra-ops.js +5 -5
  207. package/dist/runtime/memory-extra-ops.js.map +1 -1
  208. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  209. package/dist/runtime/orchestrate-ops.js +8 -2
  210. package/dist/runtime/orchestrate-ops.js.map +1 -1
  211. package/dist/runtime/planning-extra-ops.d.ts +13 -5
  212. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  213. package/dist/runtime/planning-extra-ops.js +381 -18
  214. package/dist/runtime/planning-extra-ops.js.map +1 -1
  215. package/dist/runtime/playbook-ops.d.ts +14 -0
  216. package/dist/runtime/playbook-ops.d.ts.map +1 -0
  217. package/dist/runtime/playbook-ops.js +141 -0
  218. package/dist/runtime/playbook-ops.js.map +1 -0
  219. package/dist/runtime/project-ops.d.ts.map +1 -1
  220. package/dist/runtime/project-ops.js +7 -2
  221. package/dist/runtime/project-ops.js.map +1 -1
  222. package/dist/runtime/runtime.d.ts.map +1 -1
  223. package/dist/runtime/runtime.js +28 -9
  224. package/dist/runtime/runtime.js.map +1 -1
  225. package/dist/runtime/types.d.ts +8 -0
  226. package/dist/runtime/types.d.ts.map +1 -1
  227. package/dist/runtime/vault-extra-ops.d.ts +4 -2
  228. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  229. package/dist/runtime/vault-extra-ops.js +383 -4
  230. package/dist/runtime/vault-extra-ops.js.map +1 -1
  231. package/dist/vault/playbook.d.ts +34 -0
  232. package/dist/vault/playbook.d.ts.map +1 -0
  233. package/dist/vault/playbook.js +60 -0
  234. package/dist/vault/playbook.js.map +1 -0
  235. package/dist/vault/vault.d.ts +52 -32
  236. package/dist/vault/vault.d.ts.map +1 -1
  237. package/dist/vault/vault.js +300 -181
  238. package/dist/vault/vault.js.map +1 -1
  239. package/package.json +9 -3
  240. package/src/__tests__/admin-extra-ops.test.ts +62 -15
  241. package/src/__tests__/admin-ops.test.ts +2 -2
  242. package/src/__tests__/brain.test.ts +3 -3
  243. package/src/__tests__/cognee-integration.test.ts +80 -0
  244. package/src/__tests__/cognee-sync-manager.test.ts +103 -0
  245. package/src/__tests__/core-ops.test.ts +36 -4
  246. package/src/__tests__/curator-extra-ops.test.ts +24 -2
  247. package/src/__tests__/errors.test.ts +388 -0
  248. package/src/__tests__/grading-ops.test.ts +28 -7
  249. package/src/__tests__/intake-pipeline.test.ts +162 -0
  250. package/src/__tests__/loop-ops.test.ts +74 -3
  251. package/src/__tests__/memory-cross-project-ops.test.ts +3 -1
  252. package/src/__tests__/orchestrate-ops.test.ts +8 -3
  253. package/src/__tests__/persistence.test.ts +291 -0
  254. package/src/__tests__/planner.test.ts +99 -21
  255. package/src/__tests__/planning-extra-ops.test.ts +168 -10
  256. package/src/__tests__/playbook-registry.test.ts +326 -0
  257. package/src/__tests__/playbook-seeder.test.ts +163 -0
  258. package/src/__tests__/playbook.test.ts +389 -0
  259. package/src/__tests__/postgres-provider.test.ts +58 -0
  260. package/src/__tests__/project-ops.test.ts +18 -4
  261. package/src/__tests__/template-manager.test.ts +222 -0
  262. package/src/__tests__/vault-extra-ops.test.ts +82 -7
  263. package/src/__tests__/vault.test.ts +184 -0
  264. package/src/brain/brain.ts +71 -9
  265. package/src/brain/intelligence.ts +258 -307
  266. package/src/brain/types.ts +2 -2
  267. package/src/cognee/client.ts +18 -0
  268. package/src/cognee/sync-manager.ts +389 -0
  269. package/src/control/identity-manager.ts +77 -75
  270. package/src/control/intent-router.ts +55 -57
  271. package/src/curator/curator.ts +199 -139
  272. package/src/errors/classify.ts +102 -0
  273. package/src/errors/index.ts +5 -0
  274. package/src/errors/retry.ts +132 -0
  275. package/src/errors/types.ts +81 -0
  276. package/src/governance/governance.ts +90 -107
  277. package/src/index.ts +116 -3
  278. package/src/intake/content-classifier.ts +146 -0
  279. package/src/intake/dedup-gate.ts +92 -0
  280. package/src/intake/intake-pipeline.ts +503 -0
  281. package/src/intake/types.ts +69 -0
  282. package/src/intelligence/loader.ts +1 -1
  283. package/src/intelligence/types.ts +3 -1
  284. package/src/loop/loop-manager.ts +325 -7
  285. package/src/loop/types.ts +72 -1
  286. package/src/persistence/index.ts +9 -0
  287. package/src/persistence/postgres-provider.ts +157 -0
  288. package/src/persistence/sqlite-provider.ts +115 -0
  289. package/src/persistence/types.ts +74 -0
  290. package/src/planning/gap-analysis.ts +286 -17
  291. package/src/planning/gap-types.ts +4 -1
  292. package/src/planning/planner.ts +828 -55
  293. package/src/playbooks/generic/brainstorming.ts +110 -0
  294. package/src/playbooks/generic/code-review.ts +181 -0
  295. package/src/playbooks/generic/subagent-execution.ts +74 -0
  296. package/src/playbooks/generic/systematic-debugging.ts +92 -0
  297. package/src/playbooks/generic/tdd.ts +75 -0
  298. package/src/playbooks/generic/verification.ts +79 -0
  299. package/src/playbooks/index.ts +27 -0
  300. package/src/playbooks/playbook-registry.ts +284 -0
  301. package/src/playbooks/playbook-seeder.ts +119 -0
  302. package/src/playbooks/playbook-types.ts +162 -0
  303. package/src/project/project-registry.ts +81 -74
  304. package/src/prompts/index.ts +3 -0
  305. package/src/prompts/parser.ts +59 -0
  306. package/src/prompts/template-manager.ts +77 -0
  307. package/src/prompts/types.ts +28 -0
  308. package/src/runtime/admin-extra-ops.ts +391 -13
  309. package/src/runtime/admin-ops.ts +17 -6
  310. package/src/runtime/capture-ops.ts +25 -6
  311. package/src/runtime/cognee-sync-ops.ts +63 -0
  312. package/src/runtime/core-ops.ts +258 -8
  313. package/src/runtime/curator-extra-ops.ts +17 -3
  314. package/src/runtime/domain-ops.ts +2 -2
  315. package/src/runtime/grading-ops.ts +11 -2
  316. package/src/runtime/intake-ops.ts +126 -0
  317. package/src/runtime/loop-ops.ts +96 -13
  318. package/src/runtime/memory-cross-project-ops.ts +1 -2
  319. package/src/runtime/memory-extra-ops.ts +5 -5
  320. package/src/runtime/orchestrate-ops.ts +8 -2
  321. package/src/runtime/planning-extra-ops.ts +414 -23
  322. package/src/runtime/playbook-ops.ts +169 -0
  323. package/src/runtime/project-ops.ts +9 -3
  324. package/src/runtime/runtime.ts +36 -10
  325. package/src/runtime/types.ts +8 -0
  326. package/src/runtime/vault-extra-ops.ts +425 -4
  327. package/src/vault/playbook.ts +87 -0
  328. package/src/vault/vault.ts +419 -235
@@ -0,0 +1,115 @@
1
+ /**
2
+ * SQLite persistence provider backed by better-sqlite3.
3
+ *
4
+ * Supports both positional (array) and named (object) parameters.
5
+ * Exposes getDatabase() for backward-compat consumers that need the raw db.
6
+ */
7
+
8
+ import Database from 'better-sqlite3';
9
+ import { mkdirSync } from 'node:fs';
10
+ import { dirname } from 'node:path';
11
+ import type {
12
+ PersistenceProvider,
13
+ PersistenceParams,
14
+ RunResult,
15
+ FtsSearchOptions,
16
+ } from './types.js';
17
+
18
+ export class SQLitePersistenceProvider implements PersistenceProvider {
19
+ readonly backend = 'sqlite' as const;
20
+ private db: Database.Database;
21
+
22
+ constructor(path: string = ':memory:') {
23
+ if (path !== ':memory:') mkdirSync(dirname(path), { recursive: true });
24
+ this.db = new Database(path);
25
+ if (path !== ':memory:') {
26
+ this.db.pragma('cache_size = -64000'); // 64MB
27
+ this.db.pragma('temp_store = MEMORY');
28
+ this.db.pragma('mmap_size = 268435456'); // 256MB
29
+ }
30
+ }
31
+
32
+ execSql(sql: string): void {
33
+ this.db.exec(sql);
34
+ }
35
+
36
+ run(sql: string, params?: PersistenceParams): RunResult {
37
+ const stmt = this.db.prepare(sql);
38
+ if (!params) return stmt.run();
39
+ if (Array.isArray(params)) return stmt.run(...params);
40
+ return stmt.run(params);
41
+ }
42
+
43
+ get<T = Record<string, unknown>>(sql: string, params?: PersistenceParams): T | undefined {
44
+ const stmt = this.db.prepare(sql);
45
+ if (!params) return stmt.get() as T | undefined;
46
+ if (Array.isArray(params)) return stmt.get(...params) as T | undefined;
47
+ return stmt.get(params) as T | undefined;
48
+ }
49
+
50
+ all<T = Record<string, unknown>>(sql: string, params?: PersistenceParams): T[] {
51
+ const stmt = this.db.prepare(sql);
52
+ if (!params) return stmt.all() as T[];
53
+ if (Array.isArray(params)) return stmt.all(...params) as T[];
54
+ return stmt.all(params) as T[];
55
+ }
56
+
57
+ transaction<T>(fn: () => T): T {
58
+ return this.db.transaction(fn)();
59
+ }
60
+
61
+ ftsSearch<T = Record<string, unknown>>(
62
+ table: string,
63
+ query: string,
64
+ options?: FtsSearchOptions,
65
+ ): T[] {
66
+ const ftsTable = `${table}_fts`;
67
+ const cols = options?.columns?.length ? options.columns.join(', ') : `${table}.*`;
68
+ const orderBy = options?.orderByRank !== false ? `ORDER BY rank` : '';
69
+ const limit = options?.limit ? `LIMIT ${options.limit}` : '';
70
+ const offset = options?.offset ? `OFFSET ${options.offset}` : '';
71
+
72
+ const filterClauses: string[] = [];
73
+ const filterParams: unknown[] = [query];
74
+
75
+ if (options?.filters) {
76
+ for (const [key, value] of Object.entries(options.filters)) {
77
+ filterClauses.push(`${table}.${key} = ?`);
78
+ filterParams.push(value);
79
+ }
80
+ }
81
+
82
+ const filterSql = filterClauses.length ? `AND ${filterClauses.join(' AND ')}` : '';
83
+
84
+ const sql = `SELECT ${cols} FROM ${ftsTable} JOIN ${table} ON ${table}.rowid = ${ftsTable}.rowid WHERE ${ftsTable} MATCH ? ${filterSql} ${orderBy} ${limit} ${offset}`;
85
+
86
+ return this.all<T>(sql, filterParams);
87
+ }
88
+
89
+ ftsRebuild(table: string): void {
90
+ const ftsTable = `${table}_fts`;
91
+ try {
92
+ this.execSql(`INSERT INTO ${ftsTable}(${ftsTable}) VALUES('rebuild')`);
93
+ } catch {
94
+ // Graceful degradation: FTS table may not exist
95
+ }
96
+ }
97
+
98
+ close(): void {
99
+ this.db.close();
100
+ }
101
+
102
+ /**
103
+ * Escape hatch: get the raw better-sqlite3 Database.
104
+ * Used by modules that need direct db access (ProjectRegistry, BrainIntelligence, etc.).
105
+ * @deprecated Use provider methods instead.
106
+ */
107
+ getDatabase(): Database.Database {
108
+ if (process.env.NODE_ENV !== 'test' && process.env.VITEST !== 'true') {
109
+ console.warn(
110
+ 'SQLitePersistenceProvider.getDatabase() is deprecated. Use provider methods instead.',
111
+ );
112
+ }
113
+ return this.db;
114
+ }
115
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Abstract persistence layer.
3
+ *
4
+ * Decouples Vault (and future modules) from any specific database engine.
5
+ * The default implementation is SQLitePersistenceProvider (better-sqlite3).
6
+ */
7
+
8
+ export type PersistenceParams = unknown[] | Record<string, unknown>;
9
+
10
+ export interface RunResult {
11
+ changes: number;
12
+ lastInsertRowid: number | bigint;
13
+ }
14
+
15
+ /**
16
+ * Minimal database provider interface.
17
+ *
18
+ * Supports both positional (`?`) and named (`@param`) parameter styles.
19
+ * Implementations must handle both array and object params.
20
+ */
21
+ export interface PersistenceProvider {
22
+ /** Run raw SQL (DDL, multi-statement). No return value. */
23
+ execSql(sql: string): void;
24
+
25
+ /** Run a parameterized statement (INSERT, UPDATE, DELETE). */
26
+ run(sql: string, params?: PersistenceParams): RunResult;
27
+
28
+ /** Get a single row. Returns undefined if no match. */
29
+ get<T = Record<string, unknown>>(sql: string, params?: PersistenceParams): T | undefined;
30
+
31
+ /** Get all matching rows. */
32
+ all<T = Record<string, unknown>>(sql: string, params?: PersistenceParams): T[];
33
+
34
+ /** Run a function inside a transaction. Commits on success, rolls back on error. */
35
+ transaction<T>(fn: () => T): T;
36
+
37
+ /** Identifies the backend engine. */
38
+ readonly backend: 'sqlite' | 'postgres';
39
+
40
+ /** Full-text search abstraction. */
41
+ ftsSearch<T = Record<string, unknown>>(
42
+ table: string,
43
+ query: string,
44
+ options?: FtsSearchOptions,
45
+ ): T[];
46
+
47
+ /** Rebuild FTS index for a table. */
48
+ ftsRebuild(table: string): void;
49
+
50
+ /** Close the connection. */
51
+ close(): void;
52
+ }
53
+
54
+ export interface PersistenceConfig {
55
+ type: 'sqlite' | 'postgres';
56
+ path: string;
57
+ /** PostgreSQL connection string. */
58
+ connectionString?: string;
59
+ /** PostgreSQL pool size. */
60
+ poolSize?: number;
61
+ }
62
+
63
+ export interface FtsSearchOptions {
64
+ /** Columns to search (default: all FTS columns). */
65
+ columns?: string[];
66
+ /** Max results. */
67
+ limit?: number;
68
+ /** Skip N results. */
69
+ offset?: number;
70
+ /** Additional WHERE conditions on the base table. */
71
+ filters?: Record<string, unknown>;
72
+ /** Order by FTS relevance rank (default: true). */
73
+ orderByRank?: boolean;
74
+ }
@@ -1,17 +1,23 @@
1
1
  /**
2
- * 6-pass gap analysis engine for plan grading.
3
- * Ported from Salvador MCP's plan-gap-content.ts / plan-gap-technical.ts.
2
+ * Gap analysis engine for plan grading.
3
+ * Ported from Salvador MCP's plan-gap-content.ts / plan-gap-technical.ts /
4
+ * plan-gap-domain.ts / plan-gap-antipattern.ts.
4
5
  *
5
- * Passes:
6
+ * 6 built-in passes (always run):
6
7
  * 1. Structure — required fields present and sufficiently long
7
8
  * 2. Completeness — measurable objectives, decision rationale, scope exclusions
8
9
  * 3. Feasibility — overly broad scope, missing dependency awareness
9
10
  * 4. Risk — breaking changes without mitigation, missing verification
10
11
  * 5. Clarity — ambiguous language, vague criteria
11
12
  * 6. Semantic Quality — generic objectives, shallow rationale, non-concrete approach
13
+ *
14
+ * Opt-in pass factories (registered via customPasses):
15
+ * - createToolFeasibilityPass — validates tool_chain entries and ordering
16
+ * - createFlowAlignmentPass — validates flow and target_mode against registries
17
+ * - createAntiPatternPass — detects content anti-patterns and vague criteria
12
18
  */
13
19
 
14
- import type { Plan } from './planner.js';
20
+ import type { Plan, PlanDecision } from './planner.js';
15
21
  import type { PlanGap, GapSeverity, GapCategory } from './gap-types.js';
16
22
  import {
17
23
  generateGapId,
@@ -46,6 +52,16 @@ function taskText(plan: Plan): string {
46
52
  return plan.tasks.map((t) => `${t.title} ${t.description}`).join(' ');
47
53
  }
48
54
 
55
+ /** Extract text from a decision (supports both string and structured format). */
56
+ function decisionText(d: string | PlanDecision): string {
57
+ return typeof d === 'string' ? d : `${d.decision} ${d.rationale}`;
58
+ }
59
+
60
+ /** Combine all decisions into a single text blob. */
61
+ function decisionsText(plan: Plan): string {
62
+ return plan.decisions.map(decisionText).join(' ');
63
+ }
64
+
49
65
  /** Check if text contains any of the given patterns (case-insensitive). */
50
66
  function containsAny(text: string, patterns: string[]): boolean {
51
67
  const lower = text.toLowerCase();
@@ -118,7 +134,16 @@ const METRIC_PATTERNS = [
118
134
  /benchmark/i,
119
135
  ];
120
136
 
121
- const EXCLUSION_KEYWORDS = ['not', 'exclude', 'outside', 'beyond', 'limit', 'except', 'won\'t', 'will not'];
137
+ const EXCLUSION_KEYWORDS = [
138
+ 'not',
139
+ 'exclude',
140
+ 'outside',
141
+ 'beyond',
142
+ 'limit',
143
+ 'except',
144
+ "won't",
145
+ 'will not',
146
+ ];
122
147
 
123
148
  function analyzeCompleteness(plan: Plan): PlanGap[] {
124
149
  const gaps: PlanGap[] = [];
@@ -141,12 +166,13 @@ function analyzeCompleteness(plan: Plan): PlanGap[] {
141
166
  if (plan.decisions.length > 0) {
142
167
  for (let i = 0; i < plan.decisions.length; i++) {
143
168
  const d = plan.decisions[i];
144
- if (d.trim().length < MIN_DECISION_LENGTH) {
169
+ const text = decisionText(d);
170
+ if (text.trim().length < MIN_DECISION_LENGTH) {
145
171
  gaps.push(
146
172
  gap(
147
173
  'major',
148
174
  'completeness',
149
- `Decision ${i + 1} is too short (${d.trim().length} chars) — lacks rationale.`,
175
+ `Decision ${i + 1} is too short (${text.trim().length} chars) — lacks rationale.`,
150
176
  'Expand each decision to include the reasoning (why this choice over alternatives).',
151
177
  `decisions[${i}]`,
152
178
  'short_decision',
@@ -185,7 +211,14 @@ const OVERLY_BROAD_PATTERNS = [
185
211
  'rewrite everything',
186
212
  ];
187
213
 
188
- const DEPENDENCY_KEYWORDS = ['depends', 'dependency', 'prerequisite', 'requires', 'blocked', 'before'];
214
+ const DEPENDENCY_KEYWORDS = [
215
+ 'depends',
216
+ 'dependency',
217
+ 'prerequisite',
218
+ 'requires',
219
+ 'blocked',
220
+ 'before',
221
+ ];
189
222
 
190
223
  function analyzeFeasibility(plan: Plan): PlanGap[] {
191
224
  const gaps: PlanGap[] = [];
@@ -251,14 +284,26 @@ const MITIGATION_KEYWORDS = [
251
284
  'blue-green',
252
285
  ];
253
286
 
254
- const VERIFICATION_KEYWORDS = ['test', 'verify', 'validate', 'check', 'assert', 'confirm', 'spec', 'coverage'];
287
+ const VERIFICATION_KEYWORDS = [
288
+ 'test',
289
+ 'verify',
290
+ 'validate',
291
+ 'check',
292
+ 'assert',
293
+ 'confirm',
294
+ 'spec',
295
+ 'coverage',
296
+ ];
255
297
 
256
298
  function analyzeRisk(plan: Plan): PlanGap[] {
257
299
  const gaps: PlanGap[] = [];
258
- const allText = `${plan.objective} ${plan.scope} ${taskText(plan)} ${plan.decisions.join(' ')}`;
300
+ const allText = `${plan.objective} ${plan.scope} ${taskText(plan)} ${decisionsText(plan)}`;
259
301
 
260
302
  // Breaking changes without mitigation
261
- if (containsAny(allText, BREAKING_CHANGE_KEYWORDS) && !containsAny(allText, MITIGATION_KEYWORDS)) {
303
+ if (
304
+ containsAny(allText, BREAKING_CHANGE_KEYWORDS) &&
305
+ !containsAny(allText, MITIGATION_KEYWORDS)
306
+ ) {
262
307
  gaps.push(
263
308
  gap(
264
309
  'major',
@@ -310,7 +355,7 @@ const AMBIGUOUS_WORDS = [
310
355
 
311
356
  function analyzeClarity(plan: Plan): PlanGap[] {
312
357
  const gaps: PlanGap[] = [];
313
- const allText = `${plan.objective} ${plan.scope} ${plan.decisions.join(' ')}`;
358
+ const allText = `${plan.objective} ${plan.scope} ${decisionsText(plan)}`;
314
359
  const lower = allText.toLowerCase();
315
360
 
316
361
  // Ambiguous language
@@ -333,9 +378,7 @@ function analyzeClarity(plan: Plan): PlanGap[] {
333
378
  }
334
379
 
335
380
  // Tasks with very short or missing descriptions
336
- const shortTasks = plan.tasks.filter(
337
- (t) => !t.description || t.description.trim().length < 10,
338
- );
381
+ const shortTasks = plan.tasks.filter((t) => !t.description || t.description.trim().length < 10);
339
382
  if (shortTasks.length > 0) {
340
383
  gaps.push(
341
384
  gap(
@@ -360,7 +403,15 @@ const GENERIC_OBJECTIVE_PATTERNS = [
360
403
  /^update\s+\w+$/i,
361
404
  ];
362
405
 
363
- const RATIONALE_INDICATORS = ['because', 'since', 'due to', 'in order to', 'so that', 'given that', 'as a result'];
406
+ const RATIONALE_INDICATORS = [
407
+ 'because',
408
+ 'since',
409
+ 'due to',
410
+ 'in order to',
411
+ 'so that',
412
+ 'given that',
413
+ 'as a result',
414
+ ];
364
415
  const SHALLOW_INDICATORS = ['better', 'good', 'best', 'nice', 'great', 'improved'];
365
416
 
366
417
  function analyzeSemanticQuality(plan: Plan): PlanGap[] {
@@ -412,7 +463,7 @@ function analyzeSemanticQuality(plan: Plan): PlanGap[] {
412
463
 
413
464
  // Decisions with shallow rationale (uses "better/good" without "because/since")
414
465
  for (let i = 0; i < plan.decisions.length; i++) {
415
- const d = plan.decisions[i];
466
+ const d = decisionText(plan.decisions[i]);
416
467
  const hasShallow = containsAny(d, SHALLOW_INDICATORS);
417
468
  const hasRationale = containsAny(d, RATIONALE_INDICATORS);
418
469
  if (hasShallow && !hasRationale) {
@@ -476,6 +527,224 @@ export interface GapAnalysisOptions {
476
527
  customPasses?: GapAnalysisPass[];
477
528
  }
478
529
 
530
+ // ─── Opt-In Pass Factories ──────────────────────────────────────
531
+ // Ported from Salvador's plan-gap-technical.ts, plan-gap-domain.ts,
532
+ // and plan-gap-antipattern.ts. These are parameterized factories that
533
+ // agents register via customPasses.
534
+
535
+ /**
536
+ * Factory: tool chain feasibility pass.
537
+ * Validates that tool_chain entries are known and ordering rules are respected.
538
+ * Ported from Salvador's analyzeToolFeasibility.
539
+ *
540
+ * @param validTools - Set of valid tool names for this agent
541
+ * @param orderingRules - Ordering constraints (e.g., search before create)
542
+ */
543
+ export function createToolFeasibilityPass(
544
+ validTools: Set<string>,
545
+ orderingRules?: Array<{ before: string; after: string; reason: string }>,
546
+ ): GapAnalysisPass {
547
+ return (plan: Plan) => {
548
+ const gaps: PlanGap[] = [];
549
+ const toolChain = plan.tool_chain;
550
+ if (!toolChain || toolChain.length === 0) return gaps;
551
+
552
+ // Validate tool names
553
+ const invalidTools = toolChain.filter((t) => !validTools.has(t));
554
+ if (invalidTools.length > 0) {
555
+ gaps.push(
556
+ gap(
557
+ 'critical',
558
+ 'tool-feasibility',
559
+ `Invalid tool names in tool_chain: ${invalidTools.join(', ')}`,
560
+ 'Use valid tool names. Check available tools for this agent.',
561
+ 'tool_chain',
562
+ `invalid_tools:${invalidTools.join(',')}`,
563
+ ),
564
+ );
565
+ }
566
+
567
+ // Validate ordering rules
568
+ if (orderingRules) {
569
+ for (const rule of orderingRules) {
570
+ const beforeIndex = toolChain.indexOf(rule.before);
571
+ const afterIndex = toolChain.indexOf(rule.after);
572
+ if (beforeIndex !== -1 && afterIndex !== -1 && beforeIndex > afterIndex) {
573
+ gaps.push(
574
+ gap(
575
+ 'major',
576
+ 'tool-feasibility',
577
+ `Tool ordering violation: ${rule.before} must come before ${rule.after}`,
578
+ rule.reason,
579
+ 'tool_chain',
580
+ `ordering:${rule.before}>${rule.after}`,
581
+ ),
582
+ );
583
+ }
584
+ }
585
+ }
586
+
587
+ return gaps;
588
+ };
589
+ }
590
+
591
+ /**
592
+ * Factory: flow and mode alignment pass.
593
+ * Validates flow and target_mode against known values and intent alignment.
594
+ * Ported from Salvador's analyzeFlowAlignment.
595
+ *
596
+ * @param validFlows - Set of valid flow names for this agent
597
+ * @param validModes - Set of valid operational modes for this agent
598
+ * @param intentFlowMap - Maps detected intents to expected flows
599
+ */
600
+ export function createFlowAlignmentPass(
601
+ validFlows: Set<string>,
602
+ validModes: Set<string>,
603
+ intentFlowMap?: Record<string, string[]>,
604
+ ): GapAnalysisPass {
605
+ return (plan: Plan) => {
606
+ const gaps: PlanGap[] = [];
607
+
608
+ if (plan.flow && !validFlows.has(plan.flow)) {
609
+ gaps.push(
610
+ gap(
611
+ 'major',
612
+ 'flow-alignment',
613
+ `Invalid flow: ${plan.flow}`,
614
+ `Valid flows are: ${Array.from(validFlows).join(', ')}`,
615
+ 'flow',
616
+ `invalid_flow:${plan.flow}`,
617
+ ),
618
+ );
619
+ }
620
+
621
+ if (plan.target_mode && !validModes.has(plan.target_mode)) {
622
+ gaps.push(
623
+ gap(
624
+ 'major',
625
+ 'flow-alignment',
626
+ `Invalid target_mode: ${plan.target_mode}`,
627
+ `Valid modes are: ${Array.from(validModes).join(', ')}`,
628
+ 'target_mode',
629
+ `invalid_mode:${plan.target_mode}`,
630
+ ),
631
+ );
632
+ }
633
+
634
+ // Intent-flow alignment (optional)
635
+ if (intentFlowMap && plan.flow) {
636
+ const objectiveLower = (plan.objective || '').toLowerCase();
637
+ let detectedIntent: string | null = null;
638
+
639
+ if (/\b(create|build|implement|add|new)\b/.test(objectiveLower)) {
640
+ detectedIntent = 'CREATE';
641
+ } else if (/\b(fix|debug|repair|resolve|bug)\b/.test(objectiveLower)) {
642
+ detectedIntent = 'FIX';
643
+ } else if (/\b(review|audit|check|validate|inspect)\b/.test(objectiveLower)) {
644
+ detectedIntent = 'REVIEW';
645
+ } else if (/\b(plan|design|architect|structure)\b/.test(objectiveLower)) {
646
+ detectedIntent = 'PLAN';
647
+ } else if (/\b(enhance|improve|refactor|optimize)\b/.test(objectiveLower)) {
648
+ detectedIntent = 'ENHANCE';
649
+ } else if (/\b(deliver|package|publish|deploy|release)\b/.test(objectiveLower)) {
650
+ detectedIntent = 'DELIVER';
651
+ }
652
+
653
+ if (detectedIntent) {
654
+ const expectedFlows = intentFlowMap[detectedIntent] || [];
655
+ if (expectedFlows.length > 0 && !expectedFlows.includes(plan.flow)) {
656
+ gaps.push(
657
+ gap(
658
+ 'minor',
659
+ 'flow-alignment',
660
+ `Flow '${plan.flow}' may not align with detected intent '${detectedIntent}'`,
661
+ `Consider using flow: ${expectedFlows.join(' or ')}`,
662
+ 'flow',
663
+ `intent_flow_mismatch:${detectedIntent}->${plan.flow}`,
664
+ ),
665
+ );
666
+ }
667
+ }
668
+ }
669
+
670
+ return gaps;
671
+ };
672
+ }
673
+
674
+ /**
675
+ * Factory: content anti-pattern pass.
676
+ * Detects common anti-patterns in plan content.
677
+ * Ported from Salvador's analyzeContentAntiPatterns.
678
+ *
679
+ * @param antiPatterns - Regex patterns to check against approach text
680
+ * @param mitigationPatterns - Patterns that indicate the plan is already mitigating
681
+ */
682
+ export function createAntiPatternPass(
683
+ antiPatterns?: Array<{
684
+ pattern: RegExp;
685
+ severity: GapSeverity;
686
+ description: string;
687
+ recommendation: string;
688
+ }>,
689
+ mitigationPatterns?: RegExp[],
690
+ ): GapAnalysisPass {
691
+ const VAGUE_CRITERIA_PATTERNS: RegExp[] = [
692
+ /^it (looks?|works?|is) (good|nice|fine|great|ok|correct)/i,
693
+ /^(looks?|works?) (good|nice|fine|great|ok)/i,
694
+ /^it('s| is) (done|complete|finished)/i,
695
+ /\bmy machine\b/i,
696
+ ];
697
+
698
+ return (plan: Plan) => {
699
+ const gaps: PlanGap[] = [];
700
+ const approach = (plan.approach || '').toLowerCase();
701
+ const criteria = plan.success_criteria || [];
702
+ const fullText = [approach, ...criteria].join(' ').toLowerCase();
703
+
704
+ // Check if plan is actively mitigating known anti-patterns
705
+ const isMitigating = mitigationPatterns
706
+ ? mitigationPatterns.some((p) => p.test(fullText))
707
+ : false;
708
+
709
+ // Custom anti-pattern checks
710
+ if (!isMitigating && antiPatterns) {
711
+ for (const ap of antiPatterns) {
712
+ if (ap.pattern.test(approach)) {
713
+ gaps.push(
714
+ gap(
715
+ ap.severity,
716
+ 'anti-pattern',
717
+ ap.description,
718
+ ap.recommendation,
719
+ 'approach',
720
+ `anti_pattern:${ap.description}`,
721
+ ),
722
+ );
723
+ }
724
+ }
725
+ }
726
+
727
+ // Vague success criteria (generic — always checked)
728
+ for (const criterion of criteria) {
729
+ const isVague = VAGUE_CRITERIA_PATTERNS.some((p) => p.test(criterion));
730
+ if (isVague) {
731
+ gaps.push(
732
+ gap(
733
+ 'minor',
734
+ 'anti-pattern',
735
+ `Success criterion is not measurable: "${criterion}"`,
736
+ 'Rewrite as a verifiable assertion: "Component renders X", "All Y pass Z", "No A in B".',
737
+ 'success_criteria',
738
+ `vague_criterion:${criterion}`,
739
+ ),
740
+ );
741
+ }
742
+ }
743
+
744
+ return gaps;
745
+ };
746
+ }
747
+
479
748
  // ─── Orchestrator ────────────────────────────────────────────────
480
749
 
481
750
  /**
@@ -13,7 +13,10 @@ export type GapCategory =
13
13
  | 'feasibility'
14
14
  | 'risk'
15
15
  | 'clarity'
16
- | 'semantic-quality';
16
+ | 'semantic-quality'
17
+ | 'tool-feasibility'
18
+ | 'flow-alignment'
19
+ | 'anti-pattern';
17
20
 
18
21
  export interface PlanGap {
19
22
  id: string;