@pcircle/footprint 1.3.0 → 1.6.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 (349) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +215 -137
  3. package/SKILL.md +77 -33
  4. package/bin/footprint.js +16 -0
  5. package/dist/src/adapters/claude.d.ts +2 -0
  6. package/dist/src/adapters/claude.d.ts.map +1 -0
  7. package/dist/src/adapters/claude.js +7 -0
  8. package/dist/src/adapters/claude.js.map +1 -0
  9. package/dist/src/adapters/codex.d.ts +2 -0
  10. package/dist/src/adapters/codex.d.ts.map +1 -0
  11. package/dist/src/adapters/codex.js +7 -0
  12. package/dist/src/adapters/codex.js.map +1 -0
  13. package/dist/src/adapters/gemini.d.ts +2 -0
  14. package/dist/src/adapters/gemini.d.ts.map +1 -0
  15. package/dist/src/adapters/gemini.js +7 -0
  16. package/dist/src/adapters/gemini.js.map +1 -0
  17. package/dist/src/adapters/index.d.ts +5 -0
  18. package/dist/src/adapters/index.d.ts.map +1 -0
  19. package/dist/src/adapters/index.js +12 -0
  20. package/dist/src/adapters/index.js.map +1 -0
  21. package/dist/src/adapters/structured-prefix.d.ts +10 -0
  22. package/dist/src/adapters/structured-prefix.d.ts.map +1 -0
  23. package/dist/src/adapters/structured-prefix.js +59 -0
  24. package/dist/src/adapters/structured-prefix.js.map +1 -0
  25. package/dist/src/adapters/types.d.ts +32 -0
  26. package/dist/src/adapters/types.d.ts.map +1 -0
  27. package/dist/src/adapters/types.js +2 -0
  28. package/dist/src/adapters/types.js.map +1 -0
  29. package/dist/src/analyzers/content-analyzer.d.ts.map +1 -1
  30. package/dist/src/analyzers/content-analyzer.js +20 -4
  31. package/dist/src/analyzers/content-analyzer.js.map +1 -1
  32. package/dist/src/cli/context-flow.d.ts +92 -0
  33. package/dist/src/cli/context-flow.d.ts.map +1 -0
  34. package/dist/src/cli/context-flow.js +724 -0
  35. package/dist/src/cli/context-flow.js.map +1 -0
  36. package/dist/src/cli/history-display.d.ts +27 -0
  37. package/dist/src/cli/history-display.d.ts.map +1 -0
  38. package/dist/src/cli/history-display.js +167 -0
  39. package/dist/src/cli/history-display.js.map +1 -0
  40. package/dist/src/cli/index.js +924 -0
  41. package/dist/src/cli/index.js.map +1 -1
  42. package/dist/src/cli/launch-spec.d.ts +31 -0
  43. package/dist/src/cli/launch-spec.d.ts.map +1 -0
  44. package/dist/src/cli/launch-spec.js +182 -0
  45. package/dist/src/cli/launch-spec.js.map +1 -0
  46. package/dist/src/cli/live-demo.d.ts +34 -0
  47. package/dist/src/cli/live-demo.d.ts.map +1 -0
  48. package/dist/src/cli/live-demo.js +254 -0
  49. package/dist/src/cli/live-demo.js.map +1 -0
  50. package/dist/src/cli/pty-transcript.d.ts +34 -0
  51. package/dist/src/cli/pty-transcript.d.ts.map +1 -0
  52. package/dist/src/cli/pty-transcript.js +174 -0
  53. package/dist/src/cli/pty-transcript.js.map +1 -0
  54. package/dist/src/cli/session-display.d.ts +74 -0
  55. package/dist/src/cli/session-display.d.ts.map +1 -0
  56. package/dist/src/cli/session-display.js +922 -0
  57. package/dist/src/cli/session-display.js.map +1 -0
  58. package/dist/src/cli/session-execution.d.ts +55 -0
  59. package/dist/src/cli/session-execution.d.ts.map +1 -0
  60. package/dist/src/cli/session-execution.js +817 -0
  61. package/dist/src/cli/session-execution.js.map +1 -0
  62. package/dist/src/cli/session-runtime.d.ts +5 -0
  63. package/dist/src/cli/session-runtime.d.ts.map +1 -0
  64. package/dist/src/cli/session-runtime.js +11 -0
  65. package/dist/src/cli/session-runtime.js.map +1 -0
  66. package/dist/src/cli/setup.d.ts.map +1 -1
  67. package/dist/src/cli/setup.js +36 -12
  68. package/dist/src/cli/setup.js.map +1 -1
  69. package/dist/src/cli/utils/env.d.ts +7 -2
  70. package/dist/src/cli/utils/env.d.ts.map +1 -1
  71. package/dist/src/cli/utils/env.js +37 -6
  72. package/dist/src/cli/utils/env.js.map +1 -1
  73. package/dist/src/index.d.ts +4 -1
  74. package/dist/src/index.d.ts.map +1 -1
  75. package/dist/src/index.js +187 -33
  76. package/dist/src/index.js.map +1 -1
  77. package/dist/src/ingestion/deterministic.d.ts +3 -0
  78. package/dist/src/ingestion/deterministic.d.ts.map +1 -0
  79. package/dist/src/ingestion/deterministic.js +862 -0
  80. package/dist/src/ingestion/deterministic.js.map +1 -0
  81. package/dist/src/ingestion/index.d.ts +5 -0
  82. package/dist/src/ingestion/index.d.ts.map +1 -0
  83. package/dist/src/ingestion/index.js +27 -0
  84. package/dist/src/ingestion/index.js.map +1 -0
  85. package/dist/src/ingestion/semantic.d.ts +6 -0
  86. package/dist/src/ingestion/semantic.d.ts.map +1 -0
  87. package/dist/src/ingestion/semantic.js +627 -0
  88. package/dist/src/ingestion/semantic.js.map +1 -0
  89. package/dist/src/ingestion/types.d.ts +10 -0
  90. package/dist/src/ingestion/types.d.ts.map +1 -0
  91. package/dist/src/ingestion/types.js +2 -0
  92. package/dist/src/ingestion/types.js.map +1 -0
  93. package/dist/src/lib/context-memory.d.ts +140 -0
  94. package/dist/src/lib/context-memory.d.ts.map +1 -0
  95. package/dist/src/lib/context-memory.js +974 -0
  96. package/dist/src/lib/context-memory.js.map +1 -0
  97. package/dist/src/lib/crypto/decrypt.d.ts.map +1 -1
  98. package/dist/src/lib/crypto/decrypt.js +12 -8
  99. package/dist/src/lib/crypto/decrypt.js.map +1 -1
  100. package/dist/src/lib/crypto/encrypt.d.ts.map +1 -1
  101. package/dist/src/lib/crypto/encrypt.js +6 -3
  102. package/dist/src/lib/crypto/encrypt.js.map +1 -1
  103. package/dist/src/lib/crypto/key-derivation.d.ts +1 -1
  104. package/dist/src/lib/crypto/key-derivation.d.ts.map +1 -1
  105. package/dist/src/lib/crypto/key-derivation.js +11 -11
  106. package/dist/src/lib/crypto/key-derivation.js.map +1 -1
  107. package/dist/src/lib/history-handoff.d.ts +43 -0
  108. package/dist/src/lib/history-handoff.d.ts.map +1 -0
  109. package/dist/src/lib/history-handoff.js +179 -0
  110. package/dist/src/lib/history-handoff.js.map +1 -0
  111. package/dist/src/lib/observability.d.ts +3 -0
  112. package/dist/src/lib/observability.d.ts.map +1 -0
  113. package/dist/src/lib/observability.js +63 -0
  114. package/dist/src/lib/observability.js.map +1 -0
  115. package/dist/src/lib/session-artifacts.d.ts +51 -0
  116. package/dist/src/lib/session-artifacts.d.ts.map +1 -0
  117. package/dist/src/lib/session-artifacts.js +132 -0
  118. package/dist/src/lib/session-artifacts.js.map +1 -0
  119. package/dist/src/lib/session-filters.d.ts +11 -0
  120. package/dist/src/lib/session-filters.d.ts.map +1 -0
  121. package/dist/src/lib/session-filters.js +16 -0
  122. package/dist/src/lib/session-filters.js.map +1 -0
  123. package/dist/src/lib/session-history.d.ts +50 -0
  124. package/dist/src/lib/session-history.d.ts.map +1 -0
  125. package/dist/src/lib/session-history.js +73 -0
  126. package/dist/src/lib/session-history.js.map +1 -0
  127. package/dist/src/lib/session-trends.d.ts +129 -0
  128. package/dist/src/lib/session-trends.d.ts.map +1 -0
  129. package/dist/src/lib/session-trends.js +361 -0
  130. package/dist/src/lib/session-trends.js.map +1 -0
  131. package/dist/src/lib/storage/database.d.ts +257 -3
  132. package/dist/src/lib/storage/database.d.ts.map +1 -1
  133. package/dist/src/lib/storage/database.js +1836 -161
  134. package/dist/src/lib/storage/database.js.map +1 -1
  135. package/dist/src/lib/storage/export-sessions.d.ts +33 -0
  136. package/dist/src/lib/storage/export-sessions.d.ts.map +1 -0
  137. package/dist/src/lib/storage/export-sessions.js +525 -0
  138. package/dist/src/lib/storage/export-sessions.js.map +1 -0
  139. package/dist/src/lib/storage/export.d.ts +1 -2
  140. package/dist/src/lib/storage/export.d.ts.map +1 -1
  141. package/dist/src/lib/storage/export.js +46 -33
  142. package/dist/src/lib/storage/export.js.map +1 -1
  143. package/dist/src/lib/storage/index.d.ts +7 -6
  144. package/dist/src/lib/storage/index.d.ts.map +1 -1
  145. package/dist/src/lib/storage/index.js +6 -5
  146. package/dist/src/lib/storage/index.js.map +1 -1
  147. package/dist/src/lib/storage/salt-storage.d.ts +1 -1
  148. package/dist/src/lib/storage/salt-storage.d.ts.map +1 -1
  149. package/dist/src/lib/storage/salt-storage.js +26 -18
  150. package/dist/src/lib/storage/salt-storage.js.map +1 -1
  151. package/dist/src/lib/storage/schema.d.ts +7 -2
  152. package/dist/src/lib/storage/schema.d.ts.map +1 -1
  153. package/dist/src/lib/storage/schema.js +357 -40
  154. package/dist/src/lib/storage/schema.js.map +1 -1
  155. package/dist/src/lib/storage/types.d.ts +122 -0
  156. package/dist/src/lib/storage/types.d.ts.map +1 -1
  157. package/dist/src/lib/tool-wrapper.d.ts.map +1 -1
  158. package/dist/src/lib/tool-wrapper.js +2 -2
  159. package/dist/src/lib/tool-wrapper.js.map +1 -1
  160. package/dist/src/prompts/skill-prompt.d.ts +6 -0
  161. package/dist/src/prompts/skill-prompt.d.ts.map +1 -0
  162. package/dist/src/prompts/skill-prompt.js +138 -0
  163. package/dist/src/prompts/skill-prompt.js.map +1 -0
  164. package/dist/src/tools/capture-footprint.d.ts +2 -2
  165. package/dist/src/tools/capture-footprint.d.ts.map +1 -1
  166. package/dist/src/tools/capture-footprint.js +52 -11
  167. package/dist/src/tools/capture-footprint.js.map +1 -1
  168. package/dist/src/tools/confirm-context-link.d.ts +62 -0
  169. package/dist/src/tools/confirm-context-link.d.ts.map +1 -0
  170. package/dist/src/tools/confirm-context-link.js +36 -0
  171. package/dist/src/tools/confirm-context-link.js.map +1 -0
  172. package/dist/src/tools/context-schemas.d.ts +694 -0
  173. package/dist/src/tools/context-schemas.d.ts.map +1 -0
  174. package/dist/src/tools/context-schemas.js +171 -0
  175. package/dist/src/tools/context-schemas.js.map +1 -0
  176. package/dist/src/tools/delete-footprints.d.ts +18 -1
  177. package/dist/src/tools/delete-footprints.d.ts.map +1 -1
  178. package/dist/src/tools/delete-footprints.js +53 -5
  179. package/dist/src/tools/delete-footprints.js.map +1 -1
  180. package/dist/src/tools/export-footprints.d.ts +11 -3
  181. package/dist/src/tools/export-footprints.d.ts.map +1 -1
  182. package/dist/src/tools/export-footprints.js +48 -9
  183. package/dist/src/tools/export-footprints.js.map +1 -1
  184. package/dist/src/tools/export-sessions.d.ts +111 -0
  185. package/dist/src/tools/export-sessions.d.ts.map +1 -0
  186. package/dist/src/tools/export-sessions.js +136 -0
  187. package/dist/src/tools/export-sessions.js.map +1 -0
  188. package/dist/src/tools/get-context.d.ts +208 -0
  189. package/dist/src/tools/get-context.d.ts.map +1 -0
  190. package/dist/src/tools/get-context.js +27 -0
  191. package/dist/src/tools/get-context.js.map +1 -0
  192. package/dist/src/tools/get-footprint.d.ts +1 -7
  193. package/dist/src/tools/get-footprint.d.ts.map +1 -1
  194. package/dist/src/tools/get-footprint.js +7 -3
  195. package/dist/src/tools/get-footprint.js.map +1 -1
  196. package/dist/src/tools/get-history-handoff.d.ts +109 -0
  197. package/dist/src/tools/get-history-handoff.d.ts.map +1 -0
  198. package/dist/src/tools/get-history-handoff.js +85 -0
  199. package/dist/src/tools/get-history-handoff.js.map +1 -0
  200. package/dist/src/tools/get-history-trends.d.ts +155 -0
  201. package/dist/src/tools/get-history-trends.d.ts.map +1 -0
  202. package/dist/src/tools/get-history-trends.js +123 -0
  203. package/dist/src/tools/get-history-trends.js.map +1 -0
  204. package/dist/src/tools/get-session-artifacts.d.ts +151 -0
  205. package/dist/src/tools/get-session-artifacts.d.ts.map +1 -0
  206. package/dist/src/tools/get-session-artifacts.js +184 -0
  207. package/dist/src/tools/get-session-artifacts.js.map +1 -0
  208. package/dist/src/tools/get-session-decisions.d.ts +69 -0
  209. package/dist/src/tools/get-session-decisions.d.ts.map +1 -0
  210. package/dist/src/tools/get-session-decisions.js +99 -0
  211. package/dist/src/tools/get-session-decisions.js.map +1 -0
  212. package/dist/src/tools/get-session-messages.d.ts +55 -0
  213. package/dist/src/tools/get-session-messages.d.ts.map +1 -0
  214. package/dist/src/tools/get-session-messages.js +89 -0
  215. package/dist/src/tools/get-session-messages.js.map +1 -0
  216. package/dist/src/tools/get-session-narrative.d.ts +72 -0
  217. package/dist/src/tools/get-session-narrative.d.ts.map +1 -0
  218. package/dist/src/tools/get-session-narrative.js +106 -0
  219. package/dist/src/tools/get-session-narrative.js.map +1 -0
  220. package/dist/src/tools/get-session-timeline.d.ts +55 -0
  221. package/dist/src/tools/get-session-timeline.d.ts.map +1 -0
  222. package/dist/src/tools/get-session-timeline.js +93 -0
  223. package/dist/src/tools/get-session-timeline.js.map +1 -0
  224. package/dist/src/tools/get-session-trends.d.ts +108 -0
  225. package/dist/src/tools/get-session-trends.d.ts.map +1 -0
  226. package/dist/src/tools/get-session-trends.js +130 -0
  227. package/dist/src/tools/get-session-trends.js.map +1 -0
  228. package/dist/src/tools/get-session.d.ts +251 -0
  229. package/dist/src/tools/get-session.d.ts.map +1 -0
  230. package/dist/src/tools/get-session.js +290 -0
  231. package/dist/src/tools/get-session.js.map +1 -0
  232. package/dist/src/tools/index.d.ts +23 -3
  233. package/dist/src/tools/index.d.ts.map +1 -1
  234. package/dist/src/tools/index.js +23 -3
  235. package/dist/src/tools/index.js.map +1 -1
  236. package/dist/src/tools/list-contexts.d.ts +50 -0
  237. package/dist/src/tools/list-contexts.d.ts.map +1 -0
  238. package/dist/src/tools/list-contexts.js +28 -0
  239. package/dist/src/tools/list-contexts.js.map +1 -0
  240. package/dist/src/tools/list-footprints.d.ts +1 -15
  241. package/dist/src/tools/list-footprints.d.ts.map +1 -1
  242. package/dist/src/tools/list-footprints.js +17 -6
  243. package/dist/src/tools/list-footprints.js.map +1 -1
  244. package/dist/src/tools/list-sessions.d.ts +86 -0
  245. package/dist/src/tools/list-sessions.d.ts.map +1 -0
  246. package/dist/src/tools/list-sessions.js +97 -0
  247. package/dist/src/tools/list-sessions.js.map +1 -0
  248. package/dist/src/tools/manage-tags.d.ts +47 -0
  249. package/dist/src/tools/manage-tags.d.ts.map +1 -0
  250. package/dist/src/tools/manage-tags.js +109 -0
  251. package/dist/src/tools/manage-tags.js.map +1 -0
  252. package/dist/src/tools/merge-contexts.d.ts +58 -0
  253. package/dist/src/tools/merge-contexts.d.ts.map +1 -0
  254. package/dist/src/tools/merge-contexts.js +27 -0
  255. package/dist/src/tools/merge-contexts.js.map +1 -0
  256. package/dist/src/tools/move-session-context.d.ts +62 -0
  257. package/dist/src/tools/move-session-context.d.ts.map +1 -0
  258. package/dist/src/tools/move-session-context.js +33 -0
  259. package/dist/src/tools/move-session-context.js.map +1 -0
  260. package/dist/src/tools/reingest-session.d.ts +31 -0
  261. package/dist/src/tools/reingest-session.d.ts.map +1 -0
  262. package/dist/src/tools/reingest-session.js +43 -0
  263. package/dist/src/tools/reingest-session.js.map +1 -0
  264. package/dist/src/tools/reject-context-link.d.ts +58 -0
  265. package/dist/src/tools/reject-context-link.d.ts.map +1 -0
  266. package/dist/src/tools/reject-context-link.js +26 -0
  267. package/dist/src/tools/reject-context-link.js.map +1 -0
  268. package/dist/src/tools/resolve-context.d.ts +287 -0
  269. package/dist/src/tools/resolve-context.d.ts.map +1 -0
  270. package/dist/src/tools/resolve-context.js +35 -0
  271. package/dist/src/tools/resolve-context.js.map +1 -0
  272. package/dist/src/tools/search-footprints.d.ts +2 -16
  273. package/dist/src/tools/search-footprints.d.ts.map +1 -1
  274. package/dist/src/tools/search-footprints.js +23 -7
  275. package/dist/src/tools/search-footprints.js.map +1 -1
  276. package/dist/src/tools/search-history.d.ts +86 -0
  277. package/dist/src/tools/search-history.d.ts.map +1 -0
  278. package/dist/src/tools/search-history.js +103 -0
  279. package/dist/src/tools/search-history.js.map +1 -0
  280. package/dist/src/tools/session-ui-metadata.d.ts +15 -0
  281. package/dist/src/tools/session-ui-metadata.d.ts.map +1 -0
  282. package/dist/src/tools/session-ui-metadata.js +15 -0
  283. package/dist/src/tools/session-ui-metadata.js.map +1 -0
  284. package/dist/src/tools/set-active-context.d.ts +58 -0
  285. package/dist/src/tools/set-active-context.d.ts.map +1 -0
  286. package/dist/src/tools/set-active-context.js +26 -0
  287. package/dist/src/tools/set-active-context.js.map +1 -0
  288. package/dist/src/tools/split-context.d.ts +62 -0
  289. package/dist/src/tools/split-context.d.ts.map +1 -0
  290. package/dist/src/tools/split-context.js +36 -0
  291. package/dist/src/tools/split-context.js.map +1 -0
  292. package/dist/src/tools/suggest-capture.d.ts +1 -1
  293. package/dist/src/tools/suggest-capture.d.ts.map +1 -1
  294. package/dist/src/tools/suggest-capture.js +6 -2
  295. package/dist/src/tools/suggest-capture.js.map +1 -1
  296. package/dist/src/tools/verify-footprint.d.ts +7 -54
  297. package/dist/src/tools/verify-footprint.d.ts.map +1 -1
  298. package/dist/src/tools/verify-footprint.js +11 -8
  299. package/dist/src/tools/verify-footprint.js.map +1 -1
  300. package/dist/src/types.d.ts +6 -4
  301. package/dist/src/types.d.ts.map +1 -1
  302. package/dist/src/ui/register.d.ts +6 -1
  303. package/dist/src/ui/register.d.ts.map +1 -1
  304. package/dist/src/ui/register.js +60 -16
  305. package/dist/src/ui/register.js.map +1 -1
  306. package/dist/ui/dashboard.html +259 -875
  307. package/dist/ui/detail.html +124 -252
  308. package/dist/ui/export.html +133 -303
  309. package/dist/ui/session-dashboard-live.html +264 -0
  310. package/dist/ui/session-dashboard.html +329 -0
  311. package/dist/ui/session-detail-live.html +336 -0
  312. package/dist/ui/session-detail.html +355 -0
  313. package/package.json +61 -16
  314. package/dist/src/lib/errors/base-error.d.ts +0 -15
  315. package/dist/src/lib/errors/base-error.d.ts.map +0 -1
  316. package/dist/src/lib/errors/base-error.js +0 -34
  317. package/dist/src/lib/errors/base-error.js.map +0 -1
  318. package/dist/src/lib/errors/crypto-error.d.ts +0 -29
  319. package/dist/src/lib/errors/crypto-error.d.ts.map +0 -1
  320. package/dist/src/lib/errors/crypto-error.js +0 -43
  321. package/dist/src/lib/errors/crypto-error.js.map +0 -1
  322. package/dist/src/lib/errors/index.d.ts +0 -26
  323. package/dist/src/lib/errors/index.d.ts.map +0 -1
  324. package/dist/src/lib/errors/index.js +0 -26
  325. package/dist/src/lib/errors/index.js.map +0 -1
  326. package/dist/src/lib/errors/storage-error.d.ts +0 -25
  327. package/dist/src/lib/errors/storage-error.d.ts.map +0 -1
  328. package/dist/src/lib/errors/storage-error.js +0 -38
  329. package/dist/src/lib/errors/storage-error.js.map +0 -1
  330. package/dist/src/lib/errors/validation-error.d.ts +0 -21
  331. package/dist/src/lib/errors/validation-error.d.ts.map +0 -1
  332. package/dist/src/lib/errors/validation-error.js +0 -29
  333. package/dist/src/lib/errors/validation-error.js.map +0 -1
  334. package/dist/src/test-helpers.d.ts +0 -33
  335. package/dist/src/test-helpers.d.ts.map +0 -1
  336. package/dist/src/test-helpers.js +0 -108
  337. package/dist/src/test-helpers.js.map +0 -1
  338. package/dist/src/tools/get-tag-stats.d.ts +0 -30
  339. package/dist/src/tools/get-tag-stats.d.ts.map +0 -1
  340. package/dist/src/tools/get-tag-stats.js +0 -33
  341. package/dist/src/tools/get-tag-stats.js.map +0 -1
  342. package/dist/src/tools/remove-tag.d.ts +0 -22
  343. package/dist/src/tools/remove-tag.d.ts.map +0 -1
  344. package/dist/src/tools/remove-tag.js +0 -30
  345. package/dist/src/tools/remove-tag.js.map +0 -1
  346. package/dist/src/tools/rename-tag.d.ts +0 -24
  347. package/dist/src/tools/rename-tag.d.ts.map +0 -1
  348. package/dist/src/tools/rename-tag.js +0 -34
  349. package/dist/src/tools/rename-tag.js.map +0 -1
