@joshuafolkken/kit 1.872.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 (1108) hide show
  1. package/.claude/.claude-plugin/plugin.json +11 -0
  2. package/.claude/settings.json +110 -0
  3. package/.claude/skills/dependency-update/SKILL.md +76 -0
  4. package/.claude/skills/epic-commands/SKILL.md +463 -0
  5. package/.claude/skills/verify-ui/SKILL.md +96 -0
  6. package/.claude/skills/workflow-commands/SKILL.md +265 -0
  7. package/.claude/skills/workflow-commands/background-commands.md +130 -0
  8. package/.claude/skills/workflow-commands/backlogrun-child.md +364 -0
  9. package/.claude/skills/workflow-commands/backlogrun-lanes.md +345 -0
  10. package/.claude/skills/workflow-commands/backlogrun-park.md +179 -0
  11. package/.claude/skills/workflow-commands/backlogrun-progress.md +600 -0
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +604 -0
  13. package/.claude/skills/workflow-commands/backlogrun.md +109 -0
  14. package/.claude/skills/workflow-commands/chain-rule.md +98 -0
  15. package/.claude/skills/workflow-commands/delegation.md +52 -0
  16. package/.claude/skills/workflow-commands/followup-reference.md +118 -0
  17. package/.claude/skills/workflow-commands/followup.md +222 -0
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +93 -0
  19. package/.claude/skills/workflow-commands/fullrun.md +82 -0
  20. package/.claude/skills/workflow-commands/halfrun.md +73 -0
  21. package/.claude/skills/workflow-commands/into-target.md +48 -0
  22. package/.claude/skills/workflow-commands/issue-comments.md +109 -0
  23. package/.claude/skills/workflow-commands/issue-fold-existing.md +27 -0
  24. package/.claude/skills/workflow-commands/issue-scout.md +45 -0
  25. package/.claude/skills/workflow-commands/kickoff.md +82 -0
  26. package/.claude/skills/workflow-commands/latest-gate.md +85 -0
  27. package/.claude/skills/workflow-commands/needs-human-review.md +64 -0
  28. package/.claude/skills/workflow-commands/observation-filing.md +349 -0
  29. package/.claude/skills/workflow-commands/pre-gate-cut.md +340 -0
  30. package/.claude/skills/workflow-commands/prerequisite.md +62 -0
  31. package/.claude/skills/workflow-commands/retrospective.md +81 -0
  32. package/.claude/skills/workflow-commands/rule-residency.md +267 -0
  33. package/.claude/skills/workflow-commands/split-assessment.md +130 -0
  34. package/.claude/skills/workflow-commands/target-repository.md +58 -0
  35. package/.claude/skills/workflow-commands/working-tree-hold.md +66 -0
  36. package/.claude-plugin/marketplace.json +15 -0
  37. package/.coderabbit.yaml +50 -0
  38. package/.codex/config.toml +8 -0
  39. package/.codex/hooks.json +71 -0
  40. package/.cursorrules +45 -0
  41. package/.gitattributes +7 -0
  42. package/.github/dependabot.yml +19 -0
  43. package/.github/pull_request_template.md +1 -0
  44. package/.github/release.yml +18 -0
  45. package/.github/workflows/auto-tag.yml +111 -0
  46. package/.github/workflows/ci.yml +681 -0
  47. package/.github/workflows/dependabot-auto-merge.yml +55 -0
  48. package/.github/workflows/production.yml +47 -0
  49. package/.github/workflows/publish.yml +39 -0
  50. package/.github/workflows/sonar-qube.yml +34 -0
  51. package/.mcp.json +8 -0
  52. package/.ncurc.json +3 -0
  53. package/.prettierignore +20 -0
  54. package/.vscode/extensions.json +21 -0
  55. package/.vscode/settings.json +41 -0
  56. package/AGENTS.md +29 -0
  57. package/CLAUDE.md +207 -0
  58. package/CODE_OF_CONDUCT.md +132 -0
  59. package/GEMINI.md +30 -0
  60. package/LICENSE +21 -0
  61. package/README.md +41 -0
  62. package/SECURITY.md +34 -0
  63. package/cspell/index.yaml +177 -0
  64. package/dist/CLAUDE.md +207 -0
  65. package/dist/config-merge/index.d.ts +29 -0
  66. package/dist/config-merge/index.js +459 -0
  67. package/dist/hooks/batch-guard.js +28 -0
  68. package/dist/hooks/chunk-25JL6FMS.js +4970 -0
  69. package/dist/hooks/chunk-2ANGT3XM.js +375 -0
  70. package/dist/hooks/chunk-2EI5GBSW.js +42 -0
  71. package/dist/hooks/chunk-2OT5XE2N.js +5014 -0
  72. package/dist/hooks/chunk-2RUPMGGV.js +137 -0
  73. package/dist/hooks/chunk-2XIGZQMQ.js +3299 -0
  74. package/dist/hooks/chunk-33ELOKEV.js +910 -0
  75. package/dist/hooks/chunk-33YRTKM7.js +230 -0
  76. package/dist/hooks/chunk-36JQU5NN.js +77 -0
  77. package/dist/hooks/chunk-3EJBTWVS.js +1769 -0
  78. package/dist/hooks/chunk-3FK5SFAC.js +432 -0
  79. package/dist/hooks/chunk-3PWPYDD2.js +240 -0
  80. package/dist/hooks/chunk-3TQU7TDH.js +375 -0
  81. package/dist/hooks/chunk-3TVLSFZ6.js +432 -0
  82. package/dist/hooks/chunk-3VXYCB4E.js +77 -0
  83. package/dist/hooks/chunk-44M6JXGV.js +3398 -0
  84. package/dist/hooks/chunk-46EEEHC3.js +240 -0
  85. package/dist/hooks/chunk-4A7UVP2P.js +364 -0
  86. package/dist/hooks/chunk-4LFQEZS4.js +137 -0
  87. package/dist/hooks/chunk-4OCX3V2T.js +469 -0
  88. package/dist/hooks/chunk-4OHA5DE7.js +49 -0
  89. package/dist/hooks/chunk-4PMDW3YD.js +68 -0
  90. package/dist/hooks/chunk-4QHBNAI4.js +68 -0
  91. package/dist/hooks/chunk-4SSB3FEE.js +3273 -0
  92. package/dist/hooks/chunk-5A2WQ2CQ.js +5390 -0
  93. package/dist/hooks/chunk-5EVA2JQB.js +5390 -0
  94. package/dist/hooks/chunk-5P7VF5VE.js +3230 -0
  95. package/dist/hooks/chunk-5QWJGGZP.js +49 -0
  96. package/dist/hooks/chunk-5U5EZYG6.js +77 -0
  97. package/dist/hooks/chunk-5VUUF3ZV.js +240 -0
  98. package/dist/hooks/chunk-5WA7UBT3.js +374 -0
  99. package/dist/hooks/chunk-6EBGRQ3Q.js +301 -0
  100. package/dist/hooks/chunk-6TVHWMD3.js +432 -0
  101. package/dist/hooks/chunk-6V5OPIUU.js +13 -0
  102. package/dist/hooks/chunk-6VAGLEMB.js +68 -0
  103. package/dist/hooks/chunk-75BTXKFJ.js +3424 -0
  104. package/dist/hooks/chunk-75RHN67S.js +137 -0
  105. package/dist/hooks/chunk-76KC3BDD.js +3414 -0
  106. package/dist/hooks/chunk-76SLS7CZ.js +898 -0
  107. package/dist/hooks/chunk-7DHZ4DWT.js +5015 -0
  108. package/dist/hooks/chunk-7INSJDGE.js +458 -0
  109. package/dist/hooks/chunk-7VJ4FTDX.js +268 -0
  110. package/dist/hooks/chunk-7XCYNHQK.js +77 -0
  111. package/dist/hooks/chunk-A5YJ3H7E.js +375 -0
  112. package/dist/hooks/chunk-AAEXXUUL.js +268 -0
  113. package/dist/hooks/chunk-ABVEVV2M.js +432 -0
  114. package/dist/hooks/chunk-ACN3YXFL.js +68 -0
  115. package/dist/hooks/chunk-AD3XE3QZ.js +397 -0
  116. package/dist/hooks/chunk-AENFZPZH.js +230 -0
  117. package/dist/hooks/chunk-AFKRFQ6W.js +68 -0
  118. package/dist/hooks/chunk-AHD5IPWI.js +375 -0
  119. package/dist/hooks/chunk-AMK5JGV7.js +77 -0
  120. package/dist/hooks/chunk-ARN7NCQI.js +425 -0
  121. package/dist/hooks/chunk-AUFY653N.js +3425 -0
  122. package/dist/hooks/chunk-AXQBNFEF.js +375 -0
  123. package/dist/hooks/chunk-AYC7R6U4.js +3316 -0
  124. package/dist/hooks/chunk-AYEA2FJ7.js +5015 -0
  125. package/dist/hooks/chunk-B2LIXYFL.js +77 -0
  126. package/dist/hooks/chunk-B4HPNY2I.js +375 -0
  127. package/dist/hooks/chunk-B4YNCUGB.js +469 -0
  128. package/dist/hooks/chunk-B57S3VWT.js +922 -0
  129. package/dist/hooks/chunk-BINZ3PLI.js +364 -0
  130. package/dist/hooks/chunk-BIWLABFK.js +432 -0
  131. package/dist/hooks/chunk-BODUSXKK.js +410 -0
  132. package/dist/hooks/chunk-BQBAT2YK.js +375 -0
  133. package/dist/hooks/chunk-BUJEBW75.js +391 -0
  134. package/dist/hooks/chunk-BVNWORKA.js +72 -0
  135. package/dist/hooks/chunk-BWI47LQS.js +5205 -0
  136. package/dist/hooks/chunk-C25HRMJX.js +137 -0
  137. package/dist/hooks/chunk-CBFZNC74.js +375 -0
  138. package/dist/hooks/chunk-CECYXS4Y.js +3424 -0
  139. package/dist/hooks/chunk-CELGUP5F.js +49 -0
  140. package/dist/hooks/chunk-CMHANU3F.js +3442 -0
  141. package/dist/hooks/chunk-CMN372LI.js +68 -0
  142. package/dist/hooks/chunk-CPGZLMMK.js +3299 -0
  143. package/dist/hooks/chunk-CTQKXDC7.js +268 -0
  144. package/dist/hooks/chunk-CYAT4RIT.js +68 -0
  145. package/dist/hooks/chunk-CYTWYCH2.js +5014 -0
  146. package/dist/hooks/chunk-CZSOLRBA.js +77 -0
  147. package/dist/hooks/chunk-D2PIDYJR.js +3438 -0
  148. package/dist/hooks/chunk-DE57HI6T.js +137 -0
  149. package/dist/hooks/chunk-DGXDGAPG.js +5306 -0
  150. package/dist/hooks/chunk-DNYRSYQG.js +5014 -0
  151. package/dist/hooks/chunk-DTAXH2A2.js +240 -0
  152. package/dist/hooks/chunk-E2IZUWI5.js +375 -0
  153. package/dist/hooks/chunk-E4L2K2BL.js +397 -0
  154. package/dist/hooks/chunk-E55NKX5F.js +68 -0
  155. package/dist/hooks/chunk-ECXVCCVD.js +3079 -0
  156. package/dist/hooks/chunk-EPHO443D.js +68 -0
  157. package/dist/hooks/chunk-EUFK2BI2.js +375 -0
  158. package/dist/hooks/chunk-EYCD5ZAV.js +137 -0
  159. package/dist/hooks/chunk-F2SDYJU4.js +240 -0
  160. package/dist/hooks/chunk-F4B5D5TF.js +68 -0
  161. package/dist/hooks/chunk-FGEO3NDX.js +432 -0
  162. package/dist/hooks/chunk-FJYI52RE.js +137 -0
  163. package/dist/hooks/chunk-FXAKJKTB.js +18 -0
  164. package/dist/hooks/chunk-FYTZHIY4.js +3085 -0
  165. package/dist/hooks/chunk-G7JL2A5K.js +375 -0
  166. package/dist/hooks/chunk-GA3ITDBW.js +42 -0
  167. package/dist/hooks/chunk-GDR4H4SV.js +469 -0
  168. package/dist/hooks/chunk-GFKDXPSM.js +2855 -0
  169. package/dist/hooks/chunk-GIMRTKFU.js +566 -0
  170. package/dist/hooks/chunk-GOPHRLGO.js +240 -0
  171. package/dist/hooks/chunk-GX4HO7SJ.js +230 -0
  172. package/dist/hooks/chunk-GXKKK23T.js +240 -0
  173. package/dist/hooks/chunk-GZ6FUVIK.js +566 -0
  174. package/dist/hooks/chunk-H5HPY5M5.js +2869 -0
  175. package/dist/hooks/chunk-HCF3OGEE.js +1829 -0
  176. package/dist/hooks/chunk-HDEXAOUM.js +469 -0
  177. package/dist/hooks/chunk-HM2TY3TN.js +469 -0
  178. package/dist/hooks/chunk-HOA7NXA2.js +55 -0
  179. package/dist/hooks/chunk-HOFEWH6H.js +240 -0
  180. package/dist/hooks/chunk-HUUI6S5J.js +2669 -0
  181. package/dist/hooks/chunk-I4D3NVUD.js +469 -0
  182. package/dist/hooks/chunk-I4Q6WAJE.js +68 -0
  183. package/dist/hooks/chunk-IB6N4CR2.js +432 -0
  184. package/dist/hooks/chunk-IFLDYJMD.js +469 -0
  185. package/dist/hooks/chunk-IGU466YD.js +77 -0
  186. package/dist/hooks/chunk-IJCQUHKY.js +375 -0
  187. package/dist/hooks/chunk-IKUMBDJB.js +230 -0
  188. package/dist/hooks/chunk-IM3BDIBJ.js +5005 -0
  189. package/dist/hooks/chunk-IMYMAODK.js +3431 -0
  190. package/dist/hooks/chunk-IN2ZVGXA.js +5005 -0
  191. package/dist/hooks/chunk-ITVJ2MKQ.js +18 -0
  192. package/dist/hooks/chunk-J5RIJYTM.js +2669 -0
  193. package/dist/hooks/chunk-JFLMH4K5.js +3460 -0
  194. package/dist/hooks/chunk-JR25IFML.js +77 -0
  195. package/dist/hooks/chunk-JT5AUXFI.js +432 -0
  196. package/dist/hooks/chunk-JY5YVN6N.js +3234 -0
  197. package/dist/hooks/chunk-K5Q4ETVI.js +391 -0
  198. package/dist/hooks/chunk-K67V2F24.js +137 -0
  199. package/dist/hooks/chunk-KABG6AEW.js +3460 -0
  200. package/dist/hooks/chunk-KATZESEC.js +3273 -0
  201. package/dist/hooks/chunk-KFH4H7W7.js +469 -0
  202. package/dist/hooks/chunk-KMUEI6RX.js +910 -0
  203. package/dist/hooks/chunk-KMV4OY77.js +3438 -0
  204. package/dist/hooks/chunk-KQAZNWEY.js +137 -0
  205. package/dist/hooks/chunk-KZZR6JER.js +5015 -0
  206. package/dist/hooks/chunk-LAR6DREP.js +77 -0
  207. package/dist/hooks/chunk-LNCJWEZD.js +5015 -0
  208. package/dist/hooks/chunk-LRYD2GLM.js +6 -0
  209. package/dist/hooks/chunk-LXBKYHDV.js +77 -0
  210. package/dist/hooks/chunk-LYLKIUNE.js +5024 -0
  211. package/dist/hooks/chunk-LZKCFOVC.js +432 -0
  212. package/dist/hooks/chunk-M4FCIYRI.js +77 -0
  213. package/dist/hooks/chunk-M5M7327Q.js +3425 -0
  214. package/dist/hooks/chunk-MF72MHSX.js +3455 -0
  215. package/dist/hooks/chunk-MK56LKDO.js +397 -0
  216. package/dist/hooks/chunk-N3MJADY7.js +240 -0
  217. package/dist/hooks/chunk-NFQSUDBN.js +458 -0
  218. package/dist/hooks/chunk-NHREKY45.js +137 -0
  219. package/dist/hooks/chunk-NP5TTAAW.js +375 -0
  220. package/dist/hooks/chunk-NQTLTKTJ.js +2993 -0
  221. package/dist/hooks/chunk-NVRCZPBZ.js +391 -0
  222. package/dist/hooks/chunk-O46HMMLJ.js +469 -0
  223. package/dist/hooks/chunk-OFJGH2L4.js +240 -0
  224. package/dist/hooks/chunk-OLFMCZH5.js +240 -0
  225. package/dist/hooks/chunk-OMCZS46I.js +49 -0
  226. package/dist/hooks/chunk-OQZEZW5G.js +469 -0
  227. package/dist/hooks/chunk-P2MDAT2Y.js +1897 -0
  228. package/dist/hooks/chunk-P3M2JJIF.js +68 -0
  229. package/dist/hooks/chunk-PDVHQITQ.js +3453 -0
  230. package/dist/hooks/chunk-PNT2AMDH.js +391 -0
  231. package/dist/hooks/chunk-PR2LVSY6.js +3445 -0
  232. package/dist/hooks/chunk-PRR5R4JK.js +137 -0
  233. package/dist/hooks/chunk-PXT44QVN.js +566 -0
  234. package/dist/hooks/chunk-PZLWJLAP.js +469 -0
  235. package/dist/hooks/chunk-Q2FEAZJ2.js +77 -0
  236. package/dist/hooks/chunk-Q32WETDO.js +3265 -0
  237. package/dist/hooks/chunk-Q45DUBLE.js +3600 -0
  238. package/dist/hooks/chunk-Q7NZSWQ5.js +240 -0
  239. package/dist/hooks/chunk-QH2JNAMK.js +3085 -0
  240. package/dist/hooks/chunk-QNNWYQ2R.js +375 -0
  241. package/dist/hooks/chunk-QPU5H2OS.js +68 -0
  242. package/dist/hooks/chunk-QRAHZ5TO.js +1829 -0
  243. package/dist/hooks/chunk-QUZ5HPIE.js +469 -0
  244. package/dist/hooks/chunk-QVCRG34O.js +2893 -0
  245. package/dist/hooks/chunk-R3MY4E3S.js +1675 -0
  246. package/dist/hooks/chunk-R6TXJJXP.js +77 -0
  247. package/dist/hooks/chunk-REJU6VT7.js +1829 -0
  248. package/dist/hooks/chunk-REQAQLRC.js +2993 -0
  249. package/dist/hooks/chunk-RFCXPAHH.js +391 -0
  250. package/dist/hooks/chunk-RHI6Y22X.js +137 -0
  251. package/dist/hooks/chunk-RKZVOBBS.js +469 -0
  252. package/dist/hooks/chunk-RL57TT2Y.js +566 -0
  253. package/dist/hooks/chunk-RORDOD4S.js +3321 -0
  254. package/dist/hooks/chunk-RZKYW5P2.js +77 -0
  255. package/dist/hooks/chunk-SJPJ6VSI.js +391 -0
  256. package/dist/hooks/chunk-SKSIJQQQ.js +432 -0
  257. package/dist/hooks/chunk-SSQDZKXG.js +268 -0
  258. package/dist/hooks/chunk-SSX23SJ2.js +89 -0
  259. package/dist/hooks/chunk-SYHFKE4C.js +77 -0
  260. package/dist/hooks/chunk-TCGNI2ZY.js +42 -0
  261. package/dist/hooks/chunk-TG3WXJF5.js +137 -0
  262. package/dist/hooks/chunk-TH7IJAY5.js +77 -0
  263. package/dist/hooks/chunk-TLZ27PCY.js +240 -0
  264. package/dist/hooks/chunk-U652FXTN.js +566 -0
  265. package/dist/hooks/chunk-UEK47YUF.js +268 -0
  266. package/dist/hooks/chunk-UIO45H3O.js +432 -0
  267. package/dist/hooks/chunk-UNLZEEVH.js +5005 -0
  268. package/dist/hooks/chunk-UNRVF3SZ.js +432 -0
  269. package/dist/hooks/chunk-USLFAFOI.js +3453 -0
  270. package/dist/hooks/chunk-VAEELMLL.js +442 -0
  271. package/dist/hooks/chunk-VALSWLDQ.js +3453 -0
  272. package/dist/hooks/chunk-VC5JEPNY.js +3398 -0
  273. package/dist/hooks/chunk-VEZVK6C7.js +230 -0
  274. package/dist/hooks/chunk-VK5JKFAR.js +49 -0
  275. package/dist/hooks/chunk-VNF2KP7Z.js +469 -0
  276. package/dist/hooks/chunk-VWWCUMW6.js +2669 -0
  277. package/dist/hooks/chunk-W4JARUQV.js +137 -0
  278. package/dist/hooks/chunk-WCYPBPJC.js +5014 -0
  279. package/dist/hooks/chunk-WEOBMNJG.js +2993 -0
  280. package/dist/hooks/chunk-WKJU3J5Y.js +5390 -0
  281. package/dist/hooks/chunk-WMN4TSVF.js +3299 -0
  282. package/dist/hooks/chunk-WNON54PT.js +3469 -0
  283. package/dist/hooks/chunk-WOVKBPPX.js +137 -0
  284. package/dist/hooks/chunk-WRVFORYJ.js +432 -0
  285. package/dist/hooks/chunk-WUBVYGQZ.js +240 -0
  286. package/dist/hooks/chunk-WWULTUOM.js +68 -0
  287. package/dist/hooks/chunk-WXHKKB45.js +4962 -0
  288. package/dist/hooks/chunk-XAI3YTHJ.js +469 -0
  289. package/dist/hooks/chunk-XFZH6JZJ.js +77 -0
  290. package/dist/hooks/chunk-XGPWX6IA.js +137 -0
  291. package/dist/hooks/chunk-XIXXIVGY.js +566 -0
  292. package/dist/hooks/chunk-XKDOYJGA.js +922 -0
  293. package/dist/hooks/chunk-YALTVBHM.js +432 -0
  294. package/dist/hooks/chunk-YEBEPBFK.js +5014 -0
  295. package/dist/hooks/chunk-YI2BQ3DK.js +3441 -0
  296. package/dist/hooks/chunk-YVNBCFGG.js +1829 -0
  297. package/dist/hooks/chunk-YXBN3RGG.js +432 -0
  298. package/dist/hooks/chunk-Z2OOJSW3.js +3163 -0
  299. package/dist/hooks/chunk-ZA3HVBOY.js +2644 -0
  300. package/dist/hooks/chunk-ZKID46U3.js +137 -0
  301. package/dist/hooks/chunk-ZPMU2JV6.js +49 -0
  302. package/dist/hooks/chunk-ZRKY4W7O.js +432 -0
  303. package/dist/hooks/chunk-ZTMRB7LJ.js +268 -0
  304. package/dist/hooks/chunk-ZVPPBQ3L.js +3413 -0
  305. package/dist/hooks/codex-hook-adapter.js +164 -0
  306. package/dist/hooks/duplicate-read-guard.js +29 -0
  307. package/dist/hooks/format-edited.js +37 -0
  308. package/dist/hooks/investigation-guard.js +31 -0
  309. package/dist/hooks/pretool-guard.js +21 -0
  310. package/dist/hooks/session-lang.js +34 -0
  311. package/dist/hooks/stop-guard.js +1597 -0
  312. package/dist/josh.js +1795 -0
  313. package/dist/managed-marker/index.d.ts +10 -0
  314. package/dist/managed-marker/index.js +32 -0
  315. package/dist/self-sync-guard/index.d.ts +10 -0
  316. package/dist/self-sync-guard/index.js +49 -0
  317. package/dist/version/index.d.ts +93 -0
  318. package/dist/version/index.js +1024 -0
  319. package/env/index.d.ts +7 -0
  320. package/env/index.js +62 -0
  321. package/eslint/base.js +233 -0
  322. package/eslint/checkout-rooted-parser.js +34 -0
  323. package/eslint/config-fingerprint.js +103 -0
  324. package/eslint/rules/code-quality.js +292 -0
  325. package/eslint/rules/english-only-prose.js +135 -0
  326. package/eslint/rules/formatting.js +44 -0
  327. package/eslint/rules/import.js +83 -0
  328. package/eslint/rules/namespace-object-export.js +107 -0
  329. package/eslint/rules/naming-convention.js +109 -0
  330. package/eslint/rules/promise.js +17 -0
  331. package/eslint/rules/sonarjs.js +45 -0
  332. package/eslint/rules/test-filename.js +91 -0
  333. package/eslint/rules/typescript.js +186 -0
  334. package/eslint/rules/unicorn.js +191 -0
  335. package/eslint/vanilla.js +1 -0
  336. package/evals/scenarios/consult-not-execute.json +20 -0
  337. package/evals/scenarios/no-implicit-workflow.json +26 -0
  338. package/evals/scenarios/overrides-both-locations.json +29 -0
  339. package/evals/scenarios/upstream-interrupt.json +23 -0
  340. package/evals/scenarios/workflow-skill-loaded.json +16 -0
  341. package/lefthook/base.yml +131 -0
  342. package/lefthook/vanilla.yml +7 -0
  343. package/package.json +169 -0
  344. package/playwright.config.ts +160 -0
  345. package/pnpm-workspace.yaml +41 -0
  346. package/ports/index.d.ts +17 -0
  347. package/ports/index.js +256 -0
  348. package/prettier/index.d.ts +3 -0
  349. package/prettier/index.js +31 -0
  350. package/prompts/agent-lint-protocol.json +79 -0
  351. package/prompts/agent-rules.md +63 -0
  352. package/prompts/coding-standards.md +382 -0
  353. package/prompts/collaboration-workflow/consultation-vs-execution.md +8 -0
  354. package/prompts/collaboration-workflow/cross-repo-epic.md +54 -0
  355. package/prompts/collaboration-workflow/distributed-docs.md +7 -0
  356. package/prompts/collaboration-workflow/durable-rules.md +24 -0
  357. package/prompts/collaboration-workflow/epic-audit.md +56 -0
  358. package/prompts/collaboration-workflow/epic-bundle.md +109 -0
  359. package/prompts/collaboration-workflow/file-edits.md +124 -0
  360. package/prompts/collaboration-workflow/gh-rest.md +57 -0
  361. package/prompts/collaboration-workflow/issue-citation.md +38 -0
  362. package/prompts/collaboration-workflow/issue-template.md +190 -0
  363. package/prompts/collaboration-workflow/latest-first.md +14 -0
  364. package/prompts/collaboration-workflow/no-clones.md +11 -0
  365. package/prompts/collaboration-workflow/operating-rules.md +123 -0
  366. package/prompts/collaboration-workflow/output-bounds.md +107 -0
  367. package/prompts/collaboration-workflow/overview.md +35 -0
  368. package/prompts/collaboration-workflow/plan-comment.md +85 -0
  369. package/prompts/collaboration-workflow/proposal-request.md +23 -0
  370. package/prompts/collaboration-workflow/report-format.md +206 -0
  371. package/prompts/collaboration-workflow/residency.md +94 -0
  372. package/prompts/collaboration-workflow/rule-delivery.md +146 -0
  373. package/prompts/collaboration-workflow/shell-body.md +82 -0
  374. package/prompts/collaboration-workflow/simplicity-first.md +9 -0
  375. package/prompts/collaboration-workflow/single-source-rules.md +13 -0
  376. package/prompts/collaboration-workflow/turn-batching.md +137 -0
  377. package/prompts/collaboration-workflow/upstream-interrupt.md +51 -0
  378. package/prompts/collaboration-workflow/wip-cap.md +118 -0
  379. package/prompts/collaboration-workflow.md +52 -0
  380. package/prompts/refactoring.md +103 -0
  381. package/prompts/review-rubric.md +338 -0
  382. package/prompts/review.md +217 -0
  383. package/prompts/sonar-hotspot-handling.md +77 -0
  384. package/prompts/testing-guide.md +277 -0
  385. package/scripts/adopt/adopt-logic.ts +107 -0
  386. package/scripts/adopt/adopt-toolkits.ts +181 -0
  387. package/scripts/adopt/adopt.ts +171 -0
  388. package/scripts/agent/agent-argv.ts +140 -0
  389. package/scripts/agent/agent-diagnostics.ts +120 -0
  390. package/scripts/agent/agent-event.ts +173 -0
  391. package/scripts/agent/agent-exit-record.ts +32 -0
  392. package/scripts/agent/agent-launch-environment.ts +71 -0
  393. package/scripts/agent/agent-role-profile.ts +329 -0
  394. package/scripts/agent/api-outage.ts +51 -0
  395. package/scripts/agent/claude-agent-argv.ts +151 -0
  396. package/scripts/agent/claude-result-event.ts +98 -0
  397. package/scripts/agent/codex-agent-argv.ts +94 -0
  398. package/scripts/agent/codex-home-source.ts +11 -0
  399. package/scripts/agent/interactive-ask.ts +91 -0
  400. package/scripts/auto-ok/auto-ok-cli.ts +516 -0
  401. package/scripts/backlog/backlog-arrival.ts +147 -0
  402. package/scripts/backlog/backlog-budget-cli.ts +220 -0
  403. package/scripts/backlog/backlog-budget.ts +284 -0
  404. package/scripts/backlog/backlog-defect-priority.ts +77 -0
  405. package/scripts/backlog/backlog-drive-cli.ts +377 -0
  406. package/scripts/backlog/backlog-drive-finish.ts +23 -0
  407. package/scripts/backlog/backlog-drive-named-offer.ts +81 -0
  408. package/scripts/backlog/backlog-drive-named.ts +101 -0
  409. package/scripts/backlog/backlog-drive-offer-argv.ts +29 -0
  410. package/scripts/backlog/backlog-drive-owner.ts +22 -0
  411. package/scripts/backlog/backlog-drive-restore.ts +67 -0
  412. package/scripts/backlog/backlog-drive.ts +322 -0
  413. package/scripts/backlog/backlog-named.ts +164 -0
  414. package/scripts/backlog/backlog-next.ts +376 -0
  415. package/scripts/backlog/backlog-offer-cli.ts +279 -0
  416. package/scripts/backlog/backlog-offer.ts +93 -0
  417. package/scripts/backlog/backlog-plan-cli.ts +235 -0
  418. package/scripts/backlog/backlog-plan.ts +231 -0
  419. package/scripts/backlog/backlog-pool.ts +322 -0
  420. package/scripts/backlog/backlog-ready.ts +146 -0
  421. package/scripts/backlog/backlog-scope.ts +144 -0
  422. package/scripts/backlog/backlog-stalled-cli.ts +30 -0
  423. package/scripts/backlog/backlog-stalled-detect.ts +143 -0
  424. package/scripts/backlog/backlog-stalled.ts +118 -0
  425. package/scripts/behavior/behavior-assertion.ts +87 -0
  426. package/scripts/behavior/behavior-cli.ts +88 -0
  427. package/scripts/behavior/behavior-rules.ts +128 -0
  428. package/scripts/build/build-bin.ts +36 -0
  429. package/scripts/build/build-claude-md.ts +42 -0
  430. package/scripts/build/build-config-merge.ts +26 -0
  431. package/scripts/build/build-hooks.ts +79 -0
  432. package/scripts/build/build-library.ts +83 -0
  433. package/scripts/build/build-managed-marker.ts +26 -0
  434. package/scripts/build/build-self-sync-guard.ts +26 -0
  435. package/scripts/build/build-version.ts +25 -0
  436. package/scripts/build/local-bin.ts +97 -0
  437. package/scripts/build/shim-shell.ts +25 -0
  438. package/scripts/bytes/bytes-command.ts +181 -0
  439. package/scripts/cases/cases-cli.ts +48 -0
  440. package/scripts/cases/cases-logic.ts +100 -0
  441. package/scripts/claude/skill-meta.ts +37 -0
  442. package/scripts/claude/workflow-destination.ts +13 -0
  443. package/scripts/clone/clone-aggregate.ts +76 -0
  444. package/scripts/clone/clone-fingerprint.ts +96 -0
  445. package/scripts/clone/clone-scan-cli.ts +39 -0
  446. package/scripts/clone/clone-scan.ts +158 -0
  447. package/scripts/config-merge/index.ts +19 -0
  448. package/scripts/config-merge/json-format.ts +128 -0
  449. package/scripts/config-merge/list-patch.ts +61 -0
  450. package/scripts/config-merge/parse-jsonc.ts +14 -0
  451. package/scripts/config-merge/patch-json-key.ts +439 -0
  452. package/scripts/config-merge/patch-json-list.ts +38 -0
  453. package/scripts/config-merge/patch-yaml-list.ts +107 -0
  454. package/scripts/cost-runtime/codex-usage.ts +119 -0
  455. package/scripts/cost-runtime/context-cut-payback.ts +77 -0
  456. package/scripts/cost-runtime/context-cut-threshold.ts +21 -0
  457. package/scripts/cost-runtime/cost-attribute.ts +168 -0
  458. package/scripts/cost-runtime/cost-blocks.ts +149 -0
  459. package/scripts/cost-runtime/cost-cli.ts +318 -0
  460. package/scripts/cost-runtime/cost-corpus.ts +278 -0
  461. package/scripts/cost-runtime/cost-format.ts +32 -0
  462. package/scripts/cost-runtime/cost-pricing.ts +176 -0
  463. package/scripts/cost-runtime/cost-tokens.ts +84 -0
  464. package/scripts/cost-runtime/cost-transcript.ts +531 -0
  465. package/scripts/cost-runtime/cost-usage.ts +287 -0
  466. package/scripts/cost-runtime/cost-verdict.ts +89 -0
  467. package/scripts/cost-runtime/own-session.ts +58 -0
  468. package/scripts/cost-runtime/transcript-cwd.ts +14 -0
  469. package/scripts/delegation/delegation-cli.ts +91 -0
  470. package/scripts/delegation/delegation-policy.ts +178 -0
  471. package/scripts/delegation/duplicate-read-guard.ts +244 -0
  472. package/scripts/delegation/fanout-cli.ts +61 -0
  473. package/scripts/delegation/fanout.ts +95 -0
  474. package/scripts/delegation/investigation-guard.ts +131 -0
  475. package/scripts/delegation/investigation-reads.ts +637 -0
  476. package/scripts/discovery/repo-discovery.ts +166 -0
  477. package/scripts/discovery/repo-map-logic.ts +102 -0
  478. package/scripts/discovery/repo-origin.ts +153 -0
  479. package/scripts/discovery/repo-party-cli.ts +69 -0
  480. package/scripts/discovery/repo-party.ts +46 -0
  481. package/scripts/doctor/doctor-consumer.ts +181 -0
  482. package/scripts/doctor/doctor-io.ts +210 -0
  483. package/scripts/doctor/doctor-logic.ts +122 -0
  484. package/scripts/doctor/doctor-ports.ts +117 -0
  485. package/scripts/doctor/doctor.ts +232 -0
  486. package/scripts/document/backlogrun-parent-read-set.ts +48 -0
  487. package/scripts/document/bash-output-cap.ts +45 -0
  488. package/scripts/document/document-byte-budget.ts +183 -0
  489. package/scripts/document/document-byte-check.ts +131 -0
  490. package/scripts/document/document-reachability.ts +131 -0
  491. package/scripts/document/document-read-cli.ts +82 -0
  492. package/scripts/document/document-scan.ts +108 -0
  493. package/scripts/document/document-section-cli.ts +101 -0
  494. package/scripts/document/document-section.ts +156 -0
  495. package/scripts/document/edit-files-cli.ts +280 -0
  496. package/scripts/document/entry-read-budget.ts +154 -0
  497. package/scripts/document/entry-read-set.ts +471 -0
  498. package/scripts/document/generate-catalog.ts +69 -0
  499. package/scripts/document/lane-child-read-set.ts +88 -0
  500. package/scripts/document/read-files-cli.ts +135 -0
  501. package/scripts/document/read-set-cli.ts +295 -0
  502. package/scripts/document/read-set-point-of-use.ts +89 -0
  503. package/scripts/document/read-set-pricing.ts +52 -0
  504. package/scripts/document/read-set-trim.ts +78 -0
  505. package/scripts/document/retired-phrases.ts +143 -0
  506. package/scripts/document/review-agent-type.ts +46 -0
  507. package/scripts/document/single-source.ts +73 -0
  508. package/scripts/epic/epic-audit-checks.ts +452 -0
  509. package/scripts/epic/epic-audit-cli.ts +374 -0
  510. package/scripts/epic/epic-audit-orphans.ts +142 -0
  511. package/scripts/epic/epic-audit-rationale.ts +191 -0
  512. package/scripts/epic/epic-audit-report.ts +101 -0
  513. package/scripts/epic/epic-audit.ts +240 -0
  514. package/scripts/epic/epic-bundle-cli.ts +472 -0
  515. package/scripts/epic/epic-bundle-evidence.ts +147 -0
  516. package/scripts/epic/epic-bundle-gaps.ts +86 -0
  517. package/scripts/epic/epic-bundle-referenced.ts +195 -0
  518. package/scripts/epic/epic-bundle.ts +309 -0
  519. package/scripts/epic/epic-busy.ts +204 -0
  520. package/scripts/epic/epic-candidate-confirm.ts +279 -0
  521. package/scripts/epic/epic-classify.ts +294 -0
  522. package/scripts/epic/epic-cross-repo.ts +366 -0
  523. package/scripts/epic/epic-fetch.ts +370 -0
  524. package/scripts/epic/epic-graph.ts +279 -0
  525. package/scripts/epic/epic-index.ts +209 -0
  526. package/scripts/epic/epic-issue.ts +172 -0
  527. package/scripts/epic/epic-lane-offer.ts +207 -0
  528. package/scripts/epic/epic-nested.ts +37 -0
  529. package/scripts/epic/epic-next-read.ts +141 -0
  530. package/scripts/epic/epic-next-views.ts +144 -0
  531. package/scripts/epic/epic-next.ts +477 -0
  532. package/scripts/epic/epic-outside-blocker.ts +113 -0
  533. package/scripts/epic/epic-relation-recheck.ts +108 -0
  534. package/scripts/epic/epic-report.ts +200 -0
  535. package/scripts/gate/core-budget.ts +292 -0
  536. package/scripts/gate/gate-log.ts +95 -0
  537. package/scripts/gate/gate-plan.ts +356 -0
  538. package/scripts/gate/gate-report.ts +207 -0
  539. package/scripts/gate/gate-skip.ts +123 -0
  540. package/scripts/gate/gate-tree.ts +49 -0
  541. package/scripts/gate/hook-gate-reuse.ts +130 -0
  542. package/scripts/gate/pre-commit-type-check.ts +187 -0
  543. package/scripts/gate/scoped-green.ts +260 -0
  544. package/scripts/gate/type-check-step.ts +90 -0
  545. package/scripts/gate/verification-gate.ts +531 -0
  546. package/scripts/gh/fix-gh-packages-logic.ts +232 -0
  547. package/scripts/gh/fix-gh-packages.ts +129 -0
  548. package/scripts/gh/gh-cli-token.ts +18 -0
  549. package/scripts/gh/gh-spawn.ts +44 -0
  550. package/scripts/git/animation-helpers.ts +81 -0
  551. package/scripts/git/change-base.ts +26 -0
  552. package/scripts/git/changed-file-scope.ts +209 -0
  553. package/scripts/git/changed-paths.ts +30 -0
  554. package/scripts/git/constants.ts +41 -0
  555. package/scripts/git/git-ai-review-scan.ts +154 -0
  556. package/scripts/git/git-animation.ts +41 -0
  557. package/scripts/git/git-branch.ts +127 -0
  558. package/scripts/git/git-command.ts +587 -0
  559. package/scripts/git/git-commit.ts +27 -0
  560. package/scripts/git/git-common-directory.ts +38 -0
  561. package/scripts/git/git-epic-add-body.ts +365 -0
  562. package/scripts/git/git-epic-add-plan.ts +421 -0
  563. package/scripts/git/git-epic-add.ts +249 -0
  564. package/scripts/git/git-epic-body.ts +150 -0
  565. package/scripts/git/git-epic-chains.ts +411 -0
  566. package/scripts/git/git-epic-close-comment.ts +199 -0
  567. package/scripts/git/git-epic-close.ts +393 -0
  568. package/scripts/git/git-epic-decision.ts +171 -0
  569. package/scripts/git/git-epic-parse.ts +351 -0
  570. package/scripts/git/git-epic-promote.ts +102 -0
  571. package/scripts/git/git-epic-read.ts +73 -0
  572. package/scripts/git/git-epic-reconcile.ts +246 -0
  573. package/scripts/git/git-epic-reference.ts +98 -0
  574. package/scripts/git/git-epic-relations.ts +78 -0
  575. package/scripts/git/git-epic-remove-plan.ts +152 -0
  576. package/scripts/git/git-epic-remove.ts +101 -0
  577. package/scripts/git/git-epic-run.ts +223 -0
  578. package/scripts/git/git-epic-sections.ts +98 -0
  579. package/scripts/git/git-epic-shape.ts +81 -0
  580. package/scripts/git/git-epic-validate.ts +155 -0
  581. package/scripts/git/git-error.ts +78 -0
  582. package/scripts/git/git-execa-error.ts +35 -0
  583. package/scripts/git/git-fixture-workspace.ts +88 -0
  584. package/scripts/git/git-followup-cleanup.ts +88 -0
  585. package/scripts/git/git-followup-flush.ts +63 -0
  586. package/scripts/git/git-followup-label.ts +67 -0
  587. package/scripts/git/git-followup-pending.ts +95 -0
  588. package/scripts/git/git-followup-stages.ts +149 -0
  589. package/scripts/git/git-gh-api-path.ts +118 -0
  590. package/scripts/git/git-gh-check.ts +21 -0
  591. package/scripts/git/git-gh-command.ts +17 -0
  592. package/scripts/git/git-gh-exec.ts +344 -0
  593. package/scripts/git/git-gh-failure.ts +103 -0
  594. package/scripts/git/git-gh-helpers.ts +44 -0
  595. package/scripts/git/git-gh-issue-list.ts +257 -0
  596. package/scripts/git/git-gh-issue-read.ts +457 -0
  597. package/scripts/git/git-gh-issue-rest.ts +238 -0
  598. package/scripts/git/git-gh-issue-write.ts +285 -0
  599. package/scripts/git/git-gh-issue.ts +161 -0
  600. package/scripts/git/git-gh-pr-auto-merge.ts +85 -0
  601. package/scripts/git/git-gh-pr-read.ts +322 -0
  602. package/scripts/git/git-gh-pr-rest.ts +172 -0
  603. package/scripts/git/git-gh-pr-review.ts +103 -0
  604. package/scripts/git/git-gh-pr-rollup.ts +91 -0
  605. package/scripts/git/git-gh-pr-snapshot.ts +138 -0
  606. package/scripts/git/git-gh-pr.ts +219 -0
  607. package/scripts/git/git-gh-reachability.ts +56 -0
  608. package/scripts/git/git-gh-repo.ts +37 -0
  609. package/scripts/git/git-gh-rest-state.ts +14 -0
  610. package/scripts/git/git-issue.ts +168 -0
  611. package/scripts/git/git-location-environment.ts +62 -0
  612. package/scripts/git/git-ls-remote.ts +28 -0
  613. package/scripts/git/git-next-issues.ts +98 -0
  614. package/scripts/git/git-notify.ts +104 -0
  615. package/scripts/git/git-pr-ai-review.ts +180 -0
  616. package/scripts/git/git-pr-checks-eval.ts +265 -0
  617. package/scripts/git/git-pr-checks-parse.ts +153 -0
  618. package/scripts/git/git-pr-checks-watch.ts +184 -0
  619. package/scripts/git/git-pr-checks.ts +387 -0
  620. package/scripts/git/git-pr-coderabbit.ts +129 -0
  621. package/scripts/git/git-pr-confirmation.ts +64 -0
  622. package/scripts/git/git-pr-error.ts +25 -0
  623. package/scripts/git/git-pr-followup-wrapup.ts +225 -0
  624. package/scripts/git/git-pr-followup.ts +436 -0
  625. package/scripts/git/git-pr-managed-config.ts +69 -0
  626. package/scripts/git/git-pr-messages.ts +37 -0
  627. package/scripts/git/git-pr.ts +181 -0
  628. package/scripts/git/git-prompt-display.ts +22 -0
  629. package/scripts/git/git-prompt.ts +207 -0
  630. package/scripts/git/git-push-transport.ts +173 -0
  631. package/scripts/git/git-push.ts +27 -0
  632. package/scripts/git/git-remote-branch.ts +40 -0
  633. package/scripts/git/git-spawn.ts +47 -0
  634. package/scripts/git/git-staging.ts +128 -0
  635. package/scripts/git/git-stash.ts +124 -0
  636. package/scripts/git/git-status.ts +198 -0
  637. package/scripts/git/git-worktree.ts +110 -0
  638. package/scripts/git/github-issue-url.ts +105 -0
  639. package/scripts/git/gone-branch.ts +113 -0
  640. package/scripts/git/issue-labels.ts +279 -0
  641. package/scripts/git/listing-cutoff.ts +51 -0
  642. package/scripts/git/main-merge-guard.ts +134 -0
  643. package/scripts/git/main-merge.ts +120 -0
  644. package/scripts/git/main-sync.ts +121 -0
  645. package/scripts/git/parse-json-array.ts +102 -0
  646. package/scripts/git/schemas.ts +166 -0
  647. package/scripts/git/stash-orphans.ts +91 -0
  648. package/scripts/git/stash-pop-args.ts +59 -0
  649. package/scripts/git/stash-pop-cli.ts +105 -0
  650. package/scripts/git/telegram-notify.ts +404 -0
  651. package/scripts/hooks/batch-guard.ts +144 -0
  652. package/scripts/hooks/check-commit-message.ts +134 -0
  653. package/scripts/hooks/codex-hook-adapter.ts +155 -0
  654. package/scripts/hooks/edited-cspell.ts +128 -0
  655. package/scripts/hooks/format-edited-file-fixtures.ts +109 -0
  656. package/scripts/hooks/format-edited-file.ts +510 -0
  657. package/scripts/hooks/format-rewrite-notice.ts +99 -0
  658. package/scripts/hooks/pre-push-unit.ts +146 -0
  659. package/scripts/hooks/pretool-guard.ts +96 -0
  660. package/scripts/hooks/prevent-main-commit.ts +38 -0
  661. package/scripts/hooks/prompt-hooks.ts +38 -0
  662. package/scripts/hooks/reserved-run.ts +90 -0
  663. package/scripts/hooks/stop-guard.ts +135 -0
  664. package/scripts/init/claude-plugin-config.ts +51 -0
  665. package/scripts/init/distributed-paths.ts +100 -0
  666. package/scripts/init/hook-command-rewrite.ts +85 -0
  667. package/scripts/init/hook-launch.ts +31 -0
  668. package/scripts/init/init-actions.ts +147 -0
  669. package/scripts/init/init-ai-copy.ts +235 -0
  670. package/scripts/init/init-copy-content.ts +50 -0
  671. package/scripts/init/init-logic-deploy-vps.ts +43 -0
  672. package/scripts/init/init-logic-json-merge.ts +340 -0
  673. package/scripts/init/init-logic-migrate.ts +62 -0
  674. package/scripts/init/init-logic-package-key-order.ts +50 -0
  675. package/scripts/init/init-logic-secretlint.ts +36 -0
  676. package/scripts/init/init-logic-sonar.ts +197 -0
  677. package/scripts/init/init-logic-templates.ts +142 -0
  678. package/scripts/init/init-logic-workspace.ts +59 -0
  679. package/scripts/init/init-logic-yaml-merge.ts +57 -0
  680. package/scripts/init/init-logic.ts +474 -0
  681. package/scripts/init/init-paths.ts +11 -0
  682. package/scripts/init/init-sonar.ts +32 -0
  683. package/scripts/init/init.ts +219 -0
  684. package/scripts/init/kit-base-preset.ts +60 -0
  685. package/scripts/init/plugin-install-hint.ts +47 -0
  686. package/scripts/init/tsconfig-preset-migration.ts +67 -0
  687. package/scripts/issue/baseline-measure.ts +105 -0
  688. package/scripts/issue/behavior-change-lint.ts +122 -0
  689. package/scripts/issue/defect-rate-cli.ts +167 -0
  690. package/scripts/issue/defect-rate.ts +145 -0
  691. package/scripts/issue/issue-backlinks-cli.ts +97 -0
  692. package/scripts/issue/issue-backlinks.ts +164 -0
  693. package/scripts/issue/issue-cite-cli.ts +158 -0
  694. package/scripts/issue/issue-cite.ts +102 -0
  695. package/scripts/issue/issue-comment-cli.ts +95 -0
  696. package/scripts/issue/issue-fold-cli.ts +104 -0
  697. package/scripts/issue/issue-fold-existing-cli.ts +81 -0
  698. package/scripts/issue/issue-fold-existing.ts +73 -0
  699. package/scripts/issue/issue-fold.ts +42 -0
  700. package/scripts/issue/issue-lint-cli.ts +60 -0
  701. package/scripts/issue/issue-lint.ts +26 -0
  702. package/scripts/issue/issue-logic.ts +50 -0
  703. package/scripts/issue/issue-read-cli.ts +190 -0
  704. package/scripts/issue/issue-read.ts +145 -0
  705. package/scripts/issue/issue-scout-cli.ts +482 -0
  706. package/scripts/issue/issue-scout.ts +244 -0
  707. package/scripts/issue/issue-state-cli.ts +260 -0
  708. package/scripts/issue/issue-state.ts +109 -0
  709. package/scripts/issue/markdown-section.ts +39 -0
  710. package/scripts/issue/measure-rerun-cli.ts +98 -0
  711. package/scripts/issue/reproduction-measure.ts +59 -0
  712. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +1171 -0
  713. package/scripts/josh/agent-session-environment.ts +188 -0
  714. package/scripts/josh/cli-body.ts +96 -0
  715. package/scripts/josh/command-suggest.ts +57 -0
  716. package/scripts/josh/file-map-stamp.ts +264 -0
  717. package/scripts/josh/hook-decision.ts +479 -0
  718. package/scripts/josh/josh-command-map.ts +196 -0
  719. package/scripts/josh/josh-command-types.ts +226 -0
  720. package/scripts/josh/josh-commands-ai.ts +327 -0
  721. package/scripts/josh/josh-commands-backlog.ts +54 -0
  722. package/scripts/josh/josh-commands-clone.ts +18 -0
  723. package/scripts/josh/josh-commands-development.ts +206 -0
  724. package/scripts/josh/josh-commands-document.ts +45 -0
  725. package/scripts/josh/josh-commands-guard.ts +38 -0
  726. package/scripts/josh/josh-commands-hooks.ts +42 -0
  727. package/scripts/josh/josh-commands-issue.ts +69 -0
  728. package/scripts/josh/josh-commands-lane.ts +75 -0
  729. package/scripts/josh/josh-commands-lint.ts +37 -0
  730. package/scripts/josh/josh-commands-maintenance.ts +80 -0
  731. package/scripts/josh/josh-commands-project.ts +53 -0
  732. package/scripts/josh/josh-commands-split.ts +20 -0
  733. package/scripts/josh/josh-commands-versioning.ts +48 -0
  734. package/scripts/josh/josh-commands-workflow.ts +116 -0
  735. package/scripts/josh/josh-composite-arguments.ts +55 -0
  736. package/scripts/josh/josh-environment-file.ts +31 -0
  737. package/scripts/josh/josh-in-process.ts +80 -0
  738. package/scripts/josh/josh-logic.ts +308 -0
  739. package/scripts/josh/josh-run.ts +53 -0
  740. package/scripts/josh/josh-script-reader.ts +11 -0
  741. package/scripts/josh/josh-verdict.ts +111 -0
  742. package/scripts/josh/josh.ts +60 -0
  743. package/scripts/josh/kit-only.ts +33 -0
  744. package/scripts/josh/path-decision.ts +104 -0
  745. package/scripts/josh/platform-temporary.ts +66 -0
  746. package/scripts/josh/process-identity.ts +335 -0
  747. package/scripts/josh/session-language-cli.ts +51 -0
  748. package/scripts/josh/session-language.ts +30 -0
  749. package/scripts/josh/stamp-file.ts +194 -0
  750. package/scripts/lane/lane-await.ts +165 -0
  751. package/scripts/lane/lane-cache-run.ts +39 -0
  752. package/scripts/lane/lane-cache.ts +135 -0
  753. package/scripts/lane/lane-capacity.ts +69 -0
  754. package/scripts/lane/lane-child-invocation.ts +73 -0
  755. package/scripts/lane/lane-child-marker.ts +58 -0
  756. package/scripts/lane/lane-cli.ts +410 -0
  757. package/scripts/lane/lane-close.ts +197 -0
  758. package/scripts/lane/lane-dispatch-log.ts +13 -0
  759. package/scripts/lane/lane-dispatch.ts +458 -0
  760. package/scripts/lane/lane-environment.ts +253 -0
  761. package/scripts/lane/lane-guard-policy.ts +136 -0
  762. package/scripts/lane/lane-install.ts +94 -0
  763. package/scripts/lane/lane-launch-cli.ts +133 -0
  764. package/scripts/lane/lane-occupancy.ts +112 -0
  765. package/scripts/lane/lane-open.ts +275 -0
  766. package/scripts/lane/lane-output.ts +124 -0
  767. package/scripts/lane/lane-paths.ts +96 -0
  768. package/scripts/lane/lane-reap.ts +137 -0
  769. package/scripts/lane/lane-registry.ts +261 -0
  770. package/scripts/lane/lane-relaunch.ts +68 -0
  771. package/scripts/lane/lane-report.ts +95 -0
  772. package/scripts/lane/lane-resume.ts +61 -0
  773. package/scripts/lane/lane-seed.ts +44 -0
  774. package/scripts/lane/lane-start-point.ts +175 -0
  775. package/scripts/lane/openai-lane-supervisor-cli.ts +32 -0
  776. package/scripts/lane/openai-lane-supervisor-decision.ts +63 -0
  777. package/scripts/lane/openai-lane-supervisor.ts +337 -0
  778. package/scripts/lib/bounded-pool.ts +109 -0
  779. package/scripts/lib/buffered-process.ts +82 -0
  780. package/scripts/lib/caddy-logs.sh +45 -0
  781. package/scripts/lib/cli-flags.ts +19 -0
  782. package/scripts/lib/json-value.ts +24 -0
  783. package/scripts/lib/poll.ts +57 -0
  784. package/scripts/lib/read-file.ts +16 -0
  785. package/scripts/lib/schemas.ts +67 -0
  786. package/scripts/lib/spawn-exit.ts +45 -0
  787. package/scripts/lib/status-icons.ts +24 -0
  788. package/scripts/lines/effective-limit.ts +156 -0
  789. package/scripts/lines/line-budget.ts +404 -0
  790. package/scripts/lines/line-targets.ts +80 -0
  791. package/scripts/lines/lines-command.ts +174 -0
  792. package/scripts/lint/cspell-cached.ts +41 -0
  793. package/scripts/lint/lint-parallel.ts +72 -0
  794. package/scripts/lint/lint-related-scope.ts +128 -0
  795. package/scripts/lint/lint-related.ts +104 -0
  796. package/scripts/managed-marker/index.ts +5 -0
  797. package/scripts/managed-marker/managed-marker-logic.ts +67 -0
  798. package/scripts/observations/observation-ledger-home.ts +32 -0
  799. package/scripts/observations/observation-ledger-line.ts +93 -0
  800. package/scripts/observations/observation-ledger.ts +35 -0
  801. package/scripts/observations/observations-flush-cli.ts +42 -0
  802. package/scripts/observations/observations-flush-landing.ts +97 -0
  803. package/scripts/observations/observations-flush.ts +420 -0
  804. package/scripts/overrides/lockfile-overrides.ts +105 -0
  805. package/scripts/overrides/overrides-check.ts +84 -0
  806. package/scripts/overrides/overrides-files.ts +19 -0
  807. package/scripts/overrides/overrides-logic.ts +211 -0
  808. package/scripts/overrides/schemas.ts +49 -0
  809. package/scripts/package/package-scout-cli.ts +195 -0
  810. package/scripts/package/package-scout-format.ts +151 -0
  811. package/scripts/package/package-scout.ts +121 -0
  812. package/scripts/ports/port-command.ts +87 -0
  813. package/scripts/propagate/propagate-git-failure.ts +191 -0
  814. package/scripts/propagate/propagate-git.ts +224 -0
  815. package/scripts/propagate/propagate-publish.ts +181 -0
  816. package/scripts/propagate/propagate-run.ts +201 -0
  817. package/scripts/propagate/propagate-steps.ts +421 -0
  818. package/scripts/propagate/propagate-targets.ts +160 -0
  819. package/scripts/propagate/propagate.ts +216 -0
  820. package/scripts/refactor/import-graph.ts +187 -0
  821. package/scripts/refactor/refactor-lint.ts +250 -0
  822. package/scripts/refactor/refactor-scan-cli.ts +10 -0
  823. package/scripts/refactor/refactor-scan.ts +124 -0
  824. package/scripts/refactor/refactor-targets.ts +103 -0
  825. package/scripts/release/release-cli.ts +88 -0
  826. package/scripts/release/release-history.ts +132 -0
  827. package/scripts/release/release-plan.ts +130 -0
  828. package/scripts/release/release-publish.ts +152 -0
  829. package/scripts/release/release-scope-cli.ts +103 -0
  830. package/scripts/release/release-tag.ts +93 -0
  831. package/scripts/release/release-worktree.ts +71 -0
  832. package/scripts/repo/auto-merge-setting-logic.ts +100 -0
  833. package/scripts/repo/auto-merge-setting.ts +37 -0
  834. package/scripts/repo/repo-setting.ts +112 -0
  835. package/scripts/report/report-lint-cli.ts +49 -0
  836. package/scripts/report/report-lint.ts +250 -0
  837. package/scripts/retrospective/retrospective-cli.ts +97 -0
  838. package/scripts/retrospective/retrospective.ts +127 -0
  839. package/scripts/review/disposition-cli.ts +44 -0
  840. package/scripts/review/disposition-logic.ts +45 -0
  841. package/scripts/review/live-evidence.ts +62 -0
  842. package/scripts/review/review-attest-cli.ts +115 -0
  843. package/scripts/review/review-attest.ts +319 -0
  844. package/scripts/review/review-brief-cli.ts +290 -0
  845. package/scripts/review/review-brief.ts +440 -0
  846. package/scripts/review/review-checkout.ts +56 -0
  847. package/scripts/review/review-finding-ledger.ts +167 -0
  848. package/scripts/review/review-findings-cli.ts +57 -0
  849. package/scripts/review/review-level.ts +86 -0
  850. package/scripts/review/review-record-cli.ts +196 -0
  851. package/scripts/review/review-record.ts +74 -0
  852. package/scripts/review/review-round2-cli.ts +84 -0
  853. package/scripts/review/review-round2.ts +139 -0
  854. package/scripts/review/review-stamps.ts +113 -0
  855. package/scripts/review/review-tree.ts +58 -0
  856. package/scripts/rules/bash-triggers.ts +44 -0
  857. package/scripts/rules/decision-oracle.ts +342 -0
  858. package/scripts/rules/delivered-rules-harness.ts +72 -0
  859. package/scripts/rules/delivered-rules.ts +793 -0
  860. package/scripts/rules/early-heartbeat.ts +241 -0
  861. package/scripts/rules/file-body.ts +150 -0
  862. package/scripts/rules/filing-cap.ts +133 -0
  863. package/scripts/rules/filing-offer.ts +81 -0
  864. package/scripts/rules/firing-point.ts +63 -0
  865. package/scripts/rules/gh-api.ts +65 -0
  866. package/scripts/rules/git-argv.ts +129 -0
  867. package/scripts/rules/git-force.ts +104 -0
  868. package/scripts/rules/implementation-cut-verdict.ts +84 -0
  869. package/scripts/rules/implementation-cut.ts +202 -0
  870. package/scripts/rules/issue-citation.ts +242 -0
  871. package/scripts/rules/issue-fold.ts +73 -0
  872. package/scripts/rules/issue-scout.ts +64 -0
  873. package/scripts/rules/josh-git-bare.ts +80 -0
  874. package/scripts/rules/lane-carry-conflict.ts +96 -0
  875. package/scripts/rules/lane-interactive-ask.ts +71 -0
  876. package/scripts/rules/lane-park.ts +122 -0
  877. package/scripts/rules/lane-switch-main.ts +139 -0
  878. package/scripts/rules/oracle-consulted.ts +81 -0
  879. package/scripts/rules/oracle-firing.ts +151 -0
  880. package/scripts/rules/oracle-list-cli.ts +81 -0
  881. package/scripts/rules/piped-verification.ts +126 -0
  882. package/scripts/rules/poll-loop.ts +125 -0
  883. package/scripts/rules/pre-gate-cut.ts +207 -0
  884. package/scripts/rules/prior-comment-read.ts +106 -0
  885. package/scripts/rules/raw-field-body.ts +56 -0
  886. package/scripts/rules/reply-language.ts +116 -0
  887. package/scripts/rules/rule-body-guard.ts +206 -0
  888. package/scripts/rules/rule-guard.ts +23 -0
  889. package/scripts/rules/rule-value-cli.ts +129 -0
  890. package/scripts/rules/rule-value.ts +397 -0
  891. package/scripts/rules/run-tail.ts +178 -0
  892. package/scripts/rules/shell-body-trigger.ts +204 -0
  893. package/scripts/rules/shell-segments.ts +45 -0
  894. package/scripts/rules/stop-rules.ts +329 -0
  895. package/scripts/rules/tail-commands.ts +35 -0
  896. package/scripts/rules/test-declared-commit.ts +51 -0
  897. package/scripts/rules/third-party-write.ts +90 -0
  898. package/scripts/rules/top-level-scripts-guard.ts +47 -0
  899. package/scripts/rules/worktree-guard.ts +130 -0
  900. package/scripts/run/detached-launch.ts +360 -0
  901. package/scripts/run/run-carry-args.ts +264 -0
  902. package/scripts/run/run-carry-change.ts +69 -0
  903. package/scripts/run/run-carry-cli.ts +441 -0
  904. package/scripts/run/run-carry-flush.ts +63 -0
  905. package/scripts/run/run-carry-stash.ts +71 -0
  906. package/scripts/run/run-carry-streak.ts +113 -0
  907. package/scripts/run/run-carry.ts +550 -0
  908. package/scripts/run/run-cut-args.ts +132 -0
  909. package/scripts/run/run-cut-cli.ts +461 -0
  910. package/scripts/run/run-cut-handoff.ts +126 -0
  911. package/scripts/run/run-cut.ts +531 -0
  912. package/scripts/run/run-ending-cli.ts +111 -0
  913. package/scripts/run/run-ending.ts +239 -0
  914. package/scripts/run/run-entry-cli.ts +135 -0
  915. package/scripts/run/run-entry.ts +95 -0
  916. package/scripts/run/run-event-cli.ts +210 -0
  917. package/scripts/run/run-event-follow.ts +65 -0
  918. package/scripts/run/run-event-render.ts +75 -0
  919. package/scripts/run/run-event-scope.ts +127 -0
  920. package/scripts/run/run-event-stream-emit.ts +140 -0
  921. package/scripts/run/run-event-stream.ts +258 -0
  922. package/scripts/run/run-event-watch.ts +37 -0
  923. package/scripts/run/run-headless.ts +105 -0
  924. package/scripts/run/run-hold-cli.ts +310 -0
  925. package/scripts/run/run-hold.ts +264 -0
  926. package/scripts/run/run-invocation.ts +237 -0
  927. package/scripts/run/run-issue-number.ts +19 -0
  928. package/scripts/run/run-liveness-cli.ts +169 -0
  929. package/scripts/run/run-liveness.ts +424 -0
  930. package/scripts/run/run-merge-cli.ts +385 -0
  931. package/scripts/run/run-merge-steps.ts +326 -0
  932. package/scripts/run/run-merge.ts +158 -0
  933. package/scripts/run/run-next-cli.ts +48 -0
  934. package/scripts/run/run-next.ts +80 -0
  935. package/scripts/run/run-preflight.ts +337 -0
  936. package/scripts/run/run-prep-cli.ts +151 -0
  937. package/scripts/run/run-prep.ts +84 -0
  938. package/scripts/run/run-progress-args.ts +65 -0
  939. package/scripts/run/run-progress-cli.ts +508 -0
  940. package/scripts/run/run-progress-clock.ts +320 -0
  941. package/scripts/run/run-progress-config.ts +119 -0
  942. package/scripts/run/run-progress-read.ts +199 -0
  943. package/scripts/run/run-progress.ts +366 -0
  944. package/scripts/run/run-report-cli.ts +71 -0
  945. package/scripts/run/run-report.ts +78 -0
  946. package/scripts/run/run-review-cli.ts +130 -0
  947. package/scripts/run/run-review-steps.ts +161 -0
  948. package/scripts/run/run-review.ts +121 -0
  949. package/scripts/run/run-ship-cli.ts +431 -0
  950. package/scripts/run/run-ship-detach.ts +200 -0
  951. package/scripts/run/run-ship-probe.ts +103 -0
  952. package/scripts/run/run-ship-return.ts +75 -0
  953. package/scripts/run/run-ship-review-steps.ts +227 -0
  954. package/scripts/run/run-ship-review.ts +177 -0
  955. package/scripts/run/run-ship-stage.ts +150 -0
  956. package/scripts/run/run-ship.ts +78 -0
  957. package/scripts/run/run-status-cli.ts +175 -0
  958. package/scripts/run/run-status.ts +77 -0
  959. package/scripts/run/run-step-cli.ts +111 -0
  960. package/scripts/run/run-step.ts +292 -0
  961. package/scripts/run/run-stop-notify.ts +52 -0
  962. package/scripts/run/run-stranded-cli.ts +31 -0
  963. package/scripts/run/run-stranded-detect.ts +134 -0
  964. package/scripts/run/run-stranded.ts +120 -0
  965. package/scripts/run/run-tail-cli.ts +105 -0
  966. package/scripts/run/run-tail.ts +61 -0
  967. package/scripts/run/run-transcript.golden.txt +57 -0
  968. package/scripts/run/run-wake-cli.ts +428 -0
  969. package/scripts/run/run-wake-describe.ts +97 -0
  970. package/scripts/run/run-wake-driver.ts +80 -0
  971. package/scripts/run/run-wake-handoff.ts +29 -0
  972. package/scripts/run/run-wake-loop.ts +223 -0
  973. package/scripts/run/run-wake-session.ts +150 -0
  974. package/scripts/run/run-wake-work.ts +104 -0
  975. package/scripts/run/run-wake.ts +607 -0
  976. package/scripts/run/run-watcher-guard-cli.ts +37 -0
  977. package/scripts/run/run-watcher-guard.ts +59 -0
  978. package/scripts/run/run-watcher-hook.ts +86 -0
  979. package/scripts/security/secretlint-scan.ts +86 -0
  980. package/scripts/security/security-audit-logic.ts +51 -0
  981. package/scripts/security/security-audit-provision-logic.ts +217 -0
  982. package/scripts/security/security-audit-provision.ts +186 -0
  983. package/scripts/security/security-audit.ts +132 -0
  984. package/scripts/security/security-updates-logic.ts +131 -0
  985. package/scripts/security/security-updates.ts +38 -0
  986. package/scripts/security/sonar-file.ts +44 -0
  987. package/scripts/self-sync-guard/index.ts +5 -0
  988. package/scripts/self-sync-guard/self-sync-guard-logic.ts +98 -0
  989. package/scripts/self-sync-guard/self-sync-refusal.ts +22 -0
  990. package/scripts/sonar/sonar-hotspots-cli.ts +149 -0
  991. package/scripts/sonar/sonar-hotspots.ts +111 -0
  992. package/scripts/split/split-assess-cli.ts +52 -0
  993. package/scripts/split/split-assess.ts +124 -0
  994. package/scripts/sync/dependabot-pin-logic.ts +135 -0
  995. package/scripts/sync/directory-copy-guard.ts +187 -0
  996. package/scripts/sync/file-content.ts +49 -0
  997. package/scripts/sync/managed-config-scope-cli.ts +64 -0
  998. package/scripts/sync/managed-config-scope.ts +123 -0
  999. package/scripts/sync/plugin-skill-directories.ts +15 -0
  1000. package/scripts/sync/reconcile-templates.ts +53 -0
  1001. package/scripts/sync/removed-skill-manifest.ts +27 -0
  1002. package/scripts/sync/skill-migration.ts +192 -0
  1003. package/scripts/sync/sync-configs.ts +156 -0
  1004. package/scripts/sync/sync-hook-safety.ts +82 -0
  1005. package/scripts/sync/sync.ts +417 -0
  1006. package/scripts/sync/synced-paths.ts +52 -0
  1007. package/scripts/sync/template-source-logic.ts +122 -0
  1008. package/scripts/sync/workflow-pin-logic.ts +240 -0
  1009. package/scripts/test/classify-isolation.ts +149 -0
  1010. package/scripts/test/e2e-retry-check.ts +150 -0
  1011. package/scripts/test/http-fault-injection.ts +79 -0
  1012. package/scripts/test/josh-harness-environment.ts +260 -0
  1013. package/scripts/test/josh-harness.ts +96 -0
  1014. package/scripts/test/pilot-files.ts +457 -0
  1015. package/scripts/test/pilot-measure.ts +78 -0
  1016. package/scripts/test/test-declared-changed.ts +99 -0
  1017. package/scripts/test/test-declared-logic.ts +91 -0
  1018. package/scripts/test/test-declared-match.ts +106 -0
  1019. package/scripts/test/test-declared.ts +180 -0
  1020. package/scripts/test/test-e2e-guard.ts +86 -0
  1021. package/scripts/test/test-network-guard.ts +453 -0
  1022. package/scripts/test/test-red-commit.ts +51 -0
  1023. package/scripts/test/test-red-logic.ts +76 -0
  1024. package/scripts/test/test-red.ts +154 -0
  1025. package/scripts/test/test-related-scope.ts +115 -0
  1026. package/scripts/test/test-related.ts +73 -0
  1027. package/scripts/test/test-repository-guard.ts +317 -0
  1028. package/scripts/test/test-state-guard.ts +85 -0
  1029. package/scripts/test/test-stdout-guard.ts +54 -0
  1030. package/scripts/test/test-telegram-guard.ts +90 -0
  1031. package/scripts/test/test-type-logic.ts +31 -0
  1032. package/scripts/test/test-unit-guard.ts +185 -0
  1033. package/scripts/test/unit-guard-environment.ts +12 -0
  1034. package/scripts/test/unit-projects.ts +139 -0
  1035. package/scripts/test/unit-worker-share.ts +251 -0
  1036. package/scripts/test/vitest-include-globs.ts +12 -0
  1037. package/scripts/time-runtime/time-agent-bundles.ts +128 -0
  1038. package/scripts/time-runtime/time-background.ts +300 -0
  1039. package/scripts/time-runtime/time-batch-guard-fixtures.ts +66 -0
  1040. package/scripts/time-runtime/time-batch-guard.ts +529 -0
  1041. package/scripts/time-runtime/time-bundle-call.ts +575 -0
  1042. package/scripts/time-runtime/time-bundles.ts +536 -0
  1043. package/scripts/time-runtime/time-call-identity.ts +37 -0
  1044. package/scripts/time-runtime/time-command-key.ts +35 -0
  1045. package/scripts/time-runtime/time-density-hook.ts +166 -0
  1046. package/scripts/time-runtime/time-density.ts +147 -0
  1047. package/scripts/time-runtime/time-followup-stage.ts +107 -0
  1048. package/scripts/time-runtime/time-format.ts +186 -0
  1049. package/scripts/time-runtime/time-hook-transcript.ts +82 -0
  1050. package/scripts/time-runtime/time-instant.ts +20 -0
  1051. package/scripts/time-runtime/time-markers.ts +228 -0
  1052. package/scripts/time-runtime/time-phase-names.ts +123 -0
  1053. package/scripts/time-runtime/time-reported-failure.ts +227 -0
  1054. package/scripts/time-runtime/time-round-trips.ts +279 -0
  1055. package/scripts/time-runtime/time-shell.ts +286 -0
  1056. package/scripts/time-runtime/time-single-check.ts +65 -0
  1057. package/scripts/time-runtime/time-spans.ts +545 -0
  1058. package/scripts/time-runtime/time-transcript-line.ts +253 -0
  1059. package/scripts/time-runtime/time-writes.ts +71 -0
  1060. package/scripts/ui/ui-routes-cli.ts +122 -0
  1061. package/scripts/ui/ui-routes.ts +102 -0
  1062. package/scripts/version/bump-version.ts +71 -0
  1063. package/scripts/version/effective-upstream.ts +93 -0
  1064. package/scripts/version/index.ts +25 -0
  1065. package/scripts/version/kit-descriptor.ts +10 -0
  1066. package/scripts/version/kit-version-config.ts +30 -0
  1067. package/scripts/version/latest-corepack.ts +404 -0
  1068. package/scripts/version/latest-lane-guard.ts +49 -0
  1069. package/scripts/version/latest-regression.ts +93 -0
  1070. package/scripts/version/latest-scope-cli.ts +147 -0
  1071. package/scripts/version/latest-stamp.ts +107 -0
  1072. package/scripts/version/latest-update.ts +198 -0
  1073. package/scripts/version/package-manager-version.ts +95 -0
  1074. package/scripts/version/parse-json.ts +13 -0
  1075. package/scripts/version/preinstall-version-update.ts +84 -0
  1076. package/scripts/version/publishable-range-check.ts +74 -0
  1077. package/scripts/version/publishable-range.ts +123 -0
  1078. package/scripts/version/release-age.ts +146 -0
  1079. package/scripts/version/release-hold.ts +142 -0
  1080. package/scripts/version/running-binary.ts +42 -0
  1081. package/scripts/version/upgrade-command-guard.ts +49 -0
  1082. package/scripts/version/upgrade-shell-command.ts +30 -0
  1083. package/scripts/version/version-check-logic.ts +333 -0
  1084. package/scripts/version/version-check.ts +14 -0
  1085. package/scripts/version/version-command-config.ts +177 -0
  1086. package/scripts/version/version-commands.ts +296 -0
  1087. package/scripts/version/version-remote.ts +86 -0
  1088. package/scripts/version/version-targets.ts +81 -0
  1089. package/scripts/yaml/yaml-document.ts +46 -0
  1090. package/scripts-ai/completion-gate.ts +13 -0
  1091. package/scripts-ai/environment-loader.ts +9 -0
  1092. package/scripts-ai/epic-check.ts +34 -0
  1093. package/scripts-ai/epic-cli-argv.ts +77 -0
  1094. package/scripts-ai/epic-cli-remove.ts +71 -0
  1095. package/scripts-ai/epic-cli.ts +413 -0
  1096. package/scripts-ai/epic.ts +192 -0
  1097. package/scripts-ai/followup-issue-number.ts +31 -0
  1098. package/scripts-ai/git-followup-finish.ts +217 -0
  1099. package/scripts-ai/git-followup-workflow.ts +252 -0
  1100. package/scripts-ai/git-workflow.ts +246 -0
  1101. package/scripts-ai/telegram-test-logic.ts +88 -0
  1102. package/scripts-ai/telegram-test.ts +130 -0
  1103. package/templates/gitignore +76 -0
  1104. package/templates/sonar-project.properties +52 -0
  1105. package/templates/workflows/ci.yml +639 -0
  1106. package/templates/workflows/dependabot-auto-merge.yml +428 -0
  1107. package/tsconfig/base.json +50 -0
  1108. package/tsconfig.sonar.json +34 -0
