@soleri/core 9.14.4 → 9.16.7

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 (355) hide show
  1. package/data/flows/deliver.flow.yaml +11 -0
  2. package/data/flows/design.flow.yaml +4 -14
  3. package/data/flows/enhance.flow.yaml +10 -0
  4. package/data/flows/explore.flow.yaml +16 -0
  5. package/data/flows/fix.flow.yaml +1 -1
  6. package/data/flows/review.flow.yaml +13 -4
  7. package/dist/brain/brain.d.ts +9 -0
  8. package/dist/brain/brain.d.ts.map +1 -1
  9. package/dist/brain/brain.js +11 -1
  10. package/dist/brain/brain.js.map +1 -1
  11. package/dist/brain/intelligence.d.ts.map +1 -1
  12. package/dist/brain/intelligence.js +24 -0
  13. package/dist/brain/intelligence.js.map +1 -1
  14. package/dist/brain/types.d.ts +1 -0
  15. package/dist/brain/types.d.ts.map +1 -1
  16. package/dist/capabilities/chain-mapping.d.ts.map +1 -1
  17. package/dist/capabilities/chain-mapping.js +5 -4
  18. package/dist/capabilities/chain-mapping.js.map +1 -1
  19. package/dist/capabilities/registry.d.ts +6 -0
  20. package/dist/capabilities/registry.d.ts.map +1 -1
  21. package/dist/capabilities/registry.js +3 -2
  22. package/dist/capabilities/registry.js.map +1 -1
  23. package/dist/chat/chat-session.d.ts +6 -0
  24. package/dist/chat/chat-session.d.ts.map +1 -1
  25. package/dist/chat/chat-session.js +68 -17
  26. package/dist/chat/chat-session.js.map +1 -1
  27. package/dist/context/context-engine.js +1 -1
  28. package/dist/context/context-engine.js.map +1 -1
  29. package/dist/curator/curator.d.ts +6 -0
  30. package/dist/curator/curator.d.ts.map +1 -1
  31. package/dist/curator/curator.js +138 -0
  32. package/dist/curator/curator.js.map +1 -1
  33. package/dist/curator/types.d.ts +10 -0
  34. package/dist/curator/types.d.ts.map +1 -1
  35. package/dist/engine/bin/soleri-engine.js +0 -0
  36. package/dist/engine/core-ops.d.ts.map +1 -1
  37. package/dist/engine/core-ops.js +38 -1
  38. package/dist/engine/core-ops.js.map +1 -1
  39. package/dist/flows/epilogue.d.ts +5 -1
  40. package/dist/flows/epilogue.d.ts.map +1 -1
  41. package/dist/flows/epilogue.js +11 -3
  42. package/dist/flows/epilogue.js.map +1 -1
  43. package/dist/flows/executor.d.ts.map +1 -1
  44. package/dist/flows/executor.js +13 -5
  45. package/dist/flows/executor.js.map +1 -1
  46. package/dist/flows/index.d.ts +1 -2
  47. package/dist/flows/index.d.ts.map +1 -1
  48. package/dist/flows/index.js +1 -0
  49. package/dist/flows/index.js.map +1 -1
  50. package/dist/flows/plan-builder.d.ts +17 -1
  51. package/dist/flows/plan-builder.d.ts.map +1 -1
  52. package/dist/flows/plan-builder.js +67 -6
  53. package/dist/flows/plan-builder.js.map +1 -1
  54. package/dist/flows/probes.d.ts +1 -1
  55. package/dist/flows/probes.d.ts.map +1 -1
  56. package/dist/flows/probes.js +15 -3
  57. package/dist/flows/probes.js.map +1 -1
  58. package/dist/flows/types.d.ts +47 -20
  59. package/dist/flows/types.d.ts.map +1 -1
  60. package/dist/flows/types.js +6 -1
  61. package/dist/flows/types.js.map +1 -1
  62. package/dist/index.d.ts +10 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +9 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/intake/content-classifier.d.ts +10 -4
  67. package/dist/intake/content-classifier.d.ts.map +1 -1
  68. package/dist/intake/content-classifier.js +19 -5
  69. package/dist/intake/content-classifier.js.map +1 -1
  70. package/dist/intake/text-ingester.d.ts +18 -0
  71. package/dist/intake/text-ingester.d.ts.map +1 -1
  72. package/dist/intake/text-ingester.js +37 -13
  73. package/dist/intake/text-ingester.js.map +1 -1
  74. package/dist/packs/pack-installer.d.ts.map +1 -1
  75. package/dist/packs/pack-installer.js +28 -2
  76. package/dist/packs/pack-installer.js.map +1 -1
  77. package/dist/planning/planner-types.d.ts +2 -0
  78. package/dist/planning/planner-types.d.ts.map +1 -1
  79. package/dist/planning/planner.d.ts +4 -0
  80. package/dist/planning/planner.d.ts.map +1 -1
  81. package/dist/planning/planner.js +50 -4
  82. package/dist/planning/planner.js.map +1 -1
  83. package/dist/playbooks/playbook-executor.d.ts +10 -1
  84. package/dist/playbooks/playbook-executor.d.ts.map +1 -1
  85. package/dist/playbooks/playbook-executor.js +8 -2
  86. package/dist/playbooks/playbook-executor.js.map +1 -1
  87. package/dist/playbooks/playbook-types.d.ts +8 -0
  88. package/dist/playbooks/playbook-types.d.ts.map +1 -1
  89. package/dist/plugins/types.d.ts +2 -2
  90. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  91. package/dist/runtime/admin-extra-ops.js +30 -0
  92. package/dist/runtime/admin-extra-ops.js.map +1 -1
  93. package/dist/runtime/admin-ops.d.ts.map +1 -1
  94. package/dist/runtime/admin-ops.js +60 -21
  95. package/dist/runtime/admin-ops.js.map +1 -1
  96. package/dist/runtime/admin-setup-ops.d.ts +11 -0
  97. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  98. package/dist/runtime/admin-setup-ops.js +146 -37
  99. package/dist/runtime/admin-setup-ops.js.map +1 -1
  100. package/dist/runtime/capture-ops.d.ts.map +1 -1
  101. package/dist/runtime/capture-ops.js +38 -12
  102. package/dist/runtime/capture-ops.js.map +1 -1
  103. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  104. package/dist/runtime/facades/brain-facade.js +16 -4
  105. package/dist/runtime/facades/brain-facade.js.map +1 -1
  106. package/dist/runtime/facades/context-facade.d.ts.map +1 -1
  107. package/dist/runtime/facades/context-facade.js +9 -3
  108. package/dist/runtime/facades/context-facade.js.map +1 -1
  109. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  110. package/dist/runtime/facades/memory-facade.js +20 -7
  111. package/dist/runtime/facades/memory-facade.js.map +1 -1
  112. package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
  113. package/dist/runtime/facades/orchestrate-facade.js +40 -1
  114. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  115. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  116. package/dist/runtime/facades/plan-facade.js +113 -4
  117. package/dist/runtime/facades/plan-facade.js.map +1 -1
  118. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  119. package/dist/runtime/facades/vault-facade.js +24 -3
  120. package/dist/runtime/facades/vault-facade.js.map +1 -1
  121. package/dist/runtime/orchestrate-ops.d.ts +21 -0
  122. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  123. package/dist/runtime/orchestrate-ops.js +132 -38
  124. package/dist/runtime/orchestrate-ops.js.map +1 -1
  125. package/dist/runtime/runtime.d.ts.map +1 -1
  126. package/dist/runtime/runtime.js +16 -0
  127. package/dist/runtime/runtime.js.map +1 -1
  128. package/dist/runtime/schema-helpers.d.ts.map +1 -1
  129. package/dist/runtime/schema-helpers.js +4 -0
  130. package/dist/runtime/schema-helpers.js.map +1 -1
  131. package/dist/runtime/types.d.ts +19 -0
  132. package/dist/runtime/types.d.ts.map +1 -1
  133. package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
  134. package/dist/runtime/vault-linking-ops.js +16 -3
  135. package/dist/runtime/vault-linking-ops.js.map +1 -1
  136. package/dist/scheduler/cron-validator.d.ts +15 -0
  137. package/dist/scheduler/cron-validator.d.ts.map +1 -0
  138. package/dist/scheduler/cron-validator.js +93 -0
  139. package/dist/scheduler/cron-validator.js.map +1 -0
  140. package/dist/scheduler/platform-linux.d.ts +14 -0
  141. package/dist/scheduler/platform-linux.d.ts.map +1 -0
  142. package/dist/scheduler/platform-linux.js +107 -0
  143. package/dist/scheduler/platform-linux.js.map +1 -0
  144. package/dist/scheduler/platform-macos.d.ts +15 -0
  145. package/dist/scheduler/platform-macos.d.ts.map +1 -0
  146. package/dist/scheduler/platform-macos.js +131 -0
  147. package/dist/scheduler/platform-macos.js.map +1 -0
  148. package/dist/scheduler/scheduler-ops.d.ts +14 -0
  149. package/dist/scheduler/scheduler-ops.d.ts.map +1 -0
  150. package/dist/scheduler/scheduler-ops.js +77 -0
  151. package/dist/scheduler/scheduler-ops.js.map +1 -0
  152. package/dist/scheduler/scheduler.d.ts +55 -0
  153. package/dist/scheduler/scheduler.d.ts.map +1 -0
  154. package/dist/scheduler/scheduler.js +144 -0
  155. package/dist/scheduler/scheduler.js.map +1 -0
  156. package/dist/scheduler/types.d.ts +48 -0
  157. package/dist/scheduler/types.d.ts.map +1 -0
  158. package/dist/scheduler/types.js +6 -0
  159. package/dist/scheduler/types.js.map +1 -0
  160. package/dist/skills/sync-skills.d.ts +11 -0
  161. package/dist/skills/sync-skills.d.ts.map +1 -1
  162. package/dist/skills/sync-skills.js +132 -38
  163. package/dist/skills/sync-skills.js.map +1 -1
  164. package/dist/skills/validate-skills.d.ts +32 -0
  165. package/dist/skills/validate-skills.d.ts.map +1 -0
  166. package/dist/skills/validate-skills.js +396 -0
  167. package/dist/skills/validate-skills.js.map +1 -0
  168. package/dist/utils/worktree-reaper.d.ts +38 -0
  169. package/dist/utils/worktree-reaper.d.ts.map +1 -0
  170. package/dist/utils/worktree-reaper.js +85 -0
  171. package/dist/utils/worktree-reaper.js.map +1 -0
  172. package/dist/vault/default-canonical-tags.d.ts +15 -0
  173. package/dist/vault/default-canonical-tags.d.ts.map +1 -0
  174. package/dist/vault/default-canonical-tags.js +65 -0
  175. package/dist/vault/default-canonical-tags.js.map +1 -0
  176. package/dist/vault/scope-detector.d.ts.map +1 -1
  177. package/dist/vault/scope-detector.js +37 -4
  178. package/dist/vault/scope-detector.js.map +1 -1
  179. package/dist/vault/tag-normalizer.d.ts +42 -0
  180. package/dist/vault/tag-normalizer.d.ts.map +1 -0
  181. package/dist/vault/tag-normalizer.js +157 -0
  182. package/dist/vault/tag-normalizer.js.map +1 -0
  183. package/dist/vault/vault-entries.d.ts.map +1 -1
  184. package/dist/vault/vault-entries.js +3 -1
  185. package/dist/vault/vault-entries.js.map +1 -1
  186. package/package.json +5 -1
  187. package/src/__tests__/embeddings.test.ts +3 -3
  188. package/src/agency/agency-manager.test.ts +4 -4
  189. package/src/agency/default-rules.test.ts +0 -13
  190. package/src/brain/brain-intelligence.test.ts +0 -5
  191. package/src/brain/brain.ts +25 -1
  192. package/src/brain/intelligence.ts +25 -0
  193. package/src/brain/second-brain-features.test.ts +2 -14
  194. package/src/brain/types.ts +1 -0
  195. package/src/capabilities/chain-mapping.test.ts +1 -6
  196. package/src/capabilities/chain-mapping.ts +6 -4
  197. package/src/capabilities/registry.test.ts +1 -1
  198. package/src/capabilities/registry.ts +9 -2
  199. package/src/chat/agent-loop.test.ts +1 -1
  200. package/src/chat/chat-enhanced.test.ts +0 -8
  201. package/src/chat/chat-session.ts +75 -17
  202. package/src/chat/chat-transport.test.ts +31 -1
  203. package/src/claudemd/compose.test.ts +0 -5
  204. package/src/context/context-engine.test.ts +0 -1
  205. package/src/context/context-engine.ts +1 -1
  206. package/src/control/intent-router.test.ts +2 -2
  207. package/src/curator/curator.ts +180 -0
  208. package/src/curator/tag-manager.test.ts +0 -4
  209. package/src/curator/types.ts +10 -0
  210. package/src/domain-packs/types.test.ts +0 -5
  211. package/src/dream/dream.test.ts +0 -7
  212. package/src/enforcement/registry.test.ts +2 -2
  213. package/src/engine/core-ops.test.ts +4 -22
  214. package/src/engine/core-ops.ts +36 -1
  215. package/src/engine/module-manifest.test.ts +1 -31
  216. package/src/engine/register-engine.test.ts +3 -33
  217. package/src/errors/retry.test.ts +3 -1
  218. package/src/flows/chain-runner.test.ts +0 -6
  219. package/src/flows/context-router.test.ts +3 -3
  220. package/src/flows/epilogue.test.ts +40 -2
  221. package/src/flows/epilogue.ts +11 -2
  222. package/src/flows/executor.test.ts +48 -2
  223. package/src/flows/executor.ts +15 -5
  224. package/src/flows/index.ts +1 -3
  225. package/src/flows/plan-builder.test.ts +201 -0
  226. package/src/flows/plan-builder.ts +81 -5
  227. package/src/flows/probes.ts +17 -3
  228. package/src/flows/types.ts +31 -2
  229. package/src/health/health-registry.test.ts +3 -1
  230. package/src/index.ts +24 -0
  231. package/src/intake/content-classifier.ts +22 -4
  232. package/src/intake/dedup-gate.test.ts +2 -6
  233. package/src/intake/text-ingester.test.ts +3 -4
  234. package/src/intake/text-ingester.ts +61 -12
  235. package/src/llm/llm-client.test.ts +1 -1
  236. package/src/llm/utils.test.ts +1 -1
  237. package/src/migrations/migration-runner.test.ts +0 -1
  238. package/src/operator/operator-context-store.test.ts +0 -13
  239. package/src/operator/operator-profile.test.ts +2 -20
  240. package/src/packs/pack-installer.ts +28 -2
  241. package/src/packs/pack-system.test.ts +2 -2
  242. package/src/persona/defaults.test.ts +19 -19
  243. package/src/planning/gap-passes.test.ts +0 -46
  244. package/src/planning/gap-patterns.test.ts +0 -42
  245. package/src/planning/goal-ancestry.test.ts +3 -1
  246. package/src/planning/plan-lifecycle.test.ts +15 -7
  247. package/src/planning/planner-types.ts +2 -0
  248. package/src/planning/planner.test.ts +86 -90
  249. package/src/planning/planner.ts +56 -4
  250. package/src/planning/reconciliation-engine.test.ts +3 -10
  251. package/src/planning/task-complexity-assessor.test.ts +0 -5
  252. package/src/planning/task-verifier.test.ts +3 -1
  253. package/src/playbooks/generic/generic-playbooks.test.ts +0 -28
  254. package/src/playbooks/index.test.ts +0 -55
  255. package/src/playbooks/playbook-executor.test.ts +76 -0
  256. package/src/playbooks/playbook-executor.ts +24 -3
  257. package/src/playbooks/playbook-types.ts +8 -0
  258. package/src/plugins/plugin-registry.test.ts +6 -2
  259. package/src/project/project-registry.test.ts +2 -0
  260. package/src/queue/async-infrastructure.test.ts +6 -4
  261. package/src/queue/job-queue.test.ts +13 -7
  262. package/src/runtime/admin-extra-ops.test.ts +35 -30
  263. package/src/runtime/admin-extra-ops.ts +30 -0
  264. package/src/runtime/admin-ops.test.ts +0 -4
  265. package/src/runtime/admin-ops.ts +63 -21
  266. package/src/runtime/admin-setup-ops.test.ts +229 -13
  267. package/src/runtime/admin-setup-ops.ts +145 -36
  268. package/src/runtime/archive-ops.test.ts +0 -28
  269. package/src/runtime/branching-ops.test.ts +0 -17
  270. package/src/runtime/capture-ops.test.ts +41 -16
  271. package/src/runtime/capture-ops.ts +78 -46
  272. package/src/runtime/chain-ops.test.ts +0 -21
  273. package/src/runtime/facades/admin-facade.test.ts +0 -34
  274. package/src/runtime/facades/agency-facade.test.ts +0 -39
  275. package/src/runtime/facades/archive-facade.test.ts +0 -43
  276. package/src/runtime/facades/brain-facade.test.ts +8 -99
  277. package/src/runtime/facades/brain-facade.ts +29 -12
  278. package/src/runtime/facades/branching-facade.test.ts +30 -17
  279. package/src/runtime/facades/chat-facade.test.ts +0 -91
  280. package/src/runtime/facades/chat-service-ops.test.ts +0 -24
  281. package/src/runtime/facades/chat-session-ops.test.ts +0 -12
  282. package/src/runtime/facades/chat-transport-ops.test.ts +0 -23
  283. package/src/runtime/facades/context-facade.test.ts +0 -17
  284. package/src/runtime/facades/context-facade.ts +11 -4
  285. package/src/runtime/facades/control-facade.test.ts +0 -30
  286. package/src/runtime/facades/curator-facade.test.ts +0 -33
  287. package/src/runtime/facades/intake-facade.test.ts +0 -33
  288. package/src/runtime/facades/links-facade.test.ts +0 -37
  289. package/src/runtime/facades/loop-facade.test.ts +0 -26
  290. package/src/runtime/facades/memory-facade.test.ts +0 -18
  291. package/src/runtime/facades/memory-facade.ts +27 -11
  292. package/src/runtime/facades/operator-facade.test.ts +0 -31
  293. package/src/runtime/facades/orchestrate-facade.test.ts +0 -21
  294. package/src/runtime/facades/orchestrate-facade.ts +39 -1
  295. package/src/runtime/facades/plan-facade.test.ts +7 -32
  296. package/src/runtime/facades/plan-facade.ts +137 -4
  297. package/src/runtime/facades/review-facade.test.ts +1 -49
  298. package/src/runtime/facades/sync-facade.test.ts +24 -41
  299. package/src/runtime/facades/tier-facade.test.ts +30 -22
  300. package/src/runtime/facades/vault-facade.test.ts +0 -41
  301. package/src/runtime/facades/vault-facade.ts +26 -3
  302. package/src/runtime/grading-ops.test.ts +0 -27
  303. package/src/runtime/intake-ops.test.ts +0 -19
  304. package/src/runtime/loop-ops.test.ts +0 -48
  305. package/src/runtime/memory-cross-project-ops.test.ts +0 -14
  306. package/src/runtime/memory-extra-ops.test.ts +4 -8
  307. package/src/runtime/orchestrate-ops.test.ts +238 -19
  308. package/src/runtime/orchestrate-ops.ts +166 -41
  309. package/src/runtime/pack-ops.test.ts +0 -26
  310. package/src/runtime/planning-extra-ops.test.ts +2 -14
  311. package/src/runtime/playbook-ops-execution.test.ts +9 -20
  312. package/src/runtime/playbook-ops.test.ts +4 -67
  313. package/src/runtime/review-ops.test.ts +0 -15
  314. package/src/runtime/runtime.ts +18 -0
  315. package/src/runtime/schema-helpers.ts +4 -0
  316. package/src/runtime/sync-ops.test.ts +0 -18
  317. package/src/runtime/tier-ops.test.ts +0 -21
  318. package/src/runtime/types.ts +19 -0
  319. package/src/runtime/vault-extra-ops.test.ts +0 -12
  320. package/src/runtime/vault-linking-ops.test.ts +0 -4
  321. package/src/runtime/vault-linking-ops.ts +26 -8
  322. package/src/runtime/vault-sharing-ops.test.ts +0 -9
  323. package/src/scheduler/cron-validator.ts +101 -0
  324. package/src/scheduler/platform-linux.ts +122 -0
  325. package/src/scheduler/platform-macos.ts +150 -0
  326. package/src/scheduler/scheduler-ops.ts +77 -0
  327. package/src/scheduler/scheduler.test.ts +247 -0
  328. package/src/scheduler/scheduler.ts +174 -0
  329. package/src/scheduler/types.ts +52 -0
  330. package/src/skills/__tests__/sync-skills.test.ts +6 -17
  331. package/src/skills/global-claude-md.test.ts +113 -0
  332. package/src/skills/sync-skills.ts +143 -35
  333. package/src/skills/validate-skills.test.ts +206 -0
  334. package/src/skills/validate-skills.ts +470 -0
  335. package/src/telemetry/telemetry.test.ts +1 -0
  336. package/src/transport/http-server.test.ts +3 -0
  337. package/src/transport/session-manager.test.ts +3 -1
  338. package/src/transport/token-auth.test.ts +6 -9
  339. package/src/transport/ws-server.test.ts +10 -2
  340. package/src/utils/worktree-reaper.ts +113 -0
  341. package/src/vault/__tests__/vault-characterization.test.ts +0 -108
  342. package/src/vault/default-canonical-tags.ts +64 -0
  343. package/src/vault/linking.test.ts +0 -2
  344. package/src/vault/playbook.test.ts +4 -1
  345. package/src/vault/scope-detector.test.ts +3 -1
  346. package/src/vault/scope-detector.ts +42 -4
  347. package/src/vault/tag-normalizer.test.ts +214 -0
  348. package/src/vault/tag-normalizer.ts +188 -0
  349. package/src/vault/vault-connect.test.ts +1 -1
  350. package/src/vault/vault-entries.ts +3 -1
  351. package/src/vault/vault.test.ts +23 -8
  352. package/dist/embeddings/index.d.ts +0 -5
  353. package/dist/embeddings/index.d.ts.map +0 -1
  354. package/dist/embeddings/index.js +0 -3
  355. package/dist/embeddings/index.js.map +0 -1
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Tag Normalizer — canonical tag taxonomy enforcement.
3
+ *
4
+ * Maps raw tags to nearest canonical via Levenshtein edit-distance.
5
+ * Strips noise words (version strings, single generic words).
6
+ * Respects metadata tag prefixes (e.g. 'source:').
7
+ *
8
+ * Three modes:
9
+ * - 'enforce': must match within edit-distance 3, else drop (return null)
10
+ * - 'suggest': map to nearest canonical within edit-distance 2 (passthrough if no match)
11
+ * - 'off': no normalization — return tag as-is
12
+ */
13
+
14
+ // ─── Noise filter ────────────────────────────────────────────────────────────
15
+
16
+ /**
17
+ * Version-string pattern: v1.2, v10, v1.2.3, etc.
18
+ */
19
+ const VERSION_PATTERN = /^v\d+(\.\d+)*/i;
20
+
21
+ /**
22
+ * Generic single words that add no signal.
23
+ */
24
+ const NOISE_WORDS = new Set([
25
+ 'one',
26
+ 'via',
27
+ 'new',
28
+ 'full',
29
+ 'actual',
30
+ 'raw',
31
+ 'the',
32
+ 'and',
33
+ 'for',
34
+ 'with',
35
+ 'this',
36
+ 'that',
37
+ 'from',
38
+ 'into',
39
+ ]);
40
+
41
+ function isNoisy(tag: string): boolean {
42
+ if (VERSION_PATTERN.test(tag)) return true;
43
+ if (NOISE_WORDS.has(tag.toLowerCase())) return true;
44
+ return false;
45
+ }
46
+
47
+ // ─── Levenshtein edit distance ───────────────────────────────────────────────
48
+
49
+ /**
50
+ * Compute Levenshtein edit distance between two strings.
51
+ * O(m*n) time, O(n) space using two-row DP.
52
+ */
53
+ export function computeEditDistance(a: string, b: string): number {
54
+ if (a === b) return 0;
55
+ if (a.length === 0) return b.length;
56
+ if (b.length === 0) return a.length;
57
+
58
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
59
+ let curr = Array.from<number>({ length: b.length + 1 });
60
+
61
+ for (let i = 1; i <= a.length; i++) {
62
+ curr[0] = i;
63
+ for (let j = 1; j <= b.length; j++) {
64
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
65
+ curr[j] = Math.min(
66
+ curr[j - 1] + 1, // insertion
67
+ prev[j] + 1, // deletion
68
+ prev[j - 1] + cost, // substitution
69
+ );
70
+ }
71
+ [prev, curr] = [curr, prev];
72
+ }
73
+
74
+ return prev[b.length];
75
+ }
76
+
77
+ // ─── Metadata tag check ──────────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Returns true if the tag starts with any of the given prefixes.
81
+ * Metadata tags (e.g. 'source:article') are exempt from canonical normalization.
82
+ */
83
+ export function isMetadataTag(tag: string, prefixes: string[]): boolean {
84
+ return prefixes.some((prefix) => tag.startsWith(prefix));
85
+ }
86
+
87
+ // ─── Single tag normalization ────────────────────────────────────────────────
88
+
89
+ /**
90
+ * Normalize a single tag against a canonical list.
91
+ *
92
+ * @param tag - Raw tag to normalize
93
+ * @param canonical - Canonical tag list to map against
94
+ * @param mode - Constraint mode: 'enforce' | 'suggest' | 'off'
95
+ * @returns Normalized tag string, or null if the tag should be dropped.
96
+ */
97
+ export function normalizeTag(
98
+ tag: string,
99
+ canonical: string[],
100
+ mode: 'enforce' | 'suggest' | 'off',
101
+ ): string | null {
102
+ if (mode === 'off') return tag;
103
+
104
+ const lower = tag.toLowerCase().trim();
105
+
106
+ // Always drop noise words
107
+ if (isNoisy(lower)) return null;
108
+
109
+ // Derive lowercase canonical for matching; preserve original casing for return
110
+ const canonicalLower = canonical.map((x) => x.toLowerCase());
111
+
112
+ // Exact match in canonical list — return canonical form (original casing)
113
+ const exactIdx = canonicalLower.indexOf(lower);
114
+ if (exactIdx !== -1) return canonical[exactIdx];
115
+
116
+ if (canonical.length === 0) {
117
+ // No canonical list configured — pass through in suggest, drop in enforce
118
+ return mode === 'enforce' ? null : lower;
119
+ }
120
+
121
+ // Find nearest canonical by edit distance
122
+ let bestMatch: string | null = null;
123
+ let bestDist = Infinity;
124
+
125
+ for (let i = 0; i < canonicalLower.length; i++) {
126
+ const dist = computeEditDistance(lower, canonicalLower[i]);
127
+ if (dist < bestDist) {
128
+ bestDist = dist;
129
+ bestMatch = canonical[i];
130
+ }
131
+ }
132
+
133
+ const threshold = mode === 'enforce' ? 3 : 2;
134
+
135
+ if (bestDist <= threshold && bestMatch !== null) {
136
+ return bestMatch;
137
+ }
138
+
139
+ // No close match found
140
+ if (mode === 'enforce') {
141
+ return null; // drop the tag
142
+ }
143
+
144
+ // 'suggest' mode — keep original tag unchanged (passthrough)
145
+ return lower;
146
+ }
147
+
148
+ // ─── Batch tag normalization ─────────────────────────────────────────────────
149
+
150
+ /**
151
+ * Normalize a batch of tags against a canonical list.
152
+ * Filters out nulls (dropped tags). Deduplicates the result.
153
+ *
154
+ * @param tags - Raw tags
155
+ * @param canonical - Canonical tag list
156
+ * @param mode - Constraint mode
157
+ * @param metadataPrefixes - Tags with these prefixes bypass normalization
158
+ */
159
+ export function normalizeTags(
160
+ tags: string[],
161
+ canonical: string[],
162
+ mode: 'enforce' | 'suggest' | 'off',
163
+ metadataPrefixes: string[] = ['source:'],
164
+ ): string[] {
165
+ if (mode === 'off') return tags;
166
+
167
+ const seen = new Set<string>();
168
+ const result: string[] = [];
169
+
170
+ for (const tag of tags) {
171
+ // Metadata tags bypass canonical normalization but are still kept
172
+ if (isMetadataTag(tag, metadataPrefixes)) {
173
+ if (!seen.has(tag)) {
174
+ seen.add(tag);
175
+ result.push(tag);
176
+ }
177
+ continue;
178
+ }
179
+
180
+ const normalized = normalizeTag(tag, canonical, mode);
181
+ if (normalized !== null && !seen.has(normalized)) {
182
+ seen.add(normalized);
183
+ result.push(normalized);
184
+ }
185
+ }
186
+
187
+ return result;
188
+ }
@@ -127,7 +127,7 @@ describe('VaultManager — named connections', () => {
127
127
  const results = mgr.search('shared entry');
128
128
  const sameResults = results.filter((r) => r.entry.id === 'same-id');
129
129
  expect(sameResults.length).toBe(1);
130
- // Score should reflect agent weight (1.0) not external (0.7)
130
+ // Dedup keeps only one result — agent tier wins, score is positive
131
131
  expect(sameResults[0].score).toBeGreaterThan(0);
132
132
  });
