agent-sdd 1.0.3

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 (304) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1028 -0
  3. package/README.ru.md +1046 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.js +867 -0
  6. package/dist/features/approve/adapters/inbound/CliApproveHandler.d.ts +17 -0
  7. package/dist/features/approve/adapters/inbound/CliApproveHandler.js +108 -0
  8. package/dist/features/approve/adapters/outbound/NodeApproveFileSystem.d.ts +8 -0
  9. package/dist/features/approve/adapters/outbound/NodeApproveFileSystem.js +147 -0
  10. package/dist/features/approve/adapters/outbound/NodePlanFileWriter.d.ts +6 -0
  11. package/dist/features/approve/adapters/outbound/NodePlanFileWriter.js +92 -0
  12. package/dist/features/approve/adapters/outbound/SystemApproveClock.d.ts +4 -0
  13. package/dist/features/approve/adapters/outbound/SystemApproveClock.js +5 -0
  14. package/dist/features/approve/application/ApplyApproval.d.ts +19 -0
  15. package/dist/features/approve/application/ApplyApproval.js +30 -0
  16. package/dist/features/approve/application/WriteAttestation.d.ts +19 -0
  17. package/dist/features/approve/application/WriteAttestation.js +23 -0
  18. package/dist/features/approve/domain/ApproveRequest.d.ts +24 -0
  19. package/dist/features/approve/domain/ApproveRequest.js +24 -0
  20. package/dist/features/approve/domain/Rewrite.d.ts +1 -0
  21. package/dist/features/approve/domain/Rewrite.js +6 -0
  22. package/dist/features/approve/ports/inbound/ApproveCommand.d.ts +10 -0
  23. package/dist/features/approve/ports/inbound/ApproveCommand.js +1 -0
  24. package/dist/features/approve/ports/outbound/ApproveClock.d.ts +3 -0
  25. package/dist/features/approve/ports/outbound/ApproveClock.js +1 -0
  26. package/dist/features/approve/ports/outbound/ApproveConfigPort.d.ts +4 -0
  27. package/dist/features/approve/ports/outbound/ApproveConfigPort.js +1 -0
  28. package/dist/features/approve/ports/outbound/ApproveFileSystem.d.ts +8 -0
  29. package/dist/features/approve/ports/outbound/ApproveFileSystem.js +1 -0
  30. package/dist/features/approve/ports/outbound/PlanFileWriter.d.ts +13 -0
  31. package/dist/features/approve/ports/outbound/PlanFileWriter.js +1 -0
  32. package/dist/features/check/adapters/inbound/CliCheckHandler.d.ts +8 -0
  33. package/dist/features/check/adapters/inbound/CliCheckHandler.js +62 -0
  34. package/dist/features/check/adapters/outbound/ChildProcessCheckGit.d.ts +8 -0
  35. package/dist/features/check/adapters/outbound/ChildProcessCheckGit.js +112 -0
  36. package/dist/features/check/adapters/outbound/NodeCheckFileReader.d.ts +7 -0
  37. package/dist/features/check/adapters/outbound/NodeCheckFileReader.js +44 -0
  38. package/dist/features/check/application/CheckBaseline.d.ts +28 -0
  39. package/dist/features/check/application/CheckBaseline.js +54 -0
  40. package/dist/features/check/domain/BaselineComparison.d.ts +1 -0
  41. package/dist/features/check/domain/BaselineComparison.js +2 -0
  42. package/dist/features/check/ports/inbound/CheckCommand.d.ts +4 -0
  43. package/dist/features/check/ports/inbound/CheckCommand.js +1 -0
  44. package/dist/features/check/ports/outbound/CheckConfigPort.d.ts +4 -0
  45. package/dist/features/check/ports/outbound/CheckConfigPort.js +1 -0
  46. package/dist/features/check/ports/outbound/CheckGitPort.d.ts +7 -0
  47. package/dist/features/check/ports/outbound/CheckGitPort.js +1 -0
  48. package/dist/features/check/ports/outbound/CheckSpecPort.d.ts +9 -0
  49. package/dist/features/check/ports/outbound/CheckSpecPort.js +1 -0
  50. package/dist/features/doctor/adapters/inbound/CliDoctorHandler.d.ts +8 -0
  51. package/dist/features/doctor/adapters/inbound/CliDoctorHandler.js +77 -0
  52. package/dist/features/doctor/adapters/outbound/NodeRegistryReader.d.ts +5 -0
  53. package/dist/features/doctor/adapters/outbound/NodeRegistryReader.js +40 -0
  54. package/dist/features/doctor/application/RunDoctor.d.ts +30 -0
  55. package/dist/features/doctor/application/RunDoctor.js +78 -0
  56. package/dist/features/doctor/domain/RegistryRow.d.ts +23 -0
  57. package/dist/features/doctor/domain/RegistryRow.js +114 -0
  58. package/dist/features/doctor/domain/SemverRange.d.ts +7 -0
  59. package/dist/features/doctor/domain/SemverRange.js +82 -0
  60. package/dist/features/doctor/ports/inbound/DoctorCommand.d.ts +8 -0
  61. package/dist/features/doctor/ports/inbound/DoctorCommand.js +1 -0
  62. package/dist/features/doctor/ports/outbound/RegistryReader.d.ts +12 -0
  63. package/dist/features/doctor/ports/outbound/RegistryReader.js +1 -0
  64. package/dist/features/finalize/adapters/inbound/CliFinalizeHandler.d.ts +8 -0
  65. package/dist/features/finalize/adapters/inbound/CliFinalizeHandler.js +80 -0
  66. package/dist/features/finalize/adapters/outbound/NodeFinalizeFileSystem.d.ts +11 -0
  67. package/dist/features/finalize/adapters/outbound/NodeFinalizeFileSystem.js +167 -0
  68. package/dist/features/finalize/adapters/outbound/NodePlanRepo.d.ts +7 -0
  69. package/dist/features/finalize/adapters/outbound/NodePlanRepo.js +82 -0
  70. package/dist/features/finalize/adapters/outbound/SystemFinalizeClock.d.ts +4 -0
  71. package/dist/features/finalize/adapters/outbound/SystemFinalizeClock.js +5 -0
  72. package/dist/features/finalize/application/RunFinalize.d.ts +34 -0
  73. package/dist/features/finalize/application/RunFinalize.js +98 -0
  74. package/dist/features/finalize/domain/ValidateFinalizeGraph.d.ts +9 -0
  75. package/dist/features/finalize/domain/ValidateFinalizeGraph.js +86 -0
  76. package/dist/features/finalize/ports/inbound/FinalizeCommand.d.ts +7 -0
  77. package/dist/features/finalize/ports/inbound/FinalizeCommand.js +1 -0
  78. package/dist/features/finalize/ports/outbound/FinalizeClock.d.ts +3 -0
  79. package/dist/features/finalize/ports/outbound/FinalizeClock.js +1 -0
  80. package/dist/features/finalize/ports/outbound/FinalizeConfigPort.d.ts +4 -0
  81. package/dist/features/finalize/ports/outbound/FinalizeConfigPort.js +1 -0
  82. package/dist/features/finalize/ports/outbound/FinalizeFileSystem.d.ts +14 -0
  83. package/dist/features/finalize/ports/outbound/FinalizeFileSystem.js +1 -0
  84. package/dist/features/finalize/ports/outbound/PlanRepo.d.ts +21 -0
  85. package/dist/features/finalize/ports/outbound/PlanRepo.js +1 -0
  86. package/dist/features/install/adapters/inbound/CliInstallHandler.d.ts +8 -0
  87. package/dist/features/install/adapters/inbound/CliInstallHandler.js +54 -0
  88. package/dist/features/install/adapters/outbound/NodeInstallSource.d.ts +7 -0
  89. package/dist/features/install/adapters/outbound/NodeInstallSource.js +24 -0
  90. package/dist/features/install/adapters/outbound/NodeInstallTargetFs.d.ts +7 -0
  91. package/dist/features/install/adapters/outbound/NodeInstallTargetFs.js +30 -0
  92. package/dist/features/install/application/InstallRules.d.ts +10 -0
  93. package/dist/features/install/application/InstallRules.js +73 -0
  94. package/dist/features/install/domain/InstallPlan.d.ts +27 -0
  95. package/dist/features/install/domain/InstallPlan.js +168 -0
  96. package/dist/features/install/domain/InstallResult.d.ts +23 -0
  97. package/dist/features/install/domain/InstallResult.js +1 -0
  98. package/dist/features/install/domain/InstallTarget.d.ts +6 -0
  99. package/dist/features/install/domain/InstallTarget.js +7 -0
  100. package/dist/features/install/domain/ManagedBlock.d.ts +3 -0
  101. package/dist/features/install/domain/ManagedBlock.js +20 -0
  102. package/dist/features/install/domain/RuleManifest.d.ts +17 -0
  103. package/dist/features/install/domain/RuleManifest.js +69 -0
  104. package/dist/features/install/domain/SettingsMerge.d.ts +5 -0
  105. package/dist/features/install/domain/SettingsMerge.js +43 -0
  106. package/dist/features/install/ports/inbound/InstallCommand.d.ts +10 -0
  107. package/dist/features/install/ports/inbound/InstallCommand.js +1 -0
  108. package/dist/features/install/ports/outbound/InstallSource.d.ts +4 -0
  109. package/dist/features/install/ports/outbound/InstallSource.js +1 -0
  110. package/dist/features/install/ports/outbound/InstallTargetFs.d.ts +6 -0
  111. package/dist/features/install/ports/outbound/InstallTargetFs.js +1 -0
  112. package/dist/features/lint/adapters/inbound/CliLintHandler.d.ts +8 -0
  113. package/dist/features/lint/adapters/inbound/CliLintHandler.js +61 -0
  114. package/dist/features/lint/adapters/outbound/NodeLintFileReader.d.ts +7 -0
  115. package/dist/features/lint/adapters/outbound/NodeLintFileReader.js +165 -0
  116. package/dist/features/lint/application/RunLint.d.ts +10 -0
  117. package/dist/features/lint/application/RunLint.js +100 -0
  118. package/dist/features/lint/domain/Diagnostic.d.ts +1 -0
  119. package/dist/features/lint/domain/Diagnostic.js +2 -0
  120. package/dist/features/lint/domain/Record.d.ts +1 -0
  121. package/dist/features/lint/domain/Record.js +5 -0
  122. package/dist/features/lint/domain/Rules.d.ts +1 -0
  123. package/dist/features/lint/domain/Rules.js +2 -0
  124. package/dist/features/lint/domain/SpecParser.d.ts +1 -0
  125. package/dist/features/lint/domain/SpecParser.js +2 -0
  126. package/dist/features/lint/ports/inbound/LintCommand.d.ts +4 -0
  127. package/dist/features/lint/ports/inbound/LintCommand.js +1 -0
  128. package/dist/features/lint/ports/outbound/LintConfigPort.d.ts +4 -0
  129. package/dist/features/lint/ports/outbound/LintConfigPort.js +1 -0
  130. package/dist/features/lint/ports/outbound/LintFileReader.d.ts +10 -0
  131. package/dist/features/lint/ports/outbound/LintFileReader.js +1 -0
  132. package/dist/features/plan/adapters/inbound/CliPlanShowHandler.d.ts +8 -0
  133. package/dist/features/plan/adapters/inbound/CliPlanShowHandler.js +73 -0
  134. package/dist/features/plan/adapters/outbound/NodePlanReader.d.ts +7 -0
  135. package/dist/features/plan/adapters/outbound/NodePlanReader.js +68 -0
  136. package/dist/features/plan/application/ShowPlan.d.ts +7 -0
  137. package/dist/features/plan/application/ShowPlan.js +4 -0
  138. package/dist/features/plan/ports/inbound/PlanShowCommand.d.ts +7 -0
  139. package/dist/features/plan/ports/inbound/PlanShowCommand.js +1 -0
  140. package/dist/features/plan/ports/outbound/PlanConfigPort.d.ts +4 -0
  141. package/dist/features/plan/ports/outbound/PlanConfigPort.js +1 -0
  142. package/dist/features/plan/ports/outbound/PlanReader.d.ts +19 -0
  143. package/dist/features/plan/ports/outbound/PlanReader.js +1 -0
  144. package/dist/features/ready/adapters/inbound/CliReadyHandler.d.ts +8 -0
  145. package/dist/features/ready/adapters/inbound/CliReadyHandler.js +79 -0
  146. package/dist/features/ready/adapters/outbound/ChildProcessReadyGit.d.ts +9 -0
  147. package/dist/features/ready/adapters/outbound/ChildProcessReadyGit.js +113 -0
  148. package/dist/features/ready/adapters/outbound/NodeReadyFileSystem.d.ts +8 -0
  149. package/dist/features/ready/adapters/outbound/NodeReadyFileSystem.js +159 -0
  150. package/dist/features/ready/application/RunReady.d.ts +16 -0
  151. package/dist/features/ready/application/RunReady.js +572 -0
  152. package/dist/features/ready/domain/AggregatedRules.d.ts +16 -0
  153. package/dist/features/ready/domain/AggregatedRules.js +42 -0
  154. package/dist/features/ready/domain/MarkerParser.d.ts +17 -0
  155. package/dist/features/ready/domain/MarkerParser.js +108 -0
  156. package/dist/features/ready/domain/PartitionResolver.d.ts +1 -0
  157. package/dist/features/ready/domain/PartitionResolver.js +5 -0
  158. package/dist/features/ready/domain/ReadyInput.d.ts +6 -0
  159. package/dist/features/ready/domain/ReadyInput.js +1 -0
  160. package/dist/features/ready/domain/ReadyViolation.d.ts +38 -0
  161. package/dist/features/ready/domain/ReadyViolation.js +19 -0
  162. package/dist/features/ready/domain/Rules.d.ts +22 -0
  163. package/dist/features/ready/domain/Rules.js +243 -0
  164. package/dist/features/ready/domain/SpecDiff.d.ts +33 -0
  165. package/dist/features/ready/domain/SpecDiff.js +321 -0
  166. package/dist/features/ready/ports/inbound/ReadyCommand.d.ts +4 -0
  167. package/dist/features/ready/ports/inbound/ReadyCommand.js +1 -0
  168. package/dist/features/ready/ports/outbound/ReadyConfigPort.d.ts +4 -0
  169. package/dist/features/ready/ports/outbound/ReadyConfigPort.js +1 -0
  170. package/dist/features/ready/ports/outbound/ReadyFileReader.d.ts +12 -0
  171. package/dist/features/ready/ports/outbound/ReadyFileReader.js +1 -0
  172. package/dist/features/ready/ports/outbound/ReadyGitPort.d.ts +10 -0
  173. package/dist/features/ready/ports/outbound/ReadyGitPort.js +5 -0
  174. package/dist/features/record/adapters/inbound/CliRecordHandler.d.ts +10 -0
  175. package/dist/features/record/adapters/inbound/CliRecordHandler.js +111 -0
  176. package/dist/features/record/adapters/outbound/NodeRecordFileSystem.d.ts +9 -0
  177. package/dist/features/record/adapters/outbound/NodeRecordFileSystem.js +152 -0
  178. package/dist/features/record/application/AddRecord.d.ts +11 -0
  179. package/dist/features/record/application/AddRecord.js +84 -0
  180. package/dist/features/record/application/GetRecord.d.ts +8 -0
  181. package/dist/features/record/application/GetRecord.js +22 -0
  182. package/dist/features/record/application/ListRecords.d.ts +9 -0
  183. package/dist/features/record/application/ListRecords.js +24 -0
  184. package/dist/features/record/application/SetRecord.d.ts +11 -0
  185. package/dist/features/record/application/SetRecord.js +68 -0
  186. package/dist/features/record/domain/RecordBody.d.ts +12 -0
  187. package/dist/features/record/domain/RecordBody.js +66 -0
  188. package/dist/features/record/domain/RecordPartition.d.ts +1 -0
  189. package/dist/features/record/domain/RecordPartition.js +7 -0
  190. package/dist/features/record/domain/RecordSlice.d.ts +7 -0
  191. package/dist/features/record/domain/RecordSlice.js +1 -0
  192. package/dist/features/record/domain/RecordSummary.d.ts +11 -0
  193. package/dist/features/record/domain/RecordSummary.js +13 -0
  194. package/dist/features/record/domain/RecordWrite.d.ts +14 -0
  195. package/dist/features/record/domain/RecordWrite.js +8 -0
  196. package/dist/features/record/ports/inbound/RecordCommand.d.ts +19 -0
  197. package/dist/features/record/ports/inbound/RecordCommand.js +1 -0
  198. package/dist/features/record/ports/outbound/RecordConfigPort.d.ts +4 -0
  199. package/dist/features/record/ports/outbound/RecordConfigPort.js +1 -0
  200. package/dist/features/record/ports/outbound/RecordFileReader.d.ts +10 -0
  201. package/dist/features/record/ports/outbound/RecordFileReader.js +1 -0
  202. package/dist/features/record/ports/outbound/RecordFileWriter.d.ts +6 -0
  203. package/dist/features/record/ports/outbound/RecordFileWriter.js +1 -0
  204. package/dist/features/refresh/adapters/inbound/CliRefreshHandler.d.ts +8 -0
  205. package/dist/features/refresh/adapters/inbound/CliRefreshHandler.js +24 -0
  206. package/dist/features/refresh/adapters/outbound/ChildProcessRefreshGit.d.ts +8 -0
  207. package/dist/features/refresh/adapters/outbound/ChildProcessRefreshGit.js +118 -0
  208. package/dist/features/refresh/adapters/outbound/NodeRefreshFileReader.d.ts +7 -0
  209. package/dist/features/refresh/adapters/outbound/NodeRefreshFileReader.js +44 -0
  210. package/dist/features/refresh/adapters/outbound/SystemRefreshClock.d.ts +4 -0
  211. package/dist/features/refresh/adapters/outbound/SystemRefreshClock.js +5 -0
  212. package/dist/features/refresh/application/BuildRefreshStubs.d.ts +25 -0
  213. package/dist/features/refresh/application/BuildRefreshStubs.js +43 -0
  214. package/dist/features/refresh/domain/DiffStubs.d.ts +24 -0
  215. package/dist/features/refresh/domain/DiffStubs.js +81 -0
  216. package/dist/features/refresh/domain/Footprint.d.ts +14 -0
  217. package/dist/features/refresh/domain/Footprint.js +45 -0
  218. package/dist/features/refresh/ports/inbound/RefreshCommand.d.ts +4 -0
  219. package/dist/features/refresh/ports/inbound/RefreshCommand.js +1 -0
  220. package/dist/features/refresh/ports/outbound/RefreshClockPort.d.ts +3 -0
  221. package/dist/features/refresh/ports/outbound/RefreshClockPort.js +1 -0
  222. package/dist/features/refresh/ports/outbound/RefreshConfigPort.d.ts +4 -0
  223. package/dist/features/refresh/ports/outbound/RefreshConfigPort.js +1 -0
  224. package/dist/features/refresh/ports/outbound/RefreshGitPort.d.ts +7 -0
  225. package/dist/features/refresh/ports/outbound/RefreshGitPort.js +1 -0
  226. package/dist/features/refresh/ports/outbound/RefreshSpecPort.d.ts +9 -0
  227. package/dist/features/refresh/ports/outbound/RefreshSpecPort.js +1 -0
  228. package/dist/features/report/adapters/inbound/CliReportHandler.d.ts +8 -0
  229. package/dist/features/report/adapters/inbound/CliReportHandler.js +35 -0
  230. package/dist/features/report/adapters/outbound/NodeReportFileSystem.d.ts +7 -0
  231. package/dist/features/report/adapters/outbound/NodeReportFileSystem.js +128 -0
  232. package/dist/features/report/application/RunReport.d.ts +19 -0
  233. package/dist/features/report/application/RunReport.js +161 -0
  234. package/dist/features/report/ports/inbound/ReportCommand.d.ts +8 -0
  235. package/dist/features/report/ports/inbound/ReportCommand.js +1 -0
  236. package/dist/features/report/ports/outbound/ReportConfigPort.d.ts +4 -0
  237. package/dist/features/report/ports/outbound/ReportConfigPort.js +1 -0
  238. package/dist/features/report/ports/outbound/ReportFileReader.d.ts +7 -0
  239. package/dist/features/report/ports/outbound/ReportFileReader.js +1 -0
  240. package/dist/features/token/adapters/inbound/CliTokenHandler.d.ts +8 -0
  241. package/dist/features/token/adapters/inbound/CliTokenHandler.js +53 -0
  242. package/dist/features/token/adapters/outbound/ChildProcessTokenGit.d.ts +8 -0
  243. package/dist/features/token/adapters/outbound/ChildProcessTokenGit.js +112 -0
  244. package/dist/features/token/adapters/outbound/NodeTokenConfigReader.d.ts +5 -0
  245. package/dist/features/token/adapters/outbound/NodeTokenConfigReader.js +41 -0
  246. package/dist/features/token/application/ComputeToken.d.ts +18 -0
  247. package/dist/features/token/application/ComputeToken.js +27 -0
  248. package/dist/features/token/ports/inbound/TokenCommand.d.ts +4 -0
  249. package/dist/features/token/ports/inbound/TokenCommand.js +1 -0
  250. package/dist/features/token/ports/outbound/TokenConfigPort.d.ts +4 -0
  251. package/dist/features/token/ports/outbound/TokenConfigPort.js +1 -0
  252. package/dist/features/token/ports/outbound/TokenGitPort.d.ts +7 -0
  253. package/dist/features/token/ports/outbound/TokenGitPort.js +1 -0
  254. package/dist/shared/domain/AgentBlocklist.d.ts +5 -0
  255. package/dist/shared/domain/AgentBlocklist.js +28 -0
  256. package/dist/shared/domain/BoundaryReachability.d.ts +5 -0
  257. package/dist/shared/domain/BoundaryReachability.js +71 -0
  258. package/dist/shared/domain/CheckOutcome.d.ts +10 -0
  259. package/dist/shared/domain/CheckOutcome.js +7 -0
  260. package/dist/shared/domain/CliOutput.d.ts +10 -0
  261. package/dist/shared/domain/CliOutput.js +29 -0
  262. package/dist/shared/domain/Config.d.ts +29 -0
  263. package/dist/shared/domain/Config.js +201 -0
  264. package/dist/shared/domain/DiagnosticRegistry.d.ts +8 -0
  265. package/dist/shared/domain/DiagnosticRegistry.js +71 -0
  266. package/dist/shared/domain/Errors.d.ts +12 -0
  267. package/dist/shared/domain/Errors.js +23 -0
  268. package/dist/shared/domain/GlobMatch.d.ts +2 -0
  269. package/dist/shared/domain/GlobMatch.js +58 -0
  270. package/dist/shared/domain/LintReport.d.ts +16 -0
  271. package/dist/shared/domain/LintReport.js +11 -0
  272. package/dist/shared/domain/LintRules.d.ts +67 -0
  273. package/dist/shared/domain/LintRules.js +956 -0
  274. package/dist/shared/domain/PartitionGrammar.d.ts +4 -0
  275. package/dist/shared/domain/PartitionGrammar.js +16 -0
  276. package/dist/shared/domain/PlanFile.d.ts +28 -0
  277. package/dist/shared/domain/PlanFile.js +112 -0
  278. package/dist/shared/domain/Scope.d.ts +1 -0
  279. package/dist/shared/domain/Scope.js +3 -0
  280. package/dist/shared/domain/SpecApprovalRewrite.d.ts +23 -0
  281. package/dist/shared/domain/SpecApprovalRewrite.js +254 -0
  282. package/dist/shared/domain/SpecBlocks.d.ts +12 -0
  283. package/dist/shared/domain/SpecBlocks.js +96 -0
  284. package/dist/shared/domain/SpecRecord.d.ts +17 -0
  285. package/dist/shared/domain/SpecRecord.js +208 -0
  286. package/dist/shared/domain/TemplateFieldMetadata.d.ts +2 -0
  287. package/dist/shared/domain/TemplateFieldMetadata.js +177 -0
  288. package/dist/shared/domain/Token.d.ts +2 -0
  289. package/dist/shared/domain/Token.js +5 -0
  290. package/dist/shared/domain/WeaselWords.d.ts +3 -0
  291. package/dist/shared/domain/WeaselWords.js +32 -0
  292. package/package.json +71 -0
  293. package/rules/enforcement_registry.md +126 -0
  294. package/rules/hooks/sdd-lint-reminder.sh +33 -0
  295. package/rules/hooks/sdd-spec-read-guard.sh +73 -0
  296. package/rules/manifest.json +15 -0
  297. package/rules/review-sdd.md +9 -0
  298. package/rules/sdd-cli-usage.md +91 -0
  299. package/rules/skills/spec-driven-development/SKILL.md +554 -0
  300. package/rules/skills/spec-driven-development/data/weasel-words.json +22 -0
  301. package/rules/spec-driven-development.md +69 -0
  302. package/rules/tdd-sdd.md +127 -0
  303. package/rules/workflow-sdd.md +56 -0
  304. package/schema/sdd.config.schema.json +104 -0
