@joshuafolkken/kit 1.872.0 → 1.881.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 (256) hide show
  1. package/.github/workflows/publish.yml +39 -2
  2. package/README.md +3 -3
  3. package/dist/hooks/batch-guard.js +4 -4
  4. package/dist/hooks/{chunk-KABG6AEW.js → chunk-264QY6KS.js} +7 -0
  5. package/dist/hooks/{chunk-I4D3NVUD.js → chunk-36UE53LS.js} +2 -2
  6. package/dist/hooks/{chunk-WCYPBPJC.js → chunk-4OXFU3MK.js} +8 -8
  7. package/dist/hooks/{chunk-ABVEVV2M.js → chunk-6MQCXEEA.js} +1 -1
  8. package/dist/hooks/{chunk-46EEEHC3.js → chunk-FNFOLFFV.js} +1 -1
  9. package/dist/hooks/{chunk-5U5EZYG6.js → chunk-FRJKVSK3.js} +2 -2
  10. package/dist/hooks/{chunk-2RUPMGGV.js → chunk-PRDCNGA6.js} +4 -4
  11. package/dist/hooks/{chunk-WMN4TSVF.js → chunk-VGYSA2NT.js} +2 -2
  12. package/dist/hooks/{chunk-A5YJ3H7E.js → chunk-Y5OYCU2F.js} +3 -3
  13. package/dist/hooks/{chunk-4QHBNAI4.js → chunk-ZBK4XRAS.js} +3 -3
  14. package/dist/hooks/codex-hook-adapter.js +10 -10
  15. package/dist/hooks/duplicate-read-guard.js +5 -5
  16. package/dist/hooks/format-edited.js +2 -2
  17. package/dist/hooks/investigation-guard.js +5 -5
  18. package/dist/hooks/pretool-guard.js +9 -9
  19. package/dist/hooks/stop-guard.js +3 -3
  20. package/dist/josh.js +7 -0
  21. package/package.json +6 -2
  22. package/scripts/init/distributed-paths.ts +14 -11
  23. package/scripts/init/hook-command-bootstrap.ts +51 -0
  24. package/scripts/init/hook-command-rewrite.ts +9 -1
  25. package/scripts/init/init-logic.ts +2 -8
  26. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +10 -0
  27. package/scripts/josh/josh-command-map.ts +1 -0
  28. package/scripts/josh/josh-commands-project.ts +6 -0
  29. package/scripts/registry-migration/migrate-logic.ts +229 -0
  30. package/scripts/registry-migration/migrate.ts +280 -0
  31. package/scripts/registry-migration/user-npmrc.ts +15 -0
  32. package/templates/workflows/ci.yml +6 -2
  33. package/dist/hooks/chunk-25JL6FMS.js +0 -4970
  34. package/dist/hooks/chunk-2ANGT3XM.js +0 -375
  35. package/dist/hooks/chunk-2EI5GBSW.js +0 -42
  36. package/dist/hooks/chunk-2OT5XE2N.js +0 -5014
  37. package/dist/hooks/chunk-2XIGZQMQ.js +0 -3299
  38. package/dist/hooks/chunk-33ELOKEV.js +0 -910
  39. package/dist/hooks/chunk-33YRTKM7.js +0 -230
  40. package/dist/hooks/chunk-36JQU5NN.js +0 -77
  41. package/dist/hooks/chunk-3EJBTWVS.js +0 -1769
  42. package/dist/hooks/chunk-3FK5SFAC.js +0 -432
  43. package/dist/hooks/chunk-3PWPYDD2.js +0 -240
  44. package/dist/hooks/chunk-3TQU7TDH.js +0 -375
  45. package/dist/hooks/chunk-3TVLSFZ6.js +0 -432
  46. package/dist/hooks/chunk-3VXYCB4E.js +0 -77
  47. package/dist/hooks/chunk-44M6JXGV.js +0 -3398
  48. package/dist/hooks/chunk-4A7UVP2P.js +0 -364
  49. package/dist/hooks/chunk-4LFQEZS4.js +0 -137
  50. package/dist/hooks/chunk-4OCX3V2T.js +0 -469
  51. package/dist/hooks/chunk-4OHA5DE7.js +0 -49
  52. package/dist/hooks/chunk-4PMDW3YD.js +0 -68
  53. package/dist/hooks/chunk-4SSB3FEE.js +0 -3273
  54. package/dist/hooks/chunk-5A2WQ2CQ.js +0 -5390
  55. package/dist/hooks/chunk-5EVA2JQB.js +0 -5390
  56. package/dist/hooks/chunk-5P7VF5VE.js +0 -3230
  57. package/dist/hooks/chunk-5QWJGGZP.js +0 -49
  58. package/dist/hooks/chunk-5VUUF3ZV.js +0 -240
  59. package/dist/hooks/chunk-5WA7UBT3.js +0 -374
  60. package/dist/hooks/chunk-6EBGRQ3Q.js +0 -301
  61. package/dist/hooks/chunk-6TVHWMD3.js +0 -432
  62. package/dist/hooks/chunk-6VAGLEMB.js +0 -68
  63. package/dist/hooks/chunk-75BTXKFJ.js +0 -3424
  64. package/dist/hooks/chunk-75RHN67S.js +0 -137
  65. package/dist/hooks/chunk-76KC3BDD.js +0 -3414
  66. package/dist/hooks/chunk-76SLS7CZ.js +0 -898
  67. package/dist/hooks/chunk-7DHZ4DWT.js +0 -5015
  68. package/dist/hooks/chunk-7INSJDGE.js +0 -458
  69. package/dist/hooks/chunk-7VJ4FTDX.js +0 -268
  70. package/dist/hooks/chunk-7XCYNHQK.js +0 -77
  71. package/dist/hooks/chunk-AAEXXUUL.js +0 -268
  72. package/dist/hooks/chunk-ACN3YXFL.js +0 -68
  73. package/dist/hooks/chunk-AD3XE3QZ.js +0 -397
  74. package/dist/hooks/chunk-AENFZPZH.js +0 -230
  75. package/dist/hooks/chunk-AFKRFQ6W.js +0 -68
  76. package/dist/hooks/chunk-AHD5IPWI.js +0 -375
  77. package/dist/hooks/chunk-AMK5JGV7.js +0 -77
  78. package/dist/hooks/chunk-ARN7NCQI.js +0 -425
  79. package/dist/hooks/chunk-AUFY653N.js +0 -3425
  80. package/dist/hooks/chunk-AXQBNFEF.js +0 -375
  81. package/dist/hooks/chunk-AYC7R6U4.js +0 -3316
  82. package/dist/hooks/chunk-AYEA2FJ7.js +0 -5015
  83. package/dist/hooks/chunk-B2LIXYFL.js +0 -77
  84. package/dist/hooks/chunk-B4HPNY2I.js +0 -375
  85. package/dist/hooks/chunk-B4YNCUGB.js +0 -469
  86. package/dist/hooks/chunk-B57S3VWT.js +0 -922
  87. package/dist/hooks/chunk-BINZ3PLI.js +0 -364
  88. package/dist/hooks/chunk-BIWLABFK.js +0 -432
  89. package/dist/hooks/chunk-BODUSXKK.js +0 -410
  90. package/dist/hooks/chunk-BQBAT2YK.js +0 -375
  91. package/dist/hooks/chunk-BUJEBW75.js +0 -391
  92. package/dist/hooks/chunk-BVNWORKA.js +0 -72
  93. package/dist/hooks/chunk-BWI47LQS.js +0 -5205
  94. package/dist/hooks/chunk-C25HRMJX.js +0 -137
  95. package/dist/hooks/chunk-CBFZNC74.js +0 -375
  96. package/dist/hooks/chunk-CECYXS4Y.js +0 -3424
  97. package/dist/hooks/chunk-CELGUP5F.js +0 -49
  98. package/dist/hooks/chunk-CMHANU3F.js +0 -3442
  99. package/dist/hooks/chunk-CMN372LI.js +0 -68
  100. package/dist/hooks/chunk-CPGZLMMK.js +0 -3299
  101. package/dist/hooks/chunk-CTQKXDC7.js +0 -268
  102. package/dist/hooks/chunk-CYAT4RIT.js +0 -68
  103. package/dist/hooks/chunk-CYTWYCH2.js +0 -5014
  104. package/dist/hooks/chunk-CZSOLRBA.js +0 -77
  105. package/dist/hooks/chunk-D2PIDYJR.js +0 -3438
  106. package/dist/hooks/chunk-DE57HI6T.js +0 -137
  107. package/dist/hooks/chunk-DGXDGAPG.js +0 -5306
  108. package/dist/hooks/chunk-DNYRSYQG.js +0 -5014
  109. package/dist/hooks/chunk-DTAXH2A2.js +0 -240
  110. package/dist/hooks/chunk-E2IZUWI5.js +0 -375
  111. package/dist/hooks/chunk-E4L2K2BL.js +0 -397
  112. package/dist/hooks/chunk-E55NKX5F.js +0 -68
  113. package/dist/hooks/chunk-ECXVCCVD.js +0 -3079
  114. package/dist/hooks/chunk-EPHO443D.js +0 -68
  115. package/dist/hooks/chunk-EUFK2BI2.js +0 -375
  116. package/dist/hooks/chunk-EYCD5ZAV.js +0 -137
  117. package/dist/hooks/chunk-F2SDYJU4.js +0 -240
  118. package/dist/hooks/chunk-F4B5D5TF.js +0 -68
  119. package/dist/hooks/chunk-FGEO3NDX.js +0 -432
  120. package/dist/hooks/chunk-FJYI52RE.js +0 -137
  121. package/dist/hooks/chunk-FYTZHIY4.js +0 -3085
  122. package/dist/hooks/chunk-G7JL2A5K.js +0 -375
  123. package/dist/hooks/chunk-GA3ITDBW.js +0 -42
  124. package/dist/hooks/chunk-GDR4H4SV.js +0 -469
  125. package/dist/hooks/chunk-GFKDXPSM.js +0 -2855
  126. package/dist/hooks/chunk-GIMRTKFU.js +0 -566
  127. package/dist/hooks/chunk-GOPHRLGO.js +0 -240
  128. package/dist/hooks/chunk-GX4HO7SJ.js +0 -230
  129. package/dist/hooks/chunk-GXKKK23T.js +0 -240
  130. package/dist/hooks/chunk-GZ6FUVIK.js +0 -566
  131. package/dist/hooks/chunk-H5HPY5M5.js +0 -2869
  132. package/dist/hooks/chunk-HCF3OGEE.js +0 -1829
  133. package/dist/hooks/chunk-HDEXAOUM.js +0 -469
  134. package/dist/hooks/chunk-HM2TY3TN.js +0 -469
  135. package/dist/hooks/chunk-HOA7NXA2.js +0 -55
  136. package/dist/hooks/chunk-HOFEWH6H.js +0 -240
  137. package/dist/hooks/chunk-HUUI6S5J.js +0 -2669
  138. package/dist/hooks/chunk-I4Q6WAJE.js +0 -68
  139. package/dist/hooks/chunk-IB6N4CR2.js +0 -432
  140. package/dist/hooks/chunk-IFLDYJMD.js +0 -469
  141. package/dist/hooks/chunk-IGU466YD.js +0 -77
  142. package/dist/hooks/chunk-IJCQUHKY.js +0 -375
  143. package/dist/hooks/chunk-IKUMBDJB.js +0 -230
  144. package/dist/hooks/chunk-IM3BDIBJ.js +0 -5005
  145. package/dist/hooks/chunk-IMYMAODK.js +0 -3431
  146. package/dist/hooks/chunk-IN2ZVGXA.js +0 -5005
  147. package/dist/hooks/chunk-ITVJ2MKQ.js +0 -18
  148. package/dist/hooks/chunk-J5RIJYTM.js +0 -2669
  149. package/dist/hooks/chunk-JFLMH4K5.js +0 -3460
  150. package/dist/hooks/chunk-JR25IFML.js +0 -77
  151. package/dist/hooks/chunk-JT5AUXFI.js +0 -432
  152. package/dist/hooks/chunk-JY5YVN6N.js +0 -3234
  153. package/dist/hooks/chunk-K5Q4ETVI.js +0 -391
  154. package/dist/hooks/chunk-K67V2F24.js +0 -137
  155. package/dist/hooks/chunk-KATZESEC.js +0 -3273
  156. package/dist/hooks/chunk-KFH4H7W7.js +0 -469
  157. package/dist/hooks/chunk-KMUEI6RX.js +0 -910
  158. package/dist/hooks/chunk-KMV4OY77.js +0 -3438
  159. package/dist/hooks/chunk-KQAZNWEY.js +0 -137
  160. package/dist/hooks/chunk-KZZR6JER.js +0 -5015
  161. package/dist/hooks/chunk-LAR6DREP.js +0 -77
  162. package/dist/hooks/chunk-LNCJWEZD.js +0 -5015
  163. package/dist/hooks/chunk-LRYD2GLM.js +0 -6
  164. package/dist/hooks/chunk-LXBKYHDV.js +0 -77
  165. package/dist/hooks/chunk-LYLKIUNE.js +0 -5024
  166. package/dist/hooks/chunk-LZKCFOVC.js +0 -432
  167. package/dist/hooks/chunk-M4FCIYRI.js +0 -77
  168. package/dist/hooks/chunk-M5M7327Q.js +0 -3425
  169. package/dist/hooks/chunk-MF72MHSX.js +0 -3455
  170. package/dist/hooks/chunk-MK56LKDO.js +0 -397
  171. package/dist/hooks/chunk-N3MJADY7.js +0 -240
  172. package/dist/hooks/chunk-NFQSUDBN.js +0 -458
  173. package/dist/hooks/chunk-NHREKY45.js +0 -137
  174. package/dist/hooks/chunk-NP5TTAAW.js +0 -375
  175. package/dist/hooks/chunk-NQTLTKTJ.js +0 -2993
  176. package/dist/hooks/chunk-NVRCZPBZ.js +0 -391
  177. package/dist/hooks/chunk-O46HMMLJ.js +0 -469
  178. package/dist/hooks/chunk-OFJGH2L4.js +0 -240
  179. package/dist/hooks/chunk-OLFMCZH5.js +0 -240
  180. package/dist/hooks/chunk-OMCZS46I.js +0 -49
  181. package/dist/hooks/chunk-OQZEZW5G.js +0 -469
  182. package/dist/hooks/chunk-P2MDAT2Y.js +0 -1897
  183. package/dist/hooks/chunk-P3M2JJIF.js +0 -68
  184. package/dist/hooks/chunk-PDVHQITQ.js +0 -3453
  185. package/dist/hooks/chunk-PNT2AMDH.js +0 -391
  186. package/dist/hooks/chunk-PR2LVSY6.js +0 -3445
  187. package/dist/hooks/chunk-PRR5R4JK.js +0 -137
  188. package/dist/hooks/chunk-PXT44QVN.js +0 -566
  189. package/dist/hooks/chunk-PZLWJLAP.js +0 -469
  190. package/dist/hooks/chunk-Q2FEAZJ2.js +0 -77
  191. package/dist/hooks/chunk-Q32WETDO.js +0 -3265
  192. package/dist/hooks/chunk-Q45DUBLE.js +0 -3600
  193. package/dist/hooks/chunk-Q7NZSWQ5.js +0 -240
  194. package/dist/hooks/chunk-QH2JNAMK.js +0 -3085
  195. package/dist/hooks/chunk-QNNWYQ2R.js +0 -375
  196. package/dist/hooks/chunk-QPU5H2OS.js +0 -68
  197. package/dist/hooks/chunk-QRAHZ5TO.js +0 -1829
  198. package/dist/hooks/chunk-QUZ5HPIE.js +0 -469
  199. package/dist/hooks/chunk-QVCRG34O.js +0 -2893
  200. package/dist/hooks/chunk-R3MY4E3S.js +0 -1675
  201. package/dist/hooks/chunk-R6TXJJXP.js +0 -77
  202. package/dist/hooks/chunk-REJU6VT7.js +0 -1829
  203. package/dist/hooks/chunk-REQAQLRC.js +0 -2993
  204. package/dist/hooks/chunk-RFCXPAHH.js +0 -391
  205. package/dist/hooks/chunk-RHI6Y22X.js +0 -137
  206. package/dist/hooks/chunk-RKZVOBBS.js +0 -469
  207. package/dist/hooks/chunk-RL57TT2Y.js +0 -566
  208. package/dist/hooks/chunk-RORDOD4S.js +0 -3321
  209. package/dist/hooks/chunk-RZKYW5P2.js +0 -77
  210. package/dist/hooks/chunk-SJPJ6VSI.js +0 -391
  211. package/dist/hooks/chunk-SKSIJQQQ.js +0 -432
  212. package/dist/hooks/chunk-SSQDZKXG.js +0 -268
  213. package/dist/hooks/chunk-SYHFKE4C.js +0 -77
  214. package/dist/hooks/chunk-TCGNI2ZY.js +0 -42
  215. package/dist/hooks/chunk-TG3WXJF5.js +0 -137
  216. package/dist/hooks/chunk-TH7IJAY5.js +0 -77
  217. package/dist/hooks/chunk-TLZ27PCY.js +0 -240
  218. package/dist/hooks/chunk-U652FXTN.js +0 -566
  219. package/dist/hooks/chunk-UEK47YUF.js +0 -268
  220. package/dist/hooks/chunk-UIO45H3O.js +0 -432
  221. package/dist/hooks/chunk-UNLZEEVH.js +0 -5005
  222. package/dist/hooks/chunk-UNRVF3SZ.js +0 -432
  223. package/dist/hooks/chunk-USLFAFOI.js +0 -3453
  224. package/dist/hooks/chunk-VAEELMLL.js +0 -442
  225. package/dist/hooks/chunk-VALSWLDQ.js +0 -3453
  226. package/dist/hooks/chunk-VC5JEPNY.js +0 -3398
  227. package/dist/hooks/chunk-VEZVK6C7.js +0 -230
  228. package/dist/hooks/chunk-VK5JKFAR.js +0 -49
  229. package/dist/hooks/chunk-VNF2KP7Z.js +0 -469
  230. package/dist/hooks/chunk-VWWCUMW6.js +0 -2669
  231. package/dist/hooks/chunk-W4JARUQV.js +0 -137
  232. package/dist/hooks/chunk-WEOBMNJG.js +0 -2993
  233. package/dist/hooks/chunk-WKJU3J5Y.js +0 -5390
  234. package/dist/hooks/chunk-WNON54PT.js +0 -3469
  235. package/dist/hooks/chunk-WOVKBPPX.js +0 -137
  236. package/dist/hooks/chunk-WRVFORYJ.js +0 -432
  237. package/dist/hooks/chunk-WUBVYGQZ.js +0 -240
  238. package/dist/hooks/chunk-WWULTUOM.js +0 -68
  239. package/dist/hooks/chunk-WXHKKB45.js +0 -4962
  240. package/dist/hooks/chunk-XAI3YTHJ.js +0 -469
  241. package/dist/hooks/chunk-XFZH6JZJ.js +0 -77
  242. package/dist/hooks/chunk-XGPWX6IA.js +0 -137
  243. package/dist/hooks/chunk-XIXXIVGY.js +0 -566
  244. package/dist/hooks/chunk-XKDOYJGA.js +0 -922
  245. package/dist/hooks/chunk-YALTVBHM.js +0 -432
  246. package/dist/hooks/chunk-YEBEPBFK.js +0 -5014
  247. package/dist/hooks/chunk-YI2BQ3DK.js +0 -3441
  248. package/dist/hooks/chunk-YVNBCFGG.js +0 -1829
  249. package/dist/hooks/chunk-YXBN3RGG.js +0 -432
  250. package/dist/hooks/chunk-Z2OOJSW3.js +0 -3163
  251. package/dist/hooks/chunk-ZA3HVBOY.js +0 -2644
  252. package/dist/hooks/chunk-ZKID46U3.js +0 -137
  253. package/dist/hooks/chunk-ZPMU2JV6.js +0 -49
  254. package/dist/hooks/chunk-ZRKY4W7O.js +0 -432
  255. package/dist/hooks/chunk-ZTMRB7LJ.js +0 -268
  256. package/dist/hooks/chunk-ZVPPBQ3L.js +0 -3413
