safeword 0.72.0 → 0.74.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 (253) hide show
  1. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  2. package/codex-plugin/hooks.json +5 -5
  3. package/codex-plugin/skills/bdd/references/SCENARIOS.md +6 -6
  4. package/codex-plugin/skills/closeout/SKILL.md +20 -7
  5. package/codex-plugin/skills/debug/SKILL.md +19 -3
  6. package/codex-plugin/skills/retro-filer/SKILL.md +1 -1
  7. package/codex-plugin/skills/testing/SKILL.md +20 -0
  8. package/dist/{architecture-GOUJM5NE.js → architecture-XQGXZQRR.js} +7 -6
  9. package/dist/{architecture-GOUJM5NE.js.map → architecture-XQGXZQRR.js.map} +1 -1
  10. package/dist/{architecture-document-KFR4JDUT.js → architecture-document-CTLCH76G.js} +6 -5
  11. package/dist/{architecture-monorepo-QQ2OCQMC.js → architecture-monorepo-XWJN3X5I.js} +4 -3
  12. package/dist/{boundary-J2RW4N3E.js → boundary-I2Z6PZDO.js} +9 -8
  13. package/dist/boundary-I2Z6PZDO.js.map +1 -0
  14. package/dist/{chunk-LX6G2SZC.js → chunk-2D5IR56T.js} +4 -4
  15. package/dist/{chunk-RFP2MSVO.js → chunk-2MI7M2CO.js} +2 -2
  16. package/dist/{chunk-5KUTV6L5.js → chunk-3D6BHVQX.js} +1 -1
  17. package/dist/chunk-3SBTSETS.js +7 -0
  18. package/dist/chunk-3SBTSETS.js.map +1 -0
  19. package/dist/{chunk-F4CA33GP.js → chunk-42RXDQAQ.js} +31 -20
  20. package/dist/chunk-42RXDQAQ.js.map +1 -0
  21. package/dist/{chunk-5GPCAAVW.js → chunk-56BJOCCK.js} +1 -1
  22. package/dist/{chunk-ZQCKTQKJ.js → chunk-5XHVFUX5.js} +2 -2
  23. package/dist/{chunk-PPQOPS6F.js → chunk-6GQX7IJP.js} +2 -2
  24. package/dist/{chunk-UW3BGLRB.js → chunk-6MK7T6BV.js} +1 -1
  25. package/dist/{chunk-GUIZH3NI.js → chunk-6S7CTKGC.js} +2 -2
  26. package/dist/{chunk-X26EJNPZ.js → chunk-7G6OSNIV.js} +1 -1
  27. package/dist/{migrate-codex-plugin-CPLYYCGP.js → chunk-DHX7G27S.js} +434 -150
  28. package/dist/chunk-DHX7G27S.js.map +1 -0
  29. package/dist/{chunk-QPWX5JXI.js → chunk-EWZEO64K.js} +53 -7
  30. package/dist/chunk-EWZEO64K.js.map +1 -0
  31. package/dist/chunk-FJSFM7Y7.js +318 -0
  32. package/dist/chunk-FJSFM7Y7.js.map +1 -0
  33. package/dist/{chunk-I5QEPYVK.js → chunk-FPSBF7F3.js} +16 -130
  34. package/dist/chunk-FPSBF7F3.js.map +1 -0
  35. package/dist/{chunk-2OBVDGB4.js → chunk-FS2LEZBO.js} +1 -1
  36. package/dist/{chunk-7BRCUXTB.js → chunk-G7ZPEVA3.js} +1 -1
  37. package/dist/{chunk-KWBGQ2YZ.js → chunk-JBA7AB6K.js} +6 -6
  38. package/dist/{chunk-QWL47LKR.js → chunk-JBOLNV2L.js} +1 -1
  39. package/dist/{chunk-PGUVVBIN.js → chunk-JDCGOUXS.js} +1 -1
  40. package/dist/chunk-JDCGOUXS.js.map +1 -0
  41. package/dist/{chunk-AF6L253C.js → chunk-K64BTVJ7.js} +4 -4
  42. package/dist/{chunk-MDXMCB37.js → chunk-KULHJBJ6.js} +1 -1
  43. package/dist/chunk-L6XMSCXJ.js +117 -0
  44. package/dist/chunk-L6XMSCXJ.js.map +1 -0
  45. package/dist/{chunk-OWGNCT45.js → chunk-LXUBCIMR.js} +2 -2
  46. package/dist/{chunk-OSBX5BZS.js → chunk-M2FRVQT7.js} +14 -4
  47. package/dist/chunk-M2FRVQT7.js.map +1 -0
  48. package/dist/chunk-N6U2BZ7S.js +632 -0
  49. package/dist/chunk-N6U2BZ7S.js.map +1 -0
  50. package/dist/{chunk-RLH5PLSD.js → chunk-NRTOKMGY.js} +2 -2
  51. package/dist/{chunk-4HWB6QFG.js → chunk-NSK2HI7O.js} +4 -4
  52. package/dist/{chunk-ZFM3XTN3.js → chunk-NYTHQ2B5.js} +3 -3
  53. package/dist/{chunk-QYO5EMNH.js → chunk-O2TTGWG6.js} +3 -3
  54. package/dist/{chunk-TOLJ6T4S.js → chunk-PQCE5GIH.js} +1 -1
  55. package/dist/{chunk-UM7PJKBV.js → chunk-PZTGLQSD.js} +4 -4
  56. package/dist/{chunk-KWOEDO5W.js → chunk-QOIQQY4E.js} +1 -1
  57. package/dist/{chunk-DAFOEHJA.js → chunk-QSLVO4XF.js} +1 -1
  58. package/dist/{chunk-MLEJHDVU.js → chunk-RYDEPCC3.js} +12 -2
  59. package/dist/chunk-RYDEPCC3.js.map +1 -0
  60. package/dist/{chunk-IEBFBHR2.js → chunk-SK6TC4BO.js} +1 -1
  61. package/dist/{chunk-PAC2VLLK.js → chunk-SPK32BMX.js} +2 -2
  62. package/dist/{chunk-PUNN7MZ6.js → chunk-TJ627SKI.js} +3 -3
  63. package/dist/{chunk-X2OHUUNE.js → chunk-U7OZP77P.js} +2 -2
  64. package/dist/{chunk-WPDGHG6D.js → chunk-UAFM77KW.js} +1 -1
  65. package/dist/{chunk-4DGDH7SG.js → chunk-UDLS7BHG.js} +1 -1
  66. package/dist/{chunk-MMSUTN3X.js → chunk-ULY7JQH4.js} +1 -1
  67. package/dist/{chunk-ZESGPJCY.js → chunk-URVJZ4NL.js} +2 -2
  68. package/dist/{chunk-XH6FTCM7.js → chunk-USGSZ4Y4.js} +2 -2
  69. package/dist/{chunk-KG7MFUUQ.js → chunk-UTO5XZ4S.js} +1 -1
  70. package/dist/{chunk-7NZ26QJP.js → chunk-VEIP5Y7K.js} +4 -4
  71. package/dist/{chunk-O5JEWG3M.js → chunk-XHNWNZRM.js} +1 -1
  72. package/dist/{chunk-AKPXZ75V.js → chunk-XQV3MM3G.js} +1 -1
  73. package/dist/{chunk-XIGSW56Z.js → chunk-Y2XB5HIH.js} +119 -21
  74. package/dist/chunk-Y2XB5HIH.js.map +1 -0
  75. package/dist/{chunk-FLMWLQHK.js → chunk-YP2V3YUV.js} +2 -2
  76. package/dist/{chunk-PSKZASFR.js → chunk-Z4ESH6KU.js} +1 -1
  77. package/dist/{cleanup-STJVSD7S.js → cleanup-YBWFEZVV.js} +42 -30
  78. package/dist/cleanup-YBWFEZVV.js.map +1 -0
  79. package/dist/cli.js +177 -73
  80. package/dist/cli.js.map +1 -1
  81. package/dist/{clients-2EXYFMMV.js → clients-3R4XYZVV.js} +4 -3
  82. package/dist/codex-bootstrap-QUL4BIMC.js +125 -0
  83. package/dist/codex-bootstrap-QUL4BIMC.js.map +1 -0
  84. package/dist/{codex-hook-HBEPMPEK.js → codex-hook-AJ6HNSIN.js} +26 -18
  85. package/dist/codex-hook-AJ6HNSIN.js.map +1 -0
  86. package/dist/{codify-L2V7J2GJ.js → codify-6RVSYYKB.js} +9 -8
  87. package/dist/{codify-L2V7J2GJ.js.map → codify-6RVSYYKB.js.map} +1 -1
  88. package/dist/config-37744FRY.js +8 -0
  89. package/dist/{configured-paths-TXRFWRTV.js → configured-paths-O3WBQ3NC.js} +4 -3
  90. package/dist/{contract-BJD62H2W.js → contract-L6J3ZMVZ.js} +3 -1
  91. package/dist/{contract-BJD62H2W.js.map → contract-L6J3ZMVZ.js.map} +1 -1
  92. package/dist/{converge-setup-6WS2RMSG.js → converge-setup-VFKDPZDV.js} +90 -39
  93. package/dist/converge-setup-VFKDPZDV.js.map +1 -0
  94. package/dist/{coordinator-P7SET5EM.js → coordinator-J6R6HHCP.js} +21 -6
  95. package/dist/{coordinator-P7SET5EM.js.map → coordinator-J6R6HHCP.js.map} +1 -1
  96. package/dist/corpus-QCEGFTUQ.js +15 -0
  97. package/dist/{feature-directories-36DL4FAU.js → feature-directories-2MMZPQM5.js} +6 -5
  98. package/dist/{feature-directories-36DL4FAU.js.map → feature-directories-2MMZPQM5.js.map} +1 -1
  99. package/dist/{finalization-3YYUBUTJ.js → finalization-7Q7PAV5J.js} +6 -5
  100. package/dist/{gh-cli-7XMXAKF7.js → gh-cli-4ASCBV6O.js} +3 -2
  101. package/dist/{github-rest-S2INRKNE.js → github-rest-FEBO3WJO.js} +6 -5
  102. package/dist/{github-rest-S2INRKNE.js.map → github-rest-FEBO3WJO.js.map} +1 -1
  103. package/dist/index.js +4 -3
  104. package/dist/{learning-sync-6ESNEZTX.js → learning-sync-XMWOGO72.js} +4 -3
  105. package/dist/{learning-sync-6ESNEZTX.js.map → learning-sync-XMWOGO72.js.map} +1 -1
  106. package/dist/{legacy-global-guidance-JPJBHFMW.js → legacy-global-guidance-Q45EDKB2.js} +5 -4
  107. package/dist/{lint-gherkin-UHMNF5SD.js → lint-gherkin-WRGJQFSQ.js} +8 -7
  108. package/dist/{lint-gherkin-UHMNF5SD.js.map → lint-gherkin-WRGJQFSQ.js.map} +1 -1
  109. package/dist/migrate-codex-plugin-65N3EQFX.js +39 -0
  110. package/dist/{output-DCTUSINZ.js → output-5KEYCOQM.js} +3 -2
  111. package/dist/{plan-RRN2ESJ7.js → plan-GDQ5MLFP.js} +15 -14
  112. package/dist/{plan-RRN2ESJ7.js.map → plan-GDQ5MLFP.js.map} +1 -1
  113. package/dist/presets/typescript/index.js +4 -3
  114. package/dist/profile-BNQL7PTZ.js +24 -0
  115. package/dist/prompt-SCCI7GNE.js +8 -0
  116. package/dist/{remove-GNAT5APA.js → remove-B7R4ACGX.js} +16 -15
  117. package/dist/{remove-GNAT5APA.js.map → remove-B7R4ACGX.js.map} +1 -1
  118. package/dist/retro-M643IMX6.js +3170 -0
  119. package/dist/retro-M643IMX6.js.map +1 -0
  120. package/dist/{retro-draft-spool-OU4YMZQO.js → retro-draft-spool-MAP37TNR.js} +6 -3
  121. package/dist/{retro-extract-E5F5A35R.js → retro-extract-JH7R6GUZ.js} +12 -3
  122. package/dist/{run-HQCZ67WE.js → run-B4I3UOXV.js} +7 -6
  123. package/dist/{run-HQCZ67WE.js.map → run-B4I3UOXV.js.map} +1 -1
  124. package/dist/{self-report-EBTIB7G3.js → self-report-PHAQ6LHB.js} +6 -3
  125. package/dist/{status-ILKQIXSD.js → status-X6FSZJFP.js} +25 -22
  126. package/dist/{status-ILKQIXSD.js.map → status-X6FSZJFP.js.map} +1 -1
  127. package/dist/status-YZIWSG6P.js +19 -0
  128. package/dist/{sync-config-N7U2FXWV.js → sync-config-D7H2UFLO.js} +5 -4
  129. package/dist/{sync-tracker-EMEVBKQS.js → sync-tracker-W2BVBY7K.js} +13 -12
  130. package/dist/{sync-tracker-EMEVBKQS.js.map → sync-tracker-W2BVBY7K.js.map} +1 -1
  131. package/dist/{test-plan-QAQT6OXT.js → test-plan-Q7LOS4P6.js} +6 -5
  132. package/dist/{test-plan-QAQT6OXT.js.map → test-plan-Q7LOS4P6.js.map} +1 -1
  133. package/dist/{ticket-new-Y2QIVBHL.js → ticket-new-USRB2XOT.js} +10 -9
  134. package/dist/{ticket-new-Y2QIVBHL.js.map → ticket-new-USRB2XOT.js.map} +1 -1
  135. package/dist/{ticket-sync-5XRY6Q2Z.js → ticket-sync-EJWYJVLR.js} +5 -4
  136. package/dist/{tracker-map-PAHJEOGE.js → tracker-map-3X2IOQ44.js} +3 -2
  137. package/dist/tracker-sync-LHSE4LYA.js +13 -0
  138. package/dist/tracker-sync-LHSE4LYA.js.map +1 -0
  139. package/package.json +2 -1
  140. package/templates/SAFEWORD.md +1 -1
  141. package/templates/agents/safeword-retro-filer.md +1 -1
  142. package/templates/doc-templates/tripwire-template.md +68 -0
  143. package/templates/guides/retro.md +6 -0
  144. package/templates/guides/self-report-filing.md +5 -5
  145. package/templates/guides/testing-guide.md +81 -0
  146. package/templates/hooks/lib/bash-ledger-writes.ts +0 -4
  147. package/templates/hooks/lib/closeout-binding.ts +29 -6
  148. package/templates/hooks/lib/dependency-readiness.ts +73 -8
  149. package/templates/hooks/lib/process-kill-guard.ts +1 -3
  150. package/templates/hooks/lib/quality.ts +261 -15
  151. package/templates/hooks/lib/retro-draft-spool.ts +30 -6
  152. package/templates/hooks/lib/retro-extract.ts +192 -33
  153. package/templates/hooks/lib/retro-filing-gate.ts +83 -26
  154. package/templates/hooks/lib/retro-nudge.ts +12 -7
  155. package/templates/hooks/lib/self-report.ts +28 -0
  156. package/templates/hooks/lib/shell-segments.ts +10 -2
  157. package/templates/hooks/pre-tool-architecture-stage.ts +13 -4
  158. package/templates/hooks/pre-tool-dependency-readiness.ts +9 -0
  159. package/templates/hooks/prompt-retro-nudge.ts +3 -2
  160. package/templates/hooks/record-skill-invocation.ts +3 -1
  161. package/templates/hooks/session-reply-format.ts +27 -0
  162. package/templates/hooks/stop-quality.ts +9 -1
  163. package/templates/hooks/stop-retro-filing.ts +1 -1
  164. package/templates/hooks/stop-retro.ts +1 -3
  165. package/templates/scripts/closeout-cleanup.ts +229 -50
  166. package/templates/skills/bdd/SCENARIOS.md +6 -6
  167. package/templates/skills/closeout/SKILL.md +20 -7
  168. package/templates/skills/debug/SKILL.md +19 -3
  169. package/templates/skills/retro-filer/SKILL.md +1 -1
  170. package/templates/skills/testing/SKILL.md +20 -0
  171. package/dist/boundary-J2RW4N3E.js.map +0 -1
  172. package/dist/chunk-2MQTOSGG.js +0 -312
  173. package/dist/chunk-2MQTOSGG.js.map +0 -1
  174. package/dist/chunk-F4CA33GP.js.map +0 -1
  175. package/dist/chunk-I5QEPYVK.js.map +0 -1
  176. package/dist/chunk-MLEJHDVU.js.map +0 -1
  177. package/dist/chunk-OSBX5BZS.js.map +0 -1
  178. package/dist/chunk-PGUVVBIN.js.map +0 -1
  179. package/dist/chunk-QPWX5JXI.js.map +0 -1
  180. package/dist/chunk-XIGSW56Z.js.map +0 -1
  181. package/dist/chunk-Y6LUZKTN.js +0 -144
  182. package/dist/chunk-Y6LUZKTN.js.map +0 -1
  183. package/dist/cleanup-STJVSD7S.js.map +0 -1
  184. package/dist/codex-hook-HBEPMPEK.js.map +0 -1
  185. package/dist/config-X5ZFCS6Q.js +0 -7
  186. package/dist/converge-setup-6WS2RMSG.js.map +0 -1
  187. package/dist/corpus-XW3XX3F5.js +0 -14
  188. package/dist/migrate-codex-plugin-CPLYYCGP.js.map +0 -1
  189. package/dist/profile-DM4UNHMN.js +0 -17
  190. package/dist/prompt-OD3EGKOL.js +0 -7
  191. package/dist/retro-XO7CALV4.js +0 -687
  192. package/dist/retro-XO7CALV4.js.map +0 -1
  193. package/dist/status-5DDTQIJU.js +0 -16
  194. package/dist/tracker-sync-P6DLDWJ2.js +0 -12
  195. /package/dist/{architecture-document-KFR4JDUT.js.map → architecture-document-CTLCH76G.js.map} +0 -0
  196. /package/dist/{architecture-monorepo-QQ2OCQMC.js.map → architecture-monorepo-XWJN3X5I.js.map} +0 -0
  197. /package/dist/{chunk-LX6G2SZC.js.map → chunk-2D5IR56T.js.map} +0 -0
  198. /package/dist/{chunk-RFP2MSVO.js.map → chunk-2MI7M2CO.js.map} +0 -0
  199. /package/dist/{chunk-5KUTV6L5.js.map → chunk-3D6BHVQX.js.map} +0 -0
  200. /package/dist/{chunk-5GPCAAVW.js.map → chunk-56BJOCCK.js.map} +0 -0
  201. /package/dist/{chunk-ZQCKTQKJ.js.map → chunk-5XHVFUX5.js.map} +0 -0
  202. /package/dist/{chunk-PPQOPS6F.js.map → chunk-6GQX7IJP.js.map} +0 -0
  203. /package/dist/{chunk-UW3BGLRB.js.map → chunk-6MK7T6BV.js.map} +0 -0
  204. /package/dist/{chunk-GUIZH3NI.js.map → chunk-6S7CTKGC.js.map} +0 -0
  205. /package/dist/{chunk-X26EJNPZ.js.map → chunk-7G6OSNIV.js.map} +0 -0
  206. /package/dist/{chunk-2OBVDGB4.js.map → chunk-FS2LEZBO.js.map} +0 -0
  207. /package/dist/{chunk-7BRCUXTB.js.map → chunk-G7ZPEVA3.js.map} +0 -0
  208. /package/dist/{chunk-KWBGQ2YZ.js.map → chunk-JBA7AB6K.js.map} +0 -0
  209. /package/dist/{chunk-QWL47LKR.js.map → chunk-JBOLNV2L.js.map} +0 -0
  210. /package/dist/{chunk-AF6L253C.js.map → chunk-K64BTVJ7.js.map} +0 -0
  211. /package/dist/{chunk-MDXMCB37.js.map → chunk-KULHJBJ6.js.map} +0 -0
  212. /package/dist/{chunk-OWGNCT45.js.map → chunk-LXUBCIMR.js.map} +0 -0
  213. /package/dist/{chunk-RLH5PLSD.js.map → chunk-NRTOKMGY.js.map} +0 -0
  214. /package/dist/{chunk-4HWB6QFG.js.map → chunk-NSK2HI7O.js.map} +0 -0
  215. /package/dist/{chunk-ZFM3XTN3.js.map → chunk-NYTHQ2B5.js.map} +0 -0
  216. /package/dist/{chunk-QYO5EMNH.js.map → chunk-O2TTGWG6.js.map} +0 -0
  217. /package/dist/{chunk-TOLJ6T4S.js.map → chunk-PQCE5GIH.js.map} +0 -0
  218. /package/dist/{chunk-UM7PJKBV.js.map → chunk-PZTGLQSD.js.map} +0 -0
  219. /package/dist/{chunk-KWOEDO5W.js.map → chunk-QOIQQY4E.js.map} +0 -0
  220. /package/dist/{chunk-DAFOEHJA.js.map → chunk-QSLVO4XF.js.map} +0 -0
  221. /package/dist/{chunk-IEBFBHR2.js.map → chunk-SK6TC4BO.js.map} +0 -0
  222. /package/dist/{chunk-PAC2VLLK.js.map → chunk-SPK32BMX.js.map} +0 -0
  223. /package/dist/{chunk-PUNN7MZ6.js.map → chunk-TJ627SKI.js.map} +0 -0
  224. /package/dist/{chunk-X2OHUUNE.js.map → chunk-U7OZP77P.js.map} +0 -0
  225. /package/dist/{chunk-WPDGHG6D.js.map → chunk-UAFM77KW.js.map} +0 -0
  226. /package/dist/{chunk-4DGDH7SG.js.map → chunk-UDLS7BHG.js.map} +0 -0
  227. /package/dist/{chunk-MMSUTN3X.js.map → chunk-ULY7JQH4.js.map} +0 -0
  228. /package/dist/{chunk-ZESGPJCY.js.map → chunk-URVJZ4NL.js.map} +0 -0
  229. /package/dist/{chunk-XH6FTCM7.js.map → chunk-USGSZ4Y4.js.map} +0 -0
  230. /package/dist/{chunk-KG7MFUUQ.js.map → chunk-UTO5XZ4S.js.map} +0 -0
  231. /package/dist/{chunk-7NZ26QJP.js.map → chunk-VEIP5Y7K.js.map} +0 -0
  232. /package/dist/{chunk-O5JEWG3M.js.map → chunk-XHNWNZRM.js.map} +0 -0
  233. /package/dist/{chunk-AKPXZ75V.js.map → chunk-XQV3MM3G.js.map} +0 -0
  234. /package/dist/{chunk-FLMWLQHK.js.map → chunk-YP2V3YUV.js.map} +0 -0
  235. /package/dist/{chunk-PSKZASFR.js.map → chunk-Z4ESH6KU.js.map} +0 -0
  236. /package/dist/{clients-2EXYFMMV.js.map → clients-3R4XYZVV.js.map} +0 -0
  237. /package/dist/{config-X5ZFCS6Q.js.map → config-37744FRY.js.map} +0 -0
  238. /package/dist/{configured-paths-TXRFWRTV.js.map → configured-paths-O3WBQ3NC.js.map} +0 -0
  239. /package/dist/{corpus-XW3XX3F5.js.map → corpus-QCEGFTUQ.js.map} +0 -0
  240. /package/dist/{finalization-3YYUBUTJ.js.map → finalization-7Q7PAV5J.js.map} +0 -0
  241. /package/dist/{gh-cli-7XMXAKF7.js.map → gh-cli-4ASCBV6O.js.map} +0 -0
  242. /package/dist/{legacy-global-guidance-JPJBHFMW.js.map → legacy-global-guidance-Q45EDKB2.js.map} +0 -0
  243. /package/dist/{output-DCTUSINZ.js.map → migrate-codex-plugin-65N3EQFX.js.map} +0 -0
  244. /package/dist/{profile-DM4UNHMN.js.map → output-5KEYCOQM.js.map} +0 -0
  245. /package/dist/{prompt-OD3EGKOL.js.map → profile-BNQL7PTZ.js.map} +0 -0
  246. /package/dist/{retro-draft-spool-OU4YMZQO.js.map → prompt-SCCI7GNE.js.map} +0 -0
  247. /package/dist/{retro-extract-E5F5A35R.js.map → retro-draft-spool-MAP37TNR.js.map} +0 -0
  248. /package/dist/{self-report-EBTIB7G3.js.map → retro-extract-JH7R6GUZ.js.map} +0 -0
  249. /package/dist/{status-5DDTQIJU.js.map → self-report-PHAQ6LHB.js.map} +0 -0
  250. /package/dist/{sync-config-N7U2FXWV.js.map → status-YZIWSG6P.js.map} +0 -0
  251. /package/dist/{ticket-sync-5XRY6Q2Z.js.map → sync-config-D7H2UFLO.js.map} +0 -0
  252. /package/dist/{tracker-map-PAHJEOGE.js.map → ticket-sync-EJWYJVLR.js.map} +0 -0
  253. /package/dist/{tracker-sync-P6DLDWJ2.js.map → tracker-map-3X2IOQ44.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "safeword",
3
- "version": "0.72.0",
3
+ "version": "0.74.0",
4
4
  "description": "Safe Word workflow guidance and gates for Codex.",
5
5
  "author": {
6
6
  "name": "Arcade AI"
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "bunx --bun safeword@0.72.0 hook codex session-start --plugin-hook",
9
+ "command": "bunx --bun safeword@0.74.0 hook codex session-start --plugin-hook",
10
10
  "timeout": 120,
11
11
  "statusMessage": "Loading Safe Word standing instructions"
12
12
  }
@@ -19,7 +19,7 @@
19
19
  "hooks": [
20
20
  {
21
21
  "type": "command",
22
- "command": "bunx --bun safeword@0.72.0 hook codex pre-tool-use --plugin-hook",
22
+ "command": "bunx --bun safeword@0.74.0 hook codex pre-tool-use --plugin-hook",
23
23
  "timeout": 30,
24
24
  "statusMessage": "Checking Safe Word edit gates"
25
25
  }
@@ -32,7 +32,7 @@
32
32
  "hooks": [
33
33
  {
34
34
  "type": "command",
35
- "command": "bunx --bun safeword@0.72.0 hook codex post-tool-use --plugin-hook",
35
+ "command": "bunx --bun safeword@0.74.0 hook codex post-tool-use --plugin-hook",
36
36
  "timeout": 30,
37
37
  "statusMessage": "Surfacing Safe Word post-tool context"
38
38
  }
@@ -45,7 +45,7 @@
45
45
  "hooks": [
46
46
  {
47
47
  "type": "command",
48
- "command": "bunx --bun safeword@0.72.0 hook codex user-prompt-submit --plugin-hook",
48
+ "command": "bunx --bun safeword@0.74.0 hook codex user-prompt-submit --plugin-hook",
49
49
  "timeout": 30,
50
50
  "statusMessage": "Checking queued Safe Word prompt context"
51
51
  }
@@ -58,7 +58,7 @@
58
58
  "hooks": [
59
59
  {
60
60
  "type": "command",
61
- "command": "bunx --bun safeword@0.72.0 hook codex stop --plugin-hook",
61
+ "command": "bunx --bun safeword@0.74.0 hook codex stop --plugin-hook",
62
62
  "timeout": 600,
63
63
  "statusMessage": "Checking Safe Word stop continuation"
64
64
  }
@@ -18,9 +18,9 @@
18
18
 
19
19
  Save the dimension table to `dimensions.md` in the ticket folder before writing test-definitions.md (the pre-tool hook enforces this for features). For tiny features with one obvious behavioral dimension and no partitioning to enumerate, dimensions.md may instead be a single line `skip: <non-empty reason>`.
20
20
 
21
- ### Scenario saturation
21
+ ### Are the scenarios complete?
22
22
 
23
- Each propose-and-converge turn either surfaces new scenarios or doesn't. When a turn produces no new scenarios → proceed to scenario-gate.
23
+ Ask the user: **Do these scenarios fully describe the intended behavior and important boundaries, or is anything missing?** If their feedback adds scenarios, revise the set and ask again. When they confirm nothing is missing, proceed to scenario-gate.
24
24
 
25
25
  ### Concrete example
26
26
 
@@ -55,7 +55,7 @@ Each propose-and-converge turn either surfaces new scenarios or doesn't. When a
55
55
 
56
56
  **User:** "Looks good, proceed."
57
57
 
58
- **Result:** No new scenarios scenario saturation → proceed to scenario-gate.
58
+ **Result:** The user confirms the intended behavior and important boundaries are fully described → proceed to scenario-gate.
59
59
 
60
60
  ### Two formats: discovery vs saved
61
61
 
@@ -198,11 +198,11 @@ delivery retries on exponential backoff`). IDs are 1-indexed per job and
198
198
 
199
199
  **Entry:** Agent enters `scenario-gate` phase.
200
200
 
201
- Run the **`$safeword:review-spec`** skill — it is the gate procedure (vacuous-pass, AODI, determinism risks, adversarial pass + negative-case, cross-cutting checks, and the findings format). It reads the active ticket's `.feature` source when present, using `test-definitions.md` only as the R/G/R ledger, reports findings, and is re-invokable standalone after scenario edits. Apply its findings, then complete the saturation check and exit below.
201
+ Run the **`$safeword:review-spec`** skill — it is the gate procedure (vacuous-pass, AODI, determinism risks, adversarial pass + negative-case, cross-cutting checks, and the findings format). It reads the active ticket's `.feature` source when present, using `test-definitions.md` only as the R/G/R ledger, reports findings, and is re-invokable standalone after scenario edits. Apply its findings, then complete the plain-language completeness check and exit below.
202
202
 
203
- ### Coverage saturation
203
+ ### Are the reviewed scenarios complete?
204
204
 
205
- If the adversarial pass + user feedback produced new scenarios loop back to define-behavior. If nothing new surfaced done.
205
+ Ask the user: **Do these scenarios now fully cover the intended behavior and important boundaries, or is anything still missing?** If the adversarial pass or user feedback produced new scenarios, loop back to define-behavior. When nothing is missing, the quality gate is complete.
206
206
 
207
207
  ### Scenario Gate Exit
208
208
 
@@ -27,6 +27,9 @@ Collect and report every blocker. Missing, stale, failing, pending, unknown, or
27
27
  ambiguous evidence means **no merge or cleanup**. A merge command's exit status
28
28
  never proves that the pull request is merged.
29
29
 
30
+ Dependency audit is part of this delivery-time verification boundary. Resolve
31
+ its failures before merge while the pull request head can still be changed.
32
+
30
33
  ## 2. Respect merge authority
31
34
 
32
35
  Invocation alone grants no merge authority. Read authority only from the current user request;
@@ -63,13 +66,20 @@ complete only after proving it was the exact planned target. If the pull request
63
66
  is merged, its retrospective is complete, and its exact branch and worktree are
64
67
  already absent, report that the session is already closed.
65
68
 
69
+ The guard records a private, atomic verification receipt in Git's shared common
70
+ directory only after every verification lane passes on a clean exact PR head.
71
+ For 24 hours, that receipt can prove the immutable head when an interrupted
72
+ cleanup must resume from a surviving worktree after the topic worktree is gone.
73
+ A missing, stale, malformed, dirty-state, or wrong-head receipt blocks cleanup.
74
+
66
75
  ## 4. Complete the current session's retrospective
67
76
 
68
77
  After merge is independently confirmed, invoke the cleanup guard in preview
69
78
  mode. Its host hook supplies a short-lived, single-consumer binding to this exact
70
- session (and Cursor transcript). A missing or expired binding fails closed;
71
- there is no newest-session fallback and callers cannot nominate another receipt,
72
- session, transcript, or spool.
79
+ session (and Cursor transcript). Codex Desktop may instead supply its authenticated
80
+ current `CODEX_THREAD_ID`, consistent with SafeWord's other Codex identity bridges.
81
+ A missing or expired binding or identity fails closed; there is no newest-session
82
+ fallback and callers cannot nominate another receipt, session, transcript, or spool.
73
83
 
74
84
  The guard runs `safeword retro run --json` itself and accepts only a
75
85
  successful result whose `data.agent_filing_needed` is `false` and whose derived
@@ -89,10 +99,13 @@ Run the guard from the delivery worktree; preview is the default:
89
99
  bun .safeword/scripts/closeout-cleanup.ts --pr PR_NUMBER
90
100
  ```
91
101
 
92
- The preview reruns the project's verification, build, typecheck, BDD, and
93
- dependency plans and binds the resulting repository state and exact PR identity
94
- to `PLAN_DIGEST`. Report the complete operation list and all blockers. Do not
95
- apply a blocked plan.
102
+ At the exact delivery head, the post-merge preview reruns the project's
103
+ verification, build, typecheck, and BDD plans. It does not rerun dependency audit:
104
+ that changing intelligence is enforced at the delivery-time, pre-merge boundary
105
+ and cannot repair an immutable merged head. After that worktree is gone, preview
106
+ requires its fresh clean-head receipt instead. It binds the resulting repository
107
+ state and exact PR identity to `PLAN_DIGEST`. Report the complete operation list
108
+ and all blockers. Do not apply a blocked plan.
96
109
 
97
110
  With the user's cleanup intent already established by invoking closeout, apply
98
111
  only the unchanged preview:
@@ -185,7 +185,23 @@ it('handles empty input without crashing', () => {
185
185
  - ONE change
186
186
  - No "while I'm here" improvements
187
187
 
188
- #### 3. Verify
188
+ #### 3. Root Cause Is Upstream? Ship A Tripwire With The Workaround
189
+
190
+ When the root cause lives in a dependency and the fix is a workaround — a
191
+ version pin, an avoided API, a reimplemented helper — the workaround becomes
192
+ removable on _their_ release, which nothing in this repo will ever announce.
193
+ Comments and tickets do not reach whoever holds the code then.
194
+
195
+ Add a test asserting the dependency is still pinned at the last known-bad
196
+ version, with a header naming what to delete when it fails. Assert the pin,
197
+ not the bug: a test that reproduces the bug goes green when upstream fixes
198
+ it, silently, leaving the dead workaround behind.
199
+
200
+ Warranted when removal depends on someone else's release _and_ the failure
201
+ mode is silent. Rules: `.safeword/guides/testing-guide.md` → "Upstream
202
+ Workaround Tripwires". Scaffold: `.safeword/templates/tripwire-template.md`.
203
+
204
+ #### 4. Verify
189
205
 
190
206
  - [ ] New test passes
191
207
  - [ ] Existing tests still pass
@@ -198,14 +214,14 @@ Examples:
198
214
  - **Next:** commit with `fix(auth): release pool connection in error path`, mark ticket 234 done.
199
215
  - **Next:** commit the fix, then open a ticket for the unrelated logging gap surfaced at `src/auth.ts:88`.
200
216
 
201
- #### 4. If Fix Doesn't Work
217
+ #### 5. If Fix Doesn't Work
202
218
 
203
219
  | Fix attempts | Action |
204
220
  | ------------ | ---------------------------------------- |
205
221
  | 1-2 | Return to Phase 1 with new information |
206
222
  | 3+ | STOP - Question architecture (see below) |
207
223
 
208
- #### 5. After 3+ Failed Fixes: Question Architecture
224
+ #### 6. After 3+ Failed Fixes: Question Architecture
209
225
 
210
226
  Pattern indicating architectural problem:
211
227
 
@@ -40,7 +40,7 @@ the host project.
40
40
  exhaustive reads (`list_issues`, `issue_read`) strip HTML comments and can
41
41
  never see a marker. File anyway — a duplicate is recoverable, whereas a
42
42
  finding you decline to file is lost, since this path runs exactly when the
43
- code-owned REST path could not authenticate (#834). But never merge on a
43
+ code-owned path left the draft unfiled (#834, #1900). But never merge on a
44
44
  resemblance: a matching surface or similar title is weak identity that drifts
45
45
  between sessions (#631), and commenting-and-acking on it binds the signature
46
46
  to that issue permanently while discarding the draft body. Only a confirmed
@@ -300,11 +300,31 @@ it('preserves user input after validation error');
300
300
 
301
301
  ---
302
302
 
303
+ ## Working Around An Upstream Bug? Ship A Tripwire
304
+
305
+ When you pin a dependency to dodge someone else's bug, the workaround is
306
+ temporary by intent and permanent in practice — comments and tickets do not
307
+ reach whoever eventually holds the code.
308
+
309
+ Write a test that asserts the dependency is **still pinned at the last
310
+ known-bad version**, with a file header naming what to delete when it fails.
311
+ The next upgrade turns CI red in front of the person doing the upgrade.
312
+
313
+ Assert the pin, never the bug — a test that reproduces the bug goes green when
314
+ upstream fixes it, silently, leaving the dead workaround behind.
315
+
316
+ Warranted when removal depends on someone else's release _and_ the failure
317
+ mode is silent. Rules: `.safeword/guides/testing-guide.md` → "Upstream
318
+ Workaround Tripwires". Scaffold: `.safeword/templates/tripwire-template.md`.
319
+
320
+ ---
321
+
303
322
  ## Quick Reference
304
323
 
305
324
  | Need | Action |
306
325
  | -------------------------------- | ------------------------------------------------- |
307
326
  | Full test type selection guide | `.safeword/guides/testing-guide.md` |
327
+ | Upstream-workaround tripwire | `.safeword/templates/tripwire-template.md` |
308
328
  | Smoke/live/release lane guidance | `.safeword/guides/verification-lanes-guide.md` |
309
329
  | LLM eval design guide | `.safeword/guides/llm-evals-guide.md` |
310
330
  | Test definition template (BDD) | `.safeword/templates/test-definitions-feature.md` |
@@ -4,27 +4,28 @@ import {
4
4
  planSelfHealProject,
5
5
  selfHealProject,
6
6
  selfHealProjectPreservingProse
7
- } from "./chunk-UM7PJKBV.js";
7
+ } from "./chunk-PZTGLQSD.js";
8
8
  import {
9
9
  discoverUnreadableWorkspaces,
10
10
  extractMonorepoArchitectureSnapshot
11
- } from "./chunk-FLMWLQHK.js";
11
+ } from "./chunk-YP2V3YUV.js";
12
12
  import {
13
13
  error,
14
14
  success,
15
15
  warn
16
- } from "./chunk-DAFOEHJA.js";
16
+ } from "./chunk-QSLVO4XF.js";
17
17
  import {
18
18
  GENERATED_ARCHITECTURE_FILENAME,
19
19
  isArchitectureDocumentEnforcementEnabled,
20
20
  readConfiguredPath,
21
21
  resolveGeneratedArchitecturePath,
22
22
  toRepoDirectory
23
- } from "./chunk-RFP2MSVO.js";
23
+ } from "./chunk-2MI7M2CO.js";
24
24
  import {
25
25
  readJson,
26
26
  writeJson
27
- } from "./chunk-X26EJNPZ.js";
27
+ } from "./chunk-7G6OSNIV.js";
28
+ import "./chunk-3SBTSETS.js";
28
29
 
29
30
  // src/commands/architecture.ts
30
31
  import { execFileSync } from "child_process";
@@ -636,4 +637,4 @@ export {
636
637
  architectureStage,
637
638
  architectureStaged
638
639
  };
639
- //# sourceMappingURL=architecture-GOUJM5NE.js.map
640
+ //# sourceMappingURL=architecture-XQGXZQRR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/architecture.ts"],"sourcesContent":["/**\n * `safeword project architecture` — refresh the generated architecture state document(s)\n * (ticket QD5DTT, Slice 1; FPV0E4, Slice 2; XG9SFP, Slice 3).\n *\n * Default mode is a thin CLI entry over `selfHealProject`: re-extracts the\n * skeleton and reconciles prose markers for every node — one doc for a\n * single-repo, or a derived root index plus colocated per-package leaf docs for a\n * monorepo. The SessionStart hook shells out to it so the heal logic lives in one\n * place.\n *\n * `--check` is the CI backstop: a dry-run that writes nothing and exits non-zero\n * when ANY node is stale (a would-change action), so a silently-wrong doc cannot\n * reach the main branch.\n *\n * `--stage` is the commit-time auto-fix: export the staged git index, regenerate\n * every stale node from that deterministic tree, and `git add` each into the\n * in-flight commit, so unrelated worktree changes cannot contaminate it. Never\n * blocks (always exits zero). `--staged` exposes the same deterministic source\n * without automatically adding the generated docs. The commit and CI gates\n * (`--stage` and `--check`) honor the per-project opt-out\n * (`architectureDocEnforcement: false`); explicit generation modes still run.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n copyFileSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport nodePath from 'node:path';\nimport process from 'node:process';\n\nimport {\n isSafewordOwned,\n isWouldChangeAction,\n planSelfHealProject,\n selfHealProject,\n selfHealProjectPreservingProse,\n type SelfHealResult,\n} from '../utils/architecture-document.js';\nimport {\n discoverUnreadableWorkspaces,\n extractMonorepoArchitectureSnapshot,\n} from '../utils/architecture-monorepo.js';\nimport {\n GENERATED_ARCHITECTURE_FILENAME,\n isArchitectureDocumentEnforcementEnabled,\n readConfiguredPath,\n resolveGeneratedArchitecturePath,\n} from '../utils/configured-paths.js';\nimport { readJson, writeJson } from '../utils/fs.js';\nimport { error, success, warn } from '../utils/output.js';\nimport { toRepoDirectory } from '../utils/repo-path.js';\n\nconst ARCHITECTURE_SOURCE_INDEX_ENV = 'SAFEWORD_ARCHITECTURE_SOURCE_INDEX';\nconst ARCHITECTURE_KEEP_MATERIALIZED_ENV = 'SAFEWORD_ARCHITECTURE_KEEP_MATERIALIZED';\n\nexport interface ArchitectureReporter {\n readonly success: (message: string) => void;\n readonly warn: (message: string) => void;\n readonly error: (message: string) => void;\n}\n\nexport interface ArchitectureModeOutcome {\n readonly results: readonly SelfHealResult[];\n readonly stagedPaths: readonly string[];\n readonly stageFailures: readonly string[];\n readonly failed: boolean;\n readonly autoStageAvailable: boolean;\n}\n\nconst defaultReporter: ArchitectureReporter = { success, warn, error };\n\nexport async function architecture(\n cwd: string = process.cwd(),\n options: { check?: boolean; stage?: boolean; staged?: boolean } = {},\n): Promise<void> {\n if (options.check) {\n await architectureCheck(cwd);\n return;\n }\n if (options.stage) {\n await architectureStage(cwd);\n return;\n }\n if (options.staged) {\n await architectureStaged(cwd);\n return;\n }\n\n generateFromWorktree(cwd);\n}\n\nfunction generateFromWorktree(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): SelfHealResult[] {\n const results = selfHealProject(cwd);\n for (const result of results) {\n reporter.success(`Architecture state document ${result.action}: ${result.path}`);\n }\n warnUnreadableWorkspaces(cwd, reporter);\n return results;\n}\n\n/**\n * Print a non-blocking warning for each workspace manager that is present at the root but\n * unparseable (ticket UWP4XK, GitHub #558) — a malformed `go.work`, an unreadable Cargo\n * `[workspace] members`, a flow-style `pnpm-workspace.yaml`. Advisory only: it never\n * changes a command's exit code. Surfaced in every mode (default/`--check`/`--stage`),\n * independent of `architectureDocEnforcement`, because coverage honesty is not enforcement\n * — the architecture map silently omitting a whole language is wrong regardless of opt-out.\n */\nfunction warnUnreadableWorkspaces(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): void {\n for (const workspace of discoverUnreadableWorkspaces(cwd)) {\n reporter.warn(\n `Workspace config present but unreadable: ${workspace.config} (${workspace.manager}). Its packages may be missing from the architecture doc — fix the config and re-run \\`safeword project architecture\\`. (Advisory; nothing is blocked.)`,\n );\n }\n}\n\n/**\n * Commit-time auto-fix. Regenerates every stale node from the staged git index\n * and stages it into the in-flight commit; leaves current/`noop`/foreign nodes\n * untouched. Never blocks — git failures are swallowed so the commit proceeds.\n */\nexport function architectureStage(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): Promise<ArchitectureModeOutcome> {\n let results: readonly SelfHealResult[] = [];\n const stagedPaths: string[] = [];\n const stageFailures: string[] = [];\n let autoStageAvailable = true;\n try {\n if (!isArchitectureDocumentEnforcementEnabled(cwd)) {\n warnUnreadableWorkspaces(cwd, reporter);\n reporter.success(\n 'Architecture doc enforcement is opted out (architectureDocEnforcement: false).',\n );\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n }\n\n const gitContext = resolveGitContext(cwd);\n if (gitContext === undefined) {\n autoStageAvailable = false;\n reporter.warn(\n 'No Git worktree found; generated from the worktree instead without auto-staging.',\n );\n results = generateFromWorktree(cwd, reporter);\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n }\n\n withGitIndexSnapshot(cwd, gitContext, snapshotDirectory => {\n warnUnreadableWorkspaces(snapshotDirectory, reporter);\n const materialized = materializeIndexResults(\n cwd,\n snapshotDirectory,\n 'mutations-only',\n reporter,\n );\n results = materialized.results;\n const changed = materialized.results.filter(result => isWouldChangeAction(result.action));\n if (changed.length === 0) {\n if (materialized.skippedForeignCount === 0) {\n reporter.success('Architecture docs need no change.');\n } else {\n const ownership = `${materialized.skippedForeignCount} ${\n materialized.skippedForeignCount === 1 ? 'document is' : 'documents are'\n } not Safeword-owned`;\n reporter.success(`Architecture docs left unchanged (${ownership}).`);\n }\n } else {\n for (const result of changed) {\n const failure = stageMaterializedDocument(cwd, result, reporter);\n const relativePath = nodePath.relative(cwd, result.path);\n if (failure === undefined) stagedPaths.push(relativePath);\n else stageFailures.push(relativePath);\n }\n }\n });\n warnExcludedWorktreeInputs(cwd, reporter);\n } catch (error_) {\n autoStageAvailable = false;\n reporter.warn(\n `Could not complete staged-tree architecture generation; nothing was auto-staged. CI will verify freshness. Cause: ${errorMessage(error_)}`,\n );\n }\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n}\n\ninterface WorktreeRecoveryCopy {\n directory: string;\n path: string;\n}\n\nfunction persistWorktreeRecoveryCopy(destination: string, content: string): WorktreeRecoveryCopy {\n const directory = mkdtempSync(nodePath.join(tmpdir(), 'safeword-architecture-recovery-'));\n const path = nodePath.join(directory, `${nodePath.basename(destination)}.recovery`);\n try {\n writeFileSync(path, content, { mode: 0o600 });\n return { directory, path };\n } catch (error_) {\n rmSync(directory, { recursive: true, force: true });\n throw error_;\n }\n}\n\nfunction restoreWorktreeAfterStaging(\n cwd: string,\n result: MaterializedIndexResult,\n recoveryCopy: WorktreeRecoveryCopy | undefined,\n staged: boolean,\n reporter: ArchitectureReporter,\n): void {\n if (\n result.restoreWorktreeContent === undefined ||\n process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] === '1'\n ) {\n return;\n }\n try {\n replaceArchitectureDocumentContent(result.restoreWorktreeContent, result.path, cwd);\n if (recoveryCopy !== undefined) {\n rmSync(recoveryCopy.directory, { recursive: true, force: true });\n }\n reporter.warn(`Preserved unstaged worktree architecture edits: ${result.path}`);\n } catch (error_) {\n reporter.warn(\n `Architecture doc ${staged ? 'was staged' : 'was not staged'} but unstaged worktree edits could not be restored: ${result.path}. Recovery copy: ${recoveryCopy?.path ?? 'unavailable'}. Cause: ${errorMessage(error_)}`,\n );\n }\n}\n\nfunction stageMaterializedDocument(\n cwd: string,\n result: MaterializedIndexResult,\n reporter: ArchitectureReporter,\n): string | undefined {\n const shouldRestore =\n result.restoreWorktreeContent !== undefined &&\n process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] !== '1';\n let recoveryCopy: WorktreeRecoveryCopy | undefined;\n let staged = false;\n try {\n if (shouldRestore && result.restoreWorktreeContent !== undefined) {\n recoveryCopy = persistWorktreeRecoveryCopy(result.path, result.restoreWorktreeContent);\n }\n const stageFailure = stageDocument(cwd, result);\n if (stageFailure === undefined) {\n staged = true;\n reporter.success(`Architecture doc ${result.action} and staged: ${result.path}`);\n } else {\n reporter.warn(\n `Architecture doc ${result.action} but could not be staged: ${result.path}. Cause: ${stageFailure}`,\n );\n }\n return stageFailure;\n } finally {\n restoreWorktreeAfterStaging(cwd, result, recoveryCopy, staged, reporter);\n }\n}\n\n/**\n * Explicit deterministic generation mode. It uses the same index snapshot as\n * commit-time auto-staging but leaves the index untouched so developers can\n * inspect the result before choosing what to stage.\n */\nexport function architectureStaged(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): Promise<ArchitectureModeOutcome> {\n let results: readonly SelfHealResult[] = [];\n try {\n const gitContext = resolveGitContext(cwd);\n if (gitContext === undefined) {\n reporter.warn('No Git worktree found; generated from the worktree instead.');\n results = generateFromWorktree(cwd, reporter);\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: false,\n autoStageAvailable: false,\n });\n }\n\n withGitIndexSnapshot(cwd, gitContext, snapshotDirectory => {\n warnUnreadableWorkspaces(snapshotDirectory, reporter);\n const materialized = materializeIndexResults(\n cwd,\n snapshotDirectory,\n 'restore-staged-tree',\n reporter,\n );\n results = materialized.results;\n for (const result of materialized.results) {\n reporter.success(`Architecture state document ${result.action}: ${result.path}`);\n }\n });\n warnExcludedWorktreeInputs(cwd, reporter);\n } catch (error_) {\n reporter.error(\n `Could not complete staged-tree architecture generation; inspect the worktree before retrying. Cause: ${errorMessage(error_)}`,\n );\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: true,\n autoStageAvailable: true,\n });\n }\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: false,\n autoStageAvailable: true,\n });\n}\n\n/**\n * Export the stage-zero index into an isolated directory and remove it after\n * the caller finishes. `git checkout-index` reads only the index: unstaged and\n * untracked worktree files never enter the architecture extractor.\n */\nfunction withGitIndexSnapshot<T>(\n cwd: string,\n gitContext: GitContext,\n useSnapshot: (directory: string) => T,\n): T {\n const snapshotDirectory = mkdtempSync(nodePath.join(tmpdir(), 'safeword-architecture-index-'));\n const sourceIndexFile = process.env[ARCHITECTURE_SOURCE_INDEX_ENV];\n const sourceIndexEnvironment =\n sourceIndexFile === undefined ? undefined : { ...process.env, GIT_INDEX_FILE: sourceIndexFile };\n try {\n assertNoGitlinks(gitContext, sourceIndexEnvironment);\n execFileSync(\n 'git',\n [\n 'checkout-index',\n '--all',\n '--force',\n '--ignore-skip-worktree-bits',\n `--prefix=${snapshotDirectory}${nodePath.sep}`,\n ],\n {\n cwd: gitContext.rootDirectory,\n ...(sourceIndexEnvironment && { env: sourceIndexEnvironment }),\n stdio: 'ignore',\n },\n );\n const snapshotProjectDirectory = nodePath.join(\n snapshotDirectory,\n gitContext.projectRelativeDirectory,\n );\n prepareSnapshotProjectRoot(cwd, snapshotProjectDirectory);\n return useSnapshot(snapshotProjectDirectory);\n } finally {\n rmSync(snapshotDirectory, { recursive: true, force: true });\n }\n}\n\nconst GITLINK_MODE_PREFIX = '160000 ';\n\n/** Refuse a staged tree whose pinned submodule contents cannot be materialized safely. */\nfunction assertNoGitlinks(\n gitContext: GitContext,\n sourceIndexEnvironment?: NodeJS.ProcessEnv,\n): void {\n const pathArguments =\n gitContext.projectRelativeDirectory === '' ? [] : [gitContext.projectRelativeDirectory];\n const entries = execFileSync(\n 'git',\n ['ls-files', '--stage', '-z', '--full-name', '--', ...pathArguments],\n {\n cwd: gitContext.rootDirectory,\n encoding: 'utf8',\n ...(sourceIndexEnvironment && { env: sourceIndexEnvironment }),\n stdio: ['ignore', 'pipe', 'ignore'],\n },\n )\n .split('\\0')\n .filter(entry => entry.startsWith(GITLINK_MODE_PREFIX));\n if (entries.length === 0) return;\n\n const paths = entries.map(entry => entry.slice(entry.indexOf('\\t') + 1));\n throw new Error(\n `Staged-tree architecture generation does not support submodule gitlinks: ${paths.join(', ')}. Run \\`safeword project architecture\\` from the materialized worktree, or remove the gitlink from the staged tree before retrying.`,\n );\n}\n\ninterface GitContext {\n rootDirectory: string;\n projectRelativeDirectory: string;\n}\n\n/** Resolve the invocation directory against Git's repository root. */\nfunction resolveGitContext(cwd: string): GitContext | undefined {\n let rootDirectory: string;\n try {\n rootDirectory = execFileSync('git', ['rev-parse', '--show-toplevel'], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error('Git executable is unavailable.', { cause: error_ });\n }\n return undefined;\n }\n if (rootDirectory.length === 0) return undefined;\n\n const canonicalRoot = realpathSync(rootDirectory);\n const canonicalProject = realpathSync(cwd);\n const projectRelativeDirectory = nodePath.relative(canonicalRoot, canonicalProject);\n if (\n nodePath.isAbsolute(projectRelativeDirectory) ||\n projectRelativeDirectory === '..' ||\n projectRelativeDirectory.startsWith(`..${nodePath.sep}`)\n ) {\n throw new Error('The architecture project directory is outside the Git worktree.');\n }\n return { rootDirectory: canonicalRoot, projectRelativeDirectory };\n}\n\n/**\n * Keep a configured project root inside the exported tree before the healer\n * can write through it. Absolute repo-contained paths are remapped into the\n * snapshot; lexical escapes and physical symlink escapes are rejected.\n */\nfunction prepareSnapshotProjectRoot(cwd: string, snapshotDirectory: string): void {\n const configuredRoot = readConfiguredPath(snapshotDirectory, 'projectRoot');\n if (configuredRoot === undefined) return;\n\n const repoRelativeRoot = toRepoDirectory(cwd, configuredRoot);\n if (repoRelativeRoot === undefined) {\n throw new Error('The staged projectRoot resolves outside the repository.');\n }\n assertPhysicalContainment(snapshotDirectory, nodePath.join(snapshotDirectory, repoRelativeRoot));\n if (!nodePath.isAbsolute(configuredRoot)) return;\n\n rewriteSnapshotProjectRoot(snapshotDirectory, repoRelativeRoot);\n}\n\nfunction rewriteSnapshotProjectRoot(snapshotDirectory: string, repoRelativeRoot: string): void {\n const configPath = nodePath.join(snapshotDirectory, '.safeword', 'config.json');\n const config = readJson(configPath);\n if (config === undefined || typeof config !== 'object' || config === null) return;\n const paths = (config as { paths?: unknown }).paths;\n if (paths === undefined || typeof paths !== 'object' || paths === null) return;\n writeJson(configPath, {\n ...config,\n paths: {\n ...paths,\n projectRoot: repoRelativeRoot === '' ? '.' : repoRelativeRoot,\n },\n });\n}\n\n/**\n * Resolve the nearest existing ancestor so non-existent destination leaves are\n * accepted, while any existing symlink component must resolve inside the\n * allowed root. A dangling symlink is rejected because its physical target\n * cannot be proven safe.\n */\nfunction assertPhysicalContainment(rootDirectory: string, candidatePath: string): void {\n if (toRepoDirectory(rootDirectory, candidatePath) === undefined) {\n throw new Error('The architecture path lexically escapes its allowed root.');\n }\n\n let existingAncestor = candidatePath;\n for (;;) {\n try {\n lstatSync(existingAncestor);\n break;\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code !== 'ENOENT') throw error_;\n const parent = nodePath.dirname(existingAncestor);\n if (parent === existingAncestor) throw error_;\n existingAncestor = parent;\n }\n }\n\n const canonicalRoot = realpathSync(rootDirectory);\n const canonicalAncestor = realpathSync(existingAncestor);\n if (toRepoDirectory(canonicalRoot, canonicalAncestor) === undefined) {\n throw new Error('The architecture path physically escapes its allowed root.');\n }\n}\n\n/** Validate every path selfHealProject may write before allowing its first write. */\nfunction assertSnapshotHealTargetsContained(snapshotDirectory: string): void {\n const { leaves } = extractMonorepoArchitectureSnapshot(snapshotDirectory);\n const targets = [\n resolveGeneratedArchitecturePath(snapshotDirectory),\n ...leaves.map(leaf => nodePath.join(leaf.dir, GENERATED_ARCHITECTURE_FILENAME)),\n ];\n for (const target of targets) {\n assertPhysicalContainment(snapshotDirectory, target);\n }\n}\n\n/**\n * Replace through a fresh inode so an existing hard-linked destination cannot\n * mutate another directory entry. The temporary file shares the destination\n * directory, allowing rename to atomically replace symlinks and hard links.\n */\nfunction replaceArchitectureDocumentWith(\n destination: string,\n allowedRoot: string,\n writeTemporaryFile: (path: string) => void,\n): void {\n const destinationDirectory = nodePath.dirname(destination);\n assertPhysicalContainment(allowedRoot, destination);\n mkdirSync(destinationDirectory, { recursive: true });\n\n // Prefer the OS temp root when it is on the destination filesystem: this\n // keeps crash litter outside the repository while preserving atomic rename.\n // Cross-device rename is not atomic, so fall back to an adjacent directory\n // only when the filesystems differ.\n let temporaryDirectory = mkdtempSync(\n nodePath.join(tmpdir(), 'safeword-architecture-replacement-'),\n );\n if (lstatSync(temporaryDirectory).dev !== lstatSync(destinationDirectory).dev) {\n rmSync(temporaryDirectory, { recursive: true, force: true });\n temporaryDirectory = mkdtempSync(\n nodePath.join(destinationDirectory, '.safeword-architecture-'),\n );\n }\n try {\n const temporaryPath = nodePath.join(temporaryDirectory, nodePath.basename(destination));\n writeTemporaryFile(temporaryPath);\n renameSync(temporaryPath, destination);\n } finally {\n rmSync(temporaryDirectory, { recursive: true, force: true });\n }\n}\n\nfunction replaceArchitectureDocument(\n source: string,\n destination: string,\n allowedRoot: string,\n): void {\n replaceArchitectureDocumentWith(destination, allowedRoot, temporaryPath => {\n copyFileSync(source, temporaryPath);\n });\n}\n\nfunction replaceArchitectureDocumentContent(\n content: string,\n destination: string,\n allowedRoot: string,\n): void {\n replaceArchitectureDocumentWith(destination, allowedRoot, temporaryPath => {\n writeFileSync(temporaryPath, content);\n });\n}\n\ntype IndexMaterializationMode = 'mutations-only' | 'restore-staged-tree';\n\ninterface IndexMaterializationPolicy {\n renderUnchanged: boolean;\n preservePriorStructure: boolean;\n writeUnchanged: boolean;\n captureDivergentContent: boolean;\n skipForeignDestinations: boolean;\n}\n\ninterface MaterializedIndexResult extends SelfHealResult {\n restoreWorktreeContent?: string;\n}\n\ninterface MaterializedIndexOutcome {\n results: MaterializedIndexResult[];\n skippedForeignCount: number;\n}\n\ntype WorktreeDocumentState =\n | { existed: false }\n | {\n existed: true;\n content: string;\n };\n\ninterface IndexMaterializationPlan {\n result: SelfHealResult;\n destination: string;\n shouldWrite: boolean;\n skippedForeign?: boolean;\n priorWorktreeState?: WorktreeDocumentState;\n restoreWorktreeContent?: string;\n}\n\n/**\n * Heal inside the index snapshot, then copy only generated mutations to their\n * matching worktree paths. Returned paths always name the real worktree files.\n */\nfunction materializeIndexResults(\n cwd: string,\n snapshotDirectory: string,\n mode: IndexMaterializationMode,\n reporter: ArchitectureReporter = defaultReporter,\n): MaterializedIndexOutcome {\n assertSnapshotHealTargetsContained(snapshotDirectory);\n const policy = indexMaterializationPolicy(mode);\n const plans = planIndexMaterializations(cwd, snapshotDirectory, policy);\n preflightIndexMaterializations(cwd, plans, policy, reporter);\n\n const attemptedPlans: IndexMaterializationPlan[] = [];\n try {\n for (const plan of plans) {\n if (!plan.shouldWrite) continue;\n attemptedPlans.push(plan);\n replaceArchitectureDocument(plan.result.path, plan.destination, cwd);\n }\n } catch (materializationError) {\n const rollbackErrors = restoreMaterializationPlans(cwd, attemptedPlans);\n if (rollbackErrors.length > 0) {\n throw new AggregateError(\n [materializationError, ...rollbackErrors],\n 'Architecture materialization failed and one or more worktree documents could not be restored.',\n { cause: materializationError },\n );\n }\n throw materializationError;\n }\n\n return {\n results: plans\n .filter(plan => !plan.skippedForeign)\n .map(({ result, destination, restoreWorktreeContent }) => ({\n action: result.action,\n path: destination,\n restoreWorktreeContent,\n })),\n skippedForeignCount: plans.filter(plan => plan.skippedForeign).length,\n };\n}\n\nfunction planIndexMaterializations(\n cwd: string,\n snapshotDirectory: string,\n policy: IndexMaterializationPolicy,\n): IndexMaterializationPlan[] {\n return selfHealProjectPreservingProse(snapshotDirectory, cwd, {\n renderUnchanged: policy.renderUnchanged,\n preservePriorStructure: policy.preservePriorStructure,\n }).map(result => {\n const relativePath = nodePath.relative(snapshotDirectory, result.path);\n if (\n relativePath === '' ||\n nodePath.isAbsolute(relativePath) ||\n relativePath === '..' ||\n relativePath.startsWith(`..${nodePath.sep}`)\n ) {\n throw new Error('Generated architecture path escaped the git index snapshot.');\n }\n\n return {\n result,\n destination: nodePath.join(cwd, relativePath),\n shouldWrite:\n isWouldChangeAction(result.action) ||\n (policy.writeUnchanged && result.action === 'unchanged'),\n };\n });\n}\n\n/**\n * Validate and snapshot every destination before replacing the first one. A\n * later unsafe or unreadable leaf must not leave an earlier root half-applied.\n */\nfunction preflightIndexMaterializations(\n cwd: string,\n plans: IndexMaterializationPlan[],\n policy: IndexMaterializationPolicy,\n reporter: ArchitectureReporter,\n): void {\n for (const plan of plans) {\n if (!plan.shouldWrite) continue;\n assertPhysicalContainment(cwd, plan.destination);\n plan.priorWorktreeState = readWorktreeDocumentState(plan.destination);\n if (plan.priorWorktreeState.existed && !isSafewordOwned(plan.priorWorktreeState.content)) {\n if (policy.skipForeignDestinations) {\n plan.skippedForeign = true;\n plan.shouldWrite = false;\n reporter.warn(\n `Architecture document is not owned by Safeword and was left unchanged: ${plan.destination}`,\n );\n continue;\n }\n throw new Error(\n `Architecture document is not owned by Safeword and was left unchanged: ${plan.destination}`,\n );\n }\n plan.restoreWorktreeContent =\n policy.captureDivergentContent && isWouldChangeAction(plan.result.action)\n ? readDivergentWorktreeContent(cwd, plan.destination)\n : undefined;\n }\n}\n\nfunction indexMaterializationPolicy(mode: IndexMaterializationMode): IndexMaterializationPolicy {\n switch (mode) {\n case 'mutations-only': {\n const keepMaterialized = process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] === '1';\n return {\n renderUnchanged: false,\n preservePriorStructure: keepMaterialized,\n writeUnchanged: false,\n captureDivergentContent: !keepMaterialized,\n skipForeignDestinations: true,\n };\n }\n case 'restore-staged-tree': {\n return {\n renderUnchanged: true,\n preservePriorStructure: true,\n writeUnchanged: true,\n captureDivergentContent: false,\n skipForeignDestinations: false,\n };\n }\n }\n}\n\nfunction readWorktreeDocumentState(destination: string): WorktreeDocumentState {\n try {\n return { existed: true, content: readFileSync(destination, 'utf8') };\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code === 'ENOENT') return { existed: false };\n throw error_;\n }\n}\n\nfunction restoreMaterializationPlans(cwd: string, plans: IndexMaterializationPlan[]): unknown[] {\n const errors: unknown[] = [];\n for (const plan of plans.toReversed()) {\n try {\n const priorState = plan.priorWorktreeState;\n if (priorState === undefined) continue;\n if (priorState.existed) {\n replaceArchitectureDocumentContent(priorState.content, plan.destination, cwd);\n } else {\n assertPhysicalContainment(cwd, plan.destination);\n rmSync(plan.destination, { force: true });\n }\n } catch (error_) {\n errors.push(error_);\n }\n }\n return errors;\n}\n\n/**\n * Return worktree document bytes only when they differ from the index copy.\n * `--stage` temporarily replaces that path to stage deterministic content, then\n * restores these bytes so unrelated worktree-only modules and prose survive.\n */\nfunction readDivergentWorktreeContent(cwd: string, destination: string): string | undefined {\n assertPhysicalContainment(cwd, destination);\n let worktreeContent: string;\n try {\n worktreeContent = readFileSync(destination, 'utf8');\n } catch {\n return undefined;\n }\n\n const relativePath = nodePath.relative(cwd, destination);\n let indexContent: string | undefined;\n try {\n const projectRelativePath = relativePath.replaceAll('\\\\', '/');\n indexContent = execFileSync('git', ['show', `:./${projectRelativePath}`], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n } catch {\n // An untracked worktree document has no index copy and must be preserved.\n }\n return worktreeContent === indexContent ? undefined : worktreeContent;\n}\n\n/** `git add` the regenerated doc; best-effort — a git failure never blocks the commit. */\nfunction stageDocument(cwd: string, result: SelfHealResult): string | undefined {\n try {\n const relativePath = nodePath.relative(cwd, result.path);\n execFileSync('git', ['add', '--', relativePath], { cwd, stdio: 'ignore' });\n return undefined;\n } catch (error_) {\n return errorMessage(error_);\n }\n}\n\nconst ARCHITECTURE_INPUT_BASENAMES = new Set([\n '.dependency-cruiser.cjs',\n '.dependency-cruiser.js',\n '.dependency-cruiser.json',\n '.dependency-cruiser.mjs',\n 'Cargo.toml',\n 'go.mod',\n 'go.work',\n 'package.json',\n 'pnpm-workspace.yaml',\n 'pyproject.toml',\n]);\n\nconst SOURCE_EXTENSIONS = new Set([\n '.cjs',\n '.cts',\n '.js',\n '.jsx',\n '.mjs',\n '.mts',\n '.py',\n '.rs',\n '.ts',\n '.tsx',\n]);\n\nfunction isPotentialArchitectureInput(path: string): boolean {\n const normalized = path.replaceAll('\\\\', '/');\n const segments = normalized.split('/');\n const basename = segments.at(-1) ?? '';\n return (\n normalized === '.safeword/config.json' ||\n segments.includes('src') ||\n segments.includes('lib') ||\n ARCHITECTURE_INPUT_BASENAMES.has(basename) ||\n normalized.endsWith('.prisma') ||\n normalized.endsWith('.sql') ||\n SOURCE_EXTENSIONS.has(nodePath.posix.extname(basename))\n );\n}\n\nfunction nulSeparatedGitPaths(cwd: string, args: string[]): string[] {\n try {\n return execFileSync('git', args, {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .split('\\0')\n .filter(path => path.length > 0);\n } catch {\n return [];\n }\n}\n\n/** Explain why staged-tree generation can intentionally disagree with `--check`. */\nfunction warnExcludedWorktreeInputs(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): void {\n const excluded = new Set([\n ...nulSeparatedGitPaths(cwd, ['diff', '--name-only', '-z', '--']),\n ...nulSeparatedGitPaths(cwd, ['ls-files', '--others', '--exclude-standard', '-z', '--']),\n ]);\n const relevant = [...excluded]\n .filter(path => isPotentialArchitectureInput(path))\n .toSorted((a, b) => a.localeCompare(b));\n if (relevant.length === 0) return;\n\n const shown = relevant.slice(0, 20);\n const remainder = relevant.length - shown.length;\n const remainderSummary = remainder > 0 ? ` (+${remainder} more)` : '';\n reporter.warn(\n `Excluded unstaged/untracked architecture inputs from staged-tree generation: ${shown.join(', ')}${remainderSummary}`,\n );\n}\n\nfunction errorMessage(error_: unknown): string {\n return error_ instanceof Error ? error_.message.replaceAll(/\\s+/g, ' ').trim() : String(error_);\n}\n\n/**\n * CI staleness backstop. Exits non-zero when ANY node is stale (would change),\n * passes when every node is current/`noop`/foreign or when enforcement is opted\n * out. Writes nothing — the fix is the human running `safeword project architecture`.\n */\nfunction architectureCheck(cwd: string): Promise<void> {\n warnUnreadableWorkspaces(cwd);\n if (!isArchitectureDocumentEnforcementEnabled(cwd)) {\n success('Architecture doc enforcement is opted out (architectureDocEnforcement: false).');\n return Promise.resolve();\n }\n\n const stale = planSelfHealProject(cwd).filter(action => isWouldChangeAction(action));\n if (stale.length > 0) {\n error(\n `Architecture docs are stale (${stale.join(', ')}). Run \\`safeword project architecture\\` for the current worktree, or \\`safeword project architecture --staged\\` to reproduce the staged tree, then commit the result.`,\n );\n process.exit(1);\n }\n\n success('Architecture docs are current.');\n return Promise.resolve();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/architecture.ts"],"sourcesContent":["/**\n * `safeword project architecture` — refresh the generated architecture state document(s)\n * (ticket QD5DTT, Slice 1; FPV0E4, Slice 2; XG9SFP, Slice 3).\n *\n * Default mode is a thin CLI entry over `selfHealProject`: re-extracts the\n * skeleton and reconciles prose markers for every node — one doc for a\n * single-repo, or a derived root index plus colocated per-package leaf docs for a\n * monorepo. The SessionStart hook shells out to it so the heal logic lives in one\n * place.\n *\n * `--check` is the CI backstop: a dry-run that writes nothing and exits non-zero\n * when ANY node is stale (a would-change action), so a silently-wrong doc cannot\n * reach the main branch.\n *\n * `--stage` is the commit-time auto-fix: export the staged git index, regenerate\n * every stale node from that deterministic tree, and `git add` each into the\n * in-flight commit, so unrelated worktree changes cannot contaminate it. Never\n * blocks (always exits zero). `--staged` exposes the same deterministic source\n * without automatically adding the generated docs. The commit and CI gates\n * (`--stage` and `--check`) honor the per-project opt-out\n * (`architectureDocEnforcement: false`); explicit generation modes still run.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n copyFileSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport nodePath from 'node:path';\nimport process from 'node:process';\n\nimport {\n isSafewordOwned,\n isWouldChangeAction,\n planSelfHealProject,\n selfHealProject,\n selfHealProjectPreservingProse,\n type SelfHealResult,\n} from '../utils/architecture-document.js';\nimport {\n discoverUnreadableWorkspaces,\n extractMonorepoArchitectureSnapshot,\n} from '../utils/architecture-monorepo.js';\nimport {\n GENERATED_ARCHITECTURE_FILENAME,\n isArchitectureDocumentEnforcementEnabled,\n readConfiguredPath,\n resolveGeneratedArchitecturePath,\n} from '../utils/configured-paths.js';\nimport { readJson, writeJson } from '../utils/fs.js';\nimport { error, success, warn } from '../utils/output.js';\nimport { toRepoDirectory } from '../utils/repo-path.js';\n\nconst ARCHITECTURE_SOURCE_INDEX_ENV = 'SAFEWORD_ARCHITECTURE_SOURCE_INDEX';\nconst ARCHITECTURE_KEEP_MATERIALIZED_ENV = 'SAFEWORD_ARCHITECTURE_KEEP_MATERIALIZED';\n\nexport interface ArchitectureReporter {\n readonly success: (message: string) => void;\n readonly warn: (message: string) => void;\n readonly error: (message: string) => void;\n}\n\nexport interface ArchitectureModeOutcome {\n readonly results: readonly SelfHealResult[];\n readonly stagedPaths: readonly string[];\n readonly stageFailures: readonly string[];\n readonly failed: boolean;\n readonly autoStageAvailable: boolean;\n}\n\nconst defaultReporter: ArchitectureReporter = { success, warn, error };\n\nexport async function architecture(\n cwd: string = process.cwd(),\n options: { check?: boolean; stage?: boolean; staged?: boolean } = {},\n): Promise<void> {\n if (options.check) {\n await architectureCheck(cwd);\n return;\n }\n if (options.stage) {\n await architectureStage(cwd);\n return;\n }\n if (options.staged) {\n await architectureStaged(cwd);\n return;\n }\n\n generateFromWorktree(cwd);\n}\n\nfunction generateFromWorktree(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): SelfHealResult[] {\n const results = selfHealProject(cwd);\n for (const result of results) {\n reporter.success(`Architecture state document ${result.action}: ${result.path}`);\n }\n warnUnreadableWorkspaces(cwd, reporter);\n return results;\n}\n\n/**\n * Print a non-blocking warning for each workspace manager that is present at the root but\n * unparseable (ticket UWP4XK, GitHub #558) — a malformed `go.work`, an unreadable Cargo\n * `[workspace] members`, a flow-style `pnpm-workspace.yaml`. Advisory only: it never\n * changes a command's exit code. Surfaced in every mode (default/`--check`/`--stage`),\n * independent of `architectureDocEnforcement`, because coverage honesty is not enforcement\n * — the architecture map silently omitting a whole language is wrong regardless of opt-out.\n */\nfunction warnUnreadableWorkspaces(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): void {\n for (const workspace of discoverUnreadableWorkspaces(cwd)) {\n reporter.warn(\n `Workspace config present but unreadable: ${workspace.config} (${workspace.manager}). Its packages may be missing from the architecture doc — fix the config and re-run \\`safeword project architecture\\`. (Advisory; nothing is blocked.)`,\n );\n }\n}\n\n/**\n * Commit-time auto-fix. Regenerates every stale node from the staged git index\n * and stages it into the in-flight commit; leaves current/`noop`/foreign nodes\n * untouched. Never blocks — git failures are swallowed so the commit proceeds.\n */\nexport function architectureStage(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): Promise<ArchitectureModeOutcome> {\n let results: readonly SelfHealResult[] = [];\n const stagedPaths: string[] = [];\n const stageFailures: string[] = [];\n let autoStageAvailable = true;\n try {\n if (!isArchitectureDocumentEnforcementEnabled(cwd)) {\n warnUnreadableWorkspaces(cwd, reporter);\n reporter.success(\n 'Architecture doc enforcement is opted out (architectureDocEnforcement: false).',\n );\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n }\n\n const gitContext = resolveGitContext(cwd);\n if (gitContext === undefined) {\n autoStageAvailable = false;\n reporter.warn(\n 'No Git worktree found; generated from the worktree instead without auto-staging.',\n );\n results = generateFromWorktree(cwd, reporter);\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n }\n\n withGitIndexSnapshot(cwd, gitContext, snapshotDirectory => {\n warnUnreadableWorkspaces(snapshotDirectory, reporter);\n const materialized = materializeIndexResults(\n cwd,\n snapshotDirectory,\n 'mutations-only',\n reporter,\n );\n results = materialized.results;\n const changed = materialized.results.filter(result => isWouldChangeAction(result.action));\n if (changed.length === 0) {\n if (materialized.skippedForeignCount === 0) {\n reporter.success('Architecture docs need no change.');\n } else {\n const ownership = `${materialized.skippedForeignCount} ${\n materialized.skippedForeignCount === 1 ? 'document is' : 'documents are'\n } not Safeword-owned`;\n reporter.success(`Architecture docs left unchanged (${ownership}).`);\n }\n } else {\n for (const result of changed) {\n const failure = stageMaterializedDocument(cwd, result, reporter);\n const relativePath = nodePath.relative(cwd, result.path);\n if (failure === undefined) stagedPaths.push(relativePath);\n else stageFailures.push(relativePath);\n }\n }\n });\n warnExcludedWorktreeInputs(cwd, reporter);\n } catch (error_) {\n autoStageAvailable = false;\n reporter.warn(\n `Could not complete staged-tree architecture generation; nothing was auto-staged. CI will verify freshness. Cause: ${errorMessage(error_)}`,\n );\n }\n return Promise.resolve({\n results,\n stagedPaths,\n stageFailures,\n failed: false,\n autoStageAvailable,\n });\n}\n\ninterface WorktreeRecoveryCopy {\n directory: string;\n path: string;\n}\n\nfunction persistWorktreeRecoveryCopy(destination: string, content: string): WorktreeRecoveryCopy {\n const directory = mkdtempSync(nodePath.join(tmpdir(), 'safeword-architecture-recovery-'));\n const path = nodePath.join(directory, `${nodePath.basename(destination)}.recovery`);\n try {\n writeFileSync(path, content, { mode: 0o600 });\n return { directory, path };\n } catch (error_) {\n rmSync(directory, { recursive: true, force: true });\n throw error_;\n }\n}\n\nfunction restoreWorktreeAfterStaging(\n cwd: string,\n result: MaterializedIndexResult,\n recoveryCopy: WorktreeRecoveryCopy | undefined,\n staged: boolean,\n reporter: ArchitectureReporter,\n): void {\n if (\n result.restoreWorktreeContent === undefined ||\n process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] === '1'\n ) {\n return;\n }\n try {\n replaceArchitectureDocumentContent(result.restoreWorktreeContent, result.path, cwd);\n if (recoveryCopy !== undefined) {\n rmSync(recoveryCopy.directory, { recursive: true, force: true });\n }\n reporter.warn(`Preserved unstaged worktree architecture edits: ${result.path}`);\n } catch (error_) {\n reporter.warn(\n `Architecture doc ${staged ? 'was staged' : 'was not staged'} but unstaged worktree edits could not be restored: ${result.path}. Recovery copy: ${recoveryCopy?.path ?? 'unavailable'}. Cause: ${errorMessage(error_)}`,\n );\n }\n}\n\nfunction stageMaterializedDocument(\n cwd: string,\n result: MaterializedIndexResult,\n reporter: ArchitectureReporter,\n): string | undefined {\n const shouldRestore =\n result.restoreWorktreeContent !== undefined &&\n process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] !== '1';\n let recoveryCopy: WorktreeRecoveryCopy | undefined;\n let staged = false;\n try {\n if (shouldRestore && result.restoreWorktreeContent !== undefined) {\n recoveryCopy = persistWorktreeRecoveryCopy(result.path, result.restoreWorktreeContent);\n }\n const stageFailure = stageDocument(cwd, result);\n if (stageFailure === undefined) {\n staged = true;\n reporter.success(`Architecture doc ${result.action} and staged: ${result.path}`);\n } else {\n reporter.warn(\n `Architecture doc ${result.action} but could not be staged: ${result.path}. Cause: ${stageFailure}`,\n );\n }\n return stageFailure;\n } finally {\n restoreWorktreeAfterStaging(cwd, result, recoveryCopy, staged, reporter);\n }\n}\n\n/**\n * Explicit deterministic generation mode. It uses the same index snapshot as\n * commit-time auto-staging but leaves the index untouched so developers can\n * inspect the result before choosing what to stage.\n */\nexport function architectureStaged(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): Promise<ArchitectureModeOutcome> {\n let results: readonly SelfHealResult[] = [];\n try {\n const gitContext = resolveGitContext(cwd);\n if (gitContext === undefined) {\n reporter.warn('No Git worktree found; generated from the worktree instead.');\n results = generateFromWorktree(cwd, reporter);\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: false,\n autoStageAvailable: false,\n });\n }\n\n withGitIndexSnapshot(cwd, gitContext, snapshotDirectory => {\n warnUnreadableWorkspaces(snapshotDirectory, reporter);\n const materialized = materializeIndexResults(\n cwd,\n snapshotDirectory,\n 'restore-staged-tree',\n reporter,\n );\n results = materialized.results;\n for (const result of materialized.results) {\n reporter.success(`Architecture state document ${result.action}: ${result.path}`);\n }\n });\n warnExcludedWorktreeInputs(cwd, reporter);\n } catch (error_) {\n reporter.error(\n `Could not complete staged-tree architecture generation; inspect the worktree before retrying. Cause: ${errorMessage(error_)}`,\n );\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: true,\n autoStageAvailable: true,\n });\n }\n return Promise.resolve({\n results,\n stagedPaths: [],\n stageFailures: [],\n failed: false,\n autoStageAvailable: true,\n });\n}\n\n/**\n * Export the stage-zero index into an isolated directory and remove it after\n * the caller finishes. `git checkout-index` reads only the index: unstaged and\n * untracked worktree files never enter the architecture extractor.\n */\nfunction withGitIndexSnapshot<T>(\n cwd: string,\n gitContext: GitContext,\n useSnapshot: (directory: string) => T,\n): T {\n const snapshotDirectory = mkdtempSync(nodePath.join(tmpdir(), 'safeword-architecture-index-'));\n const sourceIndexFile = process.env[ARCHITECTURE_SOURCE_INDEX_ENV];\n const sourceIndexEnvironment =\n sourceIndexFile === undefined ? undefined : { ...process.env, GIT_INDEX_FILE: sourceIndexFile };\n try {\n assertNoGitlinks(gitContext, sourceIndexEnvironment);\n execFileSync(\n 'git',\n [\n 'checkout-index',\n '--all',\n '--force',\n '--ignore-skip-worktree-bits',\n `--prefix=${snapshotDirectory}${nodePath.sep}`,\n ],\n {\n cwd: gitContext.rootDirectory,\n ...(sourceIndexEnvironment && { env: sourceIndexEnvironment }),\n stdio: 'ignore',\n },\n );\n const snapshotProjectDirectory = nodePath.join(\n snapshotDirectory,\n gitContext.projectRelativeDirectory,\n );\n prepareSnapshotProjectRoot(cwd, snapshotProjectDirectory);\n return useSnapshot(snapshotProjectDirectory);\n } finally {\n rmSync(snapshotDirectory, { recursive: true, force: true });\n }\n}\n\nconst GITLINK_MODE_PREFIX = '160000 ';\n\n/** Refuse a staged tree whose pinned submodule contents cannot be materialized safely. */\nfunction assertNoGitlinks(\n gitContext: GitContext,\n sourceIndexEnvironment?: NodeJS.ProcessEnv,\n): void {\n const pathArguments =\n gitContext.projectRelativeDirectory === '' ? [] : [gitContext.projectRelativeDirectory];\n const entries = execFileSync(\n 'git',\n ['ls-files', '--stage', '-z', '--full-name', '--', ...pathArguments],\n {\n cwd: gitContext.rootDirectory,\n encoding: 'utf8',\n ...(sourceIndexEnvironment && { env: sourceIndexEnvironment }),\n stdio: ['ignore', 'pipe', 'ignore'],\n },\n )\n .split('\\0')\n .filter(entry => entry.startsWith(GITLINK_MODE_PREFIX));\n if (entries.length === 0) return;\n\n const paths = entries.map(entry => entry.slice(entry.indexOf('\\t') + 1));\n throw new Error(\n `Staged-tree architecture generation does not support submodule gitlinks: ${paths.join(', ')}. Run \\`safeword project architecture\\` from the materialized worktree, or remove the gitlink from the staged tree before retrying.`,\n );\n}\n\ninterface GitContext {\n rootDirectory: string;\n projectRelativeDirectory: string;\n}\n\n/** Resolve the invocation directory against Git's repository root. */\nfunction resolveGitContext(cwd: string): GitContext | undefined {\n let rootDirectory: string;\n try {\n rootDirectory = execFileSync('git', ['rev-parse', '--show-toplevel'], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error('Git executable is unavailable.', { cause: error_ });\n }\n return undefined;\n }\n if (rootDirectory.length === 0) return undefined;\n\n const canonicalRoot = realpathSync(rootDirectory);\n const canonicalProject = realpathSync(cwd);\n const projectRelativeDirectory = nodePath.relative(canonicalRoot, canonicalProject);\n if (\n nodePath.isAbsolute(projectRelativeDirectory) ||\n projectRelativeDirectory === '..' ||\n projectRelativeDirectory.startsWith(`..${nodePath.sep}`)\n ) {\n throw new Error('The architecture project directory is outside the Git worktree.');\n }\n return { rootDirectory: canonicalRoot, projectRelativeDirectory };\n}\n\n/**\n * Keep a configured project root inside the exported tree before the healer\n * can write through it. Absolute repo-contained paths are remapped into the\n * snapshot; lexical escapes and physical symlink escapes are rejected.\n */\nfunction prepareSnapshotProjectRoot(cwd: string, snapshotDirectory: string): void {\n const configuredRoot = readConfiguredPath(snapshotDirectory, 'projectRoot');\n if (configuredRoot === undefined) return;\n\n const repoRelativeRoot = toRepoDirectory(cwd, configuredRoot);\n if (repoRelativeRoot === undefined) {\n throw new Error('The staged projectRoot resolves outside the repository.');\n }\n assertPhysicalContainment(snapshotDirectory, nodePath.join(snapshotDirectory, repoRelativeRoot));\n if (!nodePath.isAbsolute(configuredRoot)) return;\n\n rewriteSnapshotProjectRoot(snapshotDirectory, repoRelativeRoot);\n}\n\nfunction rewriteSnapshotProjectRoot(snapshotDirectory: string, repoRelativeRoot: string): void {\n const configPath = nodePath.join(snapshotDirectory, '.safeword', 'config.json');\n const config = readJson(configPath);\n if (config === undefined || typeof config !== 'object' || config === null) return;\n const paths = (config as { paths?: unknown }).paths;\n if (paths === undefined || typeof paths !== 'object' || paths === null) return;\n writeJson(configPath, {\n ...config,\n paths: {\n ...paths,\n projectRoot: repoRelativeRoot === '' ? '.' : repoRelativeRoot,\n },\n });\n}\n\n/**\n * Resolve the nearest existing ancestor so non-existent destination leaves are\n * accepted, while any existing symlink component must resolve inside the\n * allowed root. A dangling symlink is rejected because its physical target\n * cannot be proven safe.\n */\nfunction assertPhysicalContainment(rootDirectory: string, candidatePath: string): void {\n if (toRepoDirectory(rootDirectory, candidatePath) === undefined) {\n throw new Error('The architecture path lexically escapes its allowed root.');\n }\n\n let existingAncestor = candidatePath;\n for (;;) {\n try {\n lstatSync(existingAncestor);\n break;\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code !== 'ENOENT') throw error_;\n const parent = nodePath.dirname(existingAncestor);\n if (parent === existingAncestor) throw error_;\n existingAncestor = parent;\n }\n }\n\n const canonicalRoot = realpathSync(rootDirectory);\n const canonicalAncestor = realpathSync(existingAncestor);\n if (toRepoDirectory(canonicalRoot, canonicalAncestor) === undefined) {\n throw new Error('The architecture path physically escapes its allowed root.');\n }\n}\n\n/** Validate every path selfHealProject may write before allowing its first write. */\nfunction assertSnapshotHealTargetsContained(snapshotDirectory: string): void {\n const { leaves } = extractMonorepoArchitectureSnapshot(snapshotDirectory);\n const targets = [\n resolveGeneratedArchitecturePath(snapshotDirectory),\n ...leaves.map(leaf => nodePath.join(leaf.dir, GENERATED_ARCHITECTURE_FILENAME)),\n ];\n for (const target of targets) {\n assertPhysicalContainment(snapshotDirectory, target);\n }\n}\n\n/**\n * Replace through a fresh inode so an existing hard-linked destination cannot\n * mutate another directory entry. The temporary file shares the destination\n * directory, allowing rename to atomically replace symlinks and hard links.\n */\nfunction replaceArchitectureDocumentWith(\n destination: string,\n allowedRoot: string,\n writeTemporaryFile: (path: string) => void,\n): void {\n const destinationDirectory = nodePath.dirname(destination);\n assertPhysicalContainment(allowedRoot, destination);\n mkdirSync(destinationDirectory, { recursive: true });\n\n // Prefer the OS temp root when it is on the destination filesystem: this\n // keeps crash litter outside the repository while preserving atomic rename.\n // Cross-device rename is not atomic, so fall back to an adjacent directory\n // only when the filesystems differ.\n let temporaryDirectory = mkdtempSync(\n nodePath.join(tmpdir(), 'safeword-architecture-replacement-'),\n );\n if (lstatSync(temporaryDirectory).dev !== lstatSync(destinationDirectory).dev) {\n rmSync(temporaryDirectory, { recursive: true, force: true });\n temporaryDirectory = mkdtempSync(\n nodePath.join(destinationDirectory, '.safeword-architecture-'),\n );\n }\n try {\n const temporaryPath = nodePath.join(temporaryDirectory, nodePath.basename(destination));\n writeTemporaryFile(temporaryPath);\n renameSync(temporaryPath, destination);\n } finally {\n rmSync(temporaryDirectory, { recursive: true, force: true });\n }\n}\n\nfunction replaceArchitectureDocument(\n source: string,\n destination: string,\n allowedRoot: string,\n): void {\n replaceArchitectureDocumentWith(destination, allowedRoot, temporaryPath => {\n copyFileSync(source, temporaryPath);\n });\n}\n\nfunction replaceArchitectureDocumentContent(\n content: string,\n destination: string,\n allowedRoot: string,\n): void {\n replaceArchitectureDocumentWith(destination, allowedRoot, temporaryPath => {\n writeFileSync(temporaryPath, content);\n });\n}\n\ntype IndexMaterializationMode = 'mutations-only' | 'restore-staged-tree';\n\ninterface IndexMaterializationPolicy {\n renderUnchanged: boolean;\n preservePriorStructure: boolean;\n writeUnchanged: boolean;\n captureDivergentContent: boolean;\n skipForeignDestinations: boolean;\n}\n\ninterface MaterializedIndexResult extends SelfHealResult {\n restoreWorktreeContent?: string;\n}\n\ninterface MaterializedIndexOutcome {\n results: MaterializedIndexResult[];\n skippedForeignCount: number;\n}\n\ntype WorktreeDocumentState =\n | { existed: false }\n | {\n existed: true;\n content: string;\n };\n\ninterface IndexMaterializationPlan {\n result: SelfHealResult;\n destination: string;\n shouldWrite: boolean;\n skippedForeign?: boolean;\n priorWorktreeState?: WorktreeDocumentState;\n restoreWorktreeContent?: string;\n}\n\n/**\n * Heal inside the index snapshot, then copy only generated mutations to their\n * matching worktree paths. Returned paths always name the real worktree files.\n */\nfunction materializeIndexResults(\n cwd: string,\n snapshotDirectory: string,\n mode: IndexMaterializationMode,\n reporter: ArchitectureReporter = defaultReporter,\n): MaterializedIndexOutcome {\n assertSnapshotHealTargetsContained(snapshotDirectory);\n const policy = indexMaterializationPolicy(mode);\n const plans = planIndexMaterializations(cwd, snapshotDirectory, policy);\n preflightIndexMaterializations(cwd, plans, policy, reporter);\n\n const attemptedPlans: IndexMaterializationPlan[] = [];\n try {\n for (const plan of plans) {\n if (!plan.shouldWrite) continue;\n attemptedPlans.push(plan);\n replaceArchitectureDocument(plan.result.path, plan.destination, cwd);\n }\n } catch (materializationError) {\n const rollbackErrors = restoreMaterializationPlans(cwd, attemptedPlans);\n if (rollbackErrors.length > 0) {\n throw new AggregateError(\n [materializationError, ...rollbackErrors],\n 'Architecture materialization failed and one or more worktree documents could not be restored.',\n { cause: materializationError },\n );\n }\n throw materializationError;\n }\n\n return {\n results: plans\n .filter(plan => !plan.skippedForeign)\n .map(({ result, destination, restoreWorktreeContent }) => ({\n action: result.action,\n path: destination,\n restoreWorktreeContent,\n })),\n skippedForeignCount: plans.filter(plan => plan.skippedForeign).length,\n };\n}\n\nfunction planIndexMaterializations(\n cwd: string,\n snapshotDirectory: string,\n policy: IndexMaterializationPolicy,\n): IndexMaterializationPlan[] {\n return selfHealProjectPreservingProse(snapshotDirectory, cwd, {\n renderUnchanged: policy.renderUnchanged,\n preservePriorStructure: policy.preservePriorStructure,\n }).map(result => {\n const relativePath = nodePath.relative(snapshotDirectory, result.path);\n if (\n relativePath === '' ||\n nodePath.isAbsolute(relativePath) ||\n relativePath === '..' ||\n relativePath.startsWith(`..${nodePath.sep}`)\n ) {\n throw new Error('Generated architecture path escaped the git index snapshot.');\n }\n\n return {\n result,\n destination: nodePath.join(cwd, relativePath),\n shouldWrite:\n isWouldChangeAction(result.action) ||\n (policy.writeUnchanged && result.action === 'unchanged'),\n };\n });\n}\n\n/**\n * Validate and snapshot every destination before replacing the first one. A\n * later unsafe or unreadable leaf must not leave an earlier root half-applied.\n */\nfunction preflightIndexMaterializations(\n cwd: string,\n plans: IndexMaterializationPlan[],\n policy: IndexMaterializationPolicy,\n reporter: ArchitectureReporter,\n): void {\n for (const plan of plans) {\n if (!plan.shouldWrite) continue;\n assertPhysicalContainment(cwd, plan.destination);\n plan.priorWorktreeState = readWorktreeDocumentState(plan.destination);\n if (plan.priorWorktreeState.existed && !isSafewordOwned(plan.priorWorktreeState.content)) {\n if (policy.skipForeignDestinations) {\n plan.skippedForeign = true;\n plan.shouldWrite = false;\n reporter.warn(\n `Architecture document is not owned by Safeword and was left unchanged: ${plan.destination}`,\n );\n continue;\n }\n throw new Error(\n `Architecture document is not owned by Safeword and was left unchanged: ${plan.destination}`,\n );\n }\n plan.restoreWorktreeContent =\n policy.captureDivergentContent && isWouldChangeAction(plan.result.action)\n ? readDivergentWorktreeContent(cwd, plan.destination)\n : undefined;\n }\n}\n\nfunction indexMaterializationPolicy(mode: IndexMaterializationMode): IndexMaterializationPolicy {\n switch (mode) {\n case 'mutations-only': {\n const keepMaterialized = process.env[ARCHITECTURE_KEEP_MATERIALIZED_ENV] === '1';\n return {\n renderUnchanged: false,\n preservePriorStructure: keepMaterialized,\n writeUnchanged: false,\n captureDivergentContent: !keepMaterialized,\n skipForeignDestinations: true,\n };\n }\n case 'restore-staged-tree': {\n return {\n renderUnchanged: true,\n preservePriorStructure: true,\n writeUnchanged: true,\n captureDivergentContent: false,\n skipForeignDestinations: false,\n };\n }\n }\n}\n\nfunction readWorktreeDocumentState(destination: string): WorktreeDocumentState {\n try {\n return { existed: true, content: readFileSync(destination, 'utf8') };\n } catch (error_) {\n if ((error_ as NodeJS.ErrnoException).code === 'ENOENT') return { existed: false };\n throw error_;\n }\n}\n\nfunction restoreMaterializationPlans(cwd: string, plans: IndexMaterializationPlan[]): unknown[] {\n const errors: unknown[] = [];\n for (const plan of plans.toReversed()) {\n try {\n const priorState = plan.priorWorktreeState;\n if (priorState === undefined) continue;\n if (priorState.existed) {\n replaceArchitectureDocumentContent(priorState.content, plan.destination, cwd);\n } else {\n assertPhysicalContainment(cwd, plan.destination);\n rmSync(plan.destination, { force: true });\n }\n } catch (error_) {\n errors.push(error_);\n }\n }\n return errors;\n}\n\n/**\n * Return worktree document bytes only when they differ from the index copy.\n * `--stage` temporarily replaces that path to stage deterministic content, then\n * restores these bytes so unrelated worktree-only modules and prose survive.\n */\nfunction readDivergentWorktreeContent(cwd: string, destination: string): string | undefined {\n assertPhysicalContainment(cwd, destination);\n let worktreeContent: string;\n try {\n worktreeContent = readFileSync(destination, 'utf8');\n } catch {\n return undefined;\n }\n\n const relativePath = nodePath.relative(cwd, destination);\n let indexContent: string | undefined;\n try {\n const projectRelativePath = relativePath.replaceAll('\\\\', '/');\n indexContent = execFileSync('git', ['show', `:./${projectRelativePath}`], {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n } catch {\n // An untracked worktree document has no index copy and must be preserved.\n }\n return worktreeContent === indexContent ? undefined : worktreeContent;\n}\n\n/** `git add` the regenerated doc; best-effort — a git failure never blocks the commit. */\nfunction stageDocument(cwd: string, result: SelfHealResult): string | undefined {\n try {\n const relativePath = nodePath.relative(cwd, result.path);\n execFileSync('git', ['add', '--', relativePath], { cwd, stdio: 'ignore' });\n return undefined;\n } catch (error_) {\n return errorMessage(error_);\n }\n}\n\nconst ARCHITECTURE_INPUT_BASENAMES = new Set([\n '.dependency-cruiser.cjs',\n '.dependency-cruiser.js',\n '.dependency-cruiser.json',\n '.dependency-cruiser.mjs',\n 'Cargo.toml',\n 'go.mod',\n 'go.work',\n 'package.json',\n 'pnpm-workspace.yaml',\n 'pyproject.toml',\n]);\n\nconst SOURCE_EXTENSIONS = new Set([\n '.cjs',\n '.cts',\n '.js',\n '.jsx',\n '.mjs',\n '.mts',\n '.py',\n '.rs',\n '.ts',\n '.tsx',\n]);\n\nfunction isPotentialArchitectureInput(path: string): boolean {\n const normalized = path.replaceAll('\\\\', '/');\n const segments = normalized.split('/');\n const basename = segments.at(-1) ?? '';\n return (\n normalized === '.safeword/config.json' ||\n segments.includes('src') ||\n segments.includes('lib') ||\n ARCHITECTURE_INPUT_BASENAMES.has(basename) ||\n normalized.endsWith('.prisma') ||\n normalized.endsWith('.sql') ||\n SOURCE_EXTENSIONS.has(nodePath.posix.extname(basename))\n );\n}\n\nfunction nulSeparatedGitPaths(cwd: string, args: string[]): string[] {\n try {\n return execFileSync('git', args, {\n cwd,\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .split('\\0')\n .filter(path => path.length > 0);\n } catch {\n return [];\n }\n}\n\n/** Explain why staged-tree generation can intentionally disagree with `--check`. */\nfunction warnExcludedWorktreeInputs(\n cwd: string,\n reporter: ArchitectureReporter = defaultReporter,\n): void {\n const excluded = new Set([\n ...nulSeparatedGitPaths(cwd, ['diff', '--name-only', '-z', '--']),\n ...nulSeparatedGitPaths(cwd, ['ls-files', '--others', '--exclude-standard', '-z', '--']),\n ]);\n const relevant = [...excluded]\n .filter(path => isPotentialArchitectureInput(path))\n .toSorted((a, b) => a.localeCompare(b));\n if (relevant.length === 0) return;\n\n const shown = relevant.slice(0, 20);\n const remainder = relevant.length - shown.length;\n const remainderSummary = remainder > 0 ? ` (+${remainder} more)` : '';\n reporter.warn(\n `Excluded unstaged/untracked architecture inputs from staged-tree generation: ${shown.join(', ')}${remainderSummary}`,\n );\n}\n\nfunction errorMessage(error_: unknown): string {\n return error_ instanceof Error ? error_.message.replaceAll(/\\s+/g, ' ').trim() : String(error_);\n}\n\n/**\n * CI staleness backstop. Exits non-zero when ANY node is stale (would change),\n * passes when every node is current/`noop`/foreign or when enforcement is opted\n * out. Writes nothing — the fix is the human running `safeword project architecture`.\n */\nfunction architectureCheck(cwd: string): Promise<void> {\n warnUnreadableWorkspaces(cwd);\n if (!isArchitectureDocumentEnforcementEnabled(cwd)) {\n success('Architecture doc enforcement is opted out (architectureDocEnforcement: false).');\n return Promise.resolve();\n }\n\n const stale = planSelfHealProject(cwd).filter(action => isWouldChangeAction(action));\n if (stale.length > 0) {\n error(\n `Architecture docs are stale (${stale.join(', ')}). Run \\`safeword project architecture\\` for the current worktree, or \\`safeword project architecture --staged\\` to reproduce the staged tree, then commit the result.`,\n );\n process.exit(1);\n }\n\n success('Architecture docs are current.');\n return Promise.resolve();\n}\n"],"mappings":"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","names":[]}
@@ -7,10 +7,11 @@ import {
7
7
  selfHeal,
8
8
  selfHealProject,
9
9
  selfHealProjectPreservingProse
10
- } from "./chunk-UM7PJKBV.js";
11
- import "./chunk-FLMWLQHK.js";
12
- import "./chunk-RFP2MSVO.js";
13
- import "./chunk-X26EJNPZ.js";
10
+ } from "./chunk-PZTGLQSD.js";
11
+ import "./chunk-YP2V3YUV.js";
12
+ import "./chunk-2MI7M2CO.js";
13
+ import "./chunk-7G6OSNIV.js";
14
+ import "./chunk-3SBTSETS.js";
14
15
  export {
15
16
  isSafewordOwned,
16
17
  isWouldChangeAction,
@@ -21,4 +22,4 @@ export {
21
22
  selfHealProject,
22
23
  selfHealProjectPreservingProse
23
24
  };
24
- //# sourceMappingURL=architecture-document-KFR4JDUT.js.map
25
+ //# sourceMappingURL=architecture-document-CTLCH76G.js.map
@@ -3,12 +3,13 @@ import {
3
3
  discoverWorkspaces,
4
4
  extractMonorepoArchitectureSnapshot,
5
5
  monorepoFingerprintOf
6
- } from "./chunk-FLMWLQHK.js";
7
- import "./chunk-X26EJNPZ.js";
6
+ } from "./chunk-YP2V3YUV.js";
7
+ import "./chunk-7G6OSNIV.js";
8
+ import "./chunk-3SBTSETS.js";
8
9
  export {
9
10
  discoverUnreadableWorkspaces,
10
11
  discoverWorkspaces,
11
12
  extractMonorepoArchitectureSnapshot,
12
13
  monorepoFingerprintOf
13
14
  };
14
- //# sourceMappingURL=architecture-monorepo-QQ2OCQMC.js.map
15
+ //# sourceMappingURL=architecture-monorepo-XWJN3X5I.js.map
@@ -4,27 +4,28 @@ import {
4
4
  frontmatterOf,
5
5
  parseImplPlan,
6
6
  scalar
7
- } from "./chunk-PAC2VLLK.js";
7
+ } from "./chunk-SPK32BMX.js";
8
8
  import {
9
9
  classifyAnnotation,
10
10
  isValidSha,
11
11
  isValidSkipReason,
12
12
  parseCheckboxAnnotation
13
- } from "./chunk-PSKZASFR.js";
13
+ } from "./chunk-Z4ESH6KU.js";
14
14
  import {
15
15
  createPhaseAnchorScope
16
- } from "./chunk-AF6L253C.js";
17
- import "./chunk-ZESGPJCY.js";
16
+ } from "./chunk-K64BTVJ7.js";
17
+ import "./chunk-URVJZ4NL.js";
18
18
  import {
19
19
  warn
20
- } from "./chunk-DAFOEHJA.js";
20
+ } from "./chunk-QSLVO4XF.js";
21
21
  import {
22
22
  readConfiguredPathFromContent,
23
23
  ticketDirectoriesForConfiguredRoot
24
- } from "./chunk-RFP2MSVO.js";
24
+ } from "./chunk-2MI7M2CO.js";
25
25
  import {
26
26
  readFileSafe
27
- } from "./chunk-X26EJNPZ.js";
27
+ } from "./chunk-7G6OSNIV.js";
28
+ import "./chunk-3SBTSETS.js";
28
29
 
29
30
  // src/commands/boundary.ts
30
31
  import { execFileSync as execFileSync2 } from "child_process";
@@ -626,4 +627,4 @@ function boundary(options) {
626
627
  export {
627
628
  boundary
628
629
  };
629
- //# sourceMappingURL=boundary-J2RW4N3E.js.map
630
+ //# sourceMappingURL=boundary-I2Z6PZDO.js.map