@use-the-fork/spindle 0.0.0-stage → 0.0.1

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 (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -2
  3. package/build/Assets/Blueprints/Catalog.js +110 -0
  4. package/build/Assets/Blueprints/agents/general.agent.md +67 -0
  5. package/build/Assets/Blueprints/agents/sdd-code-reviewer.agent.md +62 -0
  6. package/build/Assets/Blueprints/agents/sdd-code-slop-reviewer.agent.md +59 -0
  7. package/build/Assets/Blueprints/agents/sdd-implementer.agent.md +77 -0
  8. package/build/Assets/Blueprints/agents/sdd-orchestrator.agent.md +42 -0
  9. package/build/Assets/Blueprints/agents/sdd-re-review.agent.md +57 -0
  10. package/build/Assets/Blueprints/agents/sdd-reviewer.agent.md +89 -0
  11. package/build/Assets/Blueprints/agents/sdd-task-reviewer.agent.md +54 -0
  12. package/build/Assets/Blueprints/agents/shared-codebase-analyzer.agent.md +151 -0
  13. package/build/Assets/Blueprints/agents/shared-codebase-locator.agent.md +130 -0
  14. package/build/Assets/Blueprints/agents/shared-codebase-pattern-finder.agent.md +247 -0
  15. package/build/Assets/Blueprints/agents/shared-explore.agent.md +53 -0
  16. package/build/Assets/Blueprints/agents/shared-r.agent.md +17 -0
  17. package/build/Assets/Blueprints/agents/shared-rw.agent.md +17 -0
  18. package/build/Assets/Blueprints/agents/shared-rwx.agent.md +17 -0
  19. package/build/Assets/Blueprints/agents/shared-web-search-researcher.agent.md +122 -0
  20. package/build/Assets/Blueprints/instructions/code-commenting.instructions.md +39 -0
  21. package/build/Assets/Blueprints/instructions/source-architecture.instructions.md +15 -0
  22. package/build/Assets/Blueprints/skills/asd-ste100/CREDITS.MD +1 -0
  23. package/build/Assets/Blueprints/skills/asd-ste100/SKILL.md +83 -0
  24. package/build/Assets/Blueprints/skills/asd-ste100/examples/before-after.md +107 -0
  25. package/build/Assets/Blueprints/skills/asd-ste100/references/writing-rules.md +65 -0
  26. package/build/Assets/Blueprints/skills/author-agent/SKILL.md +26 -0
  27. package/build/Assets/Blueprints/skills/author-design/SKILL.md +38 -0
  28. package/build/Assets/Blueprints/skills/author-instruction/SKILL.md +28 -0
  29. package/build/Assets/Blueprints/skills/author-skill/SKILL.md +26 -0
  30. package/build/Assets/Blueprints/skills/grill/SKILL.md +33 -0
  31. package/build/Assets/Blueprints/skills/grill-design/SKILL.md +41 -0
  32. package/build/Assets/Blueprints/skills/grill-with-docs/SKILL.md +14 -0
  33. package/build/Assets/Blueprints/skills/implement/SKILL.md +79 -0
  34. package/build/Assets/Blueprints/skills/implement-spec/SKILL.md +34 -0
  35. package/build/Assets/Blueprints/skills/improve-codebase-architecture/HTML-REPORT.md +129 -0
  36. package/build/Assets/Blueprints/skills/improve-codebase-architecture/SKILL.md +74 -0
  37. package/build/Assets/Blueprints/skills/int-code-review/SKILL.md +76 -0
  38. package/build/Assets/Blueprints/skills/int-code-slop-review/SKILL.md +238 -0
  39. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_sections.md +36 -0
  40. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_template.md +42 -0
  41. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-closing-brace-labels.md +112 -0
  42. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-empty-docblocks.md +132 -0
  43. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-narration.md +118 -0
  44. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-placeholder.md +130 -0
  45. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-generic-catch.md +153 -0
  46. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-impossible-null.md +157 -0
  47. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-missing-real.md +157 -0
  48. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-generic-placeholders.md +120 -0
  49. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-over-descriptive.md +108 -0
  50. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-suffix-abuse.md +167 -0
  51. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-type-in-name.md +100 -0
  52. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-dependency-creep.md +114 -0
  53. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-premature-interface.md +136 -0
  54. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-single-method-class.md +161 -0
  55. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-useless-wrapper.md +140 -0
  56. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-as-any-escape.md +127 -0
  57. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-debug-artifacts.md +144 -0
  58. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-hyper-consistent.md +84 -0
  59. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-no-hack-scars.md +113 -0
  60. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-trivial-boilerplate.md +191 -0
  61. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-doesnt-throw.md +132 -0
  62. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mirror-implementation.md +125 -0
  63. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mock-everything.md +148 -0
  64. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-snapshot-abuse.md +131 -0
  65. package/build/Assets/Blueprints/skills/int-codebase-design/SKILL.md +116 -0
  66. package/build/Assets/Blueprints/skills/int-codebase-design/references/DEEPENING.md +37 -0
  67. package/build/Assets/Blueprints/skills/int-codebase-design/references/DESIGN-IT-TWICE.md +44 -0
  68. package/build/Assets/Blueprints/skills/int-domain-modeling/SKILL.md +78 -0
  69. package/build/Assets/Blueprints/skills/int-domain-modeling/references/ADR-FORMAT.md +47 -0
  70. package/build/Assets/Blueprints/skills/int-domain-modeling/references/GLOSSARY-FORMAT.md +60 -0
  71. package/build/Assets/Blueprints/skills/int-prototype/LOGIC.md +67 -0
  72. package/build/Assets/Blueprints/skills/int-prototype/SKILL.md +30 -0
  73. package/build/Assets/Blueprints/skills/int-prototype/UI.md +112 -0
  74. package/build/Assets/Blueprints/skills/int-retrospective/SKILL.md +88 -0
  75. package/build/Assets/Blueprints/skills/int-retrospective/assets/retrospective-prompt.md +38 -0
  76. package/build/Assets/Blueprints/skills/int-retrospective/references/assessment.md +56 -0
  77. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/SKILL.md +64 -0
  78. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/implementer-prompt.md +40 -0
  79. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/reviewer-prompt.md +43 -0
  80. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/aggregate-review.md +7 -0
  81. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/corrective-rounds.md +72 -0
  82. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/example-workflow.md +25 -0
  83. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/full-spec.md +72 -0
  84. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/implementer-corrections.md +9 -0
  85. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/review-inputs.md +26 -0
  86. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/verification-evidence.md +7 -0
  87. package/build/Assets/Blueprints/skills/int-test-driven-development/SKILL.md +51 -0
  88. package/build/Assets/Blueprints/skills/int-test-driven-development/references/mocking.md +31 -0
  89. package/build/Assets/Blueprints/skills/int-test-driven-development/references/tests.md +68 -0
  90. package/build/Assets/Blueprints/skills/int-testing-agent-guidance/SKILL.md +53 -0
  91. package/build/Assets/Blueprints/skills/int-verification-before-completion/SKILL.md +25 -0
  92. package/build/Assets/Blueprints/skills/int-writing-agents/SKILL.md +66 -0
  93. package/build/Assets/Blueprints/skills/int-writing-for-agents/SKILL.md +86 -0
  94. package/build/Assets/Blueprints/skills/int-writing-instruction/SKILL.md +57 -0
  95. package/build/Assets/Blueprints/skills/int-writing-skills/SKILL.md +129 -0
  96. package/build/Assets/Blueprints/skills/int-writing-skills/assets/interactive.md +83 -0
  97. package/build/Assets/Blueprints/skills/int-writing-skills/assets/reference.md +32 -0
  98. package/build/Assets/Blueprints/skills/int-writing-skills/references/arguments.md +50 -0
  99. package/build/Assets/Blueprints/skills/int-writing-skills/references/interactive-skills.md +53 -0
  100. package/build/Assets/Blueprints/skills/int-writing-skills/references/persuasion-principles.md +220 -0
  101. package/build/Assets/Blueprints/skills/int-writing-skills/references/reference-skills.md +20 -0
  102. package/build/Assets/Blueprints/skills/int-writing-skills/references/testing-skills.md +48 -0
  103. package/build/Assets/Blueprints/skills/retrospective/SKILL.md +16 -0
  104. package/build/Assets/Blueprints/skills/setup-project/SKILL.md +66 -0
  105. package/build/Assets/Blueprints/skills/to-spec/SKILL.md +53 -0
  106. package/build/Assets/Blueprints/skills/to-tickets/SKILL.md +49 -0
  107. package/build/Assets/Blueprints/skills/update-tooling/SKILL.md +86 -0
  108. package/build/Assets/Templates/Catalog.js +12 -0
  109. package/build/Assets/Templates/Catalog.ts +17 -0
  110. package/build/Assets/Templates/project/copilot-instructions.md +17 -0
  111. package/build/Assets/Templates/project/domain.md +51 -0
  112. package/build/Assets/Templates/project/ticket-tracker.md +33 -0
  113. package/build/Assets/Templates/sdd/design.md +25 -0
  114. package/build/Assets/Templates/sdd/spec.md +29 -0
  115. package/build/Assets/Templates/sdd/ticket.md +15 -0
  116. package/build/BlueprintManagement/BlueprintManagementServiceProvider.js +15 -0
  117. package/build/BlueprintManagement/Catalog/BlueprintCatalog.js +238 -0
  118. package/build/BlueprintManagement/Commands/BlueprintCommandOptions.js +9 -0
  119. package/build/BlueprintManagement/Commands/ConflictPolicy.js +6 -0
  120. package/build/BlueprintManagement/Commands/InitCommand.js +117 -0
  121. package/build/BlueprintManagement/Commands/Prompts.js +66 -0
  122. package/build/BlueprintManagement/Commands/UpdateCommand.js +86 -0
  123. package/build/BlueprintManagement/Handlers/Agents/AgentHandler.js +21 -0
  124. package/build/BlueprintManagement/Handlers/BlueprintHandlers.js +4 -0
  125. package/build/BlueprintManagement/Handlers/Instructions/InstructionHandler.js +21 -0
  126. package/build/BlueprintManagement/Handlers/Skills/SkillHandler.js +10 -0
  127. package/build/BlueprintManagement/Reconciliation/BlueprintCatalogPlanner.js +87 -0
  128. package/build/BlueprintManagement/Reconciliation/BlueprintRemovalCoordinator.js +78 -0
  129. package/build/BlueprintManagement/Services/BlueprintReconciliationService.js +391 -0
  130. package/build/BlueprintManagement/Services/InstallationService.js +54 -0
  131. package/build/BlueprintManagement/Support/BlueprintFiles.js +113 -0
  132. package/build/BlueprintManagement/Types/Blueprint.js +1 -0
  133. package/build/BlueprintManagement/Types/Installation.js +1 -0
  134. package/build/BlueprintManagement/Types/Reconciliation.js +1 -0
  135. package/build/BlueprintManagement/Versioning/BlueprintVersion.js +70 -0
  136. package/build/BlueprintManagement/Versioning/BlueprintVersioning.js +55 -0
  137. package/build/Commands/Command.js +3 -0
  138. package/build/Commands/CommandOptions.js +12 -0
  139. package/build/Config/Config.js +3 -0
  140. package/build/Foundation/Application.js +112 -0
  141. package/build/Foundation/ApplicationBuilder.js +23 -0
  142. package/build/Foundation/Bootstrap/Bootstrapper.js +2 -0
  143. package/build/Foundation/Bootstrap/DiscoverGitRoot.js +8 -0
  144. package/build/Foundation/Bootstrap/LoadConsoleArgs.js +47 -0
  145. package/build/Foundation/Bootstrap/LoadProjectConfiguration.js +144 -0
  146. package/build/Foundation/Bootstrap/RegisterProviders.js +12 -0
  147. package/build/Foundation/Bootstrap/RequireProjectConfiguration.js +14 -0
  148. package/build/Foundation/ConsoleInvocation.js +1 -0
  149. package/build/Foundation/Container.js +185 -0
  150. package/build/Foundation/FoundationServiceProvider.js +5 -0
  151. package/build/Foundation/Kernel.js +30 -0
  152. package/build/Foundation/Service.js +23 -0
  153. package/build/Foundation/ServiceProvider.js +12 -0
  154. package/build/Git/GitServiceProvider.js +8 -0
  155. package/build/Git/Services/GitService.js +26 -0
  156. package/build/Project/ProjectServiceProvider.js +8 -0
  157. package/build/Project/Services/ProjectService.js +124 -0
  158. package/build/SubagentDrivenDevelopment/Commands/ChecksRecordCommand.js +35 -0
  159. package/build/SubagentDrivenDevelopment/Commands/ChecksRequireCommand.js +33 -0
  160. package/build/SubagentDrivenDevelopment/Commands/ClaimCommand.js +23 -0
  161. package/build/SubagentDrivenDevelopment/Commands/CorrectCommand.js +37 -0
  162. package/build/SubagentDrivenDevelopment/Commands/CreateCommand.js +26 -0
  163. package/build/SubagentDrivenDevelopment/Commands/FindingCreateCommand.js +39 -0
  164. package/build/SubagentDrivenDevelopment/Commands/FindingUpdateCommand.js +36 -0
  165. package/build/SubagentDrivenDevelopment/Commands/FinishCommand.js +23 -0
  166. package/build/SubagentDrivenDevelopment/Commands/ImplementCommand.js +23 -0
  167. package/build/SubagentDrivenDevelopment/Commands/NextCommand.js +21 -0
  168. package/build/SubagentDrivenDevelopment/Commands/ReadyCommand.js +21 -0
  169. package/build/SubagentDrivenDevelopment/Commands/RequirementsDecideCommand.js +33 -0
  170. package/build/SubagentDrivenDevelopment/Commands/ResumeCommand.js +31 -0
  171. package/build/SubagentDrivenDevelopment/Commands/ReviewCommand.js +55 -0
  172. package/build/SubagentDrivenDevelopment/Commands/ReviewRequireCommand.js +12 -0
  173. package/build/SubagentDrivenDevelopment/Commands/StatusCommand.js +21 -0
  174. package/build/SubagentDrivenDevelopment/Commands/SubmitCommand.js +59 -0
  175. package/build/SubagentDrivenDevelopment/Commands/TicketCommentCommand.js +24 -0
  176. package/build/SubagentDrivenDevelopment/Commands/TicketCreateCommand.js +25 -0
  177. package/build/SubagentDrivenDevelopment/Commands/TicketUpdateCommand.js +31 -0
  178. package/build/SubagentDrivenDevelopment/Commands/groups.js +36 -0
  179. package/build/SubagentDrivenDevelopment/Evidence/GitEvidence.js +449 -0
  180. package/build/SubagentDrivenDevelopment/Evidence/ReportEvidence.js +80 -0
  181. package/build/SubagentDrivenDevelopment/Models/Assignments.js +1 -0
  182. package/build/SubagentDrivenDevelopment/Models/Evidence.js +1 -0
  183. package/build/SubagentDrivenDevelopment/Models/Findings.js +1 -0
  184. package/build/SubagentDrivenDevelopment/Models/Options.js +1 -0
  185. package/build/SubagentDrivenDevelopment/Models/Workflow.js +16 -0
  186. package/build/SubagentDrivenDevelopment/Persistence/AssignmentSchema.js +155 -0
  187. package/build/SubagentDrivenDevelopment/Persistence/CheckSchema.js +71 -0
  188. package/build/SubagentDrivenDevelopment/Persistence/FeatureWorkspace.js +76 -0
  189. package/build/SubagentDrivenDevelopment/Persistence/FileSystem.js +28 -0
  190. package/build/SubagentDrivenDevelopment/Persistence/FindingSchema.js +81 -0
  191. package/build/SubagentDrivenDevelopment/Persistence/LedgerRepository.js +322 -0
  192. package/build/SubagentDrivenDevelopment/Persistence/PathSafety.js +62 -0
  193. package/build/SubagentDrivenDevelopment/Persistence/ProgressSchema.js +95 -0
  194. package/build/SubagentDrivenDevelopment/Persistence/ReadinessReader.js +40 -0
  195. package/build/SubagentDrivenDevelopment/Persistence/ReviewSchema.js +68 -0
  196. package/build/SubagentDrivenDevelopment/Persistence/TicketRepository.js +147 -0
  197. package/build/SubagentDrivenDevelopment/Persistence/WorkspaceTransaction.js +282 -0
  198. package/build/SubagentDrivenDevelopment/Policies/AcceptancePolicy.js +100 -0
  199. package/build/SubagentDrivenDevelopment/Policies/AssignmentPolicy.js +36 -0
  200. package/build/SubagentDrivenDevelopment/Policies/CheckPolicy.js +93 -0
  201. package/build/SubagentDrivenDevelopment/Policies/FindingPolicy.js +53 -0
  202. package/build/SubagentDrivenDevelopment/Policies/InputValidation.js +36 -0
  203. package/build/SubagentDrivenDevelopment/Policies/ReadinessPolicy.js +26 -0
  204. package/build/SubagentDrivenDevelopment/Policies/RequiredReviewers.js +12 -0
  205. package/build/SubagentDrivenDevelopment/Policies/ReviewPolicy.js +87 -0
  206. package/build/SubagentDrivenDevelopment/Policies/WorkflowPolicy.js +85 -0
  207. package/build/SubagentDrivenDevelopment/Services/AssignmentService.js +269 -0
  208. package/build/SubagentDrivenDevelopment/Services/ChecksService.js +319 -0
  209. package/build/SubagentDrivenDevelopment/Services/CorrectionService.js +273 -0
  210. package/build/SubagentDrivenDevelopment/Services/DeliveryCorrectionService.js +253 -0
  211. package/build/SubagentDrivenDevelopment/Services/DeliveryFindingService.js +302 -0
  212. package/build/SubagentDrivenDevelopment/Services/DeliveryService.js +160 -0
  213. package/build/SubagentDrivenDevelopment/Services/DeliverySubmissionService.js +273 -0
  214. package/build/SubagentDrivenDevelopment/Services/FeatureCreationService.js +138 -0
  215. package/build/SubagentDrivenDevelopment/Services/FeatureInspectionService.js +399 -0
  216. package/build/SubagentDrivenDevelopment/Services/FindingService.js +392 -0
  217. package/build/SubagentDrivenDevelopment/Services/IntegrationService.js +258 -0
  218. package/build/SubagentDrivenDevelopment/Services/ReadinessService.js +21 -0
  219. package/build/SubagentDrivenDevelopment/Services/RequirementsService.js +216 -0
  220. package/build/SubagentDrivenDevelopment/Services/ReviewService.js +471 -0
  221. package/build/SubagentDrivenDevelopment/Services/SubmissionService.js +299 -0
  222. package/build/SubagentDrivenDevelopment/Services/TicketService.js +186 -0
  223. package/build/SubagentDrivenDevelopment/SubagentDrivenDevelopmentServiceProvider.js +113 -0
  224. package/build/Support/Records.js +5 -0
  225. package/build/Support/Repository.js +139 -0
  226. package/build/Support/Stacks.js +10 -0
  227. package/build/TemplateRendering/Computed/ComputedContextService.js +13 -0
  228. package/build/TemplateRendering/Computed/ComputedVariableProvider.js +6 -0
  229. package/build/TemplateRendering/Computed/ComputedVariableProviders.js +6 -0
  230. package/build/TemplateRendering/Computed/Providers/InternalSkillDescriptionProvider.js +6 -0
  231. package/build/TemplateRendering/Computed/Providers/SpindlePackageManagerProvider.js +11 -0
  232. package/build/TemplateRendering/Computed/ResolveRenderContext.js +18 -0
  233. package/build/TemplateRendering/Rendering/RenderText.js +43 -0
  234. package/build/TemplateRendering/TemplateRenderingServiceProvider.js +8 -0
  235. package/build/Tooling/Commands/ToolingAddCommand.js +29 -0
  236. package/build/Tooling/Commands/ToolingListCommand.js +19 -0
  237. package/build/Tooling/Commands/ToolingRemoveCommand.js +19 -0
  238. package/build/Tooling/Commands/ToolingUpdateCommand.js +30 -0
  239. package/build/Tooling/Commands/groups.js +4 -0
  240. package/build/Tooling/Models/ToolingEntry.js +1 -0
  241. package/build/Tooling/Services/ToolingService.js +278 -0
  242. package/build/Tooling/ToolingServiceProvider.js +15 -0
  243. package/build/cli.js +36 -0
  244. package/build/index.js +31 -0
  245. package/package.json +54 -3
@@ -0,0 +1,155 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { isCheckRecord } from "./CheckSchema.js";
3
+ import { isReviewAssignment } from "./ReviewSchema.js";
4
+ import { Records } from "../../Support/Records.js";
5
+ const isRecord = Records.isRecord;
6
+ export function isImplementationAssignment(value) {
7
+ if (!isRecord(value) ||
8
+ typeof value.id !== "string" ||
9
+ !value.id.trim() ||
10
+ value.role !== "implementation" ||
11
+ !["implement", "correct"].includes(String(value.action)) ||
12
+ typeof value.controller !== "string" ||
13
+ !value.controller.trim() ||
14
+ typeof value.report !== "string" ||
15
+ !isAbsolute(value.report) ||
16
+ typeof value.requestedAt !== "string" ||
17
+ !Number.isFinite(Date.parse(value.requestedAt)) ||
18
+ !["pending", "submitted", "unavailable"].includes(String(value.status)) ||
19
+ !Array.isArray(value.handoffs) ||
20
+ !value.handoffs.every((handoff) => isRecord(handoff) &&
21
+ typeof handoff.at === "string" &&
22
+ Number.isFinite(Date.parse(handoff.at)) &&
23
+ typeof handoff.from === "string" &&
24
+ handoff.from.trim() &&
25
+ typeof handoff.to === "string" &&
26
+ handoff.to.trim() &&
27
+ handoff.confirmedStopped === true)) {
28
+ return false;
29
+ }
30
+ if (value.action === "correct") {
31
+ if (!Number.isSafeInteger(value.attempt) ||
32
+ Number(value.attempt) < 1 ||
33
+ !Array.isArray(value.findingIds) ||
34
+ !value.findingIds.every((id) => typeof id === "string" && /^F-\d{4,}$/.test(id)) ||
35
+ new Set(value.findingIds).size !== value.findingIds.length ||
36
+ (value.findingIds.length === 0 &&
37
+ (typeof value.checkFailure !== "string" || !value.checkFailure.trim())) ||
38
+ typeof value.objective !== "string" ||
39
+ !value.objective.trim()) {
40
+ return false;
41
+ }
42
+ }
43
+ else if (Object.hasOwn(value, "attempt") ||
44
+ Object.hasOwn(value, "findingIds") ||
45
+ Object.hasOwn(value, "checkFailure") ||
46
+ Object.hasOwn(value, "objective")) {
47
+ return false;
48
+ }
49
+ if (value.status === "submitted") {
50
+ return (typeof value.reportSha256 === "string" &&
51
+ /^[0-9a-f]{64}$/i.test(value.reportSha256) &&
52
+ typeof value.submittedAt === "string" &&
53
+ Number.isFinite(Date.parse(value.submittedAt)) &&
54
+ typeof value.submittedBy === "string" &&
55
+ !!value.submittedBy.trim());
56
+ }
57
+ if (value.status === "unavailable") {
58
+ return typeof value.unavailableDetails === "string" && !!value.unavailableDetails.trim();
59
+ }
60
+ return true;
61
+ }
62
+ export function isCorrectionAttempt(value) {
63
+ if (!isRecord(value) ||
64
+ !Number.isSafeInteger(value.number) ||
65
+ Number(value.number) < 1 ||
66
+ !Array.isArray(value.findingIds) ||
67
+ !value.findingIds.every((finding) => typeof finding === "string" && /^F-\d{4,}$/.test(finding)) ||
68
+ new Set(value.findingIds).size !== value.findingIds.length ||
69
+ (value.findingIds.length === 0 &&
70
+ (typeof value.checkFailure !== "string" || !value.checkFailure.trim())) ||
71
+ typeof value.objective !== "string" ||
72
+ !value.objective.trim() ||
73
+ typeof value.startedAt !== "string" ||
74
+ !Number.isFinite(Date.parse(value.startedAt)) ||
75
+ typeof value.startedBy !== "string" ||
76
+ !value.startedBy.trim() ||
77
+ typeof value.assignmentId !== "string" ||
78
+ !value.assignmentId.trim() ||
79
+ !isImplementationAssignment(value.assignment) ||
80
+ value.assignment.id !== value.assignmentId ||
81
+ value.assignment.action !== "correct" ||
82
+ value.assignment.attempt !== value.number ||
83
+ (Object.hasOwn(value, "priorAssignment") &&
84
+ !isImplementationAssignment(value.priorAssignment)) ||
85
+ (Object.hasOwn(value, "checks") &&
86
+ (!Array.isArray(value.checks) || !value.checks.every(isCheckRecord))) ||
87
+ (Object.hasOwn(value, "reviewAssignments") &&
88
+ (!Array.isArray(value.reviewAssignments) ||
89
+ !value.reviewAssignments.every(isReviewAssignment)))) {
90
+ return false;
91
+ }
92
+ if (Object.hasOwn(value, "progressAssessment")) {
93
+ const assessment = value.progressAssessment;
94
+ if (!isRecord(assessment) ||
95
+ assessment.decision !== "continue" ||
96
+ assessment.result !== "productive" ||
97
+ typeof assessment.details !== "string" ||
98
+ !assessment.details.trim() ||
99
+ typeof assessment.recordedAt !== "string" ||
100
+ !Number.isFinite(Date.parse(assessment.recordedAt)) ||
101
+ typeof assessment.recordedBy !== "string" ||
102
+ !assessment.recordedBy.trim()) {
103
+ return false;
104
+ }
105
+ }
106
+ if (Object.hasOwn(value, "outcome")) {
107
+ const outcome = value.outcome;
108
+ if (!isRecord(outcome) ||
109
+ !["productive", "unproductive"].includes(String(outcome.result)) ||
110
+ typeof outcome.details !== "string" ||
111
+ !outcome.details.trim() ||
112
+ typeof outcome.recordedAt !== "string" ||
113
+ !Number.isFinite(Date.parse(outcome.recordedAt)) ||
114
+ typeof outcome.recordedBy !== "string" ||
115
+ !outcome.recordedBy.trim() ||
116
+ (Object.hasOwn(outcome, "snapshot") &&
117
+ (typeof outcome.snapshot !== "string" || !/^[0-9a-f]{64}$/i.test(outcome.snapshot)))) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ export function isCorrectionAdjudication(value) {
124
+ if (isRecord(value) &&
125
+ ["pending", "resolved"].includes(String(value.status)) &&
126
+ typeof value.reason === "string" &&
127
+ !!value.reason.trim() &&
128
+ typeof value.details === "string" &&
129
+ !!value.details.trim() &&
130
+ typeof value.recordedAt === "string" &&
131
+ Number.isFinite(Date.parse(value.recordedAt)) &&
132
+ typeof value.recordedBy === "string" &&
133
+ !!value.recordedBy.trim()) {
134
+ return value.status === "pending"
135
+ ? !Object.hasOwn(value, "resolution")
136
+ : isRecord(value.resolution) &&
137
+ typeof value.resolution.details === "string" &&
138
+ !!value.resolution.details.trim() &&
139
+ typeof value.resolution.recordedAt === "string" &&
140
+ Number.isFinite(Date.parse(value.resolution.recordedAt)) &&
141
+ typeof value.resolution.recordedBy === "string" &&
142
+ !!value.resolution.recordedBy.trim();
143
+ }
144
+ return false;
145
+ }
146
+ export function hasMatchingCorrectionAttempt(ticket) {
147
+ const assignment = ticket.assignment;
148
+ if (!isImplementationAssignment(assignment) || assignment.action !== "correct")
149
+ return true;
150
+ const attempts = ticket.correctionAttempts;
151
+ return (Array.isArray(attempts) &&
152
+ attempts.some((attempt) => isCorrectionAttempt(attempt) &&
153
+ attempt.number === assignment.attempt &&
154
+ attempt.assignmentId === assignment.id));
155
+ }
@@ -0,0 +1,71 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { Records } from "../../Support/Records.js";
3
+ const isRecord = Records.isRecord;
4
+ export function isCheckRequirement(value) {
5
+ if (!isRecord(value) ||
6
+ typeof value.command !== "string" ||
7
+ !value.command.trim() ||
8
+ typeof value.addedAt !== "string" ||
9
+ !Number.isFinite(Date.parse(value.addedAt)) ||
10
+ typeof value.addedBy !== "string" ||
11
+ !value.addedBy.trim()) {
12
+ return false;
13
+ }
14
+ const removed = Object.hasOwn(value, "removedAt");
15
+ return (!removed ||
16
+ (typeof value.removedAt === "string" &&
17
+ Number.isFinite(Date.parse(value.removedAt)) &&
18
+ typeof value.removedBy === "string" &&
19
+ !!value.removedBy.trim() &&
20
+ typeof value.removalDetails === "string" &&
21
+ !!value.removalDetails.trim()));
22
+ }
23
+ export function isCheckRecord(value) {
24
+ if (isRecord(value) &&
25
+ typeof value.command === "string" &&
26
+ !!value.command.trim() &&
27
+ ["passed", "failed", "unavailable"].includes(String(value.result)) &&
28
+ typeof value.author === "string" &&
29
+ !!value.author.trim() &&
30
+ typeof value.snapshot === "string" &&
31
+ /^[0-9a-f]{64}$/i.test(value.snapshot) &&
32
+ typeof value.codeSnapshot === "string" &&
33
+ /^[0-9a-f]{64}$/i.test(value.codeSnapshot) &&
34
+ typeof value.requirementsSnapshot === "string" &&
35
+ /^[0-9a-f]{64}$/i.test(value.requirementsSnapshot) &&
36
+ typeof value.headSha === "string" &&
37
+ /^[0-9a-f]{40,64}$/i.test(value.headSha) &&
38
+ typeof value.recordedAt === "string" &&
39
+ Number.isFinite(Date.parse(value.recordedAt)) &&
40
+ (value.result === "passed" || (typeof value.details === "string" && !!value.details.trim()))) {
41
+ const hasScope = Object.hasOwn(value, "coveredPaths") || Object.hasOwn(value, "coverageSnapshot");
42
+ return (!hasScope ||
43
+ (Array.isArray(value.coveredPaths) &&
44
+ value.coveredPaths.length > 0 &&
45
+ value.coveredPaths.every(isSafeCoveragePath) &&
46
+ new Set(value.coveredPaths).size === value.coveredPaths.length &&
47
+ typeof value.coverageSnapshot === "string" &&
48
+ /^[0-9a-f]{64}$/i.test(value.coverageSnapshot)));
49
+ }
50
+ return false;
51
+ }
52
+ export function isCheckGateInvalidation(value) {
53
+ return (isRecord(value) &&
54
+ typeof value.at === "string" &&
55
+ Number.isFinite(Date.parse(value.at)) &&
56
+ typeof value.author === "string" &&
57
+ !!value.author.trim() &&
58
+ typeof value.command === "string" &&
59
+ !!value.command.trim() &&
60
+ ["accepted", "integrated"].includes(String(value.from)) &&
61
+ value.to === "reviewing");
62
+ }
63
+ export function isSafeCoveragePath(value) {
64
+ return (typeof value === "string" &&
65
+ !!value &&
66
+ !isAbsolute(value) &&
67
+ !value.includes("\\") &&
68
+ value.split("/").every((segment) => !!segment && segment !== "." && segment !== "..") &&
69
+ value !== ".scratch" &&
70
+ !value.startsWith(".scratch/"));
71
+ }
@@ -0,0 +1,76 @@
1
+ import { readFileSync, readdirSync, realpathSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+ import { Service } from "../../Foundation/Service.js";
4
+ import { FEATURE_DIRECTORY, HISTORICAL_DATE_DIRECTORY, } from "../Models/Workflow.js";
5
+ import { assertRealDirectory, lstatIfPresent, isPathInside, } from "./FileSystem.js";
6
+ export class FeatureWorkspace extends Service {
7
+ ledgerRepository;
8
+ pathSafety;
9
+ constructor(app, ledgerRepository, pathSafety) {
10
+ super(app);
11
+ this.ledgerRepository = ledgerRepository;
12
+ this.pathSafety = pathSafety;
13
+ }
14
+ statusFromPaths(root, specPath, relativeSpec, segments) {
15
+ const scratch = join(root, ".scratch");
16
+ const workspace = join(scratch, segments[1]);
17
+ const ledgerPath = join(workspace, "sdd.json");
18
+ assertRealDirectory(scratch, ".scratch");
19
+ assertRealDirectory(workspace, "Feature workspace");
20
+ for (const directory of ["tickets", "reports"]) {
21
+ assertRealDirectory(join(workspace, directory), `Feature ${directory} directory`);
22
+ }
23
+ const specEntry = lstatIfPresent(specPath);
24
+ if (!specEntry?.isFile())
25
+ throw new Error("Feature spec must be a regular file.");
26
+ const ledgerEntry = lstatIfPresent(ledgerPath);
27
+ if (!ledgerEntry?.isFile())
28
+ throw new Error("Feature ledger must be a regular file.");
29
+ if (!isPathInside(root, realpathSync(specPath)) ||
30
+ !isPathInside(root, realpathSync(ledgerPath))) {
31
+ throw new Error("Feature files must remain inside this checkout.");
32
+ }
33
+ for (const path of [relativeSpec, relative(root, ledgerPath)]) {
34
+ if (this.pathSafety.isIgnored(root, path))
35
+ throw new Error(`Feature path is ignored: ${path}`);
36
+ }
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(readFileSync(ledgerPath, "utf8"));
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Feature ledger is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
43
+ }
44
+ const state = this.ledgerRepository.validateLedger(parsed, segments[1]);
45
+ const feature = segments[1];
46
+ return {
47
+ feature,
48
+ workspace,
49
+ spec: specPath,
50
+ ledger: ledgerPath,
51
+ state,
52
+ };
53
+ }
54
+ nextFeatureId(scratch) {
55
+ let highest = 0n;
56
+ for (const entry of readdirSync(scratch, { withFileTypes: true })) {
57
+ if (!entry.isDirectory() || HISTORICAL_DATE_DIRECTORY.test(entry.name))
58
+ continue;
59
+ const match = FEATURE_DIRECTORY.exec(entry.name);
60
+ if (!match)
61
+ continue;
62
+ const id = BigInt(match[1]);
63
+ if (id > highest)
64
+ highest = id;
65
+ }
66
+ return String(highest + 1n).padStart(4, "0");
67
+ }
68
+ rejectAbandonedStaging(scratch) {
69
+ const abandoned = readdirSync(scratch, { withFileTypes: true })
70
+ .filter((entry) => entry.name.startsWith(".sdd-create-"))
71
+ .map((entry) => join(scratch, entry.name));
72
+ if (abandoned.length > 0) {
73
+ throw new Error(`Incomplete feature creation staging content was preserved at ${abandoned.join(", ")}. Inspect and remove it before retrying.`);
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,28 @@
1
+ import { lstatSync } from "node:fs";
2
+ import { isAbsolute, relative, sep } from "node:path";
3
+ export function assertRealDirectory(path, label) {
4
+ const entry = lstatSync(path, { throwIfNoEntry: false });
5
+ if (entry && !entry.isDirectory()) {
6
+ throw new Error(`${label} must be a real directory, not a file or symlink.`);
7
+ }
8
+ }
9
+ export function lstatIfPresent(path) {
10
+ try {
11
+ return lstatSync(path);
12
+ }
13
+ catch (error) {
14
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
15
+ return undefined;
16
+ }
17
+ throw error;
18
+ }
19
+ }
20
+ export function waitBriefly() {
21
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 20);
22
+ }
23
+ export function isPathInside(parent, child) {
24
+ const relativePath = relative(parent, child);
25
+ return (relativePath === "" ||
26
+ (!isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(`..${sep}`)));
27
+ }
28
+ export const LOCK_TIMEOUT_MS = 15_000;
@@ -0,0 +1,81 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { Records } from "../../Support/Records.js";
3
+ const isRecord = Records.isRecord;
4
+ export function isReviewFinding(value) {
5
+ return (isRecord(value) &&
6
+ typeof value.id === "string" &&
7
+ /^F-\d{4,}$/.test(value.id) &&
8
+ (!Object.hasOwn(value, "relatedTicket") ||
9
+ (typeof value.relatedTicket === "string" && /^T-\d{4,}$/.test(value.relatedTicket))) &&
10
+ ["high", "medium", "low"].includes(String(value.severity)) &&
11
+ typeof value.blocking === "boolean" &&
12
+ ["open", "confirmed", "fixed", "dismissed", "deferred"].includes(String(value.status)) &&
13
+ typeof value.summary === "string" &&
14
+ !!value.summary.trim() &&
15
+ typeof value.details === "string" &&
16
+ !!value.details.trim() &&
17
+ typeof value.author === "string" &&
18
+ !!value.author.trim() &&
19
+ typeof value.createdAt === "string" &&
20
+ Number.isFinite(Date.parse(value.createdAt)) &&
21
+ Array.isArray(value.provenance) &&
22
+ value.provenance.length > 0 &&
23
+ value.provenance.every((source) => isRecord(source) &&
24
+ typeof source.report === "string" &&
25
+ isAbsolute(source.report) &&
26
+ typeof source.snapshot === "string" &&
27
+ /^[0-9a-f]{64}$/i.test(source.snapshot) &&
28
+ typeof source.author === "string" &&
29
+ !!source.author.trim() &&
30
+ typeof source.summary === "string" &&
31
+ !!source.summary.trim() &&
32
+ typeof source.details === "string" &&
33
+ !!source.details.trim()) &&
34
+ Array.isArray(value.history) &&
35
+ value.history.every((entry) => isRecord(entry) &&
36
+ typeof entry.at === "string" &&
37
+ Number.isFinite(Date.parse(entry.at)) &&
38
+ typeof entry.author === "string" &&
39
+ !!entry.author.trim() &&
40
+ typeof entry.action === "string" &&
41
+ !!entry.action.trim() &&
42
+ typeof entry.details === "string" &&
43
+ !!entry.details.trim()) &&
44
+ (value.status !== "dismissed" ||
45
+ (typeof value.rulingDetails === "string" && !!value.rulingDetails.trim())) &&
46
+ (value.status !== "deferred" ||
47
+ (typeof value.rulingDetails === "string" &&
48
+ !!value.rulingDetails.trim() &&
49
+ typeof value.followUp === "string" &&
50
+ !!value.followUp.trim())) &&
51
+ (!Object.hasOwn(value, "requirementsDecision") ||
52
+ (typeof value.requirementsDecision === "string" &&
53
+ /^R-\d{4,}$/.test(value.requirementsDecision))) &&
54
+ (value.status !== "fixed" ||
55
+ (isRecord(value.verification) &&
56
+ typeof value.verification.snapshot === "string" &&
57
+ /^[0-9a-f]{64}$/i.test(value.verification.snapshot) &&
58
+ Array.isArray(value.verification.checkCommands) &&
59
+ value.verification.checkCommands.length > 0 &&
60
+ value.verification.checkCommands.every((command) => typeof command === "string" && !!command.trim()) &&
61
+ typeof value.verification.verifiedAt === "string" &&
62
+ Number.isFinite(Date.parse(value.verification.verifiedAt)) &&
63
+ typeof value.verification.verifiedBy === "string" &&
64
+ !!value.verification.verifiedBy.trim())));
65
+ }
66
+ export function isRequirementsDecision(value) {
67
+ return (isRecord(value) &&
68
+ typeof value.id === "string" &&
69
+ /^R-\d{4,}$/.test(value.id) &&
70
+ typeof value.finding === "string" &&
71
+ /^F-\d{4,}$/.test(value.finding) &&
72
+ ["approved", "rejected"].includes(String(value.status)) &&
73
+ typeof value.details === "string" &&
74
+ !!value.details.trim() &&
75
+ typeof value.author === "string" &&
76
+ !!value.author.trim() &&
77
+ typeof value.requirementsSnapshot === "string" &&
78
+ /^[0-9a-f]{64}$/i.test(value.requirementsSnapshot) &&
79
+ typeof value.recordedAt === "string" &&
80
+ Number.isFinite(Date.parse(value.recordedAt)));
81
+ }