plumbbob 0.9.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +92 -89
  3. package/dist/cli-core.js +25 -8
  4. package/dist/cli.js +1 -1
  5. package/dist/lib/agents.js +26 -26
  6. package/dist/lib/buildlog.js +11 -11
  7. package/dist/lib/buildlogsync.js +8 -8
  8. package/dist/lib/check.js +55 -22
  9. package/dist/lib/commitbody.js +72 -0
  10. package/dist/lib/commitmsg.js +7 -7
  11. package/dist/lib/git.js +44 -15
  12. package/dist/lib/intent.js +21 -20
  13. package/dist/lib/latch.js +19 -19
  14. package/dist/lib/orient.js +36 -17
  15. package/dist/lib/reentry.js +70 -0
  16. package/dist/lib/settings.js +16 -16
  17. package/dist/lib/sidecar.js +54 -54
  18. package/dist/lib/templates.js +1 -1
  19. package/dist/verbs/agent.js +27 -27
  20. package/dist/verbs/build.js +9 -9
  21. package/dist/verbs/check.js +6 -6
  22. package/dist/verbs/checkpoint.js +48 -47
  23. package/dist/verbs/doctor.js +31 -30
  24. package/dist/verbs/finish.js +28 -41
  25. package/dist/verbs/handoff.js +9 -8
  26. package/dist/verbs/init.js +9 -9
  27. package/dist/verbs/park.js +3 -3
  28. package/dist/verbs/recover.js +297 -0
  29. package/dist/verbs/revert.js +13 -13
  30. package/dist/verbs/spike.js +25 -19
  31. package/dist/verbs/start.js +49 -19
  32. package/dist/verbs/status.js +8 -8
  33. package/dist/verbs/turn.js +16 -16
  34. package/dist/verbs/use.js +4 -4
  35. package/hooks/post-edit.sh +4 -4
  36. package/hooks/pre-bash-commit.sh +3 -3
  37. package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
  38. package/node_modules/checkride/CHANGELOG.md +1404 -0
  39. package/node_modules/checkride/LICENSE +201 -21
  40. package/node_modules/checkride/README.md +197 -38
  41. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
  42. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
  43. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
  44. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
  45. package/node_modules/checkride/dist/adapters.d.ts +30 -10
  46. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  47. package/node_modules/checkride/dist/adapters.js +62 -23
  48. package/node_modules/checkride/dist/adapters.js.map +1 -1
  49. package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
  50. package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
  51. package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
  52. package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
  53. package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
  54. package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
  55. package/node_modules/checkride/dist/agent-setup/command.js +77 -0
  56. package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
  57. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +69 -0
  58. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
  59. package/node_modules/checkride/dist/agent-setup/cursor.js +247 -0
  60. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
  61. package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
  62. package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
  63. package/node_modules/checkride/dist/agent-setup/files.js +80 -0
  64. package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
  65. package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
  66. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
  67. package/node_modules/checkride/dist/agent-setup/harness.js +93 -0
  68. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
  69. package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
  70. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
  71. package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
  72. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
  73. package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
  74. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
  75. package/node_modules/checkride/dist/agent-setup/index.js +9 -4
  76. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
  77. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +81 -0
  78. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
  79. package/node_modules/checkride/dist/agent-setup/scripts.js +604 -0
  80. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
  81. package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
  82. package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
  83. package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
  84. package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
  85. package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
  86. package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
  87. package/node_modules/checkride/dist/artifacts/configured.js +45 -0
  88. package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
  89. package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
  90. package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
  91. package/node_modules/checkride/dist/artifacts/format.js +56 -0
  92. package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
  93. package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
  94. package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
  95. package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
  96. package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
  97. package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
  98. package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
  99. package/node_modules/checkride/dist/artifacts/index.js +19 -0
  100. package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
  101. package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
  102. package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
  103. package/node_modules/checkride/dist/artifacts/json.js +47 -0
  104. package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
  105. package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
  106. package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
  107. package/node_modules/checkride/dist/artifacts/raw.js +91 -0
  108. package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
  109. package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
  110. package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
  111. package/node_modules/checkride/dist/artifacts/summary.js +108 -0
  112. package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
  113. package/node_modules/checkride/dist/atomic.d.ts +16 -1
  114. package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
  115. package/node_modules/checkride/dist/atomic.js +25 -3
  116. package/node_modules/checkride/dist/atomic.js.map +1 -1
  117. package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
  118. package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
  119. package/node_modules/checkride/dist/baseline/fallow.js +163 -60
  120. package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
  121. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +20 -11
  122. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  123. package/node_modules/checkride/dist/baseline/fingerprint.js +73 -23
  124. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  125. package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
  126. package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
  127. package/node_modules/checkride/dist/baseline/history.js +232 -0
  128. package/node_modules/checkride/dist/baseline/history.js.map +1 -0
  129. package/node_modules/checkride/dist/baseline/index.d.ts +7 -5
  130. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  131. package/node_modules/checkride/dist/baseline/index.js +5 -4
  132. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  133. package/node_modules/checkride/dist/baseline/store.d.ts +41 -10
  134. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  135. package/node_modules/checkride/dist/baseline/store.js +65 -24
  136. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  137. package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
  138. package/node_modules/checkride/dist/baseline-command.js +7 -7
  139. package/node_modules/checkride/dist/baseline-command.js.map +1 -1
  140. package/node_modules/checkride/dist/cli.d.ts +21 -4
  141. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  142. package/node_modules/checkride/dist/cli.js +350 -36
  143. package/node_modules/checkride/dist/cli.js.map +1 -1
  144. package/node_modules/checkride/dist/config.d.ts +114 -9
  145. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  146. package/node_modules/checkride/dist/config.js +142 -23
  147. package/node_modules/checkride/dist/config.js.map +1 -1
  148. package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
  149. package/node_modules/checkride/dist/digest/digest.js +6 -6
  150. package/node_modules/checkride/dist/digest/index.d.ts +2 -2
  151. package/node_modules/checkride/dist/digest/index.js +2 -2
  152. package/node_modules/checkride/dist/doctor.d.ts +27 -6
  153. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  154. package/node_modules/checkride/dist/doctor.js +231 -27
  155. package/node_modules/checkride/dist/doctor.js.map +1 -1
  156. package/node_modules/checkride/dist/gate.d.ts +180 -0
  157. package/node_modules/checkride/dist/gate.d.ts.map +1 -0
  158. package/node_modules/checkride/dist/gate.js +617 -0
  159. package/node_modules/checkride/dist/gate.js.map +1 -0
  160. package/node_modules/checkride/dist/init.d.ts +79 -12
  161. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  162. package/node_modules/checkride/dist/init.js +385 -81
  163. package/node_modules/checkride/dist/init.js.map +1 -1
  164. package/node_modules/checkride/dist/json.d.ts +21 -0
  165. package/node_modules/checkride/dist/json.d.ts.map +1 -0
  166. package/node_modules/checkride/dist/json.js +21 -0
  167. package/node_modules/checkride/dist/json.js.map +1 -0
  168. package/node_modules/checkride/dist/links.d.ts +31 -5
  169. package/node_modules/checkride/dist/links.d.ts.map +1 -1
  170. package/node_modules/checkride/dist/links.js +141 -32
  171. package/node_modules/checkride/dist/links.js.map +1 -1
  172. package/node_modules/checkride/dist/node-pin.d.ts +129 -0
  173. package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
  174. package/node_modules/checkride/dist/node-pin.js +211 -0
  175. package/node_modules/checkride/dist/node-pin.js.map +1 -0
  176. package/node_modules/checkride/dist/orchestrator.d.ts +53 -10
  177. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  178. package/node_modules/checkride/dist/orchestrator.js +312 -113
  179. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  180. package/node_modules/checkride/dist/pack.d.ts +8 -9
  181. package/node_modules/checkride/dist/pack.d.ts.map +1 -1
  182. package/node_modules/checkride/dist/pack.js +53 -17
  183. package/node_modules/checkride/dist/pack.js.map +1 -1
  184. package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
  185. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
  186. package/node_modules/checkride/dist/pm/detect.js +6 -1
  187. package/node_modules/checkride/dist/pm/detect.js.map +1 -1
  188. package/node_modules/checkride/dist/pm/index.d.ts +7 -2
  189. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  190. package/node_modules/checkride/dist/pm/index.js +6 -2
  191. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  192. package/node_modules/checkride/dist/pm/launch.d.ts +72 -0
  193. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
  194. package/node_modules/checkride/dist/pm/launch.js +108 -0
  195. package/node_modules/checkride/dist/pm/launch.js.map +1 -0
  196. package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
  197. package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
  198. package/node_modules/checkride/dist/pm/tools.js +124 -0
  199. package/node_modules/checkride/dist/pm/tools.js.map +1 -0
  200. package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
  201. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
  202. package/node_modules/checkride/dist/pm/translate.js +78 -18
  203. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  204. package/node_modules/checkride/dist/proc.d.ts +30 -0
  205. package/node_modules/checkride/dist/proc.d.ts.map +1 -0
  206. package/node_modules/checkride/dist/proc.js +42 -0
  207. package/node_modules/checkride/dist/proc.js.map +1 -0
  208. package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
  209. package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
  210. package/node_modules/checkride/dist/qa/cli.js +24 -0
  211. package/node_modules/checkride/dist/qa/cli.js.map +1 -0
  212. package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
  213. package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
  214. package/node_modules/checkride/dist/qa/dead.js +88 -0
  215. package/node_modules/checkride/dist/qa/dead.js.map +1 -0
  216. package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
  217. package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
  218. package/node_modules/checkride/dist/qa/dupes.js +62 -0
  219. package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
  220. package/node_modules/checkride/dist/qa/health.d.ts +85 -0
  221. package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
  222. package/node_modules/checkride/dist/qa/health.js +109 -0
  223. package/node_modules/checkride/dist/qa/health.js.map +1 -0
  224. package/node_modules/checkride/dist/qa/index.d.ts +23 -0
  225. package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
  226. package/node_modules/checkride/dist/qa/index.js +22 -0
  227. package/node_modules/checkride/dist/qa/index.js.map +1 -0
  228. package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
  229. package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
  230. package/node_modules/checkride/dist/qa/mutation.js +195 -0
  231. package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
  232. package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
  233. package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
  234. package/node_modules/checkride/dist/qa/qa.js +158 -0
  235. package/node_modules/checkride/dist/qa/qa.js.map +1 -0
  236. package/node_modules/checkride/dist/qa/read.d.ts +40 -0
  237. package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
  238. package/node_modules/checkride/dist/qa/read.js +47 -0
  239. package/node_modules/checkride/dist/qa/read.js.map +1 -0
  240. package/node_modules/checkride/dist/qa/render.d.ts +26 -0
  241. package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
  242. package/node_modules/checkride/dist/qa/render.js +310 -0
  243. package/node_modules/checkride/dist/qa/render.js.map +1 -0
  244. package/node_modules/checkride/dist/recover.d.ts +48 -0
  245. package/node_modules/checkride/dist/recover.d.ts.map +1 -0
  246. package/node_modules/checkride/dist/recover.js +220 -0
  247. package/node_modules/checkride/dist/recover.js.map +1 -0
  248. package/node_modules/checkride/dist/security.d.ts +45 -0
  249. package/node_modules/checkride/dist/security.d.ts.map +1 -0
  250. package/node_modules/checkride/dist/security.js +86 -0
  251. package/node_modules/checkride/dist/security.js.map +1 -0
  252. package/node_modules/checkride/dist/smoke.d.ts +6 -6
  253. package/node_modules/checkride/dist/smoke.js +6 -6
  254. package/node_modules/checkride/dist/snippets.d.ts +27 -30
  255. package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
  256. package/node_modules/checkride/dist/snippets.js +26 -30
  257. package/node_modules/checkride/dist/snippets.js.map +1 -1
  258. package/node_modules/checkride/dist/tool-json.d.ts +33 -0
  259. package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
  260. package/node_modules/checkride/dist/tool-json.js +58 -0
  261. package/node_modules/checkride/dist/tool-json.js.map +1 -0
  262. package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
  263. package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
  264. package/node_modules/checkride/dist/triage/cli.js +26 -0
  265. package/node_modules/checkride/dist/triage/cli.js.map +1 -0
  266. package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
  267. package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
  268. package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
  269. package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
  270. package/node_modules/checkride/dist/triage/env.d.ts +54 -0
  271. package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
  272. package/node_modules/checkride/dist/triage/env.js +81 -0
  273. package/node_modules/checkride/dist/triage/env.js.map +1 -0
  274. package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
  275. package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
  276. package/node_modules/checkride/dist/triage/gate.js +121 -0
  277. package/node_modules/checkride/dist/triage/gate.js.map +1 -0
  278. package/node_modules/checkride/dist/triage/index.d.ts +22 -0
  279. package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
  280. package/node_modules/checkride/dist/triage/index.js +20 -0
  281. package/node_modules/checkride/dist/triage/index.js.map +1 -0
  282. package/node_modules/checkride/dist/triage/render.d.ts +19 -0
  283. package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
  284. package/node_modules/checkride/dist/triage/render.js +419 -0
  285. package/node_modules/checkride/dist/triage/render.js.map +1 -0
  286. package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
  287. package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
  288. package/node_modules/checkride/dist/triage/triage.js +131 -0
  289. package/node_modules/checkride/dist/triage/triage.js.map +1 -0
  290. package/node_modules/checkride/package.json +18 -15
  291. package/node_modules/checkride/schema/checkride.config.schema.json +70 -5
  292. package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
  293. package/node_modules/checkride/skills/check/SKILL.md +265 -0
  294. package/node_modules/checkride/skills/qa/SKILL.md +231 -0
  295. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  296. package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
  297. package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
  298. package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
  299. package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
  300. package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
  301. package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
  302. package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
  303. package/node_modules/checkride/templates/shared/vale.ini +34 -0
  304. package/package.json +10 -9
  305. package/skills/build/SKILL.md +85 -76
  306. package/skills/doctor/SKILL.md +11 -11
  307. package/skills/finish/SKILL.md +21 -18
  308. package/skills/harvest/SKILL.md +13 -11
  309. package/skills/park/SKILL.md +10 -10
  310. package/skills/plan/SKILL.md +69 -59
  311. package/skills/recover/SKILL.md +28 -0
  312. package/skills/refine/SKILL.md +21 -18
  313. package/skills/revert/SKILL.md +6 -6
  314. package/skills/spike/SKILL.md +9 -9
  315. package/skills/status/SKILL.md +5 -5
  316. package/skills/step/SKILL.md +20 -15
  317. package/skills/verify/SKILL.md +56 -46
  318. package/templates/build-log.md +7 -7
  319. package/templates/intent.md +52 -41
  320. package/templates/spike-report.md +10 -10
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Skill delivery for harnesses that have no plugin system.
3
+ *
4
+ * Claude Code gets `check` and `qa` from the bundled plugin
5
+ * (`.claude-plugin/plugin.json`), installed once and shared across every repo.
6
+ * Cursor has no equivalent — it discovers skills from directories on disk — so
7
+ * for Cursor the same two skills are written into the repo, from the same source
8
+ * files the plugin ships. One authored copy, two delivery mechanisms.
9
+ *
10
+ * The only edit made on the way through is the frontmatter `name`: a bare
11
+ * `check` would take the `/check` slash command in every repo it lands in, which
12
+ * is not a name checkride should be squatting. The plugin gets namespacing for
13
+ * free (`/checkride:check`); here it has to be spelled out.
14
+ */
15
+ import { dirname, join } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { putFile, readIfExists } from './files.js';
18
+ /** Where Cursor discovers project skills, relative to the repo root. */
19
+ export const CURSOR_SKILLS_DIR = '.cursor/skills';
20
+ const HERE = dirname(fileURLToPath(import.meta.url));
21
+ /** The package's own `skills/` directory, which ships in the published tarball. */
22
+ const SKILLS_DIR = join(HERE, '..', '..', 'skills');
23
+ /** Source skill → the name it takes once it is a repo-local Cursor skill. */
24
+ const SKILLS = [
25
+ { source: 'check', name: 'checkride-check' },
26
+ { source: 'qa', name: 'checkride-qa' },
27
+ ];
28
+ /**
29
+ * Rewrite the `name:` field inside the leading frontmatter block, and only
30
+ * there — a `name:` further down is prose in the skill body, not metadata.
31
+ */
32
+ export function renameSkill(body, name) {
33
+ const frontmatter = /^(---\r?\n)([\s\S]*?)(\r?\n---)/.exec(body);
34
+ if (!frontmatter)
35
+ return body;
36
+ const [, open, fields, close] = frontmatter;
37
+ const renamed = (fields ?? '').replace(/^name:.*$/m, `name: ${name}`);
38
+ return `${open}${renamed}${close}${body.slice(frontmatter[0].length)}`;
39
+ }
40
+ /**
41
+ * Write the bundled skills into `cwd`'s Cursor skills directory. A source skill
42
+ * that cannot be read is skipped rather than fatal: a broken or trimmed install
43
+ * should cost the skills, not the whole `agent-setup`.
44
+ */
45
+ export async function writeCursorSkills(cwd, opts = {}) {
46
+ const dryRun = opts.dryRun ?? false;
47
+ const written = await Promise.all(SKILLS.map(async (skill) => {
48
+ const body = await readIfExists(join(SKILLS_DIR, skill.source, 'SKILL.md'));
49
+ if (body === null)
50
+ return null;
51
+ const rel = `${CURSOR_SKILLS_DIR}/${skill.name}/SKILL.md`;
52
+ return putFile(cwd, rel, renameSkill(body, skill.name), { dryRun });
53
+ }));
54
+ return written.filter((f) => f !== null);
55
+ }
56
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/agent-setup/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnD,wEAAwE;AACxE,MAAM,CAAC,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAElD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAErD,mFAAmF;AACnF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpD,6EAA6E;AAC7E,MAAM,MAAM,GAAgD;IAC1D,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC5C,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE;CACvC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY;IACpD,MAAM,WAAW,GAAG,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,WAAW,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IACtE,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,OAA6B,EAAE;IAClF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;QAC5E,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,iBAAiB,IAAI,KAAK,CAAC,IAAI,WAAW,CAAC;QAC1D,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CACH,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * What the repo *declared* it checks — as opposed to what a given run selected.
3
+ *
4
+ * The summary records the slots a run selected; it says nothing about the ones
5
+ * the repo opted into and did not run. Both readers need that difference:
6
+ * triage uses it to name the slots a narrow run left uncovered, and the quality
7
+ * extractor uses it to tell "opted in but not run this time" apart from "never
8
+ * opted in at all" — three of its four artifacts come from opt-in slots, so the
9
+ * distinction decides whether a gap is a finding or the repo's normal state.
10
+ *
11
+ * `null` throughout means *unknowable*, never *empty*: a repo with no
12
+ * `checkride.config.json` runs the default catalogue, and neither reader will
13
+ * guess at it.
14
+ *
15
+ * The `../artifacts` barrel is this module's only public surface.
16
+ */
17
+ /**
18
+ * Slots the repo names in `checkride.config.json` and has not switched off
19
+ * (`false` disables one), sorted. `null` when the repo has no config file, or
20
+ * when the config is unparseable — that is the gate's problem to report, not
21
+ * the reader's to crash on.
22
+ *
23
+ * `cwd` is resolved first because `loadConfig` throws outright on a relative
24
+ * one, and both readers take their `cwd` from a command-line argument. Left
25
+ * unresolved, `dist/<reader>/cli.js .` would land in the catch below and report
26
+ * the repo's slots as *unknowable* — a silently degraded answer, which is the
27
+ * failure mode these readers exist to prevent.
28
+ */
29
+ export declare function configuredSlots(cwd: string): string[] | null;
30
+ //# sourceMappingURL=configured.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../../src/artifacts/configured.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAW5D"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * What the repo *declared* it checks — as opposed to what a given run selected.
3
+ *
4
+ * The summary records the slots a run selected; it says nothing about the ones
5
+ * the repo opted into and did not run. Both readers need that difference:
6
+ * triage uses it to name the slots a narrow run left uncovered, and the quality
7
+ * extractor uses it to tell "opted in but not run this time" apart from "never
8
+ * opted in at all" — three of its four artifacts come from opt-in slots, so the
9
+ * distinction decides whether a gap is a finding or the repo's normal state.
10
+ *
11
+ * `null` throughout means *unknowable*, never *empty*: a repo with no
12
+ * `checkride.config.json` runs the default catalogue, and neither reader will
13
+ * guess at it.
14
+ *
15
+ * The `../artifacts` barrel is this module's only public surface.
16
+ */
17
+ import { resolve } from 'node:path';
18
+ import { loadConfig } from '../config.js';
19
+ /**
20
+ * Slots the repo names in `checkride.config.json` and has not switched off
21
+ * (`false` disables one), sorted. `null` when the repo has no config file, or
22
+ * when the config is unparseable — that is the gate's problem to report, not
23
+ * the reader's to crash on.
24
+ *
25
+ * `cwd` is resolved first because `loadConfig` throws outright on a relative
26
+ * one, and both readers take their `cwd` from a command-line argument. Left
27
+ * unresolved, `dist/<reader>/cli.js .` would land in the catch below and report
28
+ * the repo's slots as *unknowable* — a silently degraded answer, which is the
29
+ * failure mode these readers exist to prevent.
30
+ */
31
+ export function configuredSlots(cwd) {
32
+ try {
33
+ const checks = loadConfig(resolve(cwd))?.checks;
34
+ if (!checks)
35
+ return null;
36
+ return Object.entries(checks)
37
+ .filter(([, value]) => value !== false)
38
+ .map(([slot]) => slot)
39
+ .toSorted();
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ //# sourceMappingURL=configured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configured.js","sourceRoot":"","sources":["../../src/artifacts/configured.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC;QAChD,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;aAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC;aACtC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;aACrB,QAAQ,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Human-scale rendering of the quantities both readers report: file sizes,
3
+ * elapsed time, and a bounded tail of captured output.
4
+ *
5
+ * Sizes and ages carry the judgment in a reader's table — "2.3 MB" and "4d" are
6
+ * the whole reason an agent knows not to open a file — so they get one
7
+ * implementation rather than one per reader.
8
+ *
9
+ * {@link tail} is truncation, never normalization: it drops whole lines from
10
+ * the front and says how many, leaving the bytes it keeps exactly as the tool
11
+ * emitted them.
12
+ *
13
+ * The `../artifacts` barrel is this module's only public surface.
14
+ */
15
+ /** `483 B`, `5.1 KB`, `2.3 MB` — one decimal above a kilobyte, none below. */
16
+ export declare function formatBytes(bytes: number): string;
17
+ /** `340ms`, `1.4s`, `12m`, `4.1d` — the coarsest unit that keeps a whole part. */
18
+ export declare function formatDuration(ms: number): string;
19
+ /** A bounded excerpt of captured output, with what it left out stated. */
20
+ export type Excerpt = {
21
+ text: string;
22
+ /** Lines dropped from the front, so the caller can say so rather than imply completeness. */
23
+ omittedLines: number;
24
+ /** Size of the full input, so "1.2 KB of 40 KB" is sayable. */
25
+ totalBytes: number;
26
+ };
27
+ /**
28
+ * The last `maxLines` non-blank lines of `text`, further trimmed from the front
29
+ * until the excerpt fits `maxBytes`. A compiler, a test runner and a crashing
30
+ * harness all put the thing worth reading at the end.
31
+ */
32
+ export declare function tail(text: string, maxLines: number, maxBytes: number): Excerpt;
33
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/artifacts/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AASD,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED,0EAA0E;AAC1E,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,6FAA6F;IAC7F,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQ9E"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Human-scale rendering of the quantities both readers report: file sizes,
3
+ * elapsed time, and a bounded tail of captured output.
4
+ *
5
+ * Sizes and ages carry the judgment in a reader's table — "2.3 MB" and "4d" are
6
+ * the whole reason an agent knows not to open a file — so they get one
7
+ * implementation rather than one per reader.
8
+ *
9
+ * {@link tail} is truncation, never normalization: it drops whole lines from
10
+ * the front and says how many, leaving the bytes it keeps exactly as the tool
11
+ * emitted them.
12
+ *
13
+ * The `../artifacts` barrel is this module's only public surface.
14
+ */
15
+ const UNITS = [
16
+ { limit: 1024 ** 3, suffix: 'GB' },
17
+ { limit: 1024 ** 2, suffix: 'MB' },
18
+ { limit: 1024, suffix: 'KB' },
19
+ ];
20
+ /** `483 B`, `5.1 KB`, `2.3 MB` — one decimal above a kilobyte, none below. */
21
+ export function formatBytes(bytes) {
22
+ for (const { limit, suffix } of UNITS) {
23
+ if (bytes >= limit)
24
+ return `${(bytes / limit).toFixed(1)} ${suffix}`;
25
+ }
26
+ return `${bytes} B`;
27
+ }
28
+ const DURATIONS = [
29
+ { limit: 86_400_000, suffix: 'd' },
30
+ { limit: 3_600_000, suffix: 'h' },
31
+ { limit: 60_000, suffix: 'm' },
32
+ { limit: 1000, suffix: 's' },
33
+ ];
34
+ /** `340ms`, `1.4s`, `12m`, `4.1d` — the coarsest unit that keeps a whole part. */
35
+ export function formatDuration(ms) {
36
+ for (const { limit, suffix } of DURATIONS) {
37
+ if (ms >= limit)
38
+ return `${(ms / limit).toFixed(1)}${suffix}`;
39
+ }
40
+ return `${Math.round(ms)}ms`;
41
+ }
42
+ /**
43
+ * The last `maxLines` non-blank lines of `text`, further trimmed from the front
44
+ * until the excerpt fits `maxBytes`. A compiler, a test runner and a crashing
45
+ * harness all put the thing worth reading at the end.
46
+ */
47
+ export function tail(text, maxLines, maxBytes) {
48
+ const lines = text.split('\n').filter((line) => line.trim() !== '');
49
+ const totalBytes = Buffer.byteLength(text, 'utf8');
50
+ let kept = lines.slice(-maxLines);
51
+ while (kept.length > 1 && Buffer.byteLength(kept.join('\n'), 'utf8') > maxBytes) {
52
+ kept = kept.slice(1);
53
+ }
54
+ return { text: kept.join('\n'), omittedLines: lines.length - kept.length, totalBytes };
55
+ }
56
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/artifacts/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,KAAK,GAAiD;IAC1D,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;IAClC,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;IAClC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;CAC9B,CAAC;AAEF,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACtC,IAAI,KAAK,IAAI,KAAK;YAAE,OAAO,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,GAAG,KAAK,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,SAAS,GAAiD;IAC9D,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE;IAClC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE;IACjC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;IAC9B,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;CAC7B,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC1C,IAAI,EAAE,IAAI,KAAK;YAAE,OAAO,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;AAC/B,CAAC;AAWD;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,QAAgB,EAAE,QAAgB;IACnE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;QAChF,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;AACzF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The freshness window — which `.check/` files belong to the run that wrote the
3
+ * summary sitting beside them.
4
+ *
5
+ * The window is `[timestamp - total_duration_ms, ∞)`: the run's *start*, not
6
+ * its end, because `timestamp` is stamped once every check has finished (see
7
+ * `buildSummary` in `../orchestrator.ts`) and every artifact the run just wrote
8
+ * is therefore older than it. Anything outside the window is labelled with its
9
+ * age, never silently dropped.
10
+ *
11
+ * Why a window at all, and why this derivation is contract-legal:
12
+ * `docs/plugin.md` §How the readers decide an artifact is stale.
13
+ *
14
+ * The `../artifacts` barrel is this module's only public surface.
15
+ */
16
+ import type { Summary } from '../orchestrator.js';
17
+ /** An artifact's standing relative to the run that wrote the summary. */
18
+ export type Freshness = {
19
+ /** `unknown` when the summary's `timestamp` could not be parsed. */
20
+ state: 'fresh' | 'stale' | 'unknown';
21
+ /** How long before the run started the file was written; `null` unless stale. */
22
+ ageMs: number | null;
23
+ };
24
+ /**
25
+ * Epoch milliseconds at which the run began, or `null` when `timestamp` is not
26
+ * a parseable date. Callers treat `null` as "cannot judge freshness" rather
27
+ * than guessing in either direction.
28
+ */
29
+ export declare function runWindowStart(summary: Summary): number | null;
30
+ /** Classify one artifact's mtime against the window from {@link runWindowStart}. */
31
+ export declare function classifyFreshness(mtimeMs: number, windowStart: number | null): Freshness;
32
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../src/artifacts/freshness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG;IACtB,oEAAoE;IACpE,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACrC,iFAAiF;IACjF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI9D;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAIxF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The freshness window — which `.check/` files belong to the run that wrote the
3
+ * summary sitting beside them.
4
+ *
5
+ * The window is `[timestamp - total_duration_ms, ∞)`: the run's *start*, not
6
+ * its end, because `timestamp` is stamped once every check has finished (see
7
+ * `buildSummary` in `../orchestrator.ts`) and every artifact the run just wrote
8
+ * is therefore older than it. Anything outside the window is labelled with its
9
+ * age, never silently dropped.
10
+ *
11
+ * Why a window at all, and why this derivation is contract-legal:
12
+ * `docs/plugin.md` §How the readers decide an artifact is stale.
13
+ *
14
+ * The `../artifacts` barrel is this module's only public surface.
15
+ */
16
+ const FRESH = { state: 'fresh', ageMs: null };
17
+ const UNKNOWN = { state: 'unknown', ageMs: null };
18
+ /**
19
+ * Epoch milliseconds at which the run began, or `null` when `timestamp` is not
20
+ * a parseable date. Callers treat `null` as "cannot judge freshness" rather
21
+ * than guessing in either direction.
22
+ */
23
+ export function runWindowStart(summary) {
24
+ const stamped = Date.parse(summary.timestamp);
25
+ if (Number.isNaN(stamped))
26
+ return null;
27
+ return stamped - summary.total_duration_ms;
28
+ }
29
+ /** Classify one artifact's mtime against the window from {@link runWindowStart}. */
30
+ export function classifyFreshness(mtimeMs, windowStart) {
31
+ if (windowStart === null)
32
+ return UNKNOWN;
33
+ if (mtimeMs >= windowStart)
34
+ return FRESH;
35
+ return { state: 'stale', ageMs: windowStart - mtimeMs };
36
+ }
37
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../../src/artifacts/freshness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAYH,MAAM,KAAK,GAAc,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzD,MAAM,OAAO,GAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAE7D;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC;AAC7C,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,WAA0B;IAC3E,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,IAAI,WAAW;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,EAAE,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Artifacts module — the shared, bounded read of what a checkride run left in
3
+ * `.check/`. Parse the summary and pin its schema, judge each file against the
4
+ * run's freshness window, resolve a slot's raw output by the documented
5
+ * convention, and size what was found without opening it.
6
+ *
7
+ * Both bundled-plugin readers (`../triage` and `../qa`) consume the
8
+ * contract only through here — one copy of the summary parse,
9
+ * one freshness rule, one raw-output lookup. This barrel is the module's only
10
+ * public surface: siblings import from `../artifacts/index.js`, never from a
11
+ * file inside it.
12
+ */
13
+ export { configuredSlots } from './configured.js';
14
+ export { formatBytes, formatDuration, tail } from './format.js';
15
+ export { classifyFreshness, runWindowStart } from './freshness.js';
16
+ export type { Freshness } from './freshness.js';
17
+ export { asNumberOrNull, asRecord, asRecordArray, asStringOrNull, isRecord, parseJson } from './json.js';
18
+ export { listArtifacts, resolveRawOutput, statArtifact } from './raw.js';
19
+ export type { ArtifactFile, RawOutput } from './raw.js';
20
+ export { CHECK_DIR, parseSummary, readSummary, SUPPORTED_SCHEMA_VERSION } from './summary.js';
21
+ export type { SummaryRead } from './summary.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEzG,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC9F,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Artifacts module — the shared, bounded read of what a checkride run left in
3
+ * `.check/`. Parse the summary and pin its schema, judge each file against the
4
+ * run's freshness window, resolve a slot's raw output by the documented
5
+ * convention, and size what was found without opening it.
6
+ *
7
+ * Both bundled-plugin readers (`../triage` and `../qa`) consume the
8
+ * contract only through here — one copy of the summary parse,
9
+ * one freshness rule, one raw-output lookup. This barrel is the module's only
10
+ * public surface: siblings import from `../artifacts/index.js`, never from a
11
+ * file inside it.
12
+ */
13
+ export { configuredSlots } from './configured.js';
14
+ export { formatBytes, formatDuration, tail } from './format.js';
15
+ export { classifyFreshness, runWindowStart } from './freshness.js';
16
+ export { asNumberOrNull, asRecord, asRecordArray, asStringOrNull, isRecord, parseJson } from './json.js';
17
+ export { listArtifacts, resolveRawOutput, statArtifact } from './raw.js';
18
+ export { CHECK_DIR, parseSummary, readSummary, SUPPORTED_SCHEMA_VERSION } from './summary.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEzG,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGzE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Defensive JSON narrowing for artifact reads.
3
+ *
4
+ * Both readers parse files a *different* checkride version may have written, so
5
+ * every field access goes through a guard rather than a cast: a reader that
6
+ * crashes on an unexpected shape is worse than one that says what it could not
7
+ * read. These are the smallest primitives that make a `JSON.parse` result
8
+ * usable without `any` and without asserting a type onto unvalidated bytes.
9
+ *
10
+ * The `../artifacts` barrel is this module's only public surface.
11
+ */
12
+ import { isRecord } from '../json.js';
13
+ import type { JsonRecord } from '../json.js';
14
+ export { isRecord };
15
+ export type { JsonRecord };
16
+ /** A string field, or `null` for every other type — including a missing key. */
17
+ export declare function asStringOrNull(value: unknown): string | null;
18
+ /** A number field, or `null` for every other type — including a missing key. */
19
+ export declare function asNumberOrNull(value: unknown): number | null;
20
+ /**
21
+ * A nested object, or an empty one when the key is missing or holds something
22
+ * else. Reading a handful of fields off a block that may not exist is the
23
+ * common shape in these artifacts, and `{}` makes every such read a `null`
24
+ * rather than a branch at each call site.
25
+ */
26
+ export declare function asRecord(value: unknown): JsonRecord;
27
+ /** The object entries of an array field; `[]` when it is not an array at all. */
28
+ export declare function asRecordArray(value: unknown): JsonRecord[];
29
+ /** Parse JSON without throwing: the parsed value, or `null` when it is not JSON. */
30
+ export declare function parseJson(raw: string): unknown;
31
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/artifacts/json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK7C,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAEnD;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,EAAE,CAE1D;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAM9C"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Defensive JSON narrowing for artifact reads.
3
+ *
4
+ * Both readers parse files a *different* checkride version may have written, so
5
+ * every field access goes through a guard rather than a cast: a reader that
6
+ * crashes on an unexpected shape is worse than one that says what it could not
7
+ * read. These are the smallest primitives that make a `JSON.parse` result
8
+ * usable without `any` and without asserting a type onto unvalidated bytes.
9
+ *
10
+ * The `../artifacts` barrel is this module's only public surface.
11
+ */
12
+ import { isRecord } from '../json.js';
13
+ // `isRecord`/`JsonRecord` are the package-wide primitives (`../json.ts`);
14
+ // re-exported here so the artifacts barrel keeps its existing surface and the
15
+ // readers' import sites are unchanged.
16
+ export { isRecord };
17
+ /** A string field, or `null` for every other type — including a missing key. */
18
+ export function asStringOrNull(value) {
19
+ return typeof value === 'string' ? value : null;
20
+ }
21
+ /** A number field, or `null` for every other type — including a missing key. */
22
+ export function asNumberOrNull(value) {
23
+ return typeof value === 'number' ? value : null;
24
+ }
25
+ /**
26
+ * A nested object, or an empty one when the key is missing or holds something
27
+ * else. Reading a handful of fields off a block that may not exist is the
28
+ * common shape in these artifacts, and `{}` makes every such read a `null`
29
+ * rather than a branch at each call site.
30
+ */
31
+ export function asRecord(value) {
32
+ return isRecord(value) ? value : {};
33
+ }
34
+ /** The object entries of an array field; `[]` when it is not an array at all. */
35
+ export function asRecordArray(value) {
36
+ return Array.isArray(value) ? value.filter(isRecord) : [];
37
+ }
38
+ /** Parse JSON without throwing: the parsed value, or `null` when it is not JSON. */
39
+ export function parseJson(raw) {
40
+ try {
41
+ return JSON.parse(raw);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/artifacts/json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,0EAA0E;AAC1E,8EAA8E;AAC9E,uCAAuC;AACvC,OAAO,EAAE,QAAQ,EAAE,CAAC;AAGpB,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Locating a slot's raw output — the bytes the summary indexes but usually does
3
+ * not name.
4
+ *
5
+ * `output_file` is populated only when a tool emits JSON on stdout, so most
6
+ * slots carry `null` there while their real output sits in `.check/` under the
7
+ * documented convention (`<slot>.json`, else `<slot>.stdout.txt` /
8
+ * `<slot>.stderr.txt`). On a full run of this repo, 8 of 17 checks name no file
9
+ * — `test` among them, the slot most likely to need triage. A reader that
10
+ * reported "no output" for those would be wrong about the one thing it exists
11
+ * to get right, so it owns the convention as a fallback.
12
+ *
13
+ * Everything found is measured, never opened: the readers report *sizes* and
14
+ * point at the file. `mutation.json` in this repo is 2.3 MB; `test.json` is
15
+ * 650 KB beside a 5 KB `test.stdout.txt` saying the same thing, which is why a
16
+ * smaller text sibling wins over a large JSON one.
17
+ *
18
+ * The `../artifacts` barrel is this module's only public surface.
19
+ */
20
+ import type { Freshness } from './freshness.js';
21
+ /** One measured `.check/` file. Size and standing only — never contents. */
22
+ export type ArtifactFile = {
23
+ /** Name within `.check/`, as an agent would type it: `lint.json`. */
24
+ file: string;
25
+ /** Absolute path, for a caller that does choose to open it. */
26
+ path: string;
27
+ bytes: number;
28
+ mtimeMs: number;
29
+ freshness: Freshness;
30
+ };
31
+ /**
32
+ * A slot's raw output: the file worth reading first, plus every other candidate
33
+ * found — so a caller can say what else is there instead of implying the chosen
34
+ * one is all of it.
35
+ */
36
+ export type RawOutput = {
37
+ chosen: ArtifactFile;
38
+ candidates: ArtifactFile[];
39
+ };
40
+ /** Measure one `.check/` file, or `null` when it does not exist. */
41
+ export declare function statArtifact(checkDir: string, file: string, windowStart: number | null): Promise<ArtifactFile | null>;
42
+ /**
43
+ * Measure every file directly in `checkDir`, name-ordered so the render is
44
+ * byte-stable. Subdirectories and anything that vanishes mid-read drop out;
45
+ * an absent directory is `[]`, because "there is nothing there" is an answer.
46
+ *
47
+ * This is the fallback index. Normally the summary names what to look at and
48
+ * {@link resolveRawOutput} locates it, but when the summary cannot be parsed
49
+ * the directory itself is the only inventory that exists — and a reader that
50
+ * gave up there would leave an agent to run `ls` by hand, which is the
51
+ * unbounded read this module exists to prevent.
52
+ */
53
+ export declare function listArtifacts(checkDir: string, windowStart: number | null): Promise<ArtifactFile[]>;
54
+ /**
55
+ * Resolve a slot's raw output under `checkDir`, freshness-gating whatever it
56
+ * finds — a stale candidate is labelled, not dropped. `null` only when the slot
57
+ * genuinely wrote nothing.
58
+ */
59
+ export declare function resolveRawOutput(checkDir: string, slot: string, outputFile: string | null, windowStart: number | null): Promise<RawOutput | null>;
60
+ //# sourceMappingURL=raw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/artifacts/raw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG;IACzB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAE7E,oEAAoE;AACpE,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAWzG;AAwBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAO3B"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Locating a slot's raw output — the bytes the summary indexes but usually does
3
+ * not name.
4
+ *
5
+ * `output_file` is populated only when a tool emits JSON on stdout, so most
6
+ * slots carry `null` there while their real output sits in `.check/` under the
7
+ * documented convention (`<slot>.json`, else `<slot>.stdout.txt` /
8
+ * `<slot>.stderr.txt`). On a full run of this repo, 8 of 17 checks name no file
9
+ * — `test` among them, the slot most likely to need triage. A reader that
10
+ * reported "no output" for those would be wrong about the one thing it exists
11
+ * to get right, so it owns the convention as a fallback.
12
+ *
13
+ * Everything found is measured, never opened: the readers report *sizes* and
14
+ * point at the file. `mutation.json` in this repo is 2.3 MB; `test.json` is
15
+ * 650 KB beside a 5 KB `test.stdout.txt` saying the same thing, which is why a
16
+ * smaller text sibling wins over a large JSON one.
17
+ *
18
+ * The `../artifacts` barrel is this module's only public surface.
19
+ */
20
+ import { readdir, stat } from 'node:fs/promises';
21
+ import { join } from 'node:path';
22
+ import { classifyFreshness } from './freshness.js';
23
+ /** Measure one `.check/` file, or `null` when it does not exist. */
24
+ export async function statArtifact(checkDir, file, windowStart) {
25
+ const path = join(checkDir, file);
26
+ try {
27
+ const stats = await stat(path);
28
+ if (!stats.isFile())
29
+ return null;
30
+ return { file, path, bytes: stats.size, mtimeMs: stats.mtimeMs, freshness: classifyFreshness(stats.mtimeMs, windowStart) };
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Measure every file directly in `checkDir`, name-ordered so the render is
38
+ * byte-stable. Subdirectories and anything that vanishes mid-read drop out;
39
+ * an absent directory is `[]`, because "there is nothing there" is an answer.
40
+ *
41
+ * This is the fallback index. Normally the summary names what to look at and
42
+ * {@link resolveRawOutput} locates it, but when the summary cannot be parsed
43
+ * the directory itself is the only inventory that exists — and a reader that
44
+ * gave up there would leave an agent to run `ls` by hand, which is the
45
+ * unbounded read this module exists to prevent.
46
+ */
47
+ export async function listArtifacts(checkDir, windowStart) {
48
+ let names;
49
+ try {
50
+ names = await readdir(checkDir);
51
+ }
52
+ catch {
53
+ return [];
54
+ }
55
+ const found = await Promise.all(names.toSorted().map((name) => statArtifact(checkDir, name, windowStart)));
56
+ return found.filter((file) => file !== null);
57
+ }
58
+ /**
59
+ * The convention, in priority order: what the summary named, then the JSON file,
60
+ * then the captured streams. Deduped, because `output_file` is usually
61
+ * `<slot>.json` when it is set at all.
62
+ */
63
+ function candidateNames(slot, outputFile) {
64
+ const names = [outputFile, `${slot}.json`, `${slot}.stdout.txt`, `${slot}.stderr.txt`];
65
+ return [...new Set(names.filter((name) => name !== null))];
66
+ }
67
+ /**
68
+ * Pick what to read first. The convention order wins, except that a *smaller*
69
+ * text sibling beats a large JSON file: `test.stdout.txt` (5 KB) carries the
70
+ * same failure `test.json` (650 KB) does, and a reader that sends an agent to
71
+ * the big one has spent the context it was built to save. A text file that is
72
+ * already first stays first — stdout is the diagnostics, stderr the leftovers.
73
+ */
74
+ function chooseRaw(first, rest) {
75
+ if (first.file.endsWith('.txt'))
76
+ return first;
77
+ return rest.find((c) => c.file.endsWith('.txt') && c.bytes < first.bytes) ?? first;
78
+ }
79
+ /**
80
+ * Resolve a slot's raw output under `checkDir`, freshness-gating whatever it
81
+ * finds — a stale candidate is labelled, not dropped. `null` only when the slot
82
+ * genuinely wrote nothing.
83
+ */
84
+ export async function resolveRawOutput(checkDir, slot, outputFile, windowStart) {
85
+ const found = await Promise.all(candidateNames(slot, outputFile).map((name) => statArtifact(checkDir, name, windowStart)));
86
+ const [first, ...rest] = found.filter((c) => c !== null);
87
+ if (first === undefined)
88
+ return null;
89
+ return { chosen: chooseRaw(first, rest), candidates: [first, ...rest] };
90
+ }
91
+ //# sourceMappingURL=raw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw.js","sourceRoot":"","sources":["../../src/artifacts/raw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAoBnD,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,IAAY,EACZ,WAA0B;IAE1B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;IAC7H,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,WAA0B;IAC9E,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAC1E,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAwB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,UAAyB;IAC7D,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,GAAG,IAAI,aAAa,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,KAAmB,EAAE,IAA6B;IACnE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;AACrF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,IAAY,EACZ,UAAyB,EACzB,WAA0B;IAE1B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAC1F,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC5E,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;AAC1E,CAAC"}