@soleri/core 9.15.0 → 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 (288) 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/capabilities/chain-mapping.d.ts.map +1 -1
  8. package/dist/capabilities/chain-mapping.js +5 -4
  9. package/dist/capabilities/chain-mapping.js.map +1 -1
  10. package/dist/capabilities/registry.d.ts +6 -0
  11. package/dist/capabilities/registry.d.ts.map +1 -1
  12. package/dist/capabilities/registry.js +3 -2
  13. package/dist/capabilities/registry.js.map +1 -1
  14. package/dist/context/context-engine.js +1 -1
  15. package/dist/context/context-engine.js.map +1 -1
  16. package/dist/engine/core-ops.d.ts.map +1 -1
  17. package/dist/engine/core-ops.js +38 -1
  18. package/dist/engine/core-ops.js.map +1 -1
  19. package/dist/flows/epilogue.d.ts +5 -1
  20. package/dist/flows/epilogue.d.ts.map +1 -1
  21. package/dist/flows/epilogue.js +11 -3
  22. package/dist/flows/epilogue.js.map +1 -1
  23. package/dist/flows/executor.d.ts.map +1 -1
  24. package/dist/flows/executor.js +13 -5
  25. package/dist/flows/executor.js.map +1 -1
  26. package/dist/flows/index.d.ts +1 -2
  27. package/dist/flows/index.d.ts.map +1 -1
  28. package/dist/flows/index.js +1 -0
  29. package/dist/flows/index.js.map +1 -1
  30. package/dist/flows/plan-builder.d.ts +17 -1
  31. package/dist/flows/plan-builder.d.ts.map +1 -1
  32. package/dist/flows/plan-builder.js +67 -6
  33. package/dist/flows/plan-builder.js.map +1 -1
  34. package/dist/flows/probes.d.ts +1 -1
  35. package/dist/flows/probes.d.ts.map +1 -1
  36. package/dist/flows/probes.js +15 -3
  37. package/dist/flows/probes.js.map +1 -1
  38. package/dist/flows/types.d.ts +31 -4
  39. package/dist/flows/types.d.ts.map +1 -1
  40. package/dist/flows/types.js +6 -1
  41. package/dist/flows/types.js.map +1 -1
  42. package/dist/index.d.ts +8 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +7 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/packs/pack-installer.d.ts.map +1 -1
  47. package/dist/packs/pack-installer.js +28 -2
  48. package/dist/packs/pack-installer.js.map +1 -1
  49. package/dist/planning/planner-types.d.ts +2 -0
  50. package/dist/planning/planner-types.d.ts.map +1 -1
  51. package/dist/planning/planner.d.ts +1 -0
  52. package/dist/planning/planner.d.ts.map +1 -1
  53. package/dist/planning/planner.js +7 -0
  54. package/dist/planning/planner.js.map +1 -1
  55. package/dist/playbooks/playbook-executor.d.ts +10 -1
  56. package/dist/playbooks/playbook-executor.d.ts.map +1 -1
  57. package/dist/playbooks/playbook-executor.js +8 -2
  58. package/dist/playbooks/playbook-executor.js.map +1 -1
  59. package/dist/playbooks/playbook-types.d.ts +8 -0
  60. package/dist/playbooks/playbook-types.d.ts.map +1 -1
  61. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  62. package/dist/runtime/admin-extra-ops.js +30 -0
  63. package/dist/runtime/admin-extra-ops.js.map +1 -1
  64. package/dist/runtime/admin-ops.d.ts.map +1 -1
  65. package/dist/runtime/admin-ops.js +60 -21
  66. package/dist/runtime/admin-ops.js.map +1 -1
  67. package/dist/runtime/admin-setup-ops.d.ts +11 -0
  68. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  69. package/dist/runtime/admin-setup-ops.js +87 -17
  70. package/dist/runtime/admin-setup-ops.js.map +1 -1
  71. package/dist/runtime/capture-ops.d.ts.map +1 -1
  72. package/dist/runtime/capture-ops.js +38 -12
  73. package/dist/runtime/capture-ops.js.map +1 -1
  74. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  75. package/dist/runtime/facades/brain-facade.js +16 -4
  76. package/dist/runtime/facades/brain-facade.js.map +1 -1
  77. package/dist/runtime/facades/context-facade.d.ts.map +1 -1
  78. package/dist/runtime/facades/context-facade.js +9 -3
  79. package/dist/runtime/facades/context-facade.js.map +1 -1
  80. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  81. package/dist/runtime/facades/memory-facade.js +20 -7
  82. package/dist/runtime/facades/memory-facade.js.map +1 -1
  83. package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
  84. package/dist/runtime/facades/orchestrate-facade.js +12 -0
  85. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  86. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  87. package/dist/runtime/facades/plan-facade.js +113 -4
  88. package/dist/runtime/facades/plan-facade.js.map +1 -1
  89. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  90. package/dist/runtime/facades/vault-facade.js +24 -3
  91. package/dist/runtime/facades/vault-facade.js.map +1 -1
  92. package/dist/runtime/orchestrate-ops.d.ts +21 -0
  93. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  94. package/dist/runtime/orchestrate-ops.js +132 -38
  95. package/dist/runtime/orchestrate-ops.js.map +1 -1
  96. package/dist/runtime/schema-helpers.d.ts.map +1 -1
  97. package/dist/runtime/schema-helpers.js +4 -0
  98. package/dist/runtime/schema-helpers.js.map +1 -1
  99. package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
  100. package/dist/runtime/vault-linking-ops.js +16 -3
  101. package/dist/runtime/vault-linking-ops.js.map +1 -1
  102. package/dist/scheduler/cron-validator.d.ts +15 -0
  103. package/dist/scheduler/cron-validator.d.ts.map +1 -0
  104. package/dist/scheduler/cron-validator.js +93 -0
  105. package/dist/scheduler/cron-validator.js.map +1 -0
  106. package/dist/scheduler/platform-linux.d.ts +14 -0
  107. package/dist/scheduler/platform-linux.d.ts.map +1 -0
  108. package/dist/scheduler/platform-linux.js +107 -0
  109. package/dist/scheduler/platform-linux.js.map +1 -0
  110. package/dist/scheduler/platform-macos.d.ts +15 -0
  111. package/dist/scheduler/platform-macos.d.ts.map +1 -0
  112. package/dist/scheduler/platform-macos.js +131 -0
  113. package/dist/scheduler/platform-macos.js.map +1 -0
  114. package/dist/scheduler/scheduler-ops.d.ts +14 -0
  115. package/dist/scheduler/scheduler-ops.d.ts.map +1 -0
  116. package/dist/scheduler/scheduler-ops.js +77 -0
  117. package/dist/scheduler/scheduler-ops.js.map +1 -0
  118. package/dist/scheduler/scheduler.d.ts +55 -0
  119. package/dist/scheduler/scheduler.d.ts.map +1 -0
  120. package/dist/scheduler/scheduler.js +144 -0
  121. package/dist/scheduler/scheduler.js.map +1 -0
  122. package/dist/scheduler/types.d.ts +48 -0
  123. package/dist/scheduler/types.d.ts.map +1 -0
  124. package/dist/scheduler/types.js +6 -0
  125. package/dist/scheduler/types.js.map +1 -0
  126. package/dist/skills/sync-skills.d.ts +11 -0
  127. package/dist/skills/sync-skills.d.ts.map +1 -1
  128. package/dist/skills/sync-skills.js +132 -38
  129. package/dist/skills/sync-skills.js.map +1 -1
  130. package/dist/utils/worktree-reaper.d.ts +38 -0
  131. package/dist/utils/worktree-reaper.d.ts.map +1 -0
  132. package/dist/utils/worktree-reaper.js +85 -0
  133. package/dist/utils/worktree-reaper.js.map +1 -0
  134. package/dist/vault/scope-detector.d.ts.map +1 -1
  135. package/dist/vault/scope-detector.js +37 -4
  136. package/dist/vault/scope-detector.js.map +1 -1
  137. package/dist/vault/vault-entries.d.ts.map +1 -1
  138. package/dist/vault/vault-entries.js +3 -1
  139. package/dist/vault/vault-entries.js.map +1 -1
  140. package/package.json +1 -1
  141. package/src/agency/agency-manager.test.ts +4 -4
  142. package/src/agency/default-rules.test.ts +0 -13
  143. package/src/brain/brain-intelligence.test.ts +0 -5
  144. package/src/brain/second-brain-features.test.ts +2 -14
  145. package/src/capabilities/chain-mapping.test.ts +1 -6
  146. package/src/capabilities/chain-mapping.ts +6 -4
  147. package/src/capabilities/registry.test.ts +1 -1
  148. package/src/capabilities/registry.ts +9 -2
  149. package/src/chat/agent-loop.test.ts +1 -1
  150. package/src/chat/chat-enhanced.test.ts +0 -8
  151. package/src/claudemd/compose.test.ts +0 -5
  152. package/src/context/context-engine.test.ts +0 -1
  153. package/src/context/context-engine.ts +1 -1
  154. package/src/control/intent-router.test.ts +2 -2
  155. package/src/curator/tag-manager.test.ts +0 -4
  156. package/src/domain-packs/types.test.ts +0 -5
  157. package/src/dream/dream.test.ts +0 -7
  158. package/src/enforcement/registry.test.ts +2 -2
  159. package/src/engine/core-ops.test.ts +4 -22
  160. package/src/engine/core-ops.ts +36 -1
  161. package/src/engine/module-manifest.test.ts +1 -31
  162. package/src/engine/register-engine.test.ts +3 -33
  163. package/src/errors/retry.test.ts +3 -1
  164. package/src/flows/chain-runner.test.ts +0 -6
  165. package/src/flows/context-router.test.ts +3 -3
  166. package/src/flows/epilogue.test.ts +40 -2
  167. package/src/flows/epilogue.ts +11 -2
  168. package/src/flows/executor.test.ts +48 -2
  169. package/src/flows/executor.ts +15 -5
  170. package/src/flows/index.ts +1 -3
  171. package/src/flows/plan-builder.test.ts +201 -0
  172. package/src/flows/plan-builder.ts +81 -5
  173. package/src/flows/probes.ts +17 -3
  174. package/src/flows/types.ts +31 -2
  175. package/src/health/health-registry.test.ts +3 -1
  176. package/src/index.ts +17 -0
  177. package/src/intake/dedup-gate.test.ts +2 -6
  178. package/src/intake/text-ingester.test.ts +3 -4
  179. package/src/llm/llm-client.test.ts +1 -1
  180. package/src/llm/utils.test.ts +1 -1
  181. package/src/migrations/migration-runner.test.ts +0 -1
  182. package/src/operator/operator-context-store.test.ts +0 -13
  183. package/src/operator/operator-profile.test.ts +2 -20
  184. package/src/packs/pack-installer.ts +28 -2
  185. package/src/packs/pack-system.test.ts +2 -2
  186. package/src/persona/defaults.test.ts +19 -19
  187. package/src/planning/gap-passes.test.ts +0 -46
  188. package/src/planning/gap-patterns.test.ts +0 -42
  189. package/src/planning/goal-ancestry.test.ts +3 -1
  190. package/src/planning/plan-lifecycle.test.ts +15 -7
  191. package/src/planning/planner-types.ts +2 -0
  192. package/src/planning/planner.ts +8 -0
  193. package/src/planning/reconciliation-engine.test.ts +3 -10
  194. package/src/planning/task-complexity-assessor.test.ts +0 -5
  195. package/src/planning/task-verifier.test.ts +3 -1
  196. package/src/playbooks/generic/generic-playbooks.test.ts +0 -28
  197. package/src/playbooks/index.test.ts +0 -55
  198. package/src/playbooks/playbook-executor.test.ts +76 -0
  199. package/src/playbooks/playbook-executor.ts +24 -3
  200. package/src/playbooks/playbook-types.ts +8 -0
  201. package/src/plugins/plugin-registry.test.ts +6 -2
  202. package/src/project/project-registry.test.ts +2 -0
  203. package/src/queue/async-infrastructure.test.ts +6 -4
  204. package/src/queue/job-queue.test.ts +13 -7
  205. package/src/runtime/admin-extra-ops.test.ts +35 -30
  206. package/src/runtime/admin-extra-ops.ts +30 -0
  207. package/src/runtime/admin-ops.test.ts +0 -4
  208. package/src/runtime/admin-ops.ts +63 -21
  209. package/src/runtime/admin-setup-ops.test.ts +185 -13
  210. package/src/runtime/admin-setup-ops.ts +86 -16
  211. package/src/runtime/archive-ops.test.ts +0 -28
  212. package/src/runtime/branching-ops.test.ts +0 -17
  213. package/src/runtime/capture-ops.test.ts +41 -16
  214. package/src/runtime/capture-ops.ts +78 -46
  215. package/src/runtime/chain-ops.test.ts +0 -21
  216. package/src/runtime/facades/admin-facade.test.ts +0 -34
  217. package/src/runtime/facades/agency-facade.test.ts +0 -39
  218. package/src/runtime/facades/archive-facade.test.ts +0 -43
  219. package/src/runtime/facades/brain-facade.test.ts +8 -99
  220. package/src/runtime/facades/brain-facade.ts +29 -12
  221. package/src/runtime/facades/branching-facade.test.ts +30 -17
  222. package/src/runtime/facades/chat-facade.test.ts +0 -91
  223. package/src/runtime/facades/chat-service-ops.test.ts +0 -24
  224. package/src/runtime/facades/chat-session-ops.test.ts +0 -12
  225. package/src/runtime/facades/chat-transport-ops.test.ts +0 -23
  226. package/src/runtime/facades/context-facade.test.ts +0 -17
  227. package/src/runtime/facades/context-facade.ts +11 -4
  228. package/src/runtime/facades/control-facade.test.ts +0 -30
  229. package/src/runtime/facades/curator-facade.test.ts +0 -33
  230. package/src/runtime/facades/intake-facade.test.ts +0 -33
  231. package/src/runtime/facades/links-facade.test.ts +0 -37
  232. package/src/runtime/facades/loop-facade.test.ts +0 -26
  233. package/src/runtime/facades/memory-facade.test.ts +0 -18
  234. package/src/runtime/facades/memory-facade.ts +27 -11
  235. package/src/runtime/facades/operator-facade.test.ts +0 -31
  236. package/src/runtime/facades/orchestrate-facade.test.ts +0 -21
  237. package/src/runtime/facades/orchestrate-facade.ts +12 -0
  238. package/src/runtime/facades/plan-facade.test.ts +7 -32
  239. package/src/runtime/facades/plan-facade.ts +137 -4
  240. package/src/runtime/facades/review-facade.test.ts +1 -49
  241. package/src/runtime/facades/sync-facade.test.ts +24 -41
  242. package/src/runtime/facades/tier-facade.test.ts +30 -22
  243. package/src/runtime/facades/vault-facade.test.ts +0 -41
  244. package/src/runtime/facades/vault-facade.ts +26 -3
  245. package/src/runtime/grading-ops.test.ts +0 -27
  246. package/src/runtime/intake-ops.test.ts +0 -19
  247. package/src/runtime/loop-ops.test.ts +0 -48
  248. package/src/runtime/memory-cross-project-ops.test.ts +0 -14
  249. package/src/runtime/memory-extra-ops.test.ts +4 -8
  250. package/src/runtime/orchestrate-ops.test.ts +238 -19
  251. package/src/runtime/orchestrate-ops.ts +166 -41
  252. package/src/runtime/pack-ops.test.ts +0 -26
  253. package/src/runtime/planning-extra-ops.test.ts +2 -14
  254. package/src/runtime/playbook-ops-execution.test.ts +9 -20
  255. package/src/runtime/playbook-ops.test.ts +4 -67
  256. package/src/runtime/review-ops.test.ts +0 -15
  257. package/src/runtime/schema-helpers.ts +4 -0
  258. package/src/runtime/sync-ops.test.ts +0 -18
  259. package/src/runtime/tier-ops.test.ts +0 -21
  260. package/src/runtime/vault-extra-ops.test.ts +0 -12
  261. package/src/runtime/vault-linking-ops.test.ts +0 -4
  262. package/src/runtime/vault-linking-ops.ts +26 -8
  263. package/src/runtime/vault-sharing-ops.test.ts +0 -9
  264. package/src/scheduler/cron-validator.ts +101 -0
  265. package/src/scheduler/platform-linux.ts +122 -0
  266. package/src/scheduler/platform-macos.ts +150 -0
  267. package/src/scheduler/scheduler-ops.ts +77 -0
  268. package/src/scheduler/scheduler.test.ts +247 -0
  269. package/src/scheduler/scheduler.ts +174 -0
  270. package/src/scheduler/types.ts +52 -0
  271. package/src/skills/__tests__/sync-skills.test.ts +6 -17
  272. package/src/skills/global-claude-md.test.ts +113 -0
  273. package/src/skills/sync-skills.ts +143 -35
  274. package/src/skills/validate-skills.test.ts +12 -11
  275. package/src/telemetry/telemetry.test.ts +1 -0
  276. package/src/transport/http-server.test.ts +3 -0
  277. package/src/transport/session-manager.test.ts +3 -1
  278. package/src/transport/token-auth.test.ts +6 -9
  279. package/src/transport/ws-server.test.ts +10 -2
  280. package/src/utils/worktree-reaper.ts +113 -0
  281. package/src/vault/__tests__/vault-characterization.test.ts +0 -108
  282. package/src/vault/linking.test.ts +0 -2
  283. package/src/vault/playbook.test.ts +4 -1
  284. package/src/vault/scope-detector.test.ts +3 -1
  285. package/src/vault/scope-detector.ts +42 -4
  286. package/src/vault/vault-connect.test.ts +1 -1
  287. package/src/vault/vault-entries.ts +3 -1
  288. package/src/vault/vault.test.ts +23 -8
