@soleri/core 2.1.0 → 2.5.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 (377) hide show
  1. package/dist/brain/brain.d.ts +10 -1
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +116 -13
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +36 -1
  6. package/dist/brain/intelligence.d.ts.map +1 -1
  7. package/dist/brain/intelligence.js +119 -14
  8. package/dist/brain/intelligence.js.map +1 -1
  9. package/dist/brain/types.d.ts +34 -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 +22 -0
  20. package/dist/control/identity-manager.d.ts.map +1 -0
  21. package/dist/control/identity-manager.js +233 -0
  22. package/dist/control/identity-manager.js.map +1 -0
  23. package/dist/control/intent-router.d.ts +32 -0
  24. package/dist/control/intent-router.d.ts.map +1 -0
  25. package/dist/control/intent-router.js +242 -0
  26. package/dist/control/intent-router.js.map +1 -0
  27. package/dist/control/types.d.ts +68 -0
  28. package/dist/control/types.d.ts.map +1 -0
  29. package/dist/control/types.js +9 -0
  30. package/dist/control/types.js.map +1 -0
  31. package/dist/curator/curator.d.ts +37 -1
  32. package/dist/curator/curator.d.ts.map +1 -1
  33. package/dist/curator/curator.js +199 -1
  34. package/dist/curator/curator.js.map +1 -1
  35. package/dist/errors/classify.d.ts +13 -0
  36. package/dist/errors/classify.d.ts.map +1 -0
  37. package/dist/errors/classify.js +97 -0
  38. package/dist/errors/classify.js.map +1 -0
  39. package/dist/errors/index.d.ts +6 -0
  40. package/dist/errors/index.d.ts.map +1 -0
  41. package/dist/errors/index.js +4 -0
  42. package/dist/errors/index.js.map +1 -0
  43. package/dist/errors/retry.d.ts +40 -0
  44. package/dist/errors/retry.d.ts.map +1 -0
  45. package/dist/errors/retry.js +97 -0
  46. package/dist/errors/retry.js.map +1 -0
  47. package/dist/errors/types.d.ts +48 -0
  48. package/dist/errors/types.d.ts.map +1 -0
  49. package/dist/errors/types.js +59 -0
  50. package/dist/errors/types.js.map +1 -0
  51. package/dist/facades/types.d.ts +1 -1
  52. package/dist/governance/governance.d.ts +42 -0
  53. package/dist/governance/governance.d.ts.map +1 -0
  54. package/dist/governance/governance.js +488 -0
  55. package/dist/governance/governance.js.map +1 -0
  56. package/dist/governance/index.d.ts +3 -0
  57. package/dist/governance/index.d.ts.map +1 -0
  58. package/dist/governance/index.js +2 -0
  59. package/dist/governance/index.js.map +1 -0
  60. package/dist/governance/types.d.ts +102 -0
  61. package/dist/governance/types.d.ts.map +1 -0
  62. package/dist/governance/types.js +3 -0
  63. package/dist/governance/types.js.map +1 -0
  64. package/dist/index.d.ts +52 -3
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +47 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/intake/content-classifier.d.ts +14 -0
  69. package/dist/intake/content-classifier.d.ts.map +1 -0
  70. package/dist/intake/content-classifier.js +125 -0
  71. package/dist/intake/content-classifier.js.map +1 -0
  72. package/dist/intake/dedup-gate.d.ts +17 -0
  73. package/dist/intake/dedup-gate.d.ts.map +1 -0
  74. package/dist/intake/dedup-gate.js +66 -0
  75. package/dist/intake/dedup-gate.js.map +1 -0
  76. package/dist/intake/intake-pipeline.d.ts +63 -0
  77. package/dist/intake/intake-pipeline.d.ts.map +1 -0
  78. package/dist/intake/intake-pipeline.js +373 -0
  79. package/dist/intake/intake-pipeline.js.map +1 -0
  80. package/dist/intake/types.d.ts +65 -0
  81. package/dist/intake/types.d.ts.map +1 -0
  82. package/dist/intake/types.js +3 -0
  83. package/dist/intake/types.js.map +1 -0
  84. package/dist/intelligence/loader.js +1 -1
  85. package/dist/intelligence/loader.js.map +1 -1
  86. package/dist/intelligence/types.d.ts +3 -1
  87. package/dist/intelligence/types.d.ts.map +1 -1
  88. package/dist/logging/logger.d.ts +37 -0
  89. package/dist/logging/logger.d.ts.map +1 -0
  90. package/dist/logging/logger.js +145 -0
  91. package/dist/logging/logger.js.map +1 -0
  92. package/dist/logging/types.d.ts +19 -0
  93. package/dist/logging/types.d.ts.map +1 -0
  94. package/dist/logging/types.js +2 -0
  95. package/dist/logging/types.js.map +1 -0
  96. package/dist/loop/loop-manager.d.ts +100 -0
  97. package/dist/loop/loop-manager.d.ts.map +1 -0
  98. package/dist/loop/loop-manager.js +379 -0
  99. package/dist/loop/loop-manager.js.map +1 -0
  100. package/dist/loop/types.d.ts +103 -0
  101. package/dist/loop/types.d.ts.map +1 -0
  102. package/dist/loop/types.js +11 -0
  103. package/dist/loop/types.js.map +1 -0
  104. package/dist/persistence/index.d.ts +3 -0
  105. package/dist/persistence/index.d.ts.map +1 -0
  106. package/dist/persistence/index.js +2 -0
  107. package/dist/persistence/index.js.map +1 -0
  108. package/dist/persistence/sqlite-provider.d.ts +25 -0
  109. package/dist/persistence/sqlite-provider.d.ts.map +1 -0
  110. package/dist/persistence/sqlite-provider.js +59 -0
  111. package/dist/persistence/sqlite-provider.js.map +1 -0
  112. package/dist/persistence/types.d.ts +36 -0
  113. package/dist/persistence/types.d.ts.map +1 -0
  114. package/dist/persistence/types.js +8 -0
  115. package/dist/persistence/types.js.map +1 -0
  116. package/dist/planning/gap-analysis.d.ts +72 -0
  117. package/dist/planning/gap-analysis.d.ts.map +1 -0
  118. package/dist/planning/gap-analysis.js +442 -0
  119. package/dist/planning/gap-analysis.js.map +1 -0
  120. package/dist/planning/gap-types.d.ts +29 -0
  121. package/dist/planning/gap-types.d.ts.map +1 -0
  122. package/dist/planning/gap-types.js +28 -0
  123. package/dist/planning/gap-types.js.map +1 -0
  124. package/dist/planning/planner.d.ts +421 -4
  125. package/dist/planning/planner.d.ts.map +1 -1
  126. package/dist/planning/planner.js +949 -21
  127. package/dist/planning/planner.js.map +1 -1
  128. package/dist/playbooks/generic/brainstorming.d.ts +9 -0
  129. package/dist/playbooks/generic/brainstorming.d.ts.map +1 -0
  130. package/dist/playbooks/generic/brainstorming.js +105 -0
  131. package/dist/playbooks/generic/brainstorming.js.map +1 -0
  132. package/dist/playbooks/generic/code-review.d.ts +11 -0
  133. package/dist/playbooks/generic/code-review.d.ts.map +1 -0
  134. package/dist/playbooks/generic/code-review.js +176 -0
  135. package/dist/playbooks/generic/code-review.js.map +1 -0
  136. package/dist/playbooks/generic/subagent-execution.d.ts +9 -0
  137. package/dist/playbooks/generic/subagent-execution.d.ts.map +1 -0
  138. package/dist/playbooks/generic/subagent-execution.js +68 -0
  139. package/dist/playbooks/generic/subagent-execution.js.map +1 -0
  140. package/dist/playbooks/generic/systematic-debugging.d.ts +9 -0
  141. package/dist/playbooks/generic/systematic-debugging.d.ts.map +1 -0
  142. package/dist/playbooks/generic/systematic-debugging.js +87 -0
  143. package/dist/playbooks/generic/systematic-debugging.js.map +1 -0
  144. package/dist/playbooks/generic/tdd.d.ts +9 -0
  145. package/dist/playbooks/generic/tdd.d.ts.map +1 -0
  146. package/dist/playbooks/generic/tdd.js +70 -0
  147. package/dist/playbooks/generic/tdd.js.map +1 -0
  148. package/dist/playbooks/generic/verification.d.ts +9 -0
  149. package/dist/playbooks/generic/verification.d.ts.map +1 -0
  150. package/dist/playbooks/generic/verification.js +74 -0
  151. package/dist/playbooks/generic/verification.js.map +1 -0
  152. package/dist/playbooks/index.d.ts +4 -0
  153. package/dist/playbooks/index.d.ts.map +1 -0
  154. package/dist/playbooks/index.js +5 -0
  155. package/dist/playbooks/index.js.map +1 -0
  156. package/dist/playbooks/playbook-registry.d.ts +42 -0
  157. package/dist/playbooks/playbook-registry.d.ts.map +1 -0
  158. package/dist/playbooks/playbook-registry.js +227 -0
  159. package/dist/playbooks/playbook-registry.js.map +1 -0
  160. package/dist/playbooks/playbook-seeder.d.ts +47 -0
  161. package/dist/playbooks/playbook-seeder.d.ts.map +1 -0
  162. package/dist/playbooks/playbook-seeder.js +104 -0
  163. package/dist/playbooks/playbook-seeder.js.map +1 -0
  164. package/dist/playbooks/playbook-types.d.ts +132 -0
  165. package/dist/playbooks/playbook-types.d.ts.map +1 -0
  166. package/dist/playbooks/playbook-types.js +12 -0
  167. package/dist/playbooks/playbook-types.js.map +1 -0
  168. package/dist/project/project-registry.d.ts +79 -0
  169. package/dist/project/project-registry.d.ts.map +1 -0
  170. package/dist/project/project-registry.js +274 -0
  171. package/dist/project/project-registry.js.map +1 -0
  172. package/dist/project/types.d.ts +28 -0
  173. package/dist/project/types.d.ts.map +1 -0
  174. package/dist/project/types.js +5 -0
  175. package/dist/project/types.js.map +1 -0
  176. package/dist/prompts/index.d.ts +4 -0
  177. package/dist/prompts/index.d.ts.map +1 -0
  178. package/dist/prompts/index.js +3 -0
  179. package/dist/prompts/index.js.map +1 -0
  180. package/dist/prompts/parser.d.ts +17 -0
  181. package/dist/prompts/parser.d.ts.map +1 -0
  182. package/dist/prompts/parser.js +47 -0
  183. package/dist/prompts/parser.js.map +1 -0
  184. package/dist/prompts/template-manager.d.ts +25 -0
  185. package/dist/prompts/template-manager.d.ts.map +1 -0
  186. package/dist/prompts/template-manager.js +71 -0
  187. package/dist/prompts/template-manager.js.map +1 -0
  188. package/dist/prompts/types.d.ts +26 -0
  189. package/dist/prompts/types.d.ts.map +1 -0
  190. package/dist/prompts/types.js +5 -0
  191. package/dist/prompts/types.js.map +1 -0
  192. package/dist/runtime/admin-extra-ops.d.ts +15 -0
  193. package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
  194. package/dist/runtime/admin-extra-ops.js +595 -0
  195. package/dist/runtime/admin-extra-ops.js.map +1 -0
  196. package/dist/runtime/admin-ops.d.ts +15 -0
  197. package/dist/runtime/admin-ops.d.ts.map +1 -0
  198. package/dist/runtime/admin-ops.js +329 -0
  199. package/dist/runtime/admin-ops.js.map +1 -0
  200. package/dist/runtime/capture-ops.d.ts +15 -0
  201. package/dist/runtime/capture-ops.d.ts.map +1 -0
  202. package/dist/runtime/capture-ops.js +363 -0
  203. package/dist/runtime/capture-ops.js.map +1 -0
  204. package/dist/runtime/cognee-sync-ops.d.ts +12 -0
  205. package/dist/runtime/cognee-sync-ops.d.ts.map +1 -0
  206. package/dist/runtime/cognee-sync-ops.js +55 -0
  207. package/dist/runtime/cognee-sync-ops.js.map +1 -0
  208. package/dist/runtime/core-ops.d.ts +9 -3
  209. package/dist/runtime/core-ops.d.ts.map +1 -1
  210. package/dist/runtime/core-ops.js +693 -10
  211. package/dist/runtime/core-ops.js.map +1 -1
  212. package/dist/runtime/curator-extra-ops.d.ts +9 -0
  213. package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
  214. package/dist/runtime/curator-extra-ops.js +71 -0
  215. package/dist/runtime/curator-extra-ops.js.map +1 -0
  216. package/dist/runtime/domain-ops.d.ts.map +1 -1
  217. package/dist/runtime/domain-ops.js +61 -15
  218. package/dist/runtime/domain-ops.js.map +1 -1
  219. package/dist/runtime/grading-ops.d.ts +14 -0
  220. package/dist/runtime/grading-ops.d.ts.map +1 -0
  221. package/dist/runtime/grading-ops.js +105 -0
  222. package/dist/runtime/grading-ops.js.map +1 -0
  223. package/dist/runtime/intake-ops.d.ts +14 -0
  224. package/dist/runtime/intake-ops.d.ts.map +1 -0
  225. package/dist/runtime/intake-ops.js +110 -0
  226. package/dist/runtime/intake-ops.js.map +1 -0
  227. package/dist/runtime/loop-ops.d.ts +14 -0
  228. package/dist/runtime/loop-ops.d.ts.map +1 -0
  229. package/dist/runtime/loop-ops.js +251 -0
  230. package/dist/runtime/loop-ops.js.map +1 -0
  231. package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
  232. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
  233. package/dist/runtime/memory-cross-project-ops.js +165 -0
  234. package/dist/runtime/memory-cross-project-ops.js.map +1 -0
  235. package/dist/runtime/memory-extra-ops.d.ts +13 -0
  236. package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
  237. package/dist/runtime/memory-extra-ops.js +173 -0
  238. package/dist/runtime/memory-extra-ops.js.map +1 -0
  239. package/dist/runtime/orchestrate-ops.d.ts +17 -0
  240. package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
  241. package/dist/runtime/orchestrate-ops.js +246 -0
  242. package/dist/runtime/orchestrate-ops.js.map +1 -0
  243. package/dist/runtime/planning-extra-ops.d.ts +25 -0
  244. package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
  245. package/dist/runtime/planning-extra-ops.js +663 -0
  246. package/dist/runtime/planning-extra-ops.js.map +1 -0
  247. package/dist/runtime/playbook-ops.d.ts +14 -0
  248. package/dist/runtime/playbook-ops.d.ts.map +1 -0
  249. package/dist/runtime/playbook-ops.js +141 -0
  250. package/dist/runtime/playbook-ops.js.map +1 -0
  251. package/dist/runtime/project-ops.d.ts +15 -0
  252. package/dist/runtime/project-ops.d.ts.map +1 -0
  253. package/dist/runtime/project-ops.js +186 -0
  254. package/dist/runtime/project-ops.js.map +1 -0
  255. package/dist/runtime/runtime.d.ts.map +1 -1
  256. package/dist/runtime/runtime.js +65 -3
  257. package/dist/runtime/runtime.js.map +1 -1
  258. package/dist/runtime/types.d.ts +29 -0
  259. package/dist/runtime/types.d.ts.map +1 -1
  260. package/dist/runtime/vault-extra-ops.d.ts +10 -0
  261. package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
  262. package/dist/runtime/vault-extra-ops.js +536 -0
  263. package/dist/runtime/vault-extra-ops.js.map +1 -0
  264. package/dist/telemetry/telemetry.d.ts +48 -0
  265. package/dist/telemetry/telemetry.d.ts.map +1 -0
  266. package/dist/telemetry/telemetry.js +87 -0
  267. package/dist/telemetry/telemetry.js.map +1 -0
  268. package/dist/vault/playbook.d.ts +34 -0
  269. package/dist/vault/playbook.d.ts.map +1 -0
  270. package/dist/vault/playbook.js +60 -0
  271. package/dist/vault/playbook.js.map +1 -0
  272. package/dist/vault/vault.d.ts +97 -4
  273. package/dist/vault/vault.d.ts.map +1 -1
  274. package/dist/vault/vault.js +424 -65
  275. package/dist/vault/vault.js.map +1 -1
  276. package/package.json +7 -3
  277. package/src/__tests__/admin-extra-ops.test.ts +467 -0
  278. package/src/__tests__/admin-ops.test.ts +271 -0
  279. package/src/__tests__/brain-intelligence.test.ts +205 -0
  280. package/src/__tests__/brain.test.ts +134 -3
  281. package/src/__tests__/capture-ops.test.ts +509 -0
  282. package/src/__tests__/cognee-integration.test.ts +80 -0
  283. package/src/__tests__/cognee-sync-manager.test.ts +103 -0
  284. package/src/__tests__/core-ops.test.ts +292 -2
  285. package/src/__tests__/curator-extra-ops.test.ts +381 -0
  286. package/src/__tests__/domain-ops.test.ts +66 -0
  287. package/src/__tests__/errors.test.ts +388 -0
  288. package/src/__tests__/governance.test.ts +522 -0
  289. package/src/__tests__/grading-ops.test.ts +361 -0
  290. package/src/__tests__/identity-manager.test.ts +243 -0
  291. package/src/__tests__/intake-pipeline.test.ts +162 -0
  292. package/src/__tests__/intent-router.test.ts +222 -0
  293. package/src/__tests__/logger.test.ts +200 -0
  294. package/src/__tests__/loop-ops.test.ts +469 -0
  295. package/src/__tests__/memory-cross-project-ops.test.ts +248 -0
  296. package/src/__tests__/memory-extra-ops.test.ts +352 -0
  297. package/src/__tests__/orchestrate-ops.test.ts +289 -0
  298. package/src/__tests__/persistence.test.ts +225 -0
  299. package/src/__tests__/planner.test.ts +416 -7
  300. package/src/__tests__/planning-extra-ops.test.ts +706 -0
  301. package/src/__tests__/playbook-registry.test.ts +326 -0
  302. package/src/__tests__/playbook-seeder.test.ts +163 -0
  303. package/src/__tests__/playbook.test.ts +389 -0
  304. package/src/__tests__/project-ops.test.ts +381 -0
  305. package/src/__tests__/template-manager.test.ts +222 -0
  306. package/src/__tests__/vault-extra-ops.test.ts +482 -0
  307. package/src/brain/brain.ts +185 -16
  308. package/src/brain/intelligence.ts +179 -10
  309. package/src/brain/types.ts +40 -2
  310. package/src/cognee/client.ts +18 -0
  311. package/src/cognee/sync-manager.ts +389 -0
  312. package/src/control/identity-manager.ts +354 -0
  313. package/src/control/intent-router.ts +326 -0
  314. package/src/control/types.ts +102 -0
  315. package/src/curator/curator.ts +295 -1
  316. package/src/errors/classify.ts +102 -0
  317. package/src/errors/index.ts +5 -0
  318. package/src/errors/retry.ts +132 -0
  319. package/src/errors/types.ts +81 -0
  320. package/src/governance/governance.ts +698 -0
  321. package/src/governance/index.ts +18 -0
  322. package/src/governance/types.ts +111 -0
  323. package/src/index.ts +213 -2
  324. package/src/intake/content-classifier.ts +146 -0
  325. package/src/intake/dedup-gate.ts +92 -0
  326. package/src/intake/intake-pipeline.ts +503 -0
  327. package/src/intake/types.ts +69 -0
  328. package/src/intelligence/loader.ts +1 -1
  329. package/src/intelligence/types.ts +3 -1
  330. package/src/logging/logger.ts +154 -0
  331. package/src/logging/types.ts +21 -0
  332. package/src/loop/loop-manager.ts +448 -0
  333. package/src/loop/types.ts +115 -0
  334. package/src/persistence/index.ts +7 -0
  335. package/src/persistence/sqlite-provider.ts +62 -0
  336. package/src/persistence/types.ts +44 -0
  337. package/src/planning/gap-analysis.ts +775 -0
  338. package/src/planning/gap-types.ts +61 -0
  339. package/src/planning/planner.ts +1273 -24
  340. package/src/playbooks/generic/brainstorming.ts +110 -0
  341. package/src/playbooks/generic/code-review.ts +181 -0
  342. package/src/playbooks/generic/subagent-execution.ts +74 -0
  343. package/src/playbooks/generic/systematic-debugging.ts +92 -0
  344. package/src/playbooks/generic/tdd.ts +75 -0
  345. package/src/playbooks/generic/verification.ts +79 -0
  346. package/src/playbooks/index.ts +27 -0
  347. package/src/playbooks/playbook-registry.ts +284 -0
  348. package/src/playbooks/playbook-seeder.ts +119 -0
  349. package/src/playbooks/playbook-types.ts +162 -0
  350. package/src/project/project-registry.ts +370 -0
  351. package/src/project/types.ts +31 -0
  352. package/src/prompts/index.ts +3 -0
  353. package/src/prompts/parser.ts +59 -0
  354. package/src/prompts/template-manager.ts +77 -0
  355. package/src/prompts/types.ts +28 -0
  356. package/src/runtime/admin-extra-ops.ts +652 -0
  357. package/src/runtime/admin-ops.ts +340 -0
  358. package/src/runtime/capture-ops.ts +404 -0
  359. package/src/runtime/cognee-sync-ops.ts +63 -0
  360. package/src/runtime/core-ops.ts +787 -9
  361. package/src/runtime/curator-extra-ops.ts +85 -0
  362. package/src/runtime/domain-ops.ts +67 -15
  363. package/src/runtime/grading-ops.ts +130 -0
  364. package/src/runtime/intake-ops.ts +126 -0
  365. package/src/runtime/loop-ops.ts +277 -0
  366. package/src/runtime/memory-cross-project-ops.ts +191 -0
  367. package/src/runtime/memory-extra-ops.ts +186 -0
  368. package/src/runtime/orchestrate-ops.ts +278 -0
  369. package/src/runtime/planning-extra-ops.ts +718 -0
  370. package/src/runtime/playbook-ops.ts +169 -0
  371. package/src/runtime/project-ops.ts +202 -0
  372. package/src/runtime/runtime.ts +77 -3
  373. package/src/runtime/types.ts +29 -0
  374. package/src/runtime/vault-extra-ops.ts +606 -0
  375. package/src/telemetry/telemetry.ts +118 -0
  376. package/src/vault/playbook.ts +87 -0
  377. package/src/vault/vault.ts +575 -98
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Types for Identity Management and Intent Routing.
3
+ *
4
+ * Two separate concerns:
5
+ * - Identity: agent persona CRUD with versioning and guidelines
6
+ * - Intent Routing: keyword-based intent classification and operational modes
7
+ */
8
+
9
+ // ─── Identity Types ──────────────────────────────────────────────────
10
+
11
+ export type GuidelineCategory = 'behavior' | 'preference' | 'restriction' | 'style';
12
+
13
+ export interface Guideline {
14
+ id: string;
15
+ category: GuidelineCategory;
16
+ text: string;
17
+ priority: number;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ }
21
+
22
+ export interface AgentIdentity {
23
+ agentId: string;
24
+ name: string;
25
+ role: string;
26
+ description: string;
27
+ personality: string[];
28
+ guidelines: Guideline[];
29
+ version: number;
30
+ updatedAt: string;
31
+ }
32
+
33
+ export interface IdentityVersion {
34
+ version: number;
35
+ snapshot: string;
36
+ changedBy: string;
37
+ changeReason: string;
38
+ createdAt: string;
39
+ }
40
+
41
+ export interface IdentityUpdateInput {
42
+ name?: string;
43
+ role?: string;
44
+ description?: string;
45
+ personality?: string[];
46
+ changedBy?: string;
47
+ changeReason?: string;
48
+ }
49
+
50
+ export interface GuidelineInput {
51
+ category: GuidelineCategory;
52
+ text: string;
53
+ priority?: number;
54
+ }
55
+
56
+ // ─── Intent Routing Types ────────────────────────────────────────────
57
+
58
+ export type IntentType =
59
+ | 'build'
60
+ | 'fix'
61
+ | 'validate'
62
+ | 'design'
63
+ | 'improve'
64
+ | 'deliver'
65
+ | 'explore'
66
+ | 'plan'
67
+ | 'review'
68
+ | 'general';
69
+
70
+ export type OperationalMode =
71
+ | 'BUILD-MODE'
72
+ | 'FIX-MODE'
73
+ | 'VALIDATE-MODE'
74
+ | 'DESIGN-MODE'
75
+ | 'IMPROVE-MODE'
76
+ | 'DELIVER-MODE'
77
+ | 'EXPLORE-MODE'
78
+ | 'PLAN-MODE'
79
+ | 'REVIEW-MODE'
80
+ | 'GENERAL-MODE';
81
+
82
+ export interface IntentClassification {
83
+ intent: IntentType;
84
+ mode: OperationalMode;
85
+ confidence: number;
86
+ method: 'keyword';
87
+ matchedKeywords: string[];
88
+ }
89
+
90
+ export interface ModeConfig {
91
+ mode: OperationalMode;
92
+ intent: IntentType;
93
+ description: string;
94
+ behaviorRules: string[];
95
+ keywords: string[];
96
+ }
97
+
98
+ export interface MorphResult {
99
+ previousMode: OperationalMode;
100
+ currentMode: OperationalMode;
101
+ behaviorRules: string[];
102
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Vault } from '../vault/vault.js';
2
2
  import type { IntelligenceEntry } from '../intelligence/types.js';
