@a-company/paradigm 5.10.0 → 5.21.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 (409) hide show
  1. package/dist/accept-orchestration-IUAWQZUN.js +18 -0
  2. package/dist/add-P76GEMGF.js +8 -0
  3. package/dist/agent-UUTYOFTH.js +33 -0
  4. package/dist/agent-loader-EPXURMO7.js +2 -0
  5. package/dist/agent-loader-PYGPX6D2.js +2 -0
  6. package/dist/agent-state-KSQ3S7OB.js +2 -0
  7. package/dist/agents-suggest-HYTFMQD3.js +10 -0
  8. package/dist/aggregate-W66DM3GA.js +10 -0
  9. package/dist/ambient-HYZR42NX.js +35 -0
  10. package/dist/assess-UFPYEJKP.js +9 -0
  11. package/dist/auto-RHJXOZFL.js +14 -0
  12. package/dist/beacon-5QVYV5DF.js +13 -0
  13. package/dist/calibration-OLJYB5HN.js +7 -0
  14. package/dist/check-THVGY4R5.js +14 -0
  15. package/dist/chunk-22ISTMKI.js +31 -0
  16. package/dist/chunk-2QO33NYK.js +3 -0
  17. package/dist/chunk-33LKBMVK.js +134 -0
  18. package/dist/chunk-4QADCWPU.js +7 -0
  19. package/dist/chunk-4TXOVRWD.js +3 -0
  20. package/dist/chunk-4UJ4NIEQ.js +4 -0
  21. package/dist/chunk-4ZGGWZ32.js +3 -0
  22. package/dist/chunk-5TAVYPOV.js +2 -0
  23. package/dist/chunk-6EX37L4Q.js +8 -0
  24. package/dist/chunk-AD5TAD2A.js +5 -0
  25. package/dist/chunk-AGVAHVUA.js +2 -0
  26. package/dist/chunk-AO7ZSRME.js +13 -0
  27. package/dist/chunk-BFD3GFRK.js +2 -0
  28. package/dist/chunk-D34YFK4M.js +6 -0
  29. package/dist/chunk-DVZWCXB6.js +2 -0
  30. package/dist/chunk-EKZDFEJW.js +2 -0
  31. package/dist/chunk-ET5XJTSX.js +2 -0
  32. package/dist/chunk-FYDRENK7.js +3 -0
  33. package/dist/chunk-HMQ5BHP2.js +743 -0
  34. package/dist/chunk-HXKWL3VK.js +29 -0
  35. package/dist/chunk-IZSBGW6E.js +2 -0
  36. package/dist/chunk-J32OPJEX.js +2 -0
  37. package/dist/chunk-JBDMCRPP.js +7 -0
  38. package/dist/chunk-JIXHEBGK.js +7 -0
  39. package/dist/chunk-JNSJVCTU.js +2 -0
  40. package/dist/chunk-JQKKVAAN.js +2 -0
  41. package/dist/chunk-KLBH26PA.js +429 -0
  42. package/dist/chunk-L6K5HNDL.js +24 -0
  43. package/dist/chunk-LKAT7IAK.js +2 -0
  44. package/dist/chunk-M4UMM6DC.js +5 -0
  45. package/dist/chunk-NKYNHSA5.js +424 -0
  46. package/dist/chunk-NW6OKHE6.js +5 -0
  47. package/dist/chunk-NXRVR37G.js +60 -0
  48. package/dist/chunk-ODVKPZZ4.js +2 -0
  49. package/dist/chunk-PUBB7LIT.js +5 -0
  50. package/dist/chunk-Q2J542ST.js +2 -0
  51. package/dist/chunk-QGZRM6ZB.js +2 -0
  52. package/dist/chunk-QNZEG7IT.js +13 -0
  53. package/dist/chunk-QT2LKB3P.js +7 -0
  54. package/dist/chunk-RVRARWSY.js +9 -0
  55. package/dist/chunk-T6IDXUUA.js +2 -0
  56. package/dist/chunk-TYWB5IQJ.js +3 -0
  57. package/dist/chunk-UIKLE3WD.js +2 -0
  58. package/dist/chunk-V7K6CQVX.js +111 -0
  59. package/dist/chunk-VCKKJDLP.js +8 -0
  60. package/dist/chunk-VG7FN2TU.js +4 -0
  61. package/dist/chunk-W5IWDW4Y.js +16 -0
  62. package/dist/chunk-W7C6FFMO.js +8 -0
  63. package/dist/chunk-WESTEMIM.js +10 -0
  64. package/dist/chunk-WR6D3SC6.js +5 -0
  65. package/dist/chunk-WS2N27RX.js +3 -0
  66. package/dist/chunk-XMAV5AG6.js +2 -0
  67. package/dist/chunk-XROULIQN.js +2 -0
  68. package/dist/chunk-XUFYOXOU.js +3 -0
  69. package/dist/chunk-Y4XFVDZC.js +3 -0
  70. package/dist/chunk-Y6KXTQBG.js +2 -0
  71. package/dist/{chunk-GTR2TBIJ.js → chunk-Z2UZUCY6.js} +237 -1047
  72. package/dist/chunk-Z34K6GY2.js +8 -0
  73. package/dist/claude-4LR3LJQZ.js +13 -0
  74. package/dist/claude-cli-UP6HGH7C.js +6 -0
  75. package/dist/claude-code-RLJ4GX77.js +11 -0
  76. package/dist/claude-code-teams-R37HJY3Y.js +29 -0
  77. package/dist/commands-LMUD5L6R.js +455 -0
  78. package/dist/compliance-GZ7UAOG3.js +6 -0
  79. package/dist/conductor-Y5IXELTL.js +4 -0
  80. package/dist/config-schema-HR7LDEQ6.js +2 -0
  81. package/dist/constellation-CG7C4WFE.js +13 -0
  82. package/dist/context-audit-RSSRX6XC.js +6 -0
  83. package/dist/cost-IDNVMAEV.js +10 -0
  84. package/dist/cost-PK4KIF7R.js +2 -0
  85. package/dist/cursor-cli-QKF7Z6M2.js +4 -0
  86. package/dist/cursorrules-U5O4G5T4.js +14 -0
  87. package/dist/decision-loader-2XPZE4EZ.js +2 -0
  88. package/dist/delete-P5VULXR4.js +14 -0
  89. package/dist/diff-RTFUKJHF.js +9 -0
  90. package/dist/discipline-H7LDI6NT.js +2 -0
  91. package/dist/dist-3ZCH25SG.js +2 -0
  92. package/dist/dist-KGRCLBJP-2QAPFYNF.js +39 -0
  93. package/dist/dist-R3RWD35F.js +2 -0
  94. package/dist/dist-VGFSP3XM.js +2 -0
  95. package/dist/dist-VXCZWVVJ.js +2 -0
  96. package/dist/dist-W3XCATBJ.js +2 -0
  97. package/dist/docs-EDQ2STFK.js +2 -0
  98. package/dist/docs-RXPN6CK7.js +12 -0
  99. package/dist/doctor-2T2QL6VM.js +2 -0
  100. package/dist/drift-ILZE5BFJ.js +13 -0
  101. package/dist/echo-UPTQUEDU.js +46 -0
  102. package/dist/edit-GUU3HBVW.js +9 -0
  103. package/dist/event-Y3VXC2RV.js +3 -0
  104. package/dist/explain-files-3GPZUETV.js +4 -0
  105. package/dist/export-CV5KCTPS.js +2 -0
  106. package/dist/flow-S3RQ4YPY.js +11 -0
  107. package/dist/global-C44FW4G2.js +13 -0
  108. package/dist/graduate-3BBSC27A.js +5 -0
  109. package/dist/graph-CNDE5TAT.js +2 -0
  110. package/dist/graph-server-COZR5C3Z.js +14 -0
  111. package/dist/habits-4J2KRYUL.js +42 -0
  112. package/dist/history-UW454SDP.js +12 -0
  113. package/dist/hooks-XH52VGOU.js +2 -0
  114. package/dist/index.js +15 -1039
  115. package/dist/init-24MAQJFM.js +2 -0
  116. package/dist/integrity-UYDOOJDP.js +7 -0
  117. package/dist/integrity-checker-DHGMZQDG.js +2 -0
  118. package/dist/journal-loader-GLH7XFTK.js +2 -0
  119. package/dist/lint-IGKE6UPS.js +26 -0
  120. package/dist/list-5IUGP3ZB.js +7 -0
  121. package/dist/list-YKIQNKGB.js +6 -0
  122. package/dist/lore-loader-RVQI5GXL.js +2 -0
  123. package/dist/lore-loader-XY5MZRR2.js +2 -0
  124. package/dist/lore-server-FC2GMDLT.js +14 -0
  125. package/dist/manual-RXSPSFLL.js +20 -0
  126. package/dist/mcp.js +93 -20484
  127. package/dist/migrate-X5OMAFAQ.js +59 -0
  128. package/dist/migrate-assessments-GEI5WMI2.js +4 -0
  129. package/dist/model-discovery-HMB3YI4L.js +2 -0
  130. package/dist/nomination-engine-XF7TWPAP.js +2 -0
  131. package/dist/notebook-PE3JSYZI.js +11 -0
  132. package/dist/notebook-loader-CENTDDUJ.js +2 -0
  133. package/dist/orchestrate-35HBQ3O3.js +8 -0
  134. package/dist/peers-P2KXU7ZK.js +5 -0
  135. package/dist/persona-STQWZH5P.js +29 -0
  136. package/dist/pipeline-MZUITRVN.js +4 -0
  137. package/dist/platform-server-2KXHGHFV.js +25 -0
  138. package/dist/plugin-update-checker-M7PW434O.js +2 -0
  139. package/dist/portal-check-3JVNLOEP.js +8 -0
  140. package/dist/portal-compliance-2UG4VKWH.js +2 -0
  141. package/dist/probe-5L5BQDGE.js +6 -0
  142. package/dist/project-type-SURTOIG7.js +2 -0
  143. package/dist/promote-NJQDZBZA.js +8 -0
  144. package/dist/providers-4PXMWA7V.js +8 -0
  145. package/dist/quiz-FE5UGAY2.js +10 -0
  146. package/dist/record-YXPB34MY.js +6 -0
  147. package/dist/reindex-PGDQSM42.js +2 -0
  148. package/dist/remember-MJRNTXYS.js +14 -0
  149. package/dist/retag-N5XF3KXP.js +6 -0
  150. package/dist/review-6UAH6V3R.js +11 -0
  151. package/dist/review-77QI6VOC.js +6 -0
  152. package/dist/ripple-ZGDITCGB.js +10 -0
  153. package/dist/roster-FLRZ5J42.js +2 -0
  154. package/dist/sentinel-HYAZ3CO5.js +19 -0
  155. package/dist/sentinel-bridge-VR357PKL.js +2 -0
  156. package/dist/sentinel-mcp.js +38 -3808
  157. package/dist/sentinel.js +1 -34
  158. package/dist/serve-JE6UF5P2.js +8 -0
  159. package/dist/serve-L52ZUTU6.js +10 -0
  160. package/dist/serve-OY6XYL7F.js +12 -0
  161. package/dist/server-2MNROHF6.js +7 -0
  162. package/dist/server-4YNUIK4W.js +8 -0
  163. package/dist/session-tracker-SKOMBDOW.js +2 -0
  164. package/dist/session-work-log-3MNUDEZ6.js +2 -0
  165. package/dist/session-work-log-J2H5OZBR.js +2 -0
  166. package/dist/setup-3F5IK7MO.js +31 -0
  167. package/dist/setup-KPIMRZ4Q.js +2 -0
  168. package/dist/shift-6GCNH666.js +11 -0
  169. package/dist/show-BOAVWZPZ.js +7 -0
  170. package/dist/show-PJ5LFLIL.js +5 -0
  171. package/dist/snapshot-L2G56RPL.js +8 -0
  172. package/dist/spawn-UH5RENSE.js +12 -0
  173. package/dist/status-77M3SDIF.js +8 -0
  174. package/dist/status-A37ECYNJ.js +6 -0
  175. package/dist/summary-ZJLQ6KHB.js +7 -0
  176. package/dist/sweep-HU74OPVW.js +17 -0
  177. package/dist/switch-CTW4PDGI.js +17 -0
  178. package/dist/symphony-3QMBGCZY.js +2 -0
  179. package/dist/symphony-QI63XL62.js +53 -0
  180. package/dist/symphony-loader-XACVV2E3.js +2 -0
  181. package/dist/symphony-peers-U4KHMKGI.js +2 -0
  182. package/dist/symphony-peers-X5NGWXFP.js +2 -0
  183. package/dist/symphony-relay-5GY5JIPT.js +3 -0
  184. package/dist/sync-QRDSFETO.js +2 -0
  185. package/dist/sync-llms-HL5PPW3M.js +15 -0
  186. package/dist/task-loader-NZFDTUQ5.js +2 -0
  187. package/dist/team-WGERKGNP.js +2 -0
  188. package/dist/test-BQJMS4Y2.js +111 -0
  189. package/dist/thread-HFXK65D4.js +41 -0
  190. package/dist/timeline-K3ZFKJ3R.js +6 -0
  191. package/dist/triage-FCWOZASE.js +18 -0
  192. package/dist/tutorial-UC6YQMNN.js +305 -0
  193. package/dist/university-content/courses/.purpose +74 -5
  194. package/dist/university-content/courses/para-701.json +807 -0
  195. package/dist/university-content/plsat/.purpose +3 -2
  196. package/dist/university-ui/assets/{index-BjewBB6s.js → index-CGFJczb1.js} +2 -2
  197. package/dist/university-ui/assets/{index-BjewBB6s.js.map → index-CGFJczb1.js.map} +1 -1
  198. package/dist/university-ui/index.html +1 -1
  199. package/dist/upgrade-B4IOLZYK.js +53 -0
  200. package/dist/validate-C6SMKGYD.js +9 -0
  201. package/dist/validate-LSCDOLBO.js +13 -0
  202. package/dist/validate-VZXTJHGO.js +6 -0
  203. package/dist/watch-LRM5XD46.js +8 -0
  204. package/dist/watch-PZCCUP6K.js +9 -0
  205. package/dist/wisdom-XZ3QKPNP.js +7 -0
  206. package/dist/work-log-loader-DL5GZ2BQ.js +2 -0
  207. package/dist/workspace-2ODL5WLY.js +2 -0
  208. package/package.json +1 -1
  209. package/platform-ui/dist/assets/AmbientSection-DqQ2mfCO.js +1 -0
  210. package/platform-ui/dist/assets/{CanvasSection-DwPTRdIN.js → CanvasSection-DLW0s-Bu.js} +1 -1
  211. package/platform-ui/dist/assets/{DocsSection-BJc_ws4I.js → DocsSection-BQ9Hi51g.js} +1 -1
  212. package/platform-ui/dist/assets/{GitSection-DhqBo1xc.js → GitSection-QQeUX6o3.js} +1 -1
  213. package/platform-ui/dist/assets/{GraphSection-D9fhVnZ0.js → GraphSection-0c9C-w7K.js} +2 -2
  214. package/platform-ui/dist/assets/{GraphSection-BlgXTl53.css → GraphSection-Bbs2a8sC.css} +1 -1
  215. package/platform-ui/dist/assets/LoreSection--t56kCj2.js +1 -0
  216. package/platform-ui/dist/assets/LoreSection-qnmm3o4y.css +1 -0
  217. package/platform-ui/dist/assets/SentinelSection-C4OoME9U.js +1 -0
  218. package/platform-ui/dist/assets/{SymphonySection-BRoBaUSS.js → SymphonySection-B-rvsLxq.js} +1 -1
  219. package/platform-ui/dist/assets/TeamSection-CBFmNEEo.js +1 -0
  220. package/platform-ui/dist/assets/index-Bxp0TVaf.css +1 -0
  221. package/platform-ui/dist/assets/index-DPpOdAtC.js +57 -0
  222. package/platform-ui/dist/index.html +2 -2
  223. package/dist/accept-orchestration-UQLM7PTQ.js +0 -189
  224. package/dist/add-FZRKEGH4.js +0 -81
  225. package/dist/agent-WERIO2XV.js +0 -523
  226. package/dist/agent-loader-TFIANSF4.js +0 -44
  227. package/dist/agent-state-S5DAWPTF.js +0 -24
  228. package/dist/agents-suggest-DNSYJ6IA.js +0 -83
  229. package/dist/aggregate-H57K7PNV.js +0 -88
  230. package/dist/assess-4WVXZLZQ.js +0 -68
  231. package/dist/auto-QFS5NHQU.js +0 -504
  232. package/dist/beacon-KXZXYQHX.js +0 -251
  233. package/dist/calibration-V46G7JTY.js +0 -135
  234. package/dist/check-OWAIWV23.js +0 -175
  235. package/dist/chunk-2IO7JAG2.js +0 -148
  236. package/dist/chunk-2T6BTYBN.js +0 -712
  237. package/dist/chunk-36TKPM5Z.js +0 -400
  238. package/dist/chunk-45MUDW6E.js +0 -804
  239. package/dist/chunk-4BLYIB7J.js +0 -5701
  240. package/dist/chunk-4L3UTYQX.js +0 -677
  241. package/dist/chunk-4NCFWYGG.js +0 -110
  242. package/dist/chunk-54LTTQBH.js +0 -138
  243. package/dist/chunk-5EWAQHFY.js +0 -269
  244. package/dist/chunk-5JGJACDU.js +0 -37
  245. package/dist/chunk-5OUOLN6M.js +0 -659
  246. package/dist/chunk-5VKJBNJL.js +0 -444
  247. package/dist/chunk-6N3JTACN.js +0 -2260
  248. package/dist/chunk-6QC3YGB6.js +0 -114
  249. package/dist/chunk-7N7GSU6K.js +0 -34
  250. package/dist/chunk-ABVQGRF7.js +0 -268
  251. package/dist/chunk-CL7JSK52.js +0 -129
  252. package/dist/chunk-CSD7IHSN.js +0 -152
  253. package/dist/chunk-EDOAWN7J.js +0 -717
  254. package/dist/chunk-EKGMAM62.js +0 -525
  255. package/dist/chunk-EZ3GOCYC.js +0 -132
  256. package/dist/chunk-F3BCHPYT.js +0 -143
  257. package/dist/chunk-FKJUBQU3.js +0 -3081
  258. package/dist/chunk-GT5QGC2H.js +0 -253
  259. package/dist/chunk-GZDFVP2N.js +0 -540
  260. package/dist/chunk-IRKUEJVW.js +0 -405
  261. package/dist/chunk-J2JEQRT3.js +0 -164
  262. package/dist/chunk-JASGXLK3.js +0 -679
  263. package/dist/chunk-KVDYJLTC.js +0 -121
  264. package/dist/chunk-L27I3CPZ.js +0 -357
  265. package/dist/chunk-LHLIAYQ3.js +0 -185
  266. package/dist/chunk-MCMOGQMU.js +0 -145
  267. package/dist/chunk-NQKQG45G.js +0 -688
  268. package/dist/chunk-PBHIFAL4.js +0 -259
  269. package/dist/chunk-PDX44BCA.js +0 -11
  270. package/dist/chunk-PMXRGPRQ.js +0 -305
  271. package/dist/chunk-RAB5IKPR.js +0 -487
  272. package/dist/chunk-RJE5G7WO.js +0 -590
  273. package/dist/chunk-RTHA3XRE.js +0 -880
  274. package/dist/chunk-S2HO5MLR.js +0 -621
  275. package/dist/chunk-S3ORKP3V.js +0 -716
  276. package/dist/chunk-TAIJOFOE.js +0 -124
  277. package/dist/chunk-TXESEO7Y.js +0 -245
  278. package/dist/chunk-UPLDI7CN.js +0 -1334
  279. package/dist/chunk-VL67H5IC.js +0 -506
  280. package/dist/chunk-VPPK3SY4.js +0 -1136
  281. package/dist/chunk-YMDLDELF.js +0 -314
  282. package/dist/chunk-YO6DVTL7.js +0 -99
  283. package/dist/chunk-YRZ5RPEB.js +0 -1561
  284. package/dist/chunk-ZDHLG5VP.js +0 -5676
  285. package/dist/chunk-ZGUAAVMA.js +0 -756
  286. package/dist/chunk-ZSYVKSY6.js +0 -2602
  287. package/dist/claude-FRRWJSTJ.js +0 -362
  288. package/dist/claude-cli-XJLK2X4L.js +0 -276
  289. package/dist/claude-code-HTBA4XRB.js +0 -126
  290. package/dist/claude-code-teams-T4SP24MD.js +0 -199
  291. package/dist/commands-5N4ILTPH.js +0 -5859
  292. package/dist/conductor-CQVGTEQN.js +0 -161
  293. package/dist/config-schema-EA4XALGG.js +0 -154
  294. package/dist/constellation-A26CCGQS.js +0 -225
  295. package/dist/context-audit-RLO3ETRP.js +0 -682
  296. package/dist/cost-BGM32XJU.js +0 -93
  297. package/dist/cost-VI46A4XL.js +0 -174
  298. package/dist/cursor-cli-JVEZGHWQ.js +0 -269
  299. package/dist/cursorrules-HLIKJJZT.js +0 -84
  300. package/dist/decision-loader-WWCLIQPJ.js +0 -20
  301. package/dist/delete-KBRPQLPC.js +0 -56
  302. package/dist/diff-D4X53HAC.js +0 -126
  303. package/dist/discipline-FA4OZXIS.js +0 -24
  304. package/dist/dist-34NA5RS5.js +0 -74
  305. package/dist/dist-5QE2BB2B-5S3T6Y3T.js +0 -6919
  306. package/dist/dist-77JDTVAY.js +0 -62
  307. package/dist/dist-OGTSAZ55.js +0 -1358
  308. package/dist/dist-QK4SQAK7.js +0 -64
  309. package/dist/dist-TA6LSC2Q.js +0 -20
  310. package/dist/docs-PBZB7LYP.js +0 -89
  311. package/dist/docs-QIYKO3BR.js +0 -155
  312. package/dist/doctor-ULBOHEIC.js +0 -11
  313. package/dist/drift-R5NRKFHI.js +0 -251
  314. package/dist/echo-O2LY7CC2.js +0 -248
  315. package/dist/edit-R2HNLMOG.js +0 -63
  316. package/dist/event-25OJKDCE.js +0 -31
  317. package/dist/export-IWVL7XLF.js +0 -38
  318. package/dist/flow-CRRVV3O3.js +0 -185
  319. package/dist/global-3NG5JXUB.js +0 -136
  320. package/dist/graduate-USAWGBJM.js +0 -160
  321. package/dist/graph-VHUMAAS6.js +0 -12
  322. package/dist/graph-server-YL22VBBN.js +0 -116
  323. package/dist/habits-OL5NGPXO.js +0 -1405
  324. package/dist/history-WOWC573W.js +0 -277
  325. package/dist/hooks-HFWSCGPV.js +0 -12
  326. package/dist/integrity-IHO4FZTS.js +0 -194
  327. package/dist/integrity-checker-PSKJA5SB.js +0 -12
  328. package/dist/journal-loader-5EYSBFFY.js +0 -18
  329. package/dist/lint-K6CJGGPH.js +0 -456
  330. package/dist/list-4YK7QKFF.js +0 -57
  331. package/dist/list-ENR7Q4CR.js +0 -56
  332. package/dist/lore-loader-7NO6N6FT.js +0 -26
  333. package/dist/lore-server-UNJY5KC3.js +0 -118
  334. package/dist/manual-G6FISID5.js +0 -204
  335. package/dist/migrate-LS45DNEV.js +0 -889
  336. package/dist/migrate-assessments-RGH4O6IX.js +0 -97
  337. package/dist/model-discovery-D2H3VBGC.js +0 -8
  338. package/dist/nomination-engine-RV5CNO5B.js +0 -42
  339. package/dist/notebook-YWIYGEHV.js +0 -155
  340. package/dist/orchestrate-JLILBBJE.js +0 -324
  341. package/dist/peers-DEOUIZM6.js +0 -82
  342. package/dist/persona-UHAHIVST.js +0 -390
  343. package/dist/pipeline-L4HCSBGN.js +0 -263
  344. package/dist/platform-server-H5YO3DQD.js +0 -1475
  345. package/dist/plugin-update-checker-KRRSGXMV.js +0 -12
  346. package/dist/portal-check-NPYGII2D.js +0 -42
  347. package/dist/portal-compliance-J7DGAPFX.js +0 -18
  348. package/dist/probe-MHL5HQZ2.js +0 -167
  349. package/dist/promote-F6ZYZZAL.js +0 -182
  350. package/dist/providers-GK7PB2OL.js +0 -104
  351. package/dist/quiz-M66SC7F7.js +0 -99
  352. package/dist/record-RA4WR2BO.js +0 -49
  353. package/dist/reindex-5LTD53ZC.js +0 -16
  354. package/dist/remember-HBWJ655S.js +0 -77
  355. package/dist/retag-3OLCVDEQ.js +0 -62
  356. package/dist/review-27ATYTD2.js +0 -33
  357. package/dist/review-57QMURZV.js +0 -334
  358. package/dist/ripple-JPBXP5I3.js +0 -215
  359. package/dist/sentinel-4XIG4STA.js +0 -63
  360. package/dist/sentinel-bridge-MDUXTQRL.js +0 -109
  361. package/dist/serve-CAH3PHE7.js +0 -33
  362. package/dist/serve-INL7SNBK.js +0 -36
  363. package/dist/serve-KBSE36PL.js +0 -49
  364. package/dist/server-54SKYFFY.js +0 -1647
  365. package/dist/server-XUOIO7E6.js +0 -338
  366. package/dist/session-tracker-C4BMD5WG.js +0 -13
  367. package/dist/session-work-log-MZ47OAPB.js +0 -20
  368. package/dist/setup-EDS27WUR.js +0 -25
  369. package/dist/setup-KO5AFC4K.js +0 -296
  370. package/dist/shift-D2JOHHBF.js +0 -668
  371. package/dist/show-5PV5KFJE.js +0 -176
  372. package/dist/show-NQKYX6WQ.js +0 -82
  373. package/dist/snapshot-BK4RBPCG.js +0 -62
  374. package/dist/spawn-RCHNXDHE.js +0 -196
  375. package/dist/status-WGIAQODY.js +0 -71
  376. package/dist/summary-NIRABMF5.js +0 -140
  377. package/dist/sweep-QMHNSIY5.js +0 -934
  378. package/dist/switch-6EJPZDIA.js +0 -232
  379. package/dist/symphony-4OCY36AI.js +0 -791
  380. package/dist/symphony-B75X2MME.js +0 -326
  381. package/dist/symphony-loader-UZGON56V.js +0 -90
  382. package/dist/symphony-peers-2ZQYLRNI.js +0 -34
  383. package/dist/symphony-peers-OL7F6M5S.js +0 -121
  384. package/dist/symphony-relay-UJYUXN65.js +0 -710
  385. package/dist/sync-VEHUH4OA.js +0 -11
  386. package/dist/sync-llms-YHCFIE6X.js +0 -166
  387. package/dist/task-loader-LDYWQSLM.js +0 -20
  388. package/dist/team-O5MIIFMA.js +0 -34
  389. package/dist/test-566CP5KC.js +0 -1017
  390. package/dist/thread-N754I4D5.js +0 -274
  391. package/dist/timeline-M3CICQFE.js +0 -112
  392. package/dist/triage-HHYGT3HY.js +0 -671
  393. package/dist/tutorial-KD22SUNO.js +0 -666
  394. package/dist/upgrade-H5PF32BW.js +0 -551
  395. package/dist/validate-CNKEKO6A.js +0 -134
  396. package/dist/validate-MB5ULIHS.js +0 -39
  397. package/dist/validate-QH3LADM6.js +0 -64
  398. package/dist/watch-2TKP5PVL.js +0 -199
  399. package/dist/watch-ZF4ML6CD.js +0 -111
  400. package/dist/wisdom-AATMGNFA.js +0 -319
  401. package/dist/work-log-loader-5L45XNYZ.js +0 -14
  402. package/dist/workspace-6E6OSRNU.js +0 -21
  403. package/platform-ui/dist/assets/AmbientSection-WtHfNedO.js +0 -1
  404. package/platform-ui/dist/assets/LoreSection-C3EixkjW.css +0 -1
  405. package/platform-ui/dist/assets/LoreSection-CwDDHrz9.js +0 -1
  406. package/platform-ui/dist/assets/SentinelSection-Cl7e5oZ6.js +0 -1
  407. package/platform-ui/dist/assets/TeamSection-CqSIMrKz.js +0 -1
  408. package/platform-ui/dist/assets/index-CfpZFjea.css +0 -1
  409. package/platform-ui/dist/assets/index-F0KL9xrN.js +0 -57
