@vinaes/succ 1.3.19

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 (781) hide show
  1. package/LICENSE +87 -0
  2. package/README.md +588 -0
  3. package/agents/succ-checkpoint-manager.md +51 -0
  4. package/agents/succ-code-reviewer.md +181 -0
  5. package/agents/succ-context-optimizer.md +83 -0
  6. package/agents/succ-debug.md +224 -0
  7. package/agents/succ-decision-auditor.md +74 -0
  8. package/agents/succ-deep-search.md +41 -0
  9. package/agents/succ-diff-reviewer.md +123 -0
  10. package/agents/succ-explore.md +83 -0
  11. package/agents/succ-general.md +109 -0
  12. package/agents/succ-knowledge-indexer.md +45 -0
  13. package/agents/succ-knowledge-mapper.md +61 -0
  14. package/agents/succ-memory-curator.md +43 -0
  15. package/agents/succ-memory-health-monitor.md +55 -0
  16. package/agents/succ-pattern-detective.md +62 -0
  17. package/agents/succ-plan.md +172 -0
  18. package/agents/succ-quality-improvement-coach.md +63 -0
  19. package/agents/succ-readiness-improver.md +62 -0
  20. package/agents/succ-session-handoff-orchestrator.md +54 -0
  21. package/agents/succ-session-reviewer.md +46 -0
  22. package/agents/succ-style-tracker.md +73 -0
  23. package/dist/cli.d.ts +3 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +749 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/commands/agents-md.d.ts +16 -0
  28. package/dist/commands/agents-md.d.ts.map +1 -0
  29. package/dist/commands/agents-md.js +33 -0
  30. package/dist/commands/agents-md.js.map +1 -0
  31. package/dist/commands/analyze-agents.d.ts +20 -0
  32. package/dist/commands/analyze-agents.d.ts.map +1 -0
  33. package/dist/commands/analyze-agents.js +305 -0
  34. package/dist/commands/analyze-agents.js.map +1 -0
  35. package/dist/commands/analyze-helpers.d.ts +22 -0
  36. package/dist/commands/analyze-helpers.d.ts.map +1 -0
  37. package/dist/commands/analyze-helpers.js +38 -0
  38. package/dist/commands/analyze-helpers.js.map +1 -0
  39. package/dist/commands/analyze-profile.d.ts +53 -0
  40. package/dist/commands/analyze-profile.d.ts.map +1 -0
  41. package/dist/commands/analyze-profile.js +638 -0
  42. package/dist/commands/analyze-profile.js.map +1 -0
  43. package/dist/commands/analyze-recursive.d.ts +20 -0
  44. package/dist/commands/analyze-recursive.d.ts.map +1 -0
  45. package/dist/commands/analyze-recursive.js +326 -0
  46. package/dist/commands/analyze-recursive.js.map +1 -0
  47. package/dist/commands/analyze-utils.d.ts +83 -0
  48. package/dist/commands/analyze-utils.d.ts.map +1 -0
  49. package/dist/commands/analyze-utils.js +541 -0
  50. package/dist/commands/analyze-utils.js.map +1 -0
  51. package/dist/commands/analyze.d.ts +15 -0
  52. package/dist/commands/analyze.d.ts.map +1 -0
  53. package/dist/commands/analyze.js +265 -0
  54. package/dist/commands/analyze.js.map +1 -0
  55. package/dist/commands/backfill.d.ts +22 -0
  56. package/dist/commands/backfill.d.ts.map +1 -0
  57. package/dist/commands/backfill.js +62 -0
  58. package/dist/commands/backfill.js.map +1 -0
  59. package/dist/commands/benchmark-quality.d.ts +18 -0
  60. package/dist/commands/benchmark-quality.d.ts.map +1 -0
  61. package/dist/commands/benchmark-quality.js +316 -0
  62. package/dist/commands/benchmark-quality.js.map +1 -0
  63. package/dist/commands/benchmark-sqlite-vec.d.ts +12 -0
  64. package/dist/commands/benchmark-sqlite-vec.d.ts.map +1 -0
  65. package/dist/commands/benchmark-sqlite-vec.js +281 -0
  66. package/dist/commands/benchmark-sqlite-vec.js.map +1 -0
  67. package/dist/commands/benchmark.d.ts +57 -0
  68. package/dist/commands/benchmark.d.ts.map +1 -0
  69. package/dist/commands/benchmark.js +682 -0
  70. package/dist/commands/benchmark.js.map +1 -0
  71. package/dist/commands/chat.d.ts +14 -0
  72. package/dist/commands/chat.d.ts.map +1 -0
  73. package/dist/commands/chat.js +84 -0
  74. package/dist/commands/chat.js.map +1 -0
  75. package/dist/commands/checkpoint.d.ts +27 -0
  76. package/dist/commands/checkpoint.d.ts.map +1 -0
  77. package/dist/commands/checkpoint.js +181 -0
  78. package/dist/commands/checkpoint.js.map +1 -0
  79. package/dist/commands/clear.d.ts +9 -0
  80. package/dist/commands/clear.d.ts.map +1 -0
  81. package/dist/commands/clear.js +31 -0
  82. package/dist/commands/clear.js.map +1 -0
  83. package/dist/commands/config.d.ts +26 -0
  84. package/dist/commands/config.d.ts.map +1 -0
  85. package/dist/commands/config.js +247 -0
  86. package/dist/commands/config.js.map +1 -0
  87. package/dist/commands/consolidate.d.ts +21 -0
  88. package/dist/commands/consolidate.d.ts.map +1 -0
  89. package/dist/commands/consolidate.js +117 -0
  90. package/dist/commands/consolidate.js.map +1 -0
  91. package/dist/commands/daemon.d.ts +48 -0
  92. package/dist/commands/daemon.d.ts.map +1 -0
  93. package/dist/commands/daemon.js +218 -0
  94. package/dist/commands/daemon.js.map +1 -0
  95. package/dist/commands/embedding.d.ts +26 -0
  96. package/dist/commands/embedding.d.ts.map +1 -0
  97. package/dist/commands/embedding.js +168 -0
  98. package/dist/commands/embedding.js.map +1 -0
  99. package/dist/commands/graph.d.ts +20 -0
  100. package/dist/commands/graph.d.ts.map +1 -0
  101. package/dist/commands/graph.js +128 -0
  102. package/dist/commands/graph.js.map +1 -0
  103. package/dist/commands/index-code.d.ts +23 -0
  104. package/dist/commands/index-code.d.ts.map +1 -0
  105. package/dist/commands/index-code.js +218 -0
  106. package/dist/commands/index-code.js.map +1 -0
  107. package/dist/commands/index.d.ts +23 -0
  108. package/dist/commands/index.d.ts.map +1 -0
  109. package/dist/commands/index.js +217 -0
  110. package/dist/commands/index.js.map +1 -0
  111. package/dist/commands/init-templates.d.ts +21 -0
  112. package/dist/commands/init-templates.d.ts.map +1 -0
  113. package/dist/commands/init-templates.js +487 -0
  114. package/dist/commands/init-templates.js.map +1 -0
  115. package/dist/commands/init.d.ts +10 -0
  116. package/dist/commands/init.d.ts.map +1 -0
  117. package/dist/commands/init.js +865 -0
  118. package/dist/commands/init.js.map +1 -0
  119. package/dist/commands/memories.d.ts +47 -0
  120. package/dist/commands/memories.d.ts.map +1 -0
  121. package/dist/commands/memories.js +597 -0
  122. package/dist/commands/memories.js.map +1 -0
  123. package/dist/commands/migrate.d.ts +19 -0
  124. package/dist/commands/migrate.d.ts.map +1 -0
  125. package/dist/commands/migrate.js +154 -0
  126. package/dist/commands/migrate.js.map +1 -0
  127. package/dist/commands/prd.d.ts +46 -0
  128. package/dist/commands/prd.d.ts.map +1 -0
  129. package/dist/commands/prd.js +378 -0
  130. package/dist/commands/prd.js.map +1 -0
  131. package/dist/commands/precompute-context.d.ts +11 -0
  132. package/dist/commands/precompute-context.d.ts.map +1 -0
  133. package/dist/commands/precompute-context.js +12 -0
  134. package/dist/commands/precompute-context.js.map +1 -0
  135. package/dist/commands/progress.d.ts +16 -0
  136. package/dist/commands/progress.d.ts.map +1 -0
  137. package/dist/commands/progress.js +38 -0
  138. package/dist/commands/progress.js.map +1 -0
  139. package/dist/commands/reindex.d.ts +17 -0
  140. package/dist/commands/reindex.d.ts.map +1 -0
  141. package/dist/commands/reindex.js +83 -0
  142. package/dist/commands/reindex.js.map +1 -0
  143. package/dist/commands/retention.d.ts +19 -0
  144. package/dist/commands/retention.d.ts.map +1 -0
  145. package/dist/commands/retention.js +162 -0
  146. package/dist/commands/retention.js.map +1 -0
  147. package/dist/commands/score.d.ts +10 -0
  148. package/dist/commands/score.d.ts.map +1 -0
  149. package/dist/commands/score.js +28 -0
  150. package/dist/commands/score.js.map +1 -0
  151. package/dist/commands/search.d.ts +7 -0
  152. package/dist/commands/search.d.ts.map +1 -0
  153. package/dist/commands/search.js +89 -0
  154. package/dist/commands/search.js.map +1 -0
  155. package/dist/commands/session-summary.d.ts +15 -0
  156. package/dist/commands/session-summary.d.ts.map +1 -0
  157. package/dist/commands/session-summary.js +16 -0
  158. package/dist/commands/session-summary.js.map +1 -0
  159. package/dist/commands/setup.d.ts +6 -0
  160. package/dist/commands/setup.d.ts.map +1 -0
  161. package/dist/commands/setup.js +222 -0
  162. package/dist/commands/setup.js.map +1 -0
  163. package/dist/commands/soul.d.ts +9 -0
  164. package/dist/commands/soul.d.ts.map +1 -0
  165. package/dist/commands/soul.js +256 -0
  166. package/dist/commands/soul.js.map +1 -0
  167. package/dist/commands/stats.d.ts +18 -0
  168. package/dist/commands/stats.d.ts.map +1 -0
  169. package/dist/commands/stats.js +138 -0
  170. package/dist/commands/stats.js.map +1 -0
  171. package/dist/commands/status.d.ts +2 -0
  172. package/dist/commands/status.d.ts.map +1 -0
  173. package/dist/commands/status.js +145 -0
  174. package/dist/commands/status.js.map +1 -0
  175. package/dist/commands/train-bpe.d.ts +8 -0
  176. package/dist/commands/train-bpe.d.ts.map +1 -0
  177. package/dist/commands/train-bpe.js +35 -0
  178. package/dist/commands/train-bpe.js.map +1 -0
  179. package/dist/commands/watch.d.ts +22 -0
  180. package/dist/commands/watch.d.ts.map +1 -0
  181. package/dist/commands/watch.js +171 -0
  182. package/dist/commands/watch.js.map +1 -0
  183. package/dist/daemon/analyzer.d.ts +54 -0
  184. package/dist/daemon/analyzer.d.ts.map +1 -0
  185. package/dist/daemon/analyzer.js +362 -0
  186. package/dist/daemon/analyzer.js.map +1 -0
  187. package/dist/daemon/client.d.ts +87 -0
  188. package/dist/daemon/client.d.ts.map +1 -0
  189. package/dist/daemon/client.js +356 -0
  190. package/dist/daemon/client.js.map +1 -0
  191. package/dist/daemon/index.d.ts +12 -0
  192. package/dist/daemon/index.d.ts.map +1 -0
  193. package/dist/daemon/index.js +12 -0
  194. package/dist/daemon/index.js.map +1 -0
  195. package/dist/daemon/service.d.ts +51 -0
  196. package/dist/daemon/service.d.ts.map +1 -0
  197. package/dist/daemon/service.js +1203 -0
  198. package/dist/daemon/service.js.map +1 -0
  199. package/dist/daemon/session-processor.d.ts +85 -0
  200. package/dist/daemon/session-processor.d.ts.map +1 -0
  201. package/dist/daemon/session-processor.js +571 -0
  202. package/dist/daemon/session-processor.js.map +1 -0
  203. package/dist/daemon/sessions.d.ts +62 -0
  204. package/dist/daemon/sessions.d.ts.map +1 -0
  205. package/dist/daemon/sessions.js +192 -0
  206. package/dist/daemon/sessions.js.map +1 -0
  207. package/dist/daemon/watcher.d.ts +52 -0
  208. package/dist/daemon/watcher.d.ts.map +1 -0
  209. package/dist/daemon/watcher.js +363 -0
  210. package/dist/daemon/watcher.js.map +1 -0
  211. package/dist/lib/agents-md-generator.d.ts +33 -0
  212. package/dist/lib/agents-md-generator.d.ts.map +1 -0
  213. package/dist/lib/agents-md-generator.js +156 -0
  214. package/dist/lib/agents-md-generator.js.map +1 -0
  215. package/dist/lib/ai-readiness.d.ts +132 -0
  216. package/dist/lib/ai-readiness.d.ts.map +1 -0
  217. package/dist/lib/ai-readiness.js +702 -0
  218. package/dist/lib/ai-readiness.js.map +1 -0
  219. package/dist/lib/analyze-state.d.ts +34 -0
  220. package/dist/lib/analyze-state.d.ts.map +1 -0
  221. package/dist/lib/analyze-state.js +106 -0
  222. package/dist/lib/analyze-state.js.map +1 -0
  223. package/dist/lib/benchmark.d.ts +250 -0
  224. package/dist/lib/benchmark.d.ts.map +1 -0
  225. package/dist/lib/benchmark.js +778 -0
  226. package/dist/lib/benchmark.js.map +1 -0
  227. package/dist/lib/bm25.d.ts +114 -0
  228. package/dist/lib/bm25.d.ts.map +1 -0
  229. package/dist/lib/bm25.js +727 -0
  230. package/dist/lib/bm25.js.map +1 -0
  231. package/dist/lib/bpe.d.ts +70 -0
  232. package/dist/lib/bpe.d.ts.map +1 -0
  233. package/dist/lib/bpe.js +270 -0
  234. package/dist/lib/bpe.js.map +1 -0
  235. package/dist/lib/checkpoint.d.ts +124 -0
  236. package/dist/lib/checkpoint.d.ts.map +1 -0
  237. package/dist/lib/checkpoint.js +321 -0
  238. package/dist/lib/checkpoint.js.map +1 -0
  239. package/dist/lib/chunker.d.ts +47 -0
  240. package/dist/lib/chunker.d.ts.map +1 -0
  241. package/dist/lib/chunker.js +358 -0
  242. package/dist/lib/chunker.js.map +1 -0
  243. package/dist/lib/claude-ws-transport.d.ts +76 -0
  244. package/dist/lib/claude-ws-transport.d.ts.map +1 -0
  245. package/dist/lib/claude-ws-transport.js +487 -0
  246. package/dist/lib/claude-ws-transport.js.map +1 -0
  247. package/dist/lib/compact-briefing.d.ts +22 -0
  248. package/dist/lib/compact-briefing.d.ts.map +1 -0
  249. package/dist/lib/compact-briefing.js +180 -0
  250. package/dist/lib/compact-briefing.js.map +1 -0
  251. package/dist/lib/config-defaults.d.ts +41 -0
  252. package/dist/lib/config-defaults.d.ts.map +1 -0
  253. package/dist/lib/config-defaults.js +99 -0
  254. package/dist/lib/config-defaults.js.map +1 -0
  255. package/dist/lib/config-display.d.ts +16 -0
  256. package/dist/lib/config-display.d.ts.map +1 -0
  257. package/dist/lib/config-display.js +408 -0
  258. package/dist/lib/config-display.js.map +1 -0
  259. package/dist/lib/config-types.d.ts +601 -0
  260. package/dist/lib/config-types.d.ts.map +1 -0
  261. package/dist/lib/config-types.js +7 -0
  262. package/dist/lib/config-types.js.map +1 -0
  263. package/dist/lib/config-validation.d.ts +19 -0
  264. package/dist/lib/config-validation.d.ts.map +1 -0
  265. package/dist/lib/config-validation.js +136 -0
  266. package/dist/lib/config-validation.js.map +1 -0
  267. package/dist/lib/config.d.ts +143 -0
  268. package/dist/lib/config.d.ts.map +1 -0
  269. package/dist/lib/config.js +689 -0
  270. package/dist/lib/config.js.map +1 -0
  271. package/dist/lib/consolidate.d.ts +115 -0
  272. package/dist/lib/consolidate.d.ts.map +1 -0
  273. package/dist/lib/consolidate.js +600 -0
  274. package/dist/lib/consolidate.js.map +1 -0
  275. package/dist/lib/db/bm25-indexes.d.ts +58 -0
  276. package/dist/lib/db/bm25-indexes.d.ts.map +1 -0
  277. package/dist/lib/db/bm25-indexes.js +333 -0
  278. package/dist/lib/db/bm25-indexes.js.map +1 -0
  279. package/dist/lib/db/bpe.d.ts +18 -0
  280. package/dist/lib/db/bpe.d.ts.map +1 -0
  281. package/dist/lib/db/bpe.js +44 -0
  282. package/dist/lib/db/bpe.js.map +1 -0
  283. package/dist/lib/db/connection.d.ts +47 -0
  284. package/dist/lib/db/connection.d.ts.map +1 -0
  285. package/dist/lib/db/connection.js +114 -0
  286. package/dist/lib/db/connection.js.map +1 -0
  287. package/dist/lib/db/documents.d.ts +58 -0
  288. package/dist/lib/db/documents.d.ts.map +1 -0
  289. package/dist/lib/db/documents.js +374 -0
  290. package/dist/lib/db/documents.js.map +1 -0
  291. package/dist/lib/db/file-hash.d.ts +26 -0
  292. package/dist/lib/db/file-hash.d.ts.map +1 -0
  293. package/dist/lib/db/file-hash.js +56 -0
  294. package/dist/lib/db/file-hash.js.map +1 -0
  295. package/dist/lib/db/global-memories.d.ts +62 -0
  296. package/dist/lib/db/global-memories.d.ts.map +1 -0
  297. package/dist/lib/db/global-memories.js +173 -0
  298. package/dist/lib/db/global-memories.js.map +1 -0
  299. package/dist/lib/db/graph.d.ts +163 -0
  300. package/dist/lib/db/graph.d.ts.map +1 -0
  301. package/dist/lib/db/graph.js +488 -0
  302. package/dist/lib/db/graph.js.map +1 -0
  303. package/dist/lib/db/helpers.d.ts +13 -0
  304. package/dist/lib/db/helpers.d.ts.map +1 -0
  305. package/dist/lib/db/helpers.js +21 -0
  306. package/dist/lib/db/helpers.js.map +1 -0
  307. package/dist/lib/db/hybrid-search.d.ts +64 -0
  308. package/dist/lib/db/hybrid-search.d.ts.map +1 -0
  309. package/dist/lib/db/hybrid-search.js +549 -0
  310. package/dist/lib/db/hybrid-search.js.map +1 -0
  311. package/dist/lib/db/index.d.ts +23 -0
  312. package/dist/lib/db/index.d.ts.map +1 -0
  313. package/dist/lib/db/index.js +23 -0
  314. package/dist/lib/db/index.js.map +1 -0
  315. package/dist/lib/db/memories.d.ts +174 -0
  316. package/dist/lib/db/memories.d.ts.map +1 -0
  317. package/dist/lib/db/memories.js +866 -0
  318. package/dist/lib/db/memories.js.map +1 -0
  319. package/dist/lib/db/retention.d.ts +64 -0
  320. package/dist/lib/db/retention.d.ts.map +1 -0
  321. package/dist/lib/db/retention.js +115 -0
  322. package/dist/lib/db/retention.js.map +1 -0
  323. package/dist/lib/db/schema.d.ts +29 -0
  324. package/dist/lib/db/schema.d.ts.map +1 -0
  325. package/dist/lib/db/schema.js +832 -0
  326. package/dist/lib/db/schema.js.map +1 -0
  327. package/dist/lib/db/skills.d.ts +65 -0
  328. package/dist/lib/db/skills.d.ts.map +1 -0
  329. package/dist/lib/db/skills.js +119 -0
  330. package/dist/lib/db/skills.js.map +1 -0
  331. package/dist/lib/db/token-frequency.d.ts +34 -0
  332. package/dist/lib/db/token-frequency.d.ts.map +1 -0
  333. package/dist/lib/db/token-frequency.js +92 -0
  334. package/dist/lib/db/token-frequency.js.map +1 -0
  335. package/dist/lib/db/token-stats.d.ts +43 -0
  336. package/dist/lib/db/token-stats.d.ts.map +1 -0
  337. package/dist/lib/db/token-stats.js +59 -0
  338. package/dist/lib/db/token-stats.js.map +1 -0
  339. package/dist/lib/db/types.d.ts +57 -0
  340. package/dist/lib/db/types.d.ts.map +1 -0
  341. package/dist/lib/db/types.js +5 -0
  342. package/dist/lib/db/types.js.map +1 -0
  343. package/dist/lib/db/web-search-history.d.ts +22 -0
  344. package/dist/lib/db/web-search-history.d.ts.map +1 -0
  345. package/dist/lib/db/web-search-history.js +107 -0
  346. package/dist/lib/db/web-search-history.js.map +1 -0
  347. package/dist/lib/debug/state.d.ts +17 -0
  348. package/dist/lib/debug/state.d.ts.map +1 -0
  349. package/dist/lib/debug/state.js +131 -0
  350. package/dist/lib/debug/state.js.map +1 -0
  351. package/dist/lib/debug/types.d.ts +74 -0
  352. package/dist/lib/debug/types.d.ts.map +1 -0
  353. package/dist/lib/debug/types.js +85 -0
  354. package/dist/lib/debug/types.js.map +1 -0
  355. package/dist/lib/embedding-pool.d.ts +37 -0
  356. package/dist/lib/embedding-pool.d.ts.map +1 -0
  357. package/dist/lib/embedding-pool.js +159 -0
  358. package/dist/lib/embedding-pool.js.map +1 -0
  359. package/dist/lib/embedding-worker.d.ts +7 -0
  360. package/dist/lib/embedding-worker.d.ts.map +1 -0
  361. package/dist/lib/embedding-worker.js +49 -0
  362. package/dist/lib/embedding-worker.js.map +1 -0
  363. package/dist/lib/embeddings.d.ts +54 -0
  364. package/dist/lib/embeddings.d.ts.map +1 -0
  365. package/dist/lib/embeddings.js +437 -0
  366. package/dist/lib/embeddings.js.map +1 -0
  367. package/dist/lib/errors.d.ts +40 -0
  368. package/dist/lib/errors.d.ts.map +1 -0
  369. package/dist/lib/errors.js +66 -0
  370. package/dist/lib/errors.js.map +1 -0
  371. package/dist/lib/fault-logger.d.ts +35 -0
  372. package/dist/lib/fault-logger.d.ts.map +1 -0
  373. package/dist/lib/fault-logger.js +182 -0
  374. package/dist/lib/fault-logger.js.map +1 -0
  375. package/dist/lib/graph/centrality.d.ts +34 -0
  376. package/dist/lib/graph/centrality.d.ts.map +1 -0
  377. package/dist/lib/graph/centrality.js +76 -0
  378. package/dist/lib/graph/centrality.js.map +1 -0
  379. package/dist/lib/graph/cleanup.d.ts +36 -0
  380. package/dist/lib/graph/cleanup.d.ts.map +1 -0
  381. package/dist/lib/graph/cleanup.js +96 -0
  382. package/dist/lib/graph/cleanup.js.map +1 -0
  383. package/dist/lib/graph/community-detection.d.ts +61 -0
  384. package/dist/lib/graph/community-detection.d.ts.map +1 -0
  385. package/dist/lib/graph/community-detection.js +218 -0
  386. package/dist/lib/graph/community-detection.js.map +1 -0
  387. package/dist/lib/graph/contextual-proximity.d.ts +41 -0
  388. package/dist/lib/graph/contextual-proximity.d.ts.map +1 -0
  389. package/dist/lib/graph/contextual-proximity.js +125 -0
  390. package/dist/lib/graph/contextual-proximity.js.map +1 -0
  391. package/dist/lib/graph/llm-relations.d.ts +54 -0
  392. package/dist/lib/graph/llm-relations.d.ts.map +1 -0
  393. package/dist/lib/graph/llm-relations.js +265 -0
  394. package/dist/lib/graph/llm-relations.js.map +1 -0
  395. package/dist/lib/graph-export.d.ts +13 -0
  396. package/dist/lib/graph-export.d.ts.map +1 -0
  397. package/dist/lib/graph-export.js +637 -0
  398. package/dist/lib/graph-export.js.map +1 -0
  399. package/dist/lib/graph-scheduler.d.ts +7 -0
  400. package/dist/lib/graph-scheduler.d.ts.map +1 -0
  401. package/dist/lib/graph-scheduler.js +21 -0
  402. package/dist/lib/graph-scheduler.js.map +1 -0
  403. package/dist/lib/indexer.d.ts +36 -0
  404. package/dist/lib/indexer.d.ts.map +1 -0
  405. package/dist/lib/indexer.js +226 -0
  406. package/dist/lib/indexer.js.map +1 -0
  407. package/dist/lib/learning-delta.d.ts +35 -0
  408. package/dist/lib/learning-delta.d.ts.map +1 -0
  409. package/dist/lib/learning-delta.js +53 -0
  410. package/dist/lib/learning-delta.js.map +1 -0
  411. package/dist/lib/llm.d.ts +118 -0
  412. package/dist/lib/llm.d.ts.map +1 -0
  413. package/dist/lib/llm.js +439 -0
  414. package/dist/lib/llm.js.map +1 -0
  415. package/dist/lib/lock.d.ts +27 -0
  416. package/dist/lib/lock.d.ts.map +1 -0
  417. package/dist/lib/lock.js +143 -0
  418. package/dist/lib/lock.js.map +1 -0
  419. package/dist/lib/md-fetch.d.ts +61 -0
  420. package/dist/lib/md-fetch.d.ts.map +1 -0
  421. package/dist/lib/md-fetch.js +141 -0
  422. package/dist/lib/md-fetch.js.map +1 -0
  423. package/dist/lib/mmr.d.ts +29 -0
  424. package/dist/lib/mmr.d.ts.map +1 -0
  425. package/dist/lib/mmr.js +89 -0
  426. package/dist/lib/mmr.js.map +1 -0
  427. package/dist/lib/onboarding/ai-chat.d.ts +11 -0
  428. package/dist/lib/onboarding/ai-chat.d.ts.map +1 -0
  429. package/dist/lib/onboarding/ai-chat.js +85 -0
  430. package/dist/lib/onboarding/ai-chat.js.map +1 -0
  431. package/dist/lib/onboarding/index.d.ts +7 -0
  432. package/dist/lib/onboarding/index.d.ts.map +1 -0
  433. package/dist/lib/onboarding/index.js +7 -0
  434. package/dist/lib/onboarding/index.js.map +1 -0
  435. package/dist/lib/onboarding/wizard.d.ts +11 -0
  436. package/dist/lib/onboarding/wizard.d.ts.map +1 -0
  437. package/dist/lib/onboarding/wizard.js +104 -0
  438. package/dist/lib/onboarding/wizard.js.map +1 -0
  439. package/dist/lib/ort-provider.d.ts +27 -0
  440. package/dist/lib/ort-provider.d.ts.map +1 -0
  441. package/dist/lib/ort-provider.js +83 -0
  442. package/dist/lib/ort-provider.js.map +1 -0
  443. package/dist/lib/ort-session.d.ts +32 -0
  444. package/dist/lib/ort-session.d.ts.map +1 -0
  445. package/dist/lib/ort-session.js +227 -0
  446. package/dist/lib/ort-session.js.map +1 -0
  447. package/dist/lib/patterns.d.ts +43 -0
  448. package/dist/lib/patterns.d.ts.map +1 -0
  449. package/dist/lib/patterns.js +395 -0
  450. package/dist/lib/patterns.js.map +1 -0
  451. package/dist/lib/prd/codebase-context.d.ts +27 -0
  452. package/dist/lib/prd/codebase-context.d.ts.map +1 -0
  453. package/dist/lib/prd/codebase-context.js +420 -0
  454. package/dist/lib/prd/codebase-context.js.map +1 -0
  455. package/dist/lib/prd/context.d.ts +24 -0
  456. package/dist/lib/prd/context.d.ts.map +1 -0
  457. package/dist/lib/prd/context.js +68 -0
  458. package/dist/lib/prd/context.js.map +1 -0
  459. package/dist/lib/prd/executor.d.ts +52 -0
  460. package/dist/lib/prd/executor.d.ts.map +1 -0
  461. package/dist/lib/prd/executor.js +154 -0
  462. package/dist/lib/prd/executor.js.map +1 -0
  463. package/dist/lib/prd/export.d.ts +40 -0
  464. package/dist/lib/prd/export.d.ts.map +1 -0
  465. package/dist/lib/prd/export.js +511 -0
  466. package/dist/lib/prd/export.js.map +1 -0
  467. package/dist/lib/prd/gates.d.ts +30 -0
  468. package/dist/lib/prd/gates.d.ts.map +1 -0
  469. package/dist/lib/prd/gates.js +100 -0
  470. package/dist/lib/prd/gates.js.map +1 -0
  471. package/dist/lib/prd/generate.d.ts +56 -0
  472. package/dist/lib/prd/generate.d.ts.map +1 -0
  473. package/dist/lib/prd/generate.js +357 -0
  474. package/dist/lib/prd/generate.js.map +1 -0
  475. package/dist/lib/prd/parse.d.ts +21 -0
  476. package/dist/lib/prd/parse.d.ts.map +1 -0
  477. package/dist/lib/prd/parse.js +270 -0
  478. package/dist/lib/prd/parse.js.map +1 -0
  479. package/dist/lib/prd/prompt-builder.d.ts +18 -0
  480. package/dist/lib/prd/prompt-builder.d.ts.map +1 -0
  481. package/dist/lib/prd/prompt-builder.js +61 -0
  482. package/dist/lib/prd/prompt-builder.js.map +1 -0
  483. package/dist/lib/prd/runner.d.ts +54 -0
  484. package/dist/lib/prd/runner.d.ts.map +1 -0
  485. package/dist/lib/prd/runner.js +563 -0
  486. package/dist/lib/prd/runner.js.map +1 -0
  487. package/dist/lib/prd/scheduler.d.ts +27 -0
  488. package/dist/lib/prd/scheduler.d.ts.map +1 -0
  489. package/dist/lib/prd/scheduler.js +113 -0
  490. package/dist/lib/prd/scheduler.js.map +1 -0
  491. package/dist/lib/prd/state.d.ts +77 -0
  492. package/dist/lib/prd/state.d.ts.map +1 -0
  493. package/dist/lib/prd/state.js +253 -0
  494. package/dist/lib/prd/state.js.map +1 -0
  495. package/dist/lib/prd/team-runner.d.ts +48 -0
  496. package/dist/lib/prd/team-runner.d.ts.map +1 -0
  497. package/dist/lib/prd/team-runner.js +261 -0
  498. package/dist/lib/prd/team-runner.js.map +1 -0
  499. package/dist/lib/prd/types.d.ts +169 -0
  500. package/dist/lib/prd/types.d.ts.map +1 -0
  501. package/dist/lib/prd/types.js +143 -0
  502. package/dist/lib/prd/types.js.map +1 -0
  503. package/dist/lib/prd/worktree.d.ts +54 -0
  504. package/dist/lib/prd/worktree.d.ts.map +1 -0
  505. package/dist/lib/prd/worktree.js +255 -0
  506. package/dist/lib/prd/worktree.js.map +1 -0
  507. package/dist/lib/precompute-context.d.ts +48 -0
  508. package/dist/lib/precompute-context.d.ts.map +1 -0
  509. package/dist/lib/precompute-context.js +265 -0
  510. package/dist/lib/precompute-context.js.map +1 -0
  511. package/dist/lib/pricing.d.ts +60 -0
  512. package/dist/lib/pricing.d.ts.map +1 -0
  513. package/dist/lib/pricing.js +258 -0
  514. package/dist/lib/pricing.js.map +1 -0
  515. package/dist/lib/process-registry.d.ts +30 -0
  516. package/dist/lib/process-registry.d.ts.map +1 -0
  517. package/dist/lib/process-registry.js +92 -0
  518. package/dist/lib/process-registry.js.map +1 -0
  519. package/dist/lib/progress-log.d.ts +44 -0
  520. package/dist/lib/progress-log.d.ts.map +1 -0
  521. package/dist/lib/progress-log.js +58 -0
  522. package/dist/lib/progress-log.js.map +1 -0
  523. package/dist/lib/public-api.d.ts +56 -0
  524. package/dist/lib/public-api.d.ts.map +1 -0
  525. package/dist/lib/public-api.js +63 -0
  526. package/dist/lib/public-api.js.map +1 -0
  527. package/dist/lib/quality.d.ts +66 -0
  528. package/dist/lib/quality.d.ts.map +1 -0
  529. package/dist/lib/quality.js +486 -0
  530. package/dist/lib/quality.js.map +1 -0
  531. package/dist/lib/query-expansion.d.ts +16 -0
  532. package/dist/lib/query-expansion.d.ts.map +1 -0
  533. package/dist/lib/query-expansion.js +53 -0
  534. package/dist/lib/query-expansion.js.map +1 -0
  535. package/dist/lib/readiness.d.ts +35 -0
  536. package/dist/lib/readiness.d.ts.map +1 -0
  537. package/dist/lib/readiness.js +142 -0
  538. package/dist/lib/readiness.js.map +1 -0
  539. package/dist/lib/reference-embeddings.d.ts +39 -0
  540. package/dist/lib/reference-embeddings.d.ts.map +1 -0
  541. package/dist/lib/reference-embeddings.js +95 -0
  542. package/dist/lib/reference-embeddings.js.map +1 -0
  543. package/dist/lib/reflection-synthesizer.d.ts +27 -0
  544. package/dist/lib/reflection-synthesizer.d.ts.map +1 -0
  545. package/dist/lib/reflection-synthesizer.js +149 -0
  546. package/dist/lib/reflection-synthesizer.js.map +1 -0
  547. package/dist/lib/retention.d.ts +105 -0
  548. package/dist/lib/retention.d.ts.map +1 -0
  549. package/dist/lib/retention.js +246 -0
  550. package/dist/lib/retention.js.map +1 -0
  551. package/dist/lib/sensitive-filter.d.ts +34 -0
  552. package/dist/lib/sensitive-filter.d.ts.map +1 -0
  553. package/dist/lib/sensitive-filter.js +344 -0
  554. package/dist/lib/sensitive-filter.js.map +1 -0
  555. package/dist/lib/session-observations.d.ts +59 -0
  556. package/dist/lib/session-observations.d.ts.map +1 -0
  557. package/dist/lib/session-observations.js +128 -0
  558. package/dist/lib/session-observations.js.map +1 -0
  559. package/dist/lib/session-summary.d.ts +65 -0
  560. package/dist/lib/session-summary.d.ts.map +1 -0
  561. package/dist/lib/session-summary.js +344 -0
  562. package/dist/lib/session-summary.js.map +1 -0
  563. package/dist/lib/similarity-worker.d.ts +7 -0
  564. package/dist/lib/similarity-worker.d.ts.map +1 -0
  565. package/dist/lib/similarity-worker.js +36 -0
  566. package/dist/lib/similarity-worker.js.map +1 -0
  567. package/dist/lib/skills.d.ts +78 -0
  568. package/dist/lib/skills.d.ts.map +1 -0
  569. package/dist/lib/skills.js +439 -0
  570. package/dist/lib/skills.js.map +1 -0
  571. package/dist/lib/skyll-client.d.ts +59 -0
  572. package/dist/lib/skyll-client.d.ts.map +1 -0
  573. package/dist/lib/skyll-client.js +257 -0
  574. package/dist/lib/skyll-client.js.map +1 -0
  575. package/dist/lib/storage/backends/interface.d.ts +383 -0
  576. package/dist/lib/storage/backends/interface.d.ts.map +1 -0
  577. package/dist/lib/storage/backends/interface.js +12 -0
  578. package/dist/lib/storage/backends/interface.js.map +1 -0
  579. package/dist/lib/storage/backends/postgresql.d.ts +454 -0
  580. package/dist/lib/storage/backends/postgresql.d.ts.map +1 -0
  581. package/dist/lib/storage/backends/postgresql.js +2528 -0
  582. package/dist/lib/storage/backends/postgresql.js.map +1 -0
  583. package/dist/lib/storage/benchmark.d.ts +16 -0
  584. package/dist/lib/storage/benchmark.d.ts.map +1 -0
  585. package/dist/lib/storage/benchmark.js +219 -0
  586. package/dist/lib/storage/benchmark.js.map +1 -0
  587. package/dist/lib/storage/dispatcher-export.d.ts +108 -0
  588. package/dist/lib/storage/dispatcher-export.d.ts.map +1 -0
  589. package/dist/lib/storage/dispatcher-export.js +593 -0
  590. package/dist/lib/storage/dispatcher-export.js.map +1 -0
  591. package/dist/lib/storage/dispatcher.d.ts +468 -0
  592. package/dist/lib/storage/dispatcher.d.ts.map +1 -0
  593. package/dist/lib/storage/dispatcher.js +1926 -0
  594. package/dist/lib/storage/dispatcher.js.map +1 -0
  595. package/dist/lib/storage/index.d.ts +481 -0
  596. package/dist/lib/storage/index.d.ts.map +1 -0
  597. package/dist/lib/storage/index.js +727 -0
  598. package/dist/lib/storage/index.js.map +1 -0
  599. package/dist/lib/storage/migration/export-import.d.ts +133 -0
  600. package/dist/lib/storage/migration/export-import.d.ts.map +1 -0
  601. package/dist/lib/storage/migration/export-import.js +264 -0
  602. package/dist/lib/storage/migration/export-import.js.map +1 -0
  603. package/dist/lib/storage/types.d.ts +313 -0
  604. package/dist/lib/storage/types.d.ts.map +1 -0
  605. package/dist/lib/storage/types.js +30 -0
  606. package/dist/lib/storage/types.js.map +1 -0
  607. package/dist/lib/storage/vector/interface.d.ts +89 -0
  608. package/dist/lib/storage/vector/interface.d.ts.map +1 -0
  609. package/dist/lib/storage/vector/interface.js +10 -0
  610. package/dist/lib/storage/vector/interface.js.map +1 -0
  611. package/dist/lib/storage/vector/qdrant.d.ts +221 -0
  612. package/dist/lib/storage/vector/qdrant.d.ts.map +1 -0
  613. package/dist/lib/storage/vector/qdrant.js +880 -0
  614. package/dist/lib/storage/vector/qdrant.js.map +1 -0
  615. package/dist/lib/supersession.d.ts +26 -0
  616. package/dist/lib/supersession.d.ts.map +1 -0
  617. package/dist/lib/supersession.js +97 -0
  618. package/dist/lib/supersession.js.map +1 -0
  619. package/dist/lib/temporal.d.ts +140 -0
  620. package/dist/lib/temporal.d.ts.map +1 -0
  621. package/dist/lib/temporal.js +303 -0
  622. package/dist/lib/temporal.js.map +1 -0
  623. package/dist/lib/token-budget.d.ts +79 -0
  624. package/dist/lib/token-budget.d.ts.map +1 -0
  625. package/dist/lib/token-budget.js +146 -0
  626. package/dist/lib/token-budget.js.map +1 -0
  627. package/dist/lib/token-counter.d.ts +27 -0
  628. package/dist/lib/token-counter.d.ts.map +1 -0
  629. package/dist/lib/token-counter.js +52 -0
  630. package/dist/lib/token-counter.js.map +1 -0
  631. package/dist/lib/tree-sitter/chunker-ts.d.ts +24 -0
  632. package/dist/lib/tree-sitter/chunker-ts.d.ts.map +1 -0
  633. package/dist/lib/tree-sitter/chunker-ts.js +206 -0
  634. package/dist/lib/tree-sitter/chunker-ts.js.map +1 -0
  635. package/dist/lib/tree-sitter/extractor.d.ts +43 -0
  636. package/dist/lib/tree-sitter/extractor.d.ts.map +1 -0
  637. package/dist/lib/tree-sitter/extractor.js +297 -0
  638. package/dist/lib/tree-sitter/extractor.js.map +1 -0
  639. package/dist/lib/tree-sitter/index.d.ts +13 -0
  640. package/dist/lib/tree-sitter/index.d.ts.map +1 -0
  641. package/dist/lib/tree-sitter/index.js +14 -0
  642. package/dist/lib/tree-sitter/index.js.map +1 -0
  643. package/dist/lib/tree-sitter/parser.d.ts +70 -0
  644. package/dist/lib/tree-sitter/parser.d.ts.map +1 -0
  645. package/dist/lib/tree-sitter/parser.js +354 -0
  646. package/dist/lib/tree-sitter/parser.js.map +1 -0
  647. package/dist/lib/tree-sitter/public.d.ts +28 -0
  648. package/dist/lib/tree-sitter/public.d.ts.map +1 -0
  649. package/dist/lib/tree-sitter/public.js +50 -0
  650. package/dist/lib/tree-sitter/public.js.map +1 -0
  651. package/dist/lib/tree-sitter/queries.d.ts +28 -0
  652. package/dist/lib/tree-sitter/queries.d.ts.map +1 -0
  653. package/dist/lib/tree-sitter/queries.js +383 -0
  654. package/dist/lib/tree-sitter/queries.js.map +1 -0
  655. package/dist/lib/tree-sitter/types.d.ts +69 -0
  656. package/dist/lib/tree-sitter/types.d.ts.map +1 -0
  657. package/dist/lib/tree-sitter/types.js +131 -0
  658. package/dist/lib/tree-sitter/types.js.map +1 -0
  659. package/dist/lib/working-memory-pipeline.d.ts +118 -0
  660. package/dist/lib/working-memory-pipeline.d.ts.map +1 -0
  661. package/dist/lib/working-memory-pipeline.js +344 -0
  662. package/dist/lib/working-memory-pipeline.js.map +1 -0
  663. package/dist/mcp/helpers.d.ts +44 -0
  664. package/dist/mcp/helpers.d.ts.map +1 -0
  665. package/dist/mcp/helpers.js +244 -0
  666. package/dist/mcp/helpers.js.map +1 -0
  667. package/dist/mcp/index.d.ts +10 -0
  668. package/dist/mcp/index.d.ts.map +1 -0
  669. package/dist/mcp/index.js +15 -0
  670. package/dist/mcp/index.js.map +1 -0
  671. package/dist/mcp/resources.d.ts +12 -0
  672. package/dist/mcp/resources.d.ts.map +1 -0
  673. package/dist/mcp/resources.js +136 -0
  674. package/dist/mcp/resources.js.map +1 -0
  675. package/dist/mcp/server.d.ts +22 -0
  676. package/dist/mcp/server.d.ts.map +1 -0
  677. package/dist/mcp/server.js +131 -0
  678. package/dist/mcp/server.js.map +1 -0
  679. package/dist/mcp/tools/config.d.ts +10 -0
  680. package/dist/mcp/tools/config.d.ts.map +1 -0
  681. package/dist/mcp/tools/config.js +236 -0
  682. package/dist/mcp/tools/config.js.map +1 -0
  683. package/dist/mcp/tools/dead-end.d.ts +9 -0
  684. package/dist/mcp/tools/dead-end.d.ts.map +1 -0
  685. package/dist/mcp/tools/dead-end.js +137 -0
  686. package/dist/mcp/tools/dead-end.js.map +1 -0
  687. package/dist/mcp/tools/debug.d.ts +9 -0
  688. package/dist/mcp/tools/debug.d.ts.map +1 -0
  689. package/dist/mcp/tools/debug.js +387 -0
  690. package/dist/mcp/tools/debug.js.map +1 -0
  691. package/dist/mcp/tools/graph.d.ts +9 -0
  692. package/dist/mcp/tools/graph.d.ts.map +1 -0
  693. package/dist/mcp/tools/graph.js +337 -0
  694. package/dist/mcp/tools/graph.js.map +1 -0
  695. package/dist/mcp/tools/indexing.d.ts +12 -0
  696. package/dist/mcp/tools/indexing.d.ts.map +1 -0
  697. package/dist/mcp/tools/indexing.js +289 -0
  698. package/dist/mcp/tools/indexing.js.map +1 -0
  699. package/dist/mcp/tools/memory.d.ts +14 -0
  700. package/dist/mcp/tools/memory.d.ts.map +1 -0
  701. package/dist/mcp/tools/memory.js +1170 -0
  702. package/dist/mcp/tools/memory.js.map +1 -0
  703. package/dist/mcp/tools/prd.d.ts +12 -0
  704. package/dist/mcp/tools/prd.d.ts.map +1 -0
  705. package/dist/mcp/tools/prd.js +276 -0
  706. package/dist/mcp/tools/prd.js.map +1 -0
  707. package/dist/mcp/tools/search.d.ts +9 -0
  708. package/dist/mcp/tools/search.d.ts.map +1 -0
  709. package/dist/mcp/tools/search.js +279 -0
  710. package/dist/mcp/tools/search.js.map +1 -0
  711. package/dist/mcp/tools/status.d.ts +10 -0
  712. package/dist/mcp/tools/status.d.ts.map +1 -0
  713. package/dist/mcp/tools/status.js +296 -0
  714. package/dist/mcp/tools/status.js.map +1 -0
  715. package/dist/mcp/tools/web-fetch.d.ts +10 -0
  716. package/dist/mcp/tools/web-fetch.d.ts.map +1 -0
  717. package/dist/mcp/tools/web-fetch.js +107 -0
  718. package/dist/mcp/tools/web-fetch.js.map +1 -0
  719. package/dist/mcp/tools/web-search.d.ts +14 -0
  720. package/dist/mcp/tools/web-search.d.ts.map +1 -0
  721. package/dist/mcp/tools/web-search.js +427 -0
  722. package/dist/mcp/tools/web-search.js.map +1 -0
  723. package/dist/mcp/types.d.ts +16 -0
  724. package/dist/mcp/types.d.ts.map +1 -0
  725. package/dist/mcp/types.js +5 -0
  726. package/dist/mcp/types.js.map +1 -0
  727. package/dist/mcp-server.d.ts +9 -0
  728. package/dist/mcp-server.d.ts.map +1 -0
  729. package/dist/mcp-server.js +9 -0
  730. package/dist/mcp-server.js.map +1 -0
  731. package/dist/prompts/analyze.d.ts +21 -0
  732. package/dist/prompts/analyze.d.ts.map +1 -0
  733. package/dist/prompts/analyze.js +27 -0
  734. package/dist/prompts/analyze.js.map +1 -0
  735. package/dist/prompts/briefing.d.ts +27 -0
  736. package/dist/prompts/briefing.d.ts.map +1 -0
  737. package/dist/prompts/briefing.js +123 -0
  738. package/dist/prompts/briefing.js.map +1 -0
  739. package/dist/prompts/chat.d.ts +8 -0
  740. package/dist/prompts/chat.d.ts.map +1 -0
  741. package/dist/prompts/chat.js +39 -0
  742. package/dist/prompts/chat.js.map +1 -0
  743. package/dist/prompts/daemon.d.ts +16 -0
  744. package/dist/prompts/daemon.d.ts.map +1 -0
  745. package/dist/prompts/daemon.js +46 -0
  746. package/dist/prompts/daemon.js.map +1 -0
  747. package/dist/prompts/extraction.d.ts +13 -0
  748. package/dist/prompts/extraction.d.ts.map +1 -0
  749. package/dist/prompts/extraction.js +93 -0
  750. package/dist/prompts/extraction.js.map +1 -0
  751. package/dist/prompts/index.d.ts +17 -0
  752. package/dist/prompts/index.d.ts.map +1 -0
  753. package/dist/prompts/index.js +27 -0
  754. package/dist/prompts/index.js.map +1 -0
  755. package/dist/prompts/memory.d.ts +11 -0
  756. package/dist/prompts/memory.d.ts.map +1 -0
  757. package/dist/prompts/memory.js +23 -0
  758. package/dist/prompts/memory.js.map +1 -0
  759. package/dist/prompts/onboarding.d.ts +16 -0
  760. package/dist/prompts/onboarding.d.ts.map +1 -0
  761. package/dist/prompts/onboarding.js +183 -0
  762. package/dist/prompts/onboarding.js.map +1 -0
  763. package/dist/prompts/prd.d.ts +12 -0
  764. package/dist/prompts/prd.d.ts.map +1 -0
  765. package/dist/prompts/prd.js +211 -0
  766. package/dist/prompts/prd.js.map +1 -0
  767. package/dist/prompts/quality.d.ts +11 -0
  768. package/dist/prompts/quality.d.ts.map +1 -0
  769. package/dist/prompts/quality.js +11 -0
  770. package/dist/prompts/quality.js.map +1 -0
  771. package/dist/prompts/skills.d.ts +16 -0
  772. package/dist/prompts/skills.d.ts.map +1 -0
  773. package/dist/prompts/skills.js +30 -0
  774. package/dist/prompts/skills.js.map +1 -0
  775. package/hooks/succ-post-tool.cjs +227 -0
  776. package/hooks/succ-pre-tool.cjs +312 -0
  777. package/hooks/succ-session-end.cjs +85 -0
  778. package/hooks/succ-session-start.cjs +618 -0
  779. package/hooks/succ-stop-reflection.cjs +87 -0
  780. package/hooks/succ-user-prompt.cjs +220 -0
  781. package/package.json +128 -0