3
+ import type { CogneeClient } from '../cognee/client.js';
3
4
  import {
4
5
  tokenize,
5
6
  calculateTfIdf,
@@ -49,9 +50,11 @@ const DEFAULT_TAG_ALIASES: Array<[string, string]> = [
49
50
 
50
51
  export class Curator {
51
52
  private vault: Vault;
53
+ private cognee: CogneeClient | undefined;
52
54
 
53
- constructor(vault: Vault) {
55
+ constructor(vault: Vault, cognee?: CogneeClient) {
54
56
  this.vault = vault;
57
+ this.cognee = cognee;
55
58
  this.initializeTables();
56
59
  this.seedDefaultAliases();
57
60
  }
@@ -93,6 +96,15 @@ export class Curator {
93
96
  created_at INTEGER NOT NULL DEFAULT (unixepoch())
94
97
  );
95
98
 
99
+ CREATE TABLE IF NOT EXISTS curator_entry_history (
100
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
101
+ entry_id TEXT NOT NULL,
102
+ snapshot TEXT NOT NULL,
103
+ changed_by TEXT DEFAULT 'system',
104
+ change_reason TEXT,
105
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
106
+ );
107
+
96
108
  CREATE TABLE IF NOT EXISTS curator_contradictions (
97
109
  id INTEGER PRIMARY KEY AUTOINCREMENT,
98
110
  pattern_id TEXT NOT NULL,
@@ -369,6 +381,85 @@ export class Curator {
369
381
  return row ? this.rowToContradiction(row) : null;
370
382
  }
371
383
 
384
+ async detectContradictionsHybrid(threshold?: number): Promise<{
385
+ contradictions: Contradiction[];
386
+ cogneeAvailable: boolean;
387
+ method: 'hybrid' | 'tfidf-only';
388
+ }> {
389
+ const effectiveThreshold = threshold ?? DEFAULT_CONTRADICTION_THRESHOLD;
390
+ const entries = this.vault.list({ limit: 100000 });
391
+ const antipatterns = entries.filter((e) => e.type === 'anti-pattern');
392
+ const patterns = entries.filter((e) => e.type === 'pattern');
393
+
394
+ if (antipatterns.length === 0 || patterns.length === 0) {
395
+ return { contradictions: [], cogneeAvailable: false, method: 'tfidf-only' };
396
+ }
397
+
398
+ const vocabulary = this.buildVocabulary(entries);
399
+ const db = this.vault.getDb();
400
+ const detected: Contradiction[] = [];
401
+
402
+ const insertStmt = db.prepare(
403
+ `INSERT OR IGNORE INTO curator_contradictions (pattern_id, antipattern_id, similarity)
404
+ VALUES (?, ?, ?)`,
405
+ );
406
+
407
+ const cogneeAvailable = this.cognee?.isAvailable ?? false;
408
+
409
+ for (const ap of antipatterns) {
410
+ let candidates: IntelligenceEntry[];
411
+ try {
412
+ const searchResults = this.vault.search(ap.title, { type: 'pattern', limit: 20 });
413
+ candidates = searchResults.length > 0 ? searchResults.map((r) => r.entry) : patterns;
414
+ } catch {
415
+ candidates = patterns;
416
+ }
417
+
418
+ const apText = [ap.title, ap.description, ap.context ?? ''].join(' ');
419
+ const apVec = calculateTfIdf(tokenize(apText), vocabulary);
420
+
421
+ for (const pattern of candidates) {
422
+ const pText = [pattern.title, pattern.description, pattern.context ?? ''].join(' ');
423
+ const pVec = calculateTfIdf(tokenize(pText), vocabulary);
424
+ const tfidfScore = cosineSimilarity(apVec, pVec);
425
+
426
+ let finalScore = tfidfScore;
427
+ if (cogneeAvailable && this.cognee) {
428
+ try {
429
+ const cogneeResults = await this.cognee.search(`${ap.title} ${pattern.title}`, {
430
+ limit: 5,
431
+ });
432
+ const cogneeScore =
433
+ cogneeResults.length > 0
434
+ ? cogneeResults.reduce((sum, r) => sum + r.score, 0) / cogneeResults.length
435
+ : 0;
436
+ finalScore = 0.6 * tfidfScore + 0.4 * cogneeScore;
437
+ } catch {
438
+ finalScore = tfidfScore;
439
+ }
440
+ }
441
+
442
+ if (finalScore >= effectiveThreshold) {
443
+ const result = insertStmt.run(pattern.id, ap.id, finalScore);
444
+ if (result.changes > 0) {
445
+ const row = db
446
+ .prepare(
447
+ 'SELECT * FROM curator_contradictions WHERE pattern_id = ? AND antipattern_id = ?',
448
+ )
449
+ .get(pattern.id, ap.id) as Record<string, unknown>;
450
+ detected.push(this.rowToContradiction(row));
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ return {
457
+ contradictions: detected,
458
+ cogneeAvailable,
459
+ method: cogneeAvailable ? 'hybrid' : 'tfidf-only',
460
+ };
461
+ }
462
+
372
463
  // ─── Grooming ───────────────────────────────────────────────────
373
464
 
374
465
  groomEntry(entryId: string): GroomResult | null {
@@ -638,6 +729,209 @@ export class Curator {
638
729
  };
639
730
  }
640
731
 
732
+ // ─── Entry History (Version Snapshots) ─────────────────────────
733
+
734
+ recordSnapshot(
735
+ entryId: string,
736
+ changedBy?: string,
737
+ changeReason?: string,
738
+ ): { recorded: boolean; historyId: number } {
739
+ const entry = this.vault.get(entryId);
740
+ if (!entry) return { recorded: false, historyId: -1 };
741
+
742
+ const db = this.vault.getDb();
743
+ const result = db
744
+ .prepare(
745
+ 'INSERT INTO curator_entry_history (entry_id, snapshot, changed_by, change_reason, created_at) VALUES (?, ?, ?, ?, unixepoch())',
746
+ )
747
+ .run(entryId, JSON.stringify(entry), changedBy ?? 'system', changeReason ?? null);
748
+
749
+ return { recorded: true, historyId: Number(result.lastInsertRowid) };
750
+ }
751
+
752
+ getVersionHistory(entryId: string): Array<{
753
+ historyId: number;
754
+ entryId: string;
755
+ snapshot: IntelligenceEntry;
756
+ changedBy: string;
757
+ changeReason: string | null;
758
+ createdAt: number;
759
+ }> {
760
+ const db = this.vault.getDb();
761
+ const rows = db
762
+ .prepare(
763
+ 'SELECT * FROM curator_entry_history WHERE entry_id = ? ORDER BY created_at ASC, id ASC',
764
+ )
765
+ .all(entryId) as Array<Record<string, unknown>>;
766
+
767
+ return rows.map((row) => ({
768
+ historyId: row.id as number,
769
+ entryId: row.entry_id as string,
770
+ snapshot: JSON.parse(row.snapshot as string) as IntelligenceEntry,
771
+ changedBy: row.changed_by as string,
772
+ changeReason: (row.change_reason as string) ?? null,
773
+ createdAt: row.created_at as number,
774
+ }));
775
+ }
776
+
777
+ // ─── Queue Stats ──────────────────────────────────────────────
778
+
779
+ getQueueStats(): {
780
+ totalEntries: number;
781
+ groomedEntries: number;
782
+ ungroomedEntries: number;
783
+ staleEntries: number;
784
+ freshEntries: number;
785
+ avgDaysSinceGroom: number;
786
+ } {
787
+ const db = this.vault.getDb();
788
+ const totalEntries = (
789
+ db.prepare('SELECT COUNT(*) as count FROM entries').get() as { count: number }
790
+ ).count;
791
+
792
+ const groomedEntries = (
793
+ db
794
+ .prepare(
795
+ 'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
796
+ )
797
+ .get() as { count: number }
798
+ ).count;
799
+
800
+ const ungroomedEntries = totalEntries - groomedEntries;
801
+
802
+ const now = Math.floor(Date.now() / 1000);
803
+ const staleThreshold = now - 30 * 86400;
804
+ const freshThreshold = now - 7 * 86400;
805
+
806
+ const staleEntries = (
807
+ db
808
+ .prepare(
809
+ 'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL AND last_groomed_at < ?',
810
+ )
811
+ .get(staleThreshold) as { count: number }
812
+ ).count;
813
+
814
+ const freshEntries = (
815
+ db
816
+ .prepare(
817
+ 'SELECT COUNT(*) as count FROM curator_entry_state WHERE last_groomed_at IS NOT NULL AND last_groomed_at >= ?',
818
+ )
819
+ .get(freshThreshold) as { count: number }
820
+ ).count;
821
+
822
+ let avgDaysSinceGroom = 0;
823
+ if (groomedEntries > 0) {
824
+ const sumRow = db
825
+ .prepare(
826
+ 'SELECT SUM(? - last_groomed_at) as total FROM curator_entry_state WHERE last_groomed_at IS NOT NULL',
827
+ )
828
+ .get(now) as { total: number | null };
829
+ const totalSeconds = sumRow.total ?? 0;
830
+ avgDaysSinceGroom = Math.round((totalSeconds / groomedEntries / 86400) * 100) / 100;
831
+ }
832
+
833
+ return {
834
+ totalEntries,
835
+ groomedEntries,
836
+ ungroomedEntries,
837
+ staleEntries,
838
+ freshEntries,
839
+ avgDaysSinceGroom,
840
+ };
841
+ }
842
+
843
+ // ─── Metadata Enrichment ──────────────────────────────────────
844
+
845
+ enrichMetadata(entryId: string): {
846
+ enriched: boolean;
847
+ changes: Array<{ field: string; before: string; after: string }>;
848
+ } {
849
+ const entry = this.vault.get(entryId);
850
+ if (!entry) return { enriched: false, changes: [] };
851
+
852
+ const changes: Array<{ field: string; before: string; after: string }> = [];
853
+ const updates: Partial<
854
+ Pick<IntelligenceEntry, 'title' | 'description' | 'tags' | 'severity' | 'type'>
855
+ > = {};
856
+
857
+ // Auto-capitalize title
858
+ if (entry.title.length > 0 && entry.title[0] !== entry.title[0].toUpperCase()) {
859
+ const capitalized = entry.title[0].toUpperCase() + entry.title.slice(1);
860
+ changes.push({ field: 'title', before: entry.title, after: capitalized });
861
+ updates.title = capitalized;
862
+ }
863
+
864
+ // Normalize tags: lowercase, trim, dedup
865
+ const normalizedTags = [...new Set(entry.tags.map((t) => t.toLowerCase().trim()))];
866
+ const tagsChanged =
867
+ normalizedTags.length !== entry.tags.length ||
868
+ normalizedTags.some((t, i) => t !== entry.tags[i]);
869
+ if (tagsChanged) {
870
+ changes.push({
871
+ field: 'tags',
872
+ before: JSON.stringify(entry.tags),
873
+ after: JSON.stringify(normalizedTags),
874
+ });
875
+ updates.tags = normalizedTags;
876
+ }
877
+
878
+ // Infer severity from keywords if currently 'suggestion'
879
+ if (entry.severity === 'suggestion') {
880
+ const text = (entry.title + ' ' + entry.description).toLowerCase();
881
+ const criticalKeywords = ['never', 'must not', 'critical', 'security', 'vulnerability'];
882
+ const warningKeywords = ['avoid', 'should not', 'deprecated', 'careful', 'warning'];
883
+ if (criticalKeywords.some((k) => text.includes(k))) {
884
+ changes.push({ field: 'severity', before: entry.severity, after: 'critical' });
885
+ updates.severity = 'critical';
886
+ } else if (warningKeywords.some((k) => text.includes(k))) {
887
+ changes.push({ field: 'severity', before: entry.severity, after: 'warning' });
888
+ updates.severity = 'warning';
889
+ }
890
+ }
891
+
892
+ // Infer type from title patterns
893
+ if (entry.type === 'pattern') {
894
+ const titleLower = entry.title.toLowerCase();
895
+ if (
896
+ titleLower.startsWith('avoid') ||
897
+ titleLower.startsWith('never') ||
898
+ titleLower.startsWith("don't") ||
899
+ titleLower.startsWith('do not')
900
+ ) {
901
+ changes.push({ field: 'type', before: entry.type, after: 'anti-pattern' });
902
+ updates.type = 'anti-pattern';
903
+ }
904
+ }
905
+
906
+ // Trim whitespace from description
907
+ const trimmed = entry.description.trim();
908
+ if (trimmed !== entry.description) {
909
+ changes.push({ field: 'description', before: entry.description, after: trimmed });
910
+ updates.description = trimmed;
911
+ }
912
+
913
+ if (changes.length === 0) {
914
+ return { enriched: false, changes: [] };
915
+ }
916
+
917
+ // Apply updates
918
+ this.vault.update(entryId, updates);
919
+
920
+ // Record snapshot
921
+ this.recordSnapshot(entryId, 'curator', 'Metadata enrichment');
922
+
923
+ // Log change
924
+ this.logChange(
925
+ 'enrich_metadata',
926
+ entryId,
927
+ JSON.stringify(changes.map((c) => c.field)),
928
+ JSON.stringify(changes.map((c) => c.after)),
929
+ 'Rule-based metadata enrichment',
930
+ );
931
+
932
+ return { enriched: true, changes };
933
+ }
934
+
641
935
  // ─── Private Helpers ────────────────────────────────────────────
642
936
 
643
937
  private buildVocabulary(entries: IntelligenceEntry[]): Map<string, number> {
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Error classifier — converts any thrown value into a typed SoleriError.
3
+ *
4
+ * Maps HTTP status codes, network error codes, and message patterns
5
+ * to the appropriate SoleriErrorCode.
6
+ */
7
+
8
+ import { SoleriError, SoleriErrorCode } from './types.js';
9
+
10
+ interface ErrorLike {
11
+ message?: string;
12
+ status?: number;
13
+ statusCode?: number;
14
+ code?: string;
15
+ cause?: unknown;
16
+ }
17
+
18
+ function toErrorLike(error: unknown): ErrorLike {
19
+ if (error instanceof SoleriError) return error;
20
+ if (error instanceof Error) return error as unknown as ErrorLike;
21
+ if (typeof error === 'object' && error !== null) return error as ErrorLike;
22
+ return { message: String(error) };
23
+ }
24
+
25
+ function getHttpStatus(e: ErrorLike): number | undefined {
26
+ return e.status ?? e.statusCode;
27
+ }
28
+
29
+ function classifyByHttpStatus(status: number): SoleriErrorCode | undefined {
30
+ if (status === 401 || status === 403) return SoleriErrorCode.AUTH;
31
+ if (status === 404) return SoleriErrorCode.RESOURCE_NOT_FOUND;
32
+ if (status === 408) return SoleriErrorCode.TIMEOUT;
33
+ if (status === 429) return SoleriErrorCode.RATE_LIMIT;
34
+ if (status === 422) return SoleriErrorCode.VALIDATION;
35
+ if (status >= 500 && status < 600) return SoleriErrorCode.INTERNAL;
36
+ return undefined;
37
+ }
38
+
39
+ const NETWORK_CODES = new Set(['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'EPIPE', 'EHOSTUNREACH']);
40
+ const TIMEOUT_CODES = new Set(['ETIMEDOUT', 'ESOCKETTIMEDOUT', 'UND_ERR_CONNECT_TIMEOUT']);
41
+
42
+ function classifyByErrorCode(code: string | undefined): SoleriErrorCode | undefined {
43
+ if (!code) return undefined;
44
+ if (NETWORK_CODES.has(code)) return SoleriErrorCode.NETWORK;
45
+ if (TIMEOUT_CODES.has(code)) return SoleriErrorCode.TIMEOUT;
46
+ return undefined;
47
+ }
48
+
49
+ const MESSAGE_PATTERNS: Array<[RegExp, SoleriErrorCode]> = [
50
+ [/overloaded|capacity|model.*busy/i, SoleriErrorCode.LLM_OVERLOAD],
51
+ [/timeout|timed?\s*out/i, SoleriErrorCode.TIMEOUT],
52
+ [/vault|database|sqlite/i, SoleriErrorCode.VAULT_UNREACHABLE],
53
+ [/invalid|validation|schema/i, SoleriErrorCode.VALIDATION],
54
+ [/config(uration)?|missing.*key|env/i, SoleriErrorCode.CONFIG_ERROR],
55
+ [/auth(entication|orization)?|forbidden|denied|unauthorized/i, SoleriErrorCode.AUTH],
56
+ [/not\s*found|404|no\s+such/i, SoleriErrorCode.RESOURCE_NOT_FOUND],
57
+ [/rate\s*limit|too\s+many\s+requests|throttl/i, SoleriErrorCode.RATE_LIMIT],
58
+ [/network|connect|socket|dns/i, SoleriErrorCode.NETWORK],
59
+ ];
60
+
61
+ function classifyByMessage(message: string | undefined): SoleriErrorCode | undefined {
62
+ if (!message) return undefined;
63
+ for (const [pattern, code] of MESSAGE_PATTERNS) {
64
+ if (pattern.test(message)) return code;
65
+ }
66
+ return undefined;
67
+ }
68
+
69
+ /**
70
+ * Classify any thrown value into a SoleriError.
71
+ * If the value is already a SoleriError, returns it as-is.
72
+ */
73
+ export function classifyError(error: unknown): SoleriError {
74
+ if (error instanceof SoleriError) return error;
75
+
76
+ const e = toErrorLike(error);
77
+ const originalError = error instanceof Error ? error : undefined;
78
+ const message = e.message ?? 'Unknown error';
79
+
80
+ // 1. HTTP status code
81
+ const httpStatus = getHttpStatus(e);
82
+ if (httpStatus !== undefined) {
83
+ const code = classifyByHttpStatus(httpStatus);
84
+ if (code)
85
+ return new SoleriError(message, code, { cause: originalError, context: { httpStatus } });
86
+ }
87
+
88
+ // 2. Node.js error code
89
+ const errCode = classifyByErrorCode(e.code);
90
+ if (errCode)
91
+ return new SoleriError(message, errCode, {
92
+ cause: originalError,
93
+ context: { errorCode: e.code },
94
+ });
95
+
96
+ // 3. Message pattern matching
97
+ const msgCode = classifyByMessage(message);
98
+ if (msgCode) return new SoleriError(message, msgCode, { cause: originalError });
99
+
100
+ // 4. Default: permanent INTERNAL
101
+ return new SoleriError(message, SoleriErrorCode.INTERNAL, { cause: originalError });
102
+ }
@@ -0,0 +1,5 @@
1
+ export { SoleriErrorCode, SoleriError, ok, err, isOk, isErr } from './types.js';
2
+ export type { ErrorClassification, Result, SoleriErrorOptions } from './types.js';
3
+ export { classifyError } from './classify.js';
4
+ export { retryWithPreset, shouldRetry, getRetryDelay, RETRY_PRESETS } from './retry.js';
5
+ export type { RetryPreset, RetryConfig, RetryOptions } from './retry.js';
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Retry presets with exponential backoff + jitter.
3
+ *
4
+ * Three presets map to different execution contexts:
5
+ * - fast: quick API calls, 3 attempts, short waits
6
+ * - normal: standard operations, 10 attempts, moderate waits
7
+ * - patient: batch/pipeline work, 25 attempts, long waits
8
+ */
9
+
10
+ import { classifyError } from './classify.js';
11
+ import { SoleriError, type Result, ok, err } from './types.js';
12
+
13
+ // ─── Types ─────────────────────────────────────────────────────────────
14
+
15
+ export type RetryPreset = 'fast' | 'normal' | 'patient';
16
+
17
+ export interface RetryConfig {
18
+ initialIntervalMs: number;
19
+ maxIntervalMs: number;
20
+ maxAttempts: number;
21
+ backoffMultiplier: number;
22
+ }
23
+
24
+ export interface RetryOptions {
25
+ onRetry?: (error: SoleriError, attempt: number, delayMs: number) => void;
26
+ signal?: AbortSignal;
27
+ }
28
+
29
+ // ─── Presets ───────────────────────────────────────────────────────────
30
+
31
+ export const RETRY_PRESETS: Record<RetryPreset, RetryConfig> = {
32
+ fast: { initialIntervalMs: 1_000, maxIntervalMs: 10_000, maxAttempts: 3, backoffMultiplier: 2 },
33
+ normal: {
34
+ initialIntervalMs: 10_000,
35
+ maxIntervalMs: 120_000,
36
+ maxAttempts: 10,
37
+ backoffMultiplier: 2,
38
+ },
39
+ patient: {
40
+ initialIntervalMs: 60_000,
41
+ maxIntervalMs: 900_000,
42
+ maxAttempts: 25,
43
+ backoffMultiplier: 1.5,
44
+ },
45
+ };
46
+
47
+ // ─── Helpers ───────────────────────────────────────────────────────────
48
+
49
+ /**
50
+ * Check if a classified error should be retried at the given attempt.
51
+ */
52
+ export function shouldRetry(error: SoleriError, attempt: number, preset: RetryPreset): boolean {
53
+ if (!error.retryable) return false;
54
+ return attempt < RETRY_PRESETS[preset].maxAttempts;
55
+ }
56
+
57
+ /**
58
+ * Calculate retry delay with exponential backoff + jitter.
59
+ * Jitter adds ±25% to prevent thundering herd.
60
+ */
61
+ export function getRetryDelay(attempt: number, preset: RetryPreset): number {
62
+ const config = RETRY_PRESETS[preset];
63
+ const base = config.initialIntervalMs * Math.pow(config.backoffMultiplier, attempt);
64
+ const capped = Math.min(base, config.maxIntervalMs);
65
+ // ±25% jitter
66
+ const jitter = capped * 0.25 * (Math.random() * 2 - 1);
67
+ return Math.max(0, Math.round(capped + jitter));
68
+ }
69
+
70
+ // ─── Retry Loop ────────────────────────────────────────────────────────
71
+
72
+ function sleep(ms: number, signal?: AbortSignal): Promise<void> {
73
+ return new Promise((resolve, reject) => {
74
+ if (signal?.aborted) {
75
+ reject(signal.reason ?? new Error('Aborted'));
76
+ return;
77
+ }
78
+ const timer = setTimeout(resolve, ms);
79
+ signal?.addEventListener(
80
+ 'abort',
81
+ () => {
82
+ clearTimeout(timer);
83
+ reject(signal.reason ?? new Error('Aborted'));
84
+ },
85
+ { once: true },
86
+ );
87
+ });
88
+ }
89
+
90
+ /**
91
+ * Retry an async operation with a named preset.
92
+ *
93
+ * - On success: returns ok(result)
94
+ * - On permanent/fixable error: returns err() immediately
95
+ * - On retryable error: retries up to maxAttempts with backoff
96
+ * - On exhaustion: returns err() with last error
97
+ */
98
+ export async function retryWithPreset<T>(
99
+ fn: () => Promise<T>,
100
+ preset: RetryPreset,
101
+ options?: RetryOptions,
102
+ ): Promise<Result<T>> {
103
+ let lastError: SoleriError | undefined;
104
+
105
+ for (let attempt = 0; attempt < RETRY_PRESETS[preset].maxAttempts; attempt++) {
106
+ try {
107
+ const value = await fn();
108
+ return ok(value);
109
+ } catch (thrown: unknown) {
110
+ lastError = classifyError(thrown);
111
+
112
+ if (!shouldRetry(lastError, attempt + 1, preset)) {
113
+ return err(lastError);
114
+ }
115
+
116
+ const delay = getRetryDelay(attempt, preset);
117
+ options?.onRetry?.(lastError, attempt + 1, delay);
118
+
119
+ try {
120
+ await sleep(delay, options?.signal);
121
+ } catch {
122
+ // Aborted during sleep
123
+ return err(lastError);
124
+ }
125
+ }
126
+ }
127
+
128
+ return err(lastError ?? new SoleriError('Max retries exceeded', SoleriErrorCode.INTERNAL));
129
+ }
130
+
131
+ // Re-import for the err fallback
132
+ import { SoleriErrorCode } from './types.js';