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,542 @@
1
+ /**
2
+ * Native tools: what the repo's OWN analyzers, scanners and coverage files
3
+ * already say, read at the newest commit and never anywhere else.
4
+ *
5
+ * ── Why HEAD-only, and from the working directory ──────────────────────────
6
+ *
7
+ * Like `workspace.mjs`, this is a list a person acts on (upgrade this
8
+ * package, fix these findings), and a tool run per commit would mean checking
9
+ * out 150 trees. Every earlier row carries `read at the newest commit only`.
10
+ * Unlike `workspace.mjs` it needs the FILES: a linter cannot run on a git
11
+ * object. So it runs in the checkout it was pointed at (`--root=`), and the
12
+ * caller passes the newest commit's timestamp: a coverage file older than the
13
+ * last commit describes some other code and is not read.
14
+ *
15
+ * ── The rules every sub-reading holds ──────────────────────────────────────
16
+ *
17
+ * - Each is `{value}` or `{value: null, reason}`. A tool that is not on the
18
+ * PATH (or, for eslint and tsc, not in the repo's own `node_modules/.bin`)
19
+ * is ABSENT with "X is not installed". It is never 0: zero findings from a
20
+ * tool that did not run is the exact lie this family exists to avoid.
21
+ * - Nothing is installed, nothing is fetched except by the scanner that
22
+ * needs a network (`osv-scanner`), and every child has a hard timeout. A
23
+ * timeout is an absence with its reason, not a partial count.
24
+ * - Nothing is written into the measured repo: mypy gets a temp cache dir,
25
+ * ruff runs with `--no-cache`, detekt's report goes to a temp dir. Tests
26
+ * are never run; coverage files are only read.
27
+ * - Counts per 1,000 lines divide by the tracked lines of THAT tool's
28
+ * language, so a Dart analyzer is not diluted by the repo's TypeScript.
29
+ *
30
+ * ── What is deliberately not here ──────────────────────────────────────────
31
+ *
32
+ * Dependency age needs a registry lookup per package, which is a network
33
+ * call per dependency on every refresh. It is reported absent with that
34
+ * reason until a cheap source exists (a lockfile has no publish date).
35
+ * `tsc` is taken at the repo ROOT tsconfig only: a root that is only project
36
+ * references reads as zero errors, and the reading says which config it ran.
37
+ * Strictness follows no `extends`: it reports what each file itself says.
38
+ *
39
+ * The metric is pure over an injected environment (`run`, `fs`), so the test
40
+ * stubs every tool; `defaultEnv()` is the one place that spawns or reads.
41
+ */
42
+ import { spawnSync } from "node:child_process";
43
+ import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from "node:fs";
44
+ import { tmpdir } from "node:os";
45
+ import { delimiter, join } from "node:path";
46
+
47
+ export const NATIVE_NOT_HEAD = "read at the newest commit only";
48
+ const SECONDS = 1000;
49
+ export const NATIVE_TIMEOUT_MS = 180 * SECONDS;
50
+ const LIST_MAX = 20;
51
+ const MAX_BUFFER = 256 * 1024 * 1024;
52
+
53
+ export const ANALYZER_KEYS = ["eslint", "tsc", "ruff", "mypy", "dart", "shellcheck", "detekt", "ktlint"];
54
+
55
+ const none = (reason) => ({ value: null, reason });
56
+ const ok = (value) => ({ value });
57
+
58
+ /** The row field for a commit that is not the newest one. */
59
+ export function nativeElsewhere() {
60
+ return {
61
+ vulns: none(NATIVE_NOT_HEAD),
62
+ dependencyAge: none(NATIVE_NOT_HEAD),
63
+ analyzers: Object.fromEntries(ANALYZER_KEYS.map((k) => [k, none(NATIVE_NOT_HEAD)])),
64
+ strictness: none(NATIVE_NOT_HEAD),
65
+ coverage: none(NATIVE_NOT_HEAD),
66
+ };
67
+ }
68
+
69
+ // ── languages ───────────────────────────────────────────────────────────────
70
+
71
+ const LANG_EXTS = {
72
+ js: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
73
+ python: [".py"],
74
+ dart: [".dart"],
75
+ shell: [".sh", ".bash"],
76
+ kotlin: [".kt", ".kts"],
77
+ };
78
+ const LANG_NAMES = { js: "TypeScript or JavaScript", python: "Python", dart: "Dart", shell: "shell", kotlin: "Kotlin" };
79
+ const SKIP_DIRS =new Set(["node_modules", "dist", "build", ".dart_tool", "vendor", "third_party", "__pycache__"]);
80
+ const skipPath = (p) =>
81
+ p.split("/").some((s) => SKIP_DIRS.has(s)) || p.endsWith(".d.ts") || p.endsWith(".g.dart") || p.endsWith(".freezed.dart");
82
+ const baseName = (p) => p.slice(p.lastIndexOf("/") + 1);
83
+
84
+ /** @returns {Record<string,string[]>} language -> tracked source paths. */
85
+ function filesByLang(files) {
86
+ const out = Object.fromEntries(Object.keys(LANG_EXTS).map((l) => [l, []]));
87
+ for (const p of files) {
88
+ if (skipPath(p)) continue;
89
+ const dot = baseName(p).lastIndexOf(".");
90
+ const ext = dot < 0 ? "" : baseName(p).slice(dot).toLowerCase();
91
+ for (const [lang, exts] of Object.entries(LANG_EXTS)) if (exts.includes(ext)) out[lang].push(p);
92
+ }
93
+ return out;
94
+ }
95
+
96
+ function countLines(env, root, paths) {
97
+ let n = 0;
98
+ for (const p of paths) {
99
+ const t = env.readText(join(root, p));
100
+ if (t === null) continue;
101
+ for (let i = 0; i < t.length; i++) if (t.charCodeAt(i) === 10) n++;
102
+ if (t.length && t.charCodeAt(t.length - 1) !== 10) n++;
103
+ }
104
+ return n;
105
+ }
106
+
107
+ // ── running a tool ──────────────────────────────────────────────────────────
108
+
109
+ /** A finished run, or a sentence for why there is none. */
110
+ function runTool(env, tool, cmd, args, opts) {
111
+ const res = env.run(cmd, args, { timeout: NATIVE_TIMEOUT_MS, ...opts });
112
+ if (res.error) {
113
+ if (res.error.code === "ETIMEDOUT" || res.timedOut) return { reason: `${tool} did not finish in ${Math.round(NATIVE_TIMEOUT_MS / SECONDS)} s` };
114
+ if (res.error.code === "ENOENT") return { reason: `${tool} is not installed` };
115
+ return { reason: `${tool} could not be run (${String(res.error.message ?? res.error.code).slice(0, 120)})` };
116
+ }
117
+ if (res.signal) return { reason: `${tool} did not finish in ${Math.round(NATIVE_TIMEOUT_MS / SECONDS)} s` };
118
+ return { res };
119
+ }
120
+
121
+ const tail = (s) => String(s ?? "").trim().split("\n").filter(Boolean).slice(-1)[0]?.slice(0, 160) ?? "";
122
+
123
+ /** Resolve a tool: the repo's own `node_modules/.bin` for `local`, else the PATH. */
124
+ function findTool(env, root, name, local) {
125
+ if (local) {
126
+ const p = join(root, "node_modules", ".bin", name);
127
+ return env.exists(p) ? p : null;
128
+ }
129
+ for (const dir of env.path) {
130
+ const p = join(dir, name);
131
+ if (env.exists(p)) return p;
132
+ }
133
+ return null;
134
+ }
135
+
136
+ function perThousand(findings, lines) {
137
+ return lines > 0 ? Math.round((findings / lines) * 10000) / 10 : null;
138
+ }
139
+
140
+ /** One analyzer's value. `parse` turns a finished run into a finding count or `{reason}`. */
141
+ function analyzer(env, ctx, spec) {
142
+ const { key, tool, lang, need, local, args, parse, okCodes = [0, 1], configReason, config, cwd } = spec;
143
+ const paths = ctx.byLang[lang];
144
+ if (!paths.length) return none(`no ${LANG_NAMES[lang]} files`);
145
+ if (config && !config()) return none(configReason);
146
+ const bin = findTool(env, ctx.root, need ?? tool, local);
147
+ if (!bin) return none(`${tool} is not installed`);
148
+ const ran = runTool(env, tool, bin, args({ paths, tmp: ctx.tmp() }), { cwd: cwd ?? ctx.root });
149
+ if (ran.reason) return none(ran.reason);
150
+ const { res } = ran;
151
+ if (!okCodes.includes(res.status)) return none(`${tool} stopped with code ${res.status}${tail(res.stderr) ? `: ${tail(res.stderr)}` : ""}`);
152
+ const found = parse(res, ctx);
153
+ if (found.reason) return none(found.reason);
154
+ const lines = found.lines ?? countLines(env, ctx.root, paths);
155
+ return ok({ tool, findings: found.findings, lines, per1000: perThousand(found.findings, lines), ...(found.note ? { note: found.note } : {}) });
156
+ }
157
+
158
+ const tryJson = (s) => {
159
+ try { return JSON.parse(s); } catch { return null; }
160
+ };
161
+
162
+ function analyzers(env, ctx) {
163
+ const has = (re) => ctx.files.some((p) => re.test(p));
164
+ const hasRoot = (names) => names.some((n) => ctx.fileSet.has(n));
165
+ const specs = [
166
+ {
167
+ key: "eslint", tool: "eslint", lang: "js", local: true,
168
+ config: () => has(/(^|\/)(eslint\.config\.(js|mjs|cjs|ts|mts|cts)|\.eslintrc(\.[a-z]+)?)$/) || ctx.pkgJsonHas("eslintConfig"),
169
+ configReason: "the repo has no eslint config",
170
+ args: () => ["-f", "json", "--no-warn-ignored", "."],
171
+ parse: (res) => {
172
+ const j = tryJson(res.stdout);
173
+ if (!Array.isArray(j)) return { reason: "eslint printed no JSON report" };
174
+ return { findings: j.reduce((n, f) => n + (f.errorCount ?? 0) + (f.warningCount ?? 0), 0) };
175
+ },
176
+ },
177
+ {
178
+ key: "tsc", tool: "tsc", lang: "js", local: true, okCodes: [0, 1, 2],
179
+ // A root that only references other projects (`files: []`) compiles nothing: its "0 errors" would be a lie.
180
+ config: () => {
181
+ if (!ctx.fileSet.has("tsconfig.json")) return false;
182
+ const j = parseJsonc(env.readText(join(ctx.root, "tsconfig.json")) ?? "");
183
+ if (!j) return false;
184
+ const empty = (Array.isArray(j.files) && j.files.length === 0 && !j.include) || (Array.isArray(j.references) && j.references.length > 0 && j.files === undefined && j.include === undefined);
185
+ return !empty;
186
+ },
187
+ configReason: "the root tsconfig.json is missing or only references other projects, so it compiles nothing",
188
+ args: () => ["--noEmit", "--incremental", "false", "-p", "tsconfig.json", "--pretty", "false"],
189
+ parse: (res) => ({
190
+ findings: String(res.stdout).split("\n").filter((l) => /\berror TS\d+:/.test(l)).length,
191
+ note: "root tsconfig.json only",
192
+ }),
193
+ },
194
+ {
195
+ key: "ruff", tool: "ruff", lang: "python",
196
+ args: () => ["check", "--output-format", "json", "--no-cache", "."],
197
+ parse: (res) => {
198
+ const j = tryJson(res.stdout);
199
+ return Array.isArray(j) ? { findings: j.length } : { reason: "ruff printed no JSON report" };
200
+ },
201
+ },
202
+ {
203
+ key: "mypy", tool: "mypy", lang: "python",
204
+ config: () => hasRoot(["mypy.ini", ".mypy.ini"]) || ctx.textHas("pyproject.toml", /^\[tool\.mypy\]/m) || ctx.textHas("setup.cfg", /^\[mypy\]/m),
205
+ configReason: "the repo has no mypy config",
206
+ args: ({ tmp }) => ["--cache-dir", join(tmp, "mypy"), "--no-error-summary", "--no-color-output", "."],
207
+ parse: (res) => ({ findings: String(res.stdout).split("\n").filter((l) => /: error:/.test(l)).length }),
208
+ },
209
+ {
210
+ key: "dart", tool: ctx.flutterApp ? "flutter" : "dart", need: ctx.flutterApp ? "flutter" : "dart", lang: "dart",
211
+ config: () => ctx.fileSet.has("pubspec.yaml") && env.exists(join(ctx.root, ".dart_tool", "package_config.json")),
212
+ configReason: ctx.fileSet.has("pubspec.yaml")
213
+ ? "the Dart packages are not fetched here (no .dart_tool/package_config.json), so the analyzer cannot resolve imports"
214
+ : "the repo has no pubspec.yaml at its root",
215
+ args: () => (ctx.flutterApp ? ["analyze", "--no-pub", "--no-fatal-infos", "--no-fatal-warnings"] : ["analyze", "--format=machine"]),
216
+ okCodes: [0, 1, 2, 3],
217
+ parse: (res) => {
218
+ const out = `${res.stdout}\n${res.stderr}`.split("\n");
219
+ // flutter: " info • message • path:1:2 • code"; dart machine: SEVERITY|TYPE|CODE|FILE|...
220
+ const n = out.filter((l) => /^\s*(error|warning|info|hint) • /i.test(l) || /^(ERROR|WARNING|INFO)\|/.test(l)).length;
221
+ return { findings: n };
222
+ },
223
+ },
224
+ {
225
+ key: "shellcheck", tool: "shellcheck", lang: "shell",
226
+ // Chunked below: a long file list would overflow one command line.
227
+ args: ({ paths }) => ["-f", "json1", ...paths],
228
+ parse: (res) => {
229
+ const j = tryJson(res.stdout);
230
+ return Array.isArray(j?.comments) ? { findings: j.comments.length } : { reason: "shellcheck printed no JSON report" };
231
+ },
232
+ },
233
+ {
234
+ key: "detekt", tool: "detekt", need: "detekt-cli", lang: "kotlin",
235
+ config: () => has(/(^|\/)detekt(\.ya?ml|-config\.ya?ml)$/) || ctx.textHas("build.gradle.kts", /detekt/) || ctx.textHas("build.gradle", /detekt/),
236
+ configReason: "the repo has no detekt config",
237
+ args: ({ tmp }) => ["--input", ".", "--report", `txt:${join(tmp, "detekt.txt")}`],
238
+ okCodes: [0, 1, 2],
239
+ parse: (res, c) => {
240
+ const f = c.tmpText("detekt.txt");
241
+ if (f === null) return { reason: "detekt wrote no report" };
242
+ return { findings: f.split("\n").filter((l) => /\.kt(s)?:\d+:\d+/.test(l) || /^\S+ - \[/.test(l)).length };
243
+ },
244
+ },
245
+ {
246
+ key: "ktlint", tool: "ktlint", lang: "kotlin",
247
+ args: () => ["--reporter=plain", "**/*.kt", "**/*.kts"],
248
+ parse: (res) => ({ findings: String(res.stdout).split("\n").filter((l) => /\.kts?:\d+:\d+/.test(l)).length }),
249
+ },
250
+ ];
251
+ const out = {};
252
+ for (const spec of specs) {
253
+ out[spec.key] = spec.key === "shellcheck" ? shellcheckChunked(env, ctx, spec) : analyzer(env, ctx, spec);
254
+ }
255
+ return out;
256
+ }
257
+
258
+ function shellcheckChunked(env, ctx, spec) {
259
+ const paths = ctx.byLang.shell;
260
+ if (!paths.length) return none("no shell files");
261
+ const bin = findTool(env, ctx.root, "shellcheck", false);
262
+ if (!bin) return none("shellcheck is not installed");
263
+ let findings = 0;
264
+ for (let i = 0; i < paths.length; i += 100) {
265
+ const ran = runTool(env, "shellcheck", bin, ["-f", "json1", ...paths.slice(i, i + 100)], { cwd: ctx.root });
266
+ if (ran.reason) return none(ran.reason);
267
+ if (![0, 1].includes(ran.res.status)) return none(`shellcheck stopped with code ${ran.res.status}`);
268
+ const got = spec.parse(ran.res);
269
+ if (got.reason) return none(got.reason);
270
+ findings += got.findings;
271
+ }
272
+ const lines = countLines(env, ctx.root, paths);
273
+ return ok({ tool: "shellcheck", findings, lines, per1000: perThousand(findings, lines) });
274
+ }
275
+
276
+ // ── vulnerable dependencies ─────────────────────────────────────────────────
277
+
278
+ const LOCKFILES = new Set([
279
+ "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "npm-shrinkwrap.json", "bun.lock",
280
+ "poetry.lock", "Pipfile.lock", "uv.lock", "pdm.lock", "pubspec.lock", "Cargo.lock", "go.mod",
281
+ "composer.lock", "Gemfile.lock", "gradle.lockfile", "packages.lock.json", "Podfile.lock",
282
+ ]);
283
+ const SEVERITIES = ["critical", "high", "moderate", "low", "unknown"];
284
+
285
+ /** Pure: an osv-scanner JSON document to the reading. */
286
+ export function parseOsv(doc) {
287
+ const seen = new Map();
288
+ const results = Array.isArray(doc?.results) ? doc.results : [];
289
+ let packages = 0;
290
+ for (const r of results) {
291
+ for (const p of Array.isArray(r?.packages) ? r.packages : []) {
292
+ const vulns = Array.isArray(p?.vulnerabilities) ? p.vulnerabilities : [];
293
+ if (!vulns.length) continue;
294
+ packages++;
295
+ const key = `${p.package?.name}@${p.package?.version}`;
296
+ const e = seen.get(key) ?? { package: String(p.package?.name ?? "?"), version: String(p.package?.version ?? "?"), ids: new Set(), rank: 4 };
297
+ for (const v of vulns) {
298
+ e.ids.add(String(v.id ?? "?"));
299
+ const sev = String(v.database_specific?.severity ?? "").toLowerCase();
300
+ const idx = SEVERITIES.indexOf(sev === "medium" ? "moderate" : sev);
301
+ // OSV groups by advisory; the worst severity wins per package.
302
+ e.rank = Math.min(e.rank, idx < 0 ? 4 : idx);
303
+ }
304
+ seen.set(key, e);
305
+ }
306
+ }
307
+ const bySeverity = Object.fromEntries(SEVERITIES.map((s) => [s, 0]));
308
+ const advisories = new Map();
309
+ for (const r of results) {
310
+ for (const p of Array.isArray(r?.packages) ? r.packages : []) {
311
+ for (const v of Array.isArray(p?.vulnerabilities) ? p.vulnerabilities : []) {
312
+ const sev = String(v.database_specific?.severity ?? "").toLowerCase();
313
+ const idx = SEVERITIES.indexOf(sev === "medium" ? "moderate" : sev);
314
+ advisories.set(String(v.id ?? "?"), SEVERITIES[idx < 0 ? 4 : idx]);
315
+ }
316
+ }
317
+ }
318
+ for (const s of advisories.values()) bySeverity[s]++;
319
+ const items = [...seen.values()]
320
+ .sort((a, b) => a.rank - b.rank || a.package.localeCompare(b.package))
321
+ .map((e) => ({ package: e.package, version: e.version, severity: SEVERITIES[e.rank], ids: [...e.ids].sort() }));
322
+ return { total: advisories.size, packages, bySeverity, items: items.slice(0, LIST_MAX), itemsTotal: items.length };
323
+ }
324
+
325
+ function vulns(env, ctx) {
326
+ const locks = ctx.files.filter((p) => LOCKFILES.has(baseName(p)) && !p.split("/").some((s) => SKIP_DIRS.has(s)));
327
+ if (!locks.length) return none("the repo has no lockfile osv-scanner reads");
328
+ const bin = findTool(env, ctx.root, "osv-scanner", false);
329
+ if (!bin) return none("osv-scanner is not installed");
330
+ const args = ["scan", "source", "--format", "json", ...locks.flatMap((p) => ["-L", join(ctx.root, p)])];
331
+ const ran = runTool(env, "osv-scanner", bin, args, { cwd: ctx.root });
332
+ if (ran.reason) return none(ran.reason);
333
+ const { res } = ran;
334
+ // 0 clean, 1 vulnerabilities found; anything else is an error (no network, bad lockfile).
335
+ if (![0, 1].includes(res.status)) return none(`osv-scanner stopped with code ${res.status}${tail(res.stderr) ? `: ${tail(res.stderr)}` : ""}`);
336
+ const doc = tryJson(res.stdout);
337
+ if (!doc || typeof doc !== "object") return none("osv-scanner printed no JSON report");
338
+ return ok({ ...parseOsv(doc), lockfiles: locks.length });
339
+ }
340
+
341
+ // ── type strictness (configs only) ──────────────────────────────────────────
342
+
343
+ /** Strip comments and trailing commas from a tsconfig, then parse; null when it will not. */
344
+ export function parseJsonc(text) {
345
+ let out = "";
346
+ let i = 0;
347
+ while (i < text.length) {
348
+ const c = text[i];
349
+ if (c === '"') {
350
+ let j = i + 1;
351
+ while (j < text.length && text[j] !== '"') j += text[j] === "\\" ? 2 : 1;
352
+ out += text.slice(i, j + 1);
353
+ i = j + 1;
354
+ } else if (c === "/" && text[i + 1] === "/") {
355
+ while (i < text.length && text[i] !== "\n") i++;
356
+ } else if (c === "/" && text[i + 1] === "*") {
357
+ const j = text.indexOf("*/", i + 2);
358
+ i = j < 0 ? text.length : j + 2;
359
+ } else {
360
+ out += c;
361
+ i++;
362
+ }
363
+ }
364
+ return tryJson(out.replace(/,(\s*[}\]])/g, "$1"));
365
+ }
366
+
367
+ const bool = (v) => (v === true || v === false ? v : null);
368
+
369
+ function iniSection(text, header) {
370
+ const lines = text.split("\n");
371
+ const at = lines.findIndex((l) => l.trim() === header);
372
+ if (at < 0) return null;
373
+ const body = [];
374
+ for (let i = at + 1; i < lines.length && !/^\s*\[/.test(lines[i]); i++) body.push(lines[i]);
375
+ return body;
376
+ }
377
+ const iniBool = (body, key) => {
378
+ const m = body.map((l) => l.match(new RegExp(`^\\s*${key}\\s*=\\s*(true|false)\\s*(#.*)?$`, "i"))).find(Boolean);
379
+ return m ? m[1].toLowerCase() === "true" : null;
380
+ };
381
+
382
+ function strictness(env, ctx) {
383
+ const facts = [];
384
+ for (const p of ctx.files) {
385
+ const name = baseName(p);
386
+ if (SKIP_DIRS.has(p.split("/")[0]) || p.split("/").some((s) => SKIP_DIRS.has(s))) continue;
387
+ if (/^tsconfig(\.[\w-]+)?\.json$/.test(name)) {
388
+ const j = parseJsonc(env.readText(join(ctx.root, p)) ?? "");
389
+ const o = j?.compilerOptions;
390
+ if (!o) continue;
391
+ facts.push({
392
+ kind: "typescript", path: p,
393
+ settings: { strict: bool(o.strict), noUncheckedIndexedAccess: bool(o.noUncheckedIndexedAccess), ...(typeof j.extends === "string" ? { extends: true } : {}) },
394
+ });
395
+ } else if (name === "mypy.ini" || name === ".mypy.ini" || name === "setup.cfg" || name === "pyproject.toml") {
396
+ const text = env.readText(join(ctx.root, p)) ?? "";
397
+ const body = iniSection(text, name === "pyproject.toml" ? "[tool.mypy]" : "[mypy]");
398
+ if (!body) continue;
399
+ facts.push({
400
+ kind: "mypy", path: p,
401
+ settings: { strict: iniBool(body, "strict"), disallow_untyped_defs: iniBool(body, "disallow_untyped_defs"), check_untyped_defs: iniBool(body, "check_untyped_defs") },
402
+ });
403
+ } else if (name === "analysis_options.yaml") {
404
+ const text = env.readText(join(ctx.root, p)) ?? "";
405
+ const get = (k) => {
406
+ const m = text.match(new RegExp(`^\\s*${k}\\s*:\\s*(true|false)\\b`, "m"));
407
+ return m ? m[1] === "true" : null;
408
+ };
409
+ facts.push({
410
+ kind: "dart", path: p,
411
+ settings: { "strict-casts": get("strict-casts"), "strict-inference": get("strict-inference"), "strict-raw-types": get("strict-raw-types") },
412
+ });
413
+ }
414
+ }
415
+ if (!facts.length) return none("the repo has no tsconfig, mypy or analysis_options config to read");
416
+ return ok({ facts: facts.slice(0, LIST_MAX), total: facts.length });
417
+ }
418
+
419
+ // ── existing coverage files ─────────────────────────────────────────────────
420
+
421
+ const COVERAGE_NAMES = [
422
+ ["coverage/lcov.info", "lcov"], ["lcov.info", "lcov"], ["coverage.lcov", "lcov"],
423
+ ["coverage.xml", "cobertura"], ["coverage/cobertura-coverage.xml", "cobertura"], ["coverage/coverage.xml", "cobertura"],
424
+ ["coverage/coverage-final.json", "istanbul"], ["coverage-final.json", "istanbul"],
425
+ ];
426
+
427
+ /** Pure parsers: file text to `{covered, total}` or null. */
428
+ export function parseLcov(t) {
429
+ let lf = 0, lh = 0, seen = false;
430
+ for (const l of t.split("\n")) {
431
+ if (l.startsWith("LF:")) { lf += Number(l.slice(3)) || 0; seen = true; }
432
+ else if (l.startsWith("LH:")) lh += Number(l.slice(3)) || 0;
433
+ }
434
+ return seen && lf > 0 ? { covered: lh, total: lf } : null;
435
+ }
436
+ export function parseCobertura(t) {
437
+ const head = t.slice(0, 4000);
438
+ const valid = head.match(/\blines-valid="(\d+)"/);
439
+ const cov = head.match(/\blines-covered="(\d+)"/);
440
+ if (valid && cov && Number(valid[1]) > 0) return { covered: Number(cov[1]), total: Number(valid[1]) };
441
+ return null;
442
+ }
443
+ export function parseIstanbul(t) {
444
+ const j = tryJson(t);
445
+ if (!j || typeof j !== "object") return null;
446
+ let covered = 0, total = 0;
447
+ for (const f of Object.values(j)) {
448
+ const s = f?.s;
449
+ if (!s || typeof s !== "object") continue;
450
+ for (const n of Object.values(s)) { total++; if (n > 0) covered++; }
451
+ }
452
+ return total > 0 ? { covered, total } : null;
453
+ }
454
+ const COVERAGE_PARSERS = { lcov: parseLcov, cobertura: parseCobertura, istanbul: parseIstanbul };
455
+
456
+ function coverage(env, ctx) {
457
+ const dirs = [""];
458
+ for (const p of ctx.files) {
459
+ const m = p.match(/^((?:packages|apps)\/[^/]+)\//);
460
+ if (m && !dirs.includes(`${m[1]}/`)) dirs.push(`${m[1]}/`);
461
+ }
462
+ const files = [];
463
+ let stale = 0;
464
+ for (const dir of dirs) {
465
+ for (const [name, kind] of COVERAGE_NAMES) {
466
+ const rel = dir + name;
467
+ const abs = join(ctx.root, rel);
468
+ const mtime = env.mtime(abs);
469
+ if (mtime === null) continue;
470
+ if (ctx.commitTs !== null && mtime < ctx.commitTs) { stale++; continue; }
471
+ const text = env.readText(abs);
472
+ const got = text === null ? null : COVERAGE_PARSERS[kind](text);
473
+ if (!got) continue;
474
+ files.push({ path: rel, kind, covered: got.covered, total: got.total, percent: Math.round((got.covered / got.total) * 1000) / 10 });
475
+ }
476
+ }
477
+ if (!files.length) {
478
+ return none(stale ? `${stale} coverage file${stale === 1 ? " is" : "s are"} older than the last commit, so describe other code` : "no coverage file in the working directory");
479
+ }
480
+ return ok({ files: files.slice(0, LIST_MAX), total: files.length });
481
+ }
482
+
483
+ // ── entry ───────────────────────────────────────────────────────────────────
484
+
485
+ /**
486
+ * The newest commit's native readings.
487
+ *
488
+ * @param {string} root
489
+ * @param {{files: string[], commitTs?: number|null, env?: object}} input
490
+ * `files`: tracked paths at HEAD. `commitTs`: the commit's time in seconds.
491
+ */
492
+ export function measureNative(root, { files, commitTs = null, env = defaultEnv() }) {
493
+ let tmpDir = null;
494
+ const ctx = {
495
+ root,
496
+ files,
497
+ fileSet: new Set(files),
498
+ commitTs,
499
+ byLang: filesByLang(files),
500
+ tmp: () => (tmpDir ??= env.mkTmp()),
501
+ tmpText: (name) => (tmpDir ? env.readText(join(tmpDir, name)) : null),
502
+ textHas: (rel, re) => ctx.fileSet.has(rel) && re.test(env.readText(join(root, rel)) ?? ""),
503
+ pkgJsonHas: (key) => ctx.fileSet.has("package.json") && key in (tryJson(env.readText(join(root, "package.json")) ?? "") ?? {}),
504
+ flutterApp: false,
505
+ };
506
+ ctx.flutterApp = ctx.textHas("pubspec.yaml", /^[ \t]*sdk:[ \t]*flutter\b/m);
507
+ try {
508
+ return {
509
+ vulns: vulns(env, ctx),
510
+ dependencyAge: none("not read: a lockfile has no publish dates, and a registry lookup per package is a network call on every refresh"),
511
+ analyzers: analyzers(env, ctx),
512
+ strictness: strictness(env, ctx),
513
+ coverage: coverage(env, ctx),
514
+ };
515
+ } finally {
516
+ if (tmpDir) env.rmTmp(tmpDir);
517
+ }
518
+ }
519
+
520
+ /** The one place that spawns or touches the disk. */
521
+ export function defaultEnv() {
522
+ return {
523
+ path: String(process.env.PATH ?? "").split(delimiter).filter(Boolean),
524
+ exists: (p) => existsSync(p),
525
+ readText: (p) => {
526
+ try { return readFileSync(p, "utf8"); } catch { return null; }
527
+ },
528
+ mtime: (p) => {
529
+ try { return statSync(p).mtimeMs / 1000; } catch { return null; }
530
+ },
531
+ mkTmp: () => mkdtempSync(join(tmpdir(), "wp-native-")),
532
+ rmTmp: (d) => rmSync(d, { recursive: true, force: true }),
533
+ run: (cmd, args, opts) => {
534
+ const r = spawnSync(cmd, args, {
535
+ cwd: opts.cwd, encoding: "utf8", timeout: opts.timeout, killSignal: "SIGKILL",
536
+ maxBuffer: MAX_BUFFER, stdio: ["ignore", "pipe", "pipe"],
537
+ env: { ...process.env, CI: "1", NO_COLOR: "1", NODE_OPTIONS: "" },
538
+ });
539
+ return { status: r.status, signal: r.signal, stdout: r.stdout, stderr: r.stderr, error: r.error, timedOut: r.error?.code === "ETIMEDOUT" };
540
+ },
541
+ };
542
+ }
@@ -151,12 +151,24 @@ function mentionsOf(tests, packs, requireDir) {
151
151
  * it), the pack and the rule. A file with no oid is read and not kept.
152
152
  */
153
153
  const IMPORTS_MEMO = new Map();
154
- function importsOf(owner, file, requireDir) {
155
- if (!file.oid) return owner.pack.imports(file.text, file.path, { requireDir });
156
- const key = `${owner.name}\0${file.oid}\0${file.path}\0${requireDir ? 1 : 0}`;
154
+ // The pack's resolver context is per snapshot (tsconfig, workspace manifests):
155
+ // an answer resolved under one is not the answer under another, so its identity
156
+ // is part of the memo key.
157
+ const CTX_IDS = new WeakMap();
158
+ let CTX_SEQ = 0;
159
+ const ctxId = (ctx) => {
160
+ if (!ctx) return 0;
161
+ let id = CTX_IDS.get(ctx);
162
+ if (!id) CTX_IDS.set(ctx, (id = ++CTX_SEQ));
163
+ return id;
164
+ };
165
+ function importsOf(owner, file, requireDir, ctx) {
166
+ const opts = ctx ? { requireDir, ctx } : { requireDir };
167
+ if (!file.oid) return owner.pack.imports(file.text, file.path, opts);
168
+ const key = `${owner.name}\0${file.oid}\0${file.path}\0${requireDir ? 1 : 0}\0${ctxId(ctx)}`;
157
169
  let keys = IMPORTS_MEMO.get(key);
158
170
  if (!keys) {
159
- keys = [...owner.pack.imports(file.text, file.path, { requireDir })];
171
+ keys = [...owner.pack.imports(file.text, file.path, opts)];
160
172
  IMPORTS_MEMO.set(key, keys);
161
173
  }
162
174
  return keys;
@@ -180,7 +192,7 @@ function importsOf(owner, file, requireDir) {
180
192
  * @param {{f: {path: string, oid?: string, text: string}, owner: object}[]} readable
181
193
  * @returns {Set<string>} paths
182
194
  */
183
- function reachOf(readable, tests, prereg, requireDir) {
195
+ function reachOf(readable, tests, prereg, requireDir, contexts) {
184
196
  const leaf = (k) => (requireDir ? k : k.slice(k.lastIndexOf("/") + 1));
185
197
  /** key -> every readable module answering to it. Two modules on one key are
186
198
  * both reached, which is the ambiguity `mentions` already resolves the
@@ -210,11 +222,11 @@ function reachOf(readable, tests, prereg, requireDir) {
210
222
  };
211
223
  for (const t of tests) {
212
224
  const owner = packFor(t.path ?? "", prereg);
213
- if (owner && typeof owner.pack.imports === "function") visit(owner.pack.imports(t.text, t.path ?? "", { requireDir }));
225
+ if (owner && typeof owner.pack.imports === "function") visit(importsOf(owner, { text: t.text, path: t.path ?? "" }, requireDir, contexts?.[owner.name]));
214
226
  }
215
227
  while (queue.length) {
216
228
  const r = byPath.get(queue.pop());
217
- if (typeof r.owner.pack.imports === "function") visit(importsOf(r.owner, r.f, requireDir));
229
+ if (typeof r.owner.pack.imports === "function") visit(importsOf(r.owner, r.f, requireDir, contexts?.[r.owner.name]));
218
230
  }
219
231
  return reached;
220
232
  }
@@ -294,7 +306,7 @@ export function measureUntested(snapshot, history, index, prereg) {
294
306
  // A pack with a mention rule and no import rule contributes no edge, so its
295
307
  // modules are read on mentions alone — the definition this row had before
296
308
  // reach existed, and never a guess in the other direction.
297
- const reached = reachOf(readable, tests, prereg, requireDir);
309
+ const reached = reachOf(readable, tests, prereg, requireDir, snapshot.graphContexts);
298
310
  const out = [];
299
311
  const unnamed = [];
300
312
  for (const { f } of readable) {