safeword 0.78.2 → 0.78.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  2. package/codex-plugin/hooks.json +5 -5
  3. package/codex-plugin/skills/bdd/references/SCENARIOS.md +3 -0
  4. package/codex-plugin/skills/bdd/references/TDD.md +11 -5
  5. package/codex-plugin/skills/closeout/SKILL.md +24 -16
  6. package/codex-plugin/skills/finish-review/SKILL.md +4 -3
  7. package/codex-plugin/skills/lint/SKILL.md +1 -1
  8. package/codex-plugin/skills/review-spec/SKILL.md +5 -1
  9. package/codex-plugin/skills/self-review/SKILL.md +2 -2
  10. package/codex-plugin/skills/ticket-system/SKILL.md +3 -0
  11. package/dist/{architecture-N5ZC4CDU.js → architecture-TCSDEFKH.js} +9 -9
  12. package/dist/{architecture-document-UBA5UT4J.js → architecture-document-L2ADWVMV.js} +6 -6
  13. package/dist/{architecture-monorepo-E4JUYJGV.js → architecture-monorepo-NKOQZBEY.js} +4 -4
  14. package/dist/{boundary-HLJILY7R.js → boundary-QP2H7C46.js} +6 -6
  15. package/dist/{chunk-NOTBZCKG.js → chunk-2XR7J5WL.js} +93 -42
  16. package/dist/chunk-2XR7J5WL.js.map +1 -0
  17. package/dist/{chunk-4CZS4YJV.js → chunk-3OKZ3X4O.js} +3 -3
  18. package/dist/{chunk-GZ36UZJG.js → chunk-73TABQRT.js} +10 -10
  19. package/dist/{chunk-4CKCRZDO.js → chunk-7ULZND56.js} +2 -2
  20. package/dist/{chunk-34NCOTP5.js → chunk-7XELS325.js} +2 -2
  21. package/dist/{chunk-USPVNZ63.js → chunk-BZWO3BVD.js} +11 -7
  22. package/dist/chunk-BZWO3BVD.js.map +1 -0
  23. package/dist/{chunk-BQTC6YGN.js → chunk-D5ENZR6N.js} +2 -2
  24. package/dist/{chunk-SME5SU3O.js → chunk-DBXX5K74.js} +258 -48
  25. package/dist/chunk-DBXX5K74.js.map +1 -0
  26. package/dist/{chunk-V63TSN3C.js → chunk-FOYGZ4MK.js} +31 -10
  27. package/dist/chunk-FOYGZ4MK.js.map +1 -0
  28. package/dist/{chunk-ZRV7TOCX.js → chunk-G5AFQXXW.js} +2 -2
  29. package/dist/{chunk-AXAGJLMP.js → chunk-G757F3EU.js} +4 -4
  30. package/dist/{chunk-KXHVFCDT.js → chunk-GFDINP7M.js} +153 -27
  31. package/dist/chunk-GFDINP7M.js.map +1 -0
  32. package/dist/{chunk-S2T356DA.js → chunk-HF3DXZEA.js} +7 -10
  33. package/dist/chunk-HF3DXZEA.js.map +1 -0
  34. package/dist/{chunk-NSZGI7HK.js → chunk-HNCUIXDY.js} +9 -9
  35. package/dist/{chunk-NSZGI7HK.js.map → chunk-HNCUIXDY.js.map} +1 -1
  36. package/dist/{chunk-BSOUMHMQ.js → chunk-IPTM5VE7.js} +101 -1094
  37. package/dist/chunk-IPTM5VE7.js.map +1 -0
  38. package/dist/chunk-JBOLNV2L.js +21 -0
  39. package/dist/chunk-JBOLNV2L.js.map +1 -0
  40. package/dist/chunk-JSR3HXFT.js +1231 -0
  41. package/dist/chunk-JSR3HXFT.js.map +1 -0
  42. package/dist/{chunk-BAVDDAN3.js → chunk-KS2ESRQL.js} +9 -9
  43. package/dist/chunk-LFC6CMMX.js +136 -0
  44. package/dist/chunk-LFC6CMMX.js.map +1 -0
  45. package/dist/{chunk-QTG2EXFT.js → chunk-LUNHU6Z3.js} +2 -2
  46. package/dist/{chunk-QTG2EXFT.js.map → chunk-LUNHU6Z3.js.map} +1 -1
  47. package/dist/{chunk-WVDRXD67.js → chunk-MLBZFB5A.js} +1 -1
  48. package/dist/chunk-MLBZFB5A.js.map +1 -0
  49. package/dist/{chunk-KFVEPQ7X.js → chunk-MVFHTUQ3.js} +2 -2
  50. package/dist/{chunk-TJ627SKI.js → chunk-O3GZ77F7.js} +15 -1
  51. package/dist/chunk-O3GZ77F7.js.map +1 -0
  52. package/dist/{chunk-Q5KLE6ZF.js → chunk-OKPRQGFG.js} +2 -2
  53. package/dist/{chunk-QUDIOBHP.js → chunk-PD7ZXRHV.js} +139 -18
  54. package/dist/chunk-PD7ZXRHV.js.map +1 -0
  55. package/dist/chunk-QAHJSG53.js +30 -0
  56. package/dist/chunk-QAHJSG53.js.map +1 -0
  57. package/dist/{chunk-3SOJBMM6.js → chunk-R6BSRNU4.js} +6 -6
  58. package/dist/{chunk-3SOJBMM6.js.map → chunk-R6BSRNU4.js.map} +1 -1
  59. package/dist/{chunk-J7UDLLTK.js → chunk-RQ7RZYNB.js} +39 -25
  60. package/dist/chunk-RQ7RZYNB.js.map +1 -0
  61. package/dist/{chunk-664YNAMR.js → chunk-RTFPKJJV.js} +5 -5
  62. package/dist/{chunk-GKR44BCH.js → chunk-RVDXBHUG.js} +2 -2
  63. package/dist/chunk-THLEVFEX.js +22 -0
  64. package/dist/chunk-THLEVFEX.js.map +1 -0
  65. package/dist/{chunk-A7Z27COA.js → chunk-VFWAZLEF.js} +3 -3
  66. package/dist/{chunk-I4KBHRZW.js → chunk-VJUPD7JI.js} +7 -7
  67. package/dist/{chunk-3EJNDIAO.js → chunk-VZ5B2SIO.js} +2 -2
  68. package/dist/chunk-WAMQTZAH.js +19 -0
  69. package/dist/chunk-WAMQTZAH.js.map +1 -0
  70. package/dist/{chunk-FDHJ63FZ.js → chunk-WVA4Q6BX.js} +1 -1
  71. package/dist/{chunk-FDHJ63FZ.js.map → chunk-WVA4Q6BX.js.map} +1 -1
  72. package/dist/{chunk-AV5LTEME.js → chunk-YZ5JGDOV.js} +30 -134
  73. package/dist/chunk-YZ5JGDOV.js.map +1 -0
  74. package/dist/{cleanup-X556LNWM.js → cleanup-JNLZ7AXA.js} +9 -9
  75. package/dist/{cleanup-command-RV2Q7G72.js → cleanup-command-MFAYNYRW.js} +15 -15
  76. package/dist/cli.js +152 -109
  77. package/dist/cli.js.map +1 -1
  78. package/dist/{clients-HP23HRN2.js → clients-7AJBKEWF.js} +2 -2
  79. package/dist/codex-bootstrap-KFNUS63Y.js +252 -0
  80. package/dist/codex-bootstrap-KFNUS63Y.js.map +1 -0
  81. package/dist/{codex-hook-IPX3PDXX.js → codex-hook-TNMYVOR7.js} +57 -49
  82. package/dist/codex-hook-TNMYVOR7.js.map +1 -0
  83. package/dist/{codify-J5ZLJ3HK.js → codify-RBWBRXQO.js} +11 -8
  84. package/dist/codify-RBWBRXQO.js.map +1 -0
  85. package/dist/{commands-L4AINARC.js → commands-4UXHBZFD.js} +127 -71
  86. package/dist/commands-4UXHBZFD.js.map +1 -0
  87. package/dist/{config-LUSJAK6B.js → config-GS7BTZJD.js} +2 -2
  88. package/dist/{configured-paths-SPQ5XWOM.js → configured-paths-CREUDQF3.js} +4 -4
  89. package/dist/contract-42CIWIWV.js +8 -0
  90. package/dist/{coordinator-SA75UB3C.js → coordinator-WOPGWDXK.js} +231 -144
  91. package/dist/coordinator-WOPGWDXK.js.map +1 -0
  92. package/dist/corpus-CAFYEMBO.js +15 -0
  93. package/dist/{doctor-DSC36R4U.js → doctor-AZP5D7QP.js} +21 -21
  94. package/dist/{feature-directories-VOHVV26X.js → feature-directories-6TLM7Y4H.js} +6 -6
  95. package/dist/{finalization-7SMLMVLV.js → finalization-AQT3SOP7.js} +4 -4
  96. package/dist/{gh-cli-ZMO7D2KE.js → gh-cli-XCQT5ST7.js} +2 -2
  97. package/dist/{github-rest-KGKS4V2H.js → github-rest-CXFJ2NFF.js} +2 -2
  98. package/dist/index.js +2 -2
  99. package/dist/{job-CDADLJDF.js → job-4POTQJZK.js} +20 -21
  100. package/dist/job-4POTQJZK.js.map +1 -0
  101. package/dist/{learning-sync-6BTHM6ZC.js → learning-sync-QVXBOP6J.js} +4 -4
  102. package/dist/{legacy-global-guidance-2JL4Y5EB.js → legacy-global-guidance-CPGUUNJI.js} +5 -5
  103. package/dist/{lint-gherkin-COSHVS6Z.js → lint-gherkin-LZ45NG4A.js} +7 -7
  104. package/dist/{operations-XVRQSLJG.js → operations-ODOA5CDG.js} +18 -16
  105. package/dist/{output-3LB2OEHN.js → output-QTZCFLAY.js} +2 -2
  106. package/dist/{packet-5WT5M3OS.js → packet-5G6RT2EW.js} +2 -2
  107. package/dist/presets/typescript/index.js +2 -2
  108. package/dist/{profile-UMKQ5JVO.js → profile-QGLZNLRU.js} +7 -7
  109. package/dist/{prompt-GWYDFMLO.js → prompt-UCTSCXSS.js} +2 -2
  110. package/dist/remove-UQPEXXNP.js +23 -0
  111. package/dist/{retro-IFSVU5KS.js → retro-ELKR6GHF.js} +8 -8
  112. package/dist/{retro-draft-spool-4S3TCHWL.js → retro-draft-spool-M75BTT32.js} +2 -2
  113. package/dist/{retro-extract-OSBFAXLU.js → retro-extract-RA6THOC4.js} +2 -2
  114. package/dist/{review-pr-6S2352CK.js → review-pr-MN6QESAJ.js} +2 -2
  115. package/dist/{review-pr-publication-CGHCRRUI.js → review-pr-publication-6AVOGWR2.js} +2 -2
  116. package/dist/{run-5JESKXUR.js → run-JFDGRAH2.js} +4 -4
  117. package/dist/{self-report-VPHBPPSJ.js → self-report-5APRPB5P.js} +2 -2
  118. package/dist/status-ATFG6Q3K.js +21 -0
  119. package/dist/{status-EX4L3ELO.js → status-HIQSP3F5.js} +21 -21
  120. package/dist/{sync-config-O7J7IDGE.js → sync-config-XPAJKBRO.js} +5 -5
  121. package/dist/{sync-tracker-U2GYOFUO.js → sync-tracker-3E5BWX73.js} +6 -6
  122. package/dist/{test-execution-6LIPMBIH.js → test-execution-VDECX7TO.js} +8 -7
  123. package/dist/{test-execution-6LIPMBIH.js.map → test-execution-VDECX7TO.js.map} +1 -1
  124. package/dist/{test-plan-VASHZXJ7.js → test-plan-2L7A7UZV.js} +7 -6
  125. package/dist/{test-plan-VASHZXJ7.js.map → test-plan-2L7A7UZV.js.map} +1 -1
  126. package/dist/{ticket-new-3YXDIWPC.js → ticket-new-HZKNZ5GO.js} +11 -11
  127. package/dist/ticket-new-HZKNZ5GO.js.map +1 -0
  128. package/dist/{ticket-sync-LLUBXZ2R.js → ticket-sync-4QJD3KOL.js} +5 -5
  129. package/dist/{tracker-map-HR4MBYG5.js → tracker-map-CFMFIEER.js} +2 -2
  130. package/dist/{tracker-sync-YDICZN66.js → tracker-sync-MOPJE6M7.js} +2 -2
  131. package/package.json +1 -1
  132. package/templates/SAFEWORD.md +2 -2
  133. package/templates/commands/lint.md +1 -1
  134. package/templates/scripts/closeout-cleanup.ts +127 -31
  135. package/templates/skills/bdd/SCENARIOS.md +3 -0
  136. package/templates/skills/bdd/TDD.md +11 -5
  137. package/templates/skills/closeout/SKILL.md +25 -17
  138. package/templates/skills/finish-review/SKILL.md +4 -3
  139. package/templates/skills/lint/SKILL.md +1 -1
  140. package/templates/skills/review-spec/SKILL.md +5 -1
  141. package/templates/skills/self-review/SKILL.md +2 -2
  142. package/templates/skills/ticket-system/SKILL.md +3 -0
  143. package/dist/chunk-6S7CTKGC.js +0 -128
  144. package/dist/chunk-6S7CTKGC.js.map +0 -1
  145. package/dist/chunk-AV5LTEME.js.map +0 -1
  146. package/dist/chunk-BSOUMHMQ.js.map +0 -1
  147. package/dist/chunk-J7UDLLTK.js.map +0 -1
  148. package/dist/chunk-KXHVFCDT.js.map +0 -1
  149. package/dist/chunk-NOTBZCKG.js.map +0 -1
  150. package/dist/chunk-QUDIOBHP.js.map +0 -1
  151. package/dist/chunk-S2T356DA.js.map +0 -1
  152. package/dist/chunk-SME5SU3O.js.map +0 -1
  153. package/dist/chunk-TJ627SKI.js.map +0 -1
  154. package/dist/chunk-USPVNZ63.js.map +0 -1
  155. package/dist/chunk-V63TSN3C.js.map +0 -1
  156. package/dist/chunk-WRUXO3WA.js +0 -48
  157. package/dist/chunk-WRUXO3WA.js.map +0 -1
  158. package/dist/chunk-WVDRXD67.js.map +0 -1
  159. package/dist/codex-bootstrap-MGY2D6HU.js +0 -178
  160. package/dist/codex-bootstrap-MGY2D6HU.js.map +0 -1
  161. package/dist/codex-hook-IPX3PDXX.js.map +0 -1
  162. package/dist/codify-J5ZLJ3HK.js.map +0 -1
  163. package/dist/commands-L4AINARC.js.map +0 -1
  164. package/dist/contract-KEZY6YC3.js +0 -8
  165. package/dist/coordinator-SA75UB3C.js.map +0 -1
  166. package/dist/corpus-PPOBTF4J.js +0 -15
  167. package/dist/job-CDADLJDF.js.map +0 -1
  168. package/dist/remove-E6HGNHOU.js +0 -22
  169. package/dist/status-7VIGNTUI.js +0 -21
  170. package/dist/ticket-new-3YXDIWPC.js.map +0 -1
  171. /package/dist/{architecture-N5ZC4CDU.js.map → architecture-TCSDEFKH.js.map} +0 -0
  172. /package/dist/{architecture-document-UBA5UT4J.js.map → architecture-document-L2ADWVMV.js.map} +0 -0
  173. /package/dist/{architecture-monorepo-E4JUYJGV.js.map → architecture-monorepo-NKOQZBEY.js.map} +0 -0
  174. /package/dist/{boundary-HLJILY7R.js.map → boundary-QP2H7C46.js.map} +0 -0
  175. /package/dist/{chunk-4CZS4YJV.js.map → chunk-3OKZ3X4O.js.map} +0 -0
  176. /package/dist/{chunk-GZ36UZJG.js.map → chunk-73TABQRT.js.map} +0 -0
  177. /package/dist/{chunk-4CKCRZDO.js.map → chunk-7ULZND56.js.map} +0 -0
  178. /package/dist/{chunk-34NCOTP5.js.map → chunk-7XELS325.js.map} +0 -0
  179. /package/dist/{chunk-BQTC6YGN.js.map → chunk-D5ENZR6N.js.map} +0 -0
  180. /package/dist/{chunk-ZRV7TOCX.js.map → chunk-G5AFQXXW.js.map} +0 -0
  181. /package/dist/{chunk-AXAGJLMP.js.map → chunk-G757F3EU.js.map} +0 -0
  182. /package/dist/{chunk-BAVDDAN3.js.map → chunk-KS2ESRQL.js.map} +0 -0
  183. /package/dist/{chunk-KFVEPQ7X.js.map → chunk-MVFHTUQ3.js.map} +0 -0
  184. /package/dist/{chunk-Q5KLE6ZF.js.map → chunk-OKPRQGFG.js.map} +0 -0
  185. /package/dist/{chunk-664YNAMR.js.map → chunk-RTFPKJJV.js.map} +0 -0
  186. /package/dist/{chunk-GKR44BCH.js.map → chunk-RVDXBHUG.js.map} +0 -0
  187. /package/dist/{chunk-A7Z27COA.js.map → chunk-VFWAZLEF.js.map} +0 -0
  188. /package/dist/{chunk-I4KBHRZW.js.map → chunk-VJUPD7JI.js.map} +0 -0
  189. /package/dist/{chunk-3EJNDIAO.js.map → chunk-VZ5B2SIO.js.map} +0 -0
  190. /package/dist/{cleanup-X556LNWM.js.map → cleanup-JNLZ7AXA.js.map} +0 -0
  191. /package/dist/{cleanup-command-RV2Q7G72.js.map → cleanup-command-MFAYNYRW.js.map} +0 -0
  192. /package/dist/{clients-HP23HRN2.js.map → clients-7AJBKEWF.js.map} +0 -0
  193. /package/dist/{config-LUSJAK6B.js.map → config-GS7BTZJD.js.map} +0 -0
  194. /package/dist/{configured-paths-SPQ5XWOM.js.map → configured-paths-CREUDQF3.js.map} +0 -0
  195. /package/dist/{contract-KEZY6YC3.js.map → contract-42CIWIWV.js.map} +0 -0
  196. /package/dist/{corpus-PPOBTF4J.js.map → corpus-CAFYEMBO.js.map} +0 -0
  197. /package/dist/{doctor-DSC36R4U.js.map → doctor-AZP5D7QP.js.map} +0 -0
  198. /package/dist/{feature-directories-VOHVV26X.js.map → feature-directories-6TLM7Y4H.js.map} +0 -0
  199. /package/dist/{finalization-7SMLMVLV.js.map → finalization-AQT3SOP7.js.map} +0 -0
  200. /package/dist/{gh-cli-ZMO7D2KE.js.map → gh-cli-XCQT5ST7.js.map} +0 -0
  201. /package/dist/{github-rest-KGKS4V2H.js.map → github-rest-CXFJ2NFF.js.map} +0 -0
  202. /package/dist/{learning-sync-6BTHM6ZC.js.map → learning-sync-QVXBOP6J.js.map} +0 -0
  203. /package/dist/{legacy-global-guidance-2JL4Y5EB.js.map → legacy-global-guidance-CPGUUNJI.js.map} +0 -0
  204. /package/dist/{lint-gherkin-COSHVS6Z.js.map → lint-gherkin-LZ45NG4A.js.map} +0 -0
  205. /package/dist/{operations-XVRQSLJG.js.map → operations-ODOA5CDG.js.map} +0 -0
  206. /package/dist/{output-3LB2OEHN.js.map → output-QTZCFLAY.js.map} +0 -0
  207. /package/dist/{packet-5WT5M3OS.js.map → packet-5G6RT2EW.js.map} +0 -0
  208. /package/dist/{profile-UMKQ5JVO.js.map → profile-QGLZNLRU.js.map} +0 -0
  209. /package/dist/{prompt-GWYDFMLO.js.map → prompt-UCTSCXSS.js.map} +0 -0
  210. /package/dist/{remove-E6HGNHOU.js.map → remove-UQPEXXNP.js.map} +0 -0
  211. /package/dist/{retro-IFSVU5KS.js.map → retro-ELKR6GHF.js.map} +0 -0
  212. /package/dist/{retro-draft-spool-4S3TCHWL.js.map → retro-draft-spool-M75BTT32.js.map} +0 -0
  213. /package/dist/{retro-extract-OSBFAXLU.js.map → retro-extract-RA6THOC4.js.map} +0 -0
  214. /package/dist/{review-pr-6S2352CK.js.map → review-pr-MN6QESAJ.js.map} +0 -0
  215. /package/dist/{review-pr-publication-CGHCRRUI.js.map → review-pr-publication-6AVOGWR2.js.map} +0 -0
  216. /package/dist/{run-5JESKXUR.js.map → run-JFDGRAH2.js.map} +0 -0
  217. /package/dist/{self-report-VPHBPPSJ.js.map → self-report-5APRPB5P.js.map} +0 -0
  218. /package/dist/{status-7VIGNTUI.js.map → status-ATFG6Q3K.js.map} +0 -0
  219. /package/dist/{status-EX4L3ELO.js.map → status-HIQSP3F5.js.map} +0 -0
  220. /package/dist/{sync-config-O7J7IDGE.js.map → sync-config-XPAJKBRO.js.map} +0 -0
  221. /package/dist/{sync-tracker-U2GYOFUO.js.map → sync-tracker-3E5BWX73.js.map} +0 -0
  222. /package/dist/{ticket-sync-LLUBXZ2R.js.map → ticket-sync-4QJD3KOL.js.map} +0 -0
  223. /package/dist/{tracker-map-HR4MBYG5.js.map → tracker-map-CFMFIEER.js.map} +0 -0
  224. /package/dist/{tracker-sync-YDICZN66.js.map → tracker-sync-MOPJE6M7.js.map} +0 -0