@@ -0,0 +1,1203 @@
1
+ /**
2
+ * Unified Daemon Service for succ
3
+ *
4
+ * Single HTTP server per project that handles:
5
+ * - Multiple Claude Code sessions (idle tracking, reflection)
6
+ * - Watch service (file monitoring)
7
+ * - Analyze queue (code analysis)
8
+ * - Data operations (search, recall, remember)
9
+ *
10
+ * Benefits:
11
+ * - No CMD windows on Windows (starts once, stays running)
12
+ * - Fast operations via HTTP (~5ms vs ~500ms spawn)
13
+ * - Shared DB connections, embeddings cache
14
+ * - Per-session idle tracking with multi-session support
15
+ */
16
+ import http from 'http';
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+ import { createSessionManager, createIdleWatcher } from './sessions.js';
20
+ import { logError, logWarn } from '../lib/fault-logger.js';
21
+ import { processRegistry } from '../lib/process-registry.js';
22
+ import { processSessionEnd } from './session-processor.js';
23
+ import { ValidationError, NotFoundError, NetworkError } from '../lib/errors.js';
24
+ import { startWatcher, stopWatcher, getWatcherStatus, indexFileOnDemand } from './watcher.js';
25
+ import { startAnalyzer, stopAnalyzer, getAnalyzerStatus, triggerAnalysis } from './analyzer.js';
26
+ import { getProjectRoot, getSuccDir, getIdleReflectionConfig, getIdleWatcherConfig, getConfig, getObserverConfig, } from '../lib/config.js';
27
+ import { hybridSearchDocs, hybridSearchCode, hybridSearchMemories, saveMemory, closeDb, getStats, getMemoryStats, incrementMemoryAccessBatch, getRecentMemories, getPinnedMemories, setMemoryInvariant,
28
+ // Global memory
29
+ saveGlobalMemory, closeGlobalDb,
30
+ // Dispatcher lifecycle
31
+ initStorageDispatcher, closeStorageDispatcher, getStorageDispatcher, } from '../lib/storage/index.js';
32
+ import { getEmbedding, cleanupEmbeddings } from '../lib/embeddings.js';
33
+ import { scoreMemory, passesQualityThreshold, cleanupQualityScoring } from '../lib/quality.js';
34
+ import { scanSensitive } from '../lib/sensitive-filter.js';
35
+ import { generateCompactBriefing } from '../lib/compact-briefing.js';
36
+ import { callLLM } from '../lib/llm.js';
37
+ import { extractSessionSummary } from '../lib/session-summary.js';
38
+ import { recordTranscriptTokens, recordExtraction, resetTranscriptCounter, loadBudgets, flushBudgets, removeBudget, } from '../lib/token-budget.js';
39
+ import { appendObservations, removeObservations, cleanupStaleObservations, } from '../lib/session-observations.js';
40
+ import { REFLECTION_PROMPT } from '../prompts/index.js';
41
+ // ============================================================================
42
+ // Constants
43
+ // ============================================================================
44
+ const DEFAULT_PORT_RANGE_START = 37842;
45
+ const MAX_PORT_ATTEMPTS = 100;
46
+ // ============================================================================
47
+ // Daemon State
48
+ // ============================================================================
49
+ let state = null;
50
+ let sessionManager = null;
51
+ let idleWatcher = null;
52
+ const briefingCache = new Map();
53
+ const briefingGenerationInProgress = new Set();
54
+ // In-flight dedup: prevents race condition when identical /api/remember requests
55
+ // arrive within a short window (e.g. hook fires twice for same tool_use)
56
+ const rememberInFlight = new Map();
57
+ const REMEMBER_DEDUP_TTL_MS = 5000;
58
+ // ============================================================================
59
+ // File Paths
60
+ // ============================================================================
61
+ function getDaemonPidFile() {
62
+ const succDir = getSuccDir();
63
+ const tmpDir = path.join(succDir, '.tmp');
64
+ if (!fs.existsSync(tmpDir)) {
65
+ fs.mkdirSync(tmpDir, { recursive: true });
66
+ }
67
+ return path.join(tmpDir, 'daemon.pid');
68
+ }
69
+ // ============================================================================
70
+ // Progress File Management
71
+ // ============================================================================
72
+ /**
73
+ * Get path to session progress file
74
+ * Progress files accumulate idle reflection briefings for session-end processing
75
+ */
76
+ function getProgressFilePath(sessionId) {
77
+ const succDir = getSuccDir();
78
+ const tmpDir = path.join(succDir, '.tmp');
79
+ if (!fs.existsSync(tmpDir)) {
80
+ fs.mkdirSync(tmpDir, { recursive: true });
81
+ }
82
+ return path.join(tmpDir, `session-${sessionId}-progress.md`);
83
+ }
84
+ /**
85
+ * Append a briefing to the session progress file
86
+ * Creates file with header if it doesn't exist
87
+ */
88
+ export function appendToProgressFile(sessionId, briefing) {
89
+ const progressPath = getProgressFilePath(sessionId);
90
+ const timestamp = new Date().toISOString();
91
+ const timeStr = new Date().toLocaleTimeString('en-US', {
92
+ hour12: false,
93
+ hour: '2-digit',
94
+ minute: '2-digit',
95
+ });
96
+ let content = '';
97
+ if (!fs.existsSync(progressPath)) {
98
+ content = `---\nsession_id: ${sessionId}\ncreated: ${timestamp}\n---\n\n`;
99
+ }
100
+ content += `## ${timeStr} - Idle Reflection\n\n`;
101
+ content += briefing;
102
+ content += '\n\n---\n\n';
103
+ fs.appendFileSync(progressPath, content);
104
+ }
105
+ /**
106
+ * Read tail of transcript file (for fallback when no progress file)
107
+ * Returns the last maxBytes of the file, starting from a complete line
108
+ */
109
+ export function readTailTranscript(transcriptPath, maxBytes = 2 * 1024 * 1024) {
110
+ if (!fs.existsSync(transcriptPath)) {
111
+ return '';
112
+ }
113
+ const stats = fs.statSync(transcriptPath);
114
+ if (stats.size <= maxBytes) {
115
+ return fs.readFileSync(transcriptPath, 'utf8');
116
+ }
117
+ // Read only tail
118
+ const fd = fs.openSync(transcriptPath, 'r');
119
+ const buffer = Buffer.alloc(maxBytes);
120
+ fs.readSync(fd, buffer, 0, maxBytes, stats.size - maxBytes);
121
+ fs.closeSync(fd);
122
+ // Find first complete line (skip partial line at start)
123
+ const content = buffer.toString('utf8');
124
+ const firstNewline = content.indexOf('\n');
125
+ return firstNewline > 0 ? content.slice(firstNewline + 1) : content;
126
+ }
127
+ // ============================================================================
128
+ // Briefing Pre-Generation
129
+ // ============================================================================
130
+ const BRIEFING_CACHE_MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes
131
+ const BRIEFING_MIN_TRANSCRIPT_GROWTH = 5000; // Re-generate after 5KB growth
132
+ // const BRIEFING_PREGENERATE_IDLE_MS = 120 * 1000; // Pre-generate after 2 min idle
133
+ /**
134
+ * Pre-generate briefing for a session in background
135
+ * Called when session is idle or transcript grows significantly
136
+ */
137
+ async function preGenerateBriefing(sessionId, transcriptPath) {
138
+ // Skip if already generating
139
+ if (briefingGenerationInProgress.has(sessionId)) {
140
+ return;
141
+ }
142
+ if (!fs.existsSync(transcriptPath)) {
143
+ return;
144
+ }
145
+ const stats = fs.statSync(transcriptPath);
146
+ const currentSize = stats.size;
147
+ // Check if we need to regenerate
148
+ const cached = briefingCache.get(sessionId);
149
+ if (cached) {
150
+ const age = Date.now() - cached.generatedAt;
151
+ const growth = currentSize - cached.transcriptSize;
152
+ // Skip if cache is fresh and transcript hasn't grown much
153
+ if (age < BRIEFING_CACHE_MAX_AGE_MS && growth < BRIEFING_MIN_TRANSCRIPT_GROWTH) {
154
+ return;
155
+ }
156
+ }
157
+ briefingGenerationInProgress.add(sessionId);
158
+ log(`[briefing] Pre-generating for session ${sessionId.slice(0, 8)}...`);
159
+ try {
160
+ const transcriptContent = fs.readFileSync(transcriptPath, 'utf-8');
161
+ const result = await generateCompactBriefing(transcriptContent);
162
+ if (result.success && result.briefing) {
163
+ briefingCache.set(sessionId, {
164
+ briefing: result.briefing,
165
+ generatedAt: Date.now(),
166
+ transcriptSize: currentSize,
167
+ });
168
+ log(`[briefing] Pre-generated for session ${sessionId.slice(0, 8)} (${result.briefing.length} chars)`);
169
+ }
170
+ else {
171
+ log(`[briefing] Pre-generation failed: ${result.error}`);
172
+ }
173
+ }
174
+ catch (error) {
175
+ log(`[briefing] Pre-generation error: ${error}`);
176
+ }
177
+ finally {
178
+ briefingGenerationInProgress.delete(sessionId);
179
+ }
180
+ }
181
+ /**
182
+ * Get cached briefing or generate on-demand
183
+ */
184
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
185
+ async function getCachedBriefing(sessionId, transcriptPath) {
186
+ const cached = briefingCache.get(sessionId);
187
+ if (cached) {
188
+ // Check if cache is still valid
189
+ const age = Date.now() - cached.generatedAt;
190
+ if (age < BRIEFING_CACHE_MAX_AGE_MS) {
191
+ return { briefing: cached.briefing, cached: true };
192
+ }
193
+ }
194
+ // Cache miss or stale - generate fresh
195
+ if (!fs.existsSync(transcriptPath)) {
196
+ return { cached: false };
197
+ }
198
+ const transcriptContent = fs.readFileSync(transcriptPath, 'utf-8');
199
+ const result = await generateCompactBriefing(transcriptContent);
200
+ if (result.success && result.briefing) {
201
+ const stats = fs.statSync(transcriptPath);
202
+ briefingCache.set(sessionId, {
203
+ briefing: result.briefing,
204
+ generatedAt: Date.now(),
205
+ transcriptSize: stats.size,
206
+ });
207
+ return { briefing: result.briefing, cached: false };
208
+ }
209
+ return { cached: false };
210
+ }
211
+ /**
212
+ * Clear briefing cache for a session (called when session ends)
213
+ */
214
+ function clearBriefingCache(sessionId) {
215
+ briefingCache.delete(sessionId);
216
+ briefingGenerationInProgress.delete(sessionId);
217
+ }
218
+ function getDaemonPortFile() {
219
+ const succDir = getSuccDir();
220
+ const tmpDir = path.join(succDir, '.tmp');
221
+ if (!fs.existsSync(tmpDir)) {
222
+ fs.mkdirSync(tmpDir, { recursive: true });
223
+ }
224
+ return path.join(tmpDir, 'daemon.port');
225
+ }
226
+ function getDaemonLogFile() {
227
+ const succDir = getSuccDir();
228
+ return path.join(succDir, 'daemon.log');
229
+ }
230
+ // ============================================================================
231
+ // Logging
232
+ // ============================================================================
233
+ function log(message) {
234
+ const timestamp = new Date().toISOString();
235
+ const line = `[${timestamp}] ${message}\n`;
236
+ // Write to daemon.log
237
+ try {
238
+ fs.appendFileSync(getDaemonLogFile(), line);
239
+ }
240
+ catch (err) {
241
+ logWarn('daemon', 'Failed to write daemon log', {
242
+ error: err instanceof Error ? err.message : String(err),
243
+ });
244
+ }
245
+ // Also write to stderr for debugging
246
+ process.stderr.write(line);
247
+ }
248
+ // ============================================================================
249
+ // Write Reflection
250
+ // ============================================================================
251
+ /**
252
+ * Write a human-like reflection to the brain vault
253
+ * Uses Claude CLI or local LLM to generate introspective text
254
+ */
255
+ async function writeReflection(transcript, _idleConfig) {
256
+ const projectRoot = getProjectRoot();
257
+ const reflectionsDir = path.join(projectRoot, '.succ', 'brain', 'reflections');
258
+ // Create reflections directory if needed
259
+ if (!fs.existsSync(reflectionsDir)) {
260
+ fs.mkdirSync(reflectionsDir, { recursive: true });
261
+ }
262
+ const now = new Date();
263
+ const dateStr = now.toISOString().split('T')[0];
264
+ const timeStr = now.toTimeString().split(' ')[0].substring(0, 5);
265
+ const timestamp = `${dateStr} ${timeStr}`;
266
+ const prompt = REFLECTION_PROMPT.replace('{transcript}', transcript.substring(0, 3000));
267
+ let reflectionText = null;
268
+ // Use sleep agent for background reflection if enabled
269
+ try {
270
+ reflectionText = await callLLM(prompt, {
271
+ timeout: 60000,
272
+ useSleepAgent: true, // Use sleep_agent config if available
273
+ });
274
+ }
275
+ catch (err) {
276
+ log(`[reflection] LLM call failed: ${err}`);
277
+ reflectionText = null;
278
+ }
279
+ if (!reflectionText || reflectionText.trim().length < 50) {
280
+ log(`[reflection] Reflection text too short or empty, skipping`);
281
+ return;
282
+ }
283
+ // Write reflection file with YAML frontmatter
284
+ const reflectionFile = path.join(reflectionsDir, `${timestamp}.md`);
285
+ const content = `---
286
+ date: ${dateStr}
287
+ time: ${timeStr}
288
+ trigger: idle
289
+ tags:
290
+ - reflection
291
+ ---
292
+
293
+ # Reflection ${dateStr} ${timeStr}
294
+
295
+ ${reflectionText.trim()}
296
+ `;
297
+ fs.writeFileSync(reflectionFile, content);
298
+ // Also save to memory (with dedup to prevent duplicate reflections)
299
+ const embedding = await getEmbedding(reflectionText.trim());
300
+ await saveMemory(reflectionText.trim(), embedding, ['reflection'], 'observation', {
301
+ qualityScore: { score: 0.6, factors: { hasContext: 1 } },
302
+ deduplicate: true,
303
+ });
304
+ }
305
+ // LLM functions moved to shared module: src/lib/llm.ts
306
+ // ============================================================================
307
+ // Reflection Handler
308
+ // ============================================================================
309
+ async function handleReflection(sessionId, session) {
310
+ // Skip reflection for service sessions (reflection subagents, analyzers, etc.)
311
+ if (session.isService) {
312
+ log(`[reflection] Skipping service session ${sessionId}`);
313
+ return;
314
+ }
315
+ log(`[reflection] Starting reflection for session ${sessionId}`);
316
+ const idleConfig = getIdleReflectionConfig();
317
+ // Only run if we have a transcript
318
+ if (!session.transcriptPath || !fs.existsSync(session.transcriptPath)) {
319
+ log(`[reflection] No transcript found for session ${sessionId}`);
320
+ return;
321
+ }
322
+ try {
323
+ // ── Change detection: skip redundant work during long AFK ──
324
+ let transcriptChanged = true;
325
+ let memoriesChanged = true;
326
+ try {
327
+ const currentSize = fs.statSync(session.transcriptPath).size;
328
+ if (session.lastTranscriptSize !== undefined && currentSize === session.lastTranscriptSize) {
329
+ transcriptChanged = false;
330
+ log(`[reflection] Transcript unchanged (${currentSize}b), skipping briefing`);
331
+ }
332
+ session.lastTranscriptSize = currentSize;
333
+ }
334
+ catch {
335
+ /* transcript file gone — skip size check */
336
+ }
337
+ // Check memory count for consolidation skip
338
+ const memStats = await getMemoryStats();
339
+ const currentMemCount = memStats.total;
340
+ if (session.lastMemoryCount !== undefined && currentMemCount === session.lastMemoryCount) {
341
+ memoriesChanged = false;
342
+ }
343
+ session.lastMemoryCount = currentMemCount;
344
+ // ── Mid-conversation observer: extract facts when enough new content ──
345
+ const observerConfig = getObserverConfig();
346
+ if (observerConfig.enabled && transcriptChanged) {
347
+ try {
348
+ const currentSize = session.lastTranscriptSize ?? 0;
349
+ const lastObsSize = session.lastObservationSize ?? 0;
350
+ const lastObsTime = session.lastObservation ?? session.registeredAt;
351
+ const now = Date.now();
352
+ // Read new content and track real token count via budget
353
+ const newBytes = currentSize - lastObsSize;
354
+ const timeThresholdMs = observerConfig.max_minutes * 60 * 1000;
355
+ const enoughTime = now - lastObsTime >= timeThresholdMs;
356
+ // Use byte-estimated token check first (cheap), then verify with real count
357
+ const estimatedTokens = Math.ceil(newBytes / 3.5);
358
+ const enoughNewContent = estimatedTokens >= observerConfig.min_tokens;
359
+ if (enoughNewContent || enoughTime) {
360
+ const newContent = readTailTranscript(session.transcriptPath, newBytes);
361
+ // Track real tokens in budget
362
+ const realTokens = recordTranscriptTokens(sessionId, newContent);
363
+ log(`[observer] Triggering extraction (tokens: ~${realTokens}, time: ${Math.round((now - lastObsTime) / 60000)}min)`);
364
+ if (newContent.length > 200) {
365
+ const result = await extractSessionSummary(newContent, { verbose: false });
366
+ recordExtraction(sessionId, result.transcriptTokens ?? 0, result.summaryTokens ?? 0, result.factsExtracted, result.factsSaved);
367
+ resetTranscriptCounter(sessionId);
368
+ // Persist extraction metadata to session observations (append-only)
369
+ if (result.factsSaved > 0) {
370
+ appendObservations(sessionId, [
371
+ {
372
+ content: `Extracted ${result.factsExtracted} facts, saved ${result.factsSaved}`,
373
+ type: 'observation',
374
+ tags: ['mid-session'],
375
+ extractedAt: new Date().toISOString(),
376
+ source: 'mid-session-observer',
377
+ transcriptOffset: currentSize,
378
+ memoryId: null,
379
+ },
380
+ ]);
381
+ }
382
+ log(`[observer] Extracted ${result.factsExtracted} facts, saved ${result.factsSaved} (skipped ${result.factsSkipped})`);
383
+ }
384
+ session.lastObservation = now;
385
+ session.lastObservationSize = currentSize;
386
+ flushBudgets();
387
+ }
388
+ }
389
+ catch (err) {
390
+ log(`[observer] Mid-session extraction failed: ${err}`);
391
+ }
392
+ }
393
+ // ── Generate briefing (skip if transcript unchanged) ──
394
+ let briefingResult = { success: false };
395
+ if (transcriptChanged) {
396
+ const transcriptContent = readTailTranscript(session.transcriptPath, 100 * 1024); // 100KB max
397
+ briefingResult = await generateCompactBriefing(transcriptContent, {
398
+ format: 'structured',
399
+ include_memories: true,
400
+ max_memories: 3,
401
+ });
402
+ if (briefingResult.success && briefingResult.briefing) {
403
+ appendToProgressFile(sessionId, briefingResult.briefing);
404
+ log(`[reflection] Appended briefing to progress file (${briefingResult.briefing.length} chars)`);
405
+ }
406
+ else {
407
+ log(`[reflection] Failed to generate briefing for ${sessionId}`);
408
+ }
409
+ }
410
+ // ── Parallel operations ──
411
+ const globalConfig = getConfig();
412
+ const parallelOps = [];
413
+ // memory_consolidation - skip if no new memories (disabled by default, opt-in only)
414
+ if (memoriesChanged && idleConfig.operations?.memory_consolidation === true) {
415
+ parallelOps.push((async () => {
416
+ const threshold = idleConfig.thresholds?.similarity_for_merge ?? 0.92;
417
+ const limit = idleConfig.max_memories_to_process ?? 50;
418
+ log(`[reflection] Running memory consolidation (threshold=${threshold}, limit=${limit})`);
419
+ const { consolidate } = await import('../commands/consolidate.js');
420
+ await consolidate({
421
+ threshold: String(threshold),
422
+ limit: String(limit),
423
+ llm: true,
424
+ verbose: false,
425
+ });
426
+ log(`[reflection] Memory consolidation complete`);
427
+ })());
428
+ }
429
+ // retention_cleanup - independent (always runs if enabled)
430
+ if (globalConfig.retention?.enabled && idleConfig.operations?.retention_cleanup !== false) {
431
+ parallelOps.push((async () => {
432
+ log(`[reflection] Running retention cleanup`);
433
+ const { retention } = await import('../commands/retention.js');
434
+ await retention({ apply: true, verbose: false });
435
+ log(`[reflection] Retention cleanup complete`);
436
+ })());
437
+ }
438
+ await Promise.all(parallelOps);
439
+ // ── Graph cleanup: prune → enrich → orphans → communities → centrality ──
440
+ if (idleConfig.operations?.graph_refinement !== false ||
441
+ idleConfig.operations?.graph_enrichment !== false) {
442
+ const shouldRun = memoriesChanged || session.lastLinkCount === undefined;
443
+ if (shouldRun) {
444
+ log(`[reflection] Running graph cleanup pipeline`);
445
+ try {
446
+ const { graphCleanup } = await import('../lib/graph/cleanup.js');
447
+ const cleanupResult = await graphCleanup({
448
+ skipEnrich: idleConfig.operations?.graph_enrichment === false,
449
+ onProgress: (step, detail) => log(`[reflection] [${step}] ${detail}`),
450
+ });
451
+ log(`[reflection] Cleanup: pruned ${cleanupResult.pruned}, enriched ${cleanupResult.enriched}, orphans ${cleanupResult.orphansConnected}, communities ${cleanupResult.communitiesDetected}, centrality ${cleanupResult.centralityUpdated}`);
452
+ // Proximity links from co-occurrence (not part of cleanup pipeline)
453
+ try {
454
+ const { createProximityLinks } = await import('../lib/graph/contextual-proximity.js');
455
+ const r = await createProximityLinks({ minCooccurrence: 2 });
456
+ log(`[reflection] Created ${r.created} proximity links`);
457
+ }
458
+ catch (err) {
459
+ log(`[reflection] Proximity failed: ${err}`);
460
+ }
461
+ // Synthesize patterns from community clusters (uses cleanup's community result)
462
+ if (cleanupResult.communityResult &&
463
+ cleanupResult.communityResult.communities.length > 0) {
464
+ try {
465
+ const { synthesizeFromCommunities } = await import('../lib/reflection-synthesizer.js');
466
+ const synthResult = await synthesizeFromCommunities(cleanupResult.communityResult, {
467
+ log,
468
+ });
469
+ const hasSynthActivity = synthResult.patternsCreated > 0 ||
470
+ synthResult.duplicatesSkipped > 0 ||
471
+ synthResult.reinforced > 0;
472
+ if (hasSynthActivity) {
473
+ log(`[reflection] Synthesized ${synthResult.patternsCreated} patterns from ${synthResult.clustersProcessed} clusters` +
474
+ (synthResult.reinforced > 0
475
+ ? `, reinforced ${synthResult.reinforced} existing`
476
+ : '') +
477
+ (synthResult.duplicatesSkipped > 0
478
+ ? `, skipped ${synthResult.duplicatesSkipped} duplicates`
479
+ : '') +
480
+ (synthResult.observationsMarked > 0
481
+ ? `, marked ${synthResult.observationsMarked} as reflected`
482
+ : ''));
483
+ }
484
+ }
485
+ catch (err) {
486
+ log(`[reflection] Synthesis failed: ${err}`);
487
+ }
488
+ }
489
+ session.lastLinkCount = (session.lastLinkCount ?? 0) + cleanupResult.orphansConnected;
490
+ }
491
+ catch (err) {
492
+ log(`[reflection] Graph cleanup failed: ${err}`);
493
+ }
494
+ }
495
+ else {
496
+ log(`[reflection] Skipping graph cleanup (no changes)`);
497
+ }
498
+ }
499
+ // ── Write reflection (runs last, may use LLM) ──
500
+ if (idleConfig.operations?.write_reflection !== false) {
501
+ log(`[reflection] Writing reflection for ${sessionId}`);
502
+ try {
503
+ const progressPath = getProgressFilePath(sessionId);
504
+ const briefingContent = fs.existsSync(progressPath)
505
+ ? fs.readFileSync(progressPath, 'utf-8')
506
+ : briefingResult.briefing || '';
507
+ if (briefingContent.length >= 100) {
508
+ await writeReflection(briefingContent, idleConfig);
509
+ log(`[reflection] Reflection written`);
510
+ }
511
+ }
512
+ catch (err) {
513
+ log(`[reflection] Write reflection error: ${err}`);
514
+ }
515
+ }
516
+ log(`[reflection] Completed reflection for session ${sessionId}`);
517
+ }
518
+ catch (err) {
519
+ log(`[reflection] Error for session ${sessionId}: ${err}`);
520
+ }
521
+ }
522
+ // ============================================================================
523
+ // HTTP Request Handler
524
+ // ============================================================================
525
+ async function handleRequest(req, res) {
526
+ const reqUrl = new URL(req.url || '/', `http://localhost`);
527
+ const method = req.method || 'GET';
528
+ // CORS headers (for potential web clients)
529
+ res.setHeader('Access-Control-Allow-Origin', '*');
530
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
531
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
532
+ if (method === 'OPTIONS') {
533
+ res.writeHead(204);
534
+ res.end();
535
+ return;
536
+ }
537
+ // Parse JSON body for POST requests
538
+ let body = null;
539
+ if (method === 'POST') {
540
+ body = await parseBody(req);
541
+ }
542
+ try {
543
+ // Route request
544
+ const result = await routeRequest(method, reqUrl.pathname, reqUrl.searchParams, body);
545
+ res.writeHead(200, { 'Content-Type': 'application/json' });
546
+ res.end(JSON.stringify(result));
547
+ }
548
+ catch (err) {
549
+ log(`[http] Error: ${err.message}`);
550
+ res.writeHead(500, { 'Content-Type': 'application/json' });
551
+ res.end(JSON.stringify({ error: err.message }));
552
+ }
553
+ }
554
+ export async function parseBody(req) {
555
+ return new Promise((resolve, reject) => {
556
+ let data = '';
557
+ req.on('data', (chunk) => (data += chunk));
558
+ req.on('end', () => {
559
+ try {
560
+ resolve(data ? JSON.parse(data) : {});
561
+ }
562
+ catch (err) {
563
+ logWarn('daemon', 'Invalid JSON in HTTP request body', {
564
+ error: err instanceof Error ? err.message : String(err),
565
+ });
566
+ resolve({});
567
+ }
568
+ });
569
+ req.on('error', reject);
570
+ });
571
+ }
572
+ /** @internal Exported for testing */
573
+ export async function routeRequest(method, pathname, searchParams, body) {
574
+ // Health check
575
+ if (pathname === '/health') {
576
+ return {
577
+ status: 'ok',
578
+ pid: process.pid,
579
+ uptime: Date.now() - (state?.startedAt || Date.now()),
580
+ activeSessions: sessionManager?.count() || 0,
581
+ cwd: state?.cwd || process.cwd(),
582
+ };
583
+ }
584
+ // Session endpoints
585
+ if (pathname === '/api/session/register' && method === 'POST') {
586
+ const { session_id, transcript_path, is_service = false } = body;
587
+ if (!session_id) {
588
+ throw new ValidationError('session_id required');
589
+ }
590
+ const session = sessionManager.register(session_id, transcript_path || '', is_service);
591
+ log(`[session] Registered: ${session_id}${is_service ? ' (service)' : ''}`);
592
+ return { success: true, session };
593
+ }
594
+ if (pathname === '/api/session/unregister' && method === 'POST') {
595
+ const { session_id, transcript_path, run_reflection } = body;
596
+ if (!session_id) {
597
+ throw new ValidationError('session_id required');
598
+ }
599
+ const session = sessionManager.get(session_id);
600
+ const transcriptFile = transcript_path || session?.transcriptPath || '';
601
+ // Flush session counters to learning_deltas before unregister
602
+ try {
603
+ const d = await getStorageDispatcher();
604
+ await d.flushSessionCounters('daemon-session');
605
+ }
606
+ catch (err) {
607
+ log(`[session] Failed to flush session counters: ${err}`);
608
+ }
609
+ // Unregister the session immediately (don't block on processing)
610
+ const removed = sessionManager.unregister(session_id);
611
+ clearBriefingCache(session_id); // Clean up any cached briefing
612
+ removeBudget(session_id); // Clean up token budget
613
+ removeObservations(session_id); // Clean up observation JSONL
614
+ flushBudgets();
615
+ log(`[session] Unregistered: ${session_id} (removed=${removed})`);
616
+ // Process session asynchronously (summarize transcript, extract learnings, save to memory)
617
+ if (run_reflection && transcriptFile) {
618
+ sessionManager.incrementPendingWork();
619
+ log(`[session] Queuing async processing for ${session_id}`);
620
+ // Fire-and-forget async processing
621
+ (async () => {
622
+ try {
623
+ const result = await processSessionEnd(transcriptFile, session_id, log);
624
+ log(`[session] Processing complete for ${session_id}: summary=${result.summary.length}chars, learnings=${result.learnings.length}, saved=${result.saved}`);
625
+ }
626
+ catch (err) {
627
+ log(`[session] Processing failed for ${session_id}: ${err}`);
628
+ }
629
+ finally {
630
+ sessionManager.decrementPendingWork();
631
+ // Check shutdown after work completes
632
+ checkShutdown();
633
+ }
634
+ })();
635
+ }
636
+ else {
637
+ // No processing needed, check shutdown immediately
638
+ checkShutdown();
639
+ }
640
+ return { success: removed, remaining_sessions: sessionManager.count() };
641
+ }
642
+ if (pathname === '/api/session/activity' && method === 'POST') {
643
+ const { session_id, type, transcript_path, is_service = false } = body;
644
+ if (!session_id || !type) {
645
+ throw new ValidationError('session_id and type required');
646
+ }
647
+ let session = sessionManager.activity(session_id, type);
648
+ if (!session) {
649
+ // Auto-register if session not found (with transcript_path if provided)
650
+ sessionManager.register(session_id, transcript_path || '', is_service);
651
+ session = sessionManager.activity(session_id, type);
652
+ log(`[session] Auto-registered and activity: ${session_id} (${type})${is_service ? ' (service)' : ''}`);
653
+ }
654
+ else if (transcript_path && !session.transcriptPath) {
655
+ // Update transcript path if not set
656
+ session.transcriptPath = transcript_path;
657
+ log(`[session] Activity: ${session_id} (${type}) + updated transcript`);
658
+ }
659
+ else {
660
+ log(`[session] Activity: ${session_id} (${type})`);
661
+ }
662
+ return { success: true };
663
+ }
664
+ if (pathname === '/api/sessions' && method === 'GET') {
665
+ const includeService = searchParams.get('includeService') === 'true';
666
+ const sessions = {};
667
+ for (const [id, session] of sessionManager.getAll(includeService)) {
668
+ sessions[id] = session;
669
+ }
670
+ return { sessions, count: sessionManager.count(includeService) };
671
+ }
672
+ // Search endpoints
673
+ if (pathname === '/api/search' && method === 'POST') {
674
+ const { query, limit = 5, threshold = 0.3 } = body;
675
+ if (!query) {
676
+ throw new ValidationError('query required');
677
+ }
678
+ const queryEmbedding = await getEmbedding(query);
679
+ const results = await hybridSearchDocs(query, queryEmbedding, limit, threshold);
680
+ // Track access for returned memories
681
+ const accesses = results
682
+ .filter((r) => r.memory_id)
683
+ .map((r) => ({ memoryId: r.memory_id, weight: 0.5 }));
684
+ if (accesses.length > 0) {
685
+ await incrementMemoryAccessBatch(accesses);
686
+ }
687
+ return { results };
688
+ }
689
+ if (pathname === '/api/search-code' && method === 'POST') {
690
+ const { query, limit = 5, threshold = 0.3 } = body;
691
+ if (!query) {
692
+ throw new ValidationError('query required');
693
+ }
694
+ const queryEmbedding = await getEmbedding(query);
695
+ const results = await hybridSearchCode(query, queryEmbedding, limit, threshold);
696
+ return { results };
697
+ }
698
+ if (pathname === '/api/recall' && method === 'POST') {
699
+ const { query, limit = 5 } = body;
700
+ // Empty query returns recent memories
701
+ if (!query) {
702
+ const memories = await getRecentMemories(limit);
703
+ return { results: memories };
704
+ }
705
+ // Generate embedding for semantic search
706
+ const queryEmbedding = await getEmbedding(query);
707
+ const results = await hybridSearchMemories(query, queryEmbedding, limit, 0.3);
708
+ // Track access for returned memories
709
+ const accesses = results
710
+ .filter((r) => r.id)
711
+ .map((r) => ({ memoryId: r.id, weight: 1.0 }));
712
+ if (accesses.length > 0) {
713
+ await incrementMemoryAccessBatch(accesses);
714
+ }
715
+ return { results };
716
+ }
717
+ if (pathname === '/api/pinned' && method === 'GET') {
718
+ const pinned = await getPinnedMemories();
719
+ return { results: pinned };
720
+ }
721
+ if (pathname === '/api/pinned/cleanup' && method === 'POST') {
722
+ // Remove false invariant flags from observation-type memories
723
+ const pinned = await getPinnedMemories();
724
+ let cleaned = 0;
725
+ for (const mem of pinned) {
726
+ if (mem.type === 'observation' && mem.is_invariant) {
727
+ await setMemoryInvariant(mem.id, false);
728
+ cleaned++;
729
+ }
730
+ }
731
+ return { cleaned, total: pinned.length };
732
+ }
733
+ if (pathname === '/api/remember' && method === 'POST') {
734
+ const { content, tags = [], type = 'observation', source, global = false, valid_from, valid_until, } = body;
735
+ if (!content) {
736
+ throw new ValidationError('content required');
737
+ }
738
+ // In-flight dedup: if an identical request is already being processed, wait for it
739
+ // Prevents race condition when hooks fire twice for the same tool_use
740
+ const contentHash = content.slice(0, 200) + '|' + (tags || []).join(',');
741
+ const existing = rememberInFlight.get(contentHash);
742
+ if (existing) {
743
+ const result = await existing;
744
+ return { success: false, id: result.id, isDuplicate: true, reason: 'in-flight dedup' };
745
+ }
746
+ const processRemember = async () => {
747
+ // Check for sensitive content
748
+ const config = getConfig();
749
+ let finalContent = content;
750
+ if (config.sensitive_filter_enabled !== false) {
751
+ const scanResult = scanSensitive(content);
752
+ if (scanResult.hasSensitive) {
753
+ if (config.sensitive_auto_redact) {
754
+ finalContent = scanResult.redactedText;
755
+ }
756
+ else {
757
+ throw new ValidationError('Content contains sensitive information');
758
+ }
759
+ }
760
+ }
761
+ // Get embedding
762
+ const embedding = await getEmbedding(finalContent);
763
+ // Score quality
764
+ const qualityResult = await scoreMemory(finalContent);
765
+ if (!passesQualityThreshold(qualityResult)) {
766
+ return { success: false, reason: 'Below quality threshold', score: qualityResult.score };
767
+ }
768
+ // Save to appropriate DB
769
+ let result;
770
+ if (global) {
771
+ result = await saveGlobalMemory(finalContent, embedding, tags, type);
772
+ }
773
+ else {
774
+ result = await saveMemory(finalContent, embedding, tags, source ?? type, {
775
+ qualityScore: { score: qualityResult.score, factors: qualityResult.factors },
776
+ validFrom: valid_from,
777
+ validUntil: valid_until,
778
+ });
779
+ }
780
+ return { success: !result.isDuplicate, id: result.id, isDuplicate: result.isDuplicate };
781
+ };
782
+ const promise = processRemember();
783
+ rememberInFlight.set(contentHash, promise);
784
+ setTimeout(() => rememberInFlight.delete(contentHash), REMEMBER_DEDUP_TTL_MS);
785
+ try {
786
+ return await promise;
787
+ }
788
+ finally {
789
+ rememberInFlight.delete(contentHash);
790
+ }
791
+ }
792
+ // Reflection endpoint
793
+ if (pathname === '/api/reflect' && method === 'POST') {
794
+ const { session_id } = body;
795
+ const watcherConfig = getIdleWatcherConfig();
796
+ if (session_id) {
797
+ const session = sessionManager.get(session_id);
798
+ if (!session) {
799
+ throw new NotFoundError('Session not found');
800
+ }
801
+ await handleReflection(session_id, session);
802
+ sessionManager.markReflection(session_id);
803
+ return { success: true, session_id };
804
+ }
805
+ else {
806
+ // Run for all idle sessions
807
+ const idleSessions = sessionManager.getIdleSessions(watcherConfig.idle_minutes);
808
+ for (const { sessionId, session } of idleSessions) {
809
+ await handleReflection(sessionId, session);
810
+ sessionManager.markReflection(sessionId);
811
+ }
812
+ return { success: true, sessions_processed: idleSessions.length };
813
+ }
814
+ }
815
+ // Compact briefing endpoint (for /compact hook)
816
+ // Supports pre-generated cache for instant responses
817
+ if (pathname === '/api/briefing' && method === 'POST') {
818
+ const { transcript, transcript_path, session_id, format, include_learnings, include_memories, max_memories, use_cache, } = body;
819
+ // Try cached briefing first if session_id provided and use_cache not explicitly false
820
+ if (session_id && use_cache !== false) {
821
+ const cached = briefingCache.get(session_id);
822
+ if (cached) {
823
+ const age = Date.now() - cached.generatedAt;
824
+ if (age < BRIEFING_CACHE_MAX_AGE_MS) {
825
+ log(`[briefing] Serving cached briefing for ${session_id.slice(0, 8)} (age: ${Math.round(age / 1000)}s)`);
826
+ return { success: true, briefing: cached.briefing, cached: true };
827
+ }
828
+ }
829
+ }
830
+ // Either transcript content or path to transcript file
831
+ let transcriptContent;
832
+ if (transcript) {
833
+ transcriptContent = transcript;
834
+ }
835
+ else if (transcript_path && fs.existsSync(transcript_path)) {
836
+ transcriptContent = fs.readFileSync(transcript_path, 'utf-8');
837
+ }
838
+ else {
839
+ throw new ValidationError('transcript or transcript_path required');
840
+ }
841
+ const result = await generateCompactBriefing(transcriptContent, {
842
+ format,
843
+ include_learnings,
844
+ include_memories,
845
+ max_memories,
846
+ });
847
+ // Cache the result if session_id provided
848
+ if (session_id && result.success && result.briefing && transcript_path) {
849
+ const stats = fs.existsSync(transcript_path) ? fs.statSync(transcript_path) : null;
850
+ briefingCache.set(session_id, {
851
+ briefing: result.briefing,
852
+ generatedAt: Date.now(),
853
+ transcriptSize: stats?.size || 0,
854
+ });
855
+ }
856
+ return { ...result, cached: false };
857
+ }
858
+ // Status endpoints
859
+ if (pathname === '/api/status' && method === 'GET') {
860
+ const stats = await getStats();
861
+ const memStats = await getMemoryStats();
862
+ const watchStatus = getWatcherStatus();
863
+ const analyzeStatus = getAnalyzerStatus();
864
+ return {
865
+ daemon: {
866
+ pid: process.pid,
867
+ uptime: Date.now() - (state?.startedAt || Date.now()),
868
+ sessions: sessionManager.count(),
869
+ },
870
+ index: stats,
871
+ memories: memStats,
872
+ services: {
873
+ watch: watchStatus,
874
+ analyze: analyzeStatus,
875
+ },
876
+ };
877
+ }
878
+ // Watch service endpoints
879
+ if (pathname === '/api/watch/start' && method === 'POST') {
880
+ const { patterns, includeCode } = body;
881
+ const watchState = await startWatcher({ patterns, includeCode }, log);
882
+ return {
883
+ success: true,
884
+ active: watchState.active,
885
+ patterns: watchState.patterns,
886
+ includeCode: watchState.includeCode,
887
+ };
888
+ }
889
+ if (pathname === '/api/watch/stop' && method === 'POST') {
890
+ await stopWatcher(log);
891
+ return { success: true };
892
+ }
893
+ if (pathname === '/api/watch/status' && method === 'GET') {
894
+ return getWatcherStatus();
895
+ }
896
+ if (pathname === '/api/watch/index' && method === 'POST') {
897
+ const { file } = body;
898
+ if (!file) {
899
+ throw new ValidationError('file required');
900
+ }
901
+ await indexFileOnDemand(file, log);
902
+ return { success: true, file };
903
+ }
904
+ // Analyze service endpoints
905
+ if (pathname === '/api/analyze/start' && method === 'POST') {
906
+ const { intervalMinutes, mode } = body;
907
+ const analyzeState = startAnalyzer({ intervalMinutes, mode }, log);
908
+ return {
909
+ success: true,
910
+ active: analyzeState.active,
911
+ runsCompleted: analyzeState.runsCompleted,
912
+ };
913
+ }
914
+ if (pathname === '/api/analyze/stop' && method === 'POST') {
915
+ stopAnalyzer(log);
916
+ return { success: true };
917
+ }
918
+ if (pathname === '/api/analyze/status' && method === 'GET') {
919
+ return getAnalyzerStatus();
920
+ }
921
+ if (pathname === '/api/analyze' && method === 'POST') {
922
+ const { mode = 'claude' } = body;
923
+ await triggerAnalysis(mode, log);
924
+ return { success: true };
925
+ }
926
+ // Skills endpoints
927
+ if (pathname === '/api/skills/suggest' && method === 'POST') {
928
+ const { prompt, limit = 2 } = body;
929
+ if (!prompt) {
930
+ throw new ValidationError('prompt required');
931
+ }
932
+ const { suggestSkills, getSkillsConfig } = await import('../lib/skills.js');
933
+ const config = getSkillsConfig();
934
+ if (!config.enabled || !config.auto_suggest?.enabled) {
935
+ return { success: true, skills: [], disabled: true };
936
+ }
937
+ const suggestions = await suggestSkills(prompt, config);
938
+ return {
939
+ success: true,
940
+ skills: suggestions.slice(0, limit),
941
+ };
942
+ }
943
+ if (pathname === '/api/skills/index' && method === 'POST') {
944
+ const { indexLocalSkills } = await import('../lib/skills.js');
945
+ const cwd = state?.cwd || process.cwd();
946
+ const count = indexLocalSkills(cwd);
947
+ return { success: true, indexed: count };
948
+ }
949
+ if (pathname === '/api/skills/track' && method === 'POST') {
950
+ const { skill_name } = body;
951
+ if (!skill_name) {
952
+ throw new ValidationError('skill_name required');
953
+ }
954
+ const { trackSkillUsage } = await import('../lib/skills.js');
955
+ trackSkillUsage(skill_name);
956
+ return { success: true };
957
+ }
958
+ // Skyll status endpoint
959
+ if (pathname === '/api/skills/skyll' && method === 'GET') {
960
+ const { getSkyllStatus } = await import('../lib/skyll-client.js');
961
+ return getSkyllStatus();
962
+ }
963
+ // Services endpoint (list all services status)
964
+ if (pathname === '/api/services' && method === 'GET') {
965
+ return {
966
+ watch: getWatcherStatus(),
967
+ analyze: getAnalyzerStatus(),
968
+ idle: {
969
+ enabled: true,
970
+ sessions: sessionManager.count(),
971
+ },
972
+ };
973
+ }
974
+ throw new NotFoundError(`Unknown endpoint: ${method} ${pathname}`);
975
+ }
976
+ // ============================================================================
977
+ // Daemon Lifecycle
978
+ // ============================================================================
979
+ export async function startDaemon() {
980
+ if (state?.server) {
981
+ return { port: state.port, pid: process.pid };
982
+ }
983
+ // Check if another daemon is already running (prevent duplicate processes)
984
+ const existingPidFile = getDaemonPidFile();
985
+ if (fs.existsSync(existingPidFile)) {
986
+ try {
987
+ const existingPid = parseInt(fs.readFileSync(existingPidFile, 'utf8').trim(), 10);
988
+ if (existingPid && existingPid !== process.pid) {
989
+ // Check if process is actually running
990
+ try {
991
+ process.kill(existingPid, 0); // Signal 0 = check if process exists
992
+ // Process exists, read port and return
993
+ const portFile = getDaemonPortFile();
994
+ if (fs.existsSync(portFile)) {
995
+ const port = parseInt(fs.readFileSync(portFile, 'utf8').trim(), 10);
996
+ log(`[daemon] Another daemon already running (pid=${existingPid}, port=${port})`);
997
+ process.exit(0); // Exit silently - another daemon is handling things
998
+ }
999
+ }
1000
+ catch {
1001
+ // Process doesn't exist, clean up stale files
1002
+ log(`[daemon] Cleaning up stale PID file (pid=${existingPid} not running)`);
1003
+ fs.unlinkSync(existingPidFile);
1004
+ const portFile = getDaemonPortFile();
1005
+ if (fs.existsSync(portFile)) {
1006
+ fs.unlinkSync(portFile);
1007
+ }
1008
+ }
1009
+ }
1010
+ }
1011
+ catch (err) {
1012
+ logWarn('daemon', 'Failed to read daemon PID file', {
1013
+ error: err instanceof Error ? err.message : String(err),
1014
+ });
1015
+ }
1016
+ }
1017
+ const cwd = getProjectRoot();
1018
+ const watcherConfig = getIdleWatcherConfig();
1019
+ getIdleReflectionConfig();
1020
+ // Initialize storage dispatcher (routes to SQLite or PG based on config)
1021
+ await initStorageDispatcher();
1022
+ // Initialize session manager
1023
+ sessionManager = createSessionManager();
1024
+ // Load token budgets from previous daemon run
1025
+ loadBudgets();
1026
+ // Clean up stale observation files (>48h)
1027
+ cleanupStaleObservations();
1028
+ // Create HTTP server
1029
+ const server = http.createServer((req, res) => {
1030
+ handleRequest(req, res).catch((err) => {
1031
+ log(`[http] Unhandled error: ${err.message}`);
1032
+ res.writeHead(500);
1033
+ res.end();
1034
+ });
1035
+ });
1036
+ // Find available port
1037
+ const portStart = DEFAULT_PORT_RANGE_START;
1038
+ let port = portStart;
1039
+ for (let i = 0; i < MAX_PORT_ATTEMPTS; i++) {
1040
+ await new Promise((resolve, reject) => {
1041
+ server.once('error', (err) => {
1042
+ if (err.code === 'EADDRINUSE') {
1043
+ port++;
1044
+ resolve();
1045
+ }
1046
+ else {
1047
+ reject(err);
1048
+ }
1049
+ });
1050
+ server.listen(port, '127.0.0.1', () => {
1051
+ resolve();
1052
+ });
1053
+ });
1054
+ if (server.listening) {
1055
+ break;
1056
+ }
1057
+ }
1058
+ if (!server.listening) {
1059
+ throw new NetworkError(`Could not find available port in range ${portStart}-${portStart + MAX_PORT_ATTEMPTS}`);
1060
+ }
1061
+ // Save state
1062
+ state = {
1063
+ cwd,
1064
+ startedAt: Date.now(),
1065
+ port,
1066
+ server,
1067
+ };
1068
+ // Write PID and port files
1069
+ fs.writeFileSync(getDaemonPidFile(), String(process.pid));
1070
+ fs.writeFileSync(getDaemonPortFile(), String(port));
1071
+ // Start idle watcher with briefing pre-generation
1072
+ idleWatcher = createIdleWatcher({
1073
+ sessionManager,
1074
+ onIdle: handleReflection,
1075
+ onPreGenerateBriefing: preGenerateBriefing,
1076
+ checkIntervalSeconds: watcherConfig.check_interval,
1077
+ idleMinutes: watcherConfig.idle_minutes,
1078
+ reflectionCooldownMinutes: watcherConfig.reflection_cooldown_minutes,
1079
+ preGenerateIdleSeconds: 120, // Pre-generate briefing after 2 min idle
1080
+ log,
1081
+ });
1082
+ idleWatcher.start();
1083
+ log(`[daemon] Started on port ${port} (pid=${process.pid})`);
1084
+ // Auto-start watch service if configured
1085
+ const config = getConfig();
1086
+ if (config.daemon?.watch?.auto_start) {
1087
+ const watchConfig = config.daemon.watch;
1088
+ await startWatcher({
1089
+ patterns: watchConfig.patterns || ['**/*.md'],
1090
+ includeCode: watchConfig.include_code ?? false,
1091
+ debounceMs: watchConfig.debounce_ms ?? 500,
1092
+ }, log);
1093
+ log(`[daemon] Auto-started watch service`);
1094
+ }
1095
+ // Auto-start analyze service if configured
1096
+ if (config.daemon?.analyze?.auto_start) {
1097
+ const analyzeConfig = config.daemon.analyze;
1098
+ startAnalyzer({
1099
+ intervalMinutes: analyzeConfig.interval_minutes ?? 30,
1100
+ mode: analyzeConfig.mode ?? 'claude',
1101
+ }, log);
1102
+ log(`[daemon] Auto-started analyze service`);
1103
+ }
1104
+ // Setup graceful shutdown
1105
+ setupShutdownHandlers();
1106
+ return { port, pid: process.pid };
1107
+ }
1108
+ function setupShutdownHandlers() {
1109
+ const shutdown = () => shutdownDaemon();
1110
+ process.on('SIGTERM', shutdown);
1111
+ process.on('SIGINT', shutdown);
1112
+ // SIGHUP only exists on Unix
1113
+ if (process.platform !== 'win32') {
1114
+ process.on('SIGHUP', shutdown);
1115
+ }
1116
+ }
1117
+ /**
1118
+ * Check if daemon should shutdown (no sessions and no pending work)
1119
+ */
1120
+ function checkShutdown() {
1121
+ if (sessionManager?.canShutdown()) {
1122
+ log(`[daemon] No more sessions and no pending work, scheduling shutdown`);
1123
+ setTimeout(() => {
1124
+ if (sessionManager?.canShutdown()) {
1125
+ shutdownDaemon();
1126
+ }
1127
+ }, 5000); // Give 5 seconds for new sessions to connect
1128
+ }
1129
+ }
1130
+ export function shutdownDaemon() {
1131
+ log('[daemon] Shutting down...');
1132
+ // Stop idle watcher
1133
+ if (idleWatcher) {
1134
+ idleWatcher.stop();
1135
+ idleWatcher = null;
1136
+ }
1137
+ // Stop watch service (async, but we're shutting down so fire-and-forget)
1138
+ stopWatcher(log).catch((err) => log(`[shutdown] Watcher stop failed: ${err}`));
1139
+ // Stop analyze service
1140
+ stopAnalyzer(log);
1141
+ // Close HTTP server
1142
+ if (state?.server) {
1143
+ state.server.close();
1144
+ state.server = null;
1145
+ }
1146
+ // Kill all spawned child processes (claude CLI, etc.)
1147
+ processRegistry.killAll();
1148
+ // Cleanup DB connections
1149
+ closeStorageDispatcher().catch((err) => log(`[shutdown] Storage close failed: ${err}`));
1150
+ cleanupEmbeddings();
1151
+ cleanupQualityScoring();
1152
+ closeDb();
1153
+ closeGlobalDb();
1154
+ // Remove PID and port files
1155
+ try {
1156
+ fs.unlinkSync(getDaemonPidFile());
1157
+ }
1158
+ catch (err) {
1159
+ if (err.code !== 'ENOENT')
1160
+ log(`[shutdown] PID file removal failed: ${err}`);
1161
+ }
1162
+ try {
1163
+ fs.unlinkSync(getDaemonPortFile());
1164
+ }
1165
+ catch (err) {
1166
+ if (err.code !== 'ENOENT')
1167
+ log(`[shutdown] Port file removal failed: ${err}`);
1168
+ }
1169
+ log('[daemon] Shutdown complete');
1170
+ process.exit(0);
1171
+ }
1172
+ // ============================================================================
1173
+ // Test Helpers (exported for unit testing)
1174
+ // ============================================================================
1175
+ /** @internal Initialize module state for testing without starting HTTP server */
1176
+ export function _initTestState(cwd = process.cwd()) {
1177
+ sessionManager = createSessionManager();
1178
+ state = { cwd, startedAt: Date.now(), port: 0, server: null };
1179
+ }
1180
+ /** @internal Reset module state after testing */
1181
+ export function _resetTestState() {
1182
+ sessionManager = null;
1183
+ idleWatcher = null;
1184
+ state = null;
1185
+ briefingCache.clear();
1186
+ briefingGenerationInProgress.clear();
1187
+ }
1188
+ // ============================================================================
1189
+ // CLI Entry Point
1190
+ // ============================================================================
1191
+ // If run directly, start daemon
1192
+ if (process.argv[1]?.endsWith('service.js') || process.argv[1]?.endsWith('service.ts')) {
1193
+ startDaemon()
1194
+ .then(({ port, pid }) => {
1195
+ console.log(`Daemon started on port ${port} (pid=${pid})`);
1196
+ })
1197
+ .catch((err) => {
1198
+ logError('daemon', `Failed to start daemon: ${err.message}`, err);
1199
+ console.error('Failed to start daemon:', err.message);
1200
+ process.exit(1);
1201
+ });
1202
+ }
1203
+ //# sourceMappingURL=service.js.map