@@ -0,0 +1,1769 @@
1
+ import {
2
+ git_utilities,
3
+ lane_park,
4
+ run_cut,
5
+ shell_segments
6
+ } from "./chunk-33ELOKEV.js";
7
+ import {
8
+ batch_outcome
9
+ } from "./chunk-BVNWORKA.js";
10
+ import {
11
+ investigation_reads,
12
+ investigation_refusal
13
+ } from "./chunk-MK56LKDO.js";
14
+ import {
15
+ lane_guard_policy,
16
+ time_batch_guard
17
+ } from "./chunk-ARN7NCQI.js";
18
+ import {
19
+ hook_decision,
20
+ lane_child_marker
21
+ } from "./chunk-VEZVK6C7.js";
22
+ import {
23
+ cost_blocks,
24
+ json_value,
25
+ lane_paths,
26
+ stamp_file,
27
+ time_density_hook,
28
+ time_shell,
29
+ time_transcript_line
30
+ } from "./chunk-5P7VF5VE.js";
31
+
32
+ // scripts/hooks/pretool-guard.ts
33
+ import { text } from "node:stream/consumers";
34
+ import { fileURLToPath } from "node:url";
35
+
36
+ // scripts/rules/bash-triggers.ts
37
+ function on_bash_command(is_match) {
38
+ return function is_trigger(call) {
39
+ if (call.name !== cost_blocks.BASH_TOOL) return false;
40
+ return is_match(time_shell.bash_command(call.input));
41
+ };
42
+ }
43
+ var ISSUE_CREATE_COMMAND = /\bgh\s+(?:\S+\s+)*?issue\s+create\b/u;
44
+ var ISSUES_ENDPOINT = /repos\/[^\s'"]*\/issues(?=$|["'\s])/u;
45
+ var TITLE_FIELD = /(?:-f|-F|--field|--raw-field)\s*'?title=/u;
46
+ function is_issue_filing(command) {
47
+ if (ISSUE_CREATE_COMMAND.test(command)) return true;
48
+ return ISSUES_ENDPOINT.test(command) && TITLE_FIELD.test(command);
49
+ }
50
+ var bash_triggers = { is_issue_filing, on_bash_command };
51
+
52
+ // scripts/run/run-progress.ts
53
+ var DEFAULT_INTERVAL_MINUTES = 20;
54
+ var INTERVAL_KEY = "JOSH_PROGRESS_INTERVAL_MINUTES";
55
+ var MS_PER_MINUTE = 6e4;
56
+ var MS_PER_SECOND = 1e3;
57
+ var DEFAULT_INTERVAL_MS = DEFAULT_INTERVAL_MINUTES * MS_PER_MINUTE;
58
+ var NO_LANES = "none";
59
+ var NO_CHILD_YET = "no in-progress child yet";
60
+ var NO_NEXT = "none";
61
+ var QUIET_MARKER = "\u23F3";
62
+ var STAMP_END = 16;
63
+ var PAD_WIDTH = 2;
64
+ var MINUTES_PER_HOUR = 60;
65
+ function to_minutes(elapsed_ms) {
66
+ return Math.floor(elapsed_ms / MS_PER_MINUTE);
67
+ }
68
+ function format_minutes(elapsed_ms) {
69
+ return `${String(to_minutes(elapsed_ms))}m`;
70
+ }
71
+ function pad(value) {
72
+ return String(value).padStart(PAD_WIDTH, "0");
73
+ }
74
+ function offset_minutes(date) {
75
+ return Math.round(-date.getTimezoneOffset());
76
+ }
77
+ function format_offset(total_minutes) {
78
+ const sign = total_minutes < 0 ? "-" : "+";
79
+ const absolute = Math.abs(total_minutes);
80
+ return `${sign}${pad(Math.floor(absolute / MINUTES_PER_HOUR))}:${pad(absolute % MINUTES_PER_HOUR)}`;
81
+ }
82
+ function format_observed_at(now_ms) {
83
+ const minutes = offset_minutes(new Date(now_ms));
84
+ const local = new Date(now_ms + minutes * MS_PER_MINUTE);
85
+ const day = `${String(local.getUTCFullYear())}-${pad(local.getUTCMonth() + 1)}-${pad(local.getUTCDate())}`;
86
+ const clock = `${pad(local.getUTCHours())}:${pad(local.getUTCMinutes())}${format_offset(minutes)}`;
87
+ return `${day} ${clock} / ${new Date(now_ms).toISOString().slice(0, STAMP_END)}Z`;
88
+ }
89
+ function observation_key(observations) {
90
+ return JSON.stringify({ children: observations.children, lanes: observations.lanes });
91
+ }
92
+ function next_state(previous, key, now_ms) {
93
+ if (previous?.key === key) return previous;
94
+ return { key, unchanged_since_ms: now_ms };
95
+ }
96
+ function format_child(child) {
97
+ const labels = child.labels.length > 0 ? child.labels.join(",") : "(no labels)";
98
+ return `#${child.issue} ${labels} PR:${child.pr_state}`;
99
+ }
100
+ function format_children(children) {
101
+ if (children.length === 0) return NO_CHILD_YET;
102
+ return children.map((child) => format_child(child)).join(" \xB7 ");
103
+ }
104
+ function format_lanes(lanes) {
105
+ if (lanes.length === 0) return NO_LANES;
106
+ return lanes.map((lane) => `${lane.issue}:${lane.state}`).join(" ");
107
+ }
108
+ function format_record(record_age_ms) {
109
+ return record_age_ms === void 0 ? "unread" : `+${format_minutes(record_age_ms)}`;
110
+ }
111
+ function format_next_report(now_ms, interval_ms) {
112
+ return format_observed_at(now_ms + interval_ms);
113
+ }
114
+ function format_next_line(next) {
115
+ return `next ${next ?? NO_NEXT}`;
116
+ }
117
+ function format_report(fields) {
118
+ return [
119
+ `${QUIET_MARKER} at ${fields.observed_at}`,
120
+ `quiet ${fields.quiet} \xB7 unchanged ${fields.unchanged}`,
121
+ `children ${fields.children}`,
122
+ `lanes ${fields.lanes} \xB7 load ${fields.load} \xB7 record ${fields.record}`,
123
+ format_next_line(fields.next)
124
+ ].join("\n");
125
+ }
126
+ function format_line(observations, timing) {
127
+ return format_report({
128
+ observed_at: format_observed_at(timing.now_ms),
129
+ quiet: format_minutes(timing.now_ms - timing.quiet_since_ms),
130
+ unchanged: format_minutes(timing.now_ms - timing.unchanged_since_ms),
131
+ children: format_children(observations.children),
132
+ lanes: format_lanes(observations.lanes),
133
+ load: observations.load_average.toFixed(1),
134
+ record: format_record(observations.record_age_ms),
135
+ next: format_next_report(timing.now_ms, timing.interval_ms)
136
+ });
137
+ }
138
+ function is_due(last_report_ms, now_ms, interval_ms) {
139
+ return now_ms - last_report_ms >= interval_ms;
140
+ }
141
+ function minutes_from(raw) {
142
+ const minutes = Number(raw);
143
+ if (raw === void 0 || raw.trim() === "" || !Number.isFinite(minutes) || minutes <= 0) {
144
+ return void 0;
145
+ }
146
+ return minutes;
147
+ }
148
+ var run_progress = {
149
+ DEFAULT_INTERVAL_MINUTES,
150
+ DEFAULT_INTERVAL_MS,
151
+ INTERVAL_KEY,
152
+ MS_PER_MINUTE,
153
+ MS_PER_SECOND,
154
+ NO_CHILD_YET,
155
+ NO_NEXT,
156
+ format_child,
157
+ format_children,
158
+ format_lanes,
159
+ format_line,
160
+ format_next_line,
161
+ format_next_report,
162
+ format_record,
163
+ format_report,
164
+ is_due,
165
+ minutes_from,
166
+ next_state,
167
+ observation_key
168
+ };
169
+
170
+ // scripts/run/run-progress-clock.ts
171
+ import { execaSync } from "execa";
172
+ import { z } from "zod";
173
+ var PROGRESS_PREFIX = "josh-run-progress-";
174
+ var LIFE_PREFIX = "josh-run-progress-life-";
175
+ var LOG_SUFFIX = ".log";
176
+ var LOG_KEEP = 12;
177
+ var MS_PER_MINUTE2 = 6e4;
178
+ var LOG_STALE_MINUTES = 90;
179
+ var LOG_STALE_MS = LOG_STALE_MINUTES * MS_PER_MINUTE2;
180
+ var BLOCK_SEPARATOR = "\n\n";
181
+ var GIT_TIMEOUT_MS = 5e3;
182
+ var GIT_DIRECTORY_ARGUMENTS = ["rev-parse", "--absolute-git-dir"];
183
+ var report_stamp_schema = z.object({ reported_at: z.string(), line: z.string().optional() });
184
+ function parse_stamp(raw) {
185
+ const parsed = report_stamp_schema.safeParse(JSON.parse(raw));
186
+ if (!parsed.success) return void 0;
187
+ const reported_at = Date.parse(parsed.data.reported_at);
188
+ return Number.isNaN(reported_at) ? void 0 : reported_at;
189
+ }
190
+ function read_last_line(target) {
191
+ const raw = stamp_file.read_stamp_text(target);
192
+ if (raw === void 0) return void 0;
193
+ try {
194
+ return report_stamp_schema.safeParse(JSON.parse(raw)).data?.line;
195
+ } catch {
196
+ return void 0;
197
+ }
198
+ }
199
+ function read_last_report(target) {
200
+ const raw = stamp_file.read_stamp_text(target);
201
+ if (raw === void 0) return void 0;
202
+ try {
203
+ return parse_stamp(raw);
204
+ } catch {
205
+ return void 0;
206
+ }
207
+ }
208
+ function log_path_of(target) {
209
+ return `${target}${LOG_SUFFIX}`;
210
+ }
211
+ function is_log_stale(target, now_ms) {
212
+ const previous_ms = read_last_report(target);
213
+ return previous_ms === void 0 || now_ms - previous_ms > LOG_STALE_MS;
214
+ }
215
+ function recent_blocks(log_target, is_fresh) {
216
+ if (is_fresh) return [];
217
+ const raw = stamp_file.read_stamp_text(log_target);
218
+ if (raw === void 0) return [];
219
+ return raw.split(BLOCK_SEPARATOR).map((block) => block.trimEnd()).filter((block) => block.length > 0);
220
+ }
221
+ function append_line(log_target, reported_at, line, is_fresh) {
222
+ const block = `${reported_at}
223
+ ${line}`;
224
+ const blocks = [...recent_blocks(log_target, is_fresh), block].slice(-LOG_KEEP);
225
+ stamp_file.write_text_stamp(log_target, `${blocks.join(BLOCK_SEPARATOR)}
226
+ `);
227
+ }
228
+ function mark(target, now_ms, line) {
229
+ const reported_at = new Date(now_ms).toISOString();
230
+ const kept = line ?? read_last_line(target);
231
+ if (line !== void 0) {
232
+ append_line(log_path_of(target), reported_at, line, is_log_stale(target, now_ms));
233
+ }
234
+ stamp_file.write_stamp(target, kept === void 0 ? { reported_at } : { reported_at, line: kept });
235
+ }
236
+ function stamp_target_of(git_directory) {
237
+ return stamp_file.stamp_path(PROGRESS_PREFIX, git_directory);
238
+ }
239
+ function life_target_of(git_directory) {
240
+ return stamp_file.stamp_path(LIFE_PREFIX, git_directory);
241
+ }
242
+ var life_schema = z.object({ alive: z.literal(true), pinged_at: z.string().optional() });
243
+ function begin_life(target) {
244
+ stamp_file.write_stamp(target, { alive: true, pinged_at: (/* @__PURE__ */ new Date()).toISOString() });
245
+ }
246
+ function ping_life(target) {
247
+ begin_life(target);
248
+ }
249
+ function parse_pinged_at(raw) {
250
+ const parsed = life_schema.safeParse(JSON.parse(raw));
251
+ if (!parsed.success || parsed.data.pinged_at === void 0) return void 0;
252
+ const pinged_ms = Date.parse(parsed.data.pinged_at);
253
+ return Number.isNaN(pinged_ms) ? void 0 : pinged_ms;
254
+ }
255
+ function is_life_fresh(target, threshold_ms) {
256
+ const raw = stamp_file.read_stamp_text(target);
257
+ if (raw === void 0) return false;
258
+ try {
259
+ const pinged_ms = parse_pinged_at(raw);
260
+ return pinged_ms !== void 0 && Date.now() - pinged_ms < threshold_ms;
261
+ } catch {
262
+ return false;
263
+ }
264
+ }
265
+ function is_life_ended(target) {
266
+ return stamp_file.read_stamp_text(target) === void 0;
267
+ }
268
+ function end_life(target) {
269
+ stamp_file.remove_stamp(target);
270
+ }
271
+ function git_directory_sync() {
272
+ const git_binary = git_utilities.get_git_command_for_spawn();
273
+ const result = execaSync(git_binary, GIT_DIRECTORY_ARGUMENTS, {
274
+ reject: false,
275
+ timeout: GIT_TIMEOUT_MS
276
+ });
277
+ if (result.exitCode !== 0) return void 0;
278
+ const output = result.stdout.trim();
279
+ return output === "" ? void 0 : output;
280
+ }
281
+ function stamp_target_sync() {
282
+ const directory = git_directory_sync();
283
+ return directory === void 0 ? void 0 : stamp_target_of(directory);
284
+ }
285
+ function read_last_report_sync() {
286
+ const target = stamp_target_sync();
287
+ return target === void 0 ? void 0 : read_last_report(target);
288
+ }
289
+ var run_progress_clock = {
290
+ LIFE_PREFIX,
291
+ LOG_KEEP,
292
+ LOG_STALE_MS,
293
+ PROGRESS_PREFIX,
294
+ append_line,
295
+ begin_life,
296
+ end_life,
297
+ is_life_ended,
298
+ is_life_fresh,
299
+ life_target_of,
300
+ log_path_of,
301
+ mark,
302
+ parse_stamp,
303
+ ping_life,
304
+ read_last_line,
305
+ read_last_report,
306
+ read_last_report_sync,
307
+ stamp_target_of,
308
+ stamp_target_sync
309
+ };
310
+
311
+ // scripts/run/run-progress-config.ts
312
+ import { readFileSync } from "node:fs";
313
+ import path from "node:path";
314
+ import { z as z2 } from "zod";
315
+ var PACKAGE_FILE = "package.json";
316
+ var CONFIG_FIELD = "josh";
317
+ var INTERVAL_FIELD = "progress_interval_minutes";
318
+ var MAX_DEPTH = 10;
319
+ var package_schema = z2.object({
320
+ josh: z2.object({ progress_interval_minutes: z2.number().positive() }).optional()
321
+ });
322
+ function ancestors_of(start) {
323
+ const directories = [];
324
+ let current = path.resolve(start);
325
+ while (directories.length < MAX_DEPTH && !directories.includes(current)) {
326
+ directories.push(current);
327
+ current = path.dirname(current);
328
+ }
329
+ return directories;
330
+ }
331
+ function read_declared_minutes(directory) {
332
+ try {
333
+ const raw = readFileSync(path.join(directory, PACKAGE_FILE), "utf8");
334
+ const parsed = package_schema.safeParse(JSON.parse(raw));
335
+ return parsed.success ? parsed.data.josh?.progress_interval_minutes : void 0;
336
+ } catch {
337
+ return void 0;
338
+ }
339
+ }
340
+ function read_package_minutes(start) {
341
+ for (const directory of ancestors_of(start)) {
342
+ const minutes = read_declared_minutes(directory);
343
+ if (minutes !== void 0) return minutes;
344
+ }
345
+ return void 0;
346
+ }
347
+ function to_ms(minutes) {
348
+ return minutes === void 0 ? void 0 : minutes * run_progress.MS_PER_MINUTE;
349
+ }
350
+ function resolve_interval_ms(raw, directory = process.cwd()) {
351
+ return to_ms(run_progress.minutes_from(raw)) ?? to_ms(run_progress.minutes_from(process.env[run_progress.INTERVAL_KEY])) ?? to_ms(read_package_minutes(directory)) ?? run_progress.DEFAULT_INTERVAL_MS;
352
+ }
353
+ function configured_interval_ms(directory = process.cwd()) {
354
+ return resolve_interval_ms(void 0, directory);
355
+ }
356
+ var run_progress_config = {
357
+ CONFIG_FIELD,
358
+ INTERVAL_FIELD,
359
+ PACKAGE_FILE,
360
+ configured_interval_ms,
361
+ read_package_minutes,
362
+ resolve_interval_ms
363
+ };
364
+
365
+ // scripts/rules/early-heartbeat.ts
366
+ var ARM_PREFIX = "josh-heartbeat-arm-";
367
+ var SEGMENT_SEPARATOR = /&&|\|\||;|&|\n/u;
368
+ var SLEEP_SEGMENT = /^sleep\s+(\d+(?:\.\d+)?)([smhd]?)$/u;
369
+ var INERT_SEGMENT = /^(?::|true|(?:echo|printf|date)\b.*)$/u;
370
+ var LOOP_KEYWORD = /\b(?:while|until|for|do|done)\b/u;
371
+ var SECONDS_PER_UNIT = { d: 86400, h: 3600, m: 60, s: 1 };
372
+ var BARE_NUMBER_SECONDS = 1;
373
+ var AMOUNT_GROUP = 1;
374
+ var UNIT_GROUP = 2;
375
+ var NO_SECONDS = 0;
376
+ var ARM_RECORD = hook_decision.create_refusal_stamp(ARM_PREFIX);
377
+ function segments_of(command) {
378
+ return command.split(SEGMENT_SEPARATOR).map((segment) => segment.trim()).filter((segment) => segment !== "");
379
+ }
380
+ function sleep_seconds(segment) {
381
+ const matched = SLEEP_SEGMENT.exec(segment);
382
+ if (matched === null) return void 0;
383
+ const unit = matched[UNIT_GROUP] ?? "";
384
+ return Number(matched[AMOUNT_GROUP]) * (SECONDS_PER_UNIT[unit] ?? BARE_NUMBER_SECONDS);
385
+ }
386
+ function is_wait_or_inert(segment) {
387
+ return sleep_seconds(segment) !== void 0 || INERT_SEGMENT.test(segment);
388
+ }
389
+ function is_wait_timer(command) {
390
+ if (LOOP_KEYWORD.test(command)) return false;
391
+ const segments = segments_of(command);
392
+ if (segments.every((segment) => sleep_seconds(segment) === void 0)) return false;
393
+ return segments.every((segment) => is_wait_or_inert(segment));
394
+ }
395
+ function wait_duration_ms(command) {
396
+ const seconds = segments_of(command).reduce(
397
+ (total, segment) => total + (sleep_seconds(segment) ?? NO_SECONDS),
398
+ NO_SECONDS
399
+ );
400
+ return seconds * run_progress.MS_PER_SECOND;
401
+ }
402
+ function is_armed(target, now_ms) {
403
+ return now_ms < ARM_RECORD.last_ms(target);
404
+ }
405
+ function landing_ms(command, now_ms, last_report_ms) {
406
+ const interval_ms = run_progress_config.configured_interval_ms();
407
+ const duration_ms = wait_duration_ms(command);
408
+ if (duration_ms > interval_ms) return void 0;
409
+ const lands_ms = now_ms + duration_ms;
410
+ return run_progress.is_due(last_report_ms, lands_ms, interval_ms) ? lands_ms : void 0;
411
+ }
412
+ function decide(call, run, can_record) {
413
+ const last_report_ms = run_progress_clock.read_last_report_sync();
414
+ if (last_report_ms === void 0) return false;
415
+ const target = ARM_RECORD.path(run.transcript);
416
+ if (is_armed(target, run.now_ms)) return true;
417
+ const lands_ms = landing_ms(time_shell.bash_command(call.input), run.now_ms, last_report_ms);
418
+ if (lands_ms === void 0) return true;
419
+ if (can_record) ARM_RECORD.record(target, lands_ms);
420
+ return false;
421
+ }
422
+ var EARLY_HEARTBEAT_REASON = '\u26D4 early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours to keep. `pnpm josh run:progress --wait` waits the interval out for you (`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, default 20 minutes), prints the five labelled lines and exits \u2014 start it in the background, relay the lines it printed when it exits, and start the next one. Two timers armed at once is what produced reports 3\u20135 minutes apart on a 15-minute setting (joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a child\'s completion woke the run, and `--mark` recorded each report without anything refusing the early ones. **An explicit ask is not a heartbeat**: if the person asked for progress now, run `pnpm josh run:progress --once`, which prints the five labelled lines whatever the clock says. If you are waiting on something rather than on a clock, wait on the thing itself \u2014 `pnpm josh followup` waits for CI. The procedure is `.claude/skills/workflow-commands/backlogrun.md` \u2192 "Progress while the run is quiet". **This rule fires on every early arm, not once per run**, so reissuing the same sleep will be refused again.';
423
+ var PROGRESS_NAMES = /* @__PURE__ */ new Set(["run:progress"]);
424
+ var WATCH_FLAG = /(?:^|\s)--(?:wait|once)(?=\s|$)/u;
425
+ function is_progress_watch_segment(segment) {
426
+ return shell_segments.is_josh_command(segment, PROGRESS_NAMES) && WATCH_FLAG.test(segment);
427
+ }
428
+ function is_progress_watch(command) {
429
+ return segments_of(time_shell.unquoted(command)).some(
430
+ (segment) => is_progress_watch_segment(segment)
431
+ );
432
+ }
433
+ function waits_for_progress(command) {
434
+ return is_wait_timer(command) || is_progress_watch(command);
435
+ }
436
+ var early_heartbeat = {
437
+ ARM_PREFIX,
438
+ EARLY_HEARTBEAT_REASON,
439
+ decide,
440
+ is_progress_watch,
441
+ is_wait_timer,
442
+ wait_duration_ms,
443
+ waits_for_progress
444
+ };
445
+
446
+ // scripts/rules/file-body.ts
447
+ import { existsSync } from "node:fs";
448
+ var HEREDOC = /<<-?\s*['"]?\w+/u;
449
+ var LINE_BREAK = "\n";
450
+ function first_line(command) {
451
+ const [line] = command.split(LINE_BREAK);
452
+ return line ?? "";
453
+ }
454
+ function has_heredoc(command) {
455
+ return HEREDOC.test(command);
456
+ }
457
+ var FILE_REDIRECT = /(?:^|\s)>>?\s*(?!&)("[^"]+"|'[^']+'|\S+)/u;
458
+ var TEE_TARGET = /\btee\s+(?:-a\s+)?(?!-)("[^"]+"|'[^']+'|\S+)/u;
459
+ var QUOTES = /^['"]|['"]$/gu;
460
+ function redirect_target(line) {
461
+ const target = FILE_REDIRECT.exec(line)?.[1] ?? TEE_TARGET.exec(line)?.[1];
462
+ return target === void 0 ? void 0 : target.replaceAll(QUOTES, "");
463
+ }
464
+ function writes_existing_file(command, has_file) {
465
+ if (!has_heredoc(command)) return false;
466
+ const target = redirect_target(first_line(command));
467
+ return target !== void 0 && has_file(target);
468
+ }
469
+ var BODY_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3", "ruby", "perl", "php"]);
470
+ var NODE = "node";
471
+ var NODE_EVAL = /(?:^|\s)(?:-e|--eval)\b/u;
472
+ var WRITE_CALL = /writeFile|appendFile|createWriteStream|\.write(?:lines)?\s*\(/u;
473
+ var WRITE_MODE = /open\s*\([^)]*['"][rbt+]*[wax]|os\.replace|shutil\.(?:copy|move)/u;
474
+ function body_writes(command) {
475
+ return WRITE_CALL.test(command) || WRITE_MODE.test(command);
476
+ }
477
+ function is_interpreter_write(segment, command) {
478
+ const leading = time_shell.leading_word(segment);
479
+ if (BODY_INTERPRETERS.has(leading)) return has_heredoc(command) && body_writes(command);
480
+ return leading === NODE && NODE_EVAL.test(segment) && body_writes(segment);
481
+ }
482
+ var PERL = "perl";
483
+ var PERL_IN_PLACE = /^-[A-Za-z0-9]*i/u;
484
+ var WHITESPACE = /\s+/u;
485
+ function is_in_place_perl(segment) {
486
+ if (time_shell.leading_word(segment) !== PERL) return false;
487
+ return segment.split(WHITESPACE).some((word) => PERL_IN_PLACE.test(word));
488
+ }
489
+ function has_body_interpreter(command) {
490
+ return shell_segments.segments_of(first_line(command)).some((segment) => is_interpreter_write(segment, command) || is_in_place_perl(segment));
491
+ }
492
+ function carries_a_file_body(command, has_file = existsSync) {
493
+ return writes_existing_file(command, has_file) || has_body_interpreter(command);
494
+ }
495
+ var FILE_BODY_REASON = "\u26D4 file body in a shell command: this carries a file's new text inline \u2014 a heredoc rewriting an existing file, an interpreter (`python3 - <<`, `node -e`) whose body writes, or an in-place `perl -0pi -e`. `CLAUDE.md` forbids it because the command body is re-read on every later request of the run, so an editing script written early is billed for the rest of it (`file-edits.md` measured one run at ~2m45s spent retyping existing lines). Edit a region with the Edit tool (old / new), or pass a body by path (`--field body=@<path>`, `--body-file <path>`). A new-file creation (`cat > <new-file> <<EOF`), a read-only heredoc (`cat <<EOF`), and a short `sed -i` stay allowed. **This rule fires on every occurrence, not once per run.**";
496
+ var ROW = {
497
+ id: "file-body",
498
+ is_trigger: bash_triggers.on_bash_command((command) => carries_a_file_body(command)),
499
+ reason: FILE_BODY_REASON,
500
+ decide: () => true
501
+ };
502
+ var file_body = {
503
+ FILE_BODY_REASON,
504
+ ROW,
505
+ carries_a_file_body,
506
+ is_in_place_perl,
507
+ is_interpreter_write,
508
+ writes_existing_file
509
+ };
510
+
511
+ // scripts/rules/tail-commands.ts
512
+ function is_bash_use(block) {
513
+ return block.type === cost_blocks.TOOL_USE_TYPE && block.name === cost_blocks.BASH_TOOL;
514
+ }
515
+ function bash_commands_of(line) {
516
+ const parsed = time_transcript_line.parse_line(line);
517
+ if (parsed === void 0) return [];
518
+ return parsed.blocks.filter((block) => is_bash_use(block)).map((block) => time_shell.bash_command(block.input));
519
+ }
520
+ function prior_bash_commands(tail) {
521
+ return tail.split("\n").flatMap((line) => bash_commands_of(line));
522
+ }
523
+ var tail_commands = { bash_commands_of, is_bash_use, prior_bash_commands };
524
+
525
+ // scripts/rules/filing-cap.ts
526
+ var FILING_CAP = 10;
527
+ var CAP_REACHED = FILING_CAP;
528
+ function is_filing_use(block) {
529
+ if (!tail_commands.is_bash_use(block)) return false;
530
+ return bash_triggers.is_issue_filing(time_shell.bash_command(block.input));
531
+ }
532
+ function collect_block(block, found) {
533
+ if (block.result_id !== "") found.refusals.set(block.result_id, block.refusal_guard);
534
+ if (is_filing_use(block)) found.filing_ids.push(block.id);
535
+ }
536
+ function collect_line(line, found) {
537
+ const parsed = time_transcript_line.parse_line(line);
538
+ if (parsed === void 0) return;
539
+ for (const block of parsed.blocks) collect_block(block, found);
540
+ }
541
+ function scan_tail(tail) {
542
+ const found = { filing_ids: [], refusals: /* @__PURE__ */ new Map() };
543
+ for (const line of tail.split("\n")) collect_line(line, found);
544
+ return found;
545
+ }
546
+ function prior_filing_count(tail) {
547
+ const { filing_ids, refusals } = scan_tail(tail);
548
+ return filing_ids.filter((id) => (refusals.get(id) ?? "") === "").length;
549
+ }
550
+ function decide2(_call, run) {
551
+ return prior_filing_count(time_density_hook.read_tail(run.transcript)) >= CAP_REACHED;
552
+ }
553
+ var FILING_CAP_REASON = `\u26D4 filing cap: this run has already filed ${String(FILING_CAP)} Issues, the per-run ceiling \u2014 on reaching it, stop and report rather than filing more. Automatic filing is capped so a run cannot manufacture Issues faster than they can be closed (\`.claude/skills/workflow-commands/SKILL.md\` \u2192 \xA72d, \`observation-filing.md\`). A further Issue that genuinely must exist is a person's call, not this run's. **This rule fires on every filing past the cap, not once per run**, so reissuing the same filing will be refused again.`;
554
+ var ROW2 = {
555
+ id: "filing-cap",
556
+ is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
557
+ reason: FILING_CAP_REASON,
558
+ decide: decide2
559
+ };
560
+ var filing_cap = { FILING_CAP, FILING_CAP_REASON, ROW: ROW2, decide: decide2, prior_filing_count };
561
+
562
+ // scripts/rules/gh-api.ts
563
+ var GH_FLAGS = String.raw`(?:-{1,2}[\w-]+(?:[= ][^\s]+)?\s+)*`;
564
+ var GH_API_COMMAND = new RegExp(String.raw`^gh\s+${GH_FLAGS}api\s`, "u");
565
+ var API_METHOD = /(?:^|\s)(?:--method|-X)[= ]([A-Za-z]+)/u;
566
+ var API_FIELD = /(?:^|\s)(?:--raw-field|--field|--input|-F|-f)(?:[= ]|$)/u;
567
+ var READ_METHOD = "GET";
568
+ var REPO_PATH = /repos\/([^/\s'"?]+)\/([^/\s'"?]+)/u;
569
+ var OWNER_GROUP = 1;
570
+ var REPO_GROUP = 2;
571
+ function is_gh_api(segment) {
572
+ return GH_API_COMMAND.test(segment);
573
+ }
574
+ function is_read(segment) {
575
+ const method = API_METHOD.exec(segment)?.[1];
576
+ if (method !== void 0) return method.toUpperCase() === READ_METHOD;
577
+ return !API_FIELD.test(segment);
578
+ }
579
+ function is_write(segment) {
580
+ return !is_read(segment);
581
+ }
582
+ function repo_target(segment) {
583
+ const match = REPO_PATH.exec(segment);
584
+ if (match === null) return void 0;
585
+ return { owner: match[OWNER_GROUP] ?? "", repo: match[REPO_GROUP] ?? "" };
586
+ }
587
+ var gh_api = { GH_API_COMMAND, GH_FLAGS, is_gh_api, is_read, is_write, repo_target };
588
+
589
+ // scripts/rules/git-argv.ts
590
+ var ENV_ASSIGNMENT = /^[A-Za-z_]\w*=/u;
591
+ var WRAPPER_WORDS = /* @__PURE__ */ new Set([
592
+ "pnpm",
593
+ "npx",
594
+ "exec",
595
+ "run",
596
+ "sudo",
597
+ "command"
598
+ ]);
599
+ var SUBSHELL_OPEN = "(";
600
+ var VALUE_TAKING_GLOBALS = /* @__PURE__ */ new Set([
601
+ "-C",
602
+ "-c",
603
+ "--git-dir",
604
+ "--work-tree",
605
+ "--namespace",
606
+ "--exec-path",
607
+ "--super-prefix"
608
+ ]);
609
+ var FLAG_PREFIX = "-";
610
+ var GIT_COMMAND = "git";
611
+ var NEXT = 1;
612
+ var AFTER_VALUE = 2;
613
+ var WHITESPACE2 = /\s+/u;
614
+ function words_of(segment) {
615
+ return segment.split(WHITESPACE2).filter((word) => word !== "");
616
+ }
617
+ function is_wrapper_token(word) {
618
+ return word === SUBSHELL_OPEN || ENV_ASSIGNMENT.test(word) || WRAPPER_WORDS.has(word);
619
+ }
620
+ function after_wrapper(words) {
621
+ let index = 0;
622
+ while (index < words.length && is_wrapper_token(words[index] ?? "")) index += NEXT;
623
+ return index;
624
+ }
625
+ function global_step(flag) {
626
+ return VALUE_TAKING_GLOBALS.has(flag) ? AFTER_VALUE : NEXT;
627
+ }
628
+ function after_globals(words, start) {
629
+ let index = start;
630
+ while (index < words.length) {
631
+ const flag = words[index] ?? "";
632
+ if (!flag.startsWith(FLAG_PREFIX)) return index;
633
+ index += global_step(flag);
634
+ }
635
+ return index;
636
+ }
637
+ function parse(segment) {
638
+ const words = words_of(segment);
639
+ const git_index = after_wrapper(words);
640
+ if (words[git_index] !== GIT_COMMAND) return void 0;
641
+ const subcommand_index = after_globals(words, git_index + NEXT);
642
+ return { subcommand: words[subcommand_index], args: words.slice(subcommand_index + NEXT) };
643
+ }
644
+ var SHORT_CLUSTER = /^-[A-Za-z]+$/u;
645
+ function short_cluster_has(token, letters) {
646
+ if (!SHORT_CLUSTER.test(token)) return false;
647
+ const cluster = token.slice(FLAG_PREFIX.length);
648
+ for (let index = 0; index < letters.length; index += 1) {
649
+ if (cluster.includes(letters.charAt(index))) return true;
650
+ }
651
+ return false;
652
+ }
653
+ var git_argv = { parse, short_cluster_has, words_of };
654
+
655
+ // scripts/rules/git-force.ts
656
+ var FORCE_LONG_PREFIX = "--force";
657
+ var DELETE_LONG = "--delete";
658
+ var PUSH_SHORT_LETTERS = "fd";
659
+ var FORCE_OR_DELETE_REFSPEC = /^[+:]/u;
660
+ function is_force_or_delete_push(args) {
661
+ return args.some(
662
+ (argument) => argument.startsWith(FORCE_LONG_PREFIX) || argument === DELETE_LONG || git_argv.short_cluster_has(argument, PUSH_SHORT_LETTERS) || FORCE_OR_DELETE_REFSPEC.test(argument)
663
+ );
664
+ }
665
+ var BRANCH_DELETE_LETTERS = "dD";
666
+ function is_branch_delete(args) {
667
+ return args.some(
668
+ (argument) => argument === DELETE_LONG || git_argv.short_cluster_has(argument, BRANCH_DELETE_LETTERS)
669
+ );
670
+ }
671
+ var PUSH_SUBCOMMAND = "push";
672
+ var BRANCH_SUBCOMMAND = "branch";
673
+ function is_destructive_segment(segment) {
674
+ const call = git_argv.parse(segment);
675
+ if (call === void 0) return false;
676
+ if (call.subcommand === PUSH_SUBCOMMAND) return is_force_or_delete_push(call.args);
677
+ return call.subcommand === BRANCH_SUBCOMMAND && is_branch_delete(call.args);
678
+ }
679
+ function is_force_or_delete(command) {
680
+ return shell_segments.segments_of(command).some((segment) => is_destructive_segment(segment));
681
+ }
682
+ var GIT_FORCE_REASON = "\u26D4 force push or branch delete: this rewrites or removes shared history, which is Tier C and needs explicit current-turn user instruction \u2014 never an AI decision, even to fix a problem you caused (`prompts/collaboration-workflow/operating-rules.md`). The `.claude/settings.json` deny list matches globs, so it misses this spelling: a combined short cluster (`git push -uf`), a `git -C <path>` prefix, and the colon-form delete (`git push origin :branch`) all pass it. This row reads the argv instead, so the spelling does not matter. For an ordinary push use `pnpm josh git`; a force push, a `git push --delete` / `:branch`, or a `git branch -d` / `-D` is the user's to run in their own terminal. **This rule fires on every occurrence, not once per run.**";
683
+ var ROW3 = {
684
+ id: "git-force",
685
+ is_trigger: bash_triggers.on_bash_command(is_force_or_delete),
686
+ reason: GIT_FORCE_REASON,
687
+ decide: () => true
688
+ };
689
+ var git_force = {
690
+ GIT_FORCE_REASON,
691
+ ROW: ROW3,
692
+ is_branch_delete,
693
+ is_force_or_delete,
694
+ is_force_or_delete_push
695
+ };
696
+
697
+ // scripts/rules/issue-scout.ts
698
+ var SCOUT_NAMES = /* @__PURE__ */ new Set(["issue:scout"]);
699
+ function runs_the_scout(command) {
700
+ return shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, SCOUT_NAMES));
701
+ }
702
+ function already_scouted(tail, _call) {
703
+ return tail_commands.prior_bash_commands(tail).some((command) => runs_the_scout(command));
704
+ }
705
+ var ISSUE_SCOUT_REASON = '\u26D4 issue scout: this files an Issue with no `pnpm josh issue:scout` earlier in the run. A duplicate is likeliest for the work that just finished, which is exactly where self-restraint is weakest. Reissue after scouting: `pnpm josh issue:scout "<title>"` (add `--body "<one-line summary, citing #N where the work follows one>"` so the epic half can answer), then read its `Duplicates:` \u2014 an **open** candidate covering the same work stops the run rather than filing a second Issue, and a `(closed)` one means the work is already done \u2014 before reissuing this filing. The procedure is `.claude/skills/workflow-commands/SKILL.md` \u2192 \xA72e. It fires once per run and cannot repeat on the call in hand.';
706
+ var ROW4 = {
707
+ id: "issue-scout",
708
+ is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
709
+ reason: ISSUE_SCOUT_REASON,
710
+ already_satisfied: already_scouted,
711
+ keeps: bash_triggers.on_bash_command(runs_the_scout)
712
+ };
713
+ var issue_scout = { ISSUE_SCOUT_REASON, ROW: ROW4, already_scouted, runs_the_scout };
714
+
715
+ // scripts/agent/interactive-ask.ts
716
+ import { z as z3 } from "zod";
717
+ var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion"]);
718
+ function is_interactive_tool(name) {
719
+ return INTERACTIVE_TOOLS.has(name);
720
+ }
721
+ var OPTION_SCHEMA = z3.looseObject({ label: z3.string().optional() });
722
+ var QUESTION_SCHEMA = z3.looseObject({
723
+ question: z3.string().optional(),
724
+ options: z3.array(OPTION_SCHEMA).optional()
725
+ });
726
+ var ASK_INPUT_SCHEMA = z3.looseObject({ questions: z3.array(QUESTION_SCHEMA).optional() });
727
+ var DENIAL_SCHEMA = z3.looseObject({
728
+ tool_name: z3.string().optional(),
729
+ tool_input: z3.unknown().optional()
730
+ });
731
+ var UNKNOWN_QUESTION = "(question text unavailable)";
732
+ var OPTION_SEPARATOR = " / ";
733
+ var QUESTION_SEPARATOR = "; ";
734
+ function labels_of(question) {
735
+ return (question.options ?? []).map((option) => option.label ?? "").filter((label) => label !== "");
736
+ }
737
+ function render_question(question) {
738
+ const labels = labels_of(question);
739
+ const text2 = question.question ?? UNKNOWN_QUESTION;
740
+ return labels.length === 0 ? text2 : `${text2} [${labels.join(OPTION_SEPARATOR)}]`;
741
+ }
742
+ function interactive_input(raw) {
743
+ const denial = DENIAL_SCHEMA.safeParse(raw);
744
+ if (!denial.success || !is_interactive_tool(denial.data.tool_name ?? "")) return void 0;
745
+ const input = ASK_INPUT_SCHEMA.safeParse(denial.data.tool_input);
746
+ return input.success ? input.data : void 0;
747
+ }
748
+ function refused_ask_of(permission_denials) {
749
+ if (!Array.isArray(permission_denials)) return void 0;
750
+ const input = permission_denials.map((raw) => interactive_input(raw)).find((one) => one !== void 0);
751
+ const questions = input?.questions ?? [];
752
+ if (questions.length === 0) return void 0;
753
+ return questions.map((question) => render_question(question)).join(QUESTION_SEPARATOR);
754
+ }
755
+ var interactive_ask = { INTERACTIVE_TOOLS, is_interactive_tool, refused_ask_of };
756
+
757
+ // scripts/rules/lane-interactive-ask.ts
758
+ function is_interactive_ask(call, is_lane_child = lane_child_marker.is_child_of(process.cwd())) {
759
+ if (!interactive_ask.is_interactive_tool(call.name)) return false;
760
+ return is_lane_child;
761
+ }
762
+ var LANE_INTERACTIVE_ASK_REASON = '\u26D4 lane child interactive ask: this session is a dispatched lane child and cannot ask a person, so this call is refused. Left to run it would end the turn with nothing on the Issue \u2014 the parent then finds an OPEN Issue with `in-progress` and no question (joshuafolkken/kit#2201; joshuafolkken/kit#2034 placed the same rule one tool-call too late). Do not ask: park the decision instead. Apply `needs-decision` and post a comment carrying the question, the options and whether work was stashed \u2014 `gh api repos/{owner}/{repo}/issues/<N>/labels -f \'labels[]=needs-decision\'` then `gh api repos/{owner}/{repo}/issues/<N>/comments --field body=@<path>` \u2014 then send the `confirmation` Telegram and stop. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` \u2192 "A lane child records its park before it stops", and the park itself is `backlogrun-park.md` \u2192 "park and continue". This rule fires on every occurrence, not once per run.';
763
+ var ROW5 = {
764
+ id: "lane-interactive-ask",
765
+ is_trigger: is_interactive_ask,
766
+ reason: LANE_INTERACTIVE_ASK_REASON,
767
+ decide: () => true
768
+ };
769
+ var lane_interactive_ask = { LANE_INTERACTIVE_ASK_REASON, ROW: ROW5, is_interactive_ask };
770
+
771
+ // scripts/rules/piped-verification.ts
772
+ var VERIFICATION_COMMANDS = /* @__PURE__ */ new Set([
773
+ "check",
774
+ "cspell",
775
+ "cspell:dot",
776
+ "eval",
777
+ "gate",
778
+ "lint",
779
+ "lint:eslint",
780
+ "lint:prettier",
781
+ "lint:related",
782
+ "overrides",
783
+ "ranges",
784
+ "test",
785
+ "test:e2e",
786
+ "test:related",
787
+ "test:unit"
788
+ ]);
789
+ function is_verification_command(segment) {
790
+ return shell_segments.is_josh_command(segment, VERIFICATION_COMMANDS);
791
+ }
792
+ function is_masked_verification(command) {
793
+ return time_shell.discarded_commands(command).some((segment) => is_verification_command(segment));
794
+ }
795
+ var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed, and the verdict is discarded before anything reads it. Run the check without the pipe \u2014 josh prints its verdict line last, so the harness output cap keeps it even when the middle is elided. Where the output genuinely has to be narrowed, redirect it to a file and read ranges from that file, or prefix `set -o pipefail` so the pipeline carries the check's status. Read the printed verdict either way, never the exit code alone. Read-only listings are untouched \u2014 this fires only on a command whose result means pass or fail. The rule is in `prompts/collaboration-workflow/output-bounds.md`. Reissue this call with no pipe \u2014 it fires once per run and cannot repeat on the call in hand.";
796
+ function command_pieces(command) {
797
+ return shell_segments.segments_of(time_shell.unquoted(command)).flatMap((segment) => segment.split("|")).map((piece) => piece.trim());
798
+ }
799
+ function runs_verification(command) {
800
+ return command_pieces(command).some((piece) => is_verification_command(piece));
801
+ }
802
+ function keeps_verdict_intact(command) {
803
+ return runs_verification(command) && !is_masked_verification(command);
804
+ }
805
+ var piped_verification = {
806
+ PIPED_VERIFICATION_REASON,
807
+ VERIFICATION_COMMANDS,
808
+ is_masked_verification,
809
+ keeps_verdict_intact,
810
+ runs_verification
811
+ };
812
+
813
+ // scripts/rules/pre-gate-cut.ts
814
+ var GATE_COMMANDS = /* @__PURE__ */ new Set(["gate"]);
815
+ var CUT_COMMANDS = /* @__PURE__ */ new Set(["run:cut"]);
816
+ var CUT_MODE_FLAG = /(?:^|\s)--(?:resume|end|json)(?:[=\s]|$)/u;
817
+ var HOLD_COMMANDS = /* @__PURE__ */ new Set(["run:hold"]);
818
+ var HOLD_MODE_FLAG = /(?:^|\s)--release(?:[=\s]|$)/u;
819
+ function invokes_josh(command, names, mode_flag) {
820
+ return shell_segments.segments_of(command).some(
821
+ (segment) => shell_segments.is_josh_command(segment, names) && mode_flag?.test(segment) !== true
822
+ );
823
+ }
824
+ function runs_the_gate(command) {
825
+ return invokes_josh(command, GATE_COMMANDS);
826
+ }
827
+ function takes_the_cut(command) {
828
+ return invokes_josh(command, CUT_COMMANDS, CUT_MODE_FLAG);
829
+ }
830
+ function claims_the_hold(command) {
831
+ return invokes_josh(command, HOLD_COMMANDS, HOLD_MODE_FLAG);
832
+ }
833
+ function asks_about_the_cut(command) {
834
+ return invokes_josh(command, CUT_COMMANDS);
835
+ }
836
+ function current_state() {
837
+ return {
838
+ directory: process.cwd(),
839
+ carried: run_cut.carried_cut_sync,
840
+ marked_issue: lane_child_marker.marked_issue()
841
+ };
842
+ }
843
+ function uncut_lane_issue(state) {
844
+ const issue = lane_paths.lane_issue_of(state.directory);
845
+ if (issue === void 0) return void 0;
846
+ if (state.marked_issue !== issue) return void 0;
847
+ return state.carried()?.issue === issue ? void 0 : issue;
848
+ }
849
+ function is_uncut_gate(command, state = current_state()) {
850
+ if (!runs_the_gate(command)) return false;
851
+ return uncut_lane_issue(state) !== void 0;
852
+ }
853
+ var PRE_GATE_CUT_REASON = "\u26D4 pre-gate cut: this checkout is a lane dispatched for this issue and the gate is the boundary to cut at, so take the cut before running it. `pnpm josh run:cut <N>` ends this process and relaunches a fresh one that resumes from the gate, dropping the thinking built up while implementing rather than carrying it on every later request \u2014 joshuafolkken/kit#1839 measured 176K of 204K output riding across that boundary, and joshuafolkken/kit#1864 measured the step itself firing 0 times in 6 lane children while it was carried as prose. Issue `pnpm josh run:cut <N>` now, and read the verdict: on `cut`, **end the turn immediately** \u2014 the fresh process owns the run from there and must not be waited for; on `not-a-lane`, `unready`, `busy`, `failed` or `unknown`, this process carries the run on and the gate is simply the next call. Never relaunch a second process after `busy`. This fired because the dispatch mark names this lane; a person working here carries no mark and sees no refusal, so there is no human-or-child judgement left to make. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md`. Reissue the gate once the cut has answered \u2014 this fires once per run, so it cannot repeat on the call in hand.";
854
+ var pre_gate_cut = {
855
+ PRE_GATE_CUT_REASON,
856
+ asks_about_the_cut,
857
+ claims_the_hold,
858
+ is_uncut_gate,
859
+ runs_the_gate,
860
+ takes_the_cut,
861
+ uncut_lane_issue
862
+ };
863
+
864
+ // scripts/rules/prior-comment-read.ts
865
+ var ISSUE_PATH_NUMBER = /issues\/(\d+)/gu;
866
+ var ISSUE_VIEW_NUMBER = /\bissue\s+view\s+(?:-{1,2}\S+\s+)*(\d+)/u;
867
+ var ISSUE_READ_ARGUMENTS = /\bissue:read\b([\s\d]*)/u;
868
+ var A_NUMBER = /^\d+$/u;
869
+ var COMMENTS_ENDPOINT = /issues\/\d+\/comments\b/u;
870
+ var VIEW_WITH_COMMENTS = /\bissue\s+view\b[^\n]*--comments\b/u;
871
+ var ISSUE_READ_COMMAND = /\bissue:read\b/u;
872
+ function add_issue_read_numbers(command, numbers) {
873
+ const match = ISSUE_READ_ARGUMENTS.exec(command);
874
+ if (match === null) return;
875
+ const tokens = (match[1] ?? "").split(/\s+/u);
876
+ for (const token of tokens) {
877
+ if (A_NUMBER.test(token)) numbers.add(Number(token));
878
+ }
879
+ }
880
+ function issue_numbers_of(command) {
881
+ const numbers = /* @__PURE__ */ new Set();
882
+ for (const match of command.matchAll(ISSUE_PATH_NUMBER)) numbers.add(Number(match[1]));
883
+ const view = ISSUE_VIEW_NUMBER.exec(command);
884
+ if (view !== null) numbers.add(Number(view[1]));
885
+ add_issue_read_numbers(command, numbers);
886
+ return numbers;
887
+ }
888
+ function fetches_comments(command) {
889
+ return COMMENTS_ENDPOINT.test(command) || VIEW_WITH_COMMENTS.test(command) || ISSUE_READ_COMMAND.test(command);
890
+ }
891
+ function reads_target_comments(command, target) {
892
+ if (!fetches_comments(command)) return false;
893
+ for (const number of issue_numbers_of(command)) {
894
+ if (target.has(number)) return true;
895
+ }
896
+ return false;
897
+ }
898
+ function already_read_comments_for(tail, command) {
899
+ const target = issue_numbers_of(command);
900
+ if (target.size === 0) return false;
901
+ return tail_commands.prior_bash_commands(tail).some((prior) => reads_target_comments(prior, target));
902
+ }
903
+ function already_read_for_call(tail, call) {
904
+ if (call.name !== cost_blocks.BASH_TOOL) return false;
905
+ return already_read_comments_for(tail, time_shell.bash_command(call.input));
906
+ }
907
+ var prior_comment_read = {
908
+ already_read_comments_for,
909
+ already_read_for_call,
910
+ fetches_comments,
911
+ issue_numbers_of
912
+ };
913
+
914
+ // scripts/rules/run-tail.ts
915
+ var SEGMENT_PREFIX = String.raw`(?:\(\s*)?(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:npx\s+|pnpm\s+(?:exec\s+|run\s+)?)?`;
916
+ var WORD_END = String.raw`(?=\s|$|\))`;
917
+ var PUSH_STEP_SEGMENT = new RegExp(String.raw`^${SEGMENT_PREFIX}josh\s+(?:git|g)${WORD_END}`, "u");
918
+ var CONFIRMED_FLAG = new RegExp(String.raw`(?:^|\s)(?:-y|--yes)${WORD_END}`, "u");
919
+ var SKIPS_THE_PUSH = new RegExp(String.raw`(?:^|\s)--skip-push${WORD_END}`, "u");
920
+ var BACKGROUND_KEY = "run_in_background";
921
+ var QUOTED_SPAN = /"[^"]*"|'[^']*'/gu;
922
+ function flags_of(segment) {
923
+ return segment.replaceAll(QUOTED_SPAN, " ");
924
+ }
925
+ function is_push_step_segment(segment) {
926
+ if (!PUSH_STEP_SEGMENT.test(segment)) return false;
927
+ const flags = flags_of(segment);
928
+ if (SKIPS_THE_PUSH.test(flags)) return false;
929
+ return CONFIRMED_FLAG.test(flags);
930
+ }
931
+ function is_push_step(command) {
932
+ return shell_segments.segments_of(command).some((segment) => is_push_step_segment(segment));
933
+ }
934
+ function is_backgrounded(input) {
935
+ if (!json_value.is_record(input)) return false;
936
+ return input[BACKGROUND_KEY] === true;
937
+ }
938
+ function is_push_step_call(call) {
939
+ if (call.name !== cost_blocks.BASH_TOOL) return false;
940
+ return is_push_step(time_shell.bash_command(call.input));
941
+ }
942
+ function is_backgrounded_push_step(call) {
943
+ if (!is_backgrounded(call.input)) return false;
944
+ return is_push_step_call(call);
945
+ }
946
+ function is_foreground_push_step(call) {
947
+ if (is_backgrounded(call.input)) return false;
948
+ return is_push_step_call(call);
949
+ }
950
+ function decide3() {
951
+ return true;
952
+ }
953
+ var RUN_TAIL_REASON = '\u26D4 run tail: this issues the commit-push-PR step in the foreground, where the harness decides when to stop waiting. Reissue it with `run_in_background` set. In `fullrun #1501` this call was given a 900-second timeout, the harness detached it at its own 600-second cap, and nothing read the output for a further 6m28s \u2014 45m03s of wall clock on about 17 minutes of work (joshuafolkken/kit#1510). **Never give a foreground call a timeout above the harness cap**: the cap decides, not the number. A backgrounded call re-invokes you when it exits, so the completion notification is what resumes the run. **When it arrives, the turn that reads it goes straight through any branch-2 filing and `pnpm josh epic:bundle` to `pnpm josh followup` \u2014 the turn never ends at the push.** CI went green 6m06s before the merge started in that run, and it started only because the person asked; joshuafolkken/kit#1333 had already settled that the merge is issued in the turn the review closes. While the push runs, do the work that writes nothing \u2014 drafting the completion body to a file, deciding the branch-2 disposition. `pnpm josh followup` itself stays in the **foreground** \u2014 nearly every step after it reads its result. But a tail does follow the merge, measured at 3.0 min and 5.9% of a run (joshuafolkken/kit#1462), so empty it beforehand: the steps that read the merge result stay after `followup`, and the rest are composed in the turn that issues it, bar the one exception background-commands.md names. The procedure is `.claude/skills/workflow-commands/background-commands.md`, "A command that can take minutes is issued in the background". **This rule fires on every foreground push, not once per run**, so reissuing the same call in the foreground will be refused again.';
954
+ var run_tail = {
955
+ RUN_TAIL_REASON,
956
+ decide: decide3,
957
+ is_backgrounded_push_step,
958
+ is_foreground_push_step,
959
+ is_push_step,
960
+ is_push_step_call
961
+ };
962
+
963
+ // scripts/rules/shell-body-trigger.ts
964
+ var FIELD_FLAGS = "(?:-f|-F|--field|--raw-field)";
965
+ var MESSAGE_FLAGS = "(?:--body|--notify-message)";
966
+ var FIELD_OPENING = String.raw`${FIELD_FLAGS}[\s=]*(?:'?body="|"body=)`;
967
+ var MESSAGE_OPENING = String.raw`${MESSAGE_FLAGS}[\s=]+"`;
968
+ var NESTED_SUBSTITUTION = String.raw`\$\([^()]*\)`;
969
+ var SUBSTITUTION = String.raw`\$\((?:[^()$]|\$(?!\()|${NESTED_SUBSTITUTION})*\)`;
970
+ var QUOTED_VALUE = String.raw`(?:[^"\\$]|\\.|\$(?!\()|${SUBSTITUTION})*`;
971
+ var INLINE_BODY_VALUE = new RegExp(
972
+ `(?:${FIELD_OPENING}|${MESSAGE_OPENING})(${QUOTED_VALUE})"`,
973
+ "gu"
974
+ );
975
+ var SHELL_EVALUATED = /[`$]/u;
976
+ var WHOLE_VALUE_SUBSTITUTION = new RegExp(`^${SUBSTITUTION}$`, "u");
977
+ var BACKTICK = "`";
978
+ var WHOLE_VALUE_FILE_REFERENCE = /^@\S+$/u;
979
+ var ESCAPED_PAIR = /\\./gu;
980
+ function is_whole_value_substitution(literal) {
981
+ return WHOLE_VALUE_SUBSTITUTION.test(literal) && !literal.includes(BACKTICK);
982
+ }
983
+ function is_body_already_in_a_file(literal) {
984
+ return WHOLE_VALUE_FILE_REFERENCE.test(literal) || is_whole_value_substitution(literal);
985
+ }
986
+ function is_evaluated_value(raw_value) {
987
+ const literal = raw_value.replaceAll(ESCAPED_PAIR, "");
988
+ if (is_body_already_in_a_file(literal)) return false;
989
+ return SHELL_EVALUATED.test(literal);
990
+ }
991
+ function is_shell_evaluated_body(command) {
992
+ for (const match of command.matchAll(INLINE_BODY_VALUE)) {
993
+ if (is_evaluated_value(match[1] ?? "")) return true;
994
+ }
995
+ return false;
996
+ }
997
+ var FILE_FLAG = /(?:--body-file|--notify-message-file)(?:[\s=]|$)/u;
998
+ var FIELD_FILE_REFERENCE = new RegExp(String.raw`${FIELD_FLAGS}[\s=]*body=@\S`, "u");
999
+ var ANSI_C_BODY = /(?:(?:--body|--notify-message)[\s=]+|body=)\$'/u;
1000
+ var DOUBLE_QUOTED_SPAN = /"[^"]*"/gu;
1001
+ var BODY_FLAG = new RegExp(
1002
+ String.raw`${FIELD_FLAGS}[\s=]*'?"?body=|${MESSAGE_FLAGS}[\s=]|--body-file[\s=]|--notify-message-file[\s=]`,
1003
+ "u"
1004
+ );
1005
+ var QUOTED_SPAN2 = /"[^"]*"|'[^']*'/gu;
1006
+ function inline_body_literals(command) {
1007
+ return Array.from(
1008
+ command.matchAll(INLINE_BODY_VALUE),
1009
+ (match) => (match[1] ?? "").replaceAll(ESCAPED_PAIR, "")
1010
+ );
1011
+ }
1012
+ function is_safe_body_form(command) {
1013
+ if (ANSI_C_BODY.test(command.replaceAll(DOUBLE_QUOTED_SPAN, " "))) return true;
1014
+ const flags = command.replaceAll(QUOTED_SPAN2, " ");
1015
+ if (FILE_FLAG.test(flags) || FIELD_FILE_REFERENCE.test(flags)) return true;
1016
+ return inline_body_literals(command).some((literal) => is_body_already_in_a_file(literal));
1017
+ }
1018
+ function keeps_body_safe(command) {
1019
+ return is_safe_body_form(command) && !is_shell_evaluated_body(command);
1020
+ }
1021
+ function carries_a_body(command) {
1022
+ if (BODY_FLAG.test(command.replaceAll(QUOTED_SPAN2, " "))) return true;
1023
+ return inline_body_literals(command).length > 0;
1024
+ }
1025
+ var shell_body_trigger = {
1026
+ carries_a_body,
1027
+ is_safe_body_form,
1028
+ is_shell_evaluated_body,
1029
+ keeps_body_safe
1030
+ };
1031
+
1032
+ // scripts/test/test-declared-changed.ts
1033
+ import { execFileSync } from "node:child_process";
1034
+
1035
+ // scripts/test/test-declared-logic.ts
1036
+ var TEST_SUFFIXES = [".e2e.ts", ".test.ts"];
1037
+ var EXEMPT_PATHS = [".editorconfig"];
1038
+ var EXEMPT_PREFIXES = [".idea/", ".vscode/", "prompts/"];
1039
+ var EXEMPT_SUFFIXES = [".md"];
1040
+ function normalize(paths) {
1041
+ return paths.map((path3) => path3.trim()).filter((path3) => path3 !== "");
1042
+ }
1043
+ function is_test_file(path3) {
1044
+ return TEST_SUFFIXES.some((suffix) => path3.endsWith(suffix));
1045
+ }
1046
+ function is_exempt(path3) {
1047
+ if (EXEMPT_PATHS.includes(path3)) return true;
1048
+ return EXEMPT_SUFFIXES.some((suffix) => path3.endsWith(suffix)) || EXEMPT_PREFIXES.some((prefix) => path3.startsWith(prefix));
1049
+ }
1050
+ function is_runtime(path3) {
1051
+ return !is_test_file(path3) && !is_exempt(path3);
1052
+ }
1053
+ function verdict_for(paths) {
1054
+ const changed = normalize(paths);
1055
+ if (changed.some((path3) => is_test_file(path3))) return "satisfied";
1056
+ if (changed.some((path3) => is_runtime(path3))) return "required";
1057
+ return "exempt";
1058
+ }
1059
+ function runtime_files(paths) {
1060
+ return normalize(paths).filter((path3) => is_runtime(path3));
1061
+ }
1062
+ function exempt_files(paths) {
1063
+ return normalize(paths).filter((path3) => is_exempt(path3));
1064
+ }
1065
+ var test_declared_logic = {
1066
+ EXEMPT_PATHS,
1067
+ EXEMPT_PREFIXES,
1068
+ EXEMPT_SUFFIXES,
1069
+ TEST_SUFFIXES,
1070
+ exempt_files,
1071
+ is_exempt,
1072
+ is_runtime,
1073
+ is_test_file,
1074
+ runtime_files,
1075
+ verdict_for
1076
+ };
1077
+
1078
+ // scripts/test/test-declared-changed.ts
1079
+ var RENAME_ARROW = " -> ";
1080
+ var STATUS_PREFIX_LENGTH = 3;
1081
+ function path_of(line) {
1082
+ const body = line.slice(STATUS_PREFIX_LENGTH);
1083
+ const arrow = body.indexOf(RENAME_ARROW);
1084
+ return arrow === -1 ? body : body.slice(arrow + RENAME_ARROW.length);
1085
+ }
1086
+ function read_changed_paths_sync() {
1087
+ try {
1088
+ const output = execFileSync("git", ["status", "--porcelain"], {
1089
+ encoding: "utf8",
1090
+ stdio: ["ignore", "pipe", "ignore"]
1091
+ });
1092
+ return output.split("\n").filter((line) => line.length > STATUS_PREFIX_LENGTH).map((line) => path_of(line));
1093
+ } catch {
1094
+ return [];
1095
+ }
1096
+ }
1097
+ var injected = {};
1098
+ function source_paths() {
1099
+ return injected.paths ?? read_changed_paths_sync();
1100
+ }
1101
+ function current_verdict(paths = source_paths()) {
1102
+ return test_declared_logic.verdict_for(paths);
1103
+ }
1104
+ function restore_injection(previous) {
1105
+ if (previous === void 0) {
1106
+ delete injected.paths;
1107
+ return;
1108
+ }
1109
+ injected.paths = previous;
1110
+ }
1111
+ function with_paths(paths, body) {
1112
+ const previous = injected.paths;
1113
+ injected.paths = paths;
1114
+ try {
1115
+ return body();
1116
+ } finally {
1117
+ restore_injection(previous);
1118
+ }
1119
+ }
1120
+ var test_declared_changed = { current_verdict, path_of, read_changed_paths_sync, with_paths };
1121
+
1122
+ // scripts/rules/test-declared-commit.ts
1123
+ function is_untested_commit(call) {
1124
+ if (!run_tail.is_push_step_call(call)) return false;
1125
+ return test_declared_changed.current_verdict() === "required";
1126
+ }
1127
+ var REASON = '\u26D4 test declared: this commits a runtime code change with no test beside it \u2014 `pnpm josh test:declared` reads the working tree as `required` (a changed file that is neither a test \u2014 `*.test.ts` / `*.e2e.ts` \u2014 nor a mechanically-exempt non-runtime path). `CLAUDE.md` \u2192 Code Change Rules requires a test for ALL code changes: a bug fix gets a regression test, a refactor gets tests pinning behavior first, logic gets a unit test, an observable UI/timing change gets an E2E. Add the declared test and reissue this commit. **If the change genuinely touches no executable runtime path** it is the pre-approved non-runtime exception \u2014 declare it in your Step 0 work summary with the reason it is exempt (non-executable config, a cosmetic asset swap) and reissue; the exception is a presentation, not a stop. Run `pnpm josh test:declared` to see the files it names. The procedure is `prompts/collaboration-workflow/rule-delivery.md` \u2192 "\u914D\u9001\u3055\u308C\u3066\u3044\u308B\u898F\u5247". This fires once per run, so reissuing will not repeat on the call in hand.';
1128
+ var ROW6 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
1129
+ var test_declared_commit = { REASON, ROW: ROW6, is_untested_commit };
1130
+
1131
+ // scripts/discovery/repo-discovery.ts
1132
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
1133
+ import path2 from "node:path";
1134
+
1135
+ // scripts/discovery/repo-origin.ts
1136
+ var GITHUB_HOST = "github.com";
1137
+ var SSH_ALIAS_PATTERN = /^github(?:-\w+)*$/u;
1138
+ var GIT_SUFFIX = ".git";
1139
+ var PATH_SEPARATOR = "/";
1140
+ var USER_SEPARATOR = "@";
1141
+ var HOST_SEPARATOR = ":";
1142
+ var OWNER_INDEX = 0;
1143
+ var REPO_INDEX = 1;
1144
+ var REPO_PATH_SEGMENTS = 2;
1145
+ var NOT_FOUND = -1;
1146
+ var SECTION_PREFIX = "[";
1147
+ var ORIGIN_SECTION = /^\[remote\s+"origin"\]$/u;
1148
+ var URL_KEY = "url";
1149
+ function is_github_hostname(host) {
1150
+ return host.toLowerCase() === GITHUB_HOST;
1151
+ }
1152
+ function is_github_ssh_host(host) {
1153
+ const normalized = host.toLowerCase();
1154
+ return is_github_hostname(normalized) || SSH_ALIAS_PATTERN.test(normalized);
1155
+ }
1156
+ function strip_git_suffix(name) {
1157
+ return name.endsWith(GIT_SUFFIX) ? name.slice(0, -GIT_SUFFIX.length) : name;
1158
+ }
1159
+ function to_identity(repository_path) {
1160
+ const segments = repository_path.split(PATH_SEPARATOR).filter((segment) => segment !== "");
1161
+ if (segments.length !== REPO_PATH_SEGMENTS) return void 0;
1162
+ const owner = segments[OWNER_INDEX] ?? "";
1163
+ const repo = strip_git_suffix(segments[REPO_INDEX] ?? "");
1164
+ return repo === "" ? void 0 : { owner, repo };
1165
+ }
1166
+ function parse_scp_like(url) {
1167
+ const user_end = url.indexOf(USER_SEPARATOR);
1168
+ const authority = user_end === NOT_FOUND ? url : url.slice(user_end + 1);
1169
+ const host_end = authority.indexOf(HOST_SEPARATOR);
1170
+ if (host_end === NOT_FOUND) return void 0;
1171
+ if (!is_github_ssh_host(authority.slice(0, host_end))) return void 0;
1172
+ return to_identity(authority.slice(host_end + 1));
1173
+ }
1174
+ function parse_url_like(url) {
1175
+ try {
1176
+ const parsed = new URL(url);
1177
+ return is_github_hostname(parsed.hostname) ? to_identity(parsed.pathname) : void 0;
1178
+ } catch {
1179
+ return void 0;
1180
+ }
1181
+ }
1182
+ function parse_origin_url(url) {
1183
+ const trimmed = url.trim();
1184
+ if (trimmed === "") return void 0;
1185
+ return parse_url_like(trimmed) ?? parse_scp_like(trimmed);
1186
+ }
1187
+ function is_section_header(line) {
1188
+ return line.startsWith(SECTION_PREFIX);
1189
+ }
1190
+ function origin_section_lines(lines) {
1191
+ const start = lines.findIndex((line) => ORIGIN_SECTION.test(line));
1192
+ if (start === NOT_FOUND) return [];
1193
+ const rest = lines.slice(start + 1);
1194
+ const end = rest.findIndex((line) => is_section_header(line));
1195
+ return end === NOT_FOUND ? rest : rest.slice(0, end);
1196
+ }
1197
+ function entry_value(line, key) {
1198
+ const separator = line.indexOf("=");
1199
+ if (separator === NOT_FOUND) return void 0;
1200
+ if (line.slice(0, separator).trim() !== key) return void 0;
1201
+ return line.slice(separator + 1).trim();
1202
+ }
1203
+ function parse_origin_from_config(content) {
1204
+ const lines = content.split("\n").map((line) => line.trim());
1205
+ return origin_section_lines(lines).map((line) => entry_value(line, URL_KEY)).find((url) => url !== void 0);
1206
+ }
1207
+ function format_identity(identity) {
1208
+ return `${identity.owner}${PATH_SEPARATOR}${identity.repo}`.toLowerCase();
1209
+ }
1210
+ var repo_origin = {
1211
+ GITHUB_HOST,
1212
+ is_github_hostname,
1213
+ is_github_ssh_host,
1214
+ parse_origin_from_config,
1215
+ parse_origin_url,
1216
+ format_identity
1217
+ };
1218
+
1219
+ // scripts/discovery/repo-map-logic.ts
1220
+ var OVERRIDE_ENTRY_SEPARATOR = ",";
1221
+ var OVERRIDE_PAIR_SEPARATOR = "=";
1222
+ var OVERRIDE_PAIR_PARTS = 2;
1223
+ var KEY_INDEX = 0;
1224
+ var PATH_INDEX = 1;
1225
+ function is_same_owner(identity, current_owner2) {
1226
+ return identity.owner.toLowerCase() === current_owner2.toLowerCase();
1227
+ }
1228
+ function add_entry(target, origin_url, repository_path, current_owner2) {
1229
+ if (origin_url === void 0) return;
1230
+ const identity = repo_origin.parse_origin_url(origin_url);
1231
+ if (identity === void 0 || !is_same_owner(identity, current_owner2)) return;
1232
+ target.set(repo_origin.format_identity(identity), repository_path);
1233
+ }
1234
+ function parse_override_entry(entry) {
1235
+ const parts = entry.split(OVERRIDE_PAIR_SEPARATOR).map((part) => part.trim());
1236
+ if (parts.length !== OVERRIDE_PAIR_PARTS) return void 0;
1237
+ const key = parts[KEY_INDEX] ?? "";
1238
+ const repository_path = parts[PATH_INDEX] ?? "";
1239
+ if (repository_path === "") return void 0;
1240
+ return { path: repository_path, origin_url: `https://${repo_origin.GITHUB_HOST}/${key}` };
1241
+ }
1242
+ function parse_overrides(raw) {
1243
+ if (raw === void 0) return [];
1244
+ return raw.split(OVERRIDE_ENTRY_SEPARATOR).map((entry) => parse_override_entry(entry)).filter((entry) => entry !== void 0);
1245
+ }
1246
+ function build_repository_map(discovered, current_owner2, override_value) {
1247
+ const result = /* @__PURE__ */ new Map();
1248
+ for (const entry of discovered) add_entry(result, entry.origin_url, entry.path, current_owner2);
1249
+ for (const entry of parse_overrides(override_value)) {
1250
+ add_entry(result, entry.origin_url, entry.path, current_owner2);
1251
+ }
1252
+ return result;
1253
+ }
1254
+ var repo_map_logic = {
1255
+ is_same_owner,
1256
+ parse_overrides,
1257
+ build_repository_map
1258
+ };
1259
+
1260
+ // scripts/discovery/repo-discovery.ts
1261
+ var GIT_DIRECTORY = ".git";
1262
+ var GIT_CONFIG = "config";
1263
+ var GITDIR_PREFIX = "gitdir:";
1264
+ var COMMON_DIRECTORY_FILE = "commondir";
1265
+ var OVERRIDE_ENV_KEY = "JOSH_REPO_PATHS";
1266
+ function resolve_common_directory(git_directory) {
1267
+ const pointer = path2.join(git_directory, COMMON_DIRECTORY_FILE);
1268
+ if (!existsSync2(pointer)) return git_directory;
1269
+ try {
1270
+ return path2.resolve(git_directory, readFileSync2(pointer, "utf8").trim());
1271
+ } catch {
1272
+ return git_directory;
1273
+ }
1274
+ }
1275
+ function follow_git_file(repository_path, git_file) {
1276
+ const pointer = readFileSync2(git_file, "utf8").trim();
1277
+ if (!pointer.startsWith(GITDIR_PREFIX)) return void 0;
1278
+ return path2.resolve(repository_path, pointer.slice(GITDIR_PREFIX.length).trim());
1279
+ }
1280
+ function resolve_git_directory(repository_path) {
1281
+ const candidate = path2.join(repository_path, GIT_DIRECTORY);
1282
+ if (!existsSync2(candidate)) return void 0;
1283
+ try {
1284
+ if (statSync(candidate).isDirectory()) return candidate;
1285
+ const linked = follow_git_file(repository_path, candidate);
1286
+ return linked === void 0 ? void 0 : resolve_common_directory(linked);
1287
+ } catch {
1288
+ return void 0;
1289
+ }
1290
+ }
1291
+ function read_origin_url(repository_path) {
1292
+ const git_directory = resolve_git_directory(repository_path);
1293
+ if (git_directory === void 0) return void 0;
1294
+ try {
1295
+ return repo_origin.parse_origin_from_config(
1296
+ readFileSync2(path2.join(git_directory, GIT_CONFIG), "utf8")
1297
+ );
1298
+ } catch {
1299
+ return void 0;
1300
+ }
1301
+ }
1302
+ function sibling_directories(parent) {
1303
+ try {
1304
+ return readdirSync(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path2.join(parent, entry.name)).toSorted((left, right) => left.localeCompare(right));
1305
+ } catch {
1306
+ return [];
1307
+ }
1308
+ }
1309
+ function scan_siblings(parent) {
1310
+ return sibling_directories(parent).map((repository_path) => ({
1311
+ path: repository_path,
1312
+ origin_url: read_origin_url(repository_path)
1313
+ }));
1314
+ }
1315
+ function resolve_current_owner(repository_path) {
1316
+ const origin_url = read_origin_url(repository_path);
1317
+ if (origin_url === void 0) return void 0;
1318
+ return repo_origin.parse_origin_url(origin_url)?.owner;
1319
+ }
1320
+ function main_worktree(repository_path) {
1321
+ const git_directory = resolve_git_directory(repository_path);
1322
+ if (git_directory === void 0) return repository_path;
1323
+ if (path2.basename(git_directory) !== GIT_DIRECTORY) return repository_path;
1324
+ return path2.dirname(git_directory);
1325
+ }
1326
+ function discover_repositories(repository_path, environment = process.env) {
1327
+ const main = main_worktree(repository_path);
1328
+ const current_owner2 = resolve_current_owner(main);
1329
+ if (current_owner2 === void 0) return /* @__PURE__ */ new Map();
1330
+ return repo_map_logic.build_repository_map(
1331
+ scan_siblings(path2.dirname(main)),
1332
+ current_owner2,
1333
+ environment[OVERRIDE_ENV_KEY]
1334
+ );
1335
+ }
1336
+ var repo_discovery = {
1337
+ OVERRIDE_ENV_KEY,
1338
+ main_worktree,
1339
+ read_origin_url,
1340
+ resolve_current_owner,
1341
+ scan_siblings,
1342
+ discover_repositories
1343
+ };
1344
+
1345
+ // scripts/discovery/repo-party.ts
1346
+ var FIRST_PARTY = "first-party";
1347
+ var THIRD_PARTY = "third-party";
1348
+ var UNKNOWN = "unknown";
1349
+ function classify(session_owner, target) {
1350
+ if (session_owner === void 0 || target === void 0) return UNKNOWN;
1351
+ return session_owner.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
1352
+ }
1353
+ function target_owner(owner_repo) {
1354
+ return repo_origin.parse_origin_url(`https://${repo_origin.GITHUB_HOST}/${owner_repo}`)?.owner;
1355
+ }
1356
+ function current_owner(repository_path = process.cwd()) {
1357
+ return repo_discovery.resolve_current_owner(repository_path);
1358
+ }
1359
+ var repo_party = { FIRST_PARTY, THIRD_PARTY, UNKNOWN, classify, current_owner, target_owner };
1360
+
1361
+ // scripts/rules/third-party-write.ts
1362
+ function is_third_party_write_segment(segment, session_owner) {
1363
+ if (!gh_api.is_gh_api(segment) || !gh_api.is_write(segment)) return false;
1364
+ const target = gh_api.repo_target(segment);
1365
+ if (target === void 0) return false;
1366
+ return repo_party.classify(session_owner, target.owner) === repo_party.THIRD_PARTY;
1367
+ }
1368
+ function writes_third_party(command, resolve_owner = repo_party.current_owner) {
1369
+ const targets = shell_segments.segments_of(command).filter((segment) => gh_api.is_gh_api(segment) && gh_api.is_write(segment));
1370
+ if (targets.length === 0) return false;
1371
+ const session_owner = resolve_owner();
1372
+ return targets.some((segment) => is_third_party_write_segment(segment, session_owner));
1373
+ }
1374
+ var THIRD_PARTY_WRITE_REASON = '\u26D4 third-party write: this `gh api` call writes to a repository whose owner is not this session \u2014 a tracker we do not own is Tier C, and every write there (Issue, comment, PR, Discussion, review) needs explicit current-turn user instruction; typing the target, or holding a correct diagnosis, is not that instruction (`CLAUDE.md` \u2192 "Third-party repositories are Tier C", `prompts/collaboration-workflow/upstream-interrupt.md`). Confirm the party with `pnpm josh repo:party <owner/repo>` \u2014 owner equality, computed not judged. A read (`-X GET`, or no field flag) passes untouched; only a write (`-f`/`-F`/`--field`/`--raw-field`/`--input`, or `-X POST|PATCH|PUT|DELETE`) is refused. Record the finding on our own Issue and draft the artifact for a person to post \u2014 do not publish it yourself. **This rule fires on every occurrence, not once per run.**';
1375
+ var ROW7 = {
1376
+ id: "third-party-write",
1377
+ is_trigger: bash_triggers.on_bash_command((command) => writes_third_party(command)),
1378
+ reason: THIRD_PARTY_WRITE_REASON,
1379
+ decide: () => true
1380
+ };
1381
+ var third_party_write = {
1382
+ ROW: ROW7,
1383
+ THIRD_PARTY_WRITE_REASON,
1384
+ is_third_party_write_segment,
1385
+ writes_third_party
1386
+ };
1387
+
1388
+ // scripts/rules/worktree-guard.ts
1389
+ var CHECKOUT_SUBCOMMAND = "checkout";
1390
+ var RESTORE_SUBCOMMAND = "restore";
1391
+ var STASH_SUBCOMMAND = "stash";
1392
+ var PATHSPEC_SEPARATOR = "--";
1393
+ function is_worktree_checkout(args) {
1394
+ return args.includes(PATHSPEC_SEPARATOR);
1395
+ }
1396
+ var STAGED_LONG = "--staged";
1397
+ var STAGED_LETTER = "S";
1398
+ var WORKTREE_LONG = "--worktree";
1399
+ var WORKTREE_LETTER = "W";
1400
+ function touches_worktree(args) {
1401
+ const is_staged = args.some(
1402
+ (argument) => argument === STAGED_LONG || git_argv.short_cluster_has(argument, STAGED_LETTER)
1403
+ );
1404
+ const is_worktree = args.some(
1405
+ (argument) => argument === WORKTREE_LONG || git_argv.short_cluster_has(argument, WORKTREE_LETTER)
1406
+ );
1407
+ return !is_staged || is_worktree;
1408
+ }
1409
+ var PUSH_STASH = "push";
1410
+ var MESSAGE_LONG = "--message";
1411
+ var MESSAGE_SHORT_LETTER = "m";
1412
+ var READ_ONLY_STASH = /* @__PURE__ */ new Set(["list", "show"]);
1413
+ function has_message(args) {
1414
+ return args.some(
1415
+ (argument) => argument === MESSAGE_LONG || argument.startsWith(`${MESSAGE_LONG}=`) || git_argv.short_cluster_has(argument, MESSAGE_SHORT_LETTER)
1416
+ );
1417
+ }
1418
+ function is_unauthorized_stash(args) {
1419
+ const [stash_subcommand, ...rest] = args;
1420
+ if (stash_subcommand === void 0) return true;
1421
+ if (READ_ONLY_STASH.has(stash_subcommand)) return false;
1422
+ if (stash_subcommand === PUSH_STASH) return !has_message(rest);
1423
+ return true;
1424
+ }
1425
+ function is_unauthorized_segment(segment) {
1426
+ const call = git_argv.parse(segment);
1427
+ if (call === void 0) return false;
1428
+ if (call.subcommand === CHECKOUT_SUBCOMMAND) return is_worktree_checkout(call.args);
1429
+ if (call.subcommand === RESTORE_SUBCOMMAND) return touches_worktree(call.args);
1430
+ return call.subcommand === STASH_SUBCOMMAND && is_unauthorized_stash(call.args);
1431
+ }
1432
+ function is_unauthorized_worktree_change(command) {
1433
+ return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
1434
+ }
1435
+ var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout -- <path>`, `git restore <path>` and an unauthorized `git stash` mutate the working tree or the repository-wide stash every work tree shares, and none is on the `.claude/settings.json` deny list (`operating-rules.md`). Do not run them on your own judgement. A commit goes through `pnpm josh git`; a stash pop goes through `pnpm josh stash:pop "<message>"`, never a positional `git stash pop` a shared stack lets another lane divert. A stash push is authorized only inside a documented flow and only with a findable message \u2014 `git stash push -u -m "<message>"` \u2014 which this row allows; a bare `git stash`, a message-less push, or `pop` / `apply` / `drop` is refused. **This rule fires on every occurrence, not once per run.**';
1436
+ var ROW8 = {
1437
+ id: "worktree-mutation",
1438
+ is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
1439
+ reason: WORKTREE_MUTATION_REASON,
1440
+ decide: () => true
1441
+ };
1442
+ var worktree_guard = {
1443
+ ROW: ROW8,
1444
+ WORKTREE_MUTATION_REASON,
1445
+ is_unauthorized_stash,
1446
+ is_unauthorized_worktree_change,
1447
+ is_worktree_checkout,
1448
+ touches_worktree
1449
+ };
1450
+
1451
+ // scripts/rules/delivered-rules.ts
1452
+ var SWITCH_ENV_KEY = "JOSH_RULE_GUARD";
1453
+ var STAMP_PREFIX = "josh-rule-guard-";
1454
+ var { is_issue_filing: is_issue_filing2, on_bash_command: on_bash_command2 } = bash_triggers;
1455
+ var WIP_CAP_REASON = "\u26D4 backlog WIP cap: count the target repository's open Issues before filing. With more than 30 open, close one first; nothing honestly closable means do not file. Two filings are exempt and proceed while stating the overage \u2014 one the run is blocked by, and an interrupt, decided by three tests rather than judgement: a verification answers wrongly, a documented workflow cannot complete, or data is lost or written outside the repository. Meeting none of the three, the finding is discretionary and waits. The count command and both procedures are in `prompts/collaboration-workflow/wip-cap.md`. Reissue this call once you have counted \u2014 it fires once per run and cannot repeat on the call in hand.";
1456
+ var ISSUE_VIEW_COMMAND = new RegExp(String.raw`^gh\s+${gh_api.GH_FLAGS}issue\s+view\s`, "u");
1457
+ var ISSUE_BODY_PATH = /repos\/[^\s'"]*\/issues\/\d+(?=$|["'\s])/u;
1458
+ var FETCHES_COMMENTS = /--comments\b|--json\s[\w,]*\bcomments\b|\/comments\b/u;
1459
+ var ISSUES_PATH = /repos\/[^\s'"]*\/issues\//u;
1460
+ var FIELD_PROJECTION = /(?:--jq|--json)[= ]\s*('[^']*'|"[^"]*"|\S+)/u;
1461
+ var NAMES_THE_BODY = /\bbody\b/u;
1462
+ function projects_away_body(segment) {
1463
+ const projection = FIELD_PROJECTION.exec(segment);
1464
+ if (projection === null) return false;
1465
+ return !NAMES_THE_BODY.test(projection[1] ?? "");
1466
+ }
1467
+ function is_body_read_segment(segment) {
1468
+ if (projects_away_body(segment)) return false;
1469
+ if (ISSUE_VIEW_COMMAND.test(segment)) return true;
1470
+ return gh_api.is_gh_api(segment) && ISSUE_BODY_PATH.test(segment) && gh_api.is_read(segment);
1471
+ }
1472
+ function fetches_issue_comments(segment) {
1473
+ if (!FETCHES_COMMENTS.test(segment)) return false;
1474
+ return ISSUE_VIEW_COMMAND.test(segment) || gh_api.is_gh_api(segment) && ISSUES_PATH.test(segment);
1475
+ }
1476
+ function is_body_only_issue_read(command) {
1477
+ const segments = shell_segments.segments_of(command);
1478
+ if (segments.some((segment) => fetches_issue_comments(segment))) return false;
1479
+ return segments.some((segment) => is_body_read_segment(segment));
1480
+ }
1481
+ var ISSUE_COMMENTS_REASON = "\u26D4 an Issue's comments are part of the Issue: read them before implementing, not only the body. A decision recorded after the body was written lives only in a comment \u2014 a corrected diagnosis (joshuafolkken/kit#1537), a changed default and an added acceptance criterion (joshuafolkken/kit#1520), a scope handed to another Issue (joshuafolkken/kit#1304) \u2014 and nothing in the body says it was superseded, so a body-only reader builds the wrong thing and sees no contradiction. Reissue this read with the comments included: `gh api repos/{owner}/{repo}/issues/<N>/comments --jq '.[] | {user: .user.login, created_at, body}'` beside the body read, or `gh issue view <N> --comments` where GraphQL is reachable. Then the later text is the agreement in force \u2014 a comment supersedes the body it contradicts \u2014 except for two answers that are not the run's to make: work a comment reassigns to another Issue is out of scope and is not implemented, and a comment saying the Issue no longer has a reason to exist stops the run with a `confirmation` Telegram. The procedure is `.claude/skills/workflow-commands/SKILL.md` \u2192 \"An Issue's comments are part of the Issue\". It fires once per run and cannot repeat on the call in hand.";
1482
+ var { carries_a_body: carries_a_body2, is_shell_evaluated_body: is_shell_evaluated_body2, keeps_body_safe: keeps_body_safe2 } = shell_body_trigger;
1483
+ var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a body inline in double quotes, and that body contains a backtick or a `$`. The shell evaluates both before the command runs, so the text is executed rather than merely mangled \u2014 joshuafolkken/kit#1198 recorded a PR comment whose own words ran as git commands and switched a lane's work tree onto main. Write the body to a file and pass it by path: `gh api repos/{owner}/{repo}/issues/<N>/comments --field body=@<path>` (a PR comment is an issue comment), `pnpm josh followup --notify-message-file <path>`, `pnpm josh notify --body-file <path>`, and `--body-file <path>` wherever a command offers it. `$'\u2026'` quoting is the other safe form and is unchanged. The rule and what the trigger cannot see are in `prompts/collaboration-workflow/shell-body.md`. Reissue this call once the body is in a file \u2014 it fires once per run and cannot repeat on the call in hand.";
1484
+ var ISSUE_LISTING = /^gh\s+(?:-{1,2}[\w-]+(?:[= ]\S+)?\s+)*issue\s+list\b/u;
1485
+ var ISSUES_QUERY = /repos\/[^\s'"]*\/issues\?[^\s'"]*state=open/u;
1486
+ var OPEN_STATE = /--state[= ]open|state=open/u;
1487
+ var LABEL_FILTER = /--label\b|[?&]labels=/u;
1488
+ function counts_open_issues(command) {
1489
+ return shell_segments.segments_of(command).some((segment) => {
1490
+ if (LABEL_FILTER.test(segment)) return false;
1491
+ return ISSUE_LISTING.test(segment) && OPEN_STATE.test(segment) || ISSUES_QUERY.test(segment);
1492
+ });
1493
+ }
1494
+ function reads_issue_comments(command) {
1495
+ return shell_segments.segments_of(command).some((segment) => fetches_issue_comments(segment));
1496
+ }
1497
+ var ASKS_ABOUT_THE_CUT = on_bash_command2(pre_gate_cut.asks_about_the_cut);
1498
+ var CLAIMS_THE_HOLD = on_bash_command2(pre_gate_cut.claims_the_hold);
1499
+ function reaches_the_pre_gate_boundary(call, _turn, run) {
1500
+ if (!ASKS_ABOUT_THE_CUT(call)) return false;
1501
+ return run.some((issued) => CLAIMS_THE_HOLD(issued));
1502
+ }
1503
+ var DELIVERED_RULES = [
1504
+ // **Listed first, ahead of the filing trigger it overlaps** (joshuafolkken/kit#2122). A `gh api`
1505
+ // that files an Issue into a repository we do not own trips both this row and `wip-cap` /
1506
+ // `issue-scout` / `filing-cap` — but the backlog count, the scout and the per-run cap are all about
1507
+ // filing into *our own* backlog, so on a third-party target the right answer is to stop the write
1508
+ // entirely rather than to count anything. Placing it first means a third-party write is refused
1509
+ // before any of those speak; on a first-party filing it is silent (the owners match), so `wip-cap`
1510
+ // still speaks first, exactly as before. It fires on every occurrence (`git-force.ts`).
1511
+ third_party_write.ROW,
1512
+ {
1513
+ id: "wip-cap",
1514
+ is_trigger: on_bash_command2(is_issue_filing2),
1515
+ reason: WIP_CAP_REASON,
1516
+ keeps: on_bash_command2(counts_open_issues)
1517
+ },
1518
+ // **Three rows share the filing trigger** (joshuafolkken/kit#2119), listed after `wip-cap` so the
1519
+ // backlog count still speaks first: `issue-scout` refuses a filing the run has not scouted (once per
1520
+ // run, stood down once the scout is on the tail), and `filing-cap` refuses every filing past the
1521
+ // per-run ceiling. Each is a real instance of the admissible overlap the comment on `delivery`
1522
+ // describes — the losing rule's delivery is still correct one reissue later — so a scout-less,
1523
+ // over-cap filing is delivered `wip-cap`, then `issue-scout`, then `filing-cap` across its reissues.
1524
+ issue_scout.ROW,
1525
+ filing_cap.ROW,
1526
+ {
1527
+ id: "issue-comments",
1528
+ is_trigger: on_bash_command2(is_body_only_issue_read),
1529
+ reason: ISSUE_COMMENTS_REASON,
1530
+ already_satisfied: prior_comment_read.already_read_for_call,
1531
+ keeps: on_bash_command2(reads_issue_comments)
1532
+ },
1533
+ {
1534
+ id: "shell-body",
1535
+ is_trigger: on_bash_command2(is_shell_evaluated_body2),
1536
+ reason: SHELL_BODY_REASON,
1537
+ keeps: on_bash_command2(keeps_body_safe2),
1538
+ reaches: on_bash_command2(carries_a_body2)
1539
+ },
1540
+ {
1541
+ id: "piped-verification",
1542
+ is_trigger: on_bash_command2(piped_verification.is_masked_verification),
1543
+ reason: piped_verification.PIPED_VERIFICATION_REASON,
1544
+ keeps: on_bash_command2(piped_verification.keeps_verdict_intact),
1545
+ reaches: on_bash_command2(piped_verification.runs_verification)
1546
+ },
1547
+ {
1548
+ id: "early-heartbeat",
1549
+ is_trigger: on_bash_command2(early_heartbeat.is_wait_timer),
1550
+ reason: early_heartbeat.EARLY_HEARTBEAT_REASON,
1551
+ decide: early_heartbeat.decide,
1552
+ keeps: on_bash_command2(early_heartbeat.is_progress_watch),
1553
+ reaches: on_bash_command2(early_heartbeat.waits_for_progress)
1554
+ },
1555
+ // **Listed before `run-tail`, the one row it deliberately overlaps** (joshuafolkken/kit#2118). A
1556
+ // foreground `pnpm josh git -y` with no test beside the change is claimed by both: `test-declared`
1557
+ // decides whether the commit should happen at all, so it is listed first, exactly as `wip-cap`
1558
+ // precedes `shell-body` for deciding whether an Issue should exist. Nothing is lost by `run-tail`
1559
+ // losing the race — the stamps are keyed per `id`, so the reissued push is delivered `run-tail`,
1560
+ // which is asserted rather than assumed. The overlap only arises in a real checkout where the
1561
+ // verdict is `required`; in the hermetic non-repo suite the git read fails to `exempt`, so
1562
+ // `test-declared` claims nothing and the "exactly one rule" invariant over `run-tail`'s fixture holds.
1563
+ test_declared_commit.ROW,
1564
+ // **The one row whose trigger reads a field of the input beside the command**, so it supplies its
1565
+ // own tool-name check rather than going through `on_bash_command`: a push step already issued with
1566
+ // `run_in_background` is the rule obeyed, and refusing it would charge a run for doing the right
1567
+ // thing. It supplies `decide` because a push is a recurring act — one per child in a batch, and a
1568
+ // second inside one `fullrun` when round 2 fixes a finding in place.
1569
+ {
1570
+ id: "run-tail",
1571
+ is_trigger: run_tail.is_foreground_push_step,
1572
+ reason: run_tail.RUN_TAIL_REASON,
1573
+ decide: run_tail.decide,
1574
+ keeps: run_tail.is_backgrounded_push_step,
1575
+ reaches: run_tail.is_push_step_call
1576
+ },
1577
+ // **The one row whose trigger consults the world beside the command**, because "is this a lane that
1578
+ // has not cut" is not readable from the call: it is the working directory's own name and the cut
1579
+ // record on disk. Both reads are synchronous, and the command match runs first, so a run that never
1580
+ // types `pnpm josh gate` pays nothing for it.
1581
+ //
1582
+ // **Once per run rather than `decide`, and the direction of the error is why.** Taking the cut ends
1583
+ // the process, so this is not the recurring act joshuafolkken/kit#1570 wrote `decide` for — and the
1584
+ // five verdicts that legitimately leave a run at the gate (`not-a-lane`, `unready`, `busy`,
1585
+ // `failed`, `unknown`) all need the reissue to go through. A row that refused every time would wedge exactly
1586
+ // those runs; a row that refuses once cannot.
1587
+ //
1588
+ // **`pnpm josh rule:value` read this row with a ceiling of about 50%, and joshuafolkken/kit#1867 is
1589
+ // what removed it** (the ceiling was recorded here by joshuafolkken/kit#1864's review round 2). A
1590
+ // cut relaunches a *new session*, which the measurement groups as a run of its own, and that
1591
+ // resumed run issues the entry check — so scored on the asking alone it joined the denominator
1592
+ // while never being able to satisfy `keeps`, which only the cutting run can, and ten perfectly
1593
+ // obedient children read as ten kept out of twenty. **The two halves are separable, just not from
1594
+ // one call**: both processes issue byte-identical `--resume` strings, but the `fresh` verdict sends
1595
+ // a run on to claim the working-tree hold while the `resume` verdict tells its counterpart to skip
1596
+ // that claim. `reaches_the_pre_gate_boundary` is that conjunction, and it is why `CallTest` is
1597
+ // handed the run's calls beside the turn's rather than a second predicate slot of its own.
1598
+ // Dropping `reaches` altogether is still strictly worse — the trigger evaluates against the
1599
+ // *measuring* process's working directory, so it is always false from the main checkout and the row
1600
+ // would read as no runs at all.
1601
+ //
1602
+ // **It overlaps `piped-verification` on a piped gate call, and the order is safe in both
1603
+ // directions.** `pnpm josh gate | tail` in an uncut lane is a real instance of both defects; the
1604
+ // earlier row speaks, its own reason says to reissue, and this one delivers on the reissue — the
1605
+ // reading "the losing rule's delivery is still correct one call later" that the comment below
1606
+ // requires of any admissible overlap.
1607
+ {
1608
+ id: "pre-gate-cut",
1609
+ is_trigger: on_bash_command2(pre_gate_cut.is_uncut_gate),
1610
+ reason: pre_gate_cut.PRE_GATE_CUT_REASON,
1611
+ keeps: on_bash_command2(pre_gate_cut.takes_the_cut),
1612
+ reaches: reaches_the_pre_gate_boundary
1613
+ },
1614
+ // **The second row whose trigger consults the world beside the command** (joshuafolkken/kit#2034):
1615
+ // "is this a dispatched lane child" is the dispatch mark against this checkout's own issue, read
1616
+ // synchronously by `lane_child_marker.is_child_of`, and the command match runs first so an ordinary
1617
+ // run pays nothing for it.
1618
+ //
1619
+ // **Once per run rather than `decide`, and no `already_satisfied`.** The stop ends the turn, so it
1620
+ // is not the recurring act joshuafolkken/kit#1570 wrote `decide` for. It carries no
1621
+ // `already_satisfied` because the park it asks for is a GitHub label a synchronous guard cannot
1622
+ // read, and the transcript-tail alternative would read a child that merely *read*
1623
+ // `backlogrun-park.md` — whose prose carries the `labels[]=needs-decision` command — as compliant
1624
+ // and fall silent on a real violation. `lane-park.ts` states why one wasted reissue on the compliant
1625
+ // path is the safe direction. `keeps` reads an actual label-application `Bash` command, never the
1626
+ // tail, so it is not fooled the same way; `reaches` stays `is_trigger`, since a compliant run issues
1627
+ // the same confirmation notify and belongs in the denominator.
1628
+ {
1629
+ id: "lane-park",
1630
+ is_trigger: on_bash_command2(lane_park.is_unparked_stop),
1631
+ reason: lane_park.LANE_PARK_REASON,
1632
+ keeps: on_bash_command2(lane_park.records_the_park)
1633
+ },
1634
+ // **joshuafolkken/kit#2034's rule, one tool-call earlier** (joshuafolkken/kit#2201). `lane-park`
1635
+ // fires on the `confirmation` notify a routed child reaches; a child that reaches for
1636
+ // `AskUserQuestion` never gets there, because the harness ends its turn at the refused ask. This
1637
+ // row's trigger is that ask, so the refusal becomes an instruction — park the question — instead of
1638
+ // the child's death. Its trigger reads the input's tool name and consults the dispatch mark, like
1639
+ // `lane-park`, and shares no command with any Bash row, so it claims no `gh` / `git` / `josh` call.
1640
+ // It fires on every occurrence (`decide` returns true), the disposition `git-force.ts` takes: an
1641
+ // interactive ask must never succeed in a child, and the route is always the park, never a reissue.
1642
+ lane_interactive_ask.ROW,
1643
+ // **The three Bash-string gaps the deny glob cannot express** (joshuafolkken/kit#2120), each reading
1644
+ // the command's argv rather than a literal a glob keys on. They share no trigger with any row above —
1645
+ // force/delete is `git push` / `git branch`, the worktree change is `git checkout` / `restore` /
1646
+ // `stash`, and the file body is a heredoc / `node -e` / `perl -i` — so no two rows claim one command,
1647
+ // which `delivered-rules-bash.test.ts` pins. Each declares `decide` returning true: a destructive or
1648
+ // billed act is refused on every occurrence, never once per run (`git-force.ts`).
1649
+ git_force.ROW,
1650
+ worktree_guard.ROW,
1651
+ file_body.ROW
1652
+ ];
1653
+ var ALONE_IN_TURN = 1;
1654
+ function batches_the_turn(call, turn) {
1655
+ return time_batch_guard.is_guarded_call(call) && turn.length > ALONE_IN_TURN;
1656
+ }
1657
+ var BATCHING_RULE = {
1658
+ id: "batching",
1659
+ reason: time_batch_guard.REASON,
1660
+ keeps: batches_the_turn,
1661
+ reaches: time_batch_guard.is_guarded_call
1662
+ };
1663
+ var INVESTIGATION_RULE = {
1664
+ id: "investigation",
1665
+ reason: investigation_reads.REASON,
1666
+ reaches: investigation_reads.is_refusable_call
1667
+ };
1668
+ var MEASURED_RULES = [
1669
+ ...DELIVERED_RULES,
1670
+ BATCHING_RULE,
1671
+ INVESTIGATION_RULE
1672
+ ];
1673
+ var BATCH_STAMP = hook_decision.create_refusal_stamp(time_batch_guard.STAMP_PREFIX);
1674
+ var BATCH_REFUSAL_WINDOW_MS = 1e4;
1675
+ function will_batch_guard_refuse(tail, call, run) {
1676
+ if (lane_guard_policy.mode_here("batching") !== "refuse") return false;
1677
+ const refused_at_ms = BATCH_STAMP.last_ms(BATCH_STAMP.path(run.transcript));
1678
+ if (run.now_ms - refused_at_ms < BATCH_REFUSAL_WINDOW_MS) return true;
1679
+ return time_batch_guard.should_block(tail, call, refused_at_ms);
1680
+ }
1681
+ function is_first_delivery(tail, call, delivered_at_ms, run) {
1682
+ if (delivered_at_ms !== hook_decision.NEVER_MS) return false;
1683
+ return !will_batch_guard_refuse(tail, call, run);
1684
+ }
1685
+ function delivery_decision(rule) {
1686
+ const { decide: decide4, already_satisfied } = rule;
1687
+ if (decide4 === void 0 && already_satisfied === void 0) return is_first_delivery;
1688
+ return function should_block(tail, call, delivered_at_ms, run) {
1689
+ if (already_satisfied?.(tail, call) === true) return false;
1690
+ if (decide4 === void 0) return is_first_delivery(tail, call, delivered_at_ms, run);
1691
+ return decide4(call, run, !will_batch_guard_refuse(tail, call, run));
1692
+ };
1693
+ }
1694
+ function guard_of(rule) {
1695
+ return hook_decision.create_transcript_guard({
1696
+ prefix: `${STAMP_PREFIX}${rule.id}-`,
1697
+ switch_key: SWITCH_ENV_KEY,
1698
+ is_candidate: rule.is_trigger,
1699
+ should_block: delivery_decision(rule),
1700
+ reason: rule.reason
1701
+ });
1702
+ }
1703
+ var GUARDS = new Map(DELIVERED_RULES.map((rule) => [rule.id, guard_of(rule)]));
1704
+ function delivery_path(rule_id, transcript_path) {
1705
+ const guard = GUARDS.get(rule_id);
1706
+ return guard === void 0 ? "" : guard.refusal_path(transcript_path);
1707
+ }
1708
+ function delivery(raw_payload, now_ms = Date.now()) {
1709
+ for (const guard of GUARDS.values()) {
1710
+ const reason = guard.refusal(raw_payload, now_ms);
1711
+ if (reason !== void 0) return reason;
1712
+ }
1713
+ return void 0;
1714
+ }
1715
+ function is_enabled() {
1716
+ return hook_decision.is_switch_enabled(SWITCH_ENV_KEY);
1717
+ }
1718
+ var delivered_rules = {
1719
+ DELIVERED_RULES,
1720
+ EARLY_HEARTBEAT_REASON: early_heartbeat.EARLY_HEARTBEAT_REASON,
1721
+ FILE_BODY_REASON: file_body.FILE_BODY_REASON,
1722
+ FILING_CAP_REASON: filing_cap.FILING_CAP_REASON,
1723
+ GIT_FORCE_REASON: git_force.GIT_FORCE_REASON,
1724
+ ISSUE_COMMENTS_REASON,
1725
+ ISSUE_SCOUT_REASON: issue_scout.ISSUE_SCOUT_REASON,
1726
+ LANE_INTERACTIVE_ASK_REASON: lane_interactive_ask.LANE_INTERACTIVE_ASK_REASON,
1727
+ LANE_PARK_REASON: lane_park.LANE_PARK_REASON,
1728
+ MEASURED_RULES,
1729
+ PIPED_VERIFICATION_REASON: piped_verification.PIPED_VERIFICATION_REASON,
1730
+ PRE_GATE_CUT_REASON: pre_gate_cut.PRE_GATE_CUT_REASON,
1731
+ RUN_TAIL_REASON: run_tail.RUN_TAIL_REASON,
1732
+ SHELL_BODY_REASON,
1733
+ SWITCH_ENV_KEY,
1734
+ THIRD_PARTY_WRITE_REASON: third_party_write.THIRD_PARTY_WRITE_REASON,
1735
+ WIP_CAP_REASON,
1736
+ WORKTREE_MUTATION_REASON: worktree_guard.WORKTREE_MUTATION_REASON,
1737
+ delivery,
1738
+ delivery_path,
1739
+ is_body_only_issue_read,
1740
+ is_enabled,
1741
+ is_issue_filing: is_issue_filing2,
1742
+ is_masked_verification: piped_verification.is_masked_verification,
1743
+ is_wait_timer: early_heartbeat.is_wait_timer
1744
+ };
1745
+
1746
+ // scripts/hooks/pretool-guard.ts
1747
+ function combine_outcomes(batch, extra_reason) {
1748
+ if (batch.reason !== void 0) return batch;
1749
+ if (extra_reason !== void 0) {
1750
+ return { reason: extra_reason, notice: void 0, fault: void 0 };
1751
+ }
1752
+ return batch;
1753
+ }
1754
+ function pretool_outcome(raw_payload) {
1755
+ const batch = batch_outcome(raw_payload);
1756
+ const investigation = investigation_refusal(raw_payload);
1757
+ const rule = delivered_rules.delivery(raw_payload);
1758
+ return combine_outcomes(batch, investigation ?? rule);
1759
+ }
1760
+ var pretool_guard = { combine_outcomes, pretool_outcome };
1761
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
1762
+ if (process.stdin.isTTY) hook_decision.report_no_payload("pretool:guard");
1763
+ else hook_decision.write_outcome(await text(process.stdin), pretool_outcome);
1764
+ }
1765
+
1766
+ export {
1767
+ pretool_outcome,
1768
+ pretool_guard
1769
+ };