waterplane 0.1.24 → 0.1.26

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 (429) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/SECURITY.md +25 -5
  3. package/node_modules/@waterplane/shared/dist/agentseries/compare.d.ts +8 -0
  4. package/node_modules/@waterplane/shared/dist/agentseries/compare.js +103 -0
  5. package/node_modules/@waterplane/shared/dist/agentseries/compare.js.map +1 -0
  6. package/node_modules/@waterplane/shared/dist/agentseries/markers.d.ts +17 -0
  7. package/node_modules/@waterplane/shared/dist/agentseries/markers.js +125 -0
  8. package/node_modules/@waterplane/shared/dist/agentseries/markers.js.map +1 -0
  9. package/node_modules/@waterplane/shared/dist/agentseries/series.d.ts +16 -0
  10. package/node_modules/@waterplane/shared/dist/agentseries/series.js +93 -0
  11. package/node_modules/@waterplane/shared/dist/agentseries/series.js.map +1 -0
  12. package/node_modules/@waterplane/shared/dist/agentseries/stats.d.ts +8 -0
  13. package/node_modules/@waterplane/shared/dist/agentseries/stats.js +33 -0
  14. package/node_modules/@waterplane/shared/dist/agentseries/stats.js.map +1 -0
  15. package/node_modules/@waterplane/shared/dist/agentseries/types.d.ts +103 -0
  16. package/node_modules/@waterplane/shared/dist/agentseries/types.js +11 -0
  17. package/node_modules/@waterplane/shared/dist/agentseries/types.js.map +1 -0
  18. package/node_modules/@waterplane/shared/dist/agentseries.d.ts +10 -0
  19. package/node_modules/@waterplane/shared/dist/agentseries.js +11 -0
  20. package/node_modules/@waterplane/shared/dist/agentseries.js.map +1 -0
  21. package/node_modules/@waterplane/shared/dist/calday.d.ts +5 -0
  22. package/node_modules/@waterplane/shared/dist/calday.js +10 -0
  23. package/node_modules/@waterplane/shared/dist/calday.js.map +1 -1
  24. package/node_modules/@waterplane/shared/dist/clihealth/healthfixture.d.ts +13 -1
  25. package/node_modules/@waterplane/shared/dist/clihealth/healthfixture.js +22 -4
  26. package/node_modules/@waterplane/shared/dist/clihealth/healthfixture.js.map +1 -1
  27. package/node_modules/@waterplane/shared/dist/clihealth.d.ts +1 -1
  28. package/node_modules/@waterplane/shared/dist/clihealth.js +1 -1
  29. package/node_modules/@waterplane/shared/dist/clihealth.js.map +1 -1
  30. package/node_modules/@waterplane/shared/dist/dictate.d.ts +6 -0
  31. package/node_modules/@waterplane/shared/dist/dictate.js.map +1 -1
  32. package/node_modules/@waterplane/shared/dist/dictatemodels.d.ts +23 -0
  33. package/node_modules/@waterplane/shared/dist/dictatemodels.js +31 -0
  34. package/node_modules/@waterplane/shared/dist/dictatemodels.js.map +1 -0
  35. package/node_modules/@waterplane/shared/dist/healthindex/commits.d.ts +1 -1
  36. package/node_modules/@waterplane/shared/dist/healthindex/commits.js +2 -2
  37. package/node_modules/@waterplane/shared/dist/healthindex/commits.js.map +1 -1
  38. package/node_modules/@waterplane/shared/dist/healthindex/coverage.d.ts +128 -0
  39. package/node_modules/@waterplane/shared/dist/healthindex/coverage.js +343 -0
  40. package/node_modules/@waterplane/shared/dist/healthindex/coverage.js.map +1 -0
  41. package/node_modules/@waterplane/shared/dist/healthindex/readings.d.ts +9 -1
  42. package/node_modules/@waterplane/shared/dist/healthindex/readings.js +122 -4
  43. package/node_modules/@waterplane/shared/dist/healthindex/readings.js.map +1 -1
  44. package/node_modules/@waterplane/shared/dist/healthindex/repoindex.d.ts +5 -0
  45. package/node_modules/@waterplane/shared/dist/healthindex/repoindex.js +2 -0
  46. package/node_modules/@waterplane/shared/dist/healthindex/repoindex.js.map +1 -1
  47. package/node_modules/@waterplane/shared/dist/healthindex/score.d.ts +3 -0
  48. package/node_modules/@waterplane/shared/dist/healthindex/score.js +52 -16
  49. package/node_modules/@waterplane/shared/dist/healthindex/score.js.map +1 -1
  50. package/node_modules/@waterplane/shared/dist/healthindex/types.d.ts +82 -6
  51. package/node_modules/@waterplane/shared/dist/healthindex/types.js +35 -2
  52. package/node_modules/@waterplane/shared/dist/healthindex/types.js.map +1 -1
  53. package/node_modules/@waterplane/shared/dist/healthindex/words.js +65 -6
  54. package/node_modules/@waterplane/shared/dist/healthindex/words.js.map +1 -1
  55. package/node_modules/@waterplane/shared/dist/healthindex.d.ts +21 -7
  56. package/node_modules/@waterplane/shared/dist/healthindex.js +20 -7
  57. package/node_modules/@waterplane/shared/dist/healthindex.js.map +1 -1
  58. package/node_modules/@waterplane/shared/dist/healthindexresponse.js +3 -2
  59. package/node_modules/@waterplane/shared/dist/healthindexresponse.js.map +1 -1
  60. package/node_modules/@waterplane/shared/dist/healthspend.d.ts +23 -0
  61. package/node_modules/@waterplane/shared/dist/healthspend.js +32 -1
  62. package/node_modules/@waterplane/shared/dist/healthspend.js.map +1 -1
  63. package/node_modules/@waterplane/shared/dist/hints.js +9 -0
  64. package/node_modules/@waterplane/shared/dist/hints.js.map +1 -1
  65. package/node_modules/@waterplane/shared/dist/index.d.ts +9 -0
  66. package/node_modules/@waterplane/shared/dist/index.js +9 -0
  67. package/node_modules/@waterplane/shared/dist/index.js.map +1 -1
  68. package/node_modules/@waterplane/shared/dist/installrow.js +10 -0
  69. package/node_modules/@waterplane/shared/dist/installrow.js.map +1 -1
  70. package/node_modules/@waterplane/shared/dist/intent/kind.d.ts +45 -1
  71. package/node_modules/@waterplane/shared/dist/intent/kind.js +60 -2
  72. package/node_modules/@waterplane/shared/dist/intent/kind.js.map +1 -1
  73. package/node_modules/@waterplane/shared/dist/intent.d.ts +1 -1
  74. package/node_modules/@waterplane/shared/dist/intent.js +1 -1
  75. package/node_modules/@waterplane/shared/dist/intent.js.map +1 -1
  76. package/node_modules/@waterplane/shared/dist/itempaths.d.ts +23 -0
  77. package/node_modules/@waterplane/shared/dist/itempaths.js +38 -0
  78. package/node_modules/@waterplane/shared/dist/itempaths.js.map +1 -1
  79. package/node_modules/@waterplane/shared/dist/pluginlaunch.d.ts +3 -2
  80. package/node_modules/@waterplane/shared/dist/pluginlaunch.js +1 -1
  81. package/node_modules/@waterplane/shared/dist/pluginlaunch.js.map +1 -1
  82. package/node_modules/@waterplane/shared/dist/pricelist.d.ts +57 -0
  83. package/node_modules/@waterplane/shared/dist/pricelist.js +128 -0
  84. package/node_modules/@waterplane/shared/dist/pricelist.js.map +1 -0
  85. package/node_modules/@waterplane/shared/dist/pricing.d.ts +86 -9
  86. package/node_modules/@waterplane/shared/dist/pricing.js +140 -20
  87. package/node_modules/@waterplane/shared/dist/pricing.js.map +1 -1
  88. package/node_modules/@waterplane/shared/dist/queue/queuelanestate.d.ts +14 -0
  89. package/node_modules/@waterplane/shared/dist/queue/queuelanestate.js +25 -0
  90. package/node_modules/@waterplane/shared/dist/queue/queuelanestate.js.map +1 -0
  91. package/node_modules/@waterplane/shared/dist/queue/queueplan.d.ts +4 -0
  92. package/node_modules/@waterplane/shared/dist/queue/queueplan.js +21 -0
  93. package/node_modules/@waterplane/shared/dist/queue/queueplan.js.map +1 -1
  94. package/node_modules/@waterplane/shared/dist/queue/queuewords.js +2 -1
  95. package/node_modules/@waterplane/shared/dist/queue/queuewords.js.map +1 -1
  96. package/node_modules/@waterplane/shared/dist/queue.d.ts +2 -0
  97. package/node_modules/@waterplane/shared/dist/queue.js +1 -0
  98. package/node_modules/@waterplane/shared/dist/queue.js.map +1 -1
  99. package/node_modules/@waterplane/shared/dist/repohealth.d.ts +178 -0
  100. package/node_modules/@waterplane/shared/dist/repohealth.js.map +1 -1
  101. package/node_modules/@waterplane/shared/dist/repohealthhabits.d.ts +15 -0
  102. package/node_modules/@waterplane/shared/dist/repohealthhabits.js +117 -0
  103. package/node_modules/@waterplane/shared/dist/repohealthhabits.js.map +1 -0
  104. package/node_modules/@waterplane/shared/dist/repohealthnative.d.ts +10 -0
  105. package/node_modules/@waterplane/shared/dist/repohealthnative.js +94 -0
  106. package/node_modules/@waterplane/shared/dist/repohealthnative.js.map +1 -0
  107. package/node_modules/@waterplane/shared/dist/repohealthread.js +23 -1
  108. package/node_modules/@waterplane/shared/dist/repohealthread.js.map +1 -1
  109. package/node_modules/@waterplane/shared/dist/skillstate.d.ts +51 -0
  110. package/node_modules/@waterplane/shared/dist/skillstate.js +176 -0
  111. package/node_modules/@waterplane/shared/dist/skillstate.js.map +1 -0
  112. package/node_modules/@waterplane/shared/dist/skillwords.d.ts +10 -0
  113. package/node_modules/@waterplane/shared/dist/skillwords.js +18 -0
  114. package/node_modules/@waterplane/shared/dist/skillwords.js.map +1 -0
  115. package/node_modules/@waterplane/shared/dist/wire/agentreadings.d.ts +248 -0
  116. package/node_modules/@waterplane/shared/dist/wire/agentreadings.js +36 -0
  117. package/node_modules/@waterplane/shared/dist/wire/agentreadings.js.map +1 -0
  118. package/node_modules/@waterplane/shared/dist/wire/backend.d.ts +2 -0
  119. package/node_modules/@waterplane/shared/dist/wire/costwindow.d.ts +4 -0
  120. package/node_modules/@waterplane/shared/dist/wire/dictatesetup.d.ts +42 -0
  121. package/node_modules/@waterplane/shared/dist/wire/dictatesetup.js +9 -0
  122. package/node_modules/@waterplane/shared/dist/wire/dictatesetup.js.map +1 -0
  123. package/node_modules/@waterplane/shared/dist/wire/messages/hostcore.d.ts +22 -1
  124. package/node_modules/@waterplane/shared/dist/wire/notify.d.ts +6 -1
  125. package/node_modules/@waterplane/shared/dist/wire/notify.js +6 -1
  126. package/node_modules/@waterplane/shared/dist/wire/notify.js.map +1 -1
  127. package/node_modules/@waterplane/shared/dist/wire/repo.d.ts +1 -1
  128. package/node_modules/@waterplane/shared/dist/wire/skills.d.ts +142 -0
  129. package/node_modules/@waterplane/shared/dist/wire/skills.js +6 -0
  130. package/node_modules/@waterplane/shared/dist/wire/skills.js.map +1 -0
  131. package/node_modules/@waterplane/shared/dist/wire/sysstat.d.ts +17 -0
  132. package/node_modules/@waterplane/shared/dist/wire/telemetry.d.ts +4 -0
  133. package/npm-shrinkwrap.json +2 -2
  134. package/package.json +1 -1
  135. package/packages/extensions/diskspace/waterplane-plugin.json +16 -0
  136. package/packages/extensions/links/waterplane-plugin.json +18 -0
  137. package/packages/host/dist/agentclass.d.ts +116 -0
  138. package/packages/host/dist/agentclass.js +339 -0
  139. package/packages/host/dist/agentclass.js.map +1 -0
  140. package/packages/host/dist/agentintents.d.ts +18 -0
  141. package/packages/host/dist/agentintents.js +40 -7
  142. package/packages/host/dist/agentintents.js.map +1 -1
  143. package/packages/host/dist/agentmarkers.d.ts +49 -0
  144. package/packages/host/dist/agentmarkers.js +255 -0
  145. package/packages/host/dist/agentmarkers.js.map +1 -0
  146. package/packages/host/dist/agentreadings.d.ts +68 -0
  147. package/packages/host/dist/agentreadings.js +336 -0
  148. package/packages/host/dist/agentreadings.js.map +1 -0
  149. package/packages/host/dist/agentscan.d.ts +8 -0
  150. package/packages/host/dist/agentscan.js +427 -0
  151. package/packages/host/dist/agentscan.js.map +1 -0
  152. package/packages/host/dist/archive.js +9 -3
  153. package/packages/host/dist/archive.js.map +1 -1
  154. package/packages/host/dist/artifacts.js +4 -7
  155. package/packages/host/dist/artifacts.js.map +1 -1
  156. package/packages/host/dist/askrules.js +12 -4
  157. package/packages/host/dist/askrules.js.map +1 -1
  158. package/packages/host/dist/auth.d.ts +1 -0
  159. package/packages/host/dist/auth.js +5 -3
  160. package/packages/host/dist/auth.js.map +1 -1
  161. package/packages/host/dist/autopull.js +4 -8
  162. package/packages/host/dist/autopull.js.map +1 -1
  163. package/packages/host/dist/backends/claude.js +1 -0
  164. package/packages/host/dist/backends/claude.js.map +1 -1
  165. package/packages/host/dist/backends/derive.js +3 -1
  166. package/packages/host/dist/backends/derive.js.map +1 -1
  167. package/packages/host/dist/binguard.js +19 -2
  168. package/packages/host/dist/binguard.js.map +1 -1
  169. package/packages/host/dist/capture.js +7 -10
  170. package/packages/host/dist/capture.js.map +1 -1
  171. package/packages/host/dist/clifixtures.d.ts +24 -4
  172. package/packages/host/dist/clifixtures.js +50 -10
  173. package/packages/host/dist/clifixtures.js.map +1 -1
  174. package/packages/host/dist/clihealth.d.ts +8 -2
  175. package/packages/host/dist/clihealth.js +11 -3
  176. package/packages/host/dist/clihealth.js.map +1 -1
  177. package/packages/host/dist/costwindow.js +4 -2
  178. package/packages/host/dist/costwindow.js.map +1 -1
  179. package/packages/host/dist/ctxlog/ctxagents.d.ts +2 -0
  180. package/packages/host/dist/ctxlog/ctxagents.js +5 -5
  181. package/packages/host/dist/ctxlog/ctxagents.js.map +1 -1
  182. package/packages/host/dist/ctxlog/ctxcursor.d.ts +2 -0
  183. package/packages/host/dist/ctxlog/ctxcursor.js +2 -2
  184. package/packages/host/dist/ctxlog/ctxcursor.js.map +1 -1
  185. package/packages/host/dist/ctxlog/ctxupdate.js +11 -6
  186. package/packages/host/dist/ctxlog/ctxupdate.js.map +1 -1
  187. package/packages/host/dist/deliver/deliverknobs.d.ts +0 -2
  188. package/packages/host/dist/deliver/deliverknobs.js +0 -2
  189. package/packages/host/dist/deliver/deliverknobs.js.map +1 -1
  190. package/packages/host/dist/deliver/deliverproof.d.ts +3 -2
  191. package/packages/host/dist/deliver/deliverproof.js +9 -8
  192. package/packages/host/dist/deliver/deliverproof.js.map +1 -1
  193. package/packages/host/dist/deliver/deliverreturn.d.ts +3 -2
  194. package/packages/host/dist/deliver/deliverreturn.js +13 -12
  195. package/packages/host/dist/deliver/deliverreturn.js.map +1 -1
  196. package/packages/host/dist/deliver/deliverrun.js +20 -18
  197. package/packages/host/dist/deliver/deliverrun.js.map +1 -1
  198. package/packages/host/dist/deliver/deliverscreen.d.ts +2 -1
  199. package/packages/host/dist/deliver/deliverscreen.js +9 -8
  200. package/packages/host/dist/deliver/deliverscreen.js.map +1 -1
  201. package/packages/host/dist/deliver/delivertypes.d.ts +4 -0
  202. package/packages/host/dist/deliver.js +2 -1
  203. package/packages/host/dist/deliver.js.map +1 -1
  204. package/packages/host/dist/dictate.d.ts +11 -0
  205. package/packages/host/dist/dictate.js +20 -10
  206. package/packages/host/dist/dictate.js.map +1 -1
  207. package/packages/host/dist/dictatesetup.d.ts +54 -0
  208. package/packages/host/dist/dictatesetup.js +261 -0
  209. package/packages/host/dist/dictatesetup.js.map +1 -0
  210. package/packages/host/dist/doctor.js +1 -1
  211. package/packages/host/dist/doctor.js.map +1 -1
  212. package/packages/host/dist/exposure.d.ts +10 -0
  213. package/packages/host/dist/exposure.js +25 -0
  214. package/packages/host/dist/exposure.js.map +1 -1
  215. package/packages/host/dist/exposurepush.js +2 -2
  216. package/packages/host/dist/exposurepush.js.map +1 -1
  217. package/packages/host/dist/extensions/diskspace/host/candidates.d.mts +180 -0
  218. package/packages/host/dist/extensions/diskspace/host/candidates.mjs +716 -0
  219. package/packages/host/dist/extensions/diskspace/host/candidates.mjs.map +1 -0
  220. package/packages/host/dist/extensions/diskspace/host/engine.d.mts +21 -0
  221. package/packages/host/dist/extensions/diskspace/host/engine.mjs +498 -0
  222. package/packages/host/dist/extensions/diskspace/host/engine.mjs.map +1 -0
  223. package/packages/host/dist/extensions/diskspace/host/index.d.mts +25 -0
  224. package/packages/host/dist/extensions/diskspace/host/index.mjs +135 -0
  225. package/packages/host/dist/extensions/diskspace/host/index.mjs.map +1 -0
  226. package/packages/host/dist/extensions/diskspace/host/large.d.mts +11 -0
  227. package/packages/host/dist/extensions/diskspace/host/large.mjs +56 -0
  228. package/packages/host/dist/extensions/diskspace/host/large.mjs.map +1 -0
  229. package/packages/host/dist/extensions/diskspace/host/run.d.mts +94 -0
  230. package/packages/host/dist/extensions/diskspace/host/run.mjs +200 -0
  231. package/packages/host/dist/extensions/diskspace/host/run.mjs.map +1 -0
  232. package/packages/host/dist/extensions/diskspace/shared/wire.d.mts +197 -0
  233. package/packages/host/dist/extensions/diskspace/shared/wire.mjs +23 -0
  234. package/packages/host/dist/extensions/diskspace/shared/wire.mjs.map +1 -0
  235. package/packages/host/dist/extensions/links/host/engine.d.mts +39 -0
  236. package/packages/host/dist/extensions/links/host/engine.mjs +285 -0
  237. package/packages/host/dist/extensions/links/host/engine.mjs.map +1 -0
  238. package/packages/host/dist/extensions/links/host/index.d.mts +10 -0
  239. package/packages/host/dist/extensions/links/host/index.mjs +72 -0
  240. package/packages/host/dist/extensions/links/host/index.mjs.map +1 -0
  241. package/packages/host/dist/extensions/links/host/parse.d.mts +61 -0
  242. package/packages/host/dist/extensions/links/host/parse.mjs +225 -0
  243. package/packages/host/dist/extensions/links/host/parse.mjs.map +1 -0
  244. package/packages/host/dist/extensions/links/host/run.d.mts +15 -0
  245. package/packages/host/dist/extensions/links/host/run.mjs +32 -0
  246. package/packages/host/dist/extensions/links/host/run.mjs.map +1 -0
  247. package/packages/host/dist/extensions/links/host/store.d.mts +11 -0
  248. package/packages/host/dist/extensions/links/host/store.mjs +76 -0
  249. package/packages/host/dist/extensions/links/host/store.mjs.map +1 -0
  250. package/packages/host/dist/extensions/links/shared/wire.d.mts +141 -0
  251. package/packages/host/dist/extensions/links/shared/wire.mjs +20 -0
  252. package/packages/host/dist/extensions/links/shared/wire.mjs.map +1 -0
  253. package/packages/host/dist/git.d.ts +5 -3
  254. package/packages/host/dist/git.js +16 -28
  255. package/packages/host/dist/git.js.map +1 -1
  256. package/packages/host/dist/halt.js +16 -3
  257. package/packages/host/dist/halt.js.map +1 -1
  258. package/packages/host/dist/jsonstore.d.ts +16 -4
  259. package/packages/host/dist/jsonstore.js +32 -8
  260. package/packages/host/dist/jsonstore.js.map +1 -1
  261. package/packages/host/dist/landedbase.d.ts +41 -0
  262. package/packages/host/dist/landedbase.js +59 -0
  263. package/packages/host/dist/landedbase.js.map +1 -0
  264. package/packages/host/dist/lantls.js +2 -2
  265. package/packages/host/dist/lantls.js.map +1 -1
  266. package/packages/host/dist/limitretry.js +2 -3
  267. package/packages/host/dist/limitretry.js.map +1 -1
  268. package/packages/host/dist/localledger.js +9 -12
  269. package/packages/host/dist/localledger.js.map +1 -1
  270. package/packages/host/dist/main.js +2 -0
  271. package/packages/host/dist/main.js.map +1 -1
  272. package/packages/host/dist/opendeliveries.d.ts +4 -0
  273. package/packages/host/dist/opendeliveries.js +27 -1
  274. package/packages/host/dist/opendeliveries.js.map +1 -1
  275. package/packages/host/dist/plugins/setupcontrib.js +3 -2
  276. package/packages/host/dist/plugins/setupcontrib.js.map +1 -1
  277. package/packages/host/dist/pricefetch.d.ts +80 -0
  278. package/packages/host/dist/pricefetch.js +289 -0
  279. package/packages/host/dist/pricefetch.js.map +1 -0
  280. package/packages/host/dist/pricegap.d.ts +11 -0
  281. package/packages/host/dist/pricegap.js +30 -0
  282. package/packages/host/dist/pricegap.js.map +1 -0
  283. package/packages/host/dist/repohealthscopes.js +16 -24
  284. package/packages/host/dist/repohealthscopes.js.map +1 -1
  285. package/packages/host/dist/repos.d.ts +4 -0
  286. package/packages/host/dist/repos.js +1 -1
  287. package/packages/host/dist/repos.js.map +1 -1
  288. package/packages/host/dist/reposkilltext.d.ts +2 -0
  289. package/packages/host/dist/reposkilltext.js +8 -2
  290. package/packages/host/dist/reposkilltext.js.map +1 -1
  291. package/packages/host/dist/routes/apiagentpoints.d.ts +5 -0
  292. package/packages/host/dist/routes/apiagentpoints.js +48 -0
  293. package/packages/host/dist/routes/apiagentpoints.js.map +1 -0
  294. package/packages/host/dist/routes/apidictate.d.ts +2 -0
  295. package/packages/host/dist/routes/apidictate.js +27 -0
  296. package/packages/host/dist/routes/apidictate.js.map +1 -0
  297. package/packages/host/dist/routes/apihost.js +3 -2
  298. package/packages/host/dist/routes/apihost.js.map +1 -1
  299. package/packages/host/dist/routes/apirepofiles.js +3 -1
  300. package/packages/host/dist/routes/apirepofiles.js.map +1 -1
  301. package/packages/host/dist/routes/apirepowork.js +14 -0
  302. package/packages/host/dist/routes/apirepowork.js.map +1 -1
  303. package/packages/host/dist/routes/apiroutes.js +4 -1
  304. package/packages/host/dist/routes/apiroutes.js.map +1 -1
  305. package/packages/host/dist/routes/apiskills.d.ts +3 -0
  306. package/packages/host/dist/routes/apiskills.js +81 -0
  307. package/packages/host/dist/routes/apiskills.js.map +1 -0
  308. package/packages/host/dist/routes/apistats.js +2 -2
  309. package/packages/host/dist/routes/apistats.js.map +1 -1
  310. package/packages/host/dist/routes/apisystem.js +3 -1
  311. package/packages/host/dist/routes/apisystem.js.map +1 -1
  312. package/packages/host/dist/routes/apitable.d.ts +2 -0
  313. package/packages/host/dist/routes/apitable.js.map +1 -1
  314. package/packages/host/dist/server/billingwire.js +5 -0
  315. package/packages/host/dist/server/billingwire.js.map +1 -1
  316. package/packages/host/dist/server/deliveries.d.ts +4 -1
  317. package/packages/host/dist/server/deliveries.js +38 -6
  318. package/packages/host/dist/server/deliveries.js.map +1 -1
  319. package/packages/host/dist/server/http.js +1 -1
  320. package/packages/host/dist/server/http.js.map +1 -1
  321. package/packages/host/dist/server/intentDeps.js +20 -6
  322. package/packages/host/dist/server/intentDeps.js.map +1 -1
  323. package/packages/host/dist/server/wsops.js +2 -1
  324. package/packages/host/dist/server/wsops.js.map +1 -1
  325. package/packages/host/dist/sessions/core.d.ts +1 -0
  326. package/packages/host/dist/sessions/ctxseries.js +7 -5
  327. package/packages/host/dist/sessions/ctxseries.js.map +1 -1
  328. package/packages/host/dist/sessions/drive.d.ts +6 -1
  329. package/packages/host/dist/sessions/drive.js +13 -10
  330. package/packages/host/dist/sessions/drive.js.map +1 -1
  331. package/packages/host/dist/sessions/record.js +16 -17
  332. package/packages/host/dist/sessions/record.js.map +1 -1
  333. package/packages/host/dist/sessions/sidechannel.js +1 -1
  334. package/packages/host/dist/sessions/sidechannel.js.map +1 -1
  335. package/packages/host/dist/sessions/tmux.js +6 -1
  336. package/packages/host/dist/sessions/tmux.js.map +1 -1
  337. package/packages/host/dist/sessions/turn.js +5 -0
  338. package/packages/host/dist/sessions/turn.js.map +1 -1
  339. package/packages/host/dist/sessions.d.ts +2 -1
  340. package/packages/host/dist/sessions.js +1 -1
  341. package/packages/host/dist/sessions.js.map +1 -1
  342. package/packages/host/dist/settle.d.ts +3 -2
  343. package/packages/host/dist/settle.js +13 -13
  344. package/packages/host/dist/settle.js.map +1 -1
  345. package/packages/host/dist/sidecar/sidecarname.d.ts +2 -0
  346. package/packages/host/dist/sidecar/sidecarname.js +5 -1
  347. package/packages/host/dist/sidecar/sidecarname.js.map +1 -1
  348. package/packages/host/dist/sidecar/sidecarroute.d.ts +1 -1
  349. package/packages/host/dist/sidecar/sidecarroute.js +5 -0
  350. package/packages/host/dist/sidecar/sidecarroute.js.map +1 -1
  351. package/packages/host/dist/sidecar.d.ts +1 -1
  352. package/packages/host/dist/sidecar.js +1 -1
  353. package/packages/host/dist/sidecar.js.map +1 -1
  354. package/packages/host/dist/skills/skillinventory.d.ts +23 -0
  355. package/packages/host/dist/skills/skillinventory.js +275 -0
  356. package/packages/host/dist/skills/skillinventory.js.map +1 -0
  357. package/packages/host/dist/skills/skilllayers.d.ts +28 -0
  358. package/packages/host/dist/skills/skilllayers.js +73 -0
  359. package/packages/host/dist/skills/skilllayers.js.map +1 -0
  360. package/packages/host/dist/skills/skillrecommend.d.ts +42 -0
  361. package/packages/host/dist/skills/skillrecommend.js +171 -0
  362. package/packages/host/dist/skills/skillrecommend.js.map +1 -0
  363. package/packages/host/dist/skills/skillrefs.d.ts +2 -0
  364. package/packages/host/dist/skills/skillrefs.js +50 -0
  365. package/packages/host/dist/skills/skillrefs.js.map +1 -0
  366. package/packages/host/dist/skills/skilluse.d.ts +57 -0
  367. package/packages/host/dist/skills/skilluse.js +242 -0
  368. package/packages/host/dist/skills/skilluse.js.map +1 -0
  369. package/packages/host/dist/skills/skillweight.d.ts +18 -0
  370. package/packages/host/dist/skills/skillweight.js +69 -0
  371. package/packages/host/dist/skills/skillweight.js.map +1 -0
  372. package/packages/host/dist/skills/skillwrite.d.ts +56 -0
  373. package/packages/host/dist/skills/skillwrite.js +183 -0
  374. package/packages/host/dist/skills/skillwrite.js.map +1 -0
  375. package/packages/host/dist/sysstat.d.ts +34 -1
  376. package/packages/host/dist/sysstat.js +82 -14
  377. package/packages/host/dist/sysstat.js.map +1 -1
  378. package/packages/host/dist/tokenscan.js +5 -2
  379. package/packages/host/dist/tokenscan.js.map +1 -1
  380. package/packages/host/dist/tokenstats.js +7 -4
  381. package/packages/host/dist/tokenstats.js.map +1 -1
  382. package/packages/host/dist/transcript/transcriptparse.js +2 -2
  383. package/packages/host/dist/transcript/transcriptparse.js.map +1 -1
  384. package/packages/host/dist/waitclock.d.ts +12 -0
  385. package/packages/host/dist/waitclock.js +23 -0
  386. package/packages/host/dist/waitclock.js.map +1 -0
  387. package/packages/host/dist/weekburn.js +7 -5
  388. package/packages/host/dist/weekburn.js.map +1 -1
  389. package/packages/host/dist/worktreeleftover.js +13 -15
  390. package/packages/host/dist/worktreeleftover.js.map +1 -1
  391. package/packages/web/dist/assets/demo-DHkwSmU5.js +26 -0
  392. package/packages/web/dist/assets/{icons-D8RlmSLR.js → icons-5lVTFNUU.js} +1 -1
  393. package/packages/web/dist/assets/index-Bh4cH6X8.js +170 -0
  394. package/packages/web/dist/assets/index-F7VHtsLI.css +1 -0
  395. package/packages/web/dist/assets/shared-BvQMg9ra.js +51 -0
  396. package/packages/web/dist/assets/sheets-Cwi72V02.js +257 -0
  397. package/packages/web/dist/assets/sheets-DjU2XiUd.css +1 -0
  398. package/packages/web/dist/build-id.txt +1 -1
  399. package/packages/web/dist/buildstamp.json +1 -1
  400. package/packages/web/dist/index.html +7 -7
  401. package/packages/web/dist/sw.js +2 -2
  402. package/release.json +11 -3
  403. package/tools/repohealth/constants.mjs +34 -1
  404. package/tools/repohealth/fixture.json +5374 -38
  405. package/tools/repohealth/git.mjs +77 -0
  406. package/tools/repohealth/lang/dart-analyze.mjs +181 -0
  407. package/tools/repohealth/lang/dart-lex.mjs +494 -0
  408. package/tools/repohealth/lang/dart-resolve.mjs +95 -0
  409. package/tools/repohealth/lang/python-ast.mjs +602 -0
  410. package/tools/repohealth/lang/python-resolve.mjs +228 -0
  411. package/tools/repohealth/metrics/habits.mjs +286 -0
  412. package/tools/repohealth/metrics/native.mjs +542 -0
  413. package/tools/repohealth/metrics/untested.mjs +20 -8
  414. package/tools/repohealth/metrics/workspace.mjs +256 -0
  415. package/tools/repohealth/own.mjs +67 -5
  416. package/tools/repohealth/packs/dart.mjs +153 -85
  417. package/tools/repohealth/packs/python.mjs +51 -14
  418. package/tools/repohealth/plot.mjs +143 -1
  419. package/tools/repohealth/reach.mjs +98 -0
  420. package/tools/repohealth/scope.mjs +14 -1
  421. package/tools/repohealth/series.mjs +5 -0
  422. package/tools/repohealth/types.mjs +4 -0
  423. package/tools/repohealth.mjs +39 -5
  424. package/packages/web/dist/assets/demo-ad3g3HDa.js +0 -26
  425. package/packages/web/dist/assets/index-Csb7jynu.js +0 -170
  426. package/packages/web/dist/assets/index-Cz9Haocy.css +0 -1
  427. package/packages/web/dist/assets/shared-DBaaGttP.js +0 -51
  428. package/packages/web/dist/assets/sheets-CqsP9w1V.js +0 -256
  429. package/packages/web/dist/assets/sheets-DoUhPGK0.css +0 -1
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Where a Python import points inside the tree, resolved against the set of
3
+ * `.py` paths the tree holds. The Python half of `metrics/graph.mjs`'s
4
+ * contract, beside `typescript-resolve.mjs`.
5
+ *
6
+ * ── What counts as a module, and the key an edge carries ────────────────────
7
+ *
8
+ * `a/b.py` is module `a.b` and its graph key is `a/b`. `a/b/__init__.py` is
9
+ * package `a.b` and its key is `a/b/__init__`. (`graphKeysFor` in the pack
10
+ * offers exactly these two shapes, so a package and a module of one name never
11
+ * share a key.) A directory with `.py` files below it and no `__init__.py` is a
12
+ * namespace package: it exists, it has no file, it is no edge.
13
+ *
14
+ * ── Which directory an absolute import is read from ─────────────────────────
15
+ *
16
+ * Python reads `import a.b` against `sys.path`, and a repo does not say what
17
+ * its `sys.path` is. The roots tried, nearest first, are the directories above
18
+ * the importing file that are NOT themselves packages (a package directory is
19
+ * never a `sys.path` entry), and each one's `src/`. That finds the repo root,
20
+ * a `src` layout, and a script's own directory. Only when none of them holds
21
+ * the first segment is the name looked for tree-wide, and only if it lives in
22
+ * exactly ONE place and is not a standard-library name. Two places is an
23
+ * ambiguity reported as a MISS, never a pick — a guessed edge can invent a cycle.
24
+ *
25
+ * ── What is external ────────────────────────────────────────────────────────
26
+ *
27
+ * A first segment no root holds is a package from outside (`numpy`, `fastapi`,
28
+ * the standard library): no entry at all, no miss. A first segment that IS this
29
+ * tree's but whose rest is not (`import app.nothing`) is a miss. Every relative
30
+ * import is this tree's own, so one that finds nothing is a miss.
31
+ *
32
+ * ── Edges the graph does not draw ───────────────────────────────────────────
33
+ *
34
+ * - Imports under `if TYPE_CHECKING:` never run: no edge.
35
+ * - Imports inside a function body run when it is CALLED, not when the module
36
+ * loads. Python code puts them there on purpose to break a cycle (in
37
+ * `trading` they are the whole of a 16-module cycle: 1,438 edges and one
38
+ * cycle with them, 1,169 and none without). The graph is the load-time
39
+ * coupling, so they draw no edge and count as neither hit nor miss.
40
+ * - The parent packages `import a.b.c` also executes (`a/__init__`,
41
+ * `a/b/__init__`) are not edges: every package would then sit in a cycle
42
+ * with every module that imports a sibling. The target itself is the edge.
43
+ * - `from pkg import name` is an edge to `pkg/name.py` when that submodule
44
+ * exists and to `pkg` otherwise (`name` is then an attribute).
45
+ * - A target that is a test file is dropped: it is not a node of the graph.
46
+ */
47
+
48
+ const STDLIB = new Set(
49
+ (
50
+ "abc argparse array ast asyncio atexit base64 bdb binascii bisect builtins bz2 cProfile calendar cmath cmd code codecs " +
51
+ "codeop collections colorsys compileall concurrent configparser contextlib contextvars copy copyreg csv ctypes curses " +
52
+ "dataclasses datetime dbm decimal difflib dis doctest email encodings ensurepip enum errno faulthandler fcntl filecmp " +
53
+ "fileinput fnmatch fractions ftplib functools gc genericpath getopt getpass gettext glob graphlib grp gzip hashlib " +
54
+ "heapq hmac html http imaplib importlib inspect io ipaddress itertools json keyword linecache locale logging lzma " +
55
+ "mailbox marshal math mimetypes mmap modulefinder msvcrt multiprocessing netrc nt ntpath numbers opcode operator " +
56
+ "optparse os pathlib pdb pickle pickletools pkgutil platform plistlib poplib posix posixpath pprint profile pstats pty " +
57
+ "pwd py_compile pyclbr pydoc pyexpat queue quopri random re readline reprlib resource rlcompleter runpy sched secrets " +
58
+ "select selectors shelve shlex shutil signal site smtplib socket socketserver sqlite3 sre_compile sre_constants " +
59
+ "sre_parse ssl stat statistics string stringprep struct subprocess symtable sys sysconfig syslog tabnanny tarfile " +
60
+ "tempfile termios textwrap this threading time timeit tkinter token tokenize tomllib trace traceback tracemalloc tty " +
61
+ "turtle types typing unicodedata unittest urllib uuid venv warnings wave weakref webbrowser winreg winsound wsgiref " +
62
+ "xml xmlrpc zipapp zipfile zipimport zlib zoneinfo"
63
+ ).split(" "),
64
+ );
65
+
66
+ /** Same three conventions as `packs/python.mjs` `testGlobs`, for one path. */
67
+ export function isPythonTest(path) {
68
+ const segs = path.split("/");
69
+ const file = segs[segs.length - 1];
70
+ return file.startsWith("test_") || file.endsWith("_test.py") || segs.slice(0, -1).includes("tests");
71
+ }
72
+
73
+ /**
74
+ * The resolver's data for one tree: every `.py` path (the entries are paths
75
+ * only; no text is read), the directories holding any, and the packages.
76
+ * @param {{path: string}[]} entries
77
+ */
78
+ export function buildPythonContext(entries) {
79
+ const all = new Set();
80
+ const dirs = new Set([""]);
81
+ const inits = new Set();
82
+ /** first segment -> parents ("" for the root) holding a module or directory of that name */
83
+ const heads = new Map();
84
+ const top = [];
85
+ for (const e of entries) {
86
+ if (!e.path.endsWith(".py")) continue;
87
+ all.add(e.path);
88
+ const segs = e.path.split("/");
89
+ const file = segs.pop();
90
+ for (let i = 1; i <= segs.length; i++) dirs.add(segs.slice(0, i).join("/"));
91
+ if (file === "__init__.py") inits.add(segs.join("/"));
92
+ if (file !== "__init__.py") top.push([file.slice(0, -3), segs.join("/")]);
93
+ }
94
+ // A head is a module or package that sits in a directory which is not itself
95
+ // a package: the only places a `sys.path` entry can be.
96
+ const parentOf = (d) => d.slice(0, Math.max(0, d.lastIndexOf("/")));
97
+ for (const [name, dir] of top) if (!inits.has(dir) || dir === "") note(heads, name, dir);
98
+ for (const d of inits) {
99
+ if (!d) continue;
100
+ const parent = d.includes("/") ? parentOf(d) : "";
101
+ if (!inits.has(parent) || parent === "") note(heads, d.slice(d.lastIndexOf("/") + 1), parent);
102
+ }
103
+ return { all, dirs, inits, heads };
104
+ }
105
+
106
+ function note(map, head, parent) {
107
+ let s = map.get(head);
108
+ if (!s) map.set(head, (s = new Set()));
109
+ s.add(parent);
110
+ }
111
+
112
+ const join = (root, segs) => (root ? [root, ...segs] : segs).join("/");
113
+
114
+ /** What `root/segs` is: `{key}` for a module or package file, `{ns: true}` for a namespace directory, or null. */
115
+ function modAt(ctx, root, segs) {
116
+ if (!segs.length) return ctx.inits.has(root) ? { key: join(root, ["__init__"]) } : ctx.dirs.has(root) ? { ns: true } : null;
117
+ const p = join(root, segs);
118
+ if (ctx.all.has(p + ".py")) return { key: p };
119
+ if (ctx.all.has(p + "/__init__.py")) return { key: p + "/__init__" };
120
+ if (ctx.dirs.has(p)) return { ns: true };
121
+ return null;
122
+ }
123
+
124
+ /** The sys.path-like roots for a file in `dirSegs`, nearest first. */
125
+ function rootsFor(ctx, dirSegs) {
126
+ const roots = [];
127
+ for (let n = dirSegs.length; n >= 0; n--) {
128
+ const dir = dirSegs.slice(0, n).join("/");
129
+ if (ctx.inits.has(dir) && n > 0) continue;
130
+ roots.push(dir);
131
+ const src = join(dir, ["src"]);
132
+ if (ctx.dirs.has(src)) roots.push(src);
133
+ }
134
+ return roots;
135
+ }
136
+
137
+ /**
138
+ * Every module one file's import records load, as graph entries:
139
+ * `{spec, internal, candidates}`. Candidates are whole tree keys.
140
+ * @param {object[]} records `importsOf` output
141
+ * @param {string} fromPath
142
+ * @param {ReturnType<typeof buildPythonContext> | null} ctx
143
+ */
144
+ export function resolvePythonImports(records, fromPath, ctx) {
145
+ if (!ctx) return [];
146
+ const out = [];
147
+ const seen = new Set();
148
+ const dirSegs = fromPath.split("/").slice(0, -1);
149
+ const emit = (spec, key) => {
150
+ // A test file is no node of the graph; neither hit nor miss.
151
+ if (key && isPythonTest(key.endsWith("/__init__") ? key.slice(0, -9) + "/__init__.py" : key + ".py")) return;
152
+ const id = `${spec}\u0000${key ?? ""}`;
153
+ if (seen.has(id)) return;
154
+ seen.add(id);
155
+ out.push({ spec, internal: true, candidates: key ? [key] : [] });
156
+ };
157
+
158
+ /** Resolve `base` (a root) + module segments + imported names for a `from` record; false if nothing is there. */
159
+ const fromAt = (spec, root, segs, names) => {
160
+ const base = modAt(ctx, root, segs);
161
+ if (!base) return false;
162
+ if (names.includes("*") || !names.length) names = [];
163
+ if (base.key && !base.key.endsWith("/__init__")) {
164
+ emit(spec, base.key); // module: names are attributes
165
+ return true;
166
+ }
167
+ if (!names.length) {
168
+ if (base.key) emit(spec, base.key);
169
+ return true;
170
+ }
171
+ for (const nm of names) {
172
+ const sub = modAt(ctx, root, [...segs, nm]);
173
+ if (sub && sub.key) emit(spec, sub.key);
174
+ else if (base.key) emit(spec, base.key);
175
+ else emit(spec, null);
176
+ }
177
+ return true;
178
+ };
179
+
180
+ for (const r of records) {
181
+ if (r.tc || r.deferred) continue;
182
+ if (r.from && r.dots > 0) {
183
+ const spec = ".".repeat(r.dots) + r.module.join(".");
184
+ if (r.dots - 1 > dirSegs.length) {
185
+ emit(spec, null);
186
+ continue;
187
+ }
188
+ const root = dirSegs.slice(0, dirSegs.length - (r.dots - 1)).join("/");
189
+ if (!fromAt(spec, root, r.module, r.names)) emit(spec, null);
190
+ continue;
191
+ }
192
+ const mods = r.from ? [r.module] : r.modules;
193
+ for (const segs of mods) {
194
+ const spec = segs.join(".");
195
+ const head = segs[0];
196
+ let root = null;
197
+ for (const cand of rootsFor(ctx, dirSegs)) {
198
+ if (modAt(ctx, cand, [head])) {
199
+ root = cand;
200
+ break;
201
+ }
202
+ }
203
+ if (root === null) {
204
+ if (STDLIB.has(head)) continue;
205
+ const places = ctx.heads.get(head);
206
+ if (!places) continue; // external
207
+ if (places.size > 1) {
208
+ emit(spec, null);
209
+ continue;
210
+ }
211
+ root = [...places][0];
212
+ // The head must be a module/package AT that parent, not a deep directory of that name.
213
+ if (!modAt(ctx, root, [head])) {
214
+ continue;
215
+ }
216
+ }
217
+ if (r.from) {
218
+ if (!fromAt(spec, root, segs, r.names)) emit(spec, null);
219
+ } else {
220
+ const t = modAt(ctx, root, segs);
221
+ if (t && t.key) emit(spec, t.key);
222
+ else if (t && t.ns) continue; // a namespace directory: nothing to load
223
+ else emit(spec, null);
224
+ }
225
+ }
226
+ }
227
+ return out;
228
+ }
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Habits: what the commit log alone says about how work lands. Git only, no
3
+ * language knowledge beyond the one thing the packs already decide — which
4
+ * paths are source and which are tests.
5
+ *
6
+ * ── The six readings, and the question each one answers ────────────────────
7
+ *
8
+ * fix Of the commits that touched source or tests, what share were a
9
+ * FIX or REVERT of files a different commit had changed in the
10
+ * seven days before. "Is the last thing I shipped holding?"
11
+ * Re-touch asks it per file; this asks it per commit and by what
12
+ * the author SAID, so the two disagree usefully.
13
+ * deletion Lines deleted per line added over the window, with the four
14
+ * weeks it is made of. The owner's grooming signal: an agent
15
+ * rarely deletes unless asked, so a ratio that stays near zero
16
+ * is a repo that only grows.
17
+ * netNegative The share of commits that delete more than they add.
18
+ * testsWithCode Of the commits that touched source, the share that also
19
+ * touched a test file.
20
+ * commitSize p95 (nearest rank) of changed lines (added + deleted) per
21
+ * commit, with the median beside it.
22
+ * hotspots The files where churn and size multiply — a LIST, like
23
+ * `untested`, because "src/a.ts, 4 changes, 2,100 lines" is
24
+ * something a person opens and "0.43" is not.
25
+ *
26
+ * ── The fix pattern ────────────────────────────────────────────────────────
27
+ *
28
+ * A commit is a fix when its SUBJECT, case-insensitively, starts with
29
+ * `revert`, `fix`, `fixes`, `fixed`, `bugfix` or `hotfix` (as a word), or is a
30
+ * Conventional-Commits subject whose type is `fix`/`revert`/`hotfix`
31
+ * (`fix(web): …`, `fix!: …`). It is pinned in `FIX_SUBJECT` below, is a
32
+ * message heuristic and nothing more: a repo that never writes "fix" reads 0
33
+ * fixes, which is why `fixes` travels beside the rate and a window with no
34
+ * fix-worded commit still reports the rate (0 of N) rather than an absence —
35
+ * "nothing was labelled a fix" is a true statement about the window.
36
+ *
37
+ * ── Which commits are the subject, and which are only evidence ─────────────
38
+ *
39
+ * The same rule `retouch` argues out. A BATCH commit (`history.batch`, the
40
+ * flag as recorded, never recomputed) is a day swept up by one `git add`, and
41
+ * a MERGE (subject `Merge …`; first-parent history gives it the whole branch
42
+ * as one diff) is a branch landing at once. Neither is a commit someone sized
43
+ * or worded, so neither is counted in a per-commit share (fix, test, net
44
+ * negative, size). Both still count as PRIOR touches for fix-after-change, and
45
+ * both still count in the line TOTALS of the deletion ratio: those lines
46
+ * really were added and deleted, and dropping them would make a repo that
47
+ * grooms in one big commit look like one that never does.
48
+ *
49
+ * ── Line counts: renames are not deletions ─────────────────────────────────
50
+ *
51
+ * Added and deleted lines come from `git.readChurn`, which runs numstat with
52
+ * `-M`. A pure move is `0 0`; a move with edits counts only the edit. The
53
+ * history `lines` map (rename detection OFF, pinned for path fidelity) would
54
+ * read a reorganisation as 100% deleted and 100% added. Paths inside the
55
+ * packs' excluded directories (build output, vendored code) are dropped from
56
+ * every count here: nobody grooms `node_modules`.
57
+ *
58
+ * ── Shallow clones and young repos ─────────────────────────────────────────
59
+ *
60
+ * In a shallow clone the boundary commit "adds" the whole tree, so any window
61
+ * that reaches it would read a repo-sized addition as a day's work. The whole
62
+ * family is absent when the history is shallow and the window (plus the
63
+ * fix look-back) reaches the first commit it has. A repo that is genuinely
64
+ * young reads normally: its root commit really did add everything.
65
+ *
66
+ * ── Cost ────────────────────────────────────────────────────────────────────
67
+ *
68
+ * Per row: one scan of the commits in the trailing window plus the look-back,
69
+ * found by walking back from `index` (not from 0, unlike `retouch`'s scan),
70
+ * with a `Map` of last-touch times. No git, no blobs; `history.churn` is read
71
+ * once per `update`.
72
+ *
73
+ * ── Purity ─────────────────────────────────────────────────────────────────
74
+ *
75
+ * The `History` and `Snapshot` handed in are the whole world, nothing past
76
+ * `index` is read, and every sub-reading is `{value, reason}`: a reading that
77
+ * cannot be taken is absent with the sentence that says why, never 0.
78
+ */
79
+ import { isSource, isTestPath, inExcludedDir } from "../source.mjs";
80
+ import { nearestRankP95 } from "./size.mjs";
81
+
82
+ const DAY = 86400;
83
+ const WEEKS = 4;
84
+
85
+ /** See the header: the pinned meaning of "this commit is a fix". */
86
+ export const FIX_SUBJECT =
87
+ /^\s*(?:(?:revert|fix|fixes|fixed|bugfix|hotfix)\b|[a-z]+(?:\([^)]*\))?!?:\s*(?:revert|fix|hotfix)\b)/i;
88
+
89
+ /** A merge commit, by git's own default subject. */
90
+ const MERGE_SUBJECT = /^Merge\b/;
91
+
92
+ /**
93
+ * Per-path class, kept for the life of the process per `SRC` object: a path's
94
+ * class never changes within one configuration, and the scan below asks it of
95
+ * every path of every commit in the window for every row (measured: this was
96
+ * most of the per-row cost).
97
+ * @type {WeakMap<object, Map<string, 0|1|2>>} 0 other, 1 source, 2 test
98
+ */
99
+ const CLASS = new WeakMap();
100
+ function classOf(path, prereg) {
101
+ let m = CLASS.get(prereg.SRC);
102
+ if (!m) CLASS.set(prereg.SRC, (m = new Map()));
103
+ let c = m.get(path);
104
+ if (c === undefined) {
105
+ c = isSource(path, prereg) ? 1 : isTestPath(path, prereg) && !inExcludedDir(path, prereg.SRC.excludeDirs) ? 2 : 0;
106
+ m.set(path, c);
107
+ }
108
+ return c;
109
+ }
110
+
111
+ const none = (reason) => ({ value: null, reason });
112
+
113
+ /** Nearest-rank median over an ascending list, same convention as the p95. */
114
+ function nearestRankMedian(ascending) {
115
+ return ascending[Math.max(0, Math.ceil(0.5 * ascending.length) - 1)];
116
+ }
117
+
118
+ /** Count desc, then path asc — a total order so the fixture can be compared. */
119
+ function byScoreThenPath(a, b) {
120
+ if (b.score !== a.score) return b.score - a.score;
121
+ return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
122
+ }
123
+
124
+ /**
125
+ * @param {import("../types.mjs").Snapshot} snapshot
126
+ * @param {import("../types.mjs").History & {churn?: Map<string, Map<string, {add: number, del: number}>>, shallow?: boolean}} history
127
+ * @param {number} index
128
+ * @param {import("../types.mjs").EffectivePrereg} prereg
129
+ * @returns {import("../types.mjs").Measured<object>}
130
+ */
131
+ export function measureHabits(snapshot, history, index, prereg) {
132
+ const commits = history?.commits ?? [];
133
+ const here = commits[index];
134
+ if (!here) return none("no commit at index " + index);
135
+ if (!history.churn) return none("no rename-aware line counts were read");
136
+
137
+ const windowSecs = prereg.HABITS_WINDOW_DAYS * DAY;
138
+ const fixSecs = prereg.FIX_AFTER_DAYS * DAY;
139
+ const windowStart = here.ts - windowSecs;
140
+
141
+ if (history.shallow && commits[0] && commits[0].ts >= windowStart - fixSecs) {
142
+ return none(
143
+ "shallow clone: the history it holds starts at " + commits[0].day +
144
+ ", inside the " + prereg.HABITS_WINDOW_DAYS + "-day window, and that first commit adds the whole tree",
145
+ );
146
+ }
147
+
148
+ // First in-window commit, and the first commit of the fix look-back.
149
+ let lo = index;
150
+ while (lo > 0 && commits[lo - 1].ts >= windowStart) lo--;
151
+ let pre = lo;
152
+ while (pre > 0 && commits[pre - 1].ts >= windowStart - fixSecs) pre--;
153
+
154
+ const src = prereg.SRC;
155
+ const dirs = src.excludeDirs;
156
+ const pathsOf = (c) => history.touches?.get(c.sha) ?? c.filesTouched ?? [];
157
+ const isBatch = (c) => history.batch?.has(c.sha) ?? c.batch ?? false;
158
+ const isMerge = (c) => MERGE_SUBJECT.test(c.subject ?? "");
159
+ const hasSrc = src.exts.length > 0;
160
+ const hasTests = src.testGlobs.length > 0;
161
+
162
+ // ── fix-after-change, tests-with-code: path-level, per subject commit ────
163
+ const lastTouch = new Map();
164
+ let subjects = 0; // subject commits touching source or tests
165
+ let fixes = 0;
166
+ let fixesAfter = 0;
167
+ let srcCommits = 0;
168
+ let withTests = 0;
169
+ for (let i = pre; i <= index; i++) {
170
+ const c = commits[i];
171
+ const all = pathsOf(c);
172
+ const files = hasSrc ? all.filter((p) => classOf(p, prereg) !== 0) : [];
173
+ if (i >= lo && !isBatch(c) && !isMerge(c)) {
174
+ if (files.length) {
175
+ subjects++;
176
+ if (FIX_SUBJECT.test(c.subject ?? "")) {
177
+ fixes++;
178
+ if (files.some((p) => {
179
+ const t = lastTouch.get(p);
180
+ return t !== undefined && Math.abs(c.ts - t) <= fixSecs;
181
+ })) fixesAfter++;
182
+ }
183
+ if (all.some((p) => classOf(p, prereg) === 1)) {
184
+ srcCommits++;
185
+ if (all.some((p) => classOf(p, prereg) === 2)) withTests++;
186
+ }
187
+ }
188
+ }
189
+ // Prior-touch bookkeeping runs for every commit, batch and merge included.
190
+ for (const p of files) lastTouch.set(p, c.ts);
191
+ }
192
+
193
+ // ── line-level: totals over everything, per-commit stats over subjects ───
194
+ let added = 0;
195
+ let deleted = 0;
196
+ const weeks = Array.from({ length: WEEKS }, () => ({ added: 0, deleted: 0 }));
197
+ const sizes = [];
198
+ let negative = 0;
199
+ /** path -> churn (added + deleted) over subject commits. */
200
+ const churnOf = new Map();
201
+ for (let i = lo; i <= index; i++) {
202
+ const c = commits[i];
203
+ const files = history.churn.get(c.sha);
204
+ if (!files) continue;
205
+ let a = 0;
206
+ let d = 0;
207
+ for (const [p, v] of files) {
208
+ if (inExcludedDir(p, dirs)) continue;
209
+ a += v.add;
210
+ d += v.del;
211
+ }
212
+ const wk = Math.min(WEEKS - 1, Math.max(0, Math.floor((here.ts - c.ts) / (7 * DAY))));
213
+ weeks[WEEKS - 1 - wk].added += a;
214
+ weeks[WEEKS - 1 - wk].deleted += d;
215
+ added += a;
216
+ deleted += d;
217
+ if (isBatch(c) || isMerge(c) || a + d === 0) continue;
218
+ sizes.push(a + d);
219
+ if (d > a) negative++;
220
+ for (const [p, v] of files) {
221
+ if (inExcludedDir(p, dirs)) continue;
222
+ churnOf.set(p, (churnOf.get(p) ?? 0) + v.add + v.del);
223
+ }
224
+ }
225
+ sizes.sort((x, y) => x - y);
226
+
227
+ const noSource = "no active language pack recognises source files in this tree";
228
+
229
+ const fix = !hasSrc
230
+ ? none(noSource)
231
+ : subjects === 0
232
+ ? none("no non-batch commit touched source or test files in the trailing " + prereg.HABITS_WINDOW_DAYS + "d")
233
+ : { value: { rate: fixesAfter / subjects, commits: subjects, fixes, fixesAfter } };
234
+
235
+ const deletion = added === 0
236
+ ? none("no lines were added in the trailing " + prereg.HABITS_WINDOW_DAYS + "d, so there is nothing to compare deletions with")
237
+ : { value: { ratio: deleted / added, added, deleted, weeks } };
238
+
239
+ const netNegative = sizes.length === 0
240
+ ? none("no non-batch, non-merge commit changed a line in the trailing " + prereg.HABITS_WINDOW_DAYS + "d")
241
+ : { value: { share: negative / sizes.length, commits: sizes.length, negative } };
242
+
243
+ const commitSize = sizes.length === 0
244
+ ? none("no non-batch, non-merge commit changed a line in the trailing " + prereg.HABITS_WINDOW_DAYS + "d")
245
+ : { value: { p95: nearestRankP95(sizes), median: nearestRankMedian(sizes), commits: sizes.length } };
246
+
247
+ const testsWithCode = !hasSrc
248
+ ? none(noSource)
249
+ : !hasTests
250
+ ? none("no active language pack recognises test files in this tree")
251
+ : srcCommits === 0
252
+ ? none("no non-batch commit touched source files in the trailing " + prereg.HABITS_WINDOW_DAYS + "d")
253
+ : { value: { rate: withTests / srcCommits, commits: srcCommits, withTests } };
254
+
255
+ // ── hotspots: churn x size, source files that still exist at this sha ────
256
+ let hotspots;
257
+ const files = snapshot?.files ?? [];
258
+ if (!files.length) {
259
+ hotspots = none(noSource);
260
+ } else {
261
+ const locOf = new Map(files.map((f) => [f.path, f.loc]));
262
+ const ranked = [];
263
+ for (const [path, churn] of churnOf) {
264
+ const loc = locOf.get(path);
265
+ if (loc === undefined) continue;
266
+ ranked.push({ path, churn, loc, score: churn * loc });
267
+ }
268
+ ranked.sort(byScoreThenPath);
269
+ hotspots = ranked.length === 0
270
+ ? none("no source file that exists now changed in the trailing " + prereg.HABITS_WINDOW_DAYS + "d")
271
+ : { value: { items: ranked.slice(0, prereg.HABITS_LIST_N) } };
272
+ }
273
+
274
+ // Key order is fixed and load-bearing: the row is compared to a fixture.
275
+ return {
276
+ value: {
277
+ windowDays: prereg.HABITS_WINDOW_DAYS,
278
+ fix,
279
+ deletion,
280
+ netNegative,
281
+ testsWithCode,
282
+ commitSize,
283
+ hotspots,
284
+ },
285
+ };
286
+ }