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
package/dist/cli.js ADDED
@@ -0,0 +1,867 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, realpathSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import process from "node:process";
5
+ import { fileURLToPath } from "node:url";
6
+ import { CliApproveHandler } from "./features/approve/adapters/inbound/CliApproveHandler.js";
7
+ import { NodeApproveFileSystem } from "./features/approve/adapters/outbound/NodeApproveFileSystem.js";
8
+ import { NodePlanFileWriter } from "./features/approve/adapters/outbound/NodePlanFileWriter.js";
9
+ import { SystemApproveClock } from "./features/approve/adapters/outbound/SystemApproveClock.js";
10
+ import { CliCheckHandler } from "./features/check/adapters/inbound/CliCheckHandler.js";
11
+ import { CliDoctorHandler } from "./features/doctor/adapters/inbound/CliDoctorHandler.js";
12
+ import { NodeRegistryReader } from "./features/doctor/adapters/outbound/NodeRegistryReader.js";
13
+ import { CliFinalizeHandler } from "./features/finalize/adapters/inbound/CliFinalizeHandler.js";
14
+ import { NodeFinalizeFileSystem } from "./features/finalize/adapters/outbound/NodeFinalizeFileSystem.js";
15
+ import { NodePlanRepo } from "./features/finalize/adapters/outbound/NodePlanRepo.js";
16
+ import { SystemFinalizeClock } from "./features/finalize/adapters/outbound/SystemFinalizeClock.js";
17
+ import { CliPlanShowHandler } from "./features/plan/adapters/inbound/CliPlanShowHandler.js";
18
+ import { NodePlanReader } from "./features/plan/adapters/outbound/NodePlanReader.js";
19
+ import { CliReportHandler } from "./features/report/adapters/inbound/CliReportHandler.js";
20
+ import { NodeReportFileSystem } from "./features/report/adapters/outbound/NodeReportFileSystem.js";
21
+ import { ChildProcessCheckGit } from "./features/check/adapters/outbound/ChildProcessCheckGit.js";
22
+ import { NodeCheckFileReader } from "./features/check/adapters/outbound/NodeCheckFileReader.js";
23
+ import { CliLintHandler } from "./features/lint/adapters/inbound/CliLintHandler.js";
24
+ import { NodeLintFileReader } from "./features/lint/adapters/outbound/NodeLintFileReader.js";
25
+ import { CliReadyHandler } from "./features/ready/adapters/inbound/CliReadyHandler.js";
26
+ import { ChildProcessReadyGit } from "./features/ready/adapters/outbound/ChildProcessReadyGit.js";
27
+ import { NodeReadyFileSystem } from "./features/ready/adapters/outbound/NodeReadyFileSystem.js";
28
+ import { CliRefreshHandler } from "./features/refresh/adapters/inbound/CliRefreshHandler.js";
29
+ import { ChildProcessRefreshGit } from "./features/refresh/adapters/outbound/ChildProcessRefreshGit.js";
30
+ import { NodeRefreshFileReader } from "./features/refresh/adapters/outbound/NodeRefreshFileReader.js";
31
+ import { SystemRefreshClock } from "./features/refresh/adapters/outbound/SystemRefreshClock.js";
32
+ import { CliRecordHandler } from "./features/record/adapters/inbound/CliRecordHandler.js";
33
+ import { NodeRecordFileSystem } from "./features/record/adapters/outbound/NodeRecordFileSystem.js";
34
+ import { CliInstallHandler } from "./features/install/adapters/inbound/CliInstallHandler.js";
35
+ import { NodeInstallSource } from "./features/install/adapters/outbound/NodeInstallSource.js";
36
+ import { NodeInstallTargetFs } from "./features/install/adapters/outbound/NodeInstallTargetFs.js";
37
+ import { isInstallTarget, } from "./features/install/domain/InstallTarget.js";
38
+ import { CliTokenHandler } from "./features/token/adapters/inbound/CliTokenHandler.js";
39
+ import { ChildProcessTokenGit } from "./features/token/adapters/outbound/ChildProcessTokenGit.js";
40
+ import { NodeTokenConfigReader } from "./features/token/adapters/outbound/NodeTokenConfigReader.js";
41
+ const TOP_LEVEL_HELP = `sdd
42
+
43
+ Usage:
44
+ sdd token [--format=json|human]
45
+ sdd check [--format=json|human]
46
+ sdd refresh [--format=json|human|yaml]
47
+ sdd lint [--format=json|human]
48
+ sdd approve --id <id-or-glob> --approver <human-id>
49
+ --owner-role <role> --change-request <url>
50
+ [--scope <scope>] [--target-status approved|deprecated|removed]
51
+ [--reviewed-test-oracle <ref>]
52
+ [--inline | --plan <plan_id>] [--format=json|human]
53
+ sdd plan show [--plan <plan_id>] [--format=json|human]
54
+ sdd finalize [--plan <plan_id>] [--format=json|human]
55
+ sdd doctor --rule-version [--rules <path>] [--format=json|human]
56
+ sdd report --pr-summary [--against <ref>] [--format=json|human]
57
+ sdd ready [--format=json|human] [--partition <name>]
58
+ sdd record list [--partition <name>] [--format=json|human]
59
+ sdd record get <id> [--format=json|human]
60
+ sdd record set <id> (--from-file <p> | --content <s>) [--format=json|human]
61
+ sdd record add --after <id> (--from-file <p> | --content <s>) [--format=json|human]
62
+ sdd install <all|claude|codex> [--scope user|project] [--dry-run] [--format=json|human]
63
+ sdd --help
64
+ sdd --version`;
65
+ const COMMAND_HELP = {
66
+ token: "Usage: sdd token [--format=json|human]",
67
+ check: "Usage: sdd check [--format=json|human]",
68
+ refresh: "Usage: sdd refresh [--format=json|human|yaml]",
69
+ lint: "Usage: sdd lint [--format=json|human]",
70
+ approve: "Usage: sdd approve --id <id-or-glob> --approver <human-id> --owner-role <role> --change-request <url> [--scope <scope>] [--target-status approved|deprecated|removed] [--reviewed-test-oracle <ref>] [--inline | --plan <plan_id>] [--format=json|human]",
71
+ ready: "Usage: sdd ready [--format=json|human] [--partition <name>]",
72
+ finalize: "Usage: sdd finalize [--plan <plan_id>] [--format=json|human]",
73
+ plan: "Usage: sdd plan show [--plan <plan_id>] [--format=json|human]",
74
+ doctor: "Usage: sdd doctor --rule-version [--rules <path>] [--format=json|human]",
75
+ report: "Usage: sdd report --pr-summary [--against <ref>] [--format=json|human]",
76
+ record: "Usage: sdd record list [--partition <name>] | get <id> | set <id> (--from-file <p>|--content <s>) | add --after <id> (--from-file <p>|--content <s>) [--format=json|human]",
77
+ install: "Usage: sdd install <all|claude|codex> [--scope user|project] [--dry-run] [--format=json|human]",
78
+ };
79
+ export async function main(argv, cwd) {
80
+ const parsed = parseArgv(argv);
81
+ if (parsed.mode === "help") {
82
+ return {
83
+ exitCode: 0,
84
+ stdout: `${parsed.subcommand ? COMMAND_HELP[parsed.subcommand] : TOP_LEVEL_HELP}\n`,
85
+ stderr: "",
86
+ };
87
+ }
88
+ if (parsed.mode === "version") {
89
+ return { exitCode: 0, stdout: `${packageVersion()}\n`, stderr: "" };
90
+ }
91
+ if (parsed.mode === "error") {
92
+ return {
93
+ exitCode: 2,
94
+ stdout: "",
95
+ stderr: `${parsed.message ?? "invalid arguments"}\n${TOP_LEVEL_HELP}\n`,
96
+ };
97
+ }
98
+ if (parsed.subcommand === "token") {
99
+ return dispatchToken(cwd, parsed.format);
100
+ }
101
+ if (parsed.subcommand === "check") {
102
+ return dispatchCheck(cwd, parsed.format);
103
+ }
104
+ if (parsed.subcommand === "lint") {
105
+ return dispatchLint(cwd, parsed.format);
106
+ }
107
+ if (parsed.subcommand === "approve") {
108
+ return dispatchApprove(parsed, cwd);
109
+ }
110
+ if (parsed.subcommand === "finalize") {
111
+ return dispatchFinalize(parsed, cwd);
112
+ }
113
+ if (parsed.subcommand === "plan") {
114
+ return dispatchPlan(parsed, cwd);
115
+ }
116
+ if (parsed.subcommand === "doctor") {
117
+ return dispatchDoctor(parsed, cwd);
118
+ }
119
+ if (parsed.subcommand === "report") {
120
+ return dispatchReport(parsed, cwd);
121
+ }
122
+ if (parsed.subcommand === "record") {
123
+ return dispatchRecord(parsed, cwd);
124
+ }
125
+ if (parsed.subcommand === "install") {
126
+ return dispatchInstall(parsed);
127
+ }
128
+ if (parsed.subcommand === "ready") {
129
+ return dispatchReady(parsed, cwd);
130
+ }
131
+ return dispatchRefresh(parsed, cwd);
132
+ }
133
+ function dispatchToken(cwd, format) {
134
+ const command = new CliTokenHandler({
135
+ config: new NodeTokenConfigReader(),
136
+ git: new ChildProcessTokenGit(),
137
+ });
138
+ return command.execute(cwd, format === "json" ? "json" : "human");
139
+ }
140
+ function dispatchCheck(cwd, format) {
141
+ const files = new NodeCheckFileReader();
142
+ const command = new CliCheckHandler({
143
+ config: files,
144
+ git: new ChildProcessCheckGit(),
145
+ spec: files,
146
+ });
147
+ return command.execute(cwd, format === "json" ? "json" : "human");
148
+ }
149
+ function dispatchLint(cwd, format) {
150
+ const files = new NodeLintFileReader();
151
+ const command = new CliLintHandler({ config: files, files });
152
+ return command.execute(cwd, format === "json" ? "json" : "human");
153
+ }
154
+ function dispatchApprove(parsed, cwd) {
155
+ const approve = parsed.command?.approve;
156
+ const req = approveRequest(approve ?? {});
157
+ if (req.mode === "error") {
158
+ return Promise.resolve({
159
+ exitCode: 2,
160
+ stdout: "",
161
+ stderr: `${req.message}\n${COMMAND_HELP.approve}\n`,
162
+ });
163
+ }
164
+ const files = new NodeApproveFileSystem();
165
+ const plans = new NodePlanFileWriter();
166
+ const command = new CliApproveHandler({
167
+ clock: new SystemApproveClock(),
168
+ config: files,
169
+ files,
170
+ plans,
171
+ });
172
+ return command.execute(cwd, req.value, parsed.format === "json" ? "json" : "human", {
173
+ inline: approve?.inline === true,
174
+ planId: approve?.planId,
175
+ });
176
+ }
177
+ function dispatchFinalize(parsed, cwd) {
178
+ const finalizeFs = new NodeFinalizeFileSystem();
179
+ const command = new CliFinalizeHandler({
180
+ clock: new SystemFinalizeClock(),
181
+ config: finalizeFs,
182
+ files: finalizeFs,
183
+ plans: new NodePlanRepo(),
184
+ });
185
+ return command.execute(cwd, { planId: parsed.command?.finalize?.planId }, parsed.format === "json" ? "json" : "human");
186
+ }
187
+ function dispatchPlan(parsed, cwd) {
188
+ const plan = parsed.command?.plan;
189
+ if (plan?.subcommand !== "show") {
190
+ return Promise.resolve({
191
+ exitCode: 2,
192
+ stdout: "",
193
+ stderr: `${COMMAND_HELP.plan}\n`,
194
+ });
195
+ }
196
+ const reader = new NodePlanReader();
197
+ const command = new CliPlanShowHandler({ config: reader, reader });
198
+ return command.execute(cwd, { planId: plan.planId }, parsed.format === "json" ? "json" : "human");
199
+ }
200
+ function dispatchDoctor(parsed, cwd) {
201
+ const doctor = parsed.command?.doctor;
202
+ if (doctor === undefined) {
203
+ return Promise.resolve({
204
+ exitCode: 2,
205
+ stdout: "",
206
+ stderr: `${COMMAND_HELP.doctor}\n`,
207
+ });
208
+ }
209
+ const command = new CliDoctorHandler({
210
+ registry: new NodeRegistryReader(),
211
+ });
212
+ return command.execute(cwd, {
213
+ ruleVersion: doctor.ruleVersion,
214
+ rulesPath: doctor.rulesPath,
215
+ }, parsed.format === "json" ? "json" : "human");
216
+ }
217
+ function dispatchReport(parsed, cwd) {
218
+ const report = parsed.command?.report;
219
+ if (report === undefined) {
220
+ return Promise.resolve({
221
+ exitCode: 2,
222
+ stdout: "",
223
+ stderr: `${COMMAND_HELP.report}\n`,
224
+ });
225
+ }
226
+ const reportFs = new NodeReportFileSystem();
227
+ const git = new ChildProcessReadyGit();
228
+ const command = new CliReportHandler({
229
+ config: reportFs,
230
+ files: reportFs,
231
+ readAtRef: (root, ref, path) => git.readAtRef(root, ref, path),
232
+ repoRoot: (cwdInner) => git.repoRoot(cwdInner),
233
+ });
234
+ return command.execute(cwd, {
235
+ prSummary: report.prSummary,
236
+ against: report.against,
237
+ }, parsed.format === "json" ? "json" : "human");
238
+ }
239
+ function dispatchRecord(parsed, cwd) {
240
+ if (parsed.command?.record === undefined) {
241
+ return Promise.resolve({
242
+ exitCode: 2,
243
+ stdout: "",
244
+ stderr: `${COMMAND_HELP.record}\n`,
245
+ });
246
+ }
247
+ const record = parsed.command.record;
248
+ const fs = new NodeRecordFileSystem();
249
+ const command = new CliRecordHandler({ config: fs, files: fs, writer: fs });
250
+ const format = parsed.format === "json" ? "json" : "human";
251
+ const sub = record.subcommand;
252
+ if (sub === "list") {
253
+ return command.execute(cwd, { kind: "list", partition: record.partition }, format);
254
+ }
255
+ if (sub === "get") {
256
+ const id = record.id;
257
+ if (id === undefined) {
258
+ return Promise.resolve({
259
+ exitCode: 2,
260
+ stdout: "",
261
+ stderr: `${COMMAND_HELP.record}\n`,
262
+ });
263
+ }
264
+ return command.execute(cwd, { kind: "get", id }, format);
265
+ }
266
+ const bodyResult = resolveRecordBody(record, cwd);
267
+ if (bodyResult.error !== undefined) {
268
+ return Promise.resolve({
269
+ exitCode: 2,
270
+ stdout: "",
271
+ stderr: `${bodyResult.error}\n`,
272
+ });
273
+ }
274
+ if (sub === "set") {
275
+ const id = record.id;
276
+ if (id === undefined) {
277
+ return Promise.resolve({
278
+ exitCode: 2,
279
+ stdout: "",
280
+ stderr: `${COMMAND_HELP.record}\n`,
281
+ });
282
+ }
283
+ return command.execute(cwd, { kind: "set", id, body: bodyResult.body }, format);
284
+ }
285
+ const afterId = record.afterId;
286
+ if (afterId === undefined) {
287
+ return Promise.resolve({
288
+ exitCode: 2,
289
+ stdout: "",
290
+ stderr: `${COMMAND_HELP.record}\n`,
291
+ });
292
+ }
293
+ const action = {
294
+ kind: "add",
295
+ afterId,
296
+ body: bodyResult.body,
297
+ };
298
+ return command.execute(cwd, action, format);
299
+ }
300
+ function dispatchInstall(parsed) {
301
+ const install = parsed.command?.install;
302
+ if (install === undefined) {
303
+ return Promise.resolve({
304
+ exitCode: 2,
305
+ stdout: "",
306
+ stderr: `${COMMAND_HELP.install}\n`,
307
+ });
308
+ }
309
+ const command = new CliInstallHandler({
310
+ source: new NodeInstallSource(),
311
+ fs: new NodeInstallTargetFs(),
312
+ });
313
+ return command.execute(install.target, { dryRun: install.dryRun, scope: install.scope }, parsed.format === "json" ? "json" : "human");
314
+ }
315
+ function dispatchReady(parsed, cwd) {
316
+ const fs = new NodeReadyFileSystem();
317
+ const command = new CliReadyHandler({
318
+ config: fs,
319
+ files: fs,
320
+ git: new ChildProcessReadyGit(),
321
+ });
322
+ return command.execute(cwd, parsed.format === "json" ? "json" : "human", parsed.command?.ready?.partition, parsed.command?.ready?.against);
323
+ }
324
+ function dispatchRefresh(parsed, cwd) {
325
+ const refreshFiles = new NodeRefreshFileReader();
326
+ const refreshCommand = new CliRefreshHandler({
327
+ clock: new SystemRefreshClock(),
328
+ config: refreshFiles,
329
+ git: new ChildProcessRefreshGit(),
330
+ spec: refreshFiles,
331
+ });
332
+ return refreshCommand.execute(cwd, parsed.format ?? "yaml");
333
+ }
334
+ function parseArgv(argv) {
335
+ if (argv.length === 0) {
336
+ return { mode: "help" };
337
+ }
338
+ if (argv.length === 1 && argv[0] === "--help") {
339
+ return { mode: "help" };
340
+ }
341
+ if (argv.length === 1 && argv[0] === "--version") {
342
+ return { mode: "version" };
343
+ }
344
+ const subcommand = argv[0];
345
+ if (!isSubcommand(subcommand)) {
346
+ return { mode: "error", message: `unknown subcommand: ${subcommand}` };
347
+ }
348
+ if (argv.length === 2 && argv[1] === "--help") {
349
+ return { mode: "help", subcommand };
350
+ }
351
+ const rest = argv.slice(1);
352
+ if (subcommand === "approve") {
353
+ return parseApproveArgv(rest);
354
+ }
355
+ if (subcommand === "ready") {
356
+ return parseReadyArgv(rest);
357
+ }
358
+ if (subcommand === "finalize") {
359
+ return parseFinalizeArgv(rest);
360
+ }
361
+ if (subcommand === "plan") {
362
+ return parsePlanArgv(rest);
363
+ }
364
+ if (subcommand === "doctor") {
365
+ return parseDoctorArgv(rest);
366
+ }
367
+ if (subcommand === "report") {
368
+ return parseReportArgv(rest);
369
+ }
370
+ if (subcommand === "record") {
371
+ return parseRecordArgv(rest);
372
+ }
373
+ if (subcommand === "install") {
374
+ return parseInstallArgv(rest);
375
+ }
376
+ const defaultFormat = subcommand === "refresh" ? "yaml" : "human";
377
+ let format = defaultFormat;
378
+ for (const arg of rest) {
379
+ if (!arg.startsWith("--format=")) {
380
+ return { mode: "error", message: `unknown flag: ${arg}` };
381
+ }
382
+ const value = arg.slice("--format=".length);
383
+ if (!isFormat(value) || (subcommand !== "refresh" && value === "yaml")) {
384
+ return { mode: "error", message: `invalid format: ${value}` };
385
+ }
386
+ format = value;
387
+ }
388
+ return { mode: "command", subcommand, format };
389
+ }
390
+ function parseReadyArgv(args) {
391
+ const ready = {};
392
+ let format = "human";
393
+ for (let i = 0; i < args.length; i++) {
394
+ const arg = args[i];
395
+ if (arg.startsWith("--format=")) {
396
+ const value = arg.slice("--format=".length);
397
+ if (!isFormat(value) || value === "yaml") {
398
+ return { mode: "error", message: `invalid format: ${value}` };
399
+ }
400
+ format = value;
401
+ continue;
402
+ }
403
+ if (arg === "--partition") {
404
+ const next = args[i + 1];
405
+ if (next === undefined || next.startsWith("--")) {
406
+ return { mode: "error", message: "missing value for --partition" };
407
+ }
408
+ ready.partition = next;
409
+ i++;
410
+ continue;
411
+ }
412
+ if (arg === "--against") {
413
+ const next = args[i + 1];
414
+ if (next === undefined || next.startsWith("--")) {
415
+ return { mode: "error", message: "missing value for --against" };
416
+ }
417
+ ready.against = next;
418
+ i++;
419
+ continue;
420
+ }
421
+ return { mode: "error", message: `unknown flag: ${arg}` };
422
+ }
423
+ return { mode: "command", subcommand: "ready", format, command: { ready } };
424
+ }
425
+ function parseApproveArgv(args) {
426
+ const approve = {};
427
+ let format = "human";
428
+ for (let i = 0; i < args.length; i++) {
429
+ const arg = args[i];
430
+ if (arg.startsWith("--format=")) {
431
+ const value = arg.slice("--format=".length);
432
+ if (!isFormat(value) || value === "yaml") {
433
+ return { mode: "error", message: `invalid format: ${value}` };
434
+ }
435
+ format = value;
436
+ continue;
437
+ }
438
+ if (arg === "--inline") {
439
+ approve.inline = true;
440
+ continue;
441
+ }
442
+ if (!arg.startsWith("--")) {
443
+ return { mode: "error", message: `unknown positional: ${arg}` };
444
+ }
445
+ const key = arg.slice(2);
446
+ const next = args[i + 1];
447
+ if (next === undefined || next.startsWith("--")) {
448
+ return { mode: "error", message: `missing value for --${key}` };
449
+ }
450
+ i++;
451
+ switch (key) {
452
+ case "id":
453
+ approve.id = next;
454
+ break;
455
+ case "approver":
456
+ approve.approver = next;
457
+ break;
458
+ case "owner-role":
459
+ approve.ownerRole = next;
460
+ break;
461
+ case "change-request":
462
+ approve.changeRequest = next;
463
+ break;
464
+ case "scope":
465
+ approve.scope = next;
466
+ break;
467
+ case "target-status":
468
+ approve.targetStatus = next;
469
+ break;
470
+ case "reviewed-test-oracle":
471
+ approve.reviewedTestOracle = next;
472
+ break;
473
+ case "plan":
474
+ approve.planId = next;
475
+ break;
476
+ default:
477
+ return { mode: "error", message: `unknown flag: --${key}` };
478
+ }
479
+ }
480
+ if (approve.inline === true && approve.planId !== undefined) {
481
+ return {
482
+ mode: "error",
483
+ message: "--inline and --plan are mutually exclusive",
484
+ };
485
+ }
486
+ return {
487
+ mode: "command",
488
+ subcommand: "approve",
489
+ format,
490
+ command: { approve },
491
+ };
492
+ }
493
+ function parseFinalizeArgv(args) {
494
+ const finalize = {};
495
+ let format = "human";
496
+ for (let i = 0; i < args.length; i++) {
497
+ const arg = args[i];
498
+ if (arg.startsWith("--format=")) {
499
+ const value = arg.slice("--format=".length);
500
+ if (!isFormat(value) || value === "yaml") {
501
+ return { mode: "error", message: `invalid format: ${value}` };
502
+ }
503
+ format = value;
504
+ continue;
505
+ }
506
+ if (arg === "--plan") {
507
+ const next = args[i + 1];
508
+ if (next === undefined || next.startsWith("--")) {
509
+ return { mode: "error", message: "missing value for --plan" };
510
+ }
511
+ finalize.planId = next;
512
+ i++;
513
+ continue;
514
+ }
515
+ return { mode: "error", message: `unknown flag: ${arg}` };
516
+ }
517
+ return {
518
+ mode: "command",
519
+ subcommand: "finalize",
520
+ format,
521
+ command: { finalize },
522
+ };
523
+ }
524
+ function parsePlanArgv(args) {
525
+ if (args.length === 0 || args[0] !== "show") {
526
+ return {
527
+ mode: "error",
528
+ message: "expected: sdd plan show [--plan <plan_id>]",
529
+ };
530
+ }
531
+ const plan = { subcommand: "show" };
532
+ let format = "human";
533
+ for (let i = 1; i < args.length; i++) {
534
+ const arg = args[i];
535
+ if (arg.startsWith("--format=")) {
536
+ const value = arg.slice("--format=".length);
537
+ if (!isFormat(value) || value === "yaml") {
538
+ return { mode: "error", message: `invalid format: ${value}` };
539
+ }
540
+ format = value;
541
+ continue;
542
+ }
543
+ if (arg === "--plan") {
544
+ const next = args[i + 1];
545
+ if (next === undefined || next.startsWith("--")) {
546
+ return { mode: "error", message: "missing value for --plan" };
547
+ }
548
+ plan.planId = next;
549
+ i++;
550
+ continue;
551
+ }
552
+ return { mode: "error", message: `unknown flag: ${arg}` };
553
+ }
554
+ return { mode: "command", subcommand: "plan", format, command: { plan } };
555
+ }
556
+ function approveRequest(args) {
557
+ if (args.id === undefined) {
558
+ return { mode: "error", message: "--id required" };
559
+ }
560
+ if (args.approver === undefined) {
561
+ return { mode: "error", message: "--approver required" };
562
+ }
563
+ if (args.ownerRole === undefined) {
564
+ return { mode: "error", message: "--owner-role required" };
565
+ }
566
+ if (args.changeRequest === undefined) {
567
+ return { mode: "error", message: "--change-request required" };
568
+ }
569
+ const targetStatus = args.targetStatus ?? "approved";
570
+ if (!isTargetStatus(targetStatus)) {
571
+ return {
572
+ mode: "error",
573
+ message: `invalid --target-status: ${targetStatus}`,
574
+ };
575
+ }
576
+ return {
577
+ mode: "ok",
578
+ value: {
579
+ id: args.id,
580
+ approver: args.approver,
581
+ ownerRole: args.ownerRole,
582
+ changeRequest: args.changeRequest,
583
+ scope: args.scope ?? "first-time-approval",
584
+ targetStatus,
585
+ reviewedTestOracle: args.reviewedTestOracle ?? null,
586
+ },
587
+ };
588
+ }
589
+ function isTargetStatus(value) {
590
+ return value === "approved" || value === "deprecated" || value === "removed";
591
+ }
592
+ function packageVersion() {
593
+ const packagePath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
594
+ const value = JSON.parse(readFileSync(packagePath, "utf8"));
595
+ if (!isRecord(value) || typeof value.version !== "string") {
596
+ throw new Error("package.json version is missing");
597
+ }
598
+ return value.version;
599
+ }
600
+ function isRecord(value) {
601
+ return typeof value === "object" && value !== null && !Array.isArray(value);
602
+ }
603
+ function isSubcommand(value) {
604
+ return (value === "token" ||
605
+ value === "check" ||
606
+ value === "refresh" ||
607
+ value === "lint" ||
608
+ value === "approve" ||
609
+ value === "ready" ||
610
+ value === "finalize" ||
611
+ value === "plan" ||
612
+ value === "doctor" ||
613
+ value === "report" ||
614
+ value === "record" ||
615
+ value === "install");
616
+ }
617
+ function parseRecordArgv(args) {
618
+ const sub = args[0];
619
+ if (sub !== "list" && sub !== "get" && sub !== "set" && sub !== "add") {
620
+ return {
621
+ mode: "error",
622
+ message: "expected: sdd record list | get <id> | set <id> | add --after <id>",
623
+ };
624
+ }
625
+ const record = { subcommand: sub };
626
+ let rest = args.slice(1);
627
+ if (sub === "get" || sub === "set") {
628
+ const id = rest[0];
629
+ if (id === undefined || id.startsWith("--")) {
630
+ return { mode: "error", message: `expected: sdd record ${sub} <id>` };
631
+ }
632
+ record.id = id;
633
+ rest = rest.slice(1);
634
+ }
635
+ const parsedFlags = parseRecordFlags(rest, record);
636
+ if (parsedFlags.mode === "error") {
637
+ return parsedFlags;
638
+ }
639
+ if (sub === "add" && record.afterId === undefined) {
640
+ return { mode: "error", message: "sdd record add requires --after <id>" };
641
+ }
642
+ if (sub === "set" || sub === "add") {
643
+ const hasContent = record.content !== undefined;
644
+ const hasFile = record.fromFile !== undefined;
645
+ if (hasContent === hasFile) {
646
+ return {
647
+ mode: "error",
648
+ message: "provide exactly one of --from-file <path> or --content <body>",
649
+ };
650
+ }
651
+ }
652
+ return {
653
+ mode: "command",
654
+ subcommand: "record",
655
+ format: parsedFlags.format,
656
+ command: { record },
657
+ };
658
+ }
659
+ function parseRecordFlags(rest, record) {
660
+ const sub = record.subcommand;
661
+ let format = "human";
662
+ for (let i = 0; i < rest.length; i++) {
663
+ const arg = rest[i];
664
+ if (arg.startsWith("--format=")) {
665
+ const value = arg.slice("--format=".length);
666
+ if (!isFormat(value) || value === "yaml") {
667
+ return { mode: "error", message: `invalid format: ${value}` };
668
+ }
669
+ format = value;
670
+ continue;
671
+ }
672
+ if (arg === "--partition" && sub === "list") {
673
+ const next = rest[i + 1];
674
+ if (next === undefined || next.startsWith("--")) {
675
+ return { mode: "error", message: "missing value for --partition" };
676
+ }
677
+ record.partition = next;
678
+ i++;
679
+ continue;
680
+ }
681
+ if (arg === "--after" && sub === "add") {
682
+ const next = rest[i + 1];
683
+ if (next === undefined || next.startsWith("--")) {
684
+ return { mode: "error", message: "missing value for --after" };
685
+ }
686
+ record.afterId = next;
687
+ i++;
688
+ continue;
689
+ }
690
+ if (arg === "--content" && (sub === "set" || sub === "add")) {
691
+ const next = rest[i + 1];
692
+ if (next === undefined) {
693
+ return { mode: "error", message: "missing value for --content" };
694
+ }
695
+ record.content = next;
696
+ i++;
697
+ continue;
698
+ }
699
+ if (arg === "--from-file" && (sub === "set" || sub === "add")) {
700
+ const next = rest[i + 1];
701
+ if (next === undefined || next.startsWith("--")) {
702
+ return { mode: "error", message: "missing value for --from-file" };
703
+ }
704
+ record.fromFile = next;
705
+ i++;
706
+ continue;
707
+ }
708
+ return { mode: "error", message: `unknown flag: ${arg}` };
709
+ }
710
+ return { mode: "ok", format };
711
+ }
712
+ function parseInstallArgv(args) {
713
+ const target = args[0];
714
+ if (target === undefined || !isInstallTarget(target)) {
715
+ return {
716
+ mode: "error",
717
+ message: "expected: sdd install <all|claude|codex>",
718
+ };
719
+ }
720
+ const install = { target, dryRun: false, scope: "user" };
721
+ let format = "human";
722
+ const rest = args.slice(1);
723
+ for (let i = 0; i < rest.length; i++) {
724
+ const arg = rest[i];
725
+ if (arg.startsWith("--format=")) {
726
+ const value = arg.slice("--format=".length);
727
+ if (!isFormat(value) || value === "yaml") {
728
+ return { mode: "error", message: `invalid format: ${value}` };
729
+ }
730
+ format = value;
731
+ continue;
732
+ }
733
+ if (arg === "--dry-run") {
734
+ install.dryRun = true;
735
+ continue;
736
+ }
737
+ if (arg === "--scope" || arg.startsWith("--scope=")) {
738
+ const value = arg.startsWith("--scope=")
739
+ ? arg.slice("--scope=".length)
740
+ : rest[++i];
741
+ if (value !== "user" && value !== "project") {
742
+ return {
743
+ mode: "error",
744
+ message: `invalid scope: ${value ?? "(missing)"}`,
745
+ };
746
+ }
747
+ install.scope = value;
748
+ continue;
749
+ }
750
+ return { mode: "error", message: `unknown flag: ${arg}` };
751
+ }
752
+ return {
753
+ mode: "command",
754
+ subcommand: "install",
755
+ format,
756
+ command: { install },
757
+ };
758
+ }
759
+ function resolveRecordBody(record, cwd) {
760
+ if (record.content !== undefined) {
761
+ return { body: record.content };
762
+ }
763
+ const fromFile = record.fromFile;
764
+ if (fromFile === undefined) {
765
+ return { error: "provide --from-file or --content" };
766
+ }
767
+ try {
768
+ return { body: readFileSync(resolve(cwd, fromFile), "utf8") };
769
+ }
770
+ catch {
771
+ return { error: `cannot read --from-file: ${fromFile}` };
772
+ }
773
+ }
774
+ function parseReportArgv(args) {
775
+ const report = { prSummary: false };
776
+ let format = "human";
777
+ for (let i = 0; i < args.length; i++) {
778
+ const arg = args[i];
779
+ if (arg.startsWith("--format=")) {
780
+ const value = arg.slice("--format=".length);
781
+ if (!isFormat(value) || value === "yaml") {
782
+ return { mode: "error", message: `invalid format: ${value}` };
783
+ }
784
+ format = value;
785
+ continue;
786
+ }
787
+ if (arg === "--pr-summary") {
788
+ report.prSummary = true;
789
+ continue;
790
+ }
791
+ if (arg === "--against") {
792
+ const next = args[i + 1];
793
+ if (next === undefined || next.startsWith("--")) {
794
+ return { mode: "error", message: "missing value for --against" };
795
+ }
796
+ report.against = next;
797
+ i++;
798
+ continue;
799
+ }
800
+ return { mode: "error", message: `unknown flag: ${arg}` };
801
+ }
802
+ if (!report.prSummary) {
803
+ return { mode: "error", message: "report requires --pr-summary" };
804
+ }
805
+ return {
806
+ mode: "command",
807
+ subcommand: "report",
808
+ format,
809
+ command: { report },
810
+ };
811
+ }
812
+ function parseDoctorArgv(args) {
813
+ const doctor = {
814
+ ruleVersion: false,
815
+ rulesPath: "rules/enforcement_registry.md",
816
+ };
817
+ let format = "human";
818
+ for (let i = 0; i < args.length; i++) {
819
+ const arg = args[i];
820
+ if (arg.startsWith("--format=")) {
821
+ const value = arg.slice("--format=".length);
822
+ if (!isFormat(value) || value === "yaml") {
823
+ return { mode: "error", message: `invalid format: ${value}` };
824
+ }
825
+ format = value;
826
+ continue;
827
+ }
828
+ if (arg === "--rule-version") {
829
+ doctor.ruleVersion = true;
830
+ continue;
831
+ }
832
+ if (arg === "--rules") {
833
+ const next = args[i + 1];
834
+ if (next === undefined || next.startsWith("--")) {
835
+ return { mode: "error", message: "missing value for --rules" };
836
+ }
837
+ doctor.rulesPath = next;
838
+ i++;
839
+ continue;
840
+ }
841
+ return { mode: "error", message: `unknown flag: ${arg}` };
842
+ }
843
+ if (!doctor.ruleVersion) {
844
+ return { mode: "error", message: "doctor requires --rule-version" };
845
+ }
846
+ return {
847
+ mode: "command",
848
+ subcommand: "doctor",
849
+ format,
850
+ command: { doctor },
851
+ };
852
+ }
853
+ function isFormat(value) {
854
+ return value === "json" || value === "human" || value === "yaml";
855
+ }
856
+ if (isEntrypoint()) {
857
+ const result = await main(process.argv.slice(2), process.cwd());
858
+ process.stdout.write(result.stdout);
859
+ process.stderr.write(result.stderr);
860
+ process.exitCode = result.exitCode;
861
+ }
862
+ function isEntrypoint() {
863
+ if (process.argv[1] === undefined) {
864
+ return false;
865
+ }
866
+ return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
867
+ }