@@ -0,0 +1,168 @@
1
+ import { upsertManagedBlock } from "./ManagedBlock.js";
2
+ import { mergeHooks } from "./SettingsMerge.js";
3
+ export function installLayout(scope) {
4
+ if (scope === "project") {
5
+ return {
6
+ claudeMemoryRel: "CLAUDE.md",
7
+ codexMemoryRel: "AGENTS.md",
8
+ claudeImportPrefix: "@.claude/sdd/",
9
+ codexRulePrefix: ".codex/sdd/",
10
+ hookCommand: (_home, source) => `$CLAUDE_PROJECT_DIR/.claude/sdd/${source}`,
11
+ };
12
+ }
13
+ return {
14
+ claudeMemoryRel: ".claude/CLAUDE.md",
15
+ codexMemoryRel: ".codex/AGENTS.md",
16
+ claudeImportPrefix: "@sdd/",
17
+ codexRulePrefix: "~/.codex/sdd/",
18
+ hookCommand: (home, source) => homePath(home, `.claude/sdd/${source}`),
19
+ };
20
+ }
21
+ export function buildPlan(manifest, agent, sources, existing, home, scope = "user") {
22
+ const layout = installLayout(scope);
23
+ return agent === "claude"
24
+ ? planClaude(manifest, sources, existing, home, layout)
25
+ : planCodex(manifest, sources, existing, home, layout);
26
+ }
27
+ function planClaude(manifest, sources, existing, home, layout) {
28
+ const writes = [];
29
+ const actions = [];
30
+ const contextSources = [];
31
+ const desiredHooks = [];
32
+ for (const artifact of artifactsFor(manifest, "claude")) {
33
+ const relPath = artifact.kind === "skill"
34
+ ? `.claude/skills/${skillName(artifact)}/SKILL.md`
35
+ : `.claude/sdd/${artifact.source}`;
36
+ writes.push({
37
+ absPath: homePath(home, relPath),
38
+ content: content(sources, artifact.source),
39
+ executable: artifact.kind === "hook",
40
+ });
41
+ actions.push({
42
+ target: "claude",
43
+ kind: artifact.kind,
44
+ op: "copy",
45
+ path: relPath,
46
+ note: null,
47
+ });
48
+ if (artifact.kind === "context") {
49
+ contextSources.push(artifact.source);
50
+ }
51
+ if (artifact.kind === "hook" && artifact.event !== undefined) {
52
+ const event = artifact.event;
53
+ const command = layout.hookCommand(home, artifact.source);
54
+ desiredHooks.push({ matcher: event, command });
55
+ actions.push({
56
+ target: "claude",
57
+ kind: "hook",
58
+ op: "merge_hook",
59
+ path: ".claude/settings.json",
60
+ note: event,
61
+ });
62
+ }
63
+ }
64
+ const claudeMdRel = layout.claudeMemoryRel;
65
+ writes.push({
66
+ absPath: homePath(home, claudeMdRel),
67
+ content: upsertManagedBlock(existing.claudeMd, claudeImportBody(contextSources, layout.claudeImportPrefix)),
68
+ executable: false,
69
+ });
70
+ actions.push({
71
+ target: "claude",
72
+ kind: "managed_block",
73
+ op: "write_block",
74
+ path: claudeMdRel,
75
+ note: null,
76
+ });
77
+ if (desiredHooks.length > 0) {
78
+ writes.push({
79
+ absPath: homePath(home, ".claude/settings.json"),
80
+ content: mergeHooks(existing.settingsJson, desiredHooks),
81
+ executable: false,
82
+ });
83
+ }
84
+ return { writes, actions };
85
+ }
86
+ function planCodex(manifest, sources, existing, home, layout) {
87
+ const writes = [];
88
+ const actions = [];
89
+ const contextSources = [];
90
+ for (const artifact of artifactsFor(manifest, "codex")) {
91
+ const relPath = `.codex/sdd/${artifact.source}`;
92
+ writes.push({
93
+ absPath: homePath(home, relPath),
94
+ content: content(sources, artifact.source),
95
+ executable: false,
96
+ });
97
+ actions.push({
98
+ target: "codex",
99
+ kind: artifact.kind,
100
+ op: "copy",
101
+ path: relPath,
102
+ note: null,
103
+ });
104
+ if (artifact.kind === "context") {
105
+ contextSources.push(artifact.source);
106
+ }
107
+ }
108
+ for (const artifact of manifest.artifacts) {
109
+ if (artifact.kind === "hook" && !artifact.targets.includes("codex")) {
110
+ actions.push({
111
+ target: "codex",
112
+ kind: "hook",
113
+ op: "skip",
114
+ path: artifact.source,
115
+ note: "codex has no PreToolUse host",
116
+ });
117
+ }
118
+ }
119
+ const agentsMdRel = layout.codexMemoryRel;
120
+ writes.push({
121
+ absPath: homePath(home, agentsMdRel),
122
+ content: upsertManagedBlock(existing.agentsMd, codexReferenceBody(contextSources, layout.codexRulePrefix)),
123
+ executable: false,
124
+ });
125
+ actions.push({
126
+ target: "codex",
127
+ kind: "managed_block",
128
+ op: "write_block",
129
+ path: agentsMdRel,
130
+ note: null,
131
+ });
132
+ return { writes, actions };
133
+ }
134
+ function artifactsFor(manifest, agent) {
135
+ return manifest.artifacts.filter((a) => a.targets.includes(agent));
136
+ }
137
+ function content(sources, source) {
138
+ const value = sources.get(source);
139
+ if (value === undefined) {
140
+ throw new Error(`missing source content for ${source}`);
141
+ }
142
+ return value;
143
+ }
144
+ function claudeImportBody(contextSources, prefix) {
145
+ const imports = contextSources.map((s) => `${prefix}${s}`).join("\n");
146
+ return `SDD methodology rules (installed by \`sdd install\`). Loaded into context every session:\n\n${imports}`;
147
+ }
148
+ function codexReferenceBody(contextSources, prefix) {
149
+ const bullets = contextSources.map((s) => `- ${prefix}${s}`).join("\n");
150
+ return [
151
+ `SDD methodology rules installed by \`sdd install\` at ${prefix}.`,
152
+ "Read these before working in a project that carries .sdd/config.json:",
153
+ "",
154
+ bullets,
155
+ "",
156
+ `On-demand reference (read when needed): ${prefix}skills/spec-driven-development/SKILL.md, ${prefix}enforcement_registry.md`,
157
+ ].join("\n");
158
+ }
159
+ function skillName(artifact) {
160
+ if (artifact.skillName !== undefined) {
161
+ return artifact.skillName;
162
+ }
163
+ const segments = artifact.source.split("/");
164
+ return segments.length >= 2 ? segments[segments.length - 2] : segments[0];
165
+ }
166
+ export function homePath(home, relPath) {
167
+ return `${home.replace(/\/+$/, "")}/${relPath}`;
168
+ }
@@ -0,0 +1,23 @@
1
+ import type { AgentTarget, InstallScope } from "./InstallTarget.js";
2
+ export type ActionKind = "context" | "skill" | "reference" | "data" | "hook" | "managed_block";
3
+ export type InstallOp = "copy" | "write_block" | "merge_hook" | "skip";
4
+ export interface InstallAction {
5
+ target: AgentTarget;
6
+ kind: ActionKind;
7
+ op: InstallOp;
8
+ path: string;
9
+ note: string | null;
10
+ }
11
+ export type InstallFailureReason = "manifest-missing" | "manifest-invalid" | "artifact-missing";
12
+ export type InstallOutcome = {
13
+ ok: true;
14
+ dryRun: boolean;
15
+ scope: InstallScope;
16
+ targets: AgentTarget[];
17
+ actions: InstallAction[];
18
+ } | {
19
+ ok: false;
20
+ exitCode: 1;
21
+ reason: InstallFailureReason;
22
+ message: string;
23
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export type AgentTarget = "claude" | "codex";
2
+ export type InstallTarget = AgentTarget | "all";
3
+ export type InstallScope = "user" | "project";
4
+ export declare const AGENT_TARGETS: readonly AgentTarget[];
5
+ export declare function isInstallTarget(value: string): value is InstallTarget;
6
+ export declare function agentsFor(target: InstallTarget): readonly AgentTarget[];
@@ -0,0 +1,7 @@
1
+ export const AGENT_TARGETS = ["claude", "codex"];
2
+ export function isInstallTarget(value) {
3
+ return value === "all" || value === "claude" || value === "codex";
4
+ }
5
+ export function agentsFor(target) {
6
+ return target === "all" ? AGENT_TARGETS : [target];
7
+ }
@@ -0,0 +1,3 @@
1
+ export declare const BLOCK_BEGIN = "<!-- BEGIN sdd-cli (managed by `sdd install`) -->";
2
+ export declare const BLOCK_END = "<!-- END sdd-cli -->";
3
+ export declare function upsertManagedBlock(existing: string | null, body: string): string;
@@ -0,0 +1,20 @@
1
+ export const BLOCK_BEGIN = "<!-- BEGIN sdd-cli (managed by `sdd install`) -->";
2
+ export const BLOCK_END = "<!-- END sdd-cli -->";
3
+ export function upsertManagedBlock(existing, body) {
4
+ const block = `${BLOCK_BEGIN}\n${body}\n${BLOCK_END}`;
5
+ const current = existing ?? "";
6
+ const beginAt = current.indexOf(BLOCK_BEGIN);
7
+ const endAt = current.indexOf(BLOCK_END, beginAt + BLOCK_BEGIN.length);
8
+ if (beginAt !== -1 && endAt !== -1) {
9
+ const before = current.slice(0, beginAt);
10
+ const after = current.slice(endAt + BLOCK_END.length);
11
+ return ensureTrailingLf(`${before}${block}${after}`);
12
+ }
13
+ if (current.trim().length === 0) {
14
+ return `${block}\n`;
15
+ }
16
+ return `${current.replace(/\n+$/, "")}\n\n${block}\n`;
17
+ }
18
+ function ensureTrailingLf(value) {
19
+ return value.endsWith("\n") ? value : `${value}\n`;
20
+ }
@@ -0,0 +1,17 @@
1
+ import type { AgentTarget } from "./InstallTarget.js";
2
+ export type ArtifactKind = "context" | "skill" | "reference" | "data" | "hook";
3
+ export interface ManifestArtifact {
4
+ source: string;
5
+ kind: ArtifactKind;
6
+ targets: readonly AgentTarget[];
7
+ event?: string;
8
+ skillName?: string;
9
+ }
10
+ export interface RuleManifest {
11
+ formatVersion: 1;
12
+ artifacts: readonly ManifestArtifact[];
13
+ }
14
+ export declare class ManifestError extends Error {
15
+ constructor(message: string);
16
+ }
17
+ export declare function parseManifest(text: string): RuleManifest;
@@ -0,0 +1,69 @@
1
+ const ARTIFACT_KINDS = [
2
+ "context",
3
+ "skill",
4
+ "reference",
5
+ "data",
6
+ "hook",
7
+ ];
8
+ export class ManifestError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "ManifestError";
12
+ }
13
+ }
14
+ export function parseManifest(text) {
15
+ let raw;
16
+ try {
17
+ raw = JSON.parse(text);
18
+ }
19
+ catch (error) {
20
+ throw new ManifestError(`manifest is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
21
+ }
22
+ if (!isObject(raw)) {
23
+ throw new ManifestError("manifest must be a JSON object");
24
+ }
25
+ if (raw.format_version !== 1) {
26
+ throw new ManifestError("manifest format_version must be 1");
27
+ }
28
+ if (!Array.isArray(raw.artifacts)) {
29
+ throw new ManifestError("manifest artifacts must be an array");
30
+ }
31
+ const artifacts = raw.artifacts.map((entry, index) => parseArtifact(entry, index));
32
+ return { formatVersion: 1, artifacts };
33
+ }
34
+ function parseArtifact(entry, index) {
35
+ if (!isObject(entry)) {
36
+ throw new ManifestError(`artifact #${index} must be an object`);
37
+ }
38
+ const { source, kind, targets, event, skill_name: skillName } = entry;
39
+ if (typeof source !== "string" || source.length === 0) {
40
+ throw new ManifestError(`artifact #${index} has a missing or empty source`);
41
+ }
42
+ if (typeof kind !== "string" || !isArtifactKind(kind)) {
43
+ throw new ManifestError(`artifact ${source} has an unknown kind: ${String(kind)}`);
44
+ }
45
+ if (!Array.isArray(targets) ||
46
+ targets.length === 0 ||
47
+ !targets.every(isAgentTarget)) {
48
+ throw new ManifestError(`artifact ${source} must declare a non-empty targets array of claude|codex`);
49
+ }
50
+ if (kind === "hook" && (typeof event !== "string" || event.length === 0)) {
51
+ throw new ManifestError(`hook artifact ${source} must declare an event matcher`);
52
+ }
53
+ return {
54
+ source,
55
+ kind,
56
+ targets: targets,
57
+ event: typeof event === "string" ? event : undefined,
58
+ skillName: typeof skillName === "string" ? skillName : undefined,
59
+ };
60
+ }
61
+ function isArtifactKind(value) {
62
+ return ARTIFACT_KINDS.includes(value);
63
+ }
64
+ function isAgentTarget(value) {
65
+ return value === "claude" || value === "codex";
66
+ }
67
+ function isObject(value) {
68
+ return typeof value === "object" && value !== null && !Array.isArray(value);
69
+ }
@@ -0,0 +1,5 @@
1
+ export interface DesiredHook {
2
+ matcher: string;
3
+ command: string;
4
+ }
5
+ export declare function mergeHooks(existingText: string | null, desired: readonly DesiredHook[]): string;
@@ -0,0 +1,43 @@
1
+ export function mergeHooks(existingText, desired) {
2
+ const settings = parseSettings(existingText);
3
+ const hooks = asObject(settings.hooks);
4
+ settings.hooks = hooks;
5
+ const preToolUse = asHookEntries(hooks.PreToolUse);
6
+ hooks.PreToolUse = preToolUse;
7
+ for (const want of desired) {
8
+ if (!hasHook(preToolUse, want)) {
9
+ preToolUse.push({
10
+ matcher: want.matcher,
11
+ hooks: [{ type: "command", command: want.command }],
12
+ });
13
+ }
14
+ }
15
+ return `${JSON.stringify(settings, null, 2)}\n`;
16
+ }
17
+ function hasHook(entries, want) {
18
+ return entries.some((entry) => entry.matcher === want.matcher &&
19
+ Array.isArray(entry.hooks) &&
20
+ entry.hooks.some((h) => h.command === want.command));
21
+ }
22
+ function parseSettings(text) {
23
+ if (text === null || text.trim().length === 0) {
24
+ return {};
25
+ }
26
+ const parsed = JSON.parse(text);
27
+ if (!isRecord(parsed)) {
28
+ throw new Error("settings.json must contain a JSON object");
29
+ }
30
+ return parsed;
31
+ }
32
+ function asObject(value) {
33
+ return isRecord(value) ? value : {};
34
+ }
35
+ function asHookEntries(value) {
36
+ return isHookEntryArray(value) ? value : [];
37
+ }
38
+ function isHookEntryArray(value) {
39
+ return Array.isArray(value);
40
+ }
41
+ function isRecord(value) {
42
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43
+ }
@@ -0,0 +1,10 @@
1
+ import type { CommandResult } from "../../../../shared/domain/CliOutput.js";
2
+ import type { InstallScope, InstallTarget } from "../../domain/InstallTarget.js";
3
+ export type { InstallScope, InstallTarget };
4
+ export interface InstallOptions {
5
+ dryRun: boolean;
6
+ scope: InstallScope;
7
+ }
8
+ export interface InstallCommand {
9
+ execute(target: InstallTarget, options: InstallOptions, format: "json" | "human"): Promise<CommandResult>;
10
+ }
@@ -0,0 +1,4 @@
1
+ export interface InstallSource {
2
+ manifestText(): Promise<string | null>;
3
+ readArtifact(source: string): Promise<string | null>;
4
+ }
@@ -0,0 +1,6 @@
1
+ export interface InstallTargetFs {
2
+ homeRoot(): string;
3
+ projectRoot(): string;
4
+ readText(absPath: string): Promise<string | null>;
5
+ writeText(absPath: string, content: string, executable: boolean): Promise<void>;
6
+ }
@@ -0,0 +1,8 @@
1
+ import { type CommandResult, type OutputFormat } from "../../../../shared/domain/CliOutput.js";
2
+ import { type RunLintPorts } from "../../application/RunLint.js";
3
+ import type { LintCommand } from "../../ports/inbound/LintCommand.js";
4
+ export declare class CliLintHandler implements LintCommand {
5
+ private readonly ports;
6
+ constructor(ports: RunLintPorts);
7
+ execute(cwd: string, format: Exclude<OutputFormat, "yaml">): Promise<CommandResult>;
8
+ }
@@ -0,0 +1,61 @@
1
+ import { failed, ok, } from "../../../../shared/domain/CliOutput.js";
2
+ import { CliFailure } from "../../../../shared/domain/Errors.js";
3
+ import { runLint, } from "../../application/RunLint.js";
4
+ export class CliLintHandler {
5
+ ports;
6
+ constructor(ports) {
7
+ this.ports = ports;
8
+ }
9
+ async execute(cwd, format) {
10
+ try {
11
+ const report = await runLint(cwd, this.ports);
12
+ if (format === "json") {
13
+ return jsonResult(report);
14
+ }
15
+ return humanResult(report);
16
+ }
17
+ catch (error) {
18
+ if (error instanceof CliFailure) {
19
+ return failed(error, format);
20
+ }
21
+ throw error;
22
+ }
23
+ }
24
+ }
25
+ function jsonResult(report) {
26
+ const body = JSON.stringify({
27
+ format_version: 1,
28
+ ok: report.errorCount === 0,
29
+ error_count: report.errorCount,
30
+ warn_count: report.warnCount,
31
+ diagnostics: report.diagnostics.map((d) => ({
32
+ severity: d.severity,
33
+ rule: d.rule,
34
+ file: d.file,
35
+ line: d.line ?? null,
36
+ message: d.message,
37
+ })),
38
+ });
39
+ if (report.errorCount === 0) {
40
+ return ok(body);
41
+ }
42
+ return { exitCode: 1, stdout: `${body}\n`, stderr: "" };
43
+ }
44
+ function humanResult(report) {
45
+ const lines = [];
46
+ for (const d of report.diagnostics) {
47
+ lines.push(formatDiagnostic(d));
48
+ }
49
+ lines.push("");
50
+ lines.push(`spec-lint: ${report.errorCount} error(s), ${report.warnCount} warning(s).`);
51
+ const stdout = `${lines.join("\n")}\n`;
52
+ if (report.errorCount === 0) {
53
+ return { exitCode: 0, stdout, stderr: "" };
54
+ }
55
+ return { exitCode: 1, stdout, stderr: "" };
56
+ }
57
+ function formatDiagnostic(d) {
58
+ const where = d.line !== undefined ? `${d.file}:${d.line}` : d.file;
59
+ const tag = d.severity === "error" ? "ERROR" : "warn";
60
+ return `[${tag}] ${where} ${d.rule}: ${d.message}`;
61
+ }
@@ -0,0 +1,7 @@
1
+ import { type SddConfig } from "../../../../shared/domain/Config.js";
2
+ import type { LintConfigPort } from "../../ports/outbound/LintConfigPort.js";
3
+ import type { LintFileReader, SpecFileEntry } from "../../ports/outbound/LintFileReader.js";
4
+ export declare class NodeLintFileReader implements LintConfigPort, LintFileReader {
5
+ config(repoRoot: string): Promise<SddConfig>;
6
+ resolveSpecFiles(repoRoot: string, patterns: readonly string[]): Promise<SpecFileEntry[]>;
7
+ }
@@ -0,0 +1,165 @@
1
+ import { readFile, readdir, stat } from "node:fs/promises";
2
+ import { join, relative, resolve } from "node:path";
3
+ import { configFromJson, } from "../../../../shared/domain/Config.js";
4
+ import { configFailure } from "../../../../shared/domain/Errors.js";
5
+ export class NodeLintFileReader {
6
+ async config(repoRoot) {
7
+ const configPath = join(repoRoot, ".sdd", "config.json");
8
+ const text = await readConfig(configPath);
9
+ return configFromJson(parseConfigJson(text, configPath), configPath);
10
+ }
11
+ async resolveSpecFiles(repoRoot, patterns) {
12
+ const matched = new Set();
13
+ for (const pattern of patterns) {
14
+ for (const abs of await expandGlob(repoRoot, pattern)) {
15
+ matched.add(abs);
16
+ }
17
+ }
18
+ const list = [...matched].sort();
19
+ const out = [];
20
+ for (const abs of list) {
21
+ const text = await readFile(abs, "utf8");
22
+ const rel = relative(repoRoot, abs);
23
+ out.push({ path: rel.split("\\").join("/"), content: text });
24
+ }
25
+ return out;
26
+ }
27
+ }
28
+ /*
29
+ * CST-006
30
+ * Minimal glob expander, no third-party glob library: keeps the runtime
31
+ * dependency surface to yaml only.
32
+ */
33
+ async function expandGlob(repoRoot, pattern) {
34
+ const normalised = pattern.split("\\").join("/");
35
+ if (!hasGlob(normalised)) {
36
+ const abs = resolve(repoRoot, normalised);
37
+ return (await isFile(abs)) ? [abs] : [];
38
+ }
39
+ const segments = normalised.split("/");
40
+ const literalSegments = [];
41
+ let firstGlobIndex = -1;
42
+ for (let i = 0; i < segments.length; i++) {
43
+ if (hasGlob(segments[i])) {
44
+ firstGlobIndex = i;
45
+ break;
46
+ }
47
+ literalSegments.push(segments[i]);
48
+ }
49
+ const baseDir = resolve(repoRoot, ...literalSegments);
50
+ const remaining = segments.slice(firstGlobIndex);
51
+ const out = [];
52
+ await walkAndMatch(baseDir, remaining, out);
53
+ return out;
54
+ }
55
+ async function walkAndMatch(dir, remaining, acc) {
56
+ if (remaining.length === 0) {
57
+ return;
58
+ }
59
+ const head = remaining[0];
60
+ const rest = remaining.slice(1);
61
+ let entries;
62
+ try {
63
+ entries = await readdir(dir, { withFileTypes: true });
64
+ }
65
+ catch {
66
+ return;
67
+ }
68
+ if (head === "**") {
69
+ /*
70
+ * Match zero or more directory levels: keep `**` in the remaining set
71
+ * until a non-** segment matches.
72
+ */
73
+ if (rest.length === 0) {
74
+ /* `**` as the last segment matches every file under dir. */
75
+ for (const entry of entries) {
76
+ const abs = join(dir, entry.name);
77
+ if (entry.isDirectory()) {
78
+ await walkAndMatch(abs, ["**"], acc);
79
+ }
80
+ else if (entry.isFile()) {
81
+ acc.push(abs);
82
+ }
83
+ }
84
+ return;
85
+ }
86
+ /* Try to match without consuming a directory level (descend keeping **). */
87
+ for (const entry of entries) {
88
+ const abs = join(dir, entry.name);
89
+ if (entry.isDirectory()) {
90
+ await walkAndMatch(abs, remaining, acc);
91
+ }
92
+ }
93
+ /* Try to consume `**` here and match the next segment. */
94
+ await walkAndMatch(dir, rest, acc);
95
+ return;
96
+ }
97
+ for (const entry of entries) {
98
+ if (!matchSegment(head, entry.name)) {
99
+ continue;
100
+ }
101
+ const abs = join(dir, entry.name);
102
+ if (rest.length === 0) {
103
+ if (entry.isFile()) {
104
+ acc.push(abs);
105
+ }
106
+ continue;
107
+ }
108
+ if (entry.isDirectory()) {
109
+ await walkAndMatch(abs, rest, acc);
110
+ }
111
+ }
112
+ }
113
+ function matchSegment(pattern, name) {
114
+ if (!hasGlob(pattern)) {
115
+ return pattern === name;
116
+ }
117
+ /*
118
+ * Translate the segment pattern to a regex; supports `*` (any chars except /),
119
+ * `?` (single char), and literal characters.
120
+ */
121
+ const re = new RegExp(`^${pattern
122
+ .split("")
123
+ .map((c) => {
124
+ if (c === "*") {
125
+ return "[^/]*";
126
+ }
127
+ if (c === "?") {
128
+ return "[^/]";
129
+ }
130
+ return c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
131
+ })
132
+ .join("")}$`);
133
+ return re.test(name);
134
+ }
135
+ function hasGlob(value) {
136
+ return /[*?[\]]/.test(value);
137
+ }
138
+ async function isFile(abs) {
139
+ try {
140
+ const s = await stat(abs);
141
+ return s.isFile();
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
147
+ async function readConfig(path) {
148
+ try {
149
+ return await readFile(path, "utf8");
150
+ }
151
+ catch (error) {
152
+ throw configFailure("config-missing", ".sdd/config.json is missing or unreadable", errorMessage(error), path);
153
+ }
154
+ }
155
+ function parseConfigJson(text, path) {
156
+ try {
157
+ return JSON.parse(text);
158
+ }
159
+ catch (error) {
160
+ throw configFailure("config-invalid", ".sdd/config.json is not valid JSON", errorMessage(error), path);
161
+ }
162
+ }
163
+ function errorMessage(error) {
164
+ return error instanceof Error ? error.message : String(error);
165
+ }
@@ -0,0 +1,10 @@
1
+ import { type Diagnostic, type LintReport } from "../domain/Diagnostic.js";
2
+ export type { Diagnostic, LintReport };
3
+ import type { LintConfigPort } from "../ports/outbound/LintConfigPort.js";
4
+ import type { LintFileReader } from "../ports/outbound/LintFileReader.js";
5
+ export interface RunLintPorts {
6
+ config: LintConfigPort;
7
+ files: LintFileReader;
8
+ }
9
+ export declare function runLint(cwd: string, ports: RunLintPorts): Promise<LintReport>;
10
+ export declare function diagnosticsByFile(report: LintReport): Map<string, Diagnostic[]>;