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.
- package/LICENSE +21 -0
- package/README.md +1028 -0
- package/README.ru.md +1046 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +867 -0
- package/dist/features/approve/adapters/inbound/CliApproveHandler.d.ts +17 -0
- package/dist/features/approve/adapters/inbound/CliApproveHandler.js +108 -0
- package/dist/features/approve/adapters/outbound/NodeApproveFileSystem.d.ts +8 -0
- package/dist/features/approve/adapters/outbound/NodeApproveFileSystem.js +147 -0
- package/dist/features/approve/adapters/outbound/NodePlanFileWriter.d.ts +6 -0
- package/dist/features/approve/adapters/outbound/NodePlanFileWriter.js +92 -0
- package/dist/features/approve/adapters/outbound/SystemApproveClock.d.ts +4 -0
- package/dist/features/approve/adapters/outbound/SystemApproveClock.js +5 -0
- package/dist/features/approve/application/ApplyApproval.d.ts +19 -0
- package/dist/features/approve/application/ApplyApproval.js +30 -0
- package/dist/features/approve/application/WriteAttestation.d.ts +19 -0
- package/dist/features/approve/application/WriteAttestation.js +23 -0
- package/dist/features/approve/domain/ApproveRequest.d.ts +24 -0
- package/dist/features/approve/domain/ApproveRequest.js +24 -0
- package/dist/features/approve/domain/Rewrite.d.ts +1 -0
- package/dist/features/approve/domain/Rewrite.js +6 -0
- package/dist/features/approve/ports/inbound/ApproveCommand.d.ts +10 -0
- package/dist/features/approve/ports/inbound/ApproveCommand.js +1 -0
- package/dist/features/approve/ports/outbound/ApproveClock.d.ts +3 -0
- package/dist/features/approve/ports/outbound/ApproveClock.js +1 -0
- package/dist/features/approve/ports/outbound/ApproveConfigPort.d.ts +4 -0
- package/dist/features/approve/ports/outbound/ApproveConfigPort.js +1 -0
- package/dist/features/approve/ports/outbound/ApproveFileSystem.d.ts +8 -0
- package/dist/features/approve/ports/outbound/ApproveFileSystem.js +1 -0
- package/dist/features/approve/ports/outbound/PlanFileWriter.d.ts +13 -0
- package/dist/features/approve/ports/outbound/PlanFileWriter.js +1 -0
- package/dist/features/check/adapters/inbound/CliCheckHandler.d.ts +8 -0
- package/dist/features/check/adapters/inbound/CliCheckHandler.js +62 -0
- package/dist/features/check/adapters/outbound/ChildProcessCheckGit.d.ts +8 -0
- package/dist/features/check/adapters/outbound/ChildProcessCheckGit.js +112 -0
- package/dist/features/check/adapters/outbound/NodeCheckFileReader.d.ts +7 -0
- package/dist/features/check/adapters/outbound/NodeCheckFileReader.js +44 -0
- package/dist/features/check/application/CheckBaseline.d.ts +28 -0
- package/dist/features/check/application/CheckBaseline.js +54 -0
- package/dist/features/check/domain/BaselineComparison.d.ts +1 -0
- package/dist/features/check/domain/BaselineComparison.js +2 -0
- package/dist/features/check/ports/inbound/CheckCommand.d.ts +4 -0
- package/dist/features/check/ports/inbound/CheckCommand.js +1 -0
- package/dist/features/check/ports/outbound/CheckConfigPort.d.ts +4 -0
- package/dist/features/check/ports/outbound/CheckConfigPort.js +1 -0
- package/dist/features/check/ports/outbound/CheckGitPort.d.ts +7 -0
- package/dist/features/check/ports/outbound/CheckGitPort.js +1 -0
- package/dist/features/check/ports/outbound/CheckSpecPort.d.ts +9 -0
- package/dist/features/check/ports/outbound/CheckSpecPort.js +1 -0
- package/dist/features/doctor/adapters/inbound/CliDoctorHandler.d.ts +8 -0
- package/dist/features/doctor/adapters/inbound/CliDoctorHandler.js +77 -0
- package/dist/features/doctor/adapters/outbound/NodeRegistryReader.d.ts +5 -0
- package/dist/features/doctor/adapters/outbound/NodeRegistryReader.js +40 -0
- package/dist/features/doctor/application/RunDoctor.d.ts +30 -0
- package/dist/features/doctor/application/RunDoctor.js +78 -0
- package/dist/features/doctor/domain/RegistryRow.d.ts +23 -0
- package/dist/features/doctor/domain/RegistryRow.js +114 -0
- package/dist/features/doctor/domain/SemverRange.d.ts +7 -0
- package/dist/features/doctor/domain/SemverRange.js +82 -0
- package/dist/features/doctor/ports/inbound/DoctorCommand.d.ts +8 -0
- package/dist/features/doctor/ports/inbound/DoctorCommand.js +1 -0
- package/dist/features/doctor/ports/outbound/RegistryReader.d.ts +12 -0
- package/dist/features/doctor/ports/outbound/RegistryReader.js +1 -0
- package/dist/features/finalize/adapters/inbound/CliFinalizeHandler.d.ts +8 -0
- package/dist/features/finalize/adapters/inbound/CliFinalizeHandler.js +80 -0
- package/dist/features/finalize/adapters/outbound/NodeFinalizeFileSystem.d.ts +11 -0
- package/dist/features/finalize/adapters/outbound/NodeFinalizeFileSystem.js +167 -0
- package/dist/features/finalize/adapters/outbound/NodePlanRepo.d.ts +7 -0
- package/dist/features/finalize/adapters/outbound/NodePlanRepo.js +82 -0
- package/dist/features/finalize/adapters/outbound/SystemFinalizeClock.d.ts +4 -0
- package/dist/features/finalize/adapters/outbound/SystemFinalizeClock.js +5 -0
- package/dist/features/finalize/application/RunFinalize.d.ts +34 -0
- package/dist/features/finalize/application/RunFinalize.js +98 -0
- package/dist/features/finalize/domain/ValidateFinalizeGraph.d.ts +9 -0
- package/dist/features/finalize/domain/ValidateFinalizeGraph.js +86 -0
- package/dist/features/finalize/ports/inbound/FinalizeCommand.d.ts +7 -0
- package/dist/features/finalize/ports/inbound/FinalizeCommand.js +1 -0
- package/dist/features/finalize/ports/outbound/FinalizeClock.d.ts +3 -0
- package/dist/features/finalize/ports/outbound/FinalizeClock.js +1 -0
- package/dist/features/finalize/ports/outbound/FinalizeConfigPort.d.ts +4 -0
- package/dist/features/finalize/ports/outbound/FinalizeConfigPort.js +1 -0
- package/dist/features/finalize/ports/outbound/FinalizeFileSystem.d.ts +14 -0
- package/dist/features/finalize/ports/outbound/FinalizeFileSystem.js +1 -0
- package/dist/features/finalize/ports/outbound/PlanRepo.d.ts +21 -0
- package/dist/features/finalize/ports/outbound/PlanRepo.js +1 -0
- package/dist/features/install/adapters/inbound/CliInstallHandler.d.ts +8 -0
- package/dist/features/install/adapters/inbound/CliInstallHandler.js +54 -0
- package/dist/features/install/adapters/outbound/NodeInstallSource.d.ts +7 -0
- package/dist/features/install/adapters/outbound/NodeInstallSource.js +24 -0
- package/dist/features/install/adapters/outbound/NodeInstallTargetFs.d.ts +7 -0
- package/dist/features/install/adapters/outbound/NodeInstallTargetFs.js +30 -0
- package/dist/features/install/application/InstallRules.d.ts +10 -0
- package/dist/features/install/application/InstallRules.js +73 -0
- package/dist/features/install/domain/InstallPlan.d.ts +27 -0
- package/dist/features/install/domain/InstallPlan.js +168 -0
- package/dist/features/install/domain/InstallResult.d.ts +23 -0
- package/dist/features/install/domain/InstallResult.js +1 -0
- package/dist/features/install/domain/InstallTarget.d.ts +6 -0
- package/dist/features/install/domain/InstallTarget.js +7 -0
- package/dist/features/install/domain/ManagedBlock.d.ts +3 -0
- package/dist/features/install/domain/ManagedBlock.js +20 -0
- package/dist/features/install/domain/RuleManifest.d.ts +17 -0
- package/dist/features/install/domain/RuleManifest.js +69 -0
- package/dist/features/install/domain/SettingsMerge.d.ts +5 -0
- package/dist/features/install/domain/SettingsMerge.js +43 -0
- package/dist/features/install/ports/inbound/InstallCommand.d.ts +10 -0
- package/dist/features/install/ports/inbound/InstallCommand.js +1 -0
- package/dist/features/install/ports/outbound/InstallSource.d.ts +4 -0
- package/dist/features/install/ports/outbound/InstallSource.js +1 -0
- package/dist/features/install/ports/outbound/InstallTargetFs.d.ts +6 -0
- package/dist/features/install/ports/outbound/InstallTargetFs.js +1 -0
- package/dist/features/lint/adapters/inbound/CliLintHandler.d.ts +8 -0
- package/dist/features/lint/adapters/inbound/CliLintHandler.js +61 -0
- package/dist/features/lint/adapters/outbound/NodeLintFileReader.d.ts +7 -0
- package/dist/features/lint/adapters/outbound/NodeLintFileReader.js +165 -0
- package/dist/features/lint/application/RunLint.d.ts +10 -0
- package/dist/features/lint/application/RunLint.js +100 -0
- package/dist/features/lint/domain/Diagnostic.d.ts +1 -0
- package/dist/features/lint/domain/Diagnostic.js +2 -0
- package/dist/features/lint/domain/Record.d.ts +1 -0
- package/dist/features/lint/domain/Record.js +5 -0
- package/dist/features/lint/domain/Rules.d.ts +1 -0
- package/dist/features/lint/domain/Rules.js +2 -0
- package/dist/features/lint/domain/SpecParser.d.ts +1 -0
- package/dist/features/lint/domain/SpecParser.js +2 -0
- package/dist/features/lint/ports/inbound/LintCommand.d.ts +4 -0
- package/dist/features/lint/ports/inbound/LintCommand.js +1 -0
- package/dist/features/lint/ports/outbound/LintConfigPort.d.ts +4 -0
- package/dist/features/lint/ports/outbound/LintConfigPort.js +1 -0
- package/dist/features/lint/ports/outbound/LintFileReader.d.ts +10 -0
- package/dist/features/lint/ports/outbound/LintFileReader.js +1 -0
- package/dist/features/plan/adapters/inbound/CliPlanShowHandler.d.ts +8 -0
- package/dist/features/plan/adapters/inbound/CliPlanShowHandler.js +73 -0
- package/dist/features/plan/adapters/outbound/NodePlanReader.d.ts +7 -0
- package/dist/features/plan/adapters/outbound/NodePlanReader.js +68 -0
- package/dist/features/plan/application/ShowPlan.d.ts +7 -0
- package/dist/features/plan/application/ShowPlan.js +4 -0
- package/dist/features/plan/ports/inbound/PlanShowCommand.d.ts +7 -0
- package/dist/features/plan/ports/inbound/PlanShowCommand.js +1 -0
- package/dist/features/plan/ports/outbound/PlanConfigPort.d.ts +4 -0
- package/dist/features/plan/ports/outbound/PlanConfigPort.js +1 -0
- package/dist/features/plan/ports/outbound/PlanReader.d.ts +19 -0
- package/dist/features/plan/ports/outbound/PlanReader.js +1 -0
- package/dist/features/ready/adapters/inbound/CliReadyHandler.d.ts +8 -0
- package/dist/features/ready/adapters/inbound/CliReadyHandler.js +79 -0
- package/dist/features/ready/adapters/outbound/ChildProcessReadyGit.d.ts +9 -0
- package/dist/features/ready/adapters/outbound/ChildProcessReadyGit.js +113 -0
- package/dist/features/ready/adapters/outbound/NodeReadyFileSystem.d.ts +8 -0
- package/dist/features/ready/adapters/outbound/NodeReadyFileSystem.js +159 -0
- package/dist/features/ready/application/RunReady.d.ts +16 -0
- package/dist/features/ready/application/RunReady.js +572 -0
- package/dist/features/ready/domain/AggregatedRules.d.ts +16 -0
- package/dist/features/ready/domain/AggregatedRules.js +42 -0
- package/dist/features/ready/domain/MarkerParser.d.ts +17 -0
- package/dist/features/ready/domain/MarkerParser.js +108 -0
- package/dist/features/ready/domain/PartitionResolver.d.ts +1 -0
- package/dist/features/ready/domain/PartitionResolver.js +5 -0
- package/dist/features/ready/domain/ReadyInput.d.ts +6 -0
- package/dist/features/ready/domain/ReadyInput.js +1 -0
- package/dist/features/ready/domain/ReadyViolation.d.ts +38 -0
- package/dist/features/ready/domain/ReadyViolation.js +19 -0
- package/dist/features/ready/domain/Rules.d.ts +22 -0
- package/dist/features/ready/domain/Rules.js +243 -0
- package/dist/features/ready/domain/SpecDiff.d.ts +33 -0
- package/dist/features/ready/domain/SpecDiff.js +321 -0
- package/dist/features/ready/ports/inbound/ReadyCommand.d.ts +4 -0
- package/dist/features/ready/ports/inbound/ReadyCommand.js +1 -0
- package/dist/features/ready/ports/outbound/ReadyConfigPort.d.ts +4 -0
- package/dist/features/ready/ports/outbound/ReadyConfigPort.js +1 -0
- package/dist/features/ready/ports/outbound/ReadyFileReader.d.ts +12 -0
- package/dist/features/ready/ports/outbound/ReadyFileReader.js +1 -0
- package/dist/features/ready/ports/outbound/ReadyGitPort.d.ts +10 -0
- package/dist/features/ready/ports/outbound/ReadyGitPort.js +5 -0
- package/dist/features/record/adapters/inbound/CliRecordHandler.d.ts +10 -0
- package/dist/features/record/adapters/inbound/CliRecordHandler.js +111 -0
- package/dist/features/record/adapters/outbound/NodeRecordFileSystem.d.ts +9 -0
- package/dist/features/record/adapters/outbound/NodeRecordFileSystem.js +152 -0
- package/dist/features/record/application/AddRecord.d.ts +11 -0
- package/dist/features/record/application/AddRecord.js +84 -0
- package/dist/features/record/application/GetRecord.d.ts +8 -0
- package/dist/features/record/application/GetRecord.js +22 -0
- package/dist/features/record/application/ListRecords.d.ts +9 -0
- package/dist/features/record/application/ListRecords.js +24 -0
- package/dist/features/record/application/SetRecord.d.ts +11 -0
- package/dist/features/record/application/SetRecord.js +68 -0
- package/dist/features/record/domain/RecordBody.d.ts +12 -0
- package/dist/features/record/domain/RecordBody.js +66 -0
- package/dist/features/record/domain/RecordPartition.d.ts +1 -0
- package/dist/features/record/domain/RecordPartition.js +7 -0
- package/dist/features/record/domain/RecordSlice.d.ts +7 -0
- package/dist/features/record/domain/RecordSlice.js +1 -0
- package/dist/features/record/domain/RecordSummary.d.ts +11 -0
- package/dist/features/record/domain/RecordSummary.js +13 -0
- package/dist/features/record/domain/RecordWrite.d.ts +14 -0
- package/dist/features/record/domain/RecordWrite.js +8 -0
- package/dist/features/record/ports/inbound/RecordCommand.d.ts +19 -0
- package/dist/features/record/ports/inbound/RecordCommand.js +1 -0
- package/dist/features/record/ports/outbound/RecordConfigPort.d.ts +4 -0
- package/dist/features/record/ports/outbound/RecordConfigPort.js +1 -0
- package/dist/features/record/ports/outbound/RecordFileReader.d.ts +10 -0
- package/dist/features/record/ports/outbound/RecordFileReader.js +1 -0
- package/dist/features/record/ports/outbound/RecordFileWriter.d.ts +6 -0
- package/dist/features/record/ports/outbound/RecordFileWriter.js +1 -0
- package/dist/features/refresh/adapters/inbound/CliRefreshHandler.d.ts +8 -0
- package/dist/features/refresh/adapters/inbound/CliRefreshHandler.js +24 -0
- package/dist/features/refresh/adapters/outbound/ChildProcessRefreshGit.d.ts +8 -0
- package/dist/features/refresh/adapters/outbound/ChildProcessRefreshGit.js +118 -0
- package/dist/features/refresh/adapters/outbound/NodeRefreshFileReader.d.ts +7 -0
- package/dist/features/refresh/adapters/outbound/NodeRefreshFileReader.js +44 -0
- package/dist/features/refresh/adapters/outbound/SystemRefreshClock.d.ts +4 -0
- package/dist/features/refresh/adapters/outbound/SystemRefreshClock.js +5 -0
- package/dist/features/refresh/application/BuildRefreshStubs.d.ts +25 -0
- package/dist/features/refresh/application/BuildRefreshStubs.js +43 -0
- package/dist/features/refresh/domain/DiffStubs.d.ts +24 -0
- package/dist/features/refresh/domain/DiffStubs.js +81 -0
- package/dist/features/refresh/domain/Footprint.d.ts +14 -0
- package/dist/features/refresh/domain/Footprint.js +45 -0
- package/dist/features/refresh/ports/inbound/RefreshCommand.d.ts +4 -0
- package/dist/features/refresh/ports/inbound/RefreshCommand.js +1 -0
- package/dist/features/refresh/ports/outbound/RefreshClockPort.d.ts +3 -0
- package/dist/features/refresh/ports/outbound/RefreshClockPort.js +1 -0
- package/dist/features/refresh/ports/outbound/RefreshConfigPort.d.ts +4 -0
- package/dist/features/refresh/ports/outbound/RefreshConfigPort.js +1 -0
- package/dist/features/refresh/ports/outbound/RefreshGitPort.d.ts +7 -0
- package/dist/features/refresh/ports/outbound/RefreshGitPort.js +1 -0
- package/dist/features/refresh/ports/outbound/RefreshSpecPort.d.ts +9 -0
- package/dist/features/refresh/ports/outbound/RefreshSpecPort.js +1 -0
- package/dist/features/report/adapters/inbound/CliReportHandler.d.ts +8 -0
- package/dist/features/report/adapters/inbound/CliReportHandler.js +35 -0
- package/dist/features/report/adapters/outbound/NodeReportFileSystem.d.ts +7 -0
- package/dist/features/report/adapters/outbound/NodeReportFileSystem.js +128 -0
- package/dist/features/report/application/RunReport.d.ts +19 -0
- package/dist/features/report/application/RunReport.js +161 -0
- package/dist/features/report/ports/inbound/ReportCommand.d.ts +8 -0
- package/dist/features/report/ports/inbound/ReportCommand.js +1 -0
- package/dist/features/report/ports/outbound/ReportConfigPort.d.ts +4 -0
- package/dist/features/report/ports/outbound/ReportConfigPort.js +1 -0
- package/dist/features/report/ports/outbound/ReportFileReader.d.ts +7 -0
- package/dist/features/report/ports/outbound/ReportFileReader.js +1 -0
- package/dist/features/token/adapters/inbound/CliTokenHandler.d.ts +8 -0
- package/dist/features/token/adapters/inbound/CliTokenHandler.js +53 -0
- package/dist/features/token/adapters/outbound/ChildProcessTokenGit.d.ts +8 -0
- package/dist/features/token/adapters/outbound/ChildProcessTokenGit.js +112 -0
- package/dist/features/token/adapters/outbound/NodeTokenConfigReader.d.ts +5 -0
- package/dist/features/token/adapters/outbound/NodeTokenConfigReader.js +41 -0
- package/dist/features/token/application/ComputeToken.d.ts +18 -0
- package/dist/features/token/application/ComputeToken.js +27 -0
- package/dist/features/token/ports/inbound/TokenCommand.d.ts +4 -0
- package/dist/features/token/ports/inbound/TokenCommand.js +1 -0
- package/dist/features/token/ports/outbound/TokenConfigPort.d.ts +4 -0
- package/dist/features/token/ports/outbound/TokenConfigPort.js +1 -0
- package/dist/features/token/ports/outbound/TokenGitPort.d.ts +7 -0
- package/dist/features/token/ports/outbound/TokenGitPort.js +1 -0
- package/dist/shared/domain/AgentBlocklist.d.ts +5 -0
- package/dist/shared/domain/AgentBlocklist.js +28 -0
- package/dist/shared/domain/BoundaryReachability.d.ts +5 -0
- package/dist/shared/domain/BoundaryReachability.js +71 -0
- package/dist/shared/domain/CheckOutcome.d.ts +10 -0
- package/dist/shared/domain/CheckOutcome.js +7 -0
- package/dist/shared/domain/CliOutput.d.ts +10 -0
- package/dist/shared/domain/CliOutput.js +29 -0
- package/dist/shared/domain/Config.d.ts +29 -0
- package/dist/shared/domain/Config.js +201 -0
- package/dist/shared/domain/DiagnosticRegistry.d.ts +8 -0
- package/dist/shared/domain/DiagnosticRegistry.js +71 -0
- package/dist/shared/domain/Errors.d.ts +12 -0
- package/dist/shared/domain/Errors.js +23 -0
- package/dist/shared/domain/GlobMatch.d.ts +2 -0
- package/dist/shared/domain/GlobMatch.js +58 -0
- package/dist/shared/domain/LintReport.d.ts +16 -0
- package/dist/shared/domain/LintReport.js +11 -0
- package/dist/shared/domain/LintRules.d.ts +67 -0
- package/dist/shared/domain/LintRules.js +956 -0
- package/dist/shared/domain/PartitionGrammar.d.ts +4 -0
- package/dist/shared/domain/PartitionGrammar.js +16 -0
- package/dist/shared/domain/PlanFile.d.ts +28 -0
- package/dist/shared/domain/PlanFile.js +112 -0
- package/dist/shared/domain/Scope.d.ts +1 -0
- package/dist/shared/domain/Scope.js +3 -0
- package/dist/shared/domain/SpecApprovalRewrite.d.ts +23 -0
- package/dist/shared/domain/SpecApprovalRewrite.js +254 -0
- package/dist/shared/domain/SpecBlocks.d.ts +12 -0
- package/dist/shared/domain/SpecBlocks.js +96 -0
- package/dist/shared/domain/SpecRecord.d.ts +17 -0
- package/dist/shared/domain/SpecRecord.js +208 -0
- package/dist/shared/domain/TemplateFieldMetadata.d.ts +2 -0
- package/dist/shared/domain/TemplateFieldMetadata.js +177 -0
- package/dist/shared/domain/Token.d.ts +2 -0
- package/dist/shared/domain/Token.js +5 -0
- package/dist/shared/domain/WeaselWords.d.ts +3 -0
- package/dist/shared/domain/WeaselWords.js +32 -0
- package/package.json +71 -0
- package/rules/enforcement_registry.md +126 -0
- package/rules/hooks/sdd-lint-reminder.sh +33 -0
- package/rules/hooks/sdd-spec-read-guard.sh +73 -0
- package/rules/manifest.json +15 -0
- package/rules/review-sdd.md +9 -0
- package/rules/sdd-cli-usage.md +91 -0
- package/rules/skills/spec-driven-development/SKILL.md +554 -0
- package/rules/skills/spec-driven-development/data/weasel-words.json +22 -0
- package/rules/spec-driven-development.md +69 -0
- package/rules/tdd-sdd.md +127 -0
- package/rules/workflow-sdd.md +56 -0
- package/schema/sdd.config.schema.json +104 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function ok(stdout) {
|
|
2
|
+
return { exitCode: 0, stdout: withLf(stdout), stderr: "" };
|
|
3
|
+
}
|
|
4
|
+
export function failed(failure, format) {
|
|
5
|
+
if (format === "json") {
|
|
6
|
+
return {
|
|
7
|
+
exitCode: failure.exitCode,
|
|
8
|
+
stdout: `${JSON.stringify({
|
|
9
|
+
format_version: 1,
|
|
10
|
+
ok: false,
|
|
11
|
+
reason: failure.reason,
|
|
12
|
+
path: failure.path,
|
|
13
|
+
detail: failure.detail ?? failure.message,
|
|
14
|
+
})}\n`,
|
|
15
|
+
stderr: "",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
exitCode: failure.exitCode,
|
|
20
|
+
stdout: "",
|
|
21
|
+
stderr: `${failure.reason}: ${failure.message}${failure.detail ? ` (${failure.detail})` : ""}\n`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function withLf(value) {
|
|
25
|
+
if (value.length === 0 || value.endsWith("\n")) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
return `${value}\n`;
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type Mechanism = "git_tree_hash_v1";
|
|
2
|
+
export interface FootprintConfig {
|
|
3
|
+
bindingIdPrefix: string;
|
|
4
|
+
bindingField: string;
|
|
5
|
+
}
|
|
6
|
+
export interface Partition {
|
|
7
|
+
name: string;
|
|
8
|
+
specPaths: string[];
|
|
9
|
+
testPaths: string[];
|
|
10
|
+
sandboxPaths: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface SddConfig {
|
|
13
|
+
specFile: string;
|
|
14
|
+
baselineId: string;
|
|
15
|
+
discoveryScope: string[];
|
|
16
|
+
footprint: FootprintConfig;
|
|
17
|
+
mechanism: Mechanism;
|
|
18
|
+
lint: LintConfig;
|
|
19
|
+
partitions: Partition[];
|
|
20
|
+
/** Directory under <repo_root> where attestation plan files live (P0.6).
|
|
21
|
+
* Default: ".sdd/plans". */
|
|
22
|
+
plansDir: string;
|
|
23
|
+
}
|
|
24
|
+
export interface LintConfig {
|
|
25
|
+
specFiles: string[];
|
|
26
|
+
approverBlocklist: string[];
|
|
27
|
+
partitionGlob: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function configFromJson(value: unknown, path: string): SddConfig;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { configFailure } from "./Errors.js";
|
|
2
|
+
import { NORMATIVE_ID_RE, PARTITION_NAME_RE } from "./PartitionGrammar.js";
|
|
3
|
+
const TOP_LEVEL_FIELDS = new Set([
|
|
4
|
+
"$schema",
|
|
5
|
+
"spec_file",
|
|
6
|
+
"baseline_id",
|
|
7
|
+
"discovery_scope",
|
|
8
|
+
"footprint",
|
|
9
|
+
"mechanism",
|
|
10
|
+
"lint",
|
|
11
|
+
"partitions",
|
|
12
|
+
"plans_dir",
|
|
13
|
+
"test_paths",
|
|
14
|
+
"sandbox_paths",
|
|
15
|
+
]);
|
|
16
|
+
const DEFAULT_PLANS_DIR = ".sdd/plans";
|
|
17
|
+
const FOOTPRINT_FIELDS = new Set(["binding_id_prefix", "binding_field"]);
|
|
18
|
+
const LINT_FIELDS = new Set([
|
|
19
|
+
"spec_files",
|
|
20
|
+
"approver_blocklist",
|
|
21
|
+
"partition_glob",
|
|
22
|
+
]);
|
|
23
|
+
const PARTITION_FIELDS = new Set(["spec_paths", "test_paths", "sandbox_paths"]);
|
|
24
|
+
const DEFAULT_PARTITION_NAME = "default";
|
|
25
|
+
export function configFromJson(value, path) {
|
|
26
|
+
if (!isObject(value)) {
|
|
27
|
+
throw configFailure("config-invalid", ".sdd/config.json must be a JSON object", undefined, path);
|
|
28
|
+
}
|
|
29
|
+
for (const key of Object.keys(value)) {
|
|
30
|
+
if (!TOP_LEVEL_FIELDS.has(key)) {
|
|
31
|
+
throw configFailure("config-invalid", `unknown config field: ${key}`, undefined, path);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const specFile = stringField(value, "spec_file", path);
|
|
35
|
+
const baselineId = stringField(value, "baseline_id", path);
|
|
36
|
+
const discoveryScope = stringArrayField(value, "discovery_scope", path);
|
|
37
|
+
const mechanism = stringField(value, "mechanism", path);
|
|
38
|
+
if (mechanism !== "git_tree_hash_v1") {
|
|
39
|
+
throw configFailure("config-invalid", `unsupported mechanism: ${mechanism}`, undefined, path);
|
|
40
|
+
}
|
|
41
|
+
if (!NORMATIVE_ID_RE.test(baselineId)) {
|
|
42
|
+
throw configFailure("config-invalid", `invalid baseline_id: ${baselineId}`, undefined, path);
|
|
43
|
+
}
|
|
44
|
+
const lint = lintConfig(value.lint, path, specFile);
|
|
45
|
+
const topLevelTestPaths = optionalGlobArrayField(value, "test_paths", path);
|
|
46
|
+
const topLevelSandboxPaths = optionalGlobArrayField(value, "sandbox_paths", path);
|
|
47
|
+
const partitions = partitionsField(value.partitions, path, lint.specFiles, topLevelTestPaths, topLevelSandboxPaths);
|
|
48
|
+
const plansDir = optionalStringField(value, "plans_dir", path) ?? DEFAULT_PLANS_DIR;
|
|
49
|
+
return {
|
|
50
|
+
specFile,
|
|
51
|
+
baselineId,
|
|
52
|
+
discoveryScope,
|
|
53
|
+
footprint: footprintConfig(value.footprint, path),
|
|
54
|
+
mechanism,
|
|
55
|
+
lint,
|
|
56
|
+
partitions,
|
|
57
|
+
plansDir,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function partitionsField(raw, path, lintSpecFiles, topLevelTestPaths, topLevelSandboxPaths) {
|
|
61
|
+
if (raw === undefined) {
|
|
62
|
+
return [
|
|
63
|
+
{
|
|
64
|
+
name: DEFAULT_PARTITION_NAME,
|
|
65
|
+
specPaths: [...lintSpecFiles],
|
|
66
|
+
testPaths: topLevelTestPaths,
|
|
67
|
+
sandboxPaths: topLevelSandboxPaths,
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
if (!isObject(raw)) {
|
|
72
|
+
throw configFailure("config-invalid", "partitions must be an object", undefined, path);
|
|
73
|
+
}
|
|
74
|
+
const out = [];
|
|
75
|
+
for (const name of Object.keys(raw)) {
|
|
76
|
+
if (!PARTITION_NAME_RE.test(name)) {
|
|
77
|
+
throw configFailure("config-invalid", `invalid partition name "${name}" — must match /^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)*$/`, undefined, path);
|
|
78
|
+
}
|
|
79
|
+
const entry = raw[name];
|
|
80
|
+
if (!isObject(entry)) {
|
|
81
|
+
throw configFailure("config-invalid", `partitions.${name} must be an object`, undefined, path);
|
|
82
|
+
}
|
|
83
|
+
for (const key of Object.keys(entry)) {
|
|
84
|
+
if (!PARTITION_FIELDS.has(key)) {
|
|
85
|
+
throw configFailure("config-invalid", `unknown partition field: partitions.${name}.${key}`, undefined, path);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const specPaths = stringArrayField(entry, "spec_paths", path);
|
|
89
|
+
const testPaths = optionalGlobArrayField(entry, "test_paths", path);
|
|
90
|
+
const sandboxPaths = optionalGlobArrayField(entry, "sandbox_paths", path);
|
|
91
|
+
out.push({ name, specPaths, testPaths, sandboxPaths });
|
|
92
|
+
}
|
|
93
|
+
if (out.length === 0) {
|
|
94
|
+
throw configFailure("config-invalid", "partitions must declare at least one entry when present", undefined, path);
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
function optionalGlobArrayField(value, key, path) {
|
|
99
|
+
const field = value[key];
|
|
100
|
+
if (field === undefined) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
if (!Array.isArray(field)) {
|
|
104
|
+
throw configFailure("config-invalid", `${key} must be an array`, undefined, path);
|
|
105
|
+
}
|
|
106
|
+
if (!field.every((entry) => typeof entry === "string" && entry.length > 0)) {
|
|
107
|
+
throw configFailure("config-invalid", `${key} entries must be non-empty strings`, undefined, path);
|
|
108
|
+
}
|
|
109
|
+
return [...field];
|
|
110
|
+
}
|
|
111
|
+
function lintConfig(value, path, specFileFallback) {
|
|
112
|
+
if (value === undefined) {
|
|
113
|
+
return {
|
|
114
|
+
specFiles: [specFileFallback],
|
|
115
|
+
approverBlocklist: [],
|
|
116
|
+
partitionGlob: [],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (!isObject(value)) {
|
|
120
|
+
throw configFailure("config-invalid", "lint must be an object", undefined, path);
|
|
121
|
+
}
|
|
122
|
+
for (const key of Object.keys(value)) {
|
|
123
|
+
if (!LINT_FIELDS.has(key)) {
|
|
124
|
+
throw configFailure("config-invalid", `unknown lint field: ${key}`, undefined, path);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const specFilesRaw = value.spec_files;
|
|
128
|
+
const specFiles = specFilesRaw === undefined
|
|
129
|
+
? [specFileFallback]
|
|
130
|
+
: nonEmptyStringArray(specFilesRaw, "lint.spec_files", path);
|
|
131
|
+
const approverBlocklist = optionalStringArray(value.approver_blocklist, "lint.approver_blocklist", path);
|
|
132
|
+
const partitionGlob = optionalStringArray(value.partition_glob, "lint.partition_glob", path);
|
|
133
|
+
return { specFiles, approverBlocklist, partitionGlob };
|
|
134
|
+
}
|
|
135
|
+
function nonEmptyStringArray(raw, field, path) {
|
|
136
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
137
|
+
throw configFailure("config-invalid", `${field} must be a non-empty array`, undefined, path);
|
|
138
|
+
}
|
|
139
|
+
return assertStringEntries(raw, field, path);
|
|
140
|
+
}
|
|
141
|
+
function optionalStringArray(raw, field, path) {
|
|
142
|
+
if (raw === undefined) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
if (!Array.isArray(raw)) {
|
|
146
|
+
throw configFailure("config-invalid", `${field} must be an array`, undefined, path);
|
|
147
|
+
}
|
|
148
|
+
return assertStringEntries(raw, field, path);
|
|
149
|
+
}
|
|
150
|
+
function assertStringEntries(raw, field, path) {
|
|
151
|
+
if (!raw.every((entry) => typeof entry === "string" && entry.length > 0)) {
|
|
152
|
+
throw configFailure("config-invalid", `${field} entries must be non-empty strings`, undefined, path);
|
|
153
|
+
}
|
|
154
|
+
return [...raw];
|
|
155
|
+
}
|
|
156
|
+
function footprintConfig(value, path) {
|
|
157
|
+
if (value === undefined) {
|
|
158
|
+
return { bindingIdPrefix: "IMP-", bindingField: "binding" };
|
|
159
|
+
}
|
|
160
|
+
if (!isObject(value)) {
|
|
161
|
+
throw configFailure("config-invalid", "footprint must be an object", undefined, path);
|
|
162
|
+
}
|
|
163
|
+
for (const key of Object.keys(value)) {
|
|
164
|
+
if (!FOOTPRINT_FIELDS.has(key)) {
|
|
165
|
+
throw configFailure("config-invalid", `unknown footprint field: ${key}`, undefined, path);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const bindingIdPrefix = optionalStringField(value, "binding_id_prefix", path) ?? "IMP-";
|
|
169
|
+
const bindingField = optionalStringField(value, "binding_field", path) ?? "binding";
|
|
170
|
+
return { bindingIdPrefix, bindingField };
|
|
171
|
+
}
|
|
172
|
+
function stringField(value, key, path) {
|
|
173
|
+
const field = value[key];
|
|
174
|
+
if (typeof field !== "string" || field.length === 0) {
|
|
175
|
+
throw configFailure("config-invalid", `${key} must be a non-empty string`, undefined, path);
|
|
176
|
+
}
|
|
177
|
+
return field;
|
|
178
|
+
}
|
|
179
|
+
function optionalStringField(value, key, path) {
|
|
180
|
+
const field = value[key];
|
|
181
|
+
if (field === undefined) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
if (typeof field !== "string" || field.length === 0) {
|
|
185
|
+
throw configFailure("config-invalid", `${key} must be a non-empty string`, undefined, path);
|
|
186
|
+
}
|
|
187
|
+
return field;
|
|
188
|
+
}
|
|
189
|
+
function stringArrayField(value, key, path) {
|
|
190
|
+
const field = value[key];
|
|
191
|
+
if (!Array.isArray(field) || field.length === 0) {
|
|
192
|
+
throw configFailure("config-invalid", `${key} must be a non-empty array`, undefined, path);
|
|
193
|
+
}
|
|
194
|
+
if (!field.every((entry) => typeof entry === "string" && entry.length > 0)) {
|
|
195
|
+
throw configFailure("config-invalid", `${key} entries must be non-empty strings`, undefined, path);
|
|
196
|
+
}
|
|
197
|
+
return field;
|
|
198
|
+
}
|
|
199
|
+
function isObject(value) {
|
|
200
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
201
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const LINT_DIAGNOSTIC_IDS: readonly ["sdd:section-presence", "sdd:section-order", "sdd:weasel-word", "sdd:lifecycle-status-present", "sdd:lifecycle-status-valid", "sdd:approval-record-required", "sdd:approval-record-forbidden", "sdd:test-obligation-required", "sdd:type-version-int", "sdd:type-invariant-evidence", "sdd:type-invariant-stability", "sdd:type-data-scope", "sdd:type-nfr-stage", "sdd:type-migration-direction", "sdd:type-migration-mode", "sdd:type-migration-runtime-state", "sdd:type-surface-boundary-type", "sdd:baseline-version-required", "sdd:deprecated-fields-required", "sdd:assumption-downgrade-approval", "sdd:partition-default-policy-set", "sdd:generated-artifact-surface-ref", "sdd:boundary-policy-ref", "sdd:boundary-concurrency-model", "sdd:applicability-required", "sdd:data-scope-required", "sdd:migration-enforcement-stage", "sdd:migration-cross-partition", "sdd:debt-budget-form", "sdd:open-q-blocking"];
|
|
2
|
+
export type LintDiagnosticId = (typeof LINT_DIAGNOSTIC_IDS)[number];
|
|
3
|
+
export declare const READY_VIOLATION_KINDS: readonly ["unapproved", "uncovered", "removed_no_compat_test", "removed_compat_action_mismatch", "surface_unapproved_ref", "orphan_covers", "unknown_partition_covers", "aggregated_lint", "aggregated_check", "surface_semver_cascade", "generated_artifact_structural_diff_unbumped", "debt_budget_increased"];
|
|
4
|
+
export type ReadyViolationKindId = (typeof READY_VIOLATION_KINDS)[number];
|
|
5
|
+
export declare const DOCTOR_DRIFT_KINDS: readonly ["version_mismatch", "missing_diagnostic", "stale_diagnostic"];
|
|
6
|
+
export type DoctorDriftKindId = (typeof DOCTOR_DRIFT_KINDS)[number];
|
|
7
|
+
export declare const LINT_DIAGNOSTIC_ID_GRAMMAR: RegExp;
|
|
8
|
+
export declare const READY_VIOLATION_KIND_GRAMMAR: RegExp;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Source of truth for Surface `sdd-cli/diagnostics` (SUR-009): the
|
|
3
|
+
* published rule / violation-kind identifiers. Coverage with src/ is
|
|
4
|
+
* enforced by diagnostic-registry-coverage.test.ts (INV-010).
|
|
5
|
+
*/
|
|
6
|
+
export const LINT_DIAGNOSTIC_IDS = [
|
|
7
|
+
"sdd:section-presence",
|
|
8
|
+
"sdd:section-order",
|
|
9
|
+
"sdd:weasel-word",
|
|
10
|
+
"sdd:lifecycle-status-present",
|
|
11
|
+
"sdd:lifecycle-status-valid",
|
|
12
|
+
"sdd:approval-record-required",
|
|
13
|
+
"sdd:approval-record-forbidden",
|
|
14
|
+
"sdd:test-obligation-required",
|
|
15
|
+
"sdd:type-version-int",
|
|
16
|
+
"sdd:type-invariant-evidence",
|
|
17
|
+
"sdd:type-invariant-stability",
|
|
18
|
+
"sdd:type-data-scope",
|
|
19
|
+
"sdd:type-nfr-stage",
|
|
20
|
+
"sdd:type-migration-direction",
|
|
21
|
+
"sdd:type-migration-mode",
|
|
22
|
+
"sdd:type-migration-runtime-state",
|
|
23
|
+
"sdd:type-surface-boundary-type",
|
|
24
|
+
/* P1 — cheap requiredness gaps (ENF-003/009/010/011/012) */
|
|
25
|
+
"sdd:baseline-version-required",
|
|
26
|
+
"sdd:deprecated-fields-required",
|
|
27
|
+
"sdd:assumption-downgrade-approval",
|
|
28
|
+
"sdd:partition-default-policy-set",
|
|
29
|
+
"sdd:generated-artifact-surface-ref",
|
|
30
|
+
/* P2.1 — boundary requiredness (ENF-013/014/015/016) */
|
|
31
|
+
"sdd:boundary-policy-ref",
|
|
32
|
+
"sdd:boundary-concurrency-model",
|
|
33
|
+
"sdd:applicability-required",
|
|
34
|
+
"sdd:data-scope-required",
|
|
35
|
+
/* P2.2 — migration consistency (ENF-017/018) */
|
|
36
|
+
"sdd:migration-enforcement-stage",
|
|
37
|
+
"sdd:migration-cross-partition",
|
|
38
|
+
/* P3.1 — debt budget form (ENF-020) */
|
|
39
|
+
"sdd:debt-budget-form",
|
|
40
|
+
/* unresolved blocking Open-Q (ENF-059) */
|
|
41
|
+
"sdd:open-q-blocking",
|
|
42
|
+
];
|
|
43
|
+
export const READY_VIOLATION_KINDS = [
|
|
44
|
+
"unapproved",
|
|
45
|
+
"uncovered",
|
|
46
|
+
"removed_no_compat_test",
|
|
47
|
+
"removed_compat_action_mismatch",
|
|
48
|
+
"surface_unapproved_ref",
|
|
49
|
+
"orphan_covers",
|
|
50
|
+
"unknown_partition_covers",
|
|
51
|
+
"aggregated_lint",
|
|
52
|
+
"aggregated_check",
|
|
53
|
+
/* P2.3 — semver cascade (ENF-004A) shipped as severity:warn initially */
|
|
54
|
+
"surface_semver_cascade",
|
|
55
|
+
/* P2.3-stretch — structural diff in a published GeneratedArtifact (ENF-019) */
|
|
56
|
+
"generated_artifact_structural_diff_unbumped",
|
|
57
|
+
/* P3.2 — debt-budget monotonicity check (ENF-020 runtime side) */
|
|
58
|
+
"debt_budget_increased",
|
|
59
|
+
];
|
|
60
|
+
/*
|
|
61
|
+
* Drift kinds published by `sdd doctor` (CTR-022 / ENF-008). Not lint or ready
|
|
62
|
+
* diagnostics — they are doctor's own surface — but `sdd doctor` must treat
|
|
63
|
+
* them as known so a registry row declaring them does not self-report missing.
|
|
64
|
+
*/
|
|
65
|
+
export const DOCTOR_DRIFT_KINDS = [
|
|
66
|
+
"version_mismatch",
|
|
67
|
+
"missing_diagnostic",
|
|
68
|
+
"stale_diagnostic",
|
|
69
|
+
];
|
|
70
|
+
export const LINT_DIAGNOSTIC_ID_GRAMMAR = /^sdd:[a-z][a-z0-9-]*$/;
|
|
71
|
+
export const READY_VIOLATION_KIND_GRAMMAR = /^[a-z][a-z0-9_]*$/;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ExitCode = 0 | 1 | 2 | 3;
|
|
2
|
+
export type FailureReason = "baseline-dirty" | "baseline-stale" | "config-missing" | "config-invalid" | "baseline-block-missing" | "baseline-block-duplicate" | "git-not-on-path" | "not-a-git-repo" | "head-unborn";
|
|
3
|
+
export declare class CliFailure extends Error {
|
|
4
|
+
readonly exitCode: ExitCode;
|
|
5
|
+
readonly reason: FailureReason;
|
|
6
|
+
readonly path?: string;
|
|
7
|
+
readonly detail?: string;
|
|
8
|
+
constructor(exitCode: ExitCode, reason: FailureReason, message: string, detail?: string, path?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function configFailure(reason: FailureReason, message: string, detail?: string, path?: string): CliFailure;
|
|
11
|
+
export declare function environmentFailure(reason: FailureReason, message: string, detail?: string): CliFailure;
|
|
12
|
+
export declare function errorMessage(e: unknown): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class CliFailure extends Error {
|
|
2
|
+
exitCode;
|
|
3
|
+
reason;
|
|
4
|
+
path;
|
|
5
|
+
detail;
|
|
6
|
+
constructor(exitCode, reason, message, detail, path) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "CliFailure";
|
|
9
|
+
this.exitCode = exitCode;
|
|
10
|
+
this.reason = reason;
|
|
11
|
+
this.detail = detail;
|
|
12
|
+
this.path = path;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function configFailure(reason, message, detail, path) {
|
|
16
|
+
return new CliFailure(2, reason, message, detail, path);
|
|
17
|
+
}
|
|
18
|
+
export function environmentFailure(reason, message, detail) {
|
|
19
|
+
return new CliFailure(3, reason, message, detail);
|
|
20
|
+
}
|
|
21
|
+
export function errorMessage(e) {
|
|
22
|
+
return e instanceof Error ? e.message : String(e);
|
|
23
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Pattern-match a posix-style file path against a glob pattern (the CST-006
|
|
3
|
+
* dialect: `*` = any chars within a segment, `?` = single char, `**` =
|
|
4
|
+
* zero-or-more directory levels, literal segments). Pure; no I/O.
|
|
5
|
+
*/
|
|
6
|
+
export function matchesGlob(pattern, path) {
|
|
7
|
+
const patternSegments = pattern.split("/").filter((s) => s.length > 0);
|
|
8
|
+
const pathSegments = path.split("/").filter((s) => s.length > 0);
|
|
9
|
+
return matchSegments(patternSegments, 0, pathSegments, 0);
|
|
10
|
+
}
|
|
11
|
+
function matchSegments(p, pi, x, xi) {
|
|
12
|
+
if (pi === p.length) {
|
|
13
|
+
return xi === x.length;
|
|
14
|
+
}
|
|
15
|
+
const head = p[pi];
|
|
16
|
+
if (head === "**") {
|
|
17
|
+
if (pi === p.length - 1) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
for (let k = xi; k <= x.length; k++) {
|
|
21
|
+
if (matchSegments(p, pi + 1, x, k)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (xi === x.length) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (!segmentMatches(head, x[xi])) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return matchSegments(p, pi + 1, x, xi + 1);
|
|
34
|
+
}
|
|
35
|
+
function segmentMatches(pattern, name) {
|
|
36
|
+
if (!hasGlob(pattern)) {
|
|
37
|
+
return pattern === name;
|
|
38
|
+
}
|
|
39
|
+
const re = new RegExp(`^${pattern
|
|
40
|
+
.split("")
|
|
41
|
+
.map((c) => {
|
|
42
|
+
if (c === "*") {
|
|
43
|
+
return "[^/]*";
|
|
44
|
+
}
|
|
45
|
+
if (c === "?") {
|
|
46
|
+
return "[^/]";
|
|
47
|
+
}
|
|
48
|
+
return c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
49
|
+
})
|
|
50
|
+
.join("")}$`);
|
|
51
|
+
return re.test(name);
|
|
52
|
+
}
|
|
53
|
+
function hasGlob(value) {
|
|
54
|
+
return /[*?[\]]/.test(value);
|
|
55
|
+
}
|
|
56
|
+
export function fileInGlobs(file, patterns) {
|
|
57
|
+
return patterns.some((p) => matchesGlob(p, file));
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LintDiagnosticId } from "./DiagnosticRegistry.js";
|
|
2
|
+
export type DiagnosticSeverity = "error" | "warn";
|
|
3
|
+
export interface Diagnostic {
|
|
4
|
+
severity: DiagnosticSeverity;
|
|
5
|
+
rule: LintDiagnosticId;
|
|
6
|
+
file: string;
|
|
7
|
+
line?: number;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
export interface LintReport {
|
|
11
|
+
diagnostics: Diagnostic[];
|
|
12
|
+
errorCount: number;
|
|
13
|
+
warnCount: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function emptyReport(): LintReport;
|
|
16
|
+
export declare function appendDiagnostic(report: LintReport, d: Diagnostic): LintReport;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* Lint diagnostics shared between lint and ready slices. */
|
|
2
|
+
export function emptyReport() {
|
|
3
|
+
return { diagnostics: [], errorCount: 0, warnCount: 0 };
|
|
4
|
+
}
|
|
5
|
+
export function appendDiagnostic(report, d) {
|
|
6
|
+
return {
|
|
7
|
+
diagnostics: [...report.diagnostics, d],
|
|
8
|
+
errorCount: report.errorCount + (d.severity === "error" ? 1 : 0),
|
|
9
|
+
warnCount: report.warnCount + (d.severity === "warn" ? 1 : 0),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Diagnostic } from "./LintReport.js";
|
|
2
|
+
import { type LintRecord } from "./SpecRecord.js";
|
|
3
|
+
import { WEASEL_ABSOLUTE, WEASEL_MODAL_IN_NORMATIVE } from "./WeaselWords.js";
|
|
4
|
+
export declare const REQUIRED_PARTITION_SECTIONS: ReadonlyArray<string>;
|
|
5
|
+
export declare const NORMATIVE_SECTIONS: ReadonlyArray<string>;
|
|
6
|
+
export declare const WEASEL_WORDS: ReadonlyArray<string>;
|
|
7
|
+
export { WEASEL_ABSOLUTE, WEASEL_MODAL_IN_NORMATIVE };
|
|
8
|
+
export declare function lifecycleStatusRules(rec: LintRecord): Diagnostic[];
|
|
9
|
+
export declare function approvalRecordRules(rec: LintRecord): Diagnostic[];
|
|
10
|
+
export declare function testObligationRules(rec: LintRecord): Diagnostic[];
|
|
11
|
+
export declare function fieldTypeRules(rec: LintRecord): Diagnostic[];
|
|
12
|
+
/** ENF-003: Delta and Migration records MUST pin a baseline_version. */
|
|
13
|
+
export declare function baselineVersionRequiredRule(rec: LintRecord): Diagnostic[];
|
|
14
|
+
/** ENF-009: records with lifecycle.status=deprecated MUST carry both
|
|
15
|
+
* sunset_version and replacement_id (SDD §1.6). */
|
|
16
|
+
export declare function deprecatedFieldsRequiredRule(rec: LintRecord): Diagnostic[];
|
|
17
|
+
/** ENF-059: an Open-Q with blocking=yes fails spec-valid (SDD §0);
|
|
18
|
+
* a `removed` Open-Q is already resolved and does not fire. */
|
|
19
|
+
export declare function openQBlockingRule(rec: LintRecord): Diagnostic[];
|
|
20
|
+
/** ENF-010: ASSUMPTIONs downgraded to blocking=advisory MUST carry an
|
|
21
|
+
* approval_record with a non-agent approver (SDD §7.5); OQ-018 tracks
|
|
22
|
+
* whether blocking=no should also fire. */
|
|
23
|
+
export declare function assumptionDowngradeApprovalRule(rec: LintRecord, approverBlocklist?: readonly string[]): Diagnostic[];
|
|
24
|
+
/** ENF-011: Partition records MUST carry a default_policy_set field (an array;
|
|
25
|
+
* empty allowed — explicit "no policies" is still a typed value). */
|
|
26
|
+
export declare function partitionDefaultPolicySetRule(rec: LintRecord): Diagnostic[];
|
|
27
|
+
/** ENF-012: GeneratedArtifact records that publish a Surface (published_surface
|
|
28
|
+
* == "yes") MUST carry a surface_ref. */
|
|
29
|
+
export declare function generatedArtifactSurfaceRefRule(rec: LintRecord): Diagnostic[];
|
|
30
|
+
/** ENF-013: boundary CTR/BEH must declare policy_refs (or an explicit
|
|
31
|
+
* policy_override block with a rationale). */
|
|
32
|
+
export declare function boundaryPolicyRefRule(rec: LintRecord, boundaryIds: ReadonlySet<string>): Diagnostic[];
|
|
33
|
+
/** ENF-014: boundary CTR/BEH must declare concurrency_model with the four
|
|
34
|
+
* required sub-fields. */
|
|
35
|
+
export declare function boundaryConcurrencyModelRule(rec: LintRecord, boundaryIds: ReadonlySet<string>): Diagnostic[];
|
|
36
|
+
/** ENF-015: boundary CTR/BEH must declare an applicability field (a typed
|
|
37
|
+
* axis-classification block; `invariant_to_all_axes: true` is acceptable). */
|
|
38
|
+
export declare function applicabilityRequiredRule(rec: LintRecord, boundaryIds: ReadonlySet<string>): Diagnostic[];
|
|
39
|
+
/** ENF-016: boundary CTR/BEH touching persistent state must declare
|
|
40
|
+
* data_scope (allowing `not_applicable` with a reason); persistence is
|
|
41
|
+
* detected heuristically — see the spec record for the predicate. */
|
|
42
|
+
export declare function dataScopeRequiredRule(rec: LintRecord, boundaryIds: ReadonlySet<string>): Diagnostic[];
|
|
43
|
+
/** ENF-017: an Invariant/Contract/Behavior with data_scope
|
|
44
|
+
* `post_migration:<MIG-ID>` requires the referenced Migration to exist and
|
|
45
|
+
* to declare a non-empty `enforcement_stage` (presence is what we check). */
|
|
46
|
+
export declare function migrationEnforcementStageRule(rec: LintRecord, records: ReadonlyArray<LintRecord>): Diagnostic[];
|
|
47
|
+
/** ENF-020 (P3.1): every Partition record must carry an `unmodeled_budget`
|
|
48
|
+
* block with the required sub-fields (current, baseline_at, baseline_value,
|
|
49
|
+
* trend) — see the spec record for the per-field constraints. */
|
|
50
|
+
export declare function debtBudgetFormRule(rec: LintRecord): Diagnostic[];
|
|
51
|
+
/** ENF-018: a Migration whose target_ids reference IDs from more than one
|
|
52
|
+
* partition MUST declare partition_slice[] entries with coordinator_id set. */
|
|
53
|
+
export declare function migrationCrossPartitionRule(rec: LintRecord): Diagnostic[];
|
|
54
|
+
export interface SectionViolation {
|
|
55
|
+
rule: "sdd:section-presence" | "sdd:section-order";
|
|
56
|
+
message: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function sectionViolations(markdown: string): SectionViolation[];
|
|
59
|
+
export interface WeaselFinding {
|
|
60
|
+
line: number;
|
|
61
|
+
word: string;
|
|
62
|
+
section: string;
|
|
63
|
+
/** Present only for modal-pass findings. Names the normative field where
|
|
64
|
+
* the word was found, e.g. "Behavior.then". */
|
|
65
|
+
field?: string;
|
|
66
|
+
}
|
|
67
|
+
export declare function weaselFindings(markdown: string, records?: ReadonlyArray<LintRecord>): WeaselFinding[];
|