@@ -0,0 +1,862 @@
1
+ const COMMAND_PREFIXES = [
2
+ "pnpm",
3
+ "npm",
4
+ "yarn",
5
+ "bun",
6
+ "npx",
7
+ "node",
8
+ "python",
9
+ "pytest",
10
+ "vitest",
11
+ "jest",
12
+ "cargo",
13
+ "go test",
14
+ "git",
15
+ "docker",
16
+ "make",
17
+ ];
18
+ const COMMAND_PATTERN = /\b(?:pnpm|npm|yarn|bun|npx|node|python|pytest|vitest|jest|cargo|go test|git|docker|make)\b/i;
19
+ const TEST_PATTERN = /\b(?:test|tests|vitest|jest|pytest|spec|PASS|FAIL|failing)\b/i;
20
+ const DECISIONLESS_ERROR_PATTERN = /\b(?:error|failed|retry|exception)\b/i;
21
+ const FILE_PATTERN = /\b(?:[\w.-]+\/)+[\w.-]+\.[A-Za-z0-9]+|\b[\w.-]+\.(?:ts|tsx|js|jsx|json|md|yml|yaml|py|go|rs|sql|sh)\b/g;
22
+ function truncate(value, maxLength = 140) {
23
+ const trimmed = value.trim();
24
+ if (trimmed.length <= maxLength) {
25
+ return trimmed;
26
+ }
27
+ return `${trimmed.slice(0, maxLength - 3)}...`;
28
+ }
29
+ function parseJson(value) {
30
+ if (!value) {
31
+ return null;
32
+ }
33
+ try {
34
+ return JSON.parse(value);
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function toStringArray(value) {
41
+ if (!Array.isArray(value)) {
42
+ return [];
43
+ }
44
+ return value.filter((item) => typeof item === "string");
45
+ }
46
+ function getString(value) {
47
+ return typeof value === "string" && value.trim() ? value.trim() : null;
48
+ }
49
+ function getPrimaryCommand(text) {
50
+ const normalized = text.trim().toLowerCase();
51
+ for (const prefix of COMMAND_PREFIXES) {
52
+ if (normalized === prefix ||
53
+ normalized.startsWith(`${prefix} `) ||
54
+ normalized.includes(` ${prefix} `)) {
55
+ return prefix;
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function normalizeWhitespace(value) {
61
+ return value.trim().replace(/\s+/g, " ");
62
+ }
63
+ function sanitizeIssueKey(value) {
64
+ return value
65
+ .trim()
66
+ .toLowerCase()
67
+ .replace(/[^a-z0-9]+/g, "-")
68
+ .replace(/^-+|-+$/g, "");
69
+ }
70
+ function resolveCommandParts(commandInput, argInput, fallbackText) {
71
+ let command = normalizeWhitespace(commandInput ?? "");
72
+ let args = [...argInput];
73
+ if (command && args.length === 0 && /\s/.test(command)) {
74
+ const [first, ...rest] = command.split(" ");
75
+ command = first;
76
+ args = rest;
77
+ }
78
+ const fallbackInvocation = normalizeWhitespace(fallbackText);
79
+ const joinedInvocation = normalizeWhitespace([command, ...args].filter(Boolean).join(" "));
80
+ const invocation = joinedInvocation || fallbackInvocation;
81
+ const primaryCommand = getPrimaryCommand(invocation) ?? (command || null);
82
+ if (args.length === 0 && invocation) {
83
+ const tokens = invocation.split(" ");
84
+ if (primaryCommand?.includes(" ")) {
85
+ const primaryTokens = primaryCommand.split(" ");
86
+ if (primaryTokens.every((token, index) => tokens[index]?.toLowerCase() === token)) {
87
+ args = tokens.slice(primaryTokens.length);
88
+ }
89
+ }
90
+ else if (primaryCommand && tokens[0]?.toLowerCase() === primaryCommand) {
91
+ args = tokens.slice(1);
92
+ }
93
+ }
94
+ return {
95
+ command: primaryCommand,
96
+ args,
97
+ invocation: invocation || "Command activity captured",
98
+ };
99
+ }
100
+ function getPackageManager(command) {
101
+ return command && /^(?:pnpm|npm|yarn|bun)$/i.test(command) ? command : null;
102
+ }
103
+ function getScriptName(packageManager, args) {
104
+ if (!packageManager) {
105
+ return null;
106
+ }
107
+ const scriptArgs = args.filter((arg) => arg && !arg.startsWith("-"));
108
+ if (scriptArgs.length === 0) {
109
+ return null;
110
+ }
111
+ if (["run", "exec", "dlx"].includes(scriptArgs[0])) {
112
+ return scriptArgs[1] ?? null;
113
+ }
114
+ return scriptArgs[0] ?? null;
115
+ }
116
+ function getPayloadText(payload) {
117
+ if (!payload) {
118
+ return [];
119
+ }
120
+ const textFields = [
121
+ "stderr",
122
+ "stdout",
123
+ "output",
124
+ "error",
125
+ "message",
126
+ "details",
127
+ ];
128
+ return textFields
129
+ .map((key) => payload[key])
130
+ .filter((value) => typeof value === "string" && Boolean(value.trim()));
131
+ }
132
+ function extractDependencyMetadata(category, packageManager, args) {
133
+ if (category !== "install" || !packageManager) {
134
+ return { dependencyAction: null, dependencyNames: [] };
135
+ }
136
+ const tokens = args.filter((arg) => Boolean(arg));
137
+ const actionIndex = tokens.findIndex((token) => !token.startsWith("-"));
138
+ if (actionIndex === -1) {
139
+ return { dependencyAction: "install", dependencyNames: [] };
140
+ }
141
+ const actionToken = tokens[actionIndex].toLowerCase();
142
+ const normalizedAction = actionToken === "add"
143
+ ? "add"
144
+ : ["remove", "rm", "uninstall"].includes(actionToken)
145
+ ? "remove"
146
+ : ["upgrade", "up", "update"].includes(actionToken)
147
+ ? "update"
148
+ : "install";
149
+ const dependencyNames = tokens
150
+ .slice(actionIndex + 1)
151
+ .filter((token) => token &&
152
+ !token.startsWith("-") &&
153
+ !/^(?:install|add|remove|rm|uninstall|upgrade|up|update)$/i.test(token));
154
+ return {
155
+ dependencyAction: normalizedAction,
156
+ dependencyNames,
157
+ };
158
+ }
159
+ function extractErrorCode(text) {
160
+ const tsMatch = text.match(/\bTS\d{3,5}\b/i);
161
+ if (tsMatch) {
162
+ return tsMatch[0].toUpperCase();
163
+ }
164
+ const nodeMatch = text.match(/\b(?:E[A-Z0-9]{3,}|ERR_[A-Z0-9_]+)\b/);
165
+ return nodeMatch?.[0] ?? null;
166
+ }
167
+ function extractLintRuleId(text, category) {
168
+ if (category !== "lint") {
169
+ return null;
170
+ }
171
+ const lines = text.split(/\r?\n/).reverse();
172
+ const lintRulePattern = /(?:^|\s)(?:\d+:\d+\s+)?(?:error|warning)\s+.+?(?:\s{2,}|\t+)((?:@[\w-]+\/)?[a-z][\w-]*(?:\/[a-z][\w-]*)?(?:-[a-z0-9][\w-]*)*)\s*$/i;
173
+ for (const line of lines) {
174
+ const match = line.match(lintRulePattern);
175
+ if (match?.[1]) {
176
+ return match[1];
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ function extractTestIdentifiers(text) {
182
+ const explicitLine = text
183
+ .split(/\r?\n/)
184
+ .find((candidate) => /\b(?:FAIL|PASS)\b/i.test(candidate));
185
+ if (!explicitLine) {
186
+ return { testSuite: null, testCase: null };
187
+ }
188
+ const line = explicitLine;
189
+ const normalized = normalizeWhitespace(line.replace(/^\s*(?:FAIL|PASS)\s+/i, ""));
190
+ if (!normalized) {
191
+ return { testSuite: null, testCase: null };
192
+ }
193
+ const [suitePart, ...caseParts] = normalized
194
+ .split(/\s+>\s+/)
195
+ .map((part) => truncate(part, 96));
196
+ return {
197
+ testSuite: suitePart ?? null,
198
+ testCase: caseParts.length > 0 ? caseParts.join(" > ") : null,
199
+ };
200
+ }
201
+ function extractFailureSignature(text, category) {
202
+ const errorCode = extractErrorCode(text);
203
+ const lintRuleId = extractLintRuleId(text, category);
204
+ if (lintRuleId) {
205
+ return {
206
+ failureSignatureKey: `lint-rule:${sanitizeIssueKey(lintRuleId)}`,
207
+ failureSignatureLabel: `ESLint ${lintRuleId}`,
208
+ errorCode,
209
+ lintRuleId,
210
+ };
211
+ }
212
+ if (errorCode?.startsWith("TS")) {
213
+ return {
214
+ failureSignatureKey: `typescript:${sanitizeIssueKey(errorCode)}`,
215
+ failureSignatureLabel: `TypeScript ${errorCode}`,
216
+ errorCode,
217
+ lintRuleId: null,
218
+ };
219
+ }
220
+ const signatures = [
221
+ {
222
+ pattern: /\b(?:EACCES|EPERM|permission denied)\b/i,
223
+ key: "permission-denied",
224
+ label: "Permission denied",
225
+ },
226
+ {
227
+ pattern: /\b(?:ENOTFOUND|ECONNRESET|EAI_AGAIN|network error|connection refused)\b/i,
228
+ key: "network",
229
+ label: "Network failure",
230
+ },
231
+ {
232
+ pattern: /\b(?:cannot find module|module not found|cannot resolve)\b/i,
233
+ key: "module-not-found",
234
+ label: "Module not found",
235
+ },
236
+ {
237
+ pattern: /\b(?:command not found|missing script|script not found)\b/i,
238
+ key: "missing-command",
239
+ label: "Command or script missing",
240
+ },
241
+ {
242
+ pattern: /\b(?:timed? out|timeout)\b/i,
243
+ key: "timeout",
244
+ label: "Timeout",
245
+ },
246
+ {
247
+ pattern: /\b(?:unauthorized|forbidden|401|403)\b/i,
248
+ key: "auth",
249
+ label: "Authentication or authorization failure",
250
+ },
251
+ {
252
+ pattern: /\bassert(?:ion(?:error)?)?\b/i,
253
+ key: "assertion",
254
+ label: "Assertion failure",
255
+ },
256
+ ];
257
+ const matched = signatures.find((signature) => signature.pattern.test(text));
258
+ if (matched) {
259
+ return {
260
+ failureSignatureKey: category === "command" ? matched.key : `${category}:${matched.key}`,
261
+ failureSignatureLabel: matched.label,
262
+ errorCode,
263
+ lintRuleId: null,
264
+ };
265
+ }
266
+ return {
267
+ failureSignatureKey: errorCode
268
+ ? `${category}:${sanitizeIssueKey(errorCode)}`
269
+ : null,
270
+ failureSignatureLabel: errorCode ? `Error code ${errorCode}` : null,
271
+ errorCode,
272
+ lintRuleId: null,
273
+ };
274
+ }
275
+ function classifyCommandCategory(text) {
276
+ if (/\b(?:vitest|jest|pytest|cargo test|go test|pnpm test|npm test|yarn test|bun test)\b/i.test(text)) {
277
+ return "test";
278
+ }
279
+ if (/\b(?:typecheck|tsc(?:\s|$)|tsc --noEmit|vue-tsc)\b/i.test(text)) {
280
+ return "typecheck";
281
+ }
282
+ if (/\b(?:lint|eslint|oxlint|biome check|ruff check)\b/i.test(text)) {
283
+ return "lint";
284
+ }
285
+ if (/\b(?:build|vite build|next build|rollup|webpack|tsup)\b/i.test(text)) {
286
+ return "build";
287
+ }
288
+ if (/\b(?:format|prettier|biome format|ruff format|cargo fmt|gofmt)\b/i.test(text)) {
289
+ return "format";
290
+ }
291
+ if (/\b(?:pnpm|npm|yarn|bun)\b/i.test(text) &&
292
+ /\b(?:install|add|remove|upgrade|update|dedupe|prune|unlink|link)\b/i.test(text)) {
293
+ return "install";
294
+ }
295
+ if (/\b(?:migrate|migration|db push|prisma(?:\s+db\s+push|\s+migrate)|drizzle-kit|alembic|flyway|sequelize db:migrate|knex migrate)\b/i.test(text)) {
296
+ return "migration";
297
+ }
298
+ if (/\b(?:deploy|release|publish|wrangler deploy|vercel(?:\s|$)|docker push|kubectl apply|terraform apply)\b/i.test(text)) {
299
+ return "deploy";
300
+ }
301
+ if (/\b(?:dev|start|serve|preview|watch)\b/i.test(text) &&
302
+ /\b(?:pnpm|npm|yarn|bun|vite|next|wrangler)\b/i.test(text)) {
303
+ return "dev-server";
304
+ }
305
+ if (/\bgit\b/i.test(text)) {
306
+ return "git";
307
+ }
308
+ if (/\b(?:docker|podman|kubectl|helm)\b/i.test(text)) {
309
+ return "container";
310
+ }
311
+ if (/\b(?:pnpm|npm|yarn|bun|npx)\b/i.test(text)) {
312
+ return "package-manager";
313
+ }
314
+ if (/\b(?:node|python|tsx|bash|sh|deno)\b/i.test(text)) {
315
+ return "runtime";
316
+ }
317
+ return "command";
318
+ }
319
+ function classifyCommandFamily(command, invocation) {
320
+ if (getPackageManager(command)) {
321
+ return "package-manager";
322
+ }
323
+ if (command === "git") {
324
+ return "git";
325
+ }
326
+ if (/\b(?:docker|podman|kubectl|helm)\b/i.test(invocation)) {
327
+ return "container";
328
+ }
329
+ if (command &&
330
+ /^(?:node|python|tsx|bash|sh|deno|pytest|vitest|jest|cargo test|go test)$/i.test(command)) {
331
+ return "runtime";
332
+ }
333
+ if (command === "make") {
334
+ return "task-runner";
335
+ }
336
+ return "command";
337
+ }
338
+ function humanizeKey(value) {
339
+ return value.replace(/-/g, " ");
340
+ }
341
+ function buildIssueFamilyIdentity(options) {
342
+ if (["command", "package-manager"].includes(options.category)) {
343
+ return { issueFamilyKey: null, issueFamilyLabel: null };
344
+ }
345
+ let familyBase = null;
346
+ let familyLabel = null;
347
+ if (options.category === "test") {
348
+ if (options.framework && options.framework !== "generic") {
349
+ familyBase = options.framework;
350
+ familyLabel = `${options.framework} tests`;
351
+ }
352
+ else if (options.packageManager) {
353
+ familyBase = options.packageManager;
354
+ familyLabel = `${options.packageManager} tests`;
355
+ }
356
+ else if (options.commandFamily && options.commandFamily !== "command") {
357
+ familyBase = options.commandFamily;
358
+ familyLabel = `${humanizeKey(options.commandFamily)} tests`;
359
+ }
360
+ else if (options.command) {
361
+ familyBase = options.command;
362
+ familyLabel = `${options.command} tests`;
363
+ }
364
+ }
365
+ else if (options.category === "migration") {
366
+ if (options.scriptName && options.scriptName !== "migrate") {
367
+ familyBase = options.scriptName;
368
+ familyLabel = `${options.scriptName} migrations`;
369
+ }
370
+ else if (options.command) {
371
+ familyBase = options.command;
372
+ familyLabel = `${options.command} migrations`;
373
+ }
374
+ }
375
+ else if (options.category === "deploy") {
376
+ if (options.command) {
377
+ familyBase = options.command;
378
+ familyLabel = `${options.command} deploy`;
379
+ }
380
+ }
381
+ else if (options.packageManager) {
382
+ familyBase = options.packageManager;
383
+ familyLabel = `${options.packageManager} ${humanizeKey(options.category)}`;
384
+ }
385
+ else if (options.commandFamily && options.commandFamily !== "command") {
386
+ familyBase = options.commandFamily;
387
+ familyLabel = `${humanizeKey(options.commandFamily)} ${humanizeKey(options.category)}`;
388
+ }
389
+ else if (options.command) {
390
+ familyBase = options.command;
391
+ familyLabel = `${options.command} ${humanizeKey(options.category)}`;
392
+ }
393
+ const sanitized = familyBase ? sanitizeIssueKey(familyBase) : "";
394
+ return {
395
+ issueFamilyKey: sanitized
396
+ ? `${options.category}-family:${sanitized}`
397
+ : null,
398
+ issueFamilyLabel: familyLabel ? truncate(familyLabel, 96) : null,
399
+ };
400
+ }
401
+ function buildIssueIdentity(options) {
402
+ if (["command", "package-manager"].includes(options.category)) {
403
+ return {
404
+ issueKey: null,
405
+ issueLabel: null,
406
+ issueFamilyKey: null,
407
+ issueFamilyLabel: null,
408
+ };
409
+ }
410
+ const issueBase = options.packageManager &&
411
+ options.scriptName &&
412
+ [
413
+ "test",
414
+ "lint",
415
+ "typecheck",
416
+ "build",
417
+ "format",
418
+ "install",
419
+ "dev-server",
420
+ ].includes(options.category)
421
+ ? `${options.packageManager} ${options.scriptName}`
422
+ : options.invocation;
423
+ const normalizedBase = normalizeWhitespace(issueBase);
424
+ if (!normalizedBase) {
425
+ return {
426
+ issueKey: null,
427
+ issueLabel: null,
428
+ ...buildIssueFamilyIdentity(options),
429
+ };
430
+ }
431
+ const issueLabel = options.category === "test" &&
432
+ options.framework &&
433
+ options.framework !== "generic"
434
+ ? truncate(`${normalizedBase} / ${options.framework}`, 96)
435
+ : truncate(normalizedBase, 96);
436
+ const issueKeyBase = options.packageManager &&
437
+ options.scriptName &&
438
+ [
439
+ "test",
440
+ "lint",
441
+ "typecheck",
442
+ "build",
443
+ "format",
444
+ "install",
445
+ "dev-server",
446
+ ].includes(options.category)
447
+ ? `${options.packageManager} ${options.scriptName}`
448
+ : normalizedBase;
449
+ const sanitized = sanitizeIssueKey(issueKeyBase);
450
+ return {
451
+ issueKey: sanitized ? `${options.category}:${sanitized}` : null,
452
+ issueLabel,
453
+ ...buildIssueFamilyIdentity(options),
454
+ };
455
+ }
456
+ function classifyTestFramework(text) {
457
+ if (/\bvitest\b/i.test(text)) {
458
+ return "vitest";
459
+ }
460
+ if (/\bjest\b/i.test(text)) {
461
+ return "jest";
462
+ }
463
+ if (/\bpytest\b/i.test(text)) {
464
+ return "pytest";
465
+ }
466
+ if (/\bcargo test\b/i.test(text)) {
467
+ return "cargo";
468
+ }
469
+ if (/\bgo test\b/i.test(text)) {
470
+ return "go-test";
471
+ }
472
+ return "generic";
473
+ }
474
+ function classifyPathCategory(filePath) {
475
+ if (!filePath) {
476
+ return null;
477
+ }
478
+ if (/(^|\/)(README|CHANGELOG|LICENSE)\b|\.md$/i.test(filePath)) {
479
+ return "docs";
480
+ }
481
+ if (/(^|\/)(package|tsconfig|eslint|vite|vitest|pnpm-lock)\b|\.ya?ml$/i.test(filePath)) {
482
+ return "config";
483
+ }
484
+ if (/(^|\/)(tests?|__tests__|fixtures?)\//i.test(filePath) ||
485
+ /\.(test|spec)\./i.test(filePath)) {
486
+ return "test";
487
+ }
488
+ if (/\.(sql|prisma)$/i.test(filePath)) {
489
+ return "schema";
490
+ }
491
+ return "source";
492
+ }
493
+ function classifyChangeScope(filePath) {
494
+ if (!filePath) {
495
+ return null;
496
+ }
497
+ if (/(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Pipfile|Cargo\.toml|go\.mod)$/i.test(filePath)) {
498
+ return "dependency-manifest";
499
+ }
500
+ if (/(^|\/)(pnpm-lock\.ya?ml|package-lock\.json|yarn\.lock|bun\.lockb|Pipfile\.lock|poetry\.lock|Cargo\.lock|go\.sum)$/i.test(filePath)) {
501
+ return "dependency-lockfile";
502
+ }
503
+ if (/(^|\/)(migrations?|prisma|drizzle)\//i.test(filePath) ||
504
+ /\.(sql|prisma)$/i.test(filePath)) {
505
+ return "migration";
506
+ }
507
+ return classifyPathCategory(filePath);
508
+ }
509
+ function getManifestKind(filePath) {
510
+ if (!filePath) {
511
+ return null;
512
+ }
513
+ const segments = filePath.split("/");
514
+ return segments.at(-1) ?? null;
515
+ }
516
+ function inferOutcome(status, payload) {
517
+ if (typeof payload?.exitCode === "number") {
518
+ return payload.exitCode === 0 ? "succeeded" : "failed";
519
+ }
520
+ if (typeof payload?.passed === "boolean") {
521
+ return payload.passed ? "passed" : "failed";
522
+ }
523
+ if (!status) {
524
+ return null;
525
+ }
526
+ if (/^(?:completed|captured|success|succeeded)$/i.test(status)) {
527
+ return "succeeded";
528
+ }
529
+ if (/^passed$/i.test(status)) {
530
+ return "passed";
531
+ }
532
+ if (/^(?:failed|error|parse-error|interrupted)$/i.test(status)) {
533
+ return "failed";
534
+ }
535
+ if (/^running$/i.test(status)) {
536
+ return "running";
537
+ }
538
+ return status.toLowerCase();
539
+ }
540
+ function buildCommandMetadata(sourceRefs, payload, options) {
541
+ const resolved = resolveCommandParts(getString(payload?.command), toStringArray(payload?.args), options.content ?? options.summary ?? "Command activity captured");
542
+ const payloadText = getPayloadText(payload);
543
+ const textCorpus = [
544
+ resolved.invocation,
545
+ resolved.command ?? "",
546
+ ...resolved.args,
547
+ options.summary ?? "",
548
+ options.content ?? "",
549
+ ...payloadText,
550
+ ].join("\n");
551
+ const category = classifyCommandCategory(textCorpus);
552
+ const commandFamily = classifyCommandFamily(resolved.command, resolved.invocation);
553
+ const packageManager = getPackageManager(resolved.command);
554
+ const scriptName = getScriptName(packageManager, resolved.args);
555
+ const outcome = inferOutcome(options.status ?? null, payload);
556
+ const dependencyMetadata = extractDependencyMetadata(category, packageManager, resolved.args);
557
+ const framework = category === "test" ? classifyTestFramework(textCorpus) : null;
558
+ const testIdentifiers = category === "test"
559
+ ? extractTestIdentifiers(textCorpus)
560
+ : { testSuite: null, testCase: null };
561
+ const failureSignature = outcome === "failed"
562
+ ? extractFailureSignature(textCorpus, category)
563
+ : {
564
+ failureSignatureKey: null,
565
+ failureSignatureLabel: null,
566
+ errorCode: null,
567
+ lintRuleId: null,
568
+ };
569
+ const issueIdentity = buildIssueIdentity({
570
+ category,
571
+ command: resolved.command,
572
+ commandFamily,
573
+ invocation: resolved.invocation,
574
+ packageManager,
575
+ scriptName,
576
+ framework,
577
+ });
578
+ const invocation = truncate(options.summary ?? resolved.invocation);
579
+ return {
580
+ sourceRefs,
581
+ eventType: options.eventType ?? null,
582
+ eventSubType: options.eventSubType ?? null,
583
+ summary: invocation,
584
+ category,
585
+ intent: category,
586
+ commandFamily,
587
+ command: resolved.command,
588
+ args: resolved.args,
589
+ framework,
590
+ packageManager,
591
+ scriptName,
592
+ ...dependencyMetadata,
593
+ ...testIdentifiers,
594
+ ...failureSignature,
595
+ ...issueIdentity,
596
+ status: options.status ?? null,
597
+ outcome,
598
+ payload,
599
+ content: options.content ?? null,
600
+ role: options.role ?? null,
601
+ source: options.source ?? null,
602
+ };
603
+ }
604
+ function buildTestMetadata(sourceRefs, payload, options) {
605
+ const commandInput = getString(payload?.command);
606
+ const payloadText = getPayloadText(payload);
607
+ const resolved = resolveCommandParts(commandInput, toStringArray(payload?.args), [options.summary ?? "", options.content ?? "", commandInput ?? ""].join(" "));
608
+ const summary = truncate(options.summary ?? options.content ?? "Test activity captured");
609
+ const haystack = [
610
+ summary,
611
+ options.content ?? "",
612
+ resolved.invocation,
613
+ ...payloadText,
614
+ ].join("\n");
615
+ const framework = classifyTestFramework(haystack);
616
+ const packageManager = getPackageManager(resolved.command);
617
+ const scriptName = getScriptName(packageManager, resolved.args);
618
+ const commandFamily = classifyCommandFamily(resolved.command, resolved.invocation);
619
+ const outcome = inferOutcome(options.status ?? null, payload);
620
+ const testIdentifiers = extractTestIdentifiers(haystack);
621
+ const failureSignature = outcome === "failed"
622
+ ? extractFailureSignature(haystack, "test")
623
+ : {
624
+ failureSignatureKey: null,
625
+ failureSignatureLabel: null,
626
+ errorCode: null,
627
+ lintRuleId: null,
628
+ };
629
+ const issueIdentity = buildIssueIdentity({
630
+ category: "test",
631
+ command: resolved.command,
632
+ commandFamily,
633
+ invocation: resolved.invocation || summary,
634
+ packageManager,
635
+ scriptName,
636
+ framework,
637
+ });
638
+ return {
639
+ sourceRefs,
640
+ eventType: options.eventType ?? null,
641
+ summary,
642
+ category: "test",
643
+ intent: "test",
644
+ commandFamily,
645
+ command: resolved.command,
646
+ args: resolved.args,
647
+ framework,
648
+ packageManager,
649
+ scriptName,
650
+ ...testIdentifiers,
651
+ ...failureSignature,
652
+ ...issueIdentity,
653
+ status: options.status ?? null,
654
+ outcome,
655
+ passed: typeof payload?.passed === "boolean"
656
+ ? payload.passed
657
+ : /^passed$/i.test(options.status ?? ""),
658
+ payload,
659
+ content: options.content ?? null,
660
+ role: options.role ?? null,
661
+ source: options.source ?? null,
662
+ markers: options.content
663
+ ? {
664
+ failed: DECISIONLESS_ERROR_PATTERN.test(options.content),
665
+ }
666
+ : undefined,
667
+ };
668
+ }
669
+ function buildFileMetadata(sourceRefs, filePath, payload, options) {
670
+ return {
671
+ sourceRefs,
672
+ eventType: options.eventType ?? null,
673
+ summary: truncate(options.summary ??
674
+ (filePath
675
+ ? `File changed: ${filePath}`
676
+ : (options.content ?? "File change captured"))),
677
+ category: "file-change",
678
+ pathCategory: classifyPathCategory(filePath),
679
+ changeScope: classifyChangeScope(filePath),
680
+ manifestKind: getManifestKind(filePath),
681
+ status: options.status ?? null,
682
+ payload,
683
+ content: options.content ?? null,
684
+ };
685
+ }
686
+ function buildGitMetadata(sourceRefs, payload, options) {
687
+ return {
688
+ sourceRefs,
689
+ eventType: options.eventType ?? null,
690
+ summary: truncate(options.summary ?? "Git commit captured"),
691
+ category: "git",
692
+ status: options.status ?? null,
693
+ previousHead: getString(payload?.previousHead),
694
+ currentHead: getString(payload?.currentHead),
695
+ payload,
696
+ };
697
+ }
698
+ function getEventForMessage(detail, message) {
699
+ return (detail.timeline.find((event) => event.relatedMessageId === message.id) ??
700
+ null);
701
+ }
702
+ function makeSourceRefs(...refs) {
703
+ const seen = new Set();
704
+ return refs.filter((ref) => {
705
+ const key = `${ref.type}:${ref.id}`;
706
+ if (seen.has(key)) {
707
+ return false;
708
+ }
709
+ seen.add(key);
710
+ return true;
711
+ });
712
+ }
713
+ function fromTimelineEvent(event) {
714
+ if (event.eventType.startsWith("command.")) {
715
+ const payload = parseJson(event.payload);
716
+ return {
717
+ artifactType: "command-output",
718
+ path: null,
719
+ eventId: event.id,
720
+ metadata: buildCommandMetadata(makeSourceRefs({ type: "event", id: event.id }), payload, {
721
+ eventType: event.eventType,
722
+ eventSubType: event.eventSubType,
723
+ summary: event.summary,
724
+ status: event.status,
725
+ }),
726
+ };
727
+ }
728
+ if (event.eventType.startsWith("test.")) {
729
+ const payload = parseJson(event.payload);
730
+ return {
731
+ artifactType: "test-result",
732
+ path: null,
733
+ eventId: event.id,
734
+ metadata: buildTestMetadata(makeSourceRefs({ type: "event", id: event.id }), payload, {
735
+ eventType: event.eventType,
736
+ summary: event.summary,
737
+ status: event.status,
738
+ }),
739
+ };
740
+ }
741
+ if (event.eventType === "file.changed") {
742
+ const payload = parseJson(event.payload);
743
+ const filePath = typeof payload?.path === "string" ? payload.path : null;
744
+ return {
745
+ artifactType: "file-change",
746
+ path: filePath,
747
+ eventId: event.id,
748
+ metadata: buildFileMetadata(makeSourceRefs({ type: "event", id: event.id }), filePath, payload, {
749
+ eventType: event.eventType,
750
+ summary: event.summary,
751
+ status: event.status,
752
+ }),
753
+ };
754
+ }
755
+ if (event.eventType === "git.commit") {
756
+ const payload = parseJson(event.payload);
757
+ return {
758
+ artifactType: "git-commit",
759
+ path: null,
760
+ eventId: event.id,
761
+ metadata: buildGitMetadata(makeSourceRefs({ type: "event", id: event.id }), payload, {
762
+ eventType: event.eventType,
763
+ summary: event.summary,
764
+ status: event.status,
765
+ }),
766
+ };
767
+ }
768
+ return null;
769
+ }
770
+ function fromMessage(detail, message) {
771
+ const event = getEventForMessage(detail, message);
772
+ const refs = makeSourceRefs({ type: "message", id: message.id }, ...(event ? [{ type: "event", id: event.id }] : []));
773
+ const candidates = [];
774
+ if (COMMAND_PATTERN.test(message.content)) {
775
+ candidates.push({
776
+ artifactType: "command-output",
777
+ path: null,
778
+ eventId: event?.id ?? null,
779
+ metadata: buildCommandMetadata(refs, null, {
780
+ summary: message.content,
781
+ content: message.content,
782
+ role: message.role,
783
+ source: message.source,
784
+ }),
785
+ });
786
+ }
787
+ if (TEST_PATTERN.test(message.content)) {
788
+ candidates.push({
789
+ artifactType: "test-result",
790
+ path: null,
791
+ eventId: event?.id ?? null,
792
+ metadata: buildTestMetadata(refs, null, {
793
+ summary: message.content,
794
+ content: message.content,
795
+ role: message.role,
796
+ source: message.source,
797
+ }),
798
+ });
799
+ }
800
+ const fileMatches = message.content.match(FILE_PATTERN) ?? [];
801
+ for (const filePath of [...new Set(fileMatches)]) {
802
+ candidates.push({
803
+ artifactType: "file-change",
804
+ path: filePath,
805
+ eventId: event?.id ?? null,
806
+ metadata: buildFileMetadata(refs, filePath, null, {
807
+ summary: `Referenced file: ${filePath}`,
808
+ content: message.content,
809
+ }),
810
+ });
811
+ }
812
+ return candidates;
813
+ }
814
+ export function runDeterministicIngestion(db, sessionId) {
815
+ const detail = db.getSessionDetail(sessionId);
816
+ if (!detail) {
817
+ throw new Error(`Session not found: ${sessionId}`);
818
+ }
819
+ const run = db.createIngestionRun({
820
+ sessionId,
821
+ stage: "deterministic",
822
+ status: "running",
823
+ });
824
+ try {
825
+ const artifactCandidates = [];
826
+ for (const event of detail.timeline) {
827
+ const candidate = fromTimelineEvent(event);
828
+ if (candidate) {
829
+ artifactCandidates.push(candidate);
830
+ }
831
+ }
832
+ for (const message of detail.messages) {
833
+ artifactCandidates.push(...fromMessage(detail, message));
834
+ }
835
+ const deduped = new Map();
836
+ for (const artifact of artifactCandidates) {
837
+ const key = [
838
+ artifact.artifactType,
839
+ artifact.eventId ?? "",
840
+ artifact.path ?? "",
841
+ JSON.stringify(artifact.metadata),
842
+ ].join("|");
843
+ if (!deduped.has(key)) {
844
+ deduped.set(key, {
845
+ sessionId,
846
+ eventId: artifact.eventId,
847
+ artifactType: artifact.artifactType,
848
+ path: artifact.path,
849
+ metadata: JSON.stringify(artifact.metadata),
850
+ });
851
+ }
852
+ }
853
+ const artifacts = db.replaceArtifactsForSession(sessionId, Array.from(deduped.values()));
854
+ db.completeIngestionRun(run.id, "completed");
855
+ return artifacts;
856
+ }
857
+ catch (error) {
858
+ db.completeIngestionRun(run.id, "failed", error instanceof Error ? error.message : String(error));
859
+ throw error;
860
+ }
861
+ }
862
+ //# sourceMappingURL=deterministic.js.map