@@ -1,2602 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- SentinelStorage
4
- } from "./chunk-FKJUBQU3.js";
5
-
6
- // ../sentinel/dist/chunk-VQ3SIN7S.js
7
- import { v4 as uuidv4 } from "uuid";
8
- var DEFAULTS = {
9
- url: "http://localhost:3838",
10
- batchSize: 50,
11
- flushIntervalMs: 5e3,
12
- maxBufferSize: 1e3,
13
- maxRetries: 3,
14
- retryBackoffMs: 1e3
15
- };
16
- var SentinelClient = class {
17
- url;
18
- service;
19
- version;
20
- environment;
21
- token;
22
- batchSize;
23
- maxBufferSize;
24
- maxRetries;
25
- retryBackoffMs;
26
- onDrop;
27
- onError;
28
- sessionId;
29
- logBuffer = [];
30
- metricsBuffer = [];
31
- flushTimer = null;
32
- closed = false;
33
- beforeUnloadHandler = null;
34
- constructor(options) {
35
- this.url = (options.url ?? DEFAULTS.url).replace(/\/+$/, "");
36
- this.service = options.service;
37
- this.version = options.version;
38
- this.environment = options.environment;
39
- this.token = options.token;
40
- this.batchSize = options.batchSize ?? DEFAULTS.batchSize;
41
- this.maxBufferSize = options.maxBufferSize ?? DEFAULTS.maxBufferSize;
42
- this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;
43
- this.retryBackoffMs = options.retryBackoffMs ?? DEFAULTS.retryBackoffMs;
44
- this.onDrop = options.onDrop;
45
- this.onError = options.onError;
46
- this.sessionId = uuidv4();
47
- const intervalMs = options.flushIntervalMs ?? DEFAULTS.flushIntervalMs;
48
- this.flushTimer = setInterval(() => {
49
- this.flush().catch((err) => {
50
- this.handleError(err);
51
- });
52
- }, intervalMs);
53
- if (this.flushTimer && typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
54
- this.flushTimer.unref();
55
- }
56
- if (typeof globalThis !== "undefined" && typeof globalThis.addEventListener === "function") {
57
- this.beforeUnloadHandler = () => {
58
- this.flushSync();
59
- };
60
- globalThis.addEventListener("beforeunload", this.beforeUnloadHandler);
61
- }
62
- this.registerService();
63
- }
64
- // ── Logging Methods ──────────────────────────────────────────────
65
- /** Log a debug-level message */
66
- debug(symbol, message, data) {
67
- this.log("debug", symbol, message, data);
68
- }
69
- /** Log an info-level message */
70
- info(symbol, message, data) {
71
- this.log("info", symbol, message, data);
72
- }
73
- /** Log a warn-level message */
74
- warn(symbol, message, data) {
75
- this.log("warn", symbol, message, data);
76
- }
77
- /** Log an error-level message */
78
- error(symbol, message, data) {
79
- this.log("error", symbol, message, data);
80
- }
81
- /** Log a message at the specified level */
82
- log(level, symbol, message, data) {
83
- if (this.closed) return;
84
- const entry = {
85
- level,
86
- symbol,
87
- message,
88
- service: this.service,
89
- sessionId: this.sessionId,
90
- environment: this.environment,
91
- data
92
- };
93
- this.pushToLogBuffer(entry);
94
- }
95
- // ── Metrics Methods ──────────────────────────────────────────────
96
- /** Record a counter metric (increments) */
97
- counter(name, value, tags) {
98
- this.metric({ name, type: "counter", value: value ?? 1, tags });
99
- }
100
- /** Record a gauge metric (current value) */
101
- gauge(name, value, tags) {
102
- this.metric({ name, type: "gauge", value, tags });
103
- }
104
- /** Record a histogram metric (distribution) */
105
- histogram(name, value, tags) {
106
- this.metric({ name, type: "histogram", value, tags });
107
- }
108
- /** Record a metric of any type */
109
- metric(input) {
110
- if (this.closed) return;
111
- const entry = {
112
- ...input,
113
- service: this.service,
114
- environment: this.environment
115
- };
116
- this.pushToMetricsBuffer(entry);
117
- }
118
- // ── State Push ───────────────────────────────────────────────────
119
- /** Push an application state snapshot to the server */
120
- async pushState(state, activeFlows, activeGates) {
121
- if (this.closed) return;
122
- await this.post("/api/state", {
123
- service: this.service,
124
- sessionId: this.sessionId,
125
- state,
126
- activeFlows,
127
- activeGates
128
- });
129
- }
130
- // ── Tracing ──────────────────────────────────────────────────────
131
- /** Start a trace span. Call end() on the returned SpanContext when the operation completes. */
132
- startSpan(symbol, operation, parentSpanId) {
133
- const traceId = parentSpanId ? parentSpanId.split("-")[0] || uuidv4() : uuidv4();
134
- const spanId = uuidv4();
135
- const startTime = (/* @__PURE__ */ new Date()).toISOString();
136
- const startMs = Date.now();
137
- const self = this;
138
- return {
139
- traceId,
140
- spanId,
141
- async end(status = "ok") {
142
- const endTime = (/* @__PURE__ */ new Date()).toISOString();
143
- const durationMs = Date.now() - startMs;
144
- const span = {
145
- traceId,
146
- spanId,
147
- parentSpanId,
148
- service: self.service,
149
- symbol,
150
- operation,
151
- startTime,
152
- endTime,
153
- durationMs,
154
- status
155
- };
156
- await self.post("/api/traces", span);
157
- }
158
- };
159
- }
160
- // ── Buffer Management ────────────────────────────────────────────
161
- /** Flush all buffered logs and metrics to the server */
162
- async flush() {
163
- const logEntries = this.drainLogBuffer();
164
- const metricEntries = this.drainMetricsBuffer();
165
- const promises = [];
166
- if (logEntries.length > 0) {
167
- promises.push(this.sendLogs(logEntries));
168
- }
169
- if (metricEntries.length > 0) {
170
- promises.push(this.sendMetrics(metricEntries));
171
- }
172
- await Promise.allSettled(promises);
173
- }
174
- // ── Lifecycle ────────────────────────────────────────────────────
175
- /** Flush remaining entries and shut down the client */
176
- async close() {
177
- if (this.closed) return;
178
- this.closed = true;
179
- if (this.flushTimer !== null) {
180
- clearInterval(this.flushTimer);
181
- this.flushTimer = null;
182
- }
183
- if (this.beforeUnloadHandler && typeof globalThis !== "undefined" && typeof globalThis.removeEventListener === "function") {
184
- globalThis.removeEventListener("beforeunload", this.beforeUnloadHandler);
185
- this.beforeUnloadHandler = null;
186
- }
187
- try {
188
- await this.flush();
189
- } catch {
190
- }
191
- }
192
- /** Get the session ID assigned to this client instance */
193
- getSessionId() {
194
- return this.sessionId;
195
- }
196
- /**
197
- * Synchronous best-effort flush using sendBeacon (browser) or sync XHR fallback.
198
- * Used in beforeunload where async is unreliable.
199
- */
200
- flushSync() {
201
- const logEntries = this.drainLogBuffer();
202
- const metricEntries = this.drainMetricsBuffer();
203
- const sendBeacon = typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" ? navigator.sendBeacon.bind(navigator) : void 0;
204
- if (sendBeacon) {
205
- if (logEntries.length > 0) {
206
- sendBeacon(`${this.url}/api/logs`, JSON.stringify({ entries: logEntries }));
207
- }
208
- if (metricEntries.length > 0) {
209
- sendBeacon(`${this.url}/api/metrics`, JSON.stringify({ entries: metricEntries }));
210
- }
211
- }
212
- }
213
- // ═══════════════════════════════════════════════════════════════════
214
- // PRIVATE METHODS
215
- // ═══════════════════════════════════════════════════════════════════
216
- /** Register this service with the Sentinel server (fire-and-forget) */
217
- registerService() {
218
- const registration = {
219
- name: this.service,
220
- version: this.version,
221
- pid: typeof process !== "undefined" ? process.pid : void 0,
222
- environment: this.environment
223
- };
224
- this.post("/api/services", registration).catch(() => {
225
- });
226
- }
227
- /** Push a log entry into the ring buffer, enforcing maxBufferSize */
228
- pushToLogBuffer(entry) {
229
- if (this.logBuffer.length >= this.maxBufferSize) {
230
- const dropCount = Math.max(1, Math.floor(this.maxBufferSize * 0.1));
231
- this.logBuffer.splice(0, dropCount);
232
- if (this.onDrop) {
233
- this.onDrop(dropCount);
234
- }
235
- }
236
- this.logBuffer.push(entry);
237
- if (this.logBuffer.length >= this.batchSize) {
238
- this.flush().catch((err) => {
239
- this.handleError(err);
240
- });
241
- }
242
- }
243
- /** Push a metric entry into the ring buffer, enforcing maxBufferSize */
244
- pushToMetricsBuffer(entry) {
245
- if (this.metricsBuffer.length >= this.maxBufferSize) {
246
- const dropCount = Math.max(1, Math.floor(this.maxBufferSize * 0.1));
247
- this.metricsBuffer.splice(0, dropCount);
248
- if (this.onDrop) {
249
- this.onDrop(dropCount);
250
- }
251
- }
252
- this.metricsBuffer.push(entry);
253
- if (this.metricsBuffer.length >= this.batchSize) {
254
- this.flush().catch((err) => {
255
- this.handleError(err);
256
- });
257
- }
258
- }
259
- /** Drain and return all entries from the log buffer */
260
- drainLogBuffer() {
261
- const entries = this.logBuffer;
262
- this.logBuffer = [];
263
- return entries;
264
- }
265
- /** Drain and return all entries from the metrics buffer */
266
- drainMetricsBuffer() {
267
- const entries = this.metricsBuffer;
268
- this.metricsBuffer = [];
269
- return entries;
270
- }
271
- /** Send log entries to the server with retry */
272
- async sendLogs(entries) {
273
- try {
274
- await this.post("/api/logs", { entries });
275
- } catch (err) {
276
- const capacity = this.maxBufferSize - this.logBuffer.length;
277
- if (capacity > 0) {
278
- const toRestore = entries.slice(0, capacity);
279
- this.logBuffer.unshift(...toRestore);
280
- const dropped = entries.length - toRestore.length;
281
- if (dropped > 0 && this.onDrop) {
282
- this.onDrop(dropped);
283
- }
284
- } else if (this.onDrop) {
285
- this.onDrop(entries.length);
286
- }
287
- throw err;
288
- }
289
- }
290
- /** Send metric entries to the server with retry */
291
- async sendMetrics(entries) {
292
- try {
293
- await this.post("/api/metrics", { entries });
294
- } catch (err) {
295
- const capacity = this.maxBufferSize - this.metricsBuffer.length;
296
- if (capacity > 0) {
297
- const toRestore = entries.slice(0, capacity);
298
- this.metricsBuffer.unshift(...toRestore);
299
- const dropped = entries.length - toRestore.length;
300
- if (dropped > 0 && this.onDrop) {
301
- this.onDrop(dropped);
302
- }
303
- } else if (this.onDrop) {
304
- this.onDrop(entries.length);
305
- }
306
- throw err;
307
- }
308
- }
309
- /**
310
- * POST JSON to the Sentinel server with exponential backoff retry.
311
- * Retries on network errors and 5xx responses. Does NOT retry on 4xx.
312
- */
313
- async post(path4, body) {
314
- const fetchFn = this.getFetch();
315
- if (!fetchFn) {
316
- return void 0;
317
- }
318
- const url = `${this.url}${path4}`;
319
- const headers = {
320
- "Content-Type": "application/json"
321
- };
322
- if (this.token) {
323
- headers["Authorization"] = `Bearer ${this.token}`;
324
- }
325
- let lastError;
326
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
327
- try {
328
- const response = await fetchFn(url, {
329
- method: "POST",
330
- headers,
331
- body: JSON.stringify(body)
332
- });
333
- if (response.status >= 400 && response.status < 500) {
334
- const text = await response.text().catch(() => "");
335
- const err = new Error(`Sentinel server returned ${response.status}: ${text}`);
336
- this.handleError(err);
337
- return void 0;
338
- }
339
- if (response.status >= 500) {
340
- const text = await response.text().catch(() => "");
341
- lastError = new Error(`Sentinel server returned ${response.status}: ${text}`);
342
- if (attempt < this.maxRetries) {
343
- await this.backoff(attempt);
344
- continue;
345
- }
346
- this.handleError(lastError);
347
- throw lastError;
348
- }
349
- const contentType = response.headers.get("content-type") || "";
350
- if (contentType.includes("application/json")) {
351
- return await response.json();
352
- }
353
- return void 0;
354
- } catch (err) {
355
- lastError = err instanceof Error ? err : new Error(String(err));
356
- if (attempt < this.maxRetries) {
357
- await this.backoff(attempt);
358
- continue;
359
- }
360
- this.handleError(lastError);
361
- throw lastError;
362
- }
363
- }
364
- if (lastError) throw lastError;
365
- return void 0;
366
- }
367
- /** Get the fetch function, falling back to globalThis.fetch */
368
- getFetch() {
369
- if (typeof globalThis !== "undefined" && typeof globalThis.fetch === "function") {
370
- return globalThis.fetch;
371
- }
372
- return void 0;
373
- }
374
- /** Wait with exponential backoff */
375
- backoff(attempt) {
376
- const delayMs = this.retryBackoffMs * Math.pow(2, attempt);
377
- const jitter = Math.floor(Math.random() * delayMs * 0.25);
378
- return new Promise((resolve) => setTimeout(resolve, delayMs + jitter));
379
- }
380
- /** Handle an error, calling the onError callback if provided */
381
- handleError(err) {
382
- if (this.onError) {
383
- const error = err instanceof Error ? err : new Error(String(err));
384
- this.onError(error);
385
- }
386
- }
387
- };
388
- function createSentinelClient(options) {
389
- return new SentinelClient(options);
390
- }
391
- var SentinelTransport = class {
392
- client;
393
- constructor(client) {
394
- this.client = client;
395
- }
396
- send(entry) {
397
- this.client.log(
398
- entry.level,
399
- entry.symbol,
400
- entry.message,
401
- {
402
- ...entry.data,
403
- symbolType: entry.symbolType,
404
- correlationId: entry.correlationId
405
- }
406
- );
407
- }
408
- };
409
- function createSentinelTransport(clientOrOptions) {
410
- const client = clientOrOptions instanceof SentinelClient ? clientOrOptions : new SentinelClient(clientOrOptions);
411
- return new SentinelTransport(client);
412
- }
413
- function enableSentinel(logger, clientOrOptions) {
414
- const transport = createSentinelTransport(clientOrOptions);
415
- logger.addTransport(transport);
416
- return transport;
417
- }
418
-
419
- // ../sentinel/dist/index.js
420
- import * as path from "path";
421
- import * as fs from "fs";
422
- import { fileURLToPath } from "url";
423
- import * as fs2 from "fs";
424
- import * as path2 from "path";
425
- import * as fs3 from "fs";
426
- import * as path3 from "path";
427
- import * as fs4 from "fs";
428
- var DEFAULT_CONFIG = {
429
- minScore: 30,
430
- maxResults: 5,
431
- boostConfidence: true
432
- };
433
- var PatternMatcher = class {
434
- constructor(storage) {
435
- this.storage = storage;
436
- }
437
- /**
438
- * Match an incident against all patterns and return ranked results
439
- */
440
- match(incident, config = {}) {
441
- const { minScore, maxResults, boostConfidence } = {
442
- ...DEFAULT_CONFIG,
443
- ...config
444
- };
445
- const patterns = this.storage.getAllPatterns({ includePrivate: true });
446
- const matches = [];
447
- for (const pattern of patterns) {
448
- if (!this.matchEnvironment(pattern, incident)) {
449
- continue;
450
- }
451
- const { score, matchedCriteria } = this.scoreMatch(pattern, incident);
452
- if (score >= minScore) {
453
- let confidence = score;
454
- if (boostConfidence) {
455
- const confidenceFactor = pattern.confidence.score / 100;
456
- confidence = score * (0.5 + 0.5 * confidenceFactor);
457
- }
458
- matches.push({
459
- pattern,
460
- score,
461
- matchedCriteria,
462
- confidence: Math.round(confidence)
463
- });
464
- this.storage.updatePatternConfidence(pattern.id, "matched");
465
- }
466
- }
467
- return matches.sort((a, b) => b.confidence - a.confidence).slice(0, maxResults);
468
- }
469
- /**
470
- * Test a pattern against historical incidents
471
- */
472
- testPattern(pattern, limit = 100) {
473
- const incidents = this.storage.getRecentIncidents({ limit });
474
- const wouldMatch = [];
475
- let totalScore = 0;
476
- for (const incident of incidents) {
477
- if (!this.matchEnvironment(pattern, incident)) {
478
- continue;
479
- }
480
- const { score } = this.scoreMatch(pattern, incident);
481
- if (score >= 30) {
482
- wouldMatch.push(incident);
483
- totalScore += score;
484
- }
485
- }
486
- return {
487
- wouldMatch,
488
- matchCount: wouldMatch.length,
489
- avgScore: wouldMatch.length > 0 ? Math.round(totalScore / wouldMatch.length) : 0
490
- };
491
- }
492
- /**
493
- * Score how well a pattern matches an incident
494
- */
495
- scoreMatch(pattern, incident) {
496
- let score = 0;
497
- const matchedCriteria = {
498
- symbols: [],
499
- errorKeywords: [],
500
- missingSignals: []
501
- };
502
- const symbolScore = this.matchSymbols(
503
- pattern.pattern.symbols,
504
- incident.symbols,
505
- matchedCriteria.symbols
506
- );
507
- score += Math.min(symbolScore, 50);
508
- const errorScore = this.matchErrorText(
509
- pattern,
510
- incident,
511
- matchedCriteria.errorKeywords
512
- );
513
- score += Math.min(errorScore, 25);
514
- const signalScore = this.matchMissingSignals(
515
- pattern,
516
- incident,
517
- matchedCriteria.missingSignals
518
- );
519
- score += Math.min(signalScore, 25);
520
- score = Math.min(score, 100);
521
- return { score, matchedCriteria };
522
- }
523
- /**
524
- * Match symbols between pattern and incident
525
- */
526
- matchSymbols(patternSymbols, incidentSymbols, matched) {
527
- let score = 0;
528
- const symbolTypes = [
529
- "feature",
530
- "component",
531
- "flow",
532
- "gate",
533
- "signal",
534
- "state",
535
- "integration"
536
- ];
537
- for (const type of symbolTypes) {
538
- const patternValue = patternSymbols[type];
539
- const incidentValue = incidentSymbols[type];
540
- if (!patternValue || !incidentValue) {
541
- continue;
542
- }
543
- if (typeof patternValue === "string") {
544
- if (this.matchSingleSymbol(patternValue, incidentValue)) {
545
- score += patternValue.includes("*") ? 5 : 10;
546
- matched.push(type);
547
- }
548
- } else if (Array.isArray(patternValue)) {
549
- for (const pv of patternValue) {
550
- if (this.matchSingleSymbol(pv, incidentValue)) {
551
- score += 7;
552
- matched.push(type);
553
- break;
554
- }
555
- }
556
- }
557
- }
558
- return score;
559
- }
560
- /**
561
- * Match a single symbol value (supports wildcards)
562
- */
563
- matchSingleSymbol(pattern, value) {
564
- if (pattern === "*") {
565
- return true;
566
- }
567
- if (pattern.endsWith("*")) {
568
- const prefix = pattern.slice(0, -1);
569
- return value.startsWith(prefix);
570
- }
571
- if (pattern.startsWith("*")) {
572
- const suffix = pattern.slice(1);
573
- return value.endsWith(suffix);
574
- }
575
- if (pattern.includes("*")) {
576
- const regex = new RegExp(
577
- "^" + pattern.replace(/\*/g, ".*") + "$"
578
- );
579
- return regex.test(value);
580
- }
581
- return pattern === value;
582
- }
583
- /**
584
- * Match error text keywords and regex
585
- */
586
- matchErrorText(pattern, incident, matched) {
587
- let score = 0;
588
- const errorMessage = incident.error.message.toLowerCase();
589
- const errorType = incident.error.type?.toLowerCase();
590
- if (pattern.pattern.errorContains) {
591
- for (const keyword of pattern.pattern.errorContains) {
592
- if (errorMessage.includes(keyword.toLowerCase())) {
593
- score += 5;
594
- matched.push(keyword);
595
- }
596
- }
597
- }
598
- if (pattern.pattern.errorMatches) {
599
- try {
600
- const regex = new RegExp(pattern.pattern.errorMatches, "i");
601
- if (regex.test(incident.error.message)) {
602
- score += 10;
603
- matched.push(`regex:${pattern.pattern.errorMatches}`);
604
- }
605
- } catch {
606
- }
607
- }
608
- if (pattern.pattern.errorType && errorType) {
609
- for (const type of pattern.pattern.errorType) {
610
- if (errorType.includes(type.toLowerCase())) {
611
- score += 5;
612
- matched.push(`type:${type}`);
613
- }
614
- }
615
- }
616
- return score;
617
- }
618
- /**
619
- * Match missing signals from flow position
620
- */
621
- matchMissingSignals(pattern, incident, matched) {
622
- if (!pattern.pattern.missingSignals || !incident.flowPosition?.missing) {
623
- return 0;
624
- }
625
- let score = 0;
626
- for (const expectedSignal of pattern.pattern.missingSignals) {
627
- for (const missingSignal of incident.flowPosition.missing) {
628
- if (this.matchSingleSymbol(expectedSignal, missingSignal)) {
629
- score += 12;
630
- matched.push(missingSignal);
631
- break;
632
- }
633
- }
634
- }
635
- return score;
636
- }
637
- /**
638
- * Check if pattern's environment filter matches incident
639
- */
640
- matchEnvironment(pattern, incident) {
641
- if (!pattern.pattern.environment || pattern.pattern.environment.length === 0) {
642
- return true;
643
- }
644
- return pattern.pattern.environment.includes(incident.environment);
645
- }
646
- };
647
- var __filename = fileURLToPath(import.meta.url);
648
- var __dirname = path.dirname(__filename);
649
- function loadUniversalPatterns() {
650
- const filePath = path.join(__dirname, "universal-patterns.json");
651
- const content = fs.readFileSync(filePath, "utf-8");
652
- return JSON.parse(content);
653
- }
654
- function loadParadigmPatterns() {
655
- const filePath = path.join(__dirname, "paradigm-patterns.json");
656
- const content = fs.readFileSync(filePath, "utf-8");
657
- return JSON.parse(content);
658
- }
659
- function loadAllSeedPatterns() {
660
- const universal = loadUniversalPatterns();
661
- const paradigm = loadParadigmPatterns();
662
- return {
663
- version: "1.0.0",
664
- exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
665
- patterns: [...universal.patterns, ...paradigm.patterns]
666
- };
667
- }
668
- function ensurePrefix(id, prefix) {
669
- return id.startsWith(prefix) ? id : `${prefix}${id}`;
670
- }
671
- var FlowTracker = class {
672
- flowId;
673
- sentinel;
674
- actual = [];
675
- expected = [];
676
- completed = false;
677
- constructor(flowId, sentinel) {
678
- this.flowId = ensurePrefix(flowId, "$");
679
- this.sentinel = sentinel;
680
- }
681
- /** Declare which signals/gates are expected in this flow */
682
- expect(...symbols) {
683
- this.expected.push(...symbols);
684
- return this;
685
- }
686
- /** Record a generic step in the flow */
687
- step(symbol) {
688
- this.actual.push(symbol);
689
- return this;
690
- }
691
- /** Record a gate check result */
692
- gate(id, passed) {
693
- const gateId = ensurePrefix(id, "^");
694
- this.actual.push(gateId);
695
- if (!passed) {
696
- this.fail(new Error(`Gate ${gateId} failed`));
697
- }
698
- return this;
699
- }
700
- /** Record a signal emission */
701
- signal(id, _data) {
702
- this.actual.push(ensurePrefix(id, "!"));
703
- return this;
704
- }
705
- /** Mark the flow as successfully completed */
706
- complete() {
707
- this.completed = true;
708
- }
709
- /** Capture an error with full flow position context */
710
- fail(error) {
711
- if (this.completed) return;
712
- this.completed = true;
713
- const missing = this.expected.filter((s) => !this.actual.includes(s));
714
- const failedAt = this.actual.length > 0 ? this.actual[this.actual.length - 1] : void 0;
715
- const flowPosition = {
716
- flowId: this.flowId,
717
- expected: this.expected,
718
- actual: this.actual,
719
- missing,
720
- failedAt
721
- };
722
- this.sentinel.capture(error, { flow: this.flowId }, flowPosition);
723
- }
724
- };
725
- var Sentinel = class {
726
- storage;
727
- matcher;
728
- config;
729
- ready = false;
730
- readyPromise = null;
731
- seeded = false;
732
- constructor(config) {
733
- this.config = config;
734
- this.storage = new SentinelStorage(config.dbPath);
735
- this.matcher = new PatternMatcher(this.storage);
736
- }
737
- /** Explicitly initialize storage. Optional — auto-called on first capture. */
738
- async init() {
739
- if (this.ready) return;
740
- if (this.readyPromise) return this.readyPromise;
741
- this.readyPromise = this.doInit();
742
- return this.readyPromise;
743
- }
744
- async doInit() {
745
- await this.storage.ensureReady();
746
- if (!this.seeded) {
747
- try {
748
- const { patterns } = loadAllSeedPatterns();
749
- for (const pattern of patterns) {
750
- try {
751
- this.storage.addPattern(pattern);
752
- } catch {
753
- }
754
- }
755
- } catch {
756
- }
757
- this.seeded = true;
758
- }
759
- this.ready = true;
760
- }
761
- ensureReady() {
762
- if (!this.ready) {
763
- if (!this.readyPromise) {
764
- this.readyPromise = this.doInit();
765
- }
766
- }
767
- }
768
- // ── Symbol Context ──────────────────────────────────────────────
769
- /**
770
- * Create a component context for scoped error capture.
771
- *
772
- * @param id - Component symbol (e.g. '#checkout' or 'checkout')
773
- * @returns ComponentContext with capture() and wrap() methods
774
- */
775
- component(id) {
776
- const componentId = ensurePrefix(id, "#");
777
- const self = this;
778
- return {
779
- id: componentId,
780
- capture(error, extra) {
781
- return self.capture(error, { component: componentId, ...extra });
782
- },
783
- wrap(fn) {
784
- const wrapped = ((...args) => {
785
- try {
786
- const result = fn(...args);
787
- if (result && typeof result.catch === "function") {
788
- return result.catch((err) => {
789
- self.capture(err, { component: componentId });
790
- throw err;
791
- });
792
- }
793
- return result;
794
- } catch (err) {
795
- if (err instanceof Error) {
796
- self.capture(err, { component: componentId });
797
- }
798
- throw err;
799
- }
800
- });
801
- return wrapped;
802
- }
803
- };
804
- }
805
- /**
806
- * Record a gate check result.
807
- * If the gate fails, auto-captures an incident.
808
- *
809
- * @param id - Gate symbol (e.g. '^authenticated' or 'authenticated')
810
- * @param passed - Whether the gate passed
811
- */
812
- gate(id, passed) {
813
- if (!passed) {
814
- const gateId = ensurePrefix(id, "^");
815
- this.capture(new Error(`Gate ${gateId} failed`), { gate: gateId });
816
- }
817
- }
818
- /**
819
- * Record a signal emission. Primarily for flow tracking context.
820
- *
821
- * @param id - Signal symbol (e.g. '!payment-authorized' or 'payment-authorized')
822
- */
823
- signal(id, _data) {
824
- void ensurePrefix(id, "!");
825
- }
826
- // ── Flow Tracking ───────────────────────────────────────────────
827
- /**
828
- * Create a flow tracker for monitoring multi-step operations.
829
- *
830
- * @param id - Flow symbol (e.g. '$checkout-flow' or 'checkout-flow')
831
- * @returns FlowTracker instance
832
- */
833
- flow(id) {
834
- return new FlowTracker(id, this);
835
- }
836
- // ── Error Capture ───────────────────────────────────────────────
837
- /**
838
- * Capture an error with symbolic context.
839
- *
840
- * @param error - The error to capture
841
- * @param context - Symbolic context (component, gate, flow, signal)
842
- * @param flowPosition - Optional flow position data
843
- * @returns Incident ID (e.g. 'INC-001')
844
- */
845
- capture(error, context, flowPosition) {
846
- this.ensureReady();
847
- const input = {
848
- error: {
849
- message: error.message,
850
- stack: error.stack,
851
- type: error.constructor.name !== "Error" ? error.constructor.name : void 0
852
- },
853
- symbols: context || {},
854
- environment: this.config.environment || "development",
855
- service: this.config.service,
856
- version: this.config.version,
857
- flowPosition
858
- };
859
- const incidentId = this.storage.recordIncident(input);
860
- const incident = this.storage.getIncident(incidentId);
861
- if (incident && this.config.onCapture) {
862
- this.config.onCapture(incident);
863
- }
864
- return incidentId;
865
- }
866
- /**
867
- * Get pattern matches for a captured incident.
868
- *
869
- * @param incidentId - The incident ID to match
870
- * @returns Array of pattern matches sorted by confidence
871
- */
872
- match(incidentId) {
873
- const incident = this.storage.getIncident(incidentId);
874
- if (!incident) return [];
875
- return this.matcher.match(incident);
876
- }
877
- // ── Framework Integration ───────────────────────────────────────
878
- /**
879
- * Create Express error-handling middleware.
880
- *
881
- * Usage:
882
- * app.use(sentinel.express());
883
- */
884
- express() {
885
- const self = this;
886
- return (err, req, res, next) => {
887
- const context = {};
888
- const routeParts = (req.path || req.url || "").split("/").filter(Boolean);
889
- if (routeParts.length >= 2) {
890
- context.component = `#${routeParts[1]}`;
891
- }
892
- const incidentId = self.capture(err, context);
893
- if (res.setHeader) {
894
- res.setHeader("X-Sentinel-Incident", incidentId);
895
- }
896
- next(err);
897
- };
898
- }
899
- // ── Lifecycle ───────────────────────────────────────────────────
900
- /** Close the database connection. Call when shutting down. */
901
- close() {
902
- this.storage.close();
903
- this.ready = false;
904
- this.readyPromise = null;
905
- }
906
- /** Get the underlying storage instance (for advanced usage). */
907
- getStorage() {
908
- return this.storage;
909
- }
910
- /** Get the underlying pattern matcher (for advanced usage). */
911
- getMatcher() {
912
- return this.matcher;
913
- }
914
- };
915
- var DIR_PATTERNS = [
916
- { dirs: ["services", "src/services"], prefix: "#", type: "components" },
917
- { dirs: ["routes", "src/routes", "api", "src/api"], prefix: "#", type: "components" },
918
- { dirs: ["handlers", "src/handlers"], prefix: "#", type: "components" },
919
- { dirs: ["controllers", "src/controllers"], prefix: "#", type: "components" },
920
- { dirs: ["components", "src/components"], prefix: "#", type: "components" },
921
- { dirs: ["lib", "src/lib"], prefix: "#", type: "components" },
922
- { dirs: ["middleware", "src/middleware"], prefix: "^", type: "gates" },
923
- { dirs: ["guards", "src/guards"], prefix: "^", type: "gates" },
924
- { dirs: ["auth", "src/auth"], prefix: "^", type: "gates" },
925
- { dirs: ["events", "src/events"], prefix: "!", type: "signals" },
926
- { dirs: ["listeners", "src/listeners"], prefix: "!", type: "signals" },
927
- { dirs: ["flows", "src/flows"], prefix: "$", type: "flows" },
928
- { dirs: ["workflows", "src/workflows"], prefix: "$", type: "flows" },
929
- { dirs: ["pipelines", "src/pipelines"], prefix: "$", type: "flows" }
930
- ];
931
- var CODE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".tsx", ".jsx", ".mjs", ".mts"]);
932
- function detectSymbols(projectDir) {
933
- const result = {
934
- components: [],
935
- gates: [],
936
- flows: [],
937
- signals: [],
938
- routes: {}
939
- };
940
- const purposeSymbols = readPurposeFiles(projectDir);
941
- if (purposeSymbols) {
942
- result.components.push(...purposeSymbols.components);
943
- result.gates.push(...purposeSymbols.gates);
944
- result.flows.push(...purposeSymbols.flows);
945
- result.signals.push(...purposeSymbols.signals);
946
- }
947
- for (const pattern of DIR_PATTERNS) {
948
- for (const dir of pattern.dirs) {
949
- const fullPath = path2.join(projectDir, dir);
950
- if (!fs2.existsSync(fullPath)) continue;
951
- const files = safeReaddir(fullPath);
952
- for (const file of files) {
953
- const ext = path2.extname(file);
954
- if (!CODE_EXTENSIONS.has(ext)) continue;
955
- const name = path2.basename(file, ext);
956
- if (name === "index" || name.endsWith(".test") || name.endsWith(".spec")) continue;
957
- const symbol = `${pattern.prefix}${toKebabCase(name)}`;
958
- if (!result[pattern.type].includes(symbol)) {
959
- result[pattern.type].push(symbol);
960
- }
961
- }
962
- }
963
- }
964
- scanRoutes(projectDir, result);
965
- return result;
966
- }
967
- function generateConfig(projectDir) {
968
- const detected = detectSymbols(projectDir);
969
- return {
970
- version: "1.0",
971
- project: path2.basename(projectDir),
972
- symbols: {
973
- components: detected.components.length > 0 ? detected.components : void 0,
974
- gates: detected.gates.length > 0 ? detected.gates : void 0,
975
- flows: detected.flows.length > 0 ? detected.flows : void 0,
976
- signals: detected.signals.length > 0 ? detected.signals : void 0
977
- },
978
- routes: Object.keys(detected.routes).length > 0 ? detected.routes : void 0
979
- };
980
- }
981
- function readPurposeFiles(projectDir) {
982
- const paradigmDir = path2.join(projectDir, ".paradigm");
983
- if (!fs2.existsSync(paradigmDir)) return null;
984
- const result = {
985
- components: [],
986
- gates: [],
987
- flows: [],
988
- signals: [],
989
- routes: {}
990
- };
991
- const purposeFiles = findFiles(projectDir, ".purpose");
992
- for (const file of purposeFiles) {
993
- try {
994
- const content = fs2.readFileSync(file, "utf-8");
995
- extractPurposeSymbols(content, result);
996
- } catch {
997
- }
998
- }
999
- const hasAny = result.components.length > 0 || result.gates.length > 0 || result.flows.length > 0 || result.signals.length > 0;
1000
- return hasAny ? result : null;
1001
- }
1002
- function extractPurposeSymbols(content, result) {
1003
- const lines = content.split("\n");
1004
- let currentSection = "";
1005
- for (const line of lines) {
1006
- const trimmed = line.trim();
1007
- if (trimmed === "components:" || trimmed === "features:") {
1008
- currentSection = "components";
1009
- continue;
1010
- }
1011
- if (trimmed === "gates:") {
1012
- currentSection = "gates";
1013
- continue;
1014
- }
1015
- if (trimmed === "flows:") {
1016
- currentSection = "flows";
1017
- continue;
1018
- }
1019
- if (trimmed === "signals:") {
1020
- currentSection = "signals";
1021
- continue;
1022
- }
1023
- if (currentSection && /^\s{2}\S/.test(line)) {
1024
- const idMatch = trimmed.match(/^([a-zA-Z][\w-]*):$/);
1025
- if (idMatch) {
1026
- const prefixes = {
1027
- components: "#",
1028
- gates: "^",
1029
- flows: "$",
1030
- signals: "!"
1031
- };
1032
- const prefix = prefixes[currentSection] || "#";
1033
- const symbol = `${prefix}${idMatch[1]}`;
1034
- if (!result[currentSection]?.includes(symbol)) {
1035
- result[currentSection]?.push(symbol);
1036
- }
1037
- }
1038
- }
1039
- if (trimmed && !line.startsWith(" ") && !trimmed.endsWith(":")) {
1040
- currentSection = "";
1041
- }
1042
- }
1043
- }
1044
- function scanRoutes(projectDir, result) {
1045
- const routeDirs = ["routes", "src/routes", "api", "src/api"];
1046
- for (const dir of routeDirs) {
1047
- const fullPath = path2.join(projectDir, dir);
1048
- if (!fs2.existsSync(fullPath)) continue;
1049
- const files = safeReaddir(fullPath);
1050
- for (const file of files) {
1051
- const ext = path2.extname(file);
1052
- if (!CODE_EXTENSIONS.has(ext)) continue;
1053
- const name = path2.basename(file, ext);
1054
- if (name === "index") continue;
1055
- const routePrefix = `/api/${toKebabCase(name)}`;
1056
- const component = `#${toKebabCase(name)}`;
1057
- result.routes[routePrefix] = component;
1058
- }
1059
- }
1060
- }
1061
- function toKebabCase(str) {
1062
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").replace(/\..*$/, "").toLowerCase();
1063
- }
1064
- function safeReaddir(dir) {
1065
- try {
1066
- return fs2.readdirSync(dir).filter((f) => {
1067
- const fullPath = path2.join(dir, f);
1068
- try {
1069
- return fs2.statSync(fullPath).isFile();
1070
- } catch {
1071
- return false;
1072
- }
1073
- });
1074
- } catch {
1075
- return [];
1076
- }
1077
- }
1078
- function findFiles(dir, filename, maxDepth = 4, depth = 0) {
1079
- if (depth > maxDepth) return [];
1080
- const results = [];
1081
- const skipDirs = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".next", ".nuxt"]);
1082
- try {
1083
- const entries = fs2.readdirSync(dir, { withFileTypes: true });
1084
- for (const entry of entries) {
1085
- if (entry.isFile() && entry.name === filename) {
1086
- results.push(path2.join(dir, entry.name));
1087
- } else if (entry.isDirectory() && !skipDirs.has(entry.name)) {
1088
- results.push(...findFiles(path2.join(dir, entry.name), filename, maxDepth, depth + 1));
1089
- }
1090
- }
1091
- } catch {
1092
- }
1093
- return results;
1094
- }
1095
- var DEFAULT_SIMILARITY_THRESHOLD = 0.6;
1096
- var DECAY_HALF_LIFE_DAYS = 14;
1097
- var IncidentGrouper = class {
1098
- constructor(storage, config) {
1099
- this.storage = storage;
1100
- this.similarityThreshold = config?.similarityThreshold ?? DEFAULT_SIMILARITY_THRESHOLD;
1101
- this.decayHalfLifeDays = config?.decayHalfLifeDays ?? DECAY_HALF_LIFE_DAYS;
1102
- this.useStackFingerprint = config?.useStackFingerprint ?? true;
1103
- }
1104
- similarityThreshold;
1105
- decayHalfLifeDays;
1106
- useStackFingerprint;
1107
- /**
1108
- * Try to find or create a group for an incident
1109
- * Returns the group ID if grouped, null if no suitable group
1110
- */
1111
- group(incident) {
1112
- const groups = this.storage.getGroups({ limit: 100 });
1113
- for (const group of groups) {
1114
- if (this.shouldJoinGroup(incident, group)) {
1115
- this.storage.addToGroup(group.id, incident.id);
1116
- return group.id;
1117
- }
1118
- }
1119
- const similar = this.findSimilar(incident, 10);
1120
- if (similar.length >= 1) {
1121
- const commonSymbols = this.extractCommonSymbols([incident, ...similar]);
1122
- const commonErrorPatterns = this.extractCommonErrorPatterns([
1123
- incident,
1124
- ...similar
1125
- ]);
1126
- const groupId = this.storage.createGroup({
1127
- incidents: [incident.id, ...similar.map((i) => i.id)],
1128
- commonSymbols,
1129
- commonErrorPatterns,
1130
- firstSeen: this.getEarliestTimestamp([incident, ...similar]),
1131
- lastSeen: incident.timestamp,
1132
- environments: this.getUniqueEnvironments([incident, ...similar])
1133
- });
1134
- return groupId;
1135
- }
1136
- return null;
1137
- }
1138
- /**
1139
- * Find incidents similar to the given one
1140
- */
1141
- findSimilar(incident, limit = 10) {
1142
- const candidates = this.storage.getRecentIncidents({
1143
- limit: 500,
1144
- status: "all"
1145
- });
1146
- const similar = [];
1147
- for (const candidate of candidates) {
1148
- if (candidate.id === incident.id) {
1149
- continue;
1150
- }
1151
- const score = this.calculateSimilarity(incident, candidate);
1152
- if (score >= this.similarityThreshold) {
1153
- similar.push({ incident: candidate, score });
1154
- }
1155
- }
1156
- return similar.sort((a, b) => b.score - a.score).slice(0, limit).map((s) => s.incident);
1157
- }
1158
- /**
1159
- * Analyze ungrouped incidents and create groups automatically
1160
- */
1161
- analyzeAndGroup(options = {}) {
1162
- const minSize = options.minSize || 3;
1163
- const ungrouped = this.storage.getRecentIncidents({
1164
- limit: 1e3
1165
- }).filter((i) => !i.groupId);
1166
- const newGroups = [];
1167
- const processed = /* @__PURE__ */ new Set();
1168
- for (const incident of ungrouped) {
1169
- if (processed.has(incident.id)) {
1170
- continue;
1171
- }
1172
- const similar = ungrouped.filter(
1173
- (other) => other.id !== incident.id && !processed.has(other.id) && this.calculateSimilarity(incident, other) >= this.similarityThreshold
1174
- );
1175
- if (similar.length + 1 >= minSize) {
1176
- const members = [incident, ...similar];
1177
- const commonSymbols = this.extractCommonSymbols(members);
1178
- const commonErrorPatterns = this.extractCommonErrorPatterns(members);
1179
- const groupId = this.storage.createGroup({
1180
- incidents: members.map((m) => m.id),
1181
- commonSymbols,
1182
- commonErrorPatterns,
1183
- firstSeen: this.getEarliestTimestamp(members),
1184
- lastSeen: this.getLatestTimestamp(members),
1185
- environments: this.getUniqueEnvironments(members)
1186
- });
1187
- for (const m of members) {
1188
- processed.add(m.id);
1189
- }
1190
- const group = this.storage.getGroup(groupId);
1191
- if (group) {
1192
- newGroups.push(group);
1193
- }
1194
- }
1195
- }
1196
- return newGroups;
1197
- }
1198
- /**
1199
- * Calculate similarity between two incidents (0-1)
1200
- * Applies time-decay so older incidents contribute less, and optionally
1201
- * uses stack trace fingerprinting for more accurate grouping.
1202
- */
1203
- calculateSimilarity(a, b) {
1204
- let score = 0;
1205
- let maxScore = 0;
1206
- const hasStacks = this.useStackFingerprint && a.error.stack && b.error.stack;
1207
- const symbolWeight = hasStacks ? 0.45 : 0.6;
1208
- const errorWeight = hasStacks ? 0.25 : 0.3;
1209
- const envWeight = 0.1;
1210
- const stackWeight = hasStacks ? 0.2 : 0;
1211
- const symbolTypes = [
1212
- "feature",
1213
- "component",
1214
- "flow",
1215
- "gate",
1216
- "signal",
1217
- "state",
1218
- "integration"
1219
- ];
1220
- for (const type of symbolTypes) {
1221
- const aValue = a.symbols[type];
1222
- const bValue = b.symbols[type];
1223
- if (aValue || bValue) {
1224
- maxScore += symbolWeight / symbolTypes.length;
1225
- if (aValue === bValue) {
1226
- score += symbolWeight / symbolTypes.length;
1227
- }
1228
- }
1229
- }
1230
- const errorSimilarity = this.stringSimilarity(
1231
- a.error.message,
1232
- b.error.message
1233
- );
1234
- score += errorWeight * errorSimilarity;
1235
- maxScore += errorWeight;
1236
- if (a.environment === b.environment) {
1237
- score += envWeight;
1238
- }
1239
- maxScore += envWeight;
1240
- if (hasStacks) {
1241
- const aFingerprint = this.fingerprintStack(a.error.stack);
1242
- const bFingerprint = this.fingerprintStack(b.error.stack);
1243
- const stackSimilarity = this.compareFingerprints(aFingerprint, bFingerprint);
1244
- score += stackWeight * stackSimilarity;
1245
- maxScore += stackWeight;
1246
- }
1247
- const rawScore = maxScore > 0 ? score / maxScore : 0;
1248
- const timeDelta = Math.abs(
1249
- new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
1250
- );
1251
- const daysDelta = timeDelta / (1e3 * 60 * 60 * 24);
1252
- const decayFactor = Math.pow(0.5, daysDelta / this.decayHalfLifeDays);
1253
- return rawScore * decayFactor;
1254
- }
1255
- /**
1256
- * Extract a fingerprint from a stack trace by normalizing frames.
1257
- * Strips line numbers, column numbers, and absolute paths to capture
1258
- * the structural signature of the call stack.
1259
- */
1260
- fingerprintStack(stack) {
1261
- return stack.split("\n").filter((line) => line.trim().startsWith("at ")).slice(0, 10).map((frame) => {
1262
- return frame.trim().replace(/:\d+:\d+\)?$/, "").replace(/\(.*[/\\]/, "(").replace(/^\s*at\s+/, "");
1263
- });
1264
- }
1265
- /**
1266
- * Compare two stack fingerprints (0-1 similarity)
1267
- */
1268
- compareFingerprints(a, b) {
1269
- if (a.length === 0 && b.length === 0) return 1;
1270
- if (a.length === 0 || b.length === 0) return 0;
1271
- let matches = 0;
1272
- const maxLen = Math.max(a.length, b.length);
1273
- for (let i = 0; i < Math.min(a.length, b.length); i++) {
1274
- if (a[i] === b[i]) {
1275
- matches++;
1276
- }
1277
- }
1278
- return matches / maxLen;
1279
- }
1280
- /**
1281
- * Calculate string similarity using Levenshtein distance
1282
- */
1283
- stringSimilarity(a, b) {
1284
- const maxLen = Math.max(a.length, b.length);
1285
- if (maxLen === 0) return 1;
1286
- const distance = this.levenshteinDistance(
1287
- a.toLowerCase(),
1288
- b.toLowerCase()
1289
- );
1290
- return 1 - distance / maxLen;
1291
- }
1292
- /**
1293
- * Levenshtein distance for string comparison
1294
- */
1295
- levenshteinDistance(a, b) {
1296
- if (a.length === 0) return b.length;
1297
- if (b.length === 0) return a.length;
1298
- const matrix = [];
1299
- for (let i = 0; i <= b.length; i++) {
1300
- matrix[i] = [i];
1301
- }
1302
- for (let j = 0; j <= a.length; j++) {
1303
- matrix[0][j] = j;
1304
- }
1305
- for (let i = 1; i <= b.length; i++) {
1306
- for (let j = 1; j <= a.length; j++) {
1307
- const cost = a[j - 1] === b[i - 1] ? 0 : 1;
1308
- matrix[i][j] = Math.min(
1309
- matrix[i - 1][j] + 1,
1310
- matrix[i][j - 1] + 1,
1311
- matrix[i - 1][j - 1] + cost
1312
- );
1313
- }
1314
- }
1315
- return matrix[b.length][a.length];
1316
- }
1317
- /**
1318
- * Check if incident should join existing group
1319
- */
1320
- shouldJoinGroup(incident, group) {
1321
- let matchCount = 0;
1322
- let totalCommon = 0;
1323
- for (const [key, value] of Object.entries(group.commonSymbols)) {
1324
- if (value) {
1325
- totalCommon++;
1326
- const incidentValue = incident.symbols[key];
1327
- if (incidentValue === value) {
1328
- matchCount++;
1329
- }
1330
- }
1331
- }
1332
- if (totalCommon === 0) {
1333
- return false;
1334
- }
1335
- const symbolMatch = matchCount / totalCommon;
1336
- const errorLower = incident.error.message.toLowerCase();
1337
- const errorMatch = group.commonErrorPatterns.some(
1338
- (pattern) => errorLower.includes(pattern.toLowerCase())
1339
- );
1340
- return symbolMatch >= 0.5 || errorMatch;
1341
- }
1342
- /**
1343
- * Extract symbols common to all incidents
1344
- */
1345
- extractCommonSymbols(incidents) {
1346
- if (incidents.length === 0) return {};
1347
- const first = incidents[0].symbols;
1348
- const common = {};
1349
- for (const [key, value] of Object.entries(first)) {
1350
- if (!value) continue;
1351
- const allMatch = incidents.every(
1352
- (i) => i.symbols[key] === value
1353
- );
1354
- if (allMatch) {
1355
- common[key] = value;
1356
- }
1357
- }
1358
- return common;
1359
- }
1360
- /**
1361
- * Extract common error patterns from incidents
1362
- */
1363
- extractCommonErrorPatterns(incidents) {
1364
- if (incidents.length === 0) return [];
1365
- const wordCounts = /* @__PURE__ */ new Map();
1366
- const stopWords = /* @__PURE__ */ new Set([
1367
- "the",
1368
- "a",
1369
- "an",
1370
- "is",
1371
- "are",
1372
- "was",
1373
- "were",
1374
- "in",
1375
- "on",
1376
- "at",
1377
- "to",
1378
- "for",
1379
- "of",
1380
- "with",
1381
- "error",
1382
- "failed",
1383
- "cannot"
1384
- ]);
1385
- for (const incident of incidents) {
1386
- const words = incident.error.message.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !stopWords.has(w));
1387
- const uniqueWords = new Set(words);
1388
- for (const word of uniqueWords) {
1389
- wordCounts.set(word, (wordCounts.get(word) || 0) + 1);
1390
- }
1391
- }
1392
- const threshold = Math.ceil(incidents.length * 0.6);
1393
- const commonPatterns = Array.from(wordCounts.entries()).filter(([, count]) => count >= threshold).map(([word]) => word).slice(0, 5);
1394
- return commonPatterns;
1395
- }
1396
- getEarliestTimestamp(incidents) {
1397
- return incidents.reduce(
1398
- (earliest, i) => i.timestamp < earliest ? i.timestamp : earliest,
1399
- incidents[0].timestamp
1400
- );
1401
- }
1402
- getLatestTimestamp(incidents) {
1403
- return incidents.reduce(
1404
- (latest, i) => i.timestamp > latest ? i.timestamp : latest,
1405
- incidents[0].timestamp
1406
- );
1407
- }
1408
- getUniqueEnvironments(incidents) {
1409
- return [...new Set(incidents.map((i) => i.environment))];
1410
- }
1411
- };
1412
- var TimelineBuilder = class {
1413
- /**
1414
- * Build a timeline from an incident with flow position
1415
- */
1416
- build(incident) {
1417
- if (!incident.flowPosition) {
1418
- return null;
1419
- }
1420
- const events = [];
1421
- const baseTime = new Date(incident.timestamp).getTime();
1422
- events.push({
1423
- timestamp: new Date(baseTime - 5e3).toISOString(),
1424
- symbol: incident.flowPosition.flowId,
1425
- type: "flow-started"
1426
- });
1427
- let eventOffset = 1e3;
1428
- for (const signal of incident.flowPosition.actual) {
1429
- const type = this.inferEventType(signal);
1430
- events.push({
1431
- timestamp: new Date(baseTime - 4e3 + eventOffset).toISOString(),
1432
- symbol: signal,
1433
- type
1434
- });
1435
- eventOffset += Math.random() * 1e3 + 500;
1436
- }
1437
- const failedSymbol = incident.flowPosition.failedAt || incident.flowPosition.missing[0] || incident.symbols.gate || incident.symbols.signal || "unknown";
1438
- events.push({
1439
- timestamp: incident.timestamp,
1440
- symbol: failedSymbol,
1441
- type: "error",
1442
- data: {
1443
- message: incident.error.message,
1444
- missing: incident.flowPosition.missing
1445
- }
1446
- });
1447
- return {
1448
- incidentId: incident.id,
1449
- flowId: incident.flowPosition.flowId,
1450
- events,
1451
- failure: {
1452
- at: incident.timestamp,
1453
- symbol: failedSymbol,
1454
- reason: incident.error.message
1455
- }
1456
- };
1457
- }
1458
- /**
1459
- * Render timeline as ASCII art
1460
- */
1461
- renderAscii(timeline) {
1462
- const lines = [];
1463
- lines.push(`${timeline.flowId} Timeline`);
1464
- lines.push("\u2550".repeat(40));
1465
- lines.push("");
1466
- for (const event of timeline.events) {
1467
- const time = this.formatTime(event.timestamp);
1468
- const icon = this.getEventIcon(event.type);
1469
- const status = this.getEventStatus(event.type);
1470
- let line = `${time} ${icon} ${event.symbol}`;
1471
- if (status) {
1472
- line += ` (${status})`;
1473
- }
1474
- lines.push(line);
1475
- if (event.type === "error" && event.data) {
1476
- lines.push(` \u2514\u2500 ${event.data.message}`);
1477
- if (event.data.missing && Array.isArray(event.data.missing) && event.data.missing.length > 0) {
1478
- lines.push(
1479
- ` \u2514\u2500 Expected: ${event.data.missing.join(", ")}`
1480
- );
1481
- }
1482
- }
1483
- }
1484
- const missing = timeline.events.find((e) => e.type === "error")?.data?.missing;
1485
- if (missing && missing.length > 0) {
1486
- lines.push("");
1487
- lines.push(`Missing signals: ${missing.join(", ")}`);
1488
- }
1489
- return lines.join("\n");
1490
- }
1491
- /**
1492
- * Render timeline as structured data (for MCP/JSON output)
1493
- */
1494
- renderStructured(timeline) {
1495
- return {
1496
- incidentId: timeline.incidentId,
1497
- flow: {
1498
- id: timeline.flowId,
1499
- eventCount: timeline.events.length
1500
- },
1501
- events: timeline.events.map((event) => ({
1502
- time: this.formatTime(event.timestamp),
1503
- symbol: event.symbol,
1504
- type: event.type,
1505
- status: this.getEventStatus(event.type),
1506
- data: event.data
1507
- })),
1508
- failure: {
1509
- at: this.formatTime(timeline.failure.at),
1510
- symbol: timeline.failure.symbol,
1511
- reason: timeline.failure.reason
1512
- }
1513
- };
1514
- }
1515
- /**
1516
- * Infer event type from symbol prefix
1517
- */
1518
- inferEventType(symbol) {
1519
- if (symbol.startsWith("^")) {
1520
- return "gate-passed";
1521
- }
1522
- if (symbol.startsWith("!")) {
1523
- return "signal-emitted";
1524
- }
1525
- if (symbol.startsWith("%")) {
1526
- return "state-changed";
1527
- }
1528
- return "signal-emitted";
1529
- }
1530
- /**
1531
- * Get icon for event type
1532
- */
1533
- getEventIcon(type) {
1534
- switch (type) {
1535
- case "flow-started":
1536
- return "\u25B6";
1537
- case "flow-ended":
1538
- return "\u25A0";
1539
- case "gate-passed":
1540
- return "\u2713";
1541
- case "gate-failed":
1542
- return "\u2717";
1543
- case "signal-emitted":
1544
- return "\u26A1";
1545
- case "state-changed":
1546
- return "\u25C6";
1547
- case "error":
1548
- return "\u2717";
1549
- default:
1550
- return "\u2022";
1551
- }
1552
- }
1553
- /**
1554
- * Get status text for event type
1555
- */
1556
- getEventStatus(type) {
1557
- switch (type) {
1558
- case "gate-passed":
1559
- return "PASSED";
1560
- case "gate-failed":
1561
- return "FAILED";
1562
- case "signal-emitted":
1563
- return "EMITTED";
1564
- case "state-changed":
1565
- return "CHANGED";
1566
- case "error":
1567
- return "ERROR";
1568
- default:
1569
- return "";
1570
- }
1571
- }
1572
- /**
1573
- * Format timestamp for display
1574
- */
1575
- formatTime(timestamp) {
1576
- const date = new Date(timestamp);
1577
- const hours = String(date.getHours()).padStart(2, "0");
1578
- const minutes = String(date.getMinutes()).padStart(2, "0");
1579
- const seconds = String(date.getSeconds()).padStart(2, "0");
1580
- const millis = String(date.getMilliseconds()).padStart(3, "0");
1581
- return `${hours}:${minutes}:${seconds}.${millis}`;
1582
- }
1583
- };
1584
- var StatsCalculator = class {
1585
- constructor(storage) {
1586
- this.storage = storage;
1587
- }
1588
- /**
1589
- * Get comprehensive statistics for a time period
1590
- */
1591
- getStats(periodDays = 7) {
1592
- const end = (/* @__PURE__ */ new Date()).toISOString();
1593
- const start = new Date(
1594
- Date.now() - periodDays * 24 * 60 * 60 * 1e3
1595
- ).toISOString();
1596
- return this.storage.getStats({ start, end });
1597
- }
1598
- /**
1599
- * Get health metrics for a specific symbol
1600
- */
1601
- getSymbolHealth(symbol) {
1602
- return this.storage.getSymbolHealth(symbol);
1603
- }
1604
- /**
1605
- * Get trending issues (symbols with increasing incident rates)
1606
- */
1607
- getTrendingIssues(days = 7) {
1608
- const now = Date.now();
1609
- const halfPeriod = days * 24 * 60 * 60 * 1e3 / 2;
1610
- const firstHalfStart = new Date(now - days * 24 * 60 * 60 * 1e3).toISOString();
1611
- const midpoint = new Date(now - halfPeriod).toISOString();
1612
- const secondHalfEnd = new Date(now).toISOString();
1613
- const firstHalfIncidents = this.storage.getRecentIncidents({
1614
- dateFrom: firstHalfStart,
1615
- dateTo: midpoint,
1616
- limit: 1e3
1617
- });
1618
- const secondHalfIncidents = this.storage.getRecentIncidents({
1619
- dateFrom: midpoint,
1620
- dateTo: secondHalfEnd,
1621
- limit: 1e3
1622
- });
1623
- const firstHalfCounts = this.countSymbols(firstHalfIncidents);
1624
- const secondHalfCounts = this.countSymbols(secondHalfIncidents);
1625
- const trends = [];
1626
- const allSymbols = /* @__PURE__ */ new Set([
1627
- ...firstHalfCounts.keys(),
1628
- ...secondHalfCounts.keys()
1629
- ]);
1630
- for (const symbol of allSymbols) {
1631
- const first = firstHalfCounts.get(symbol) || 0;
1632
- const second = secondHalfCounts.get(symbol) || 0;
1633
- if (first === 0 && second > 0) {
1634
- trends.push({ symbol, trend: second * 100 });
1635
- } else if (first > 0) {
1636
- const change = (second - first) / first * 100;
1637
- trends.push({ symbol, trend: change });
1638
- }
1639
- }
1640
- return trends.filter((t) => t.trend > 0).sort((a, b) => b.trend - a.trend).slice(0, 10);
1641
- }
1642
- /**
1643
- * Get resolution metrics
1644
- */
1645
- getResolutionMetrics() {
1646
- const stats = this.getStats(30);
1647
- return {
1648
- avgTimeToResolve: stats.resolution.avgTimeToResolve,
1649
- resolvedWithPattern: stats.resolution.resolvedWithPattern,
1650
- resolvedManually: stats.resolution.resolvedManually,
1651
- totalResolved: stats.incidents.resolved,
1652
- resolutionRate: stats.resolution.resolutionRate
1653
- };
1654
- }
1655
- /**
1656
- * Get pattern effectiveness metrics
1657
- */
1658
- getPatternEffectiveness() {
1659
- const patterns = this.storage.getAllPatterns({ includePrivate: true });
1660
- return patterns.filter((p) => p.confidence.timesMatched > 0).map((p) => ({
1661
- patternId: p.id,
1662
- name: p.name,
1663
- matches: p.confidence.timesMatched,
1664
- resolutions: p.confidence.timesResolved,
1665
- recurrences: p.confidence.timesRecurred,
1666
- effectiveness: p.confidence.timesMatched > 0 ? Math.round(
1667
- (p.confidence.timesResolved - p.confidence.timesRecurred) / p.confidence.timesMatched * 100
1668
- ) : 0
1669
- })).sort((a, b) => b.effectiveness - a.effectiveness);
1670
- }
1671
- /**
1672
- * Get incident rate by hour of day
1673
- */
1674
- getIncidentsByHour(days = 7) {
1675
- const start = new Date(
1676
- Date.now() - days * 24 * 60 * 60 * 1e3
1677
- ).toISOString();
1678
- const incidents = this.storage.getRecentIncidents({
1679
- dateFrom: start,
1680
- limit: 1e4
1681
- });
1682
- const hourCounts = /* @__PURE__ */ new Map();
1683
- for (let i = 0; i < 24; i++) {
1684
- hourCounts.set(i, 0);
1685
- }
1686
- for (const incident of incidents) {
1687
- const hour = new Date(incident.timestamp).getHours();
1688
- hourCounts.set(hour, (hourCounts.get(hour) || 0) + 1);
1689
- }
1690
- return Array.from(hourCounts.entries()).map(([hour, count]) => ({
1691
- hour,
1692
- count
1693
- }));
1694
- }
1695
- /**
1696
- * Get incident rate by environment
1697
- */
1698
- getIncidentsByEnvironment() {
1699
- const stats = this.getStats(30);
1700
- const total = stats.incidents.total;
1701
- return Object.entries(stats.incidents.byEnvironment).map(([environment, count]) => ({
1702
- environment,
1703
- count,
1704
- percentage: total > 0 ? Math.round(count / total * 100) : 0
1705
- })).sort((a, b) => b.count - a.count);
1706
- }
1707
- /**
1708
- * Get symbol correlation matrix (which symbols fail together)
1709
- */
1710
- getSymbolCorrelation() {
1711
- const incidents = this.storage.getRecentIncidents({ limit: 1e3 });
1712
- const correlations = /* @__PURE__ */ new Map();
1713
- const symbolCounts = /* @__PURE__ */ new Map();
1714
- for (const incident of incidents) {
1715
- const symbols = this.getSymbolsFromIncident(incident);
1716
- for (const symbol of symbols) {
1717
- symbolCounts.set(symbol, (symbolCounts.get(symbol) || 0) + 1);
1718
- }
1719
- for (let i = 0; i < symbols.length; i++) {
1720
- for (let j = i + 1; j < symbols.length; j++) {
1721
- const key = [symbols[i], symbols[j]].sort().join("|");
1722
- correlations.set(key, (correlations.get(key) || 0) + 1);
1723
- }
1724
- }
1725
- }
1726
- const results = [];
1727
- for (const [key, count] of correlations) {
1728
- const [symbol1, symbol2] = key.split("|");
1729
- const count1 = symbolCounts.get(symbol1) || 1;
1730
- const count2 = symbolCounts.get(symbol2) || 1;
1731
- const correlation = count / Math.max(count1, count2);
1732
- if (correlation > 0.3) {
1733
- results.push({
1734
- symbol1,
1735
- symbol2,
1736
- correlation: Math.round(correlation * 100) / 100
1737
- });
1738
- }
1739
- }
1740
- return results.sort((a, b) => b.correlation - a.correlation).slice(0, 20);
1741
- }
1742
- /**
1743
- * Generate a summary dashboard string
1744
- */
1745
- generateDashboard(periodDays = 7) {
1746
- const stats = this.getStats(periodDays);
1747
- const lines = [];
1748
- lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
1749
- lines.push("\u2551 PARADIGM SENTINEL DASHBOARD \u2551");
1750
- lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
1751
- const todayCount = stats.incidents.byDay[stats.incidents.byDay.length - 1]?.count || 0;
1752
- lines.push(
1753
- `\u2551 Open: ${String(stats.incidents.open).padEnd(4)} \u2502 Investigating: ${String(stats.incidents.total - stats.incidents.open - stats.incidents.resolved).padEnd(3)} \u2502 Resolved: ${String(stats.incidents.resolved).padEnd(4)} \u2502 Today: +${todayCount} \u2551`
1754
- );
1755
- lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
1756
- lines.push("");
1757
- lines.push("Incidents by Day (last 7 days):");
1758
- lines.push("\u2500".repeat(50));
1759
- const maxDayCount = Math.max(...stats.incidents.byDay.map((d) => d.count), 1);
1760
- for (const day of stats.incidents.byDay.slice(-7)) {
1761
- const barLength = Math.round(day.count / maxDayCount * 30);
1762
- const bar = "\u2588".repeat(barLength);
1763
- lines.push(`${day.date.substring(5)} ${bar} ${day.count}`);
1764
- }
1765
- lines.push("");
1766
- lines.push("Most Affected Symbols:");
1767
- lines.push("\u2500".repeat(50));
1768
- for (const { symbol, count } of stats.symbols.mostIncidents.slice(0, 5)) {
1769
- lines.push(` ${symbol.padEnd(25)} ${count} incidents`);
1770
- }
1771
- lines.push("");
1772
- lines.push("Top Patterns:");
1773
- lines.push("\u2500".repeat(50));
1774
- for (const { patternId, resolvedCount } of stats.patterns.mostEffective.slice(0, 5)) {
1775
- lines.push(` ${patternId.padEnd(25)} ${resolvedCount} resolved`);
1776
- }
1777
- lines.push("");
1778
- lines.push("Resolution Stats:");
1779
- lines.push("\u2500".repeat(50));
1780
- lines.push(` Resolution rate: ${Math.round(stats.resolution.resolutionRate)}%`);
1781
- lines.push(` With pattern: ${stats.resolution.resolvedWithPattern}`);
1782
- lines.push(` Manual: ${stats.resolution.resolvedManually}`);
1783
- return lines.join("\n");
1784
- }
1785
- /**
1786
- * Helper: Count symbols across incidents
1787
- */
1788
- countSymbols(incidents) {
1789
- const counts = /* @__PURE__ */ new Map();
1790
- for (const incident of incidents) {
1791
- for (const [, value] of Object.entries(incident.symbols)) {
1792
- if (value) {
1793
- counts.set(value, (counts.get(value) || 0) + 1);
1794
- }
1795
- }
1796
- }
1797
- return counts;
1798
- }
1799
- /**
1800
- * Helper: Get all symbols from incident
1801
- */
1802
- getSymbolsFromIncident(incident) {
1803
- const symbols = [];
1804
- for (const [, value] of Object.entries(incident.symbols)) {
1805
- if (value) {
1806
- symbols.push(value);
1807
- }
1808
- }
1809
- return symbols;
1810
- }
1811
- };
1812
- var ContextEnricher = class {
1813
- constructor(projectRoot = process.cwd()) {
1814
- this.projectRoot = projectRoot;
1815
- }
1816
- symbolCache = /* @__PURE__ */ new Map();
1817
- purposeCache = /* @__PURE__ */ new Map();
1818
- /**
1819
- * Enrich an incident with symbol context
1820
- */
1821
- enrich(incident) {
1822
- const symbolEnrichments = {};
1823
- for (const [, value] of Object.entries(incident.symbols)) {
1824
- if (value) {
1825
- const enrichment = this.getSymbolContext(value);
1826
- if (enrichment && Object.keys(enrichment).length > 0) {
1827
- symbolEnrichments[value] = enrichment;
1828
- }
1829
- }
1830
- }
1831
- let flowDescription;
1832
- if (incident.symbols.flow) {
1833
- const flowContext = this.getSymbolContext(incident.symbols.flow);
1834
- flowDescription = flowContext?.description;
1835
- }
1836
- return {
1837
- ...incident,
1838
- enriched: {
1839
- symbols: symbolEnrichments,
1840
- flowDescription
1841
- }
1842
- };
1843
- }
1844
- /**
1845
- * Get symbol metadata from index or .purpose files
1846
- */
1847
- getSymbolContext(symbol) {
1848
- const cached = this.symbolCache.get(symbol);
1849
- if (cached) {
1850
- return cached;
1851
- }
1852
- const enrichment = {};
1853
- const indexEntry = this.findInSymbolIndex(symbol);
1854
- if (indexEntry) {
1855
- enrichment.description = indexEntry.description;
1856
- enrichment.definedIn = indexEntry.file;
1857
- enrichment.references = indexEntry.references;
1858
- enrichment.referencedBy = indexEntry.referencedBy;
1859
- }
1860
- const purposeEntry = this.findInPurposeFiles(symbol);
1861
- if (purposeEntry) {
1862
- if (!enrichment.description && purposeEntry.description) {
1863
- enrichment.description = purposeEntry.description;
1864
- }
1865
- if (purposeEntry.references) {
1866
- enrichment.references = [
1867
- .../* @__PURE__ */ new Set([...enrichment.references || [], ...purposeEntry.references])
1868
- ];
1869
- }
1870
- if (purposeEntry.referencedBy) {
1871
- enrichment.referencedBy = [
1872
- .../* @__PURE__ */ new Set([...enrichment.referencedBy || [], ...purposeEntry.referencedBy])
1873
- ];
1874
- }
1875
- }
1876
- this.symbolCache.set(symbol, enrichment);
1877
- return enrichment;
1878
- }
1879
- /**
1880
- * Find symbol in premise index
1881
- */
1882
- findInSymbolIndex(symbol) {
1883
- const indexPath = path3.join(this.projectRoot, ".paradigm", "index.json");
1884
- if (!fs3.existsSync(indexPath)) {
1885
- return null;
1886
- }
1887
- try {
1888
- const indexContent = fs3.readFileSync(indexPath, "utf-8");
1889
- const index = JSON.parse(indexContent);
1890
- if (index.symbols && Array.isArray(index.symbols)) {
1891
- return index.symbols.find(
1892
- (s) => s.id === symbol
1893
- ) || null;
1894
- }
1895
- return null;
1896
- } catch {
1897
- return null;
1898
- }
1899
- }
1900
- /**
1901
- * Find symbol in .purpose files
1902
- */
1903
- findInPurposeFiles(symbol) {
1904
- const searchPaths = this.getSearchPathsForSymbol(symbol);
1905
- for (const searchPath of searchPaths) {
1906
- const fullPath = path3.join(this.projectRoot, searchPath);
1907
- if (!fs3.existsSync(fullPath)) {
1908
- continue;
1909
- }
1910
- const cached = this.purposeCache.get(fullPath);
1911
- if (cached) {
1912
- if (cached.symbol === symbol) {
1913
- return cached;
1914
- }
1915
- continue;
1916
- }
1917
- try {
1918
- const content = fs3.readFileSync(fullPath, "utf-8");
1919
- const purpose = this.parsePurposeFile(content);
1920
- this.purposeCache.set(fullPath, purpose);
1921
- if (purpose.symbol === symbol) {
1922
- return purpose;
1923
- }
1924
- } catch {
1925
- continue;
1926
- }
1927
- }
1928
- return null;
1929
- }
1930
- /**
1931
- * Get potential file paths for a symbol
1932
- */
1933
- getSearchPathsForSymbol(symbol) {
1934
- const paths = [];
1935
- const cleanSymbol = symbol.replace(/^[@#$%^!&~?]/, "");
1936
- const prefixDirs = {
1937
- "@": ["features", "src/features"],
1938
- "#": ["components", "src/components"],
1939
- "$": ["flows", "src/flows"],
1940
- "^": ["middleware", "gates", "src/middleware"],
1941
- "!": ["signals", "events", "src/signals"],
1942
- "%": ["state", "store", "src/state"],
1943
- "&": ["integrations", "services", "src/integrations"]
1944
- };
1945
- const prefix = symbol[0];
1946
- const dirs = prefixDirs[prefix] || [];
1947
- for (const dir of dirs) {
1948
- paths.push(path3.join(dir, cleanSymbol, ".purpose"));
1949
- paths.push(path3.join(dir, `${cleanSymbol}.purpose`));
1950
- }
1951
- paths.push(path3.join(".paradigm", "purposes", `${cleanSymbol}.yaml`));
1952
- paths.push(path3.join(".paradigm", "purposes", `${cleanSymbol}.json`));
1953
- return paths;
1954
- }
1955
- /**
1956
- * Parse a .purpose file
1957
- */
1958
- parsePurposeFile(content) {
1959
- const result = {};
1960
- const lines = content.split("\n");
1961
- for (const line of lines) {
1962
- const trimmed = line.trim();
1963
- if (trimmed.startsWith("symbol:")) {
1964
- result.symbol = trimmed.substring(7).trim();
1965
- } else if (trimmed.startsWith("description:")) {
1966
- result.description = trimmed.substring(12).trim();
1967
- } else if (trimmed.startsWith("purpose:")) {
1968
- result.description = trimmed.substring(8).trim();
1969
- }
1970
- }
1971
- if (!result.description) {
1972
- const firstLine = lines.find((l) => l.trim() && !l.startsWith("#"));
1973
- if (firstLine) {
1974
- result.description = firstLine.trim();
1975
- }
1976
- }
1977
- return result;
1978
- }
1979
- /**
1980
- * Clear caches
1981
- */
1982
- clearCache() {
1983
- this.symbolCache.clear();
1984
- this.purposeCache.clear();
1985
- }
1986
- /**
1987
- * Batch enrich multiple incidents
1988
- */
1989
- enrichBatch(incidents) {
1990
- return incidents.map((i) => this.enrich(i));
1991
- }
1992
- };
1993
- var PatternSuggester = class {
1994
- constructor(storage) {
1995
- this.storage = storage;
1996
- }
1997
- /**
1998
- * Suggest a pattern from a resolved incident
1999
- */
2000
- suggestFromIncident(incident) {
2001
- const baseId = this.generatePatternId(incident);
2002
- const symbols = this.buildSymbolCriteria(incident.symbols);
2003
- const errorKeywords = this.extractErrorKeywords(incident.error.message);
2004
- const pattern = {
2005
- id: baseId,
2006
- name: this.generatePatternName(incident),
2007
- description: `Auto-suggested pattern from incident ${incident.id}`,
2008
- pattern: {
2009
- symbols,
2010
- errorContains: errorKeywords.length > 0 ? errorKeywords : void 0,
2011
- missingSignals: incident.flowPosition?.missing
2012
- },
2013
- resolution: {
2014
- description: incident.resolution?.notes || "Resolution approach TBD",
2015
- strategy: this.inferStrategy([incident]),
2016
- priority: "medium"
2017
- },
2018
- source: "suggested",
2019
- private: false,
2020
- tags: this.generateTags(incident)
2021
- };
2022
- return pattern;
2023
- }
2024
- /**
2025
- * Suggest a pattern from an incident group
2026
- */
2027
- suggestFromGroup(group) {
2028
- const baseId = `group-${group.id.toLowerCase().replace(/[^a-z0-9]/g, "-")}`;
2029
- const symbols = this.buildSymbolCriteria(group.commonSymbols);
2030
- const groupIncidents = group.incidents.slice(0, 20).map((id) => this.storage.getIncident(id)).filter((i) => i != null);
2031
- const pattern = {
2032
- id: baseId,
2033
- name: group.name || `Pattern from group ${group.id}`,
2034
- description: `Auto-suggested pattern from incident group with ${group.count} incidents`,
2035
- pattern: {
2036
- symbols,
2037
- errorContains: group.commonErrorPatterns.length > 0 ? group.commonErrorPatterns : void 0
2038
- },
2039
- resolution: {
2040
- description: "Resolution approach TBD based on grouped incidents",
2041
- strategy: groupIncidents.length > 0 ? this.inferStrategy(groupIncidents) : "fix-code",
2042
- priority: this.getPriorityFromCount(group.count)
2043
- },
2044
- source: "suggested",
2045
- private: false,
2046
- tags: this.generateTagsFromGroup(group)
2047
- };
2048
- return pattern;
2049
- }
2050
- /**
2051
- * Find incidents that could become patterns
2052
- */
2053
- findPatternCandidates(minOccurrences = 3) {
2054
- const incidents = this.storage.getRecentIncidents({
2055
- limit: 1e3,
2056
- status: "resolved"
2057
- });
2058
- const signatureGroups = /* @__PURE__ */ new Map();
2059
- for (const incident of incidents) {
2060
- const signature = this.getSymbolSignature(incident.symbols);
2061
- const existing = signatureGroups.get(signature) || [];
2062
- existing.push(incident);
2063
- signatureGroups.set(signature, existing);
2064
- }
2065
- const candidates = [];
2066
- for (const [, groupIncidents] of signatureGroups) {
2067
- if (groupIncidents.length >= minOccurrences) {
2068
- const hasPattern = this.hasMatchingPattern(groupIncidents[0]);
2069
- if (hasPattern) continue;
2070
- const suggestedPattern = this.suggestFromIncidents(groupIncidents);
2071
- candidates.push({
2072
- incidents: groupIncidents,
2073
- suggestedPattern,
2074
- occurrenceCount: groupIncidents.length
2075
- });
2076
- }
2077
- }
2078
- return candidates.sort((a, b) => b.occurrenceCount - a.occurrenceCount);
2079
- }
2080
- /**
2081
- * Generate pattern from multiple similar incidents
2082
- */
2083
- suggestFromIncidents(incidents) {
2084
- const commonSymbols = this.extractCommonSymbols(incidents);
2085
- const symbols = this.buildSymbolCriteria(commonSymbols);
2086
- const errorKeywords = this.extractCommonErrorKeywords(incidents);
2087
- const missingSignals = this.extractCommonMissingSignals(incidents);
2088
- const baseId = this.generatePatternId(incidents[0]);
2089
- return {
2090
- id: baseId,
2091
- name: this.generatePatternName(incidents[0]),
2092
- description: `Auto-suggested pattern from ${incidents.length} similar incidents`,
2093
- pattern: {
2094
- symbols,
2095
- errorContains: errorKeywords.length > 0 ? errorKeywords : void 0,
2096
- missingSignals: missingSignals.length > 0 ? missingSignals : void 0
2097
- },
2098
- resolution: {
2099
- description: "Resolution approach based on previous resolutions",
2100
- strategy: this.inferStrategy(incidents),
2101
- priority: this.getPriorityFromCount(incidents.length)
2102
- },
2103
- source: "suggested",
2104
- private: false,
2105
- tags: this.generateTagsFromIncidents(incidents)
2106
- };
2107
- }
2108
- /**
2109
- * Build symbol criteria for pattern, adding wildcards where appropriate
2110
- */
2111
- buildSymbolCriteria(symbols) {
2112
- const criteria = {};
2113
- for (const [key, value] of Object.entries(symbols)) {
2114
- if (value) {
2115
- criteria[key] = value;
2116
- }
2117
- }
2118
- return criteria;
2119
- }
2120
- /**
2121
- * Extract keywords from error message
2122
- */
2123
- extractErrorKeywords(message) {
2124
- const stopWords = /* @__PURE__ */ new Set([
2125
- "the",
2126
- "a",
2127
- "an",
2128
- "is",
2129
- "are",
2130
- "was",
2131
- "were",
2132
- "in",
2133
- "on",
2134
- "at",
2135
- "to",
2136
- "for",
2137
- "of",
2138
- "with",
2139
- "and",
2140
- "or",
2141
- "but",
2142
- "not",
2143
- "no",
2144
- "be",
2145
- "been",
2146
- "have",
2147
- "has",
2148
- "had",
2149
- "do",
2150
- "does",
2151
- "did"
2152
- ]);
2153
- const words = message.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !stopWords.has(w));
2154
- const unique = [...new Set(words)];
2155
- return unique.slice(0, 5);
2156
- }
2157
- /**
2158
- * Extract common error keywords from multiple incidents
2159
- */
2160
- extractCommonErrorKeywords(incidents) {
2161
- const wordCounts = /* @__PURE__ */ new Map();
2162
- for (const incident of incidents) {
2163
- const keywords = this.extractErrorKeywords(incident.error.message);
2164
- for (const keyword of keywords) {
2165
- wordCounts.set(keyword, (wordCounts.get(keyword) || 0) + 1);
2166
- }
2167
- }
2168
- const threshold = Math.ceil(incidents.length * 0.5);
2169
- return Array.from(wordCounts.entries()).filter(([, count]) => count >= threshold).map(([word]) => word).slice(0, 5);
2170
- }
2171
- /**
2172
- * Extract symbols common to all incidents
2173
- */
2174
- extractCommonSymbols(incidents) {
2175
- if (incidents.length === 0) return {};
2176
- const first = incidents[0].symbols;
2177
- const common = {};
2178
- for (const [key, value] of Object.entries(first)) {
2179
- if (!value) continue;
2180
- const allMatch = incidents.every(
2181
- (i) => i.symbols[key] === value
2182
- );
2183
- if (allMatch) {
2184
- common[key] = value;
2185
- }
2186
- }
2187
- return common;
2188
- }
2189
- /**
2190
- * Extract missing signals common to multiple incidents
2191
- */
2192
- extractCommonMissingSignals(incidents) {
2193
- const signalCounts = /* @__PURE__ */ new Map();
2194
- for (const incident of incidents) {
2195
- if (!incident.flowPosition?.missing) continue;
2196
- for (const signal of incident.flowPosition.missing) {
2197
- signalCounts.set(signal, (signalCounts.get(signal) || 0) + 1);
2198
- }
2199
- }
2200
- const threshold = Math.ceil(incidents.length * 0.5);
2201
- return Array.from(signalCounts.entries()).filter(([, count]) => count >= threshold).map(([signal]) => signal);
2202
- }
2203
- /**
2204
- * Generate a pattern ID from incident
2205
- */
2206
- generatePatternId(incident) {
2207
- const parts = [];
2208
- if (incident.symbols.gate) {
2209
- parts.push(incident.symbols.gate.replace(/[^a-z0-9]/gi, ""));
2210
- } else if (incident.symbols.feature) {
2211
- parts.push(incident.symbols.feature.replace(/[^a-z0-9]/gi, ""));
2212
- } else if (incident.symbols.component) {
2213
- parts.push(incident.symbols.component.replace(/[^a-z0-9]/gi, ""));
2214
- } else if (incident.symbols.integration) {
2215
- parts.push(incident.symbols.integration.replace(/[^a-z0-9]/gi, ""));
2216
- } else {
2217
- parts.push("unknown");
2218
- }
2219
- const errorType = incident.error.type?.toLowerCase() || "error";
2220
- parts.push(errorType.replace(/[^a-z0-9]/gi, ""));
2221
- parts.push(String(Date.now() % 1e3).padStart(3, "0"));
2222
- return parts.join("-");
2223
- }
2224
- /**
2225
- * Generate a human-readable pattern name
2226
- */
2227
- generatePatternName(incident) {
2228
- const parts = [];
2229
- if (incident.symbols.feature) {
2230
- parts.push(
2231
- incident.symbols.feature.replace("@", "").replace(/-/g, " ")
2232
- );
2233
- }
2234
- if (incident.symbols.gate) {
2235
- parts.push("gate " + incident.symbols.gate.replace("^", ""));
2236
- }
2237
- if (incident.error.type) {
2238
- parts.push(incident.error.type);
2239
- }
2240
- if (parts.length === 0) {
2241
- return "Unnamed Pattern";
2242
- }
2243
- const name = parts.join(" - ");
2244
- return name.charAt(0).toUpperCase() + name.slice(1);
2245
- }
2246
- /**
2247
- * Generate tags from incident
2248
- */
2249
- generateTags(incident) {
2250
- const tags = [];
2251
- if (incident.symbols.feature) {
2252
- tags.push("feature");
2253
- }
2254
- if (incident.symbols.gate) {
2255
- tags.push("gate");
2256
- }
2257
- if (incident.symbols.integration) {
2258
- tags.push("integration");
2259
- tags.push(incident.symbols.integration.replace("&", ""));
2260
- }
2261
- if (incident.error.type) {
2262
- tags.push(incident.error.type.toLowerCase());
2263
- }
2264
- tags.push(incident.environment);
2265
- return [...new Set(tags)].slice(0, 5);
2266
- }
2267
- /**
2268
- * Generate tags from incident group
2269
- */
2270
- generateTagsFromGroup(group) {
2271
- const tags = ["grouped"];
2272
- if (group.commonSymbols.feature) {
2273
- tags.push("feature");
2274
- }
2275
- if (group.commonSymbols.gate) {
2276
- tags.push("gate");
2277
- }
2278
- if (group.commonSymbols.integration) {
2279
- tags.push("integration");
2280
- }
2281
- for (const env of group.environments) {
2282
- tags.push(env);
2283
- }
2284
- return [...new Set(tags)].slice(0, 5);
2285
- }
2286
- /**
2287
- * Generate tags from multiple incidents
2288
- */
2289
- generateTagsFromIncidents(incidents) {
2290
- const tagCounts = /* @__PURE__ */ new Map();
2291
- for (const incident of incidents) {
2292
- const tags = this.generateTags(incident);
2293
- for (const tag of tags) {
2294
- tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
2295
- }
2296
- }
2297
- return Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([tag]) => tag);
2298
- }
2299
- /**
2300
- * Get symbol signature for grouping
2301
- */
2302
- getSymbolSignature(symbols) {
2303
- const parts = [];
2304
- if (symbols.feature) parts.push(`f:${symbols.feature}`);
2305
- if (symbols.component) parts.push(`c:${symbols.component}`);
2306
- if (symbols.flow) parts.push(`fl:${symbols.flow}`);
2307
- if (symbols.gate) parts.push(`g:${symbols.gate}`);
2308
- if (symbols.integration) parts.push(`i:${symbols.integration}`);
2309
- return parts.sort().join("|");
2310
- }
2311
- /**
2312
- * Check if there's already a pattern matching this incident
2313
- */
2314
- hasMatchingPattern(incident) {
2315
- const patterns = this.storage.getAllPatterns({ includePrivate: true });
2316
- for (const pattern of patterns) {
2317
- let matchCount = 0;
2318
- const symbolTypes = [
2319
- "feature",
2320
- "component",
2321
- "flow",
2322
- "gate",
2323
- "signal",
2324
- "integration"
2325
- ];
2326
- for (const type of symbolTypes) {
2327
- const patternValue = pattern.pattern.symbols[type];
2328
- const incidentValue = incident.symbols[type];
2329
- if (patternValue && incidentValue && patternValue === incidentValue) {
2330
- matchCount++;
2331
- }
2332
- }
2333
- if (matchCount >= 2) {
2334
- return true;
2335
- }
2336
- }
2337
- return false;
2338
- }
2339
- /**
2340
- * Infer resolution strategy from incident error patterns and context.
2341
- * Uses keyword heuristics across all incident messages to pick the
2342
- * most likely resolution approach.
2343
- */
2344
- inferStrategy(incidents) {
2345
- const messages = incidents.map((i) => i.error.message.toLowerCase());
2346
- const hasKeyword = (keywords) => messages.some((m) => keywords.some((k) => m.includes(k)));
2347
- if (hasKeyword(["revert", "rollback", "regression", "broke after deploy", "since deploy"])) {
2348
- return "rollback";
2349
- }
2350
- if (hasKeyword(["config", "environment variable", "env var", "missing key", "secret", "credential"])) {
2351
- return "config-change";
2352
- }
2353
- if (hasKeyword(["out of memory", "oom", "heap", "memory limit", "capacity", "too many connections", "pool exhausted"])) {
2354
- return "scale-up";
2355
- }
2356
- if (hasKeyword(["timeout", "network", "econnrefused", "econnreset", "dns", "socket hang up"])) {
2357
- return "retry";
2358
- }
2359
- if (hasKeyword(["unavailable", "service down", "circuit breaker", "fallback", "503", "502"])) {
2360
- return "fallback";
2361
- }
2362
- if (hasKeyword(["validation", "invalid", "required", "constraint", "duplicate", "not found", "404"])) {
2363
- return "fix-data";
2364
- }
2365
- if (hasKeyword(["permission", "forbidden", "403", "401", "unauthorized", "access denied"])) {
2366
- return "escalate";
2367
- }
2368
- const uniqueTypes = new Set(incidents.map((i) => i.error.type).filter(Boolean));
2369
- if (uniqueTypes.size > 2) {
2370
- return "investigate";
2371
- }
2372
- return "fix-code";
2373
- }
2374
- /**
2375
- * Get priority based on occurrence count
2376
- */
2377
- getPriorityFromCount(count) {
2378
- if (count >= 20) return "critical";
2379
- if (count >= 10) return "high";
2380
- if (count >= 5) return "medium";
2381
- return "low";
2382
- }
2383
- };
2384
- var PatternImporter = class {
2385
- /**
2386
- * Validate a pattern export file
2387
- */
2388
- validate(data) {
2389
- const errors = [];
2390
- const warnings = [];
2391
- if (!data || typeof data !== "object") {
2392
- return { valid: false, errors: ["Invalid data: expected object"], warnings: [] };
2393
- }
2394
- const obj = data;
2395
- if (!obj.version) {
2396
- errors.push("Missing version field");
2397
- }
2398
- if (!Array.isArray(obj.patterns)) {
2399
- errors.push("Missing or invalid patterns array");
2400
- return { valid: false, errors, warnings };
2401
- }
2402
- for (let i = 0; i < obj.patterns.length; i++) {
2403
- const pattern = obj.patterns[i];
2404
- const patternErrors = this.validatePattern(pattern, i);
2405
- errors.push(...patternErrors.errors);
2406
- warnings.push(...patternErrors.warnings);
2407
- }
2408
- return {
2409
- valid: errors.length === 0,
2410
- errors,
2411
- warnings
2412
- };
2413
- }
2414
- /**
2415
- * Validate a single pattern
2416
- */
2417
- validatePattern(pattern, index) {
2418
- const errors = [];
2419
- const warnings = [];
2420
- const prefix = `Pattern[${index}]`;
2421
- if (!pattern.id || typeof pattern.id !== "string") {
2422
- errors.push(`${prefix}: Missing or invalid id`);
2423
- } else if (!/^[a-z0-9-]+$/.test(pattern.id)) {
2424
- warnings.push(`${prefix}: ID "${pattern.id}" should be kebab-case`);
2425
- }
2426
- if (!pattern.name || typeof pattern.name !== "string") {
2427
- errors.push(`${prefix}: Missing or invalid name`);
2428
- }
2429
- if (!pattern.pattern || typeof pattern.pattern !== "object") {
2430
- errors.push(`${prefix}: Missing or invalid pattern criteria`);
2431
- } else {
2432
- const criteria = pattern.pattern;
2433
- const hasSymbols = criteria.symbols && typeof criteria.symbols === "object" && Object.keys(criteria.symbols).length > 0;
2434
- const hasErrorContains = Array.isArray(criteria.errorContains) && criteria.errorContains.length > 0;
2435
- const hasErrorMatches = criteria.errorMatches && typeof criteria.errorMatches === "string";
2436
- const hasMissingSignals = Array.isArray(criteria.missingSignals) && criteria.missingSignals.length > 0;
2437
- if (!hasSymbols && !hasErrorContains && !hasErrorMatches && !hasMissingSignals) {
2438
- errors.push(`${prefix}: Pattern must have at least one matching criteria`);
2439
- }
2440
- }
2441
- if (!pattern.resolution || typeof pattern.resolution !== "object") {
2442
- errors.push(`${prefix}: Missing or invalid resolution`);
2443
- } else {
2444
- const resolution = pattern.resolution;
2445
- if (!resolution.description || typeof resolution.description !== "string") {
2446
- errors.push(`${prefix}: Missing resolution description`);
2447
- }
2448
- if (!resolution.strategy || typeof resolution.strategy !== "string") {
2449
- errors.push(`${prefix}: Missing resolution strategy`);
2450
- } else {
2451
- const validStrategies = [
2452
- "retry",
2453
- "fallback",
2454
- "fix-data",
2455
- "fix-code",
2456
- "ignore",
2457
- "escalate"
2458
- ];
2459
- if (!validStrategies.includes(resolution.strategy)) {
2460
- errors.push(`${prefix}: Invalid strategy "${resolution.strategy}"`);
2461
- }
2462
- }
2463
- if (!resolution.priority || typeof resolution.priority !== "string") {
2464
- warnings.push(`${prefix}: Missing priority, will default to medium`);
2465
- } else {
2466
- const validPriorities = ["low", "medium", "high", "critical"];
2467
- if (!validPriorities.includes(resolution.priority)) {
2468
- warnings.push(`${prefix}: Invalid priority "${resolution.priority}"`);
2469
- }
2470
- }
2471
- }
2472
- return { errors, warnings };
2473
- }
2474
- /**
2475
- * Load patterns from a JSON file
2476
- */
2477
- loadFromFile(filePath) {
2478
- if (!fs4.existsSync(filePath)) {
2479
- throw new Error(`File not found: ${filePath}`);
2480
- }
2481
- const content = fs4.readFileSync(filePath, "utf-8");
2482
- const data = JSON.parse(content);
2483
- const validation = this.validate(data);
2484
- if (!validation.valid) {
2485
- throw new Error(`Invalid pattern file: ${validation.errors.join(", ")}`);
2486
- }
2487
- return this.normalizeExport(data);
2488
- }
2489
- /**
2490
- * Load patterns from a URL
2491
- */
2492
- async loadFromUrl(url) {
2493
- const response = await fetch(url);
2494
- if (!response.ok) {
2495
- throw new Error(`Failed to fetch patterns: ${response.statusText}`);
2496
- }
2497
- const data = await response.json();
2498
- const validation = this.validate(data);
2499
- if (!validation.valid) {
2500
- throw new Error(`Invalid pattern data: ${validation.errors.join(", ")}`);
2501
- }
2502
- return this.normalizeExport(data);
2503
- }
2504
- /**
2505
- * Normalize raw data to PatternExport
2506
- */
2507
- normalizeExport(data) {
2508
- const patterns = data.patterns.map(
2509
- (p) => this.normalizePattern(p)
2510
- );
2511
- return {
2512
- version: data.version || "1.0.0",
2513
- exportedAt: data.exportedAt || (/* @__PURE__ */ new Date()).toISOString(),
2514
- patterns
2515
- };
2516
- }
2517
- /**
2518
- * Normalize a raw pattern object
2519
- */
2520
- normalizePattern(data) {
2521
- const pattern = data.pattern;
2522
- const resolution = data.resolution;
2523
- const confidence = data.confidence || {};
2524
- return {
2525
- id: data.id,
2526
- name: data.name,
2527
- description: data.description || "",
2528
- pattern: {
2529
- symbols: pattern.symbols || {},
2530
- errorContains: pattern.errorContains,
2531
- errorMatches: pattern.errorMatches,
2532
- errorType: pattern.errorType,
2533
- missingSignals: pattern.missingSignals,
2534
- environment: pattern.environment
2535
- },
2536
- resolution: {
2537
- description: resolution.description,
2538
- strategy: resolution.strategy,
2539
- priority: resolution.priority || "medium",
2540
- codeHint: resolution.codeHint,
2541
- codeSnippet: resolution.codeSnippet,
2542
- symbolsToModify: resolution.symbolsToModify,
2543
- filesLikelyInvolved: resolution.filesLikelyInvolved,
2544
- commitRef: resolution.commitRef,
2545
- prRef: resolution.prRef,
2546
- docsRef: resolution.docsRef
2547
- },
2548
- confidence: {
2549
- score: confidence.score || 50,
2550
- timesMatched: confidence.timesMatched || 0,
2551
- timesResolved: confidence.timesResolved || 0,
2552
- timesRecurred: confidence.timesRecurred || 0,
2553
- avgTimeToResolve: confidence.avgTimeToResolve,
2554
- lastMatched: confidence.lastMatched,
2555
- lastResolved: confidence.lastResolved
2556
- },
2557
- source: data.source || "imported",
2558
- private: Boolean(data.private),
2559
- tags: data.tags || [],
2560
- createdAt: data.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
2561
- updatedAt: data.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
2562
- };
2563
- }
2564
- /**
2565
- * Merge patterns from multiple sources
2566
- */
2567
- mergePatterns(...exports) {
2568
- const patternMap = /* @__PURE__ */ new Map();
2569
- for (const exp of exports) {
2570
- for (const pattern of exp.patterns) {
2571
- patternMap.set(pattern.id, pattern);
2572
- }
2573
- }
2574
- return {
2575
- version: "1.0.0",
2576
- exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2577
- patterns: Array.from(patternMap.values())
2578
- };
2579
- }
2580
- };
2581
-
2582
- export {
2583
- SentinelClient,
2584
- createSentinelClient,
2585
- SentinelTransport,
2586
- createSentinelTransport,
2587
- enableSentinel,
2588
- PatternMatcher,
2589
- loadUniversalPatterns,
2590
- loadParadigmPatterns,
2591
- loadAllSeedPatterns,
2592
- FlowTracker,
2593
- Sentinel,
2594
- detectSymbols,
2595
- generateConfig,
2596
- IncidentGrouper,
2597
- TimelineBuilder,
2598
- StatsCalculator,
2599
- ContextEnricher,
2600
- PatternSuggester,
2601
- PatternImporter
2602
- };