@@ -51,14 +51,6 @@ describe('Vault Characterization Tests', () => {
51
51
  });
52
52
 
53
53
  describe('constructor', () => {
54
- it('creates an in-memory vault', () => {
55
- const v = new Vault(':memory:');
56
- expect(v).toBeInstanceOf(Vault);
57
- v.close();
58
- });
59
- it('stamps FORMAT_VERSION', () => {
60
- expect(Vault.FORMAT_VERSION).toBe(1);
61
- });
62
54
  it('createWithSQLite factory', () => {
63
55
  const v = Vault.createWithSQLite(':memory:');
64
56
  expect(v).toBeInstanceOf(Vault);
@@ -83,26 +75,11 @@ describe('Vault Characterization Tests', () => {
83
75
  });
84
76
 
85
77
  describe('seed', () => {
86
- it('inserts entries', () => {
87
- expect(vault.seed([makeEntry({ id: 'seed-1' })])).toBe(1);
88
- });
89
78
  it('upserts on conflict', () => {
90
79
  vault.seed([makeEntry({ id: 'u1', title: 'Old' })]);
91
80
  vault.seed([makeEntry({ id: 'u1', title: 'New' })]);
92
81
  expect(vault.get('u1')?.title).toBe('New');
93
82
  });
94
- it('handles multiple', () => {
95
- expect(
96
- vault.seed([makeEntry({ id: 'a1' }), makeEntry({ id: 'a2' }), makeEntry({ id: 'a3' })]),
97
- ).toBe(3);
98
- });
99
- });
100
-
101
- describe('add', () => {
102
- it('delegates to seed', () => {
103
- vault.add(makeEntry({ id: 'add-1' }));
104
- expect(vault.get('add-1')).toBeTruthy();
105
- });
106
83
  });
107
84
 
108
85
  describe('get', () => {
@@ -172,10 +149,6 @@ describe('Vault Characterization Tests', () => {
172
149
  });
173
150
 
174
151
  describe('list', () => {
175
- it('returns entries', () => {
176
- vault.seed([makeEntry({ id: 'l1' }), makeEntry({ id: 'l2' })]);
177
- expect(vault.list().length).toBe(2);
178
- });
179
152
  it('filters by domain', () => {
180
153
  vault.seed([
181
154
  makeEntry({ id: 'ld1', domain: 'react' }),
@@ -245,13 +218,6 @@ describe('Vault Characterization Tests', () => {
245
218
  ]);
246
219
  });
247
220
  });
248
- describe('getRecent', () => {
249
- it('returns entries', () => {
250
- vault.seed([makeEntry({ id: 'r1' })]);
251
- vault.seed([makeEntry({ id: 'r2' })]);
252
- expect(vault.getRecent(5).length).toBe(2);
253
- });
254
- });
255
221
 
256
222
  describe('setTemporal', () => {
257
223
  it('sets temporal fields', () => {
@@ -319,30 +285,7 @@ describe('Vault Characterization Tests', () => {
319
285
  expect(vault.findByContentHash('x')).toBeNull();
320
286
  });
321
287
  });
322
- describe('contentHashStats', () => {
323
- it('zeros for empty', () => {
324
- const s = vault.contentHashStats();
325
- expect(s.total).toBe(0);
326
- });
327
- it('counts', () => {
328
- vault.seed([
329
- makeEntry({ id: 'c1', title: 'First' }),
330
- makeEntry({ id: 'c2', title: 'Second' }),
331
- ]);
332
- const s = vault.contentHashStats();
333
- expect(s.total).toBe(2);
334
- expect(s.uniqueHashes).toBe(2);
335
- });
336
- });
337
288
 
338
- describe('exportAll', () => {
339
- it('exports all', () => {
340
- vault.seed([makeEntry({ id: 'e1' }), makeEntry({ id: 'e2' })]);
341
- const r = vault.exportAll();
342
- expect(r.count).toBe(2);
343
- expect(typeof r.exportedAt).toBe('number');
344
- });
345
- });
346
289
  describe('getAgeReport', () => {
347
290
  it('empty report', () => {
348
291
  const r = vault.getAgeReport();
@@ -389,12 +332,6 @@ describe('Vault Characterization Tests', () => {
389
332
  });
390
333
  });
391
334
 
392
- describe('optimize', () => {
393
- it('returns status', () => {
394
- const r = vault.optimize();
395
- expect(typeof r.vacuumed).toBe('boolean');
396
- });
397
- });
398
335
  describe('rebuildFtsIndex', () => {
399
336
  it('does not throw', () => {
400
337
  expect(() => vault.rebuildFtsIndex()).not.toThrow();
@@ -402,10 +339,6 @@ describe('Vault Characterization Tests', () => {
402
339
  });
403
340
 
404
341
  describe('registerProject', () => {
405
- it('registers new', () => {
406
- const p = vault.registerProject('/t', 'test');
407
- expect(p.sessionCount).toBe(1);
408
- });
409
342
  it('increments on re-register', () => {
410
343
  vault.registerProject('/t');
411
344
  expect(vault.registerProject('/t').sessionCount).toBe(2);
@@ -424,21 +357,7 @@ describe('Vault Characterization Tests', () => {
424
357
  expect(vault.getProject('/t')!.name).toBe('T');
425
358
  });
426
359
  });
427
- describe('listProjects', () => {
428
- it('lists all', () => {
429
- vault.registerProject('/a');
430
- vault.registerProject('/b');
431
- expect(vault.listProjects().length).toBe(2);
432
- });
433
- });
434
360
 
435
- describe('captureMemory', () => {
436
- it('creates with id', () => {
437
- const m = vault.captureMemory(makeMemoryInput());
438
- expect(m.id).toMatch(/^mem-/);
439
- expect(m.archivedAt).toBeNull();
440
- });
441
- });
442
361
  describe('getMemory', () => {
443
362
  it('returns null', () => {
444
363
  expect(vault.getMemory('x')).toBeNull();
@@ -489,9 +408,6 @@ describe('Vault Characterization Tests', () => {
489
408
  });
490
409
 
491
410
  describe('memoryStats', () => {
492
- it('zeros for empty', () => {
493
- expect(vault.memoryStats().total).toBe(0);
494
- });
495
411
  it('counts', () => {
496
412
  vault.captureMemory(makeMemoryInput({ projectPath: '/a', type: 'session' }));
497
413
  vault.captureMemory(makeMemoryInput({ projectPath: '/a', type: 'lesson' }));
@@ -502,20 +418,6 @@ describe('Vault Characterization Tests', () => {
502
418
  });
503
419
  });
504
420
 
505
- describe('memoryStatsDetailed', () => {
506
- it('includes extended fields', () => {
507
- vault.captureMemory(makeMemoryInput());
508
- const s = vault.memoryStatsDetailed();
509
- expect(typeof s.oldest).toBe('number');
510
- expect(s.archivedCount).toBe(0);
511
- });
512
- });
513
- describe('exportMemories', () => {
514
- it('exports', () => {
515
- vault.captureMemory(makeMemoryInput());
516
- expect(vault.exportMemories().length).toBe(1);
517
- });
518
- });
519
421
  describe('importMemories', () => {
520
422
  it('imports and deduplicates', () => {
521
423
  vault.captureMemory(makeMemoryInput());
@@ -560,16 +462,6 @@ describe('Vault Characterization Tests', () => {
560
462
  });
561
463
  });
562
464
 
563
- describe('getProvider', () => {
564
- it('returns provider', () => {
565
- expect(vault.getProvider().backend).toBe('sqlite');
566
- });
567
- });
568
- describe('getDb', () => {
569
- it('returns db', () => {
570
- expect(vault.getDb()).toBeTruthy();
571
- });
572
- });
573
465
  describe('close', () => {
574
466
  it('does not throw', () => {
575
467
  const v = new Vault(':memory:');
@@ -355,7 +355,6 @@ describe('LinkManager', () => {
355
355
  const result = mgr.backfillLinks();
356
356
  expect(result.processed).toBe(0);
357
357
  expect(result.linksCreated).toBe(0);
358
- expect(result.durationMs).toBeGreaterThanOrEqual(0);
359
358
  });
360
359
 
361
360
  it('dry run populates preview array', () => {
@@ -385,7 +384,6 @@ describe('LinkManager', () => {
385
384
  if (result.processed > 0 && result.preview) {
386
385
  expect(Array.isArray(result.preview)).toBe(true);
387
386
  }
388
- expect(result.durationMs).toBeGreaterThanOrEqual(0);
389
387
  });
390
388
 
391
389
  it('calls onProgress callback', () => {
@@ -95,7 +95,10 @@ describe('validatePlaybook', () => {
95
95
  const steps = [makeStep({ title: '', description: '' }, 1)];
96
96
  const result = validatePlaybook(makePlaybook({ title: '', steps }));
97
97
  expect(result.valid).toBe(false);
98
- expect(result.errors.length).toBeGreaterThanOrEqual(3);
98
+ expect(result.errors).toHaveLength(3);
99
+ expect(result.errors).toContain('Playbook title must not be empty');
100
+ expect(result.errors).toContain('Step 1 title must not be empty');
101
+ expect(result.errors).toContain('Step 1 description must not be empty');
99
102
  });
100
103
  });
101
104
 
@@ -165,11 +165,13 @@ describe('detectScope', () => {
165
165
  const result = detectScope(
166
166
  makeInput({ description: 'Use focus ring for keyboard navigation' }),
167
167
  );
168
+ expect(result.signals.length).toBeGreaterThan(0);
168
169
  for (const signal of result.signals) {
169
170
  expect(signal).toHaveProperty('tier');
170
171
  expect(signal).toHaveProperty('source');
171
172
  expect(signal).toHaveProperty('indicator');
172
173
  expect(signal).toHaveProperty('weight');
174
+ // Weight must be in (0, 1] range
173
175
  expect(signal.weight).toBeGreaterThan(0);
174
176
  expect(signal.weight).toBeLessThanOrEqual(1);
175
177
  }
@@ -179,7 +181,7 @@ describe('detectScope', () => {
179
181
  const result = detectScope(
180
182
  makeInput({ description: 'Accessibility best practice for a11y compliance' }),
181
183
  );
182
- expect(result.reason.length).toBeGreaterThan(0);
184
+ expect(result.reason).toMatch(/accessibility|a11y/i);
183
185
  expect(result.reason).not.toContain('defaulting');
184
186
  });
185
187
  });
@@ -49,7 +49,27 @@ const TEAM_CONTENT_PATTERNS: Array<{ pattern: RegExp; weight: number; desc: stri
49
49
  { pattern: /error\s+handling|error\s+boundary/i, weight: 0.6, desc: 'error handling' },
50
50
  { pattern: /touch\s+target|tap\s+target|fitts/i, weight: 0.8, desc: 'UX touch targets' },
51
51
  { pattern: /focus\s+(ring|state|indicator)/i, weight: 0.8, desc: 'focus states' },
52
- { pattern: /best\s+practice|anti.?pattern/i, weight: 0.65, desc: 'best practice' },
52
+ // Reduced weight: "best practice" alone is too weak to push to team tier
53
+ { pattern: /best\s+practice|anti.?pattern/i, weight: 0.4, desc: 'best practice' },
54
+ ];
55
+
56
+ /**
57
+ * Project-specific negative signals — agent/tool names and framework-specific patterns
58
+ * that indicate the entry is project-scoped, not universally applicable.
59
+ */
60
+ const PROJECT_SPECIFIC_PATTERNS: Array<{ pattern: RegExp; weight: number; desc: string }> = [
61
+ { pattern: /\bsoleri\b/i, weight: 0.9, desc: 'Soleri project reference' },
62
+ { pattern: /\bernesto\b/i, weight: 0.9, desc: 'Ernesto agent reference' },
63
+ { pattern: /\bsalvador\b/i, weight: 0.9, desc: 'Salvador agent reference' },
64
+ {
65
+ pattern: /\bskill\s+(file|system|pack|registry|sync)/i,
66
+ weight: 0.7,
67
+ desc: 'skill system specific',
68
+ },
69
+ { pattern: /vault\s+(entry|search|op|facade)/i, weight: 0.65, desc: 'vault system specific' },
70
+ { pattern: /domain\s+pack|hook\s+pack/i, weight: 0.7, desc: 'Soleri pack system' },
71
+ { pattern: /plan\s+(grade|facade|lifecycle)/i, weight: 0.65, desc: 'Soleri planning system' },
72
+ { pattern: /soleri\s+(agent|cli|core|forge)/i, weight: 0.95, desc: 'Soleri package reference' },
53
73
  ];
54
74
 
55
75
  const PROJECT_CONTENT_PATTERNS: Array<{ pattern: RegExp; weight: number; desc: string }> = [
@@ -128,6 +148,11 @@ function analyzeContent(text: string): ScopeSignal[] {
128
148
  signals.push({ tier: 'project', source: 'content', indicator: desc, weight });
129
149
  }
130
150
  }
151
+ for (const { pattern, weight, desc } of PROJECT_SPECIFIC_PATTERNS) {
152
+ if (pattern.test(text)) {
153
+ signals.push({ tier: 'project', source: 'content', indicator: desc, weight });
154
+ }
155
+ }
131
156
  for (const { pattern, weight, desc } of AGENT_CONTENT_PATTERNS) {
132
157
  if (pattern.test(text)) {
133
158
  signals.push({ tier: 'agent', source: 'content', indicator: desc, weight });
@@ -165,7 +190,11 @@ function analyzeTags(tags: string[]): ScopeSignal[] {
165
190
  return signals;
166
191
  }
167
192
 
168
- function computeConfidence(scores: Record<ScopeTier, number>, winner: ScopeTier): ConfidenceLevel {
193
+ function computeConfidence(
194
+ scores: Record<ScopeTier, number>,
195
+ winner: ScopeTier,
196
+ signals: ScopeSignal[],
197
+ ): ConfidenceLevel {
169
198
  const winScore = scores[winner];
170
199
  const others = Object.entries(scores)
171
200
  .filter(([t]) => t !== winner)
@@ -173,7 +202,16 @@ function computeConfidence(scores: Record<ScopeTier, number>, winner: ScopeTier)
173
202
  const runnerUp = Math.max(...others, 0);
174
203
 
175
204
  if (winScore === 0) return 'LOW';
176
- if (runnerUp === 0 && winScore >= 0.5) return 'HIGH';
205
+ if (runnerUp === 0 && winScore >= 0.5) {
206
+ // Cap team tier at MEDIUM when only generic/methodology signals drove the win
207
+ if (winner === 'team') {
208
+ const genericOnly = signals
209
+ .filter((s) => s.tier === 'team')
210
+ .every((s) => s.indicator === 'best practice' || s.source === 'category');
211
+ if (genericOnly) return 'MEDIUM';
212
+ }
213
+ return 'HIGH';
214
+ }
177
215
  const ratio = winScore / (winScore + runnerUp);
178
216
  if (ratio >= 0.7 && winScore >= 1.0) return 'HIGH';
179
217
  if (ratio >= 0.55) return 'MEDIUM';
@@ -205,7 +243,7 @@ export function detectScope(input: ScopeInput): ScopeDetectionResult {
205
243
  }
206
244
  }
207
245
 
208
- const confidence = computeConfidence(scores, winner);
246
+ const confidence = computeConfidence(scores, winner, signals);
209
247
  const topSignals = signals
210
248
  .filter((s) => s.tier === winner)
211
249
  .sort((a, b) => b.weight - a.weight)
@@ -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', () => {