@@ -1,6 +1,9 @@
1
1
  import {
2
- MCP_SERVERS
3
- } from "./chunk-6S7CTKGC.js";
2
+ MCP_SERVERS,
3
+ detectPythonLayers,
4
+ detectRootPackage,
5
+ detectSolePackage
6
+ } from "./chunk-JSR3HXFT.js";
4
7
  import {
5
8
  CODEX_MIGRATION_SCHEMA
6
9
  } from "./chunk-AVAUUIDB.js";
@@ -14,7 +17,7 @@ import {
14
17
  acceptedHistoricalHookEntries,
15
18
  filterOutEquivalentSafewordHooks,
16
19
  filterOutSafewordHooks
17
- } from "./chunk-NSZGI7HK.js";
20
+ } from "./chunk-HNCUIXDY.js";
18
21
  import {
19
22
  VERSION
20
23
  } from "./chunk-UAFM77KW.js";
@@ -23,696 +26,14 @@ import {
23
26
  } from "./chunk-QSLVO4XF.js";
24
27
  import {
25
28
  resolveNamespaceRoot
26
- } from "./chunk-GKR44BCH.js";
29
+ } from "./chunk-RVDXBHUG.js";
27
30
  import {
28
31
  exists,
29
32
  findInTree,
30
33
  getTemplatesDirectory,
31
34
  readFile,
32
35
  readFileSafe
33
- } from "./chunk-S2T356DA.js";
34
-
35
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/date.js
36
- var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
37
- var TomlDate = class _TomlDate extends Date {
38
- #hasDate = false;
39
- #hasTime = false;
40
- #offset = null;
41
- constructor(date) {
42
- let hasDate = true;
43
- let hasTime = true;
44
- let offset = "Z";
45
- if (typeof date === "string") {
46
- let match = date.match(DATE_TIME_RE);
47
- if (match) {
48
- if (!match[1]) {
49
- hasDate = false;
50
- date = `0000-01-01T${date}`;
51
- }
52
- hasTime = !!match[2];
53
- hasTime && date[10] === " " && (date = date.replace(" ", "T"));
54
- if (match[2] && +match[2] > 23) {
55
- date = "";
56
- } else {
57
- offset = match[3] || null;
58
- date = date.toUpperCase();
59
- if (!offset && hasTime)
60
- date += "Z";
61
- }
62
- } else {
63
- date = "";
64
- }
65
- }
66
- super(date);
67
- if (!isNaN(this.getTime())) {
68
- this.#hasDate = hasDate;
69
- this.#hasTime = hasTime;
70
- this.#offset = offset;
71
- }
72
- }
73
- isDateTime() {
74
- return this.#hasDate && this.#hasTime;
75
- }
76
- isLocal() {
77
- return !this.#hasDate || !this.#hasTime || !this.#offset;
78
- }
79
- isDate() {
80
- return this.#hasDate && !this.#hasTime;
81
- }
82
- isTime() {
83
- return this.#hasTime && !this.#hasDate;
84
- }
85
- isValid() {
86
- return this.#hasDate || this.#hasTime;
87
- }
88
- toISOString() {
89
- let iso = super.toISOString();
90
- if (this.isDate())
91
- return iso.slice(0, 10);
92
- if (this.isTime())
93
- return iso.slice(11, 23);
94
- if (this.#offset === null)
95
- return iso.slice(0, -1);
96
- if (this.#offset === "Z")
97
- return iso;
98
- let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
99
- offset = this.#offset[0] === "-" ? offset : -offset;
100
- let offsetDate = new Date(this.getTime() - offset * 6e4);
101
- return offsetDate.toISOString().slice(0, -1) + this.#offset;
102
- }
103
- static wrapAsOffsetDateTime(jsDate, offset = "Z") {
104
- let date = new _TomlDate(jsDate);
105
- date.#offset = offset;
106
- return date;
107
- }
108
- static wrapAsLocalDateTime(jsDate) {
109
- let date = new _TomlDate(jsDate);
110
- date.#offset = null;
111
- return date;
112
- }
113
- static wrapAsLocalDate(jsDate) {
114
- let date = new _TomlDate(jsDate);
115
- date.#hasTime = false;
116
- date.#offset = null;
117
- return date;
118
- }
119
- static wrapAsLocalTime(jsDate) {
120
- let date = new _TomlDate(jsDate);
121
- date.#hasDate = false;
122
- date.#offset = null;
123
- return date;
124
- }
125
- };
126
-
127
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/error.js
128
- function getLineColFromPtr(string, ptr) {
129
- let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
130
- return [lines.length, lines.pop().length + 1];
131
- }
132
- function makeCodeBlock(string, line, column) {
133
- let lines = string.split(/\r\n|\n|\r/g);
134
- let codeblock = "";
135
- let numberLen = (Math.log10(line + 1) | 0) + 1;
136
- for (let i = line - 1; i <= line + 1; i++) {
137
- let l = lines[i - 1];
138
- if (!l)
139
- continue;
140
- codeblock += i.toString().padEnd(numberLen, " ");
141
- codeblock += ": ";
142
- codeblock += l;
143
- codeblock += "\n";
144
- if (i === line) {
145
- codeblock += " ".repeat(numberLen + column + 2);
146
- codeblock += "^\n";
147
- }
148
- }
149
- return codeblock;
150
- }
151
- var TomlError = class extends Error {
152
- line;
153
- column;
154
- codeblock;
155
- constructor(message, options) {
156
- const [line, column] = getLineColFromPtr(options.toml, options.ptr);
157
- const codeblock = makeCodeBlock(options.toml, line, column);
158
- super(`Invalid TOML document: ${message}
159
-
160
- ${codeblock}`, options);
161
- this.line = line;
162
- this.column = column;
163
- this.codeblock = codeblock;
164
- }
165
- };
166
-
167
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/primitive.js
168
- var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
169
- var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
170
- var LEADING_ZERO = /^[+-]?0[0-9_]/;
171
- function parseString(str, ptr) {
172
- let c = str[ptr++];
173
- let first = c;
174
- let isLiteral = c === "'";
175
- let isMultiline = c === str[ptr] && c === str[ptr + 1];
176
- if (isMultiline) {
177
- if (str[ptr += 2] === "\n")
178
- ptr++;
179
- else if (str[ptr] === "\r" && str[ptr + 1] === "\n")
180
- ptr += 2;
181
- }
182
- let parsed = "";
183
- let sliceStart = ptr;
184
- let state = 0;
185
- for (let i = ptr; i < str.length; i++) {
186
- c = str[i];
187
- if (isMultiline && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
188
- state = state && 3;
189
- } else if (c < " " && c !== " " || c === "\x7F") {
190
- throw new TomlError("control characters are not allowed in strings", {
191
- toml: str,
192
- ptr: i
193
- });
194
- } else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) {
195
- if (isMultiline) {
196
- if (str[i + 3] === first)
197
- i++;
198
- if (str[i + 3] === first)
199
- i++;
200
- }
201
- return [
202
- // If we're in a newline escape still, then there's nothing to add.
203
- // Also try to avoid concat if there's nothing to add to parsed, or nothing has been added to parsed.
204
- state ? parsed : parsed + str.slice(sliceStart, i),
205
- i + (isMultiline ? 3 : 1)
206
- ];
207
- } else if (!state) {
208
- if (!isLiteral && c === "\\") {
209
- parsed += str.slice(sliceStart, sliceStart = i);
210
- state = 1;
211
- }
212
- } else if (state === 1) {
213
- if (c === "x" || c === "u" || c === "U") {
214
- let value = 0;
215
- let len = c === "x" ? 2 : c === "u" ? 4 : 8;
216
- for (let j = 0; j < len; j++, i++) {
217
- let hex = str.charCodeAt(i + 1);
218
- let digit = (
219
- /* 0-9 */
220
- hex >= 48 && hex <= 57 ? hex - 48 : (
221
- /* A-F */
222
- hex >= 65 && hex <= 70 ? hex - 65 + 10 : (
223
- /* a-f */
224
- hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1
225
- )
226
- )
227
- );
228
- if (digit < 0)
229
- throw new TomlError("invalid non-hex character in unicode escape", { toml: str, ptr: i + 1 });
230
- value = value << 4 | digit;
231
- }
232
- if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
233
- throw new TomlError("invalid unicode escape", { toml: str, ptr: i });
234
- }
235
- parsed += String.fromCodePoint(value);
236
- sliceStart = i + 1;
237
- state = 0;
238
- } else if (c === " " || c === " ") {
239
- state = 2;
240
- } else {
241
- if (c === "b")
242
- parsed += "\b";
243
- else if (c === "t")
244
- parsed += " ";
245
- else if (c === "n")
246
- parsed += "\n";
247
- else if (c === "f")
248
- parsed += "\f";
249
- else if (c === "r")
250
- parsed += "\r";
251
- else if (c === "e")
252
- parsed += "\x1B";
253
- else if (c === '"')
254
- parsed += '"';
255
- else if (c === "\\")
256
- parsed += "\\";
257
- else
258
- throw new TomlError("unrecognized escape sequence", { toml: str, ptr: i });
259
- sliceStart = i + 1;
260
- state = 0;
261
- }
262
- } else if (c !== " " && c !== " ") {
263
- if (state === 2) {
264
- throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
265
- toml: str,
266
- ptr: sliceStart
267
- });
268
- }
269
- state = !isLiteral && c === "\\" ? 1 : 0;
270
- sliceStart = i;
271
- }
272
- }
273
- throw new TomlError("unfinished string", { toml: str, ptr });
274
- }
275
- function parseValue(value, toml, ptr, integersAsBigInt) {
276
- if (value === "true")
277
- return true;
278
- if (value === "false")
279
- return false;
280
- if (value === "-inf")
281
- return -Infinity;
282
- if (value === "inf" || value === "+inf")
283
- return Infinity;
284
- if (value === "nan" || value === "+nan" || value === "-nan")
285
- return NaN;
286
- if (value === "-0")
287
- return integersAsBigInt ? 0n : 0;
288
- let isInt = INT_REGEX.test(value);
289
- if (isInt || FLOAT_REGEX.test(value)) {
290
- if (LEADING_ZERO.test(value)) {
291
- throw new TomlError("leading zeroes are not allowed", {
292
- toml,
293
- ptr
294
- });
295
- }
296
- value = value.replace(/_/g, "");
297
- let numeric = +value;
298
- if (isNaN(numeric)) {
299
- throw new TomlError("invalid number", {
300
- toml,
301
- ptr
302
- });
303
- }
304
- if (isInt) {
305
- if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
306
- throw new TomlError("integer value cannot be represented losslessly", {
307
- toml,
308
- ptr
309
- });
310
- }
311
- if (isInt || integersAsBigInt === true)
312
- numeric = BigInt(value);
313
- }
314
- return numeric;
315
- }
316
- const date = new TomlDate(value);
317
- if (!date.isValid()) {
318
- throw new TomlError("invalid value", {
319
- toml,
320
- ptr
321
- });
322
- }
323
- return date;
324
- }
325
-
326
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/util.js
327
- function indexOfNewline(str, start = 0, end = str.length) {
328
- let idx = str.indexOf("\n", start);
329
- if (str[idx - 1] === "\r")
330
- idx--;
331
- return idx <= end ? idx : -1;
332
- }
333
- function skipComment(str, ptr) {
334
- for (let i = ptr; i < str.length; i++) {
335
- let c = str[i];
336
- if (c === "\n")
337
- return i;
338
- if (c === "\r" && str[i + 1] === "\n")
339
- return i + 1;
340
- if (c < " " && c !== " " || c === "\x7F") {
341
- throw new TomlError("control characters are not allowed in comments", {
342
- toml: str,
343
- ptr
344
- });
345
- }
346
- }
347
- return str.length;
348
- }
349
- function skipVoid(str, ptr, banNewLines, banComments) {
350
- let c;
351
- while (1) {
352
- while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
353
- ptr++;
354
- if (banComments || c !== "#")
355
- break;
356
- ptr = skipComment(str, ptr);
357
- }
358
- return ptr;
359
- }
360
- function skipUntil(str, ptr, sep, end, banNewLines = false) {
361
- if (!end) {
362
- ptr = indexOfNewline(str, ptr);
363
- return ptr < 0 ? str.length : ptr;
364
- }
365
- for (let i = ptr; i < str.length; i++) {
366
- let c = str[i];
367
- if (c === "#") {
368
- i = indexOfNewline(str, i);
369
- if (i < 0)
370
- break;
371
- } else if (c === sep) {
372
- return i + 1;
373
- } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
374
- return i;
375
- }
376
- }
377
- throw new TomlError("cannot find end of structure", {
378
- toml: str,
379
- ptr
380
- });
381
- }
382
-
383
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/extract.js
384
- function sliceAndTrimEndOf(str, startPtr, endPtr) {
385
- let value = str.slice(startPtr, endPtr);
386
- let commentIdx = value.indexOf("#");
387
- if (commentIdx > -1) {
388
- skipComment(str, commentIdx);
389
- value = value.slice(0, commentIdx);
390
- }
391
- return [value.trimEnd(), commentIdx];
392
- }
393
- function extractValue(str, ptr, end, depth, integersAsBigInt) {
394
- if (depth === 0) {
395
- throw new TomlError("document contains excessively nested structures. aborting.", {
396
- toml: str,
397
- ptr
398
- });
399
- }
400
- let c = str[ptr];
401
- if (c === "[" || c === "{") {
402
- let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
403
- if (end) {
404
- endPtr2 = skipVoid(str, endPtr2);
405
- if (str[endPtr2] === ",")
406
- endPtr2++;
407
- else if (str[endPtr2] !== end) {
408
- throw new TomlError("expected comma or end of structure", {
409
- toml: str,
410
- ptr: endPtr2
411
- });
412
- }
413
- }
414
- return [value, endPtr2];
415
- }
416
- if (c === '"' || c === "'") {
417
- let [parsed, endPtr2] = parseString(str, ptr);
418
- if (end) {
419
- endPtr2 = skipVoid(str, endPtr2);
420
- if (str[endPtr2] && str[endPtr2] !== "," && str[endPtr2] !== end && str[endPtr2] !== "\n" && str[endPtr2] !== "\r") {
421
- throw new TomlError("unexpected character encountered", {
422
- toml: str,
423
- ptr: endPtr2
424
- });
425
- }
426
- if (str[endPtr2] === ",")
427
- endPtr2++;
428
- }
429
- return [parsed, endPtr2];
430
- }
431
- let endPtr = skipUntil(str, ptr, ",", end);
432
- let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0));
433
- if (!slice[0]) {
434
- throw new TomlError("incomplete key-value declaration: no value specified", {
435
- toml: str,
436
- ptr
437
- });
438
- }
439
- if (end && slice[1] > -1) {
440
- endPtr = skipVoid(str, ptr + slice[1]);
441
- if (str[endPtr] === ",")
442
- endPtr++;
443
- }
444
- return [
445
- parseValue(slice[0], str, ptr, integersAsBigInt),
446
- endPtr
447
- ];
448
- }
449
-
450
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/struct.js
451
- var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
452
- function parseKey(str, ptr, end = "=") {
453
- let dot = ptr - 1;
454
- let parsed = [];
455
- let endPtr = str.indexOf(end, ptr);
456
- if (endPtr < 0) {
457
- throw new TomlError("incomplete key-value: cannot find end of key", {
458
- toml: str,
459
- ptr
460
- });
461
- }
462
- do {
463
- let c = str[ptr = ++dot];
464
- if (c !== " " && c !== " ") {
465
- if (c === '"' || c === "'") {
466
- if (c === str[ptr + 1] && c === str[ptr + 2]) {
467
- throw new TomlError("multiline strings are not allowed in keys", {
468
- toml: str,
469
- ptr
470
- });
471
- }
472
- let [part, eos] = parseString(str, ptr);
473
- dot = str.indexOf(".", eos);
474
- let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
475
- let newLine = indexOfNewline(strEnd);
476
- if (newLine > -1) {
477
- throw new TomlError("newlines are not allowed in keys", {
478
- toml: str,
479
- ptr: ptr + dot + newLine
480
- });
481
- }
482
- if (strEnd.trimStart()) {
483
- throw new TomlError("found extra tokens after the string part", {
484
- toml: str,
485
- ptr: eos
486
- });
487
- }
488
- if (endPtr < eos) {
489
- endPtr = str.indexOf(end, eos);
490
- if (endPtr < 0) {
491
- throw new TomlError("incomplete key-value: cannot find end of key", {
492
- toml: str,
493
- ptr
494
- });
495
- }
496
- }
497
- parsed.push(part);
498
- } else {
499
- dot = str.indexOf(".", ptr);
500
- let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
501
- if (!KEY_PART_RE.test(part)) {
502
- throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
503
- toml: str,
504
- ptr
505
- });
506
- }
507
- parsed.push(part.trimEnd());
508
- }
509
- }
510
- } while (dot + 1 && dot < endPtr);
511
- return [parsed, skipVoid(str, endPtr + 1, true, true)];
512
- }
513
- function parseInlineTable(str, ptr, depth, integersAsBigInt) {
514
- let res = {};
515
- let seen = /* @__PURE__ */ new Set();
516
- let c;
517
- ptr++;
518
- while ((c = str[ptr++]) !== "}" && c) {
519
- if (c === ",") {
520
- throw new TomlError("expected value, found comma", {
521
- toml: str,
522
- ptr: ptr - 1
523
- });
524
- } else if (c === "#")
525
- ptr = skipComment(str, ptr);
526
- else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
527
- let k;
528
- let t = res;
529
- let hasOwn = false;
530
- let [key, keyEndPtr] = parseKey(str, ptr - 1);
531
- for (let i = 0; i < key.length; i++) {
532
- if (i)
533
- t = hasOwn ? t[k] : t[k] = {};
534
- k = key[i];
535
- if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
536
- throw new TomlError("trying to redefine an already defined value", {
537
- toml: str,
538
- ptr
539
- });
540
- }
541
- if (!hasOwn && k === "__proto__") {
542
- Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
543
- }
544
- }
545
- if (hasOwn) {
546
- throw new TomlError("trying to redefine an already defined value", {
547
- toml: str,
548
- ptr
549
- });
550
- }
551
- let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
552
- seen.add(value);
553
- t[k] = value;
554
- ptr = valueEndPtr;
555
- }
556
- }
557
- if (!c) {
558
- throw new TomlError("unfinished table encountered", {
559
- toml: str,
560
- ptr
561
- });
562
- }
563
- return [res, ptr];
564
- }
565
- function parseArray(str, ptr, depth, integersAsBigInt) {
566
- let res = [];
567
- let c;
568
- ptr++;
569
- while ((c = str[ptr++]) !== "]" && c) {
570
- if (c === ",") {
571
- throw new TomlError("expected value, found comma", {
572
- toml: str,
573
- ptr: ptr - 1
574
- });
575
- } else if (c === "#")
576
- ptr = skipComment(str, ptr);
577
- else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
578
- let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
579
- res.push(e[0]);
580
- ptr = e[1];
581
- }
582
- }
583
- if (!c) {
584
- throw new TomlError("unfinished array encountered", {
585
- toml: str,
586
- ptr
587
- });
588
- }
589
- return [res, ptr];
590
- }
591
-
592
- // ../../node_modules/.bun/smol-toml@1.7.1/node_modules/smol-toml/dist/parse.js
593
- function peekTable(key, table, meta, type) {
594
- let t = table;
595
- let m = meta;
596
- let k;
597
- let hasOwn = false;
598
- let state;
599
- for (let i = 0; i < key.length; i++) {
600
- if (i) {
601
- t = hasOwn ? t[k] : t[k] = {};
602
- m = (state = m[k]).c;
603
- if (type === 0 && (state.t === 1 || state.t === 2)) {
604
- return null;
605
- }
606
- if (state.t === 2) {
607
- let l = t.length - 1;
608
- t = t[l];
609
- m = m[l].c;
610
- }
611
- }
612
- k = key[i];
613
- if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
614
- return null;
615
- }
616
- if (!hasOwn) {
617
- if (k === "__proto__") {
618
- Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
619
- Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
620
- }
621
- m[k] = {
622
- t: i < key.length - 1 && type === 2 ? 3 : type,
623
- d: false,
624
- i: 0,
625
- c: {}
626
- };
627
- }
628
- }
629
- state = m[k];
630
- if (state.t !== type && !(type === 1 && state.t === 3)) {
631
- return null;
632
- }
633
- if (type === 2) {
634
- if (!state.d) {
635
- state.d = true;
636
- t[k] = [];
637
- }
638
- t[k].push(t = {});
639
- state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
640
- }
641
- if (state.d) {
642
- return null;
643
- }
644
- state.d = true;
645
- if (type === 1) {
646
- t = hasOwn ? t[k] : t[k] = {};
647
- } else if (type === 0 && hasOwn) {
648
- return null;
649
- }
650
- return [k, t, state.c];
651
- }
652
- function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
653
- let res = {};
654
- let meta = {};
655
- let tbl = res;
656
- let m = meta;
657
- for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
658
- if (toml[ptr] === "[") {
659
- let isTableArray = toml[++ptr] === "[";
660
- let k = parseKey(toml, ptr += +isTableArray, "]");
661
- if (isTableArray) {
662
- if (toml[k[1] - 1] !== "]") {
663
- throw new TomlError("expected end of table declaration", {
664
- toml,
665
- ptr: k[1] - 1
666
- });
667
- }
668
- k[1]++;
669
- }
670
- let p = peekTable(
671
- k[0],
672
- res,
673
- meta,
674
- isTableArray ? 2 : 1
675
- /* Type.EXPLICIT */
676
- );
677
- if (!p) {
678
- throw new TomlError("trying to redefine an already defined table or value", {
679
- toml,
680
- ptr
681
- });
682
- }
683
- m = p[2];
684
- tbl = p[1];
685
- ptr = k[1];
686
- } else {
687
- let k = parseKey(toml, ptr);
688
- let p = peekTable(
689
- k[0],
690
- tbl,
691
- m,
692
- 0
693
- /* Type.DOTTED */
694
- );
695
- if (!p) {
696
- throw new TomlError("trying to redefine an already defined table or value", {
697
- toml,
698
- ptr
699
- });
700
- }
701
- let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
702
- p[1][p[0]] = v[0];
703
- ptr = v[1];
704
- }
705
- ptr = skipVoid(toml, ptr, true);
706
- if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
707
- throw new TomlError("each key-value declaration must be followed by an end-of-line", {
708
- toml,
709
- ptr
710
- });
711
- }
712
- ptr = skipVoid(toml, ptr);
713
- }
714
- return res;
715
- }
36
+ } from "./chunk-HF3DXZEA.js";
716
37
 
