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.
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks.json +5 -5
- package/codex-plugin/skills/bdd/references/SCENARIOS.md +6 -6
- package/codex-plugin/skills/closeout/SKILL.md +20 -7
- package/codex-plugin/skills/debug/SKILL.md +19 -3
- package/codex-plugin/skills/retro-filer/SKILL.md +1 -1
- package/codex-plugin/skills/testing/SKILL.md +20 -0
- package/dist/{architecture-GOUJM5NE.js → architecture-XQGXZQRR.js} +7 -6
- package/dist/{architecture-GOUJM5NE.js.map → architecture-XQGXZQRR.js.map} +1 -1
- package/dist/{architecture-document-KFR4JDUT.js → architecture-document-CTLCH76G.js} +6 -5
- package/dist/{architecture-monorepo-QQ2OCQMC.js → architecture-monorepo-XWJN3X5I.js} +4 -3
- package/dist/{boundary-J2RW4N3E.js → boundary-I2Z6PZDO.js} +9 -8
- package/dist/boundary-I2Z6PZDO.js.map +1 -0
- package/dist/{chunk-LX6G2SZC.js → chunk-2D5IR56T.js} +4 -4
- package/dist/{chunk-RFP2MSVO.js → chunk-2MI7M2CO.js} +2 -2
- package/dist/{chunk-5KUTV6L5.js → chunk-3D6BHVQX.js} +1 -1
- package/dist/chunk-3SBTSETS.js +7 -0
- package/dist/chunk-3SBTSETS.js.map +1 -0
- package/dist/{chunk-F4CA33GP.js → chunk-42RXDQAQ.js} +31 -20
- package/dist/chunk-42RXDQAQ.js.map +1 -0
- package/dist/{chunk-5GPCAAVW.js → chunk-56BJOCCK.js} +1 -1
- package/dist/{chunk-ZQCKTQKJ.js → chunk-5XHVFUX5.js} +2 -2
- package/dist/{chunk-PPQOPS6F.js → chunk-6GQX7IJP.js} +2 -2
- package/dist/{chunk-UW3BGLRB.js → chunk-6MK7T6BV.js} +1 -1
- package/dist/{chunk-GUIZH3NI.js → chunk-6S7CTKGC.js} +2 -2
- package/dist/{chunk-X26EJNPZ.js → chunk-7G6OSNIV.js} +1 -1
- package/dist/{migrate-codex-plugin-CPLYYCGP.js → chunk-DHX7G27S.js} +434 -150
- package/dist/chunk-DHX7G27S.js.map +1 -0
- package/dist/{chunk-QPWX5JXI.js → chunk-EWZEO64K.js} +53 -7
- package/dist/chunk-EWZEO64K.js.map +1 -0
- package/dist/chunk-FJSFM7Y7.js +318 -0
- package/dist/chunk-FJSFM7Y7.js.map +1 -0
- package/dist/{chunk-I5QEPYVK.js → chunk-FPSBF7F3.js} +16 -130
- package/dist/chunk-FPSBF7F3.js.map +1 -0
- package/dist/{chunk-2OBVDGB4.js → chunk-FS2LEZBO.js} +1 -1
- package/dist/{chunk-7BRCUXTB.js → chunk-G7ZPEVA3.js} +1 -1
- package/dist/{chunk-KWBGQ2YZ.js → chunk-JBA7AB6K.js} +6 -6
- package/dist/{chunk-QWL47LKR.js → chunk-JBOLNV2L.js} +1 -1
- package/dist/{chunk-PGUVVBIN.js → chunk-JDCGOUXS.js} +1 -1
- package/dist/chunk-JDCGOUXS.js.map +1 -0
- package/dist/{chunk-AF6L253C.js → chunk-K64BTVJ7.js} +4 -4
- package/dist/{chunk-MDXMCB37.js → chunk-KULHJBJ6.js} +1 -1
- package/dist/chunk-L6XMSCXJ.js +117 -0
- package/dist/chunk-L6XMSCXJ.js.map +1 -0
- package/dist/{chunk-OWGNCT45.js → chunk-LXUBCIMR.js} +2 -2
- package/dist/{chunk-OSBX5BZS.js → chunk-M2FRVQT7.js} +14 -4
- package/dist/chunk-M2FRVQT7.js.map +1 -0
- package/dist/chunk-N6U2BZ7S.js +632 -0
- package/dist/chunk-N6U2BZ7S.js.map +1 -0
- package/dist/{chunk-RLH5PLSD.js → chunk-NRTOKMGY.js} +2 -2
- package/dist/{chunk-4HWB6QFG.js → chunk-NSK2HI7O.js} +4 -4
- package/dist/{chunk-ZFM3XTN3.js → chunk-NYTHQ2B5.js} +3 -3
- package/dist/{chunk-QYO5EMNH.js → chunk-O2TTGWG6.js} +3 -3
- package/dist/{chunk-TOLJ6T4S.js → chunk-PQCE5GIH.js} +1 -1
- package/dist/{chunk-UM7PJKBV.js → chunk-PZTGLQSD.js} +4 -4
- package/dist/{chunk-KWOEDO5W.js → chunk-QOIQQY4E.js} +1 -1
- package/dist/{chunk-DAFOEHJA.js → chunk-QSLVO4XF.js} +1 -1
- package/dist/{chunk-MLEJHDVU.js → chunk-RYDEPCC3.js} +12 -2
- package/dist/chunk-RYDEPCC3.js.map +1 -0
- package/dist/{chunk-IEBFBHR2.js → chunk-SK6TC4BO.js} +1 -1
- package/dist/{chunk-PAC2VLLK.js → chunk-SPK32BMX.js} +2 -2
- package/dist/{chunk-PUNN7MZ6.js → chunk-TJ627SKI.js} +3 -3
- package/dist/{chunk-X2OHUUNE.js → chunk-U7OZP77P.js} +2 -2
- package/dist/{chunk-WPDGHG6D.js → chunk-UAFM77KW.js} +1 -1
- package/dist/{chunk-4DGDH7SG.js → chunk-UDLS7BHG.js} +1 -1
- package/dist/{chunk-MMSUTN3X.js → chunk-ULY7JQH4.js} +1 -1
- package/dist/{chunk-ZESGPJCY.js → chunk-URVJZ4NL.js} +2 -2
- package/dist/{chunk-XH6FTCM7.js → chunk-USGSZ4Y4.js} +2 -2
- package/dist/{chunk-KG7MFUUQ.js → chunk-UTO5XZ4S.js} +1 -1
- package/dist/{chunk-7NZ26QJP.js → chunk-VEIP5Y7K.js} +4 -4
- package/dist/{chunk-O5JEWG3M.js → chunk-XHNWNZRM.js} +1 -1
- package/dist/{chunk-AKPXZ75V.js → chunk-XQV3MM3G.js} +1 -1
- package/dist/{chunk-XIGSW56Z.js → chunk-Y2XB5HIH.js} +119 -21
- package/dist/chunk-Y2XB5HIH.js.map +1 -0
- package/dist/{chunk-FLMWLQHK.js → chunk-YP2V3YUV.js} +2 -2
- package/dist/{chunk-PSKZASFR.js → chunk-Z4ESH6KU.js} +1 -1
- package/dist/{cleanup-STJVSD7S.js → cleanup-YBWFEZVV.js} +42 -30
- package/dist/cleanup-YBWFEZVV.js.map +1 -0
- package/dist/cli.js +177 -73
- package/dist/cli.js.map +1 -1
- package/dist/{clients-2EXYFMMV.js → clients-3R4XYZVV.js} +4 -3
- package/dist/codex-bootstrap-QUL4BIMC.js +125 -0
- package/dist/codex-bootstrap-QUL4BIMC.js.map +1 -0
- package/dist/{codex-hook-HBEPMPEK.js → codex-hook-AJ6HNSIN.js} +26 -18
- package/dist/codex-hook-AJ6HNSIN.js.map +1 -0
- package/dist/{codify-L2V7J2GJ.js → codify-6RVSYYKB.js} +9 -8
- package/dist/{codify-L2V7J2GJ.js.map → codify-6RVSYYKB.js.map} +1 -1
- package/dist/config-37744FRY.js +8 -0
- package/dist/{configured-paths-TXRFWRTV.js → configured-paths-O3WBQ3NC.js} +4 -3
- package/dist/{contract-BJD62H2W.js → contract-L6J3ZMVZ.js} +3 -1
- package/dist/{contract-BJD62H2W.js.map → contract-L6J3ZMVZ.js.map} +1 -1
- package/dist/{converge-setup-6WS2RMSG.js → converge-setup-VFKDPZDV.js} +90 -39
- package/dist/converge-setup-VFKDPZDV.js.map +1 -0
- package/dist/{coordinator-P7SET5EM.js → coordinator-J6R6HHCP.js} +21 -6
- package/dist/{coordinator-P7SET5EM.js.map → coordinator-J6R6HHCP.js.map} +1 -1
- package/dist/corpus-QCEGFTUQ.js +15 -0
- package/dist/{feature-directories-36DL4FAU.js → feature-directories-2MMZPQM5.js} +6 -5
- package/dist/{feature-directories-36DL4FAU.js.map → feature-directories-2MMZPQM5.js.map} +1 -1
- package/dist/{finalization-3YYUBUTJ.js → finalization-7Q7PAV5J.js} +6 -5
- package/dist/{gh-cli-7XMXAKF7.js → gh-cli-4ASCBV6O.js} +3 -2
- package/dist/{github-rest-S2INRKNE.js → github-rest-FEBO3WJO.js} +6 -5
- package/dist/{github-rest-S2INRKNE.js.map → github-rest-FEBO3WJO.js.map} +1 -1
- package/dist/index.js +4 -3
- package/dist/{learning-sync-6ESNEZTX.js → learning-sync-XMWOGO72.js} +4 -3
- package/dist/{learning-sync-6ESNEZTX.js.map → learning-sync-XMWOGO72.js.map} +1 -1
- package/dist/{legacy-global-guidance-JPJBHFMW.js → legacy-global-guidance-Q45EDKB2.js} +5 -4
- package/dist/{lint-gherkin-UHMNF5SD.js → lint-gherkin-WRGJQFSQ.js} +8 -7
- package/dist/{lint-gherkin-UHMNF5SD.js.map → lint-gherkin-WRGJQFSQ.js.map} +1 -1
- package/dist/migrate-codex-plugin-65N3EQFX.js +39 -0
- package/dist/{output-DCTUSINZ.js → output-5KEYCOQM.js} +3 -2
- package/dist/{plan-RRN2ESJ7.js → plan-GDQ5MLFP.js} +15 -14
- package/dist/{plan-RRN2ESJ7.js.map → plan-GDQ5MLFP.js.map} +1 -1
- package/dist/presets/typescript/index.js +4 -3
- package/dist/profile-BNQL7PTZ.js +24 -0
- package/dist/prompt-SCCI7GNE.js +8 -0
- package/dist/{remove-GNAT5APA.js → remove-B7R4ACGX.js} +16 -15
- package/dist/{remove-GNAT5APA.js.map → remove-B7R4ACGX.js.map} +1 -1
- package/dist/retro-M643IMX6.js +3170 -0
- package/dist/retro-M643IMX6.js.map +1 -0
- package/dist/{retro-draft-spool-OU4YMZQO.js → retro-draft-spool-MAP37TNR.js} +6 -3
- package/dist/{retro-extract-E5F5A35R.js → retro-extract-JH7R6GUZ.js} +12 -3
- package/dist/{run-HQCZ67WE.js → run-B4I3UOXV.js} +7 -6
- package/dist/{run-HQCZ67WE.js.map → run-B4I3UOXV.js.map} +1 -1
- package/dist/{self-report-EBTIB7G3.js → self-report-PHAQ6LHB.js} +6 -3
- package/dist/{status-ILKQIXSD.js → status-X6FSZJFP.js} +25 -22
- package/dist/{status-ILKQIXSD.js.map → status-X6FSZJFP.js.map} +1 -1
- package/dist/status-YZIWSG6P.js +19 -0
- package/dist/{sync-config-N7U2FXWV.js → sync-config-D7H2UFLO.js} +5 -4
- package/dist/{sync-tracker-EMEVBKQS.js → sync-tracker-W2BVBY7K.js} +13 -12
- package/dist/{sync-tracker-EMEVBKQS.js.map → sync-tracker-W2BVBY7K.js.map} +1 -1
- package/dist/{test-plan-QAQT6OXT.js → test-plan-Q7LOS4P6.js} +6 -5
- package/dist/{test-plan-QAQT6OXT.js.map → test-plan-Q7LOS4P6.js.map} +1 -1
- package/dist/{ticket-new-Y2QIVBHL.js → ticket-new-USRB2XOT.js} +10 -9
- package/dist/{ticket-new-Y2QIVBHL.js.map → ticket-new-USRB2XOT.js.map} +1 -1
- package/dist/{ticket-sync-5XRY6Q2Z.js → ticket-sync-EJWYJVLR.js} +5 -4
- package/dist/{tracker-map-PAHJEOGE.js → tracker-map-3X2IOQ44.js} +3 -2
- package/dist/tracker-sync-LHSE4LYA.js +13 -0
- package/dist/tracker-sync-LHSE4LYA.js.map +1 -0
- package/package.json +2 -1
- package/templates/SAFEWORD.md +1 -1
- package/templates/agents/safeword-retro-filer.md +1 -1
- package/templates/doc-templates/tripwire-template.md +68 -0
- package/templates/guides/retro.md +6 -0
- package/templates/guides/self-report-filing.md +5 -5
- package/templates/guides/testing-guide.md +81 -0
- package/templates/hooks/lib/bash-ledger-writes.ts +0 -4
- package/templates/hooks/lib/closeout-binding.ts +29 -6
- package/templates/hooks/lib/dependency-readiness.ts +73 -8
- package/templates/hooks/lib/process-kill-guard.ts +1 -3
- package/templates/hooks/lib/quality.ts +261 -15
- package/templates/hooks/lib/retro-draft-spool.ts +30 -6
- package/templates/hooks/lib/retro-extract.ts +192 -33
- package/templates/hooks/lib/retro-filing-gate.ts +83 -26
- package/templates/hooks/lib/retro-nudge.ts +12 -7
- package/templates/hooks/lib/self-report.ts +28 -0
- package/templates/hooks/lib/shell-segments.ts +10 -2
- package/templates/hooks/pre-tool-architecture-stage.ts +13 -4
- package/templates/hooks/pre-tool-dependency-readiness.ts +9 -0
- package/templates/hooks/prompt-retro-nudge.ts +3 -2
- package/templates/hooks/record-skill-invocation.ts +3 -1
- package/templates/hooks/session-reply-format.ts +27 -0
- package/templates/hooks/stop-quality.ts +9 -1
- package/templates/hooks/stop-retro-filing.ts +1 -1
- package/templates/hooks/stop-retro.ts +1 -3
- package/templates/scripts/closeout-cleanup.ts +229 -50
- package/templates/skills/bdd/SCENARIOS.md +6 -6
- package/templates/skills/closeout/SKILL.md +20 -7
- package/templates/skills/debug/SKILL.md +19 -3
- package/templates/skills/retro-filer/SKILL.md +1 -1
- package/templates/skills/testing/SKILL.md +20 -0
- package/dist/boundary-J2RW4N3E.js.map +0 -1
- package/dist/chunk-2MQTOSGG.js +0 -312
- package/dist/chunk-2MQTOSGG.js.map +0 -1
- package/dist/chunk-F4CA33GP.js.map +0 -1
- package/dist/chunk-I5QEPYVK.js.map +0 -1
- package/dist/chunk-MLEJHDVU.js.map +0 -1
- package/dist/chunk-OSBX5BZS.js.map +0 -1
- package/dist/chunk-PGUVVBIN.js.map +0 -1
- package/dist/chunk-QPWX5JXI.js.map +0 -1
- package/dist/chunk-XIGSW56Z.js.map +0 -1
- package/dist/chunk-Y6LUZKTN.js +0 -144
- package/dist/chunk-Y6LUZKTN.js.map +0 -1
- package/dist/cleanup-STJVSD7S.js.map +0 -1
- package/dist/codex-hook-HBEPMPEK.js.map +0 -1
- package/dist/config-X5ZFCS6Q.js +0 -7
- package/dist/converge-setup-6WS2RMSG.js.map +0 -1
- package/dist/corpus-XW3XX3F5.js +0 -14
- package/dist/migrate-codex-plugin-CPLYYCGP.js.map +0 -1
- package/dist/profile-DM4UNHMN.js +0 -17
- package/dist/prompt-OD3EGKOL.js +0 -7
- package/dist/retro-XO7CALV4.js +0 -687
- package/dist/retro-XO7CALV4.js.map +0 -1
- package/dist/status-5DDTQIJU.js +0 -16
- package/dist/tracker-sync-P6DLDWJ2.js +0 -12
- /package/dist/{architecture-document-KFR4JDUT.js.map → architecture-document-CTLCH76G.js.map} +0 -0
- /package/dist/{architecture-monorepo-QQ2OCQMC.js.map → architecture-monorepo-XWJN3X5I.js.map} +0 -0
- /package/dist/{chunk-LX6G2SZC.js.map → chunk-2D5IR56T.js.map} +0 -0
- /package/dist/{chunk-RFP2MSVO.js.map → chunk-2MI7M2CO.js.map} +0 -0
- /package/dist/{chunk-5KUTV6L5.js.map → chunk-3D6BHVQX.js.map} +0 -0
- /package/dist/{chunk-5GPCAAVW.js.map → chunk-56BJOCCK.js.map} +0 -0
- /package/dist/{chunk-ZQCKTQKJ.js.map → chunk-5XHVFUX5.js.map} +0 -0
- /package/dist/{chunk-PPQOPS6F.js.map → chunk-6GQX7IJP.js.map} +0 -0
- /package/dist/{chunk-UW3BGLRB.js.map → chunk-6MK7T6BV.js.map} +0 -0
- /package/dist/{chunk-GUIZH3NI.js.map → chunk-6S7CTKGC.js.map} +0 -0
- /package/dist/{chunk-X26EJNPZ.js.map → chunk-7G6OSNIV.js.map} +0 -0
- /package/dist/{chunk-2OBVDGB4.js.map → chunk-FS2LEZBO.js.map} +0 -0
- /package/dist/{chunk-7BRCUXTB.js.map → chunk-G7ZPEVA3.js.map} +0 -0
- /package/dist/{chunk-KWBGQ2YZ.js.map → chunk-JBA7AB6K.js.map} +0 -0
- /package/dist/{chunk-QWL47LKR.js.map → chunk-JBOLNV2L.js.map} +0 -0
- /package/dist/{chunk-AF6L253C.js.map → chunk-K64BTVJ7.js.map} +0 -0
- /package/dist/{chunk-MDXMCB37.js.map → chunk-KULHJBJ6.js.map} +0 -0
- /package/dist/{chunk-OWGNCT45.js.map → chunk-LXUBCIMR.js.map} +0 -0
- /package/dist/{chunk-RLH5PLSD.js.map → chunk-NRTOKMGY.js.map} +0 -0
- /package/dist/{chunk-4HWB6QFG.js.map → chunk-NSK2HI7O.js.map} +0 -0
- /package/dist/{chunk-ZFM3XTN3.js.map → chunk-NYTHQ2B5.js.map} +0 -0
- /package/dist/{chunk-QYO5EMNH.js.map → chunk-O2TTGWG6.js.map} +0 -0
- /package/dist/{chunk-TOLJ6T4S.js.map → chunk-PQCE5GIH.js.map} +0 -0
- /package/dist/{chunk-UM7PJKBV.js.map → chunk-PZTGLQSD.js.map} +0 -0
- /package/dist/{chunk-KWOEDO5W.js.map → chunk-QOIQQY4E.js.map} +0 -0
- /package/dist/{chunk-DAFOEHJA.js.map → chunk-QSLVO4XF.js.map} +0 -0
- /package/dist/{chunk-IEBFBHR2.js.map → chunk-SK6TC4BO.js.map} +0 -0
- /package/dist/{chunk-PAC2VLLK.js.map → chunk-SPK32BMX.js.map} +0 -0
- /package/dist/{chunk-PUNN7MZ6.js.map → chunk-TJ627SKI.js.map} +0 -0
- /package/dist/{chunk-X2OHUUNE.js.map → chunk-U7OZP77P.js.map} +0 -0
- /package/dist/{chunk-WPDGHG6D.js.map → chunk-UAFM77KW.js.map} +0 -0
- /package/dist/{chunk-4DGDH7SG.js.map → chunk-UDLS7BHG.js.map} +0 -0
- /package/dist/{chunk-MMSUTN3X.js.map → chunk-ULY7JQH4.js.map} +0 -0
- /package/dist/{chunk-ZESGPJCY.js.map → chunk-URVJZ4NL.js.map} +0 -0
- /package/dist/{chunk-XH6FTCM7.js.map → chunk-USGSZ4Y4.js.map} +0 -0
- /package/dist/{chunk-KG7MFUUQ.js.map → chunk-UTO5XZ4S.js.map} +0 -0
- /package/dist/{chunk-7NZ26QJP.js.map → chunk-VEIP5Y7K.js.map} +0 -0
- /package/dist/{chunk-O5JEWG3M.js.map → chunk-XHNWNZRM.js.map} +0 -0
- /package/dist/{chunk-AKPXZ75V.js.map → chunk-XQV3MM3G.js.map} +0 -0
- /package/dist/{chunk-FLMWLQHK.js.map → chunk-YP2V3YUV.js.map} +0 -0
- /package/dist/{chunk-PSKZASFR.js.map → chunk-Z4ESH6KU.js.map} +0 -0
- /package/dist/{clients-2EXYFMMV.js.map → clients-3R4XYZVV.js.map} +0 -0
- /package/dist/{config-X5ZFCS6Q.js.map → config-37744FRY.js.map} +0 -0
- /package/dist/{configured-paths-TXRFWRTV.js.map → configured-paths-O3WBQ3NC.js.map} +0 -0
- /package/dist/{corpus-XW3XX3F5.js.map → corpus-QCEGFTUQ.js.map} +0 -0
- /package/dist/{finalization-3YYUBUTJ.js.map → finalization-7Q7PAV5J.js.map} +0 -0
- /package/dist/{gh-cli-7XMXAKF7.js.map → gh-cli-4ASCBV6O.js.map} +0 -0
- /package/dist/{legacy-global-guidance-JPJBHFMW.js.map → legacy-global-guidance-Q45EDKB2.js.map} +0 -0
- /package/dist/{output-DCTUSINZ.js.map → migrate-codex-plugin-65N3EQFX.js.map} +0 -0
- /package/dist/{profile-DM4UNHMN.js.map → output-5KEYCOQM.js.map} +0 -0
- /package/dist/{prompt-OD3EGKOL.js.map → profile-BNQL7PTZ.js.map} +0 -0
- /package/dist/{retro-draft-spool-OU4YMZQO.js.map → prompt-SCCI7GNE.js.map} +0 -0
- /package/dist/{retro-extract-E5F5A35R.js.map → retro-draft-spool-MAP37TNR.js.map} +0 -0
- /package/dist/{self-report-EBTIB7G3.js.map → retro-extract-JH7R6GUZ.js.map} +0 -0
- /package/dist/{status-5DDTQIJU.js.map → self-report-PHAQ6LHB.js.map} +0 -0
- /package/dist/{sync-config-N7U2FXWV.js.map → status-YZIWSG6P.js.map} +0 -0
- /package/dist/{ticket-sync-5XRY6Q2Z.js.map → sync-config-D7H2UFLO.js.map} +0 -0
- /package/dist/{tracker-map-PAHJEOGE.js.map → ticket-sync-EJWYJVLR.js.map} +0 -0
- /package/dist/{tracker-sync-P6DLDWJ2.js.map → tracker-map-3X2IOQ44.js.map} +0 -0
package/codex-plugin/hooks.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "bunx --bun safeword@0.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
###
|
|
21
|
+
### Are the scenarios complete?
|
|
22
22
|
|
|
23
|
-
|
|
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:**
|
|
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
|
|
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
|
-
###
|
|
203
|
+
### Are the reviewed scenarios complete?
|
|
204
204
|
|
|
205
|
-
If the adversarial pass
|
|
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).
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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.
|
|
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
|
-
####
|
|
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
|
-
####
|
|
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
|
|
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-
|
|
7
|
+
} from "./chunk-PZTGLQSD.js";
|
|
8
8
|
import {
|
|
9
9
|
discoverUnreadableWorkspaces,
|
|
10
10
|
extractMonorepoArchitectureSnapshot
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YP2V3YUV.js";
|
|
12
12
|
import {
|
|
13
13
|
error,
|
|
14
14
|
success,
|
|
15
15
|
warn
|
|
16
|
-
} from "./chunk-
|
|
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-
|
|
23
|
+
} from "./chunk-2MI7M2CO.js";
|
|
24
24
|
import {
|
|
25
25
|
readJson,
|
|
26
26
|
writeJson
|
|
27
|
-
} from "./chunk-
|
|
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-
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,OAAO,cAAc;AACrB,OAAO,aAAa;AAwBpB,IAAM,gCAAgC;AACtC,IAAM,qCAAqC;AAgB3C,IAAM,kBAAwC,EAAE,SAAS,MAAM,MAAM;AAErE,eAAsB,aACpB,MAAc,QAAQ,IAAI,GAC1B,UAAkE,CAAC,GACpD;AACf,MAAI,QAAQ,OAAO;AACjB,UAAM,kBAAkB,GAAG;AAC3B;AAAA,EACF;AACA,MAAI,QAAQ,OAAO;AACjB,UAAM,kBAAkB,GAAG;AAC3B;AAAA,EACF;AACA,MAAI,QAAQ,QAAQ;AAClB,UAAM,mBAAmB,GAAG;AAC5B;AAAA,EACF;AAEA,uBAAqB,GAAG;AAC1B;AAEA,SAAS,qBACP,KACA,WAAiC,iBACf;AAClB,QAAM,UAAU,gBAAgB,GAAG;AACnC,aAAW,UAAU,SAAS;AAC5B,aAAS,QAAQ,+BAA+B,OAAO,MAAM,KAAK,OAAO,IAAI,EAAE;AAAA,EACjF;AACA,2BAAyB,KAAK,QAAQ;AACtC,SAAO;AACT;AAUA,SAAS,yBACP,KACA,WAAiC,iBAC3B;AACN,aAAW,aAAa,6BAA6B,GAAG,GAAG;AACzD,aAAS;AAAA,MACP,4CAA4C,UAAU,MAAM,KAAK,UAAU,OAAO;AAAA,IACpF;AAAA,EACF;AACF;AAOO,SAAS,kBACd,KACA,WAAiC,iBACC;AAClC,MAAI,UAAqC,CAAC;AAC1C,QAAM,cAAwB,CAAC;AAC/B,QAAM,gBAA0B,CAAC;AACjC,MAAI,qBAAqB;AACzB,MAAI;AACF,QAAI,CAAC,yCAAyC,GAAG,GAAG;AAClD,+BAAyB,KAAK,QAAQ;AACtC,eAAS;AAAA,QACP;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,kBAAkB,GAAG;AACxC,QAAI,eAAe,QAAW;AAC5B,2BAAqB;AACrB,eAAS;AAAA,QACP;AAAA,MACF;AACA,gBAAU,qBAAqB,KAAK,QAAQ;AAC5C,aAAO,QAAQ,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAEA,yBAAqB,KAAK,YAAY,uBAAqB;AACzD,+BAAyB,mBAAmB,QAAQ;AACpD,YAAM,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,gBAAU,aAAa;AACvB,YAAM,UAAU,aAAa,QAAQ,OAAO,YAAU,oBAAoB,OAAO,MAAM,CAAC;AACxF,UAAI,QAAQ,WAAW,GAAG;AACxB,YAAI,aAAa,wBAAwB,GAAG;AAC1C,mBAAS,QAAQ,mCAAmC;AAAA,QACtD,OAAO;AACL,gBAAM,YAAY,GAAG,aAAa,mBAAmB,IACnD,aAAa,wBAAwB,IAAI,gBAAgB,eAC3D;AACA,mBAAS,QAAQ,qCAAqC,SAAS,IAAI;AAAA,QACrE;AAAA,MACF,OAAO;AACL,mBAAW,UAAU,SAAS;AAC5B,gBAAM,UAAU,0BAA0B,KAAK,QAAQ,QAAQ;AAC/D,gBAAM,eAAe,SAAS,SAAS,KAAK,OAAO,IAAI;AACvD,cAAI,YAAY,OAAW,aAAY,KAAK,YAAY;AAAA,cACnD,eAAc,KAAK,YAAY;AAAA,QACtC;AAAA,MACF;AAAA,IACF,CAAC;AACD,+BAA2B,KAAK,QAAQ;AAAA,EAC1C,SAAS,QAAQ;AACf,yBAAqB;AACrB,aAAS;AAAA,MACP,qHAAqH,aAAa,MAAM,CAAC;AAAA,IAC3I;AAAA,EACF;AACA,SAAO,QAAQ,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AACH;AAOA,SAAS,4BAA4B,aAAqB,SAAuC;AAC/F,QAAM,YAAY,YAAY,SAAS,KAAK,OAAO,GAAG,iCAAiC,CAAC;AACxF,QAAM,OAAO,SAAS,KAAK,WAAW,GAAG,SAAS,SAAS,WAAW,CAAC,WAAW;AAClF,MAAI;AACF,kBAAc,MAAM,SAAS,EAAE,MAAM,IAAM,CAAC;AAC5C,WAAO,EAAE,WAAW,KAAK;AAAA,EAC3B,SAAS,QAAQ;AACf,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,UAAM;AAAA,EACR;AACF;AAEA,SAAS,4BACP,KACA,QACA,cACA,QACA,UACM;AACN,MACE,OAAO,2BAA2B,UAClC,QAAQ,IAAI,kCAAkC,MAAM,KACpD;AACA;AAAA,EACF;AACA,MAAI;AACF,uCAAmC,OAAO,wBAAwB,OAAO,MAAM,GAAG;AAClF,QAAI,iBAAiB,QAAW;AAC9B,aAAO,aAAa,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACjE;AACA,aAAS,KAAK,mDAAmD,OAAO,IAAI,EAAE;AAAA,EAChF,SAAS,QAAQ;AACf,aAAS;AAAA,MACP,oBAAoB,SAAS,eAAe,gBAAgB,uDAAuD,OAAO,IAAI,oBAAoB,cAAc,QAAQ,aAAa,YAAY,aAAa,MAAM,CAAC;AAAA,IACvN;AAAA,EACF;AACF;AAEA,SAAS,0BACP,KACA,QACA,UACoB;AACpB,QAAM,gBACJ,OAAO,2BAA2B,UAClC,QAAQ,IAAI,kCAAkC,MAAM;AACtD,MAAI;AACJ,MAAI,SAAS;AACb,MAAI;AACF,QAAI,iBAAiB,OAAO,2BAA2B,QAAW;AAChE,qBAAe,4BAA4B,OAAO,MAAM,OAAO,sBAAsB;AAAA,IACvF;AACA,UAAM,eAAe,cAAc,KAAK,MAAM;AAC9C,QAAI,iBAAiB,QAAW;AAC9B,eAAS;AACT,eAAS,QAAQ,oBAAoB,OAAO,MAAM,gBAAgB,OAAO,IAAI,EAAE;AAAA,IACjF,OAAO;AACL,eAAS;AAAA,QACP,oBAAoB,OAAO,MAAM,6BAA6B,OAAO,IAAI,YAAY,YAAY;AAAA,MACnG;AAAA,IACF;AACA,WAAO;AAAA,EACT,UAAE;AACA,gCAA4B,KAAK,QAAQ,cAAc,QAAQ,QAAQ;AAAA,EACzE;AACF;AAOO,SAAS,mBACd,KACA,WAAiC,iBACC;AAClC,MAAI,UAAqC,CAAC;AAC1C,MAAI;AACF,UAAM,aAAa,kBAAkB,GAAG;AACxC,QAAI,eAAe,QAAW;AAC5B,eAAS,KAAK,6DAA6D;AAC3E,gBAAU,qBAAqB,KAAK,QAAQ;AAC5C,aAAO,QAAQ,QAAQ;AAAA,QACrB;AAAA,QACA,aAAa,CAAC;AAAA,QACd,eAAe,CAAC;AAAA,QAChB,QAAQ;AAAA,QACR,oBAAoB;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,yBAAqB,KAAK,YAAY,uBAAqB;AACzD,+BAAyB,mBAAmB,QAAQ;AACpD,YAAM,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,gBAAU,aAAa;AACvB,iBAAW,UAAU,aAAa,SAAS;AACzC,iBAAS,QAAQ,+BAA+B,OAAO,MAAM,KAAK,OAAO,IAAI,EAAE;AAAA,MACjF;AAAA,IACF,CAAC;AACD,+BAA2B,KAAK,QAAQ;AAAA,EAC1C,SAAS,QAAQ;AACf,aAAS;AAAA,MACP,wGAAwG,aAAa,MAAM,CAAC;AAAA,IAC9H;AACA,WAAO,QAAQ,QAAQ;AAAA,MACrB;AAAA,MACA,aAAa,CAAC;AAAA,MACd,eAAe,CAAC;AAAA,MAChB,QAAQ;AAAA,MACR,oBAAoB;AAAA,IACtB,CAAC;AAAA,EACH;AACA,SAAO,QAAQ,QAAQ;AAAA,IACrB;AAAA,IACA,aAAa,CAAC;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,QAAQ;AAAA,IACR,oBAAoB;AAAA,EACtB,CAAC;AACH;AAOA,SAAS,qBACP,KACA,YACA,aACG;AACH,QAAM,oBAAoB,YAAY,SAAS,KAAK,OAAO,GAAG,8BAA8B,CAAC;AAC7F,QAAM,kBAAkB,QAAQ,IAAI,6BAA6B;AACjE,QAAM,yBACJ,oBAAoB,SAAY,SAAY,EAAE,GAAG,QAAQ,KAAK,gBAAgB,gBAAgB;AAChG,MAAI;AACF,qBAAiB,YAAY,sBAAsB;AACnD;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,iBAAiB,GAAG,SAAS,GAAG;AAAA,MAC9C;AAAA,MACA;AAAA,QACE,KAAK,WAAW;AAAA,QAChB,GAAI,0BAA0B,EAAE,KAAK,uBAAuB;AAAA,QAC5D,OAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,2BAA2B,SAAS;AAAA,MACxC;AAAA,MACA,WAAW;AAAA,IACb;AACA,+BAA2B,KAAK,wBAAwB;AACxD,WAAO,YAAY,wBAAwB;AAAA,EAC7C,UAAE;AACA,WAAO,mBAAmB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAC5D;AACF;AAEA,IAAM,sBAAsB;AAG5B,SAAS,iBACP,YACA,wBACM;AACN,QAAM,gBACJ,WAAW,6BAA6B,KAAK,CAAC,IAAI,CAAC,WAAW,wBAAwB;AACxF,QAAM,UAAU;AAAA,IACd;AAAA,IACA,CAAC,YAAY,WAAW,MAAM,eAAe,MAAM,GAAG,aAAa;AAAA,IACnE;AAAA,MACE,KAAK,WAAW;AAAA,MAChB,UAAU;AAAA,MACV,GAAI,0BAA0B,EAAE,KAAK,uBAAuB;AAAA,MAC5D,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC;AAAA,EACF,EACG,MAAM,IAAI,EACV,OAAO,WAAS,MAAM,WAAW,mBAAmB,CAAC;AACxD,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,QAAQ,QAAQ,IAAI,WAAS,MAAM,MAAM,MAAM,QAAQ,GAAI,IAAI,CAAC,CAAC;AACvE,QAAM,IAAI;AAAA,IACR,4EAA4E,MAAM,KAAK,IAAI,CAAC;AAAA,EAC9F;AACF;AAQA,SAAS,kBAAkB,KAAqC;AAC9D,MAAI;AACJ,MAAI;AACF,oBAAgB,aAAa,OAAO,CAAC,aAAa,iBAAiB,GAAG;AAAA,MACpE;AAAA,MACA,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC,CAAC,EAAE,KAAK;AAAA,EACV,SAAS,QAAQ;AACf,QAAK,OAAiC,SAAS,UAAU;AACvD,YAAM,IAAI,MAAM,kCAAkC,EAAE,OAAO,OAAO,CAAC;AAAA,IACrE;AACA,WAAO;AAAA,EACT;AACA,MAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,QAAM,gBAAgB,aAAa,aAAa;AAChD,QAAM,mBAAmB,aAAa,GAAG;AACzC,QAAM,2BAA2B,SAAS,SAAS,eAAe,gBAAgB;AAClF,MACE,SAAS,WAAW,wBAAwB,KAC5C,6BAA6B,QAC7B,yBAAyB,WAAW,KAAK,SAAS,GAAG,EAAE,GACvD;AACA,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AACA,SAAO,EAAE,eAAe,eAAe,yBAAyB;AAClE;AAOA,SAAS,2BAA2B,KAAa,mBAAiC;AAChF,QAAM,iBAAiB,mBAAmB,mBAAmB,aAAa;AAC1E,MAAI,mBAAmB,OAAW;AAElC,QAAM,mBAAmB,gBAAgB,KAAK,cAAc;AAC5D,MAAI,qBAAqB,QAAW;AAClC,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,4BAA0B,mBAAmB,SAAS,KAAK,mBAAmB,gBAAgB,CAAC;AAC/F,MAAI,CAAC,SAAS,WAAW,cAAc,EAAG;AAE1C,6BAA2B,mBAAmB,gBAAgB;AAChE;AAEA,SAAS,2BAA2B,mBAA2B,kBAAgC;AAC7F,QAAM,aAAa,SAAS,KAAK,mBAAmB,aAAa,aAAa;AAC9E,QAAM,SAAS,SAAS,UAAU;AAClC,MAAI,WAAW,UAAa,OAAO,WAAW,YAAY,WAAW,KAAM;AAC3E,QAAM,QAAS,OAA+B;AAC9C,MAAI,UAAU,UAAa,OAAO,UAAU,YAAY,UAAU,KAAM;AACxE,YAAU,YAAY;AAAA,IACpB,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG;AAAA,MACH,aAAa,qBAAqB,KAAK,MAAM;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;AAQA,SAAS,0BAA0B,eAAuB,eAA6B;AACrF,MAAI,gBAAgB,eAAe,aAAa,MAAM,QAAW;AAC/D,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AAEA,MAAI,mBAAmB;AACvB,aAAS;AACP,QAAI;AACF,gBAAU,gBAAgB;AAC1B;AAAA,IACF,SAAS,QAAQ;AACf,UAAK,OAAiC,SAAS,SAAU,OAAM;AAC/D,YAAM,SAAS,SAAS,QAAQ,gBAAgB;AAChD,UAAI,WAAW,iBAAkB,OAAM;AACvC,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,gBAAgB,aAAa,aAAa;AAChD,QAAM,oBAAoB,aAAa,gBAAgB;AACvD,MAAI,gBAAgB,eAAe,iBAAiB,MAAM,QAAW;AACnE,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AACF;AAGA,SAAS,mCAAmC,mBAAiC;AAC3E,QAAM,EAAE,OAAO,IAAI,oCAAoC,iBAAiB;AACxE,QAAM,UAAU;AAAA,IACd,iCAAiC,iBAAiB;AAAA,IAClD,GAAG,OAAO,IAAI,UAAQ,SAAS,KAAK,KAAK,KAAK,+BAA+B,CAAC;AAAA,EAChF;AACA,aAAW,UAAU,SAAS;AAC5B,8BAA0B,mBAAmB,MAAM;AAAA,EACrD;AACF;AAOA,SAAS,gCACP,aACA,aACA,oBACM;AACN,QAAM,uBAAuB,SAAS,QAAQ,WAAW;AACzD,4BAA0B,aAAa,WAAW;AAClD,YAAU,sBAAsB,EAAE,WAAW,KAAK,CAAC;AAMnD,MAAI,qBAAqB;AAAA,IACvB,SAAS,KAAK,OAAO,GAAG,oCAAoC;AAAA,EAC9D;AACA,MAAI,UAAU,kBAAkB,EAAE,QAAQ,UAAU,oBAAoB,EAAE,KAAK;AAC7E,WAAO,oBAAoB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC3D,yBAAqB;AAAA,MACnB,SAAS,KAAK,sBAAsB,yBAAyB;AAAA,IAC/D;AAAA,EACF;AACA,MAAI;AACF,UAAM,gBAAgB,SAAS,KAAK,oBAAoB,SAAS,SAAS,WAAW,CAAC;AACtF,uBAAmB,aAAa;AAChC,eAAW,eAAe,WAAW;AAAA,EACvC,UAAE;AACA,WAAO,oBAAoB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAC7D;AACF;AAEA,SAAS,4BACP,QACA,aACA,aACM;AACN,kCAAgC,aAAa,aAAa,mBAAiB;AACzE,iBAAa,QAAQ,aAAa;AAAA,EACpC,CAAC;AACH;AAEA,SAAS,mCACP,SACA,aACA,aACM;AACN,kCAAgC,aAAa,aAAa,mBAAiB;AACzE,kBAAc,eAAe,OAAO;AAAA,EACtC,CAAC;AACH;AAyCA,SAAS,wBACP,KACA,mBACA,MACA,WAAiC,iBACP;AAC1B,qCAAmC,iBAAiB;AACpD,QAAM,SAAS,2BAA2B,IAAI;AAC9C,QAAM,QAAQ,0BAA0B,KAAK,mBAAmB,MAAM;AACtE,iCAA+B,KAAK,OAAO,QAAQ,QAAQ;AAE3D,QAAM,iBAA6C,CAAC;AACpD,MAAI;AACF,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,KAAK,YAAa;AACvB,qBAAe,KAAK,IAAI;AACxB,kCAA4B,KAAK,OAAO,MAAM,KAAK,aAAa,GAAG;AAAA,IACrE;AAAA,EACF,SAAS,sBAAsB;AAC7B,UAAM,iBAAiB,4BAA4B,KAAK,cAAc;AACtE,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR,CAAC,sBAAsB,GAAG,cAAc;AAAA,QACxC;AAAA,QACA,EAAE,OAAO,qBAAqB;AAAA,MAChC;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAEA,SAAO;AAAA,IACL,SAAS,MACN,OAAO,UAAQ,CAAC,KAAK,cAAc,EACnC,IAAI,CAAC,EAAE,QAAQ,aAAa,uBAAuB,OAAO;AAAA,MACzD,QAAQ,OAAO;AAAA,MACf,MAAM;AAAA,MACN;AAAA,IACF,EAAE;AAAA,IACJ,qBAAqB,MAAM,OAAO,UAAQ,KAAK,cAAc,EAAE;AAAA,EACjE;AACF;AAEA,SAAS,0BACP,KACA,mBACA,QAC4B;AAC5B,SAAO,+BAA+B,mBAAmB,KAAK;AAAA,IAC5D,iBAAiB,OAAO;AAAA,IACxB,wBAAwB,OAAO;AAAA,EACjC,CAAC,EAAE,IAAI,YAAU;AACf,UAAM,eAAe,SAAS,SAAS,mBAAmB,OAAO,IAAI;AACrE,QACE,iBAAiB,MACjB,SAAS,WAAW,YAAY,KAChC,iBAAiB,QACjB,aAAa,WAAW,KAAK,SAAS,GAAG,EAAE,GAC3C;AACA,YAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AAEA,WAAO;AAAA,MACL;AAAA,MACA,aAAa,SAAS,KAAK,KAAK,YAAY;AAAA,MAC5C,aACE,oBAAoB,OAAO,MAAM,KAChC,OAAO,kBAAkB,OAAO,WAAW;AAAA,IAChD;AAAA,EACF,CAAC;AACH;AAMA,SAAS,+BACP,KACA,OACA,QACA,UACM;AACN,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,YAAa;AACvB,8BAA0B,KAAK,KAAK,WAAW;AAC/C,SAAK,qBAAqB,0BAA0B,KAAK,WAAW;AACpE,QAAI,KAAK,mBAAmB,WAAW,CAAC,gBAAgB,KAAK,mBAAmB,OAAO,GAAG;AACxF,UAAI,OAAO,yBAAyB;AAClC,aAAK,iBAAiB;AACtB,aAAK,cAAc;AACnB,iBAAS;AAAA,UACP,0EAA0E,KAAK,WAAW;AAAA,QAC5F;AACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,0EAA0E,KAAK,WAAW;AAAA,MAC5F;AAAA,IACF;AACA,SAAK,yBACH,OAAO,2BAA2B,oBAAoB,KAAK,OAAO,MAAM,IACpE,6BAA6B,KAAK,KAAK,WAAW,IAClD;AAAA,EACR;AACF;AAEA,SAAS,2BAA2B,MAA4D;AAC9F,UAAQ,MAAM;AAAA,IACZ,KAAK,kBAAkB;AACrB,YAAM,mBAAmB,QAAQ,IAAI,kCAAkC,MAAM;AAC7E,aAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,wBAAwB;AAAA,QACxB,gBAAgB;AAAA,QAChB,yBAAyB,CAAC;AAAA,QAC1B,yBAAyB;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,KAAK,uBAAuB;AAC1B,aAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,wBAAwB;AAAA,QACxB,gBAAgB;AAAA,QAChB,yBAAyB;AAAA,QACzB,yBAAyB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,0BAA0B,aAA4C;AAC7E,MAAI;AACF,WAAO,EAAE,SAAS,MAAM,SAAS,aAAa,aAAa,MAAM,EAAE;AAAA,EACrE,SAAS,QAAQ;AACf,QAAK,OAAiC,SAAS,SAAU,QAAO,EAAE,SAAS,MAAM;AACjF,UAAM;AAAA,EACR;AACF;AAEA,SAAS,4BAA4B,KAAa,OAA8C;AAC9F,QAAM,SAAoB,CAAC;AAC3B,aAAW,QAAQ,MAAM,WAAW,GAAG;AACrC,QAAI;AACF,YAAM,aAAa,KAAK;AACxB,UAAI,eAAe,OAAW;AAC9B,UAAI,WAAW,SAAS;AACtB,2CAAmC,WAAW,SAAS,KAAK,aAAa,GAAG;AAAA,MAC9E,OAAO;AACL,kCAA0B,KAAK,KAAK,WAAW;AAC/C,eAAO,KAAK,aAAa,EAAE,OAAO,KAAK,CAAC;AAAA,MAC1C;AAAA,IACF,SAAS,QAAQ;AACf,aAAO,KAAK,MAAM;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAOA,SAAS,6BAA6B,KAAa,aAAyC;AAC1F,4BAA0B,KAAK,WAAW;AAC1C,MAAI;AACJ,MAAI;AACF,sBAAkB,aAAa,aAAa,MAAM;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,SAAS,SAAS,KAAK,WAAW;AACvD,MAAI;AACJ,MAAI;AACF,UAAM,sBAAsB,aAAa,WAAW,MAAM,GAAG;AAC7D,mBAAe,aAAa,OAAO,CAAC,QAAQ,MAAM,mBAAmB,EAAE,GAAG;AAAA,MACxE;AAAA,MACA,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACA,SAAO,oBAAoB,eAAe,SAAY;AACxD;AAGA,SAAS,cAAc,KAAa,QAA4C;AAC9E,MAAI;AACF,UAAM,eAAe,SAAS,SAAS,KAAK,OAAO,IAAI;AACvD,iBAAa,OAAO,CAAC,OAAO,MAAM,YAAY,GAAG,EAAE,KAAK,OAAO,SAAS,CAAC;AACzE,WAAO;AAAA,EACT,SAAS,QAAQ;AACf,WAAO,aAAa,MAAM;AAAA,EAC5B;AACF;AAEA,IAAM,+BAA+B,oBAAI,IAAI;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,6BAA6B,MAAuB;AAC3D,QAAM,aAAa,KAAK,WAAW,MAAM,GAAG;AAC5C,QAAM,WAAW,WAAW,MAAM,GAAG;AACrC,QAAM,WAAW,SAAS,GAAG,EAAE,KAAK;AACpC,SACE,eAAe,2BACf,SAAS,SAAS,KAAK,KACvB,SAAS,SAAS,KAAK,KACvB,6BAA6B,IAAI,QAAQ,KACzC,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,MAAM,KAC1B,kBAAkB,IAAI,SAAS,MAAM,QAAQ,QAAQ,CAAC;AAE1D;AAEA,SAAS,qBAAqB,KAAa,MAA0B;AACnE,MAAI;AACF,WAAO,aAAa,OAAO,MAAM;AAAA,MAC/B;AAAA,MACA,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC,CAAC,EACE,MAAM,IAAI,EACV,OAAO,UAAQ,KAAK,SAAS,CAAC;AAAA,EACnC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,SAAS,2BACP,KACA,WAAiC,iBAC3B;AACN,QAAM,WAAW,oBAAI,IAAI;AAAA,IACvB,GAAG,qBAAqB,KAAK,CAAC,QAAQ,eAAe,MAAM,IAAI,CAAC;AAAA,IAChE,GAAG,qBAAqB,KAAK,CAAC,YAAY,YAAY,sBAAsB,MAAM,IAAI,CAAC;AAAA,EACzF,CAAC;AACD,QAAM,WAAW,CAAC,GAAG,QAAQ,EAC1B,OAAO,UAAQ,6BAA6B,IAAI,CAAC,EACjD,SAAS,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AACxC,MAAI,SAAS,WAAW,EAAG;AAE3B,QAAM,QAAQ,SAAS,MAAM,GAAG,EAAE;AAClC,QAAM,YAAY,SAAS,SAAS,MAAM;AAC1C,QAAM,mBAAmB,YAAY,IAAI,MAAM,SAAS,WAAW;AACnE,WAAS;AAAA,IACP,gFAAgF,MAAM,KAAK,IAAI,CAAC,GAAG,gBAAgB;AAAA,EACrH;AACF;AAEA,SAAS,aAAa,QAAyB;AAC7C,SAAO,kBAAkB,QAAQ,OAAO,QAAQ,WAAW,QAAQ,GAAG,EAAE,KAAK,IAAI,OAAO,MAAM;AAChG;AAOA,SAAS,kBAAkB,KAA4B;AACrD,2BAAyB,GAAG;AAC5B,MAAI,CAAC,yCAAyC,GAAG,GAAG;AAClD,YAAQ,gFAAgF;AACxF,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAEA,QAAM,QAAQ,oBAAoB,GAAG,EAAE,OAAO,YAAU,oBAAoB,MAAM,CAAC;AACnF,MAAI,MAAM,SAAS,GAAG;AACpB;AAAA,MACE,gCAAgC,MAAM,KAAK,IAAI,CAAC;AAAA,IAClD;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,gCAAgC;AACxC,SAAO,QAAQ,QAAQ;AACzB;","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-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
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-
|
|
25
|
+
//# sourceMappingURL=architecture-document-CTLCH76G.js.map
|
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
discoverWorkspaces,
|
|
4
4
|
extractMonorepoArchitectureSnapshot,
|
|
5
5
|
monorepoFingerprintOf
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
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-
|
|
15
|
+
//# sourceMappingURL=architecture-monorepo-XWJN3X5I.js.map
|
|
@@ -4,27 +4,28 @@ import {
|
|
|
4
4
|
frontmatterOf,
|
|
5
5
|
parseImplPlan,
|
|
6
6
|
scalar
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SPK32BMX.js";
|
|
8
8
|
import {
|
|
9
9
|
classifyAnnotation,
|
|
10
10
|
isValidSha,
|
|
11
11
|
isValidSkipReason,
|
|
12
12
|
parseCheckboxAnnotation
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-Z4ESH6KU.js";
|
|
14
14
|
import {
|
|
15
15
|
createPhaseAnchorScope
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-K64BTVJ7.js";
|
|
17
|
+
import "./chunk-URVJZ4NL.js";
|
|
18
18
|
import {
|
|
19
19
|
warn
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QSLVO4XF.js";
|
|
21
21
|
import {
|
|
22
22
|
readConfiguredPathFromContent,
|
|
23
23
|
ticketDirectoriesForConfiguredRoot
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-2MI7M2CO.js";
|
|
25
25
|
import {
|
|
26
26
|
readFileSafe
|
|
27
|
-
} from "./chunk-
|
|
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-
|
|
630
|
+
//# sourceMappingURL=boundary-I2Z6PZDO.js.map
|