@@ -1,397 +0,0 @@
1
- import {
2
- lane_guard_policy,
3
- time_batch_guard
4
- } from "./chunk-BODUSXKK.js";
5
- import {
6
- hook_decision
7
- } from "./chunk-GX4HO7SJ.js";
8
- import {
9
- cost_blocks,
10
- cost_transcript,
11
- time_bundle_call,
12
- time_shell,
13
- time_spans
14
- } from "./chunk-ECXVCCVD.js";
15
-
16
- // scripts/delegation/investigation-guard.ts
17
- import { text } from "node:stream/consumers";
18
- import { fileURLToPath } from "node:url";
19
-
20
- // scripts/delegation/investigation-reads.ts
21
- import path from "node:path";
22
-
23
- // scripts/delegation/delegation-policy.ts
24
- var DELEGATE_VERDICT = "delegate";
25
- var KEEP_VERDICT = "keep";
26
- var INVESTIGATION_FILE_THRESHOLD = 3;
27
- var DELEGATABLE_STEPS = [
28
- {
29
- name: "gate-fix",
30
- does: "apply the fixes the verification gate already named \u2014 a lint rule, a type error, a spelling the dictionary rejects",
31
- verifier: "`pnpm josh gate` is re-run; a wrong fix fails it again, and the failure names the file"
32
- },
33
- {
34
- name: "epic-child",
35
- // One row, two entry points: an epic's child under `epicrun` and one named issue of a
36
- // `backlogrun` are the same unit — same brief, same summary, same verifier
37
- // (joshuafolkken/kit#1149, folded from `queue` into `backlogrun` by joshuafolkken/kit#1984). A
38
- // second row for the batch would be the clone `CLAUDE.md` prohibits.
39
- does: "run one child of a batch end to end in an isolated unit \u2014 an epic's child or one named issue of a `backlogrun` alike \u2014 plan, verification gate, PR, merge \u2014 and return only its summary to the parent loop",
40
- verifier: "the parent reads the child's state from GitHub with `pnpm josh issue:state`, not from the summary; a child reported done but not merged is still open, which is the failure showing rather than a run continuing, and its own gate, `/code-review` and CI ran inside the unit before `followup` would touch the PR"
41
- },
42
- {
43
- name: "followup-filing",
44
- // The late-run follow-up filing chain — issue:scout → file the Issue → epic:bundle → epic --add
45
- // — is a dependency chain `batch:guard` correctly keeps one call per step, and what makes it
46
- // expensive is the ~340k context it runs in at the tail of a run, not the step count
47
- // (joshuafolkken/kit#1892). A fresh unit runs the same chain at a small context, and the review
48
- // round cap already composed the finding text, so what the unit is handed is mechanical: run the
49
- // four commands and act on their deterministic answers. This is not `batch:guard`'s business —
50
- // the chain stays one call per step; delegation only moves it to a cheaper context.
51
- does: "run the late-run follow-up filing chain in an isolated unit \u2014 issue:scout, file the Issue, epic:bundle, epic --add \u2014 given the finding text the parent already composed, and return the new Issue number and the epic:bundle answer",
52
- verifier: "the parent reads the filed Issue from GitHub with `pnpm josh issue:state <new>`, not the unit's summary; a follow-up reported filed but not created is still absent, the way `epic-child`'s reported-done-but-not-merged child is still open. The finding text came from the parent and `issue:scout` / `epic:bundle` are deterministic, so the unit's work is the mechanical execution `issue:state` confirms"
53
- },
54
- {
55
- name: "survey",
56
- does: "read across many files and report where something appears \u2014 every reference to a symbol, which documents carry a marker",
57
- verifier: "the reported locations are checked directly; a fabricated or missed location does not survive one `grep` of what it claimed"
58
- },
59
- {
60
- name: "investigation",
61
- // Not `survey`: that row reports *where* something appears and is checked by one `grep`, while
62
- // this one reports *how the subject works* and is checked by opening the lines it cited. The two
63
- // verifiers differ, so widening `survey` would put both in one field and lose the boundary below.
64
- // **No ordinal.** `${N}rd` would print `1rd` for any other threshold, past a test that only looks
65
- // for the numeral, so the count is phrased as a plain "N or more".
66
- does: `read the Issue's subject to find out how it currently works \u2014 once ${String(INVESTIGATION_FILE_THRESHOLD)} or more files the run will not edit have to be read \u2014 and return the conclusion plus the \`file:line\` citations that support it, never the file text, which would put the cost back where it was. A throwaway probe script is written, run and deleted inside the unit, which returns its output alone`,
67
- verifier: "the parent opens the cited lines; a conclusion those lines do not support fails there, and reading a handful of cited regions costs far less than redoing the reading. The unit reports what the code does and never what to change \u2014 deciding that is `diagnosis`, which stays kept, so a unit returning a root cause would be delegating the rejected row under this name"
68
- }
69
- ];
70
- var REJECTED_STEPS = [
71
- {
72
- name: "notify-body",
73
- because: "no verifier. A notification with a wrong body is sent and read as though it were right; nothing in the run disagrees with it afterwards"
74
- },
75
- {
76
- name: "issue-comment",
77
- because: "no verifier. A decision log or completion comment that says the wrong thing is the record, so there is nothing left to check it against"
78
- },
79
- {
80
- name: "status-read",
81
- because: "a misread routes the run to the wrong child, and no later step disagrees. Running the status command is already cheap; what is expensive is acting on it, which is not this step"
82
- },
83
- {
84
- name: "diagnosis",
85
- because: "a wrong root cause produces a fix that passes the gate and leaves the defect"
86
- },
87
- {
88
- name: "design",
89
- because: "the cost of a wrong design is paid by every step after it"
90
- },
91
- {
92
- name: "split-assessment",
93
- because: "a missed split widens one Issue into a batch nobody authorized"
94
- },
95
- {
96
- name: "review",
97
- because: "the review is the last thing between a defect and a merge; a cheaper one finds less"
98
- }
99
- ];
100
- function find_step(name) {
101
- return DELEGATABLE_STEPS.find((step2) => step2.name === name.trim());
102
- }
103
- function verdict_for(name) {
104
- return find_step(name) === void 0 ? KEEP_VERDICT : DELEGATE_VERDICT;
105
- }
106
- function rejection_for(name) {
107
- return REJECTED_STEPS.find((step2) => step2.name === name.trim());
108
- }
109
- function reason_for(name) {
110
- const step2 = find_step(name);
111
- if (step2 !== void 0) return `delegatable: ${step2.verifier}`;
112
- const rejected = rejection_for(name);
113
- if (rejected !== void 0) return `kept deliberately: ${rejected.because}`;
114
- return "kept by default: not on the delegatable list, and the list is the whole of it";
115
- }
116
- var delegation_policy = {
117
- DELEGATE_VERDICT,
118
- INVESTIGATION_FILE_THRESHOLD,
119
- KEEP_VERDICT,
120
- DELEGATABLE_STEPS,
121
- REJECTED_STEPS,
122
- find_step,
123
- verdict_for,
124
- rejection_for,
125
- reason_for
126
- };
127
-
128
- // scripts/delegation/investigation-reads.ts
129
- var READ_TOOLS = /* @__PURE__ */ new Set(["Read"]);
130
- var DELEGATION_TOOLS = /* @__PURE__ */ new Set(["Agent", "Task"]);
131
- var CONTENT_READ_COMMANDS = [
132
- "bat",
133
- "cat",
134
- "head",
135
- "less",
136
- "more",
137
- "nl",
138
- "sed",
139
- "tail"
140
- ];
141
- var CONTENT_READ_LABELS = new Set(
142
- CONTENT_READ_COMMANDS.map((command) => time_shell.bash_label(command))
143
- );
144
- var REASON = `\u26D4 investigation: ${String(delegation_policy.INVESTIGATION_FILE_THRESHOLD)} files read and not edited since the last delegated unit, so the reading from here goes to a unit of its own. Ask \`pnpm josh delegate investigation\`, then brief a unit with what the main line has already concluded and what is left to find out; it returns the conclusion plus its \`file:line\` citations, never the file text. Keep a read in the main line only where this run will edit that file \u2014 an \`Edit\` cannot be issued against text you do not hold. This run's own instructions and the harness's own session files \u2014 a backgrounded call's output, a persisted tool result, this session's scratchpad \u2014 are never counted, so they are not what took the count here. The rule is \`.claude/skills/workflow-commands/SKILL.md\` \u2192 \xA72b, "The pre-implementation reading".`;
145
- var INSTRUCTION_PATHS = ["prompts", ".claude/skills"];
146
- var INSTRUCTION_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "AGENTS.md", "GEMINI.md"]);
147
- var REPOSITORY_ROOT = process.cwd();
148
- function resolved(target) {
149
- return path.resolve(REPOSITORY_ROOT, target);
150
- }
151
- function repository_relative(absolute) {
152
- return path.relative(REPOSITORY_ROOT, absolute);
153
- }
154
- function is_instruction_document(target) {
155
- const relative = repository_relative(resolved(target));
156
- const segments = relative.split(path.sep);
157
- return INSTRUCTION_FILES.has(segments.at(-1) ?? "") || INSTRUCTION_PATHS.some((prefix) => relative.startsWith(`${prefix}${path.sep}`));
158
- }
159
- var SESSION_TEMP_SEGMENT = /^claude-\d+$/u;
160
- var SESSION_STATE_SEGMENTS = cost_transcript.TRANSCRIPT_ROOT.split(path.sep);
161
- var HARNESS_OUTPUT_DIRECTORY = "tasks";
162
- var HARNESS_OUTPUT_EXTENSION = ".output";
163
- var FILE_SEGMENT_INDEX = -1;
164
- var PARENT_SEGMENT_INDEX = -2;
165
- function has_state_root(segments, index) {
166
- return SESSION_STATE_SEGMENTS.every((segment, offset) => segments[index + offset] === segment);
167
- }
168
- function is_harness_output(segments) {
169
- return segments.some((segment) => SESSION_TEMP_SEGMENT.test(segment)) && segments.at(PARENT_SEGMENT_INDEX) === HARNESS_OUTPUT_DIRECTORY && (segments.at(FILE_SEGMENT_INDEX) ?? "").endsWith(HARNESS_OUTPUT_EXTENSION);
170
- }
171
- function is_outside_repository(absolute) {
172
- return repository_relative(absolute).startsWith("..");
173
- }
174
- function is_session_artifact(target) {
175
- const absolute = resolved(target);
176
- const segments = absolute.split(path.sep);
177
- if (!is_outside_repository(absolute)) return false;
178
- return segments.some((_segment, index) => has_state_root(segments, index)) || is_harness_output(segments);
179
- }
180
- function is_subject_file(target) {
181
- return !is_instruction_document(target) && !is_session_artifact(target);
182
- }
183
- function is_nameable_file(target) {
184
- return !target.includes("*") && !target.includes("?");
185
- }
186
- function is_content_read(label) {
187
- return READ_TOOLS.has(label) || CONTENT_READ_LABELS.has(label);
188
- }
189
- function subject_targets(targets) {
190
- return targets.filter((target) => is_nameable_file(target) && is_subject_file(target)).map((target) => resolved(target));
191
- }
192
- function call_targets(call) {
193
- return subject_targets(time_bundle_call.call_facts(call.name, call.input).targets);
194
- }
195
- function delegation_instant(span) {
196
- return span === void 0 ? hook_decision.NEVER_MS : span.ended_ms;
197
- }
198
- function is_failed_outcome(span) {
199
- return span.outcome === time_spans.FAILED_OUTCOME;
200
- }
201
- function edited_files(spans) {
202
- const written = spans.filter((span) => !is_failed_outcome(span)).flatMap((span) => subject_targets(span.writes));
203
- return new Set(written);
204
- }
205
- function add_all(pending, targets, at_ms) {
206
- for (const target of targets) if (!pending.has(target)) pending.set(target, at_ms);
207
- }
208
- function apply_span(pending, span, edited) {
209
- if (DELEGATION_TOOLS.has(span.label)) {
210
- pending.clear();
211
- return;
212
- }
213
- if (!is_content_read(span.label) || is_failed_outcome(span)) return;
214
- const fresh = subject_targets(span.targets).filter((target) => !edited.has(target));
215
- add_all(pending, fresh, span.ended_ms);
216
- }
217
- function last_delegation_ms(spans) {
218
- return delegation_instant(spans.findLast((span) => DELEGATION_TOOLS.has(span.label)));
219
- }
220
- function pending_after(pending, since_ms) {
221
- return [...pending.values()].filter((at_ms) => at_ms > since_ms).length;
222
- }
223
- function tally_of(text2, since_ms = hook_decision.NEVER_MS) {
224
- const { spans, started_ms } = time_spans.parse_timeline(text2);
225
- const edited = edited_files(spans);
226
- const pending = /* @__PURE__ */ new Map();
227
- for (const span of spans) apply_span(pending, span, edited);
228
- return {
229
- pending: [...pending.keys()],
230
- pending_since: pending_after(pending, since_ms),
231
- reset_ms: last_delegation_ms(spans),
232
- window_start_ms: started_ms,
233
- edited
234
- };
235
- }
236
- function projected_count(pending, call, edited = /* @__PURE__ */ new Set()) {
237
- return (/* @__PURE__ */ new Set([...pending, ...call_targets(call).filter((target) => !edited.has(target))])).size;
238
- }
239
- function is_at_threshold(pending_count) {
240
- return pending_count + 1 >= delegation_policy.INVESTIGATION_FILE_THRESHOLD;
241
- }
242
- function has_cleared_the_disarm(tally, refused_at_ms) {
243
- return tally.reset_ms > refused_at_ms || refused_at_ms < tally.window_start_ms;
244
- }
245
- function is_rearmed(tally, refused_at_ms) {
246
- if (refused_at_ms === hook_decision.NEVER_MS || has_cleared_the_disarm(tally, refused_at_ms)) {
247
- return true;
248
- }
249
- return is_at_threshold(tally.pending_since);
250
- }
251
- function is_unit_transcript(transcript) {
252
- return transcript.split(path.sep).includes(cost_transcript.UNIT_DIRECTORY);
253
- }
254
- function is_unit_run(run) {
255
- return run !== void 0 && is_unit_transcript(run.transcript);
256
- }
257
- function is_refusable_command(call) {
258
- const label = time_shell.bash_label(time_shell.bash_command(call.input));
259
- return CONTENT_READ_LABELS.has(label) && time_batch_guard.is_read_only_call(call);
260
- }
261
- function is_refusable_call(call) {
262
- if (call_targets(call).length === 0) return false;
263
- if (READ_TOOLS.has(call.name)) return true;
264
- return call.name === cost_blocks.BASH_TOOL && is_refusable_command(call);
265
- }
266
- function should_block(text2, call, refused_at_ms, run) {
267
- if (!is_refusable_call(call) || is_unit_run(run)) return false;
268
- const tally = tally_of(text2, refused_at_ms);
269
- if (!is_at_threshold(tally.pending.length)) return false;
270
- return projected_count(tally.pending, call, tally.edited) > tally.pending.length && is_rearmed(tally, refused_at_ms);
271
- }
272
- var EDIT_TARGET_CLASS = "edit targets";
273
- var UNDER_THRESHOLD_CLASS = "under the threshold";
274
- var REFUSED_CLASS = "refused";
275
- var LET_THROUGH_CLASS = "let through";
276
- var READ_CLASSES = [
277
- EDIT_TARGET_CLASS,
278
- UNDER_THRESHOLD_CLASS,
279
- REFUSED_CLASS,
280
- LET_THROUGH_CLASS
281
- ];
282
- var NEVER_REFUSED_LABELS = /* @__PURE__ */ new Set([time_shell.bash_label("sed")]);
283
- function tally_now(replay) {
284
- return {
285
- pending: [...replay.pending.keys()],
286
- pending_since: pending_after(replay.pending, replay.refused_at_ms),
287
- reset_ms: replay.reset_ms,
288
- window_start_ms: replay.window_start_ms,
289
- edited: replay.edited
290
- };
291
- }
292
- function reaches_threshold(replay, targets) {
293
- const added = targets.filter((target) => !replay.pending.has(target));
294
- return added.length > 0 && is_at_threshold(replay.pending.size);
295
- }
296
- function would_refuse(replay, span) {
297
- if (NEVER_REFUSED_LABELS.has(span.label)) return false;
298
- return is_rearmed(tally_now(replay), replay.refused_at_ms);
299
- }
300
- function class_of(replay, span, edited) {
301
- const fresh = subject_targets(span.targets).filter((target) => !edited.has(target));
302
- if (fresh.length === 0) return EDIT_TARGET_CLASS;
303
- if (!reaches_threshold(replay, fresh)) return UNDER_THRESHOLD_CLASS;
304
- return would_refuse(replay, span) ? REFUSED_CLASS : LET_THROUGH_CLASS;
305
- }
306
- function read_class(replay, span, edited) {
307
- if (!is_content_read(span.label)) return void 0;
308
- if (subject_targets(span.targets).length === 0) return void 0;
309
- return class_of(replay, span, edited);
310
- }
311
- function step(replay, span, edited) {
312
- if (DELEGATION_TOOLS.has(span.label)) {
313
- replay.reset_ms = span.ended_ms;
314
- apply_span(replay.pending, span, edited);
315
- return void 0;
316
- }
317
- const found = read_class(replay, span, edited);
318
- if (found === REFUSED_CLASS) replay.refused_at_ms = span.ended_ms;
319
- apply_span(replay.pending, span, edited);
320
- return found;
321
- }
322
- var FIRST_SPAN = 0;
323
- function fresh_replay(spans, edited) {
324
- return {
325
- pending: /* @__PURE__ */ new Map(),
326
- reset_ms: hook_decision.NEVER_MS,
327
- window_start_ms: spans[FIRST_SPAN]?.ended_ms ?? hook_decision.NEVER_MS,
328
- refused_at_ms: hook_decision.NEVER_MS,
329
- edited
330
- };
331
- }
332
- function classified_reads(spans) {
333
- const edited = edited_files(spans);
334
- const replay = fresh_replay(spans, edited);
335
- const reads = [];
336
- for (const [index, span] of spans.entries()) {
337
- const found = step(replay, span, edited);
338
- if (found !== void 0) reads.push({ found, index });
339
- }
340
- return reads;
341
- }
342
- var investigation_reads = {
343
- CONTENT_READ_COMMANDS,
344
- EDIT_TARGET_CLASS,
345
- LET_THROUGH_CLASS,
346
- READ_CLASSES,
347
- REFUSED_CLASS,
348
- UNDER_THRESHOLD_CLASS,
349
- classified_reads,
350
- subject_targets,
351
- DELEGATION_TOOLS,
352
- READ_TOOLS,
353
- REASON,
354
- is_at_threshold,
355
- is_content_read,
356
- is_instruction_document,
357
- is_rearmed,
358
- is_refusable_call,
359
- is_session_artifact,
360
- is_subject_file,
361
- projected_count,
362
- resolved,
363
- should_block,
364
- tally_of
365
- };
366
-
367
- // scripts/delegation/investigation-guard.ts
368
- var SWITCH_ENV_KEY = "JOSH_INVESTIGATION_GUARD";
369
- function should_block2(tail, call, refused_at_ms, run) {
370
- if (lane_guard_policy.is_suppressed_here("investigation")) return false;
371
- return investigation_reads.should_block(tail, call, refused_at_ms, run);
372
- }
373
- var GUARD = hook_decision.create_transcript_guard({
374
- prefix: "josh-investigation-guard-",
375
- switch_key: SWITCH_ENV_KEY,
376
- is_candidate: investigation_reads.is_refusable_call,
377
- should_block: should_block2,
378
- reason: investigation_reads.REASON
379
- });
380
- var investigation_refusal = GUARD.refusal;
381
- var { is_enabled, refusal_path } = GUARD;
382
- var { deny_envelope, load_environment_file, DISABLED_VALUES } = hook_decision;
383
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
384
- if (process.stdin.isTTY) hook_decision.report_no_payload("investigation:guard");
385
- else hook_decision.write_decision(await text(process.stdin), investigation_refusal);
386
- }
387
-
388
- export {
389
- investigation_reads,
390
- SWITCH_ENV_KEY,
391
- investigation_refusal,
392
- is_enabled,
393
- refusal_path,
394
- deny_envelope,
395
- load_environment_file,
396
- DISABLED_VALUES
397
- };
@@ -1,230 +0,0 @@
1
- import {
2
- lane_paths,
3
- stamp_file,
4
- time_density_hook,
5
- time_hook_transcript
6
- } from "./chunk-Q32WETDO.js";
7
- import {
8
- josh_environment_file
9
- } from "./chunk-ITVJ2MKQ.js";
10
-
11
- // scripts/josh/hook-decision.ts
12
- import { z } from "zod";
13
- var payload_schema = z.object({
14
- transcript_path: z.string().min(1),
15
- // **`nullish`, not `optional`.** A payload spelling the absent agent as `null` has to read as "no
16
- // fork"; rejected, it would fail `safeParse` for the whole payload and take the guard off every
17
- // call of the main line, in silence — the failure every other path here is written to avoid.
18
- agent_id: z.string().nullish(),
19
- tool_name: z.string().min(1),
20
- tool_input: z.unknown()
21
- });
22
- var refusal_schema = z.object({ refused_at_ms: z.number() });
23
- var HOOK_EVENT_NAME = "PreToolUse";
24
- var DENY_DECISION = "deny";
25
- var NEVER_MS = 0;
26
- var MISSING_FILE = "ENOENT";
27
- var DISABLED_VALUES = ["off", "0", "false", "no"];
28
- function is_switch_enabled(key) {
29
- return !DISABLED_VALUES.includes((process.env[key] ?? "").trim().toLowerCase());
30
- }
31
- function parse_hook_payload(raw_payload) {
32
- const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
33
- return parsed.success ? parsed.data : void 0;
34
- }
35
- function deny_envelope(reason) {
36
- return JSON.stringify({
37
- hookSpecificOutput: {
38
- hookEventName: HOOK_EVENT_NAME,
39
- permissionDecision: DENY_DECISION,
40
- permissionDecisionReason: reason
41
- }
42
- });
43
- }
44
- function notice_envelope(notice) {
45
- return JSON.stringify({
46
- systemMessage: notice,
47
- hookSpecificOutput: { hookEventName: HOOK_EVENT_NAME, additionalContext: notice }
48
- });
49
- }
50
- function stamp_fault(switch_key) {
51
- return `\u26A0 ${switch_key}: the run is past the limit but the refusal stamp could not be written, so this call was allowed rather than refused. Without the stamp a refusal could repeat and wedge the run. Batch the calls that do not need each other anyway, and check the temp directory is writable.`;
52
- }
53
- function is_missing_file(error) {
54
- if (!(error instanceof Error) || !("code" in error)) return false;
55
- return typeof error.code === "string" && error.code === MISSING_FILE;
56
- }
57
- function error_text(error) {
58
- if (error instanceof Error) return error.message;
59
- return typeof error === "string" ? error : "a value that is not an error";
60
- }
61
- function fault_notice(switch_key, error) {
62
- if (is_missing_file(error)) return void 0;
63
- const detail = error_text(error);
64
- return `\u26A0 ${switch_key}: the guard could not read the run's history, so this call was allowed without being checked \u2014 silence here is not evidence that the run is batching. Cause: ${detail}`;
65
- }
66
- function last_refusal_ms(target) {
67
- const raw = stamp_file.read_stamp_text(target);
68
- if (raw === void 0) return NEVER_MS;
69
- try {
70
- return refusal_schema.parse(JSON.parse(raw)).refused_at_ms;
71
- } catch {
72
- return NEVER_MS;
73
- }
74
- }
75
- function record_refusal(target, now_ms) {
76
- try {
77
- stamp_file.write_stamp(target, { refused_at_ms: now_ms });
78
- return true;
79
- } catch {
80
- return false;
81
- }
82
- }
83
- function create_refusal_stamp(prefix) {
84
- function path(transcript_path) {
85
- return stamp_file.stamp_path(prefix, transcript_path);
86
- }
87
- return { path, last_ms: last_refusal_ms, record: record_refusal };
88
- }
89
- var { load_environment_file } = josh_environment_file;
90
- var NO_OUTCOME = { reason: void 0, notice: void 0, fault: void 0 };
91
- function fire_once(stamp, run, should_fire, switch_key) {
92
- const target = stamp.path(run.transcript);
93
- if (!should_fire(stamp.last_ms(target))) return { fired: false, fault: void 0 };
94
- if (!stamp.record(target, run.now_ms)) return { fired: false, fault: stamp_fault(switch_key) };
95
- return { fired: true, fault: void 0 };
96
- }
97
- function block_outcome(context) {
98
- const { spec, stamp, tail, call, run } = context;
99
- const result = fire_once(
100
- stamp,
101
- run,
102
- (last_fired_ms) => spec.should_block(tail, call, last_fired_ms, run),
103
- spec.switch_key
104
- );
105
- if (result.fired) return { reason: spec.reason, notice: void 0, fault: void 0 };
106
- return { reason: void 0, notice: void 0, fault: result.fault };
107
- }
108
- function notify_outcome(context) {
109
- const { spec, notify_stamp, tail, call, run } = context;
110
- if (notify_stamp === void 0 || spec.notify === void 0) return NO_OUTCOME;
111
- const { notify } = spec;
112
- const result = fire_once(
113
- notify_stamp,
114
- run,
115
- (last_fired_ms) => notify.should_notify(tail, call, last_fired_ms, run),
116
- spec.switch_key
117
- );
118
- if (result.fired) return { reason: void 0, notice: notify.text(call, tail), fault: void 0 };
119
- return { reason: void 0, notice: void 0, fault: result.fault };
120
- }
121
- function is_clear(outcome) {
122
- return outcome.reason === void 0 && outcome.notice === void 0 && outcome.fault === void 0;
123
- }
124
- function guard_reason_for_payload(parts, payload, now_ms) {
125
- const call = { name: payload.tool_name, input: payload.tool_input };
126
- if (!parts.spec.is_candidate(call)) return NO_OUTCOME;
127
- const transcript = time_hook_transcript.transcript_of(payload.transcript_path, payload.agent_id);
128
- const tail = time_density_hook.read_tail(transcript);
129
- const context = { ...parts, tail, call, run: { transcript, now_ms } };
130
- const blocked = block_outcome(context);
131
- if (!is_clear(blocked)) return blocked;
132
- return notify_outcome(context);
133
- }
134
- function guard_outcome(parts, raw_payload, now_ms) {
135
- const payload = parse_hook_payload(raw_payload);
136
- if (payload === void 0 || !is_switch_enabled(parts.spec.switch_key)) return NO_OUTCOME;
137
- return guard_reason_for_payload(parts, payload, now_ms);
138
- }
139
- function create_transcript_guard(spec) {
140
- const stamp = create_refusal_stamp(spec.prefix);
141
- const notify_stamp = spec.notify ? create_refusal_stamp(spec.notify.prefix) : void 0;
142
- const parts = { spec, stamp, notify_stamp };
143
- function is_enabled() {
144
- return is_switch_enabled(spec.switch_key);
145
- }
146
- function refusal_path(transcript_path) {
147
- return stamp.path(transcript_path);
148
- }
149
- function outcome(raw_payload, now_ms = Date.now()) {
150
- try {
151
- return guard_outcome(parts, raw_payload, now_ms);
152
- } catch (error) {
153
- return { reason: void 0, notice: void 0, fault: fault_notice(spec.switch_key, error) };
154
- }
155
- }
156
- function refusal(raw_payload, now_ms = Date.now()) {
157
- return outcome(raw_payload, now_ms).reason;
158
- }
159
- return { is_enabled, outcome, refusal, refusal_path };
160
- }
161
- function write_outcome(raw_payload, outcome) {
162
- load_environment_file();
163
- const { reason, notice, fault } = outcome(raw_payload);
164
- if (reason !== void 0) process.stdout.write(`${deny_envelope(reason)}
165
- `);
166
- else if (notice !== void 0) process.stdout.write(`${notice_envelope(notice)}
167
- `);
168
- else if (fault !== void 0) process.stdout.write(`${notice_envelope(fault)}
169
- `);
170
- }
171
- function write_decision(raw_payload, refusal) {
172
- write_outcome(raw_payload, (raw) => ({
173
- reason: refusal(raw),
174
- notice: void 0,
175
- fault: void 0
176
- }));
177
- }
178
- function report_no_payload(command) {
179
- process.stderr.write(
180
- `${command} reads a Claude Code hook payload on stdin; it is not run by hand.
181
- `
182
- );
183
- }
184
- var hook_decision = {
185
- DISABLED_VALUES,
186
- NEVER_MS,
187
- create_refusal_stamp,
188
- create_transcript_guard,
189
- deny_envelope,
190
- fault_notice,
191
- is_switch_enabled,
192
- load_environment_file,
193
- notice_envelope,
194
- parse_hook_payload,
195
- report_no_payload,
196
- stamp_fault,
197
- write_decision,
198
- write_outcome
199
- };
200
-
201
- // scripts/run/run-issue-number.ts
202
- var ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/u;
203
- var BAD_ISSUE_MESSAGE = "Not an issue number: ";
204
- function require_issue_number(issue) {
205
- if (!ISSUE_NUMBER_PATTERN.test(issue)) throw new Error(`${BAD_ISSUE_MESSAGE}${issue}`);
206
- }
207
- var run_issue_number = { BAD_ISSUE_MESSAGE, ISSUE_NUMBER_PATTERN, require_issue_number };
208
-
209
- // scripts/lane/lane-child-marker.ts
210
- var KEY = "JOSH_LANE_CHILD";
211
- function environment_for(issue) {
212
- run_issue_number.require_issue_number(issue);
213
- return { [KEY]: issue };
214
- }
215
- function marked_issue(source = process.env) {
216
- const value = source[KEY];
217
- if (value === void 0) return void 0;
218
- return run_issue_number.ISSUE_NUMBER_PATTERN.test(value) ? value : void 0;
219
- }
220
- function is_child_of(directory, source = process.env) {
221
- const marked = marked_issue(source);
222
- return marked !== void 0 && marked === lane_paths.lane_issue_of(directory, { ...source });
223
- }
224
- var lane_child_marker = { KEY, env_for: environment_for, is_child_of, marked_issue };
225
-
226
- export {
227
- hook_decision,
228
- run_issue_number,
229
- lane_child_marker
230
- };
@@ -1,68 +0,0 @@
1
- import {
2
- investigation_reads
3
- } from "./chunk-AXQBNFEF.js";
4
- import {
5
- lane_guard_policy
6
- } from "./chunk-I4D3NVUD.js";
7
- import {
8
- hook_decision
9
- } from "./chunk-3PWPYDD2.js";
10
-
11
- // scripts/delegation/investigation-guard.ts
12
- import { text } from "node:stream/consumers";
13
- import { fileURLToPath } from "node:url";
14
- var SWITCH_ENV_KEY = "JOSH_INVESTIGATION_GUARD";
15
- var STAMP_PREFIX = "josh-investigation-guard-";
16
- var NOTICE_STAMP_PREFIX = "josh-investigation-guard-notice-";
17
- function investigation_mode() {
18
- return lane_guard_policy.mode_here("investigation");
19
- }
20
- function should_block(tail, call, refused_at_ms, run) {
21
- if (investigation_mode() !== "refuse") return false;
22
- return investigation_reads.should_block(tail, call, refused_at_ms, run);
23
- }
24
- function should_notify(tail, call, notified_at_ms, run) {
25
- if (investigation_mode() !== "notice") return false;
26
- return investigation_reads.should_block(tail, call, notified_at_ms, run);
27
- }
28
- var NOTICE = `\u{1F4A1} investigation: files read and not edited since the last delegated unit reached the threshold, so the reading from here should go to a unit of its own. This is a notice, not a refusal \u2014 the read proceeds, because a dispatched lane child ends its turn on a denial. Ask \`pnpm josh delegate investigation\`, then brief a unit with what the main line has already concluded and what is left to find out; it returns the conclusion plus its \`file:line\` citations, never the file text. Keep a read in the main line only where this run will edit that file. This recurs on the next accumulation.`;
29
- function notice_text(_call, tail) {
30
- const pending = investigation_reads.tally_of(tail).pending.map((absolute) => investigation_reads.repository_relative(absolute));
31
- return pending.length === 0 ? NOTICE : `${NOTICE} Read and not edited so far: ${pending.join(" ")}.`;
32
- }
33
- var GUARD = hook_decision.create_transcript_guard({
34
- prefix: STAMP_PREFIX,
35
- switch_key: SWITCH_ENV_KEY,
36
- is_candidate: investigation_reads.is_refusable_call,
37
- should_block,
38
- reason: investigation_reads.REASON,
39
- // The lane-child notice fires where the refusal is withheld (kit#2382), on a record of its own so it
40
- // never spends the refusal's stamp.
41
- notify: {
42
- prefix: NOTICE_STAMP_PREFIX,
43
- should_notify,
44
- text: notice_text
45
- }
46
- });
47
- var investigation_refusal = GUARD.refusal;
48
- var investigation_outcome = GUARD.outcome;
49
- var { is_enabled, refusal_path } = GUARD;
50
- var investigation_notice_path = hook_decision.create_refusal_stamp(NOTICE_STAMP_PREFIX).path;
51
- var { deny_envelope, load_environment_file, DISABLED_VALUES } = hook_decision;
52
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
53
- if (process.stdin.isTTY) hook_decision.report_no_payload("investigation:guard");
54
- else hook_decision.write_outcome(await text(process.stdin), investigation_outcome);
55
- }
56
-
57
- export {
58
- SWITCH_ENV_KEY,
59
- NOTICE,
60
- investigation_refusal,
61
- investigation_outcome,
62
- is_enabled,
63
- refusal_path,
64
- investigation_notice_path,
65
- deny_envelope,
66
- load_environment_file,
67
- DISABLED_VALUES
68
- };