717
38
  // src/owned-paths.ts
718
39
  import nodePath from "path";
@@ -730,18 +51,22 @@ function safewordIgnoreDirectories(namespaceRootLabel) {
730
51
  }
731
52
  function resolvedNamespaceDirectory(ctx) {
732
53
  const label = resolvedNamespaceRootLabel(ctx);
733
- if (label === "." || label.startsWith("..") || SAFEWORD_IGNORE_DIRS.includes(label)) {
54
+ if (label === "." || label === ".." || label.startsWith("../") || SAFEWORD_IGNORE_DIRS.includes(label)) {
734
55
  return void 0;
735
56
  }
736
57
  return label;
737
58
  }
738
59
  function resolvedNamespaceRootLabel(ctx) {
739
60
  const root = ctx.namespaceRoot ?? resolveNamespaceRoot(ctx.cwd);
740
- return nodePath.relative(ctx.cwd, root) || ".";
61
+ return (nodePath.relative(ctx.cwd, root) || ".").replaceAll(nodePath.sep, "/");
741
62
  }
742
63
  function resolvedIgnoreDirectories(ctx) {
743
64
  return safewordIgnoreDirectories(resolvedNamespaceDirectory(ctx));
744
65
  }
66
+ function durableNamespaceDirectories(ctx) {
67
+ const custom = resolvedNamespaceDirectory(ctx);
68
+ return custom === void 0 ? [".project", ".safeword-project"] : [".project", ".safeword-project", custom];
69
+ }
745
70
  function dirGlobExcludeMerge(field, globForDirectory = (dir) => `${dir}/**`) {
746
71
  return {
747
72
  keys: [field],
@@ -759,8 +84,11 @@ function dirGlobExcludeMerge(field, globForDirectory = (dir) => `${dir}/**`) {
759
84
  const safewordGlobs = new Set(
760
85
  resolvedIgnoreDirectories(ctx).map((dir) => globForDirectory(dir))
761
86
  );
87
+ const durableGlobs = new Set(
88
+ durableNamespaceDirectories(ctx).map((dir) => globForDirectory(dir))
89
+ );
762
90
  const current = Array.isArray(existing[field]) ? existing[field] : [];
763
- const cleaned = current.filter((entry) => !safewordGlobs.has(entry));
91
+ const cleaned = current.filter((entry) => !safewordGlobs.has(entry) || durableGlobs.has(entry));
764
92
  const rest = Object.fromEntries(Object.entries(existing).filter(([key]) => key !== field));
765
93
  return cleaned.length > 0 ? { ...rest, [field]: cleaned } : rest;
766
94
  }
@@ -830,7 +158,7 @@ export function filterSafewordFiles(
830
158
  }
831
159
 
832
160
  // src/schema.ts
833
- import nodePath7 from "path";
161
+ import nodePath6 from "path";
834
162
 
835
163
  // src/packs/golang/files.ts
836
164
  import { readFileSync } from "fs";
@@ -879,6 +207,10 @@ var SAFEWORD_ENABLE = [
879
207
  // error wrapping conventions
880
208
  "gocritic",
881
209
  // opinionated but high-signal
210
+ "lll",
211
+ // keep code and comments readable at the shared 100-column limit
212
+ "godoclint",
213
+ // enforce readable Go documentation without requiring docs everywhere
882
214
  "revive",
883
215
  // flexible metalinter
884
216
  "perfsprint",
@@ -894,7 +226,14 @@ var SAFEWORD_DISABLE = [
894
226
  ];
895
227
  var SAFEWORD_EXCLUSION_PRESETS = ["std-error-handling", "common-false-positives"];
896
228
  var SAFEWORD_SETTINGS = {
897
- nestif: { "min-complexity": 4 }
229
+ nestif: { "min-complexity": 4 },
230
+ lll: { "line-length": 100 },
231
+ gocritic: { commentedOutCode: { minLength: 50 } },
232
+ godoclint: {
233
+ default: "none",
234
+ enable: ["max-len"],
235
+ options: { "max-len": { length: 100 } }
236
+ }
898
237
  };
899
238
  function buildStandaloneConfig() {
900
239
  return {
@@ -1042,310 +381,9 @@ var golangManagedFiles = {
1042
381
 
1043
382
  // src/packs/python/files.ts
1044
383
  import { existsSync, readFileSync as readFileSync2 } from "fs";
1045
- import nodePath4 from "path";
1046
-
1047
- // src/packs/python/setup.ts
1048
- import { execFileSync } from "child_process";
1049
- import { readdirSync, realpathSync } from "fs";
1050
384
  import nodePath3 from "path";
1051
- var PYTHON_LAYERS = {
1052
- domain: ["domain", "models", "entities", "core"],
1053
- services: ["services", "usecases", "application"],
1054
- infra: ["infra", "infrastructure", "adapters", "repositories"],
1055
- api: ["api", "routes", "handlers", "views", "controllers"]
1056
- };
1057
- function hasAnyLayerPattern(cwd, patterns) {
1058
- for (const pattern of patterns) {
1059
- const srcPath = nodePath3.join(cwd, "src", pattern);
1060
- const rootPath = nodePath3.join(cwd, pattern);
1061
- if (exists(srcPath) || exists(rootPath)) {
1062
- return true;
1063
- }
1064
- }
1065
- return false;
1066
- }
1067
- function detectPythonLayers(cwd) {
1068
- const detected = [];
1069
- for (const [layer, patterns] of Object.entries(PYTHON_LAYERS)) {
1070
- if (hasAnyLayerPattern(cwd, patterns)) {
1071
- detected.push(layer);
1072
- }
1073
- }
1074
- const layerOrder = ["domain", "services", "infra", "api"];
1075
- return layerOrder.filter((layer) => detected.includes(layer));
1076
- }
1077
- function detectRootPackage(cwd) {
1078
- const pyprojectPath = nodePath3.join(cwd, "pyproject.toml");
1079
- const content = readFileSafe(pyprojectPath);
1080
- if (content) {
1081
- const nameMatch = /^name\s*=\s*"([^"]+)"/m.exec(content);
1082
- if (nameMatch?.[1]) {
1083
- return nameMatch[1].replaceAll("-", "_");
1084
- }
1085
- }
1086
- if (exists(nodePath3.join(cwd, "src"))) {
1087
- return "src";
1088
- }
1089
- return nodePath3.basename(cwd).replaceAll("-", "_");
1090
- }
1091
- var NON_PACKAGE_DIRS = /* @__PURE__ */ new Set([
1092
- "tests",
1093
- "test",
1094
- "docs",
1095
- "examples",
1096
- "scripts",
1097
- "node_modules",
1098
- "venv"
1099
- ]);
1100
- function importablePackagesIn(dir) {
1101
- if (!exists(dir)) return [];
1102
- try {
1103
- return readdirSync(dir, { withFileTypes: true }).filter(
1104
- (entry) => entry.isDirectory() && !entry.name.startsWith(".") && !NON_PACKAGE_DIRS.has(entry.name) && exists(nodePath3.join(dir, entry.name, "__init__.py"))
1105
- ).map((entry) => entry.name);
1106
- } catch {
1107
- return [];
1108
- }
1109
- }
1110
- function detectSolePackage(cwd) {
1111
- const candidates = [
1112
- ...importablePackagesIn(cwd),
1113
- ...importablePackagesIn(nodePath3.join(cwd, "src"))
1114
- ];
1115
- return candidates.length === 1 ? candidates[0] : void 0;
1116
- }
1117
- var PYTHON_DEPENDENCY_SEPARATORS = /* @__PURE__ */ new Set(["[", "<", ">", "=", "!", "~", ";", "@"]);
1118
- function normalizePythonDistributionName(value) {
1119
- return value.trim().toLowerCase().replaceAll(/[-_.]+/g, "-");
1120
- }
1121
- function startsPythonDependency(value, dependency) {
1122
- const candidate = normalizePythonDistributionName(value);
1123
- const normalizedDependency = normalizePythonDistributionName(dependency);
1124
- if (!candidate.startsWith(normalizedDependency)) return false;
1125
- const next = candidate.at(normalizedDependency.length);
1126
- return next === void 0 || PYTHON_DEPENDENCY_SEPARATORS.has(next) || next.trim() === "";
1127
- }
1128
- function asTomlTable(value) {
1129
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1130
- }
1131
- function parseTomlTable(content) {
1132
- try {
1133
- return asTomlTable(parse(content));
1134
- } catch {
1135
- return void 0;
1136
- }
1137
- }
1138
- function tomlTableAt(table, path) {
1139
- let current = table;
1140
- for (const key of path) {
1141
- current = current === void 0 ? void 0 : asTomlTable(current[key]);
1142
- }
1143
- return current;
1144
- }
1145
- function tomlStringArray(value) {
1146
- return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
1147
- }
1148
- function dependencyGroupSpecs(groups, groupName, visited = /* @__PURE__ */ new Set()) {
1149
- if (visited.has(groupName)) return [];
1150
- visited.add(groupName);
1151
- return (Array.isArray(groups[groupName]) ? groups[groupName] : []).flatMap((item) => {
1152
- if (typeof item === "string") return [item];
1153
- const includeGroup = asTomlTable(item)?.["include-group"];
1154
- return typeof includeGroup === "string" ? dependencyGroupSpecs(groups, includeGroup, visited) : [];
1155
- });
1156
- }
1157
- function pyprojectDependencySpecs(document) {
1158
- const project = asTomlTable(document.project);
1159
- const optionalDependencies = asTomlTable(project?.["optional-dependencies"]);
1160
- const dependencyGroups = asTomlTable(document["dependency-groups"]);
1161
- const uv = tomlTableAt(document, ["tool", "uv"]);
1162
- return [
1163
- ...tomlStringArray(project?.dependencies),
1164
- ...Object.values(optionalDependencies ?? {}).flatMap((value) => tomlStringArray(value)),
1165
- ...dependencyGroups === void 0 ? [] : Object.keys(dependencyGroups).flatMap(
1166
- (groupName) => dependencyGroupSpecs(dependencyGroups, groupName)
1167
- ),
1168
- ...tomlStringArray(uv?.["dev-dependencies"])
1169
- ];
1170
- }
1171
- function poetryDependencyNames(document) {
1172
- const poetry = tomlTableAt(document, ["tool", "poetry"]);
1173
- const groups = asTomlTable(poetry?.group);
1174
- const groupNames = Object.values(groups ?? {}).flatMap(
1175
- (group) => Object.keys(asTomlTable(asTomlTable(group)?.dependencies) ?? {})
1176
- );
1177
- return [
1178
- ...Object.keys(asTomlTable(poetry?.dependencies) ?? {}),
1179
- ...Object.keys(asTomlTable(poetry?.["dev-dependencies"]) ?? {}),
1180
- ...groupNames
1181
- ];
1182
- }
1183
- function hasPythonDependencyName(names, dependency) {
1184
- const normalizedDependency = normalizePythonDistributionName(dependency);
1185
- return names.some((name) => normalizePythonDistributionName(name) === normalizedDependency);
1186
- }
1187
- function containsPyprojectPythonDependency(content, dependency) {
1188
- const document = parseTomlTable(content);
1189
- if (document === void 0) return false;
1190
- return hasPythonDependencyName(poetryDependencyNames(document), dependency) || pyprojectDependencySpecs(document).some(
1191
- (specification) => startsPythonDependency(specification, dependency)
1192
- );
1193
- }
1194
- function containsPipfilePythonDependency(content, dependency) {
1195
- const document = parseTomlTable(content);
1196
- if (document === void 0) return false;
1197
- return hasPythonDependencyName(
1198
- [
1199
- ...Object.keys(asTomlTable(document.packages) ?? {}),
1200
- ...Object.keys(asTomlTable(document["dev-packages"]) ?? {})
1201
- ],
1202
- dependency
1203
- );
1204
- }
1205
- function shortRequirementsInclude(declaration) {
1206
- if (!declaration.startsWith("-r")) return void 0;
1207
- return declaration.slice(2).trim() || void 0;
1208
- }
1209
- function longRequirementsInclude(declaration) {
1210
- const longOption = "--requirement";
1211
- if (!declaration.startsWith(longOption)) return void 0;
1212
- const suffix = declaration.slice(longOption.length);
1213
- if (suffix.startsWith("=")) return suffix.slice(1).trim() || void 0;
1214
- if (suffix.trimStart().length === suffix.length) return void 0;
1215
- return suffix.trim() || void 0;
1216
- }
1217
- function unquoteRequirementsInclude(include) {
1218
- if (include.startsWith('"') && include.endsWith('"') || include.startsWith("'") && include.endsWith("'")) {
1219
- return include.slice(1, -1);
1220
- }
1221
- return include;
1222
- }
1223
- function requirementsIncludePath(line) {
1224
- const declaration = (line.split("#", 1)[0] ?? "").trim();
1225
- const include = shortRequirementsInclude(declaration) ?? longRequirementsInclude(declaration);
1226
- return include === void 0 ? void 0 : unquoteRequirementsInclude(include);
1227
- }
1228
- function isPathWithinDirectory(candidate, directory) {
1229
- const relative = nodePath3.relative(directory, candidate);
1230
- return relative === "" || relative !== ".." && !relative.startsWith(`..${nodePath3.sep}`);
1231
- }
1232
- function isRealPathWithinDirectory(candidate, directory) {
1233
- try {
1234
- return isPathWithinDirectory(realpathSync(candidate), realpathSync(directory));
1235
- } catch {
1236
- return false;
1237
- }
1238
- }
1239
- function containsRequirementsPythonDependency(projectDirectory, requirementsPath, dependency, visited = /* @__PURE__ */ new Set()) {
1240
- const resolvedRequirementsPath = nodePath3.resolve(requirementsPath);
1241
- if (!isRealPathWithinDirectory(resolvedRequirementsPath, projectDirectory) || visited.has(resolvedRequirementsPath)) {
1242
- return false;
1243
- }
1244
- visited.add(resolvedRequirementsPath);
1245
- const content = readFileSafe(resolvedRequirementsPath);
1246
- if (content === void 0) return false;
1247
- return content.split("\n").some((line) => {
1248
- if (line.trimStart().startsWith("#")) return false;
1249
- const declaration = line.split("#", 1)[0] ?? "";
1250
- if (startsPythonDependency(declaration, dependency)) return true;
1251
- const include = requirementsIncludePath(line);
1252
- if (include === void 0 || nodePath3.isAbsolute(include)) return false;
1253
- const includePath = nodePath3.resolve(nodePath3.dirname(resolvedRequirementsPath), include);
1254
- return containsRequirementsPythonDependency(projectDirectory, includePath, dependency, visited);
1255
- });
1256
- }
1257
- function hasPythonDependency(cwd, dependency) {
1258
- const pyprojectContent = readFileSafe(nodePath3.join(cwd, "pyproject.toml"));
1259
- const pipfileContent = readFileSafe(nodePath3.join(cwd, "Pipfile"));
1260
- return pyprojectContent !== void 0 && containsPyprojectPythonDependency(pyprojectContent, dependency) || pipfileContent !== void 0 && containsPipfilePythonDependency(pipfileContent, dependency) || containsRequirementsPythonDependency(cwd, nodePath3.join(cwd, "requirements.txt"), dependency);
1261
- }
1262
- function hasRuffDependency(cwd) {
1263
- return hasPythonDependency(cwd, "ruff");
1264
- }
1265
- function detectPythonPackageManager(cwd) {
1266
- if (exists(nodePath3.join(cwd, "uv.lock"))) {
1267
- return "uv";
1268
- }
1269
- if (exists(nodePath3.join(cwd, "poetry.lock"))) {
1270
- return "poetry";
1271
- }
1272
- const pyprojectPath = nodePath3.join(cwd, "pyproject.toml");
1273
- const pyprojectContent = readFileSafe(pyprojectPath);
1274
- if (pyprojectContent?.includes("[tool.poetry]")) {
1275
- return "poetry";
1276
- }
1277
- if (exists(nodePath3.join(cwd, "Pipfile"))) {
1278
- return "pipenv";
1279
- }
1280
- return "pip";
1281
- }
1282
- function getPythonInstallCommand(cwd, tools = ["ruff"]) {
1283
- const pm = detectPythonPackageManager(cwd);
1284
- const toolList = tools.join(" ");
1285
- switch (pm) {
1286
- case "uv": {
1287
- return `uv add --dev ${toolList}`;
1288
- }
1289
- case "poetry": {
1290
- return `poetry add --group dev ${toolList}`;
1291
- }
1292
- case "pipenv": {
1293
- return `pipenv install --dev ${toolList}`;
1294
- }
1295
- case "pip": {
1296
- return `pip install ${toolList}`;
1297
- }
1298
- }
1299
- }
1300
- function pythonInstallInvocation(cwd, tools) {
1301
- switch (detectPythonPackageManager(cwd)) {
1302
- case "uv": {
1303
- return { command: "uv", arguments: ["add", "--dev", ...tools] };
1304
- }
1305
- case "poetry": {
1306
- return { command: "poetry", arguments: ["add", "--group", "dev", ...tools] };
1307
- }
1308
- case "pipenv": {
1309
- return { command: "pipenv", arguments: ["install", "--dev", ...tools] };
1310
- }
1311
- case "pip": {
1312
- return { command: "pip", arguments: ["install", ...tools] };
1313
- }
1314
- }
1315
- }
1316
- function getPythonTools(includeImportLinter) {
1317
- const tools = ["ruff", "mypy", "deadcode"];
1318
- if (includeImportLinter) tools.push("import-linter");
1319
- return tools;
1320
- }
1321
- function getMissingPythonToolDependencies(cwd, includeImportLinter) {
1322
- return getPythonTools(includeImportLinter).filter((tool) => !hasPythonDependency(cwd, tool));
1323
- }
1324
- function installPythonDependencies(cwd, tools) {
1325
- if (tools.length === 0) return true;
1326
- if (process.env.SAFEWORD_SKIP_INSTALL) return true;
1327
- const pm = detectPythonPackageManager(cwd);
1328
- if (pm === "pip") return false;
1329
- try {
1330
- const invocation = pythonInstallInvocation(cwd, tools);
1331
- execFileSync(invocation.command, invocation.arguments, {
1332
- cwd,
1333
- stdio: "pipe",
1334
- timeout: 6e4
1335
- // 60s timeout to prevent hanging on network/resolution issues
1336
- });
1337
- return true;
1338
- } catch {
1339
- return false;
1340
- }
1341
- }
1342
- function setupPythonTooling() {
1343
- return { files: [] };
1344
- }
1345
-
1346
- // src/packs/python/files.ts
1347
385
  function hasLegacyCustomerRuffExtend(cwd) {
1348
- const ruffPath = nodePath4.join(cwd, "ruff.toml");
386
+ const ruffPath = nodePath3.join(cwd, "ruff.toml");
1349
387
  if (!existsSync(ruffPath)) return false;
1350
388
  try {
1351
389
  const content = readFileSync2(ruffPath, "utf8");
@@ -1395,7 +433,6 @@ var SAFEWORD_RULES = [
1395
433
  var RUFF_SHARED_SETTINGS = `ignore = [
1396
434
  "COM812", # missing trailing comma - conflicts with formatter
1397
435
  "ISC001", # single-line-implicit-string-concatenation - conflicts with formatter
1398
- "E501", # line too long - formatter handles this
1399
436
  ]
1400
437
 
1401
438
  [lint.per-file-ignores]
@@ -1539,7 +576,7 @@ function importLinterScaffoldContent(cwd) {
1539
576
 
1540
577
  // src/packs/rust/files.ts
1541
578
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
1542
- import nodePath5 from "path";
579
+ import nodePath4 from "path";
1543
580
  var SAFEWORD_CLIPPY_THRESHOLDS = {
1544
581
  "cognitive-complexity-threshold": 10,
1545
582
  "too-many-arguments-threshold": 5,
@@ -1562,7 +599,7 @@ function generateSafewordClippyConfig(existingConfig, cwd) {
1562
599
  ${generateClippyThresholds()}
1563
600
  `;
1564
601
  }
1565
- const configPath = nodePath5.join(cwd, existingConfig);
602
+ const configPath = nodePath4.join(cwd, existingConfig);
1566
603
  if (!existsSync2(configPath)) {
1567
604
  return `# Safeword clippy config - standalone (no project config to merge)
1568
605
  # Used by hooks for LLM enforcement.
@@ -1626,7 +663,7 @@ function editionInSection(content, header) {
1626
663
  function resolveRustEdition(cwd) {
1627
664
  let content;
1628
665
  try {
1629
- content = readFileSync3(nodePath5.join(cwd, "Cargo.toml"), "utf8");
666
+ content = readFileSync3(nodePath4.join(cwd, "Cargo.toml"), "utf8");
1630
667
  } catch {
1631
668
  return FALLBACK_RUST_EDITION;
1632
669
  }
@@ -1728,8 +765,8 @@ var rustManagedFiles = {
1728
765
 
1729
766
  // src/packs/sql/dialect.ts
1730
767
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
1731
- import nodePath6 from "path";
1732
- import process2 from "process";
768
+ import nodePath5 from "path";
769
+ import process from "process";
1733
770
  import YAML2 from "yaml";
1734
771
  var ADAPTER_TO_DIALECT = {
1735
772
  postgres: "postgres",
@@ -1816,16 +853,16 @@ function detectFromProfiles(cwd) {
1816
853
  if (!dbtProjectDirectory) return void 0;
1817
854
  try {
1818
855
  const projectContent = readFileSync4(
1819
- nodePath6.join(dbtProjectDirectory, "dbt_project.yml"),
856
+ nodePath5.join(dbtProjectDirectory, "dbt_project.yml"),
1820
857
  "utf8"
1821
858
  );
1822
859
  const project = YAML2.parse(projectContent, { schema: "failsafe" });
1823
860
  const profileName = project.profile;
1824
861
  if (typeof profileName !== "string") return void 0;
1825
862
  const candidates = [
1826
- nodePath6.join(dbtProjectDirectory, "profiles.yml"),
1827
- nodePath6.join(dbtProjectDirectory, "dbt", "profiles.yml"),
1828
- nodePath6.join(process2.env.HOME ?? "", ".dbt", "profiles.yml")
863
+ nodePath5.join(dbtProjectDirectory, "profiles.yml"),
864
+ nodePath5.join(dbtProjectDirectory, "dbt", "profiles.yml"),
865
+ nodePath5.join(process.env.HOME ?? "", ".dbt", "profiles.yml")
1829
866
  ];
1830
867
  for (const profilesPath of candidates) {
1831
868
  const adapterType = resolveProfileType(profilesPath, profileName);
@@ -1839,8 +876,8 @@ function detectFromProfiles(cwd) {
1839
876
  function detectFromPythonDependencies(cwd) {
1840
877
  const directory = findInTree(cwd, "requirements.txt") ?? findInTree(cwd, "pyproject.toml");
1841
878
  if (!directory) return void 0;
1842
- const requirementsPath = nodePath6.join(directory, "requirements.txt");
1843
- const pyprojectPath = nodePath6.join(directory, "pyproject.toml");
879
+ const requirementsPath = nodePath5.join(directory, "requirements.txt");
880
+ const pyprojectPath = nodePath5.join(directory, "pyproject.toml");
1844
881
  try {
1845
882
  let content;
1846
883
  if (existsSync3(requirementsPath)) {
@@ -1864,7 +901,7 @@ function detectFromSqlcConfig(cwd) {
1864
901
  const directory = findInTree(cwd, filename);
1865
902
  if (!directory) continue;
1866
903
  try {
1867
- const content = readFileSync4(nodePath6.join(directory, filename), "utf8");
904
+ const content = readFileSync4(nodePath5.join(directory, filename), "utf8");
1868
905
  const match = /engine['":\s]+(\w+)/.exec(content);
1869
906
  if (match?.[1]) return ADAPTER_TO_DIALECT[match[1]] ?? match[1];
1870
907
  } catch {
@@ -1874,7 +911,7 @@ function detectFromSqlcConfig(cwd) {
1874
911
  return void 0;
1875
912
  }
1876
913
  function detectFromPrismaSchema(cwd) {
1877
- const schemaPath = nodePath6.join(cwd, "prisma", "schema.prisma");
914
+ const schemaPath = nodePath5.join(cwd, "prisma", "schema.prisma");
1878
915
  if (!existsSync3(schemaPath)) return void 0;
1879
916
  try {
1880
917
  const content = readFileSync4(schemaPath, "utf8");
@@ -1887,7 +924,7 @@ function detectFromPrismaSchema(cwd) {
1887
924
  }
1888
925
  function detectFromDrizzleConfig(cwd) {
1889
926
  for (const filename of ["drizzle.config.ts", "drizzle.config.js", "drizzle.config.mjs"]) {
1890
- const filePath = nodePath6.join(cwd, filename);
927
+ const filePath = nodePath5.join(cwd, filename);
1891
928
  if (!existsSync3(filePath)) continue;
1892
929
  try {
1893
930
  const content = readFileSync4(filePath, "utf8");
@@ -1900,7 +937,7 @@ function detectFromDrizzleConfig(cwd) {
1900
937
  return void 0;
1901
938
  }
1902
939
  function detectFromDatabaseUrl(cwd) {
1903
- const envPath = nodePath6.join(cwd, ".env");
940
+ const envPath = nodePath5.join(cwd, ".env");
1904
941
  if (!existsSync3(envPath)) return void 0;
1905
942
  try {
1906
943
  const content = readFileSync4(envPath, "utf8");
@@ -2099,8 +1136,9 @@ var BIOME_JSON_MERGE = {
2099
1136
  "!.safeword/**",
2100
1137
  ...resolvedIgnoreDirectories(ctx).map((dir) => `!${dir}`)
2101
1138
  ]);
1139
+ const durableExcludes = new Set(durableNamespaceDirectories(ctx).map((dir) => `!${dir}`));
2102
1140
  const cleanedIncludes = existingIncludes.filter(
2103
- (entry) => !safewordExcludes.has(entry)
1141
+ (entry) => !safewordExcludes.has(entry) || durableExcludes.has(entry)
2104
1142
  );
2105
1143
  const cleanedFiles = { ...files };
2106
1144
  if (cleanedIncludes.length > 0) {
@@ -2197,6 +1235,9 @@ function addScriptIfMissing(scripts, name, command) {
2197
1235
  if (!existing) scripts[name] = command;
2198
1236
  }
2199
1237
  var GHERKIN_LINT_SCRIPT = "safeword project lint-gherkin";
1238
+ function removeScriptIfEqual(scripts, name, safewordValue) {
1239
+ return scripts[name] === safewordValue ? Object.fromEntries(Object.entries(scripts).filter(([key]) => key !== name)) : scripts;
1240
+ }
2200
1241
  function mergeLintScripts(scripts, projectType) {
2201
1242
  addScriptIfMissing(scripts, "lint:gherkin", GHERKIN_LINT_SCRIPT);
2202
1243
  if (projectType.existingLinter) {
@@ -2253,13 +1294,10 @@ var typescriptJsonMerges = {
2253
1294
  },
2254
1295
  unmerge: (existing, _ctx) => {
2255
1296
  const result = { ...existing };
2256
- const scripts = { ...existing.scripts };
2257
- delete scripts["lint:eslint"];
2258
- delete scripts["lint:sh"];
2259
- delete scripts["format:check"];
2260
- delete scripts.knip;
2261
- delete scripts.publint;
2262
- delete scripts["test:bdd"];
1297
+ let scripts = { ...existing.scripts };
1298
+ scripts = removeScriptIfEqual(scripts, "lint", SAFEWORD_PRIMARY_LINT_SCRIPT);
1299
+ scripts = removeScriptIfEqual(scripts, "lint:gherkin", GHERKIN_LINT_SCRIPT);
1300
+ scripts = removeScriptIfEqual(scripts, "test:bdd", "cucumber-js");
2263
1301
  assignOrPrune(result, "scripts", scripts);
2264
1302
  return result;
2265
1303
  }
@@ -2299,6 +1337,7 @@ var typescriptJsonMerges = {
2299
1337
  return result;
2300
1338
  },
2301
1339
  unmerge: (existing, ctx) => {
1340
+ if (ctx.projectType.existingPrettierConfig) return existing;
2302
1341
  const result = { ...existing };
2303
1342
  const safewordPlugins = new Set(getPrettierPlugins(ctx.projectType));
2304
1343
  if (Array.isArray(result.plugins)) {
@@ -2624,9 +1663,12 @@ var MCP_JSON_MERGE = {
2624
1663
  },
2625
1664
  unmerge: (existing) => {
2626
1665
  const result = { ...existing };
2627
- const mcpServers = { ...existing.mcpServers };
2628
- delete mcpServers.context7;
2629
- delete mcpServers.playwright;
1666
+ let mcpServers = { ...existing.mcpServers };
1667
+ for (const name of ["context7", "playwright"]) {
1668
+ if (JSON.stringify(mcpServers[name]) === JSON.stringify(MCP_SERVERS[name])) {
1669
+ mcpServers = Object.fromEntries(Object.entries(mcpServers).filter(([key]) => key !== name));
1670
+ }
1671
+ }
2630
1672
  assignOrPrune(result, "mcpServers", mcpServers);
2631
1673
  return result;
2632
1674
  }
@@ -2759,15 +1801,17 @@ var BDD_LANE_FILE_PATHS = [
2759
1801
  ];
2760
1802
  var BDD_LANE_SCRIPT = "test:bdd";
2761
1803
  function bddLaneFile(templatePath) {
1804
+ const templateContent = () => readFile(nodePath6.join(getTemplatesDirectory(), templatePath));
2762
1805
  return {
2763
1806
  // `template` declares provenance for the schema↔templates contract;
2764
1807
  // the generator (which takes precedence) gates on harness detection.
2765
1808
  template: templatePath,
2766
- generator: (ctx) => ctx.projectType.scaffoldBddLane ? readFile(nodePath7.join(getTemplatesDirectory(), templatePath)) : void 0
1809
+ generator: (ctx) => ctx.projectType.scaffoldBddLane ? templateContent() : void 0,
1810
+ removeIfUnmodified: templateContent
2767
1811
  };
2768
1812
  }
2769
1813
  function prReviewEnabled(cwd) {
2770
- const content = readFileSafe(nodePath7.join(cwd, ".safeword", "config.json"));
1814
+ const content = readFileSafe(nodePath6.join(cwd, ".safeword", "config.json"));
2771
1815
  if (content === void 0) return false;
2772
1816
  try {
2773
1817
  const config = JSON.parse(content);
@@ -2781,7 +1825,7 @@ function normalizePrReviewWorkflowVersionPins(content) {
2781
1825
  const segments = content.split(commandPrefix);
2782
1826
  return segments.map((segment, index) => {
2783
1827
  if (index === 0) return segment;
2784
- const end = segment.indexOf(" ");
1828
+ const end = segment.search(/\s/u);
2785
1829
  if (end === -1) return segment;
2786
1830
  const version = segment.slice(0, end);
2787
1831
  const coreIdentifiers = version.split("-", 1)[0]?.split(".") ?? [];
@@ -2793,7 +1837,7 @@ function normalizePrReviewWorkflowVersionPins(content) {
2793
1837
  }).join(commandPrefix);
2794
1838
  }
2795
1839
  function prReviewWorkflowFile(templatePath) {
2796
- const workflowContent = () => readFile(nodePath7.join(getTemplatesDirectory(), templatePath)).split("__SAFEWORD_VERSION__").join(VERSION);
1840
+ const workflowContent = () => readFile(nodePath6.join(getTemplatesDirectory(), templatePath)).split("__SAFEWORD_VERSION__").join(VERSION);
2797
1841
  return {
2798
1842
  template: templatePath,
2799
1843
  generator: (ctx) => prReviewEnabled(ctx.cwd) ? workflowContent() : void 0,
@@ -2852,11 +1896,16 @@ var SAFEWORD_SCHEMA = {
2852
1896
  ".claude/commands",
2853
1897
  // Custom-agent homes (GH628F): users keep their own agents in this dir —
2854
1898
  // add-to, never own. Codex is plugin-only and receives no project scaffold.
2855
- ".claude/agents"
1899
+ ".claude/agents",
1900
+ // Project-owned namespace directories. Safeword creates these when missing,
1901
+ // but uninstall must leave the resolved namespace byte-for-byte untouched.
1902
+ ".safeword-project/learnings",
1903
+ ".safeword-project/tickets",
1904
+ ".safeword-project/tickets/completed",
1905
+ ".safeword-project/tmp"
2856
1906
  ],
2857
- // Created on setup but NOT deleted on reset (preserves user data)
1907
+ // Runtime data directories removed on reset only when empty.
2858
1908
  preservedDirs: [
2859
- ".safeword-project/learnings",
2860
1909
  ".safeword/logs",
2861
1910
  // Runtime cloud-filing spool (BNGK9W) — per-session drafts + nudge markers the
2862
1911
  // retro writes at runtime; user/runtime data the schema does not own.
@@ -2867,10 +1916,7 @@ var SAFEWORD_SCHEMA = {
2867
1916
  ".safeword/self-reports",
2868
1917
  // Authored collisions retained during automatic .safeword-project → .project
2869
1918
  // migration. Recovery copies are user data, not deployed framework assets.
2870
- ".safeword/namespace-migration-conflicts-v1",
2871
- ".safeword-project/tickets",
2872
- ".safeword-project/tickets/completed",
2873
- ".safeword-project/tmp"
1919
+ ".safeword/namespace-migration-conflicts-v1"
2874
1920
  ],
2875
1921
  // Files to delete on upgrade (renamed or removed in newer versions)
2876
1922
  deprecatedFiles: [
@@ -3000,8 +2046,6 @@ var SAFEWORD_SCHEMA = {
3000
2046
  // Files owned by safeword (overwritten on upgrade if content changed)
3001
2047
  // (bddLaneFile entries: see the helper defined above the schema)
3002
2048
  ownedFiles: {
3003
- // Project root config files (for audit/quality tools)
3004
- ".jscpd.json": { template: ".jscpd.json" },
3005
2049
  // BDD acceptance lane config (ticket 102b) — safeword-owned; the lane's
3006
2050
  // working files (features/, steps/) are customer-owned in managedFiles.
3007
2051
  // Suppressed when the repo has its own cucumber harness (56JCFZ).
@@ -3472,6 +2516,9 @@ var SAFEWORD_SCHEMA = {
3472
2516
  },
3473
2517
  // Files created if missing, updated only if content matches current template
3474
2518
  managedFiles: {
2519
+ // Project-root audit config is scaffolded when absent, then customer-owned.
2520
+ // Full uninstall removes it only while it still matches Safeword's template.
2521
+ ".jscpd.json": { template: ".jscpd.json" },
3475
2522
  // Package-owned Codex runtime adapters. Their generator intentionally
3476
2523
  // returns undefined: the plugin CLI executes them from the npm package,
3477
2524
  // never from a customer repository.
@@ -3660,16 +2707,17 @@ var SAFEWORD_SCHEMA = {
3660
2707
  # Safeword - Local cache and transient state
3661
2708
  ${SAFEWORD_TRANSIENT_PATHS.join("\n")}
3662
2709
  `,
3663
- // Marker is the NEWEST line (.safeword/state/reviews/, durable review
3664
- // job state) so customers with any
3665
- // older block re-apply on upgrade and pick up the latest transient paths.
3666
- // This patch has no `rerender`, so moving the marker is the ONLY way an
3667
- // existing install ever sees a newly added path — bump it whenever
3668
- // SAFEWORD_TRANSIENT_PATHS grows. Hooks write state under the resolved
3669
- // root, so fresh installs generate these under .project/. Without them,
3670
- // those generated files show as untracked in `git status --porcelain` —
3671
- // churning the tree and blocking the auto-upgrade gate.
3672
- marker: ".safeword/state/reviews/"
2710
+ // A stable header plus rerender heals the block whenever the transient
2711
+ // path list grows and lets uninstall recognize older variants.
2712
+ rerender: true,
2713
+ // eslint-disable-next-line security/detect-non-literal-regexp -- derived only from the source-controlled constant above
2714
+ rerenderOwnedLinePattern: new RegExp(
2715
+ `^(?:${SAFEWORD_TRANSIENT_PATHS.map(
2716
+ (path) => path.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`)
2717
+ ).join("|")})$`,
2718
+ "u"
2719
+ ),
2720
+ marker: "# Safeword - Local cache and transient state"
3673
2721
  },
3674
2722
  // Prettier ignores: safeword owns the dot-directories in SAFEWORD_IGNORE_DIRS
3675
2723
  // (.safeword/, .claude/, .cursor/, .codex/, .agents/, and both namespace
@@ -3692,7 +2740,13 @@ ${PRETTIER_EXCLUSIONS_HEADER}
3692
2740
  ${managedPrettierPaths(ctx).join("\n")}
3693
2741
  `,
3694
2742
  rerender: true,
3695
- marker: PRETTIER_EXCLUSIONS_HEADER
2743
+ marker: PRETTIER_EXCLUSIONS_HEADER,
2744
+ replacementAfterUnpatch: (ctx) => `
2745
+ # Project namespace exclusions (preserved after Safeword uninstall)
2746
+ ${durableNamespaceDirectories(
2747
+ ctx
2748
+ ).map((dir) => `${dir}/`).join("\n")}
2749
+ `
3696
2750
  },
3697
2751
  ".gitattributes": {
3698
2752
  // ctx factory + rerender (issue #566), same shape as .prettierignore: a custom
@@ -3706,6 +2760,7 @@ ${managedPrettierPaths(ctx).join("\n")}
3706
2760
  content: (ctx) => `${managedGitattributes(ctx)}
3707
2761
  `,
3708
2762
  rerender: true,
2763
+ rerenderOwnedLinePattern: /^(?:\*\*\/architecture\.generated\.md|.+\/tickets\/INDEX(?:-completed)?\.md) merge=union linguist-generated=true$/u,
3709
2764
  marker: GITATTRIBUTES_HEADER
3710
2765
  }
3711
2766
  },
@@ -3805,7 +2860,6 @@ ${managedPrettierPaths(ctx).join("\n")}
3805
2860
  packages: typescriptPackages
3806
2861
  };
3807
2862
  var CURSOR_PROJECT_PATHS = /* @__PURE__ */ new Set([
3808
- ".safeword/hooks/lib/cursor-run-identity.ts",
3809
2863
  ".safeword/hooks/lib/cursor-state.ts",
3810
2864
  ".safeword/hooks/session-cursor-auto-upgrade.ts"
3811
2865
  ]);
@@ -3834,14 +2888,6 @@ function schemaForProjectSurfaces(schema, surfaces) {
3834
2888
  }
3835
2889
 
3836
2890
  export {
3837
- parse,
3838
- hasRuffDependency,
3839
- detectPythonPackageManager,
3840
- getPythonInstallCommand,
3841
- getPythonTools,
3842
- getMissingPythonToolDependencies,
3843
- installPythonDependencies,
3844
- setupPythonTooling,
3845
2891
  hasImportLinterScaffoldTarget,
3846
2892
  generateOwnedPathsModule,
3847
2893
  typescriptPackages,
@@ -3852,43 +2898,4 @@ export {
3852
2898
  isCursorProjectPath,
3853
2899
  schemaForProjectSurfaces
3854
2900
  };
3855
- /*! Bundled license information:
3856
-
3857
- smol-toml/dist/date.js:
3858
- smol-toml/dist/error.js:
3859
- smol-toml/dist/primitive.js:
3860
- smol-toml/dist/util.js:
3861
- smol-toml/dist/extract.js:
3862
- smol-toml/dist/struct.js:
3863
- smol-toml/dist/parse.js:
3864
- smol-toml/dist/stringify.js:
3865
- smol-toml/dist/index.js:
3866
- (*!
3867
- * Copyright (c) Squirrel Chat et al., All rights reserved.
3868
- * SPDX-License-Identifier: BSD-3-Clause
3869
- *
3870
- * Redistribution and use in source and binary forms, with or without
3871
- * modification, are permitted provided that the following conditions are met:
3872
- *
3873
- * 1. Redistributions of source code must retain the above copyright notice, this
3874
- * list of conditions and the following disclaimer.
3875
- * 2. Redistributions in binary form must reproduce the above copyright notice,
3876
- * this list of conditions and the following disclaimer in the
3877
- * documentation and/or other materials provided with the distribution.
3878
- * 3. Neither the name of the copyright holder nor the names of its contributors
3879
- * may be used to endorse or promote products derived from this software without
3880
- * specific prior written permission.
3881
- *
3882
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3883
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3884
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3885
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3886
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3887
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3888
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3889
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3890
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3891
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3892
- *)
3893
- */
3894
- //# sourceMappingURL=chunk-BSOUMHMQ.js.map
2901
+ //# sourceMappingURL=chunk-IPTM5VE7.js.map