@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,51 @@
1
+ # Domain Docs
2
+
3
+ How the engineering skills should consume this repo's domain documentation when exploring the codebase.
4
+
5
+ ## Before exploring, read these
6
+
7
+ - **`GLOSSARY.md`** at the repo root, or
8
+ - **`GLOSSARY-MAP.md`** at the repo root if it exists: it points at one `GLOSSARY.md` per context. Read each one relevant to the topic.
9
+ - **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
10
+
11
+ If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `int-domain-modeling` skill (reached via the `/grill-with-docs` skill and `/improve-codebase-architecture` skill) creates them lazily when terms or decisions actually get resolved.
12
+
13
+ ## File structure
14
+
15
+ Single-context repo (most repos):
16
+
17
+ ```
18
+ /
19
+ ├── GLOSSARY.md
20
+ ├── docs/adr/
21
+ │ ├── 0001-event-sourced-orders.md
22
+ │ └── 0002-postgres-for-write-model.md
23
+ └── src/
24
+ ```
25
+
26
+ Multi-context repo (presence of `GLOSSARY-MAP.md` at the root):
27
+
28
+ ```
29
+ /
30
+ ├── GLOSSARY-MAP.md
31
+ ├── docs/adr/ ← system-wide decisions
32
+ └── src/
33
+ ├── ordering/
34
+ │ ├── GLOSSARY.md
35
+ │ └── docs/adr/ ← context-specific decisions
36
+ └── billing/
37
+ ├── GLOSSARY.md
38
+ └── docs/adr/
39
+ ```
40
+
41
+ ## Use the glossary's vocabulary
42
+
43
+ When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `GLOSSARY.md`. Don't drift to synonyms the glossary explicitly avoids.
44
+
45
+ If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for the `int-domain-modeling` skill).
46
+
47
+ ## Flag ADR conflicts
48
+
49
+ If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
50
+
51
+ > _Contradicts ADR-0007 (event-sourced orders), but worth reopening because…_
@@ -0,0 +1,33 @@
1
+ # Ticket Tracker: Local Markdown
2
+
3
+ Spindle SDD stores feature work in `.scratch/` workspaces. A workspace contains an approved `spec.md`, its `sdd.json` execution ledger, `tickets/`, and `reports/`. A design is optional; when present, complete and approve it before the spec. Derive tickets from the approved spec.
4
+
5
+ ## Ticket format
6
+
7
+ - Each ticket is `tickets/T-0001.md`, with IDs starting at `T-0001` independently in each feature. IDs use at least four digits.
8
+ - `sdd.json` is authoritative for ticket metadata, status, dependencies, and execution state. Ticket Markdown contains only its ID in YAML front matter; requirements, acceptance criteria, and comments are the editable body.
9
+ - Ticket creation copies the shared template, including `[REQUIREMENTS]` and `[ACCEPTANCE CRITERIA]` placeholders. Fill both before implementation.
10
+ - Supported status values are `open`, `in-progress`, and `closed`. Dependencies must refer to existing tickets; cycles are rejected.
11
+ - There is no migration or compatibility support for `issues/`, `I-####`, or previous SDD ledger schemas. Create a fresh feature workspace when using this ticket format.
12
+
13
+ ## Create and maintain tickets
14
+
15
+ Create each approved ticket in dependency order:
16
+
17
+ ```sh
18
+ spindle sdd ticket create --spec <absolute-spec-path> --title "..." --reporter "..." --category enhancement --author maintainer
19
+ ```
20
+
21
+ The command returns the new ticket ID and path. Complete its template, then set dependencies with `ticket update`:
22
+
23
+ ```sh
24
+ spindle sdd ticket update --spec <absolute-spec-path> --ticket T-0002 --blocked-by T-0001 --author maintainer
25
+ spindle sdd ticket comment --spec <absolute-spec-path> --ticket T-0001 --details "..." --author maintainer
26
+ spindle sdd ready --spec <absolute-spec-path>
27
+ ```
28
+
29
+ Use `--clear-blocked-by` to remove dependencies. Use `ticket update --status` to change status. Ticket Markdown remains editable; attributed comments are appended under `## Comments`. Do not add an execution field to the ticket file: execution transitions are recorded in `sdd.json`.
30
+
31
+ ## Delivery
32
+
33
+ Use `spindle sdd status` and `spindle sdd ready` to inspect work. Claim and dispatch ready tickets with `spindle sdd claim` and `spindle sdd implement`, submit the assigned report with `spindle sdd submit`, and close completed tickets with `spindle sdd ticket update --status closed`. Follow the `int-subagent-driven-dev` skill for review, correction, and feature completion.
@@ -0,0 +1,25 @@
1
+ # {{ variables.title | default("[FEATURE TITLE]") }}
2
+
3
+ ## Intent
4
+
5
+ {{ variables.intent | default("[INTENT]") }}
6
+
7
+ ## Success Criteria
8
+
9
+ {{ variables.success_criteria | default("[SUCCESS CRITERIA]") }}
10
+
11
+ ## Scope and Constraints
12
+
13
+ {{ variables.scope_and_constraints | default("[SCOPE AND CONSTRAINTS]") }}
14
+
15
+ ## Approaches Considered
16
+
17
+ {{ variables.approaches_and_trade_offs | default("[APPROACHES AND TRADE-OFFS]") }}
18
+
19
+ ## Selected Direction
20
+
21
+ {{ variables.selected_direction | default("[SELECTED DIRECTION]") }}
22
+
23
+ ## Assumptions and Open Decisions
24
+
25
+ {{ variables.assumptions_and_open_decisions | default("[ASSUMPTIONS AND OPEN DECISIONS]") }}
@@ -0,0 +1,29 @@
1
+ # {{ variables.title | default("[FEATURE TITLE]") }}
2
+
3
+ ## Problem Statement
4
+
5
+ {{ variables.problem_statement | default("[PROBLEM STATEMENT]") }}
6
+
7
+ ## Solution
8
+
9
+ {{ variables.solution | default("[SOLUTION]") }}
10
+
11
+ ## User Stories
12
+
13
+ {{ variables.user_stories | default("[USER STORIES]") }}
14
+
15
+ ## Implementation Decisions
16
+
17
+ {{ variables.implementation_decisions | default("[IMPLEMENTATION DECISIONS]") }}
18
+
19
+ ## Testing Decisions
20
+
21
+ {{ variables.testing_decisions | default("[TESTING DECISIONS]") }}
22
+
23
+ ## Out of Scope
24
+
25
+ {{ variables.out_of_scope | default("[OUT OF SCOPE]") }}
26
+
27
+ ## Further Notes
28
+
29
+ {{ variables.further_notes | default("[FURTHER NOTES]") }}
@@ -0,0 +1,15 @@
1
+ # {{ variables.title | default("[TICKET TITLE]") }}
2
+
3
+ - **Reporter:** {{ variables.reporter | default("[REPORTER]") }}
4
+ - **Category:** {{ variables.category | default("[CATEGORY]") }}
5
+ - **Author:** {{ variables.author | default("[AUTHOR]") }}
6
+
7
+ ## Requirements
8
+
9
+ {{ variables.requirements | default("[REQUIREMENTS]") }}
10
+
11
+ ## Acceptance Criteria
12
+
13
+ {{ variables.acceptance_criteria | default("[ACCEPTANCE CRITERIA]") }}
14
+
15
+ ## Comments
@@ -0,0 +1,15 @@
1
+ import { InitCommand } from "./Commands/InitCommand.js";
2
+ import { UpdateCommand } from "./Commands/UpdateCommand.js";
3
+ import { BlueprintReconciliationService } from "./Services/BlueprintReconciliationService.js";
4
+ import { InstallationService } from "./Services/InstallationService.js";
5
+ import { ServiceProvider } from "../Foundation/ServiceProvider.js";
6
+ export class BlueprintManagementServiceProvider extends ServiceProvider {
7
+ static commands() {
8
+ return [InitCommand, UpdateCommand];
9
+ }
10
+ register() {
11
+ this.app.singleton(BlueprintReconciliationService);
12
+ this.app.singleton(InstallationService);
13
+ }
14
+ async boot() { }
15
+ }
@@ -0,0 +1,238 @@
1
+ import { lstat, readdir } from "node:fs/promises";
2
+ import { isAbsolute, join, relative, sep, win32 } from "node:path";
3
+ import { blueprintCatalog as assetCatalog } from "../../Assets/Blueprints/Catalog.js";
4
+ import { Stacks } from "../../Support/Stacks.js";
5
+ const catalogKinds = ["agents", "instructions", "skills"];
6
+ const allowedEntryFields = new Set(["path", "status", "stacks", "canReview"]);
7
+ const requiredEntryFields = ["path", "status", "stacks"];
8
+ const globCharacters = /[*?[\]{}]/;
9
+ function isRecord(value) {
10
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11
+ }
12
+ function validateCatalogPath(value, kind, key) {
13
+ if (typeof value !== "string" || value.length === 0) {
14
+ throw new Error(`Blueprint Catalog ${kind}.${key}.path must be a non-empty relative path.`);
15
+ }
16
+ const directory = value.endsWith("/");
17
+ const path = directory ? value.slice(0, -1) : value;
18
+ const segments = path.split("/");
19
+ if (path.length === 0 ||
20
+ path.includes("\\") ||
21
+ isAbsolute(path) ||
22
+ win32.isAbsolute(path) ||
23
+ segments.some((segment) => segment === "" || segment === "." || segment === "..") ||
24
+ globCharacters.test(path)) {
25
+ throw new Error(`Blueprint Catalog ${kind}.${key}.path '${value}' is unsafe; use a relative path without traversal or glob syntax.`);
26
+ }
27
+ return { path: segments.join("/"), directory };
28
+ }
29
+ export function validateBlueprintCatalog(data) {
30
+ if (!isRecord(data))
31
+ throw new Error("Blueprint Catalog must be an object.");
32
+ for (const key of Object.keys(data)) {
33
+ if (!catalogKinds.includes(key)) {
34
+ throw new Error(`Unknown Blueprint Catalog kind '${key}'.`);
35
+ }
36
+ }
37
+ for (const kind of catalogKinds) {
38
+ if (!Object.hasOwn(data, kind)) {
39
+ throw new Error(`Blueprint Catalog is missing required '${kind}' mapping.`);
40
+ }
41
+ }
42
+ const catalog = {};
43
+ for (const kind of catalogKinds) {
44
+ const section = data[kind];
45
+ if (!isRecord(section)) {
46
+ throw new Error(`Blueprint Catalog '${kind}' must be a mapping of logical keys to entries.`);
47
+ }
48
+ const entries = [];
49
+ for (const [key, rawEntry] of Object.entries(section)) {
50
+ if (key.length === 0 || !isRecord(rawEntry)) {
51
+ throw new Error(`Blueprint Catalog '${kind}.${key}' must be an entry mapping.`);
52
+ }
53
+ for (const field of Object.keys(rawEntry)) {
54
+ if (field === "canReview" && kind !== "agents") {
55
+ throw new Error(`Field 'canReview' is only valid for Blueprint Catalog agents, not '${kind}'.`);
56
+ }
57
+ if (!allowedEntryFields.has(field)) {
58
+ throw new Error(`Unknown field '${field}' in Blueprint Catalog entry '${kind}.${key}'.`);
59
+ }
60
+ }
61
+ for (const field of requiredEntryFields) {
62
+ if (!Object.hasOwn(rawEntry, field)) {
63
+ throw new Error(`Blueprint Catalog '${kind}.${key}' is missing required '${field}'.`);
64
+ }
65
+ }
66
+ const { path, directory } = validateCatalogPath(rawEntry.path, kind, key);
67
+ if (rawEntry.status !== "active" && rawEntry.status !== "removed") {
68
+ throw new Error(`Invalid status in Blueprint Catalog '${kind}.${key}': expected 'active' or 'removed'.`);
69
+ }
70
+ if (!Array.isArray(rawEntry.stacks) ||
71
+ !rawEntry.stacks.every((stack) => typeof stack === "string")) {
72
+ throw new Error(`Blueprint Catalog '${kind}.${key}.stacks' must be a list of Stack names.`);
73
+ }
74
+ if (kind === "agents" &&
75
+ Object.hasOwn(rawEntry, "canReview") &&
76
+ typeof rawEntry.canReview !== "boolean") {
77
+ throw new Error(`Blueprint Catalog '${kind}.${key}.canReview' must be a boolean when supplied.`);
78
+ }
79
+ for (const stack of rawEntry.stacks) {
80
+ if (!Stacks.supported.includes(stack)) {
81
+ throw new Error(`Invalid Stack '${stack}' in Blueprint Catalog '${kind}.${key}'. Supported Stacks: ${Stacks.supported.join(", ")}.`);
82
+ }
83
+ }
84
+ if (kind === "skills" && !directory) {
85
+ throw new Error(`Blueprint Catalog Skill path '${kind}.${key}' must select a directory.`);
86
+ }
87
+ entries.push({
88
+ key,
89
+ path,
90
+ directory,
91
+ status: rawEntry.status,
92
+ stacks: rawEntry.stacks,
93
+ ...(kind === "agents" && Object.hasOwn(rawEntry, "canReview")
94
+ ? { canReview: rawEntry.canReview }
95
+ : {}),
96
+ });
97
+ }
98
+ catalog[kind] = entries;
99
+ }
100
+ for (const kind of catalogKinds) {
101
+ const entries = catalog[kind];
102
+ for (let first = 0; first < entries.length; first += 1) {
103
+ for (let second = first + 1; second < entries.length; second += 1) {
104
+ const left = entries[first].path;
105
+ const right = entries[second].path;
106
+ if (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`)) {
107
+ throw new Error(`Overlapping Blueprint Catalog paths in '${kind}': '${left}' and '${right}'.`);
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return catalog;
113
+ }
114
+ async function assertNoSymlinkPath(root, path) {
115
+ let current = root;
116
+ for (const segment of path.split("/")) {
117
+ current = join(current, segment);
118
+ try {
119
+ if ((await lstat(current)).isSymbolicLink()) {
120
+ throw new Error(`Blueprint Catalog path '${path}' traverses symbolic link '${current}'.`);
121
+ }
122
+ }
123
+ catch (error) {
124
+ if (error.code === "ENOENT")
125
+ return;
126
+ throw error;
127
+ }
128
+ }
129
+ }
130
+ async function collectDirectoryFiles(source, root, result) {
131
+ for (const entry of await readdir(source, { withFileTypes: true })) {
132
+ const path = join(source, entry.name);
133
+ const stat = await lstat(path);
134
+ if (stat.isSymbolicLink()) {
135
+ throw new Error(`Blueprint directory '${relative(root, path)}' contains a symbolic link.`);
136
+ }
137
+ if (stat.isDirectory()) {
138
+ await collectDirectoryFiles(path, root, result);
139
+ }
140
+ else if (stat.isFile()) {
141
+ result.push(path);
142
+ }
143
+ else {
144
+ throw new Error(`Blueprint path '${relative(root, path)}' is not a regular file or directory.`);
145
+ }
146
+ }
147
+ }
148
+ export async function planBlueprintCatalog(catalog, kind, sourceRoot, selectedStacks) {
149
+ const selections = [];
150
+ const deletions = [];
151
+ const directories = [];
152
+ for (const entry of catalog[kind]) {
153
+ if (entry.status === "removed") {
154
+ deletions.push({ entry, path: entry.path, reason: "removed" });
155
+ continue;
156
+ }
157
+ await assertNoSymlinkPath(sourceRoot, entry.path);
158
+ const sourcePath = join(sourceRoot, ...entry.path.split("/"));
159
+ let stat;
160
+ try {
161
+ stat = await lstat(sourcePath);
162
+ }
163
+ catch (error) {
164
+ if (error.code === "ENOENT") {
165
+ throw new Error(`Active Blueprint Catalog entry '${kind}.${entry.key}' is missing source '${entry.path}'.`, { cause: error });
166
+ }
167
+ throw error;
168
+ }
169
+ if (entry.directory !== stat.isDirectory() || (!entry.directory && !stat.isFile())) {
170
+ throw new Error(`Blueprint Catalog source '${kind}.${entry.key}' has an incompatible type for '${entry.path}'.`);
171
+ }
172
+ let directoryFiles;
173
+ if (entry.directory) {
174
+ directoryFiles = [];
175
+ await collectDirectoryFiles(sourcePath, sourceRoot, directoryFiles);
176
+ }
177
+ if (kind === "skills") {
178
+ const entryFile = join(sourcePath, "SKILL.md");
179
+ try {
180
+ const entryStat = await lstat(entryFile);
181
+ if (!entryStat.isFile() || entryStat.isSymbolicLink()) {
182
+ throw new Error(`Skill Blueprint '${entry.path}' must contain a regular SKILL.md file.`);
183
+ }
184
+ }
185
+ catch (error) {
186
+ if (error.code === "ENOENT") {
187
+ throw new Error(`Skill Blueprint '${entry.path}' must contain a SKILL.md file.`, {
188
+ cause: error,
189
+ });
190
+ }
191
+ throw error;
192
+ }
193
+ }
194
+ if (entry.stacks.length > 0 && !entry.stacks.some((stack) => selectedStacks.includes(stack))) {
195
+ deletions.push({ entry, path: entry.path, reason: "stack-inapplicable" });
196
+ continue;
197
+ }
198
+ const files = [];
199
+ if (entry.directory) {
200
+ directories.push({
201
+ entry,
202
+ path: entry.path,
203
+ sourceFiles: directoryFiles.map((file) => relative(sourcePath, file).split(sep).join("/")),
204
+ });
205
+ for (const file of directoryFiles) {
206
+ files.push({
207
+ sourcePath: file,
208
+ outputPath: relative(sourcePath, file).split(sep).join("/"),
209
+ });
210
+ }
211
+ }
212
+ else {
213
+ files.push({ sourcePath, outputPath: entry.path.split("/").at(-1) });
214
+ }
215
+ if (kind === "agents" || kind === "instructions") {
216
+ for (const file of files) {
217
+ const outputPath = entry.directory
218
+ ? relative(sourceRoot, file.sourcePath).split(sep).join("/")
219
+ : entry.path;
220
+ selections.push({
221
+ entry,
222
+ name: outputPath,
223
+ files: [{ ...file, outputPath }],
224
+ });
225
+ }
226
+ }
227
+ else {
228
+ selections.push({
229
+ entry,
230
+ name: entry.path,
231
+ files,
232
+ });
233
+ }
234
+ }
235
+ return { selections, deletions, directories };
236
+ }
237
+ validateBlueprintCatalog(assetCatalog);
238
+ export const blueprintCatalog = assetCatalog;
@@ -0,0 +1,9 @@
1
+ import { Option } from "commander";
2
+ export class BlueprintCommandOptions {
3
+ static conflictPolicyOption(description) {
4
+ return new Option("--on-conflict <overwrite|skip>", description).choices(["overwrite", "skip"]);
5
+ }
6
+ static noInteractiveOption(description) {
7
+ return new Option("--no-interactive", description);
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ export function parseConflictPolicy(policy) {
2
+ if (policy !== undefined && policy !== "overwrite" && policy !== "skip") {
3
+ throw new Error(`Invalid --on-conflict '${policy}'. Use overwrite or skip.`);
4
+ }
5
+ return policy;
6
+ }
@@ -0,0 +1,117 @@
1
+ import chalk from "chalk";
2
+ import { BlueprintCommandOptions } from "./BlueprintCommandOptions.js";
3
+ import { parseConflictPolicy } from "./ConflictPolicy.js";
4
+ import { promptConflict, promptSpindlePackageManager, promptStacks, } from "./Prompts.js";
5
+ import { blueprintHandlers } from "../Handlers/BlueprintHandlers.js";
6
+ import { BlueprintReconciliationService } from "../Services/BlueprintReconciliationService.js";
7
+ import { Command } from "../../Commands/Command.js";
8
+ import { LoadProjectConfiguration, } from "../../Foundation/Bootstrap/LoadProjectConfiguration.js";
9
+ import { ProjectService } from "../../Project/Services/ProjectService.js";
10
+ import { Stacks } from "../../Support/Stacks.js";
11
+ export class InitCommand extends Command {
12
+ handlers = [];
13
+ reconciliationService;
14
+ static normalizeSpindlePackageManager(command) {
15
+ const normalized = command.trim();
16
+ if (normalized.length === 0 || /[\r\n]/.test(normalized)) {
17
+ throw new Error("--spindle-package-manager must be a non-empty, single-line command.");
18
+ }
19
+ return normalized;
20
+ }
21
+ static register(program, createApp) {
22
+ program
23
+ .command("init")
24
+ .description("Install spindle Blueprints and initialize project guidance at the Git root.")
25
+ .option("--stack <id>", `Stack to install; repeat for several (${Stacks.supported.join(", ")})`, (value, previous = []) => [...previous, value], [])
26
+ .option("--spindle-package-manager <command>", "Package-manager command prefix used in generated tooling guidance")
27
+ .addOption(BlueprintCommandOptions.conflictPolicyOption("Policy for Blueprints that already exist; required when non-interactive and any exist (interactive runs prompt per Blueprint)"))
28
+ .addOption(BlueprintCommandOptions.noInteractiveOption("Never prompt; missing required input is an error"))
29
+ .addHelpText("after", `
30
+ If Blueprint stacks are already configured, project guidance is initialized and
31
+ \`spindle update\` is required to change the installed Blueprints.
32
+ Prompts are also disabled when stdin or stdout is not a terminal.
33
+ Other commands: update (see \`spindle update --help\`), tool (see \`spindle tool --help\`), sdd (see \`spindle sdd --help\`).
34
+ Run \`spindle --version\` to print the installed version.
35
+ `)
36
+ .allowExcessArguments(false)
37
+ .action(async (options) => {
38
+ const interactive = options.interactive && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
39
+ const policy = parseConflictPolicy(options.onConflict);
40
+ Stacks.validate(options.stack);
41
+ const spindlePackageManager = options.spindlePackageManager === undefined
42
+ ? undefined
43
+ : InitCommand.normalizeSpindlePackageManager(options.spindlePackageManager);
44
+ if (!interactive && options.stack.length === 0) {
45
+ throw new Error(`Provide at least one --stack flag <${Stacks.supported.join("|")}> (or run interactively).`);
46
+ }
47
+ await (await (await createApp()).make(InitCommand)).run(options.stack, spindlePackageManager, interactive, policy);
48
+ });
49
+ }
50
+ constructor(app) {
51
+ super(app);
52
+ }
53
+ async boot() {
54
+ this.handlers = blueprintHandlers;
55
+ this.reconciliationService = await this.app.make(BlueprintReconciliationService);
56
+ }
57
+ async run(stackArguments, packageManagerArgument, interactive, policy) {
58
+ this.assertApplicationBooted();
59
+ const existing = LoadProjectConfiguration.current(this.app);
60
+ if (existing.status === "invalid") {
61
+ throw new Error(existing.reason, { cause: existing.error });
62
+ }
63
+ if (existing.status === "valid" && existing.data.stacks.length > 0) {
64
+ await (await this.app.make(ProjectService)).initialize();
65
+ console.log(`${chalk.green("✔")} Initialized project guidance and tooling documentation.`);
66
+ throw new Error("This repository already has configured Blueprint stacks; run `spindle update` instead of `init`.");
67
+ }
68
+ let stacks = [...new Set(stackArguments)];
69
+ Stacks.validate(stacks);
70
+ if (stacks.length === 0) {
71
+ if (!interactive) {
72
+ throw new Error(`Provide at least one --stack flag <${Stacks.supported.join("|")}> (or run interactively).`);
73
+ }
74
+ stacks = await promptStacks(Stacks.supported);
75
+ }
76
+ let spindlePackageManager = packageManagerArgument ??
77
+ (existing.status === "valid" ? existing.data.spindle_package_manager : undefined);
78
+ if (spindlePackageManager === undefined && interactive) {
79
+ spindlePackageManager = await promptSpindlePackageManager();
80
+ }
81
+ if (spindlePackageManager === undefined) {
82
+ throw new Error("A package-manager command is required; provide --spindle-package-manager <command> or run interactively.");
83
+ }
84
+ spindlePackageManager = InitCommand.normalizeSpindlePackageManager(spindlePackageManager);
85
+ const config = {
86
+ ...(existing.status === "valid" ? existing.data : {}),
87
+ stacks,
88
+ spindle_package_manager: spindlePackageManager,
89
+ };
90
+ delete config.variables;
91
+ const outcomes = await this.reconciliationService.reconcile(this.handlers, {
92
+ mode: "init",
93
+ context: { stacks, variables: {} },
94
+ config,
95
+ conflictPolicy: policy,
96
+ chooseConflict: interactive ? promptConflict : undefined,
97
+ });
98
+ await LoadProjectConfiguration.refresh(this.app);
99
+ for (const outcome of outcomes.filter((item) => item.status === "removed")) {
100
+ console.log(`${chalk.green("✔")} Removed ${outcome.kind.toLowerCase()} '${outcome.name}'`);
101
+ }
102
+ const kinds = [...new Set(outcomes.map((outcome) => outcome.kind))];
103
+ const counts = (status) => kinds
104
+ .map((kind) => ({
105
+ kind,
106
+ count: outcomes.filter((outcome) => outcome.kind === kind && outcome.status === status)
107
+ .length,
108
+ }))
109
+ .filter(({ count }) => status === "installed" || count > 0)
110
+ .map(({ kind, count }) => `${count} ${status === "skipped" ? "existing " : ""}${kind.toLowerCase()}(s)`)
111
+ .join(", ");
112
+ const skipped = counts("skipped");
113
+ console.log(`${chalk.green("✔")} Installed ${counts("installed") || "0 Blueprints"} for ${chalk.cyan(stacks.join(", "))}${skipped ? `. Skipped ${skipped}` : ""}`);
114
+ await (await this.app.make(ProjectService)).initialize();
115
+ console.log(`${chalk.green("✔")} Initialized project guidance and tooling documentation.`);
116
+ }
117
+ }
@@ -0,0 +1,66 @@
1
+ import { cancel, isCancel, multiselect, select, text } from "@clack/prompts";
2
+ function ensureAnswer(answer) {
3
+ // clack signals cancellation with a unique symbol
4
+ if (typeof answer === "symbol" && isCancel(answer)) {
5
+ cancel("Cancelled.");
6
+ throw new Error("Cancelled by user.");
7
+ }
8
+ return answer;
9
+ }
10
+ export async function promptStacks(supported) {
11
+ const answer = await multiselect({
12
+ message: "Which stacks does this project use?",
13
+ options: supported.map((value) => ({ value, label: value })),
14
+ required: true,
15
+ });
16
+ return ensureAnswer(answer);
17
+ }
18
+ export async function promptSpindlePackageManager() {
19
+ const answer = await select({
20
+ message: "Which package-manager command should Spindle use in generated guidance?",
21
+ options: [
22
+ { value: "npm run", label: "npm run" },
23
+ { value: "pnpm", label: "pnpm" },
24
+ { value: "yarn", label: "yarn" },
25
+ { value: "bun", label: "bun" },
26
+ { value: "other", label: "Other" },
27
+ ],
28
+ });
29
+ const selection = ensureAnswer(answer);
30
+ if (selection !== "other")
31
+ return selection;
32
+ const custom = await text({
33
+ message: "Enter the package-manager command prefix",
34
+ validate: (value) => (value ?? "").trim().length === 0 ? "A command prefix is required." : undefined,
35
+ });
36
+ return ensureAnswer(custom).trim();
37
+ }
38
+ export async function promptConflict(kind, name) {
39
+ const answer = await select({
40
+ message: `${kind} '${name}' already exists. What should happen?`,
41
+ options: [
42
+ { value: "overwrite", label: "Overwrite" },
43
+ { value: "skip", label: "Skip" },
44
+ ],
45
+ });
46
+ return ensureAnswer(answer);
47
+ }
48
+ export async function promptOutdated(kind, name, installed, available) {
49
+ const answer = await select({
50
+ message: `${kind} '${name}' is outdated (installed ${installed}, available ${available}). What should happen?`,
51
+ options: [
52
+ { value: "overwrite", label: "Overwrite" },
53
+ { value: "skip", label: "Skip" },
54
+ ],
55
+ });
56
+ return ensureAnswer(answer);
57
+ }
58
+ export async function promptNewBlueprints(kind, names) {
59
+ const answer = await multiselect({
60
+ message: `Which new ${kind}s should be installed?`,
61
+ options: names.map((value) => ({ value, label: value })),
62
+ initialValues: names,
63
+ required: false,
64
+ });
65
+ return ensureAnswer(answer);
66
+ }