133
133
 
@@ -526,9 +526,11 @@ export function rowToSearchResult(row: Record<string, unknown>): SearchResult {
526
526
 
527
527
  /** Build FTS5 query from natural language: terms joined with OR for broad matching. */
528
528
  export function buildFtsQuery(query: string): string {
529
+ // Split on whitespace AND punctuation (hyphens, underscores, dots, slashes)
530
+ // so that "smoke-test-entry" and "snake_case" are treated as multi-term queries.
529
531
  const terms = query
530
532
  .toLowerCase()
531
- .split(/\s+/)
533
+ .split(/[\s\-_./\\]+/)
532
534
  .filter((t) => t.length >= 2)
533
535
  .map((t) => t.replace(/[^a-z0-9]/g, ''))
534
536
  .filter(Boolean);
@@ -98,13 +98,14 @@ describe('Vault', () => {
98
98
 
99
99
  it('should find entries matching query', () => {
100
100
  const results = vault.search('validation input');
101
- expect(results.length).toBeGreaterThan(0);
101
+ expect(results).toHaveLength(1);
102
102
  expect(results[0].entry.id).toBe('search-1');
103
103
  });
104
104
 
105
105
  it('should return scores with results', () => {
106
106
  const results = vault.search('caching');
107
107
  expect(results[0].score).toBeGreaterThan(0);
108
+ expect(results[0].entry.id).toBe('search-2');
108
109
  });
109
110
 
110
111
  it('should filter by domain', () => {
@@ -121,6 +122,20 @@ describe('Vault', () => {
121
122
  const results = vault.search('xyznonexistent');
122
123
  expect(results).toEqual([]);
123
124
  });
125
+
126
+ it('should find entries by hyphenated query (smoke-test-entry style)', () => {
127
+ vault.seed([
128
+ makeEntry({
129
+ id: 'hyphen-test-1',
130
+ title: 'smoke-test-entry',
131
+ description: 'Hyphenated title entry for FTS regression.',
132
+ domain: 'testing',
133
+ }),
134
+ ]);
135
+ const results = vault.search('smoke-test-entry');
136
+ expect(results.length).toBeGreaterThan(0);
137
+ expect(results[0].entry.id).toBe('hyphen-test-1');
138
+ });
124
139
  });
125
140
 
126
141
  describe('get', () => {
@@ -326,7 +341,7 @@ describe('Vault', () => {
326
341
  toolsUsed: [],
327
342
  });
328
343
  expect(memory.type).toBe('session');
329
- expect(memory.createdAt).toBeGreaterThan(0);
344
+ expect(typeof memory.createdAt).toBe('number');
330
345
  });
331
346
 
332
347
  it('should capture preference memories', () => {
@@ -376,7 +391,7 @@ describe('Vault', () => {
376
391
 
377
392
  it('should find memories matching query', () => {
378
393
  const results = vault.searchMemories('parameterized queries');
379
- expect(results.length).toBeGreaterThan(0);
394
+ expect(results).toHaveLength(1);
380
395
  expect(results[0].summary).toContain('parameterized');
381
396
  });
382
397
 
@@ -578,7 +593,7 @@ describe('Vault', () => {
578
593
 
579
594
  // Before archive: should appear in search
580
595
  const before = v.search('searchable');
581
- expect(before.length).toBeGreaterThan(0);
596
+ expect(before).toHaveLength(1);
582
597
 
583
598
  v.archive({ olderThanDays: 90 });
584
599
 
@@ -643,7 +658,7 @@ describe('Vault', () => {
643
658
  v.restore('search-restore');
644
659
 
645
660
  const results = v.search('unique findable');
646
- expect(results.length).toBeGreaterThan(0);
661
+ expect(results).toHaveLength(1);
647
662
  v.close();
648
663
  });
649
664
 
@@ -726,9 +741,9 @@ describe('Vault', () => {
726
741
  },
727
742
  ]);
728
743
  const stats = vault.contentHashStats();
729
- expect(stats.total).toBeGreaterThanOrEqual(2);
730
- expect(stats.hashed).toBe(stats.total);
731
- expect(stats.uniqueHashes).toBe(stats.total);
744
+ expect(stats.total).toBe(2);
745
+ expect(stats.hashed).toBe(2);
746
+ expect(stats.uniqueHashes).toBe(2);
732
747
  });
733
748
 
734
749
  it('backfill hashes existing entries on re-initialize', () => {
@@ -1,5 +0,0 @@
1
- export type { EmbeddingProvider, EmbeddingResult, EmbeddingConfig, StoredVector, EmbeddingStats, } from './types.js';
2
- export { OpenAIEmbeddingProvider } from './openai-provider.js';
3
- export { EmbeddingPipeline } from './pipeline.js';
4
- export type { BatchEmbedOptions, BatchEmbedResult } from './pipeline.js';
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/embeddings/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
@@ -1,3 +0,0 @@
1
- export { OpenAIEmbeddingProvider } from './openai-provider.js';
2
- export { EmbeddingPipeline } from './pipeline.js';
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/embeddings/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}