@use-the-fork/spindle 0.0.0-stage → 0.0.2
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 +3 -2
- package/build/Assets/Blueprints/Catalog.js +110 -0
- package/build/Assets/Blueprints/agents/general.agent.md +67 -0
- package/build/Assets/Blueprints/agents/sdd-code-reviewer.agent.md +62 -0
- package/build/Assets/Blueprints/agents/sdd-code-slop-reviewer.agent.md +59 -0
- package/build/Assets/Blueprints/agents/sdd-implementer.agent.md +77 -0
- package/build/Assets/Blueprints/agents/sdd-orchestrator.agent.md +42 -0
- package/build/Assets/Blueprints/agents/sdd-re-review.agent.md +57 -0
- package/build/Assets/Blueprints/agents/sdd-reviewer.agent.md +89 -0
- package/build/Assets/Blueprints/agents/sdd-task-reviewer.agent.md +54 -0
- package/build/Assets/Blueprints/agents/shared-codebase-analyzer.agent.md +151 -0
- package/build/Assets/Blueprints/agents/shared-codebase-locator.agent.md +130 -0
- package/build/Assets/Blueprints/agents/shared-codebase-pattern-finder.agent.md +247 -0
- package/build/Assets/Blueprints/agents/shared-explore.agent.md +53 -0
- package/build/Assets/Blueprints/agents/shared-r.agent.md +17 -0
- package/build/Assets/Blueprints/agents/shared-rw.agent.md +17 -0
- package/build/Assets/Blueprints/agents/shared-rwx.agent.md +17 -0
- package/build/Assets/Blueprints/agents/shared-web-search-researcher.agent.md +122 -0
- package/build/Assets/Blueprints/instructions/code-commenting.instructions.md +39 -0
- package/build/Assets/Blueprints/instructions/source-architecture.instructions.md +15 -0
- package/build/Assets/Blueprints/skills/asd-ste100/CREDITS.MD +1 -0
- package/build/Assets/Blueprints/skills/asd-ste100/SKILL.md +83 -0
- package/build/Assets/Blueprints/skills/asd-ste100/examples/before-after.md +107 -0
- package/build/Assets/Blueprints/skills/asd-ste100/references/writing-rules.md +65 -0
- package/build/Assets/Blueprints/skills/author-agent/SKILL.md +26 -0
- package/build/Assets/Blueprints/skills/author-design/SKILL.md +38 -0
- package/build/Assets/Blueprints/skills/author-instruction/SKILL.md +28 -0
- package/build/Assets/Blueprints/skills/author-skill/SKILL.md +26 -0
- package/build/Assets/Blueprints/skills/grill/SKILL.md +33 -0
- package/build/Assets/Blueprints/skills/grill-design/SKILL.md +41 -0
- package/build/Assets/Blueprints/skills/grill-with-docs/SKILL.md +14 -0
- package/build/Assets/Blueprints/skills/implement/SKILL.md +79 -0
- package/build/Assets/Blueprints/skills/implement-spec/SKILL.md +34 -0
- package/build/Assets/Blueprints/skills/improve-codebase-architecture/HTML-REPORT.md +129 -0
- package/build/Assets/Blueprints/skills/improve-codebase-architecture/SKILL.md +74 -0
- package/build/Assets/Blueprints/skills/int-code-review/SKILL.md +76 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/SKILL.md +238 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_sections.md +36 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_template.md +42 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-closing-brace-labels.md +112 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-empty-docblocks.md +132 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-narration.md +118 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-placeholder.md +130 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-generic-catch.md +153 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-impossible-null.md +157 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-missing-real.md +157 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-generic-placeholders.md +120 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-over-descriptive.md +108 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-suffix-abuse.md +167 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-type-in-name.md +100 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-dependency-creep.md +114 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-premature-interface.md +136 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-single-method-class.md +161 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-useless-wrapper.md +140 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-as-any-escape.md +127 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-debug-artifacts.md +144 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-hyper-consistent.md +84 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-no-hack-scars.md +113 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-trivial-boilerplate.md +191 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-doesnt-throw.md +132 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mirror-implementation.md +125 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mock-everything.md +148 -0
- package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-snapshot-abuse.md +131 -0
- package/build/Assets/Blueprints/skills/int-codebase-design/SKILL.md +116 -0
- package/build/Assets/Blueprints/skills/int-codebase-design/references/DEEPENING.md +37 -0
- package/build/Assets/Blueprints/skills/int-codebase-design/references/DESIGN-IT-TWICE.md +44 -0
- package/build/Assets/Blueprints/skills/int-domain-modeling/SKILL.md +78 -0
- package/build/Assets/Blueprints/skills/int-domain-modeling/references/ADR-FORMAT.md +47 -0
- package/build/Assets/Blueprints/skills/int-domain-modeling/references/GLOSSARY-FORMAT.md +60 -0
- package/build/Assets/Blueprints/skills/int-prototype/LOGIC.md +67 -0
- package/build/Assets/Blueprints/skills/int-prototype/SKILL.md +30 -0
- package/build/Assets/Blueprints/skills/int-prototype/UI.md +112 -0
- package/build/Assets/Blueprints/skills/int-retrospective/SKILL.md +88 -0
- package/build/Assets/Blueprints/skills/int-retrospective/assets/retrospective-prompt.md +38 -0
- package/build/Assets/Blueprints/skills/int-retrospective/references/assessment.md +56 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/SKILL.md +64 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/implementer-prompt.md +40 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/reviewer-prompt.md +43 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/aggregate-review.md +7 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/corrective-rounds.md +72 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/example-workflow.md +25 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/full-spec.md +72 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/implementer-corrections.md +9 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/review-inputs.md +26 -0
- package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/verification-evidence.md +7 -0
- package/build/Assets/Blueprints/skills/int-test-driven-development/SKILL.md +51 -0
- package/build/Assets/Blueprints/skills/int-test-driven-development/references/mocking.md +31 -0
- package/build/Assets/Blueprints/skills/int-test-driven-development/references/tests.md +68 -0
- package/build/Assets/Blueprints/skills/int-testing-agent-guidance/SKILL.md +53 -0
- package/build/Assets/Blueprints/skills/int-verification-before-completion/SKILL.md +25 -0
- package/build/Assets/Blueprints/skills/int-writing-agents/SKILL.md +66 -0
- package/build/Assets/Blueprints/skills/int-writing-for-agents/SKILL.md +86 -0
- package/build/Assets/Blueprints/skills/int-writing-instruction/SKILL.md +57 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/SKILL.md +129 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/assets/interactive.md +83 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/assets/reference.md +32 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/references/arguments.md +50 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/references/interactive-skills.md +53 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/references/persuasion-principles.md +220 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/references/reference-skills.md +20 -0
- package/build/Assets/Blueprints/skills/int-writing-skills/references/testing-skills.md +48 -0
- package/build/Assets/Blueprints/skills/retrospective/SKILL.md +16 -0
- package/build/Assets/Blueprints/skills/setup-project/SKILL.md +66 -0
- package/build/Assets/Blueprints/skills/to-spec/SKILL.md +53 -0
- package/build/Assets/Blueprints/skills/to-tickets/SKILL.md +49 -0
- package/build/Assets/Blueprints/skills/update-tooling/SKILL.md +86 -0
- package/build/Assets/Templates/Catalog.js +12 -0
- package/build/Assets/Templates/Catalog.ts +17 -0
- package/build/Assets/Templates/project/copilot-instructions.md +17 -0
- package/build/Assets/Templates/project/domain.md +51 -0
- package/build/Assets/Templates/project/ticket-tracker.md +33 -0
- package/build/Assets/Templates/sdd/design.md +25 -0
- package/build/Assets/Templates/sdd/spec.md +29 -0
- package/build/Assets/Templates/sdd/ticket.md +15 -0
- package/build/BlueprintManagement/BlueprintManagementServiceProvider.js +15 -0
- package/build/BlueprintManagement/Catalog/BlueprintCatalog.js +238 -0
- package/build/BlueprintManagement/Commands/BlueprintCommandOptions.js +9 -0
- package/build/BlueprintManagement/Commands/ConflictPolicy.js +6 -0
- package/build/BlueprintManagement/Commands/InitCommand.js +117 -0
- package/build/BlueprintManagement/Commands/Prompts.js +66 -0
- package/build/BlueprintManagement/Commands/UpdateCommand.js +86 -0
- package/build/BlueprintManagement/Handlers/Agents/AgentHandler.js +21 -0
- package/build/BlueprintManagement/Handlers/BlueprintHandlers.js +4 -0
- package/build/BlueprintManagement/Handlers/Instructions/InstructionHandler.js +21 -0
- package/build/BlueprintManagement/Handlers/Skills/SkillHandler.js +10 -0
- package/build/BlueprintManagement/Reconciliation/BlueprintCatalogPlanner.js +87 -0
- package/build/BlueprintManagement/Reconciliation/BlueprintRemovalCoordinator.js +78 -0
- package/build/BlueprintManagement/Services/BlueprintReconciliationService.js +391 -0
- package/build/BlueprintManagement/Services/InstallationService.js +54 -0
- package/build/BlueprintManagement/Support/BlueprintFiles.js +113 -0
- package/build/BlueprintManagement/Types/Blueprint.js +1 -0
- package/build/BlueprintManagement/Types/Installation.js +1 -0
- package/build/BlueprintManagement/Types/Reconciliation.js +1 -0
- package/build/BlueprintManagement/Versioning/BlueprintVersion.js +70 -0
- package/build/BlueprintManagement/Versioning/BlueprintVersioning.js +55 -0
- package/build/Commands/Command.js +3 -0
- package/build/Commands/CommandOptions.js +12 -0
- package/build/Config/Config.js +3 -0
- package/build/Foundation/Application.js +112 -0
- package/build/Foundation/ApplicationBuilder.js +23 -0
- package/build/Foundation/Bootstrap/Bootstrapper.js +2 -0
- package/build/Foundation/Bootstrap/DiscoverGitRoot.js +8 -0
- package/build/Foundation/Bootstrap/LoadConsoleArgs.js +47 -0
- package/build/Foundation/Bootstrap/LoadProjectConfiguration.js +144 -0
- package/build/Foundation/Bootstrap/RegisterProviders.js +12 -0
- package/build/Foundation/Bootstrap/RequireProjectConfiguration.js +14 -0
- package/build/Foundation/ConsoleInvocation.js +1 -0
- package/build/Foundation/Container.js +185 -0
- package/build/Foundation/FoundationServiceProvider.js +5 -0
- package/build/Foundation/Kernel.js +30 -0
- package/build/Foundation/Service.js +23 -0
- package/build/Foundation/ServiceProvider.js +12 -0
- package/build/Git/GitServiceProvider.js +8 -0
- package/build/Git/Services/GitService.js +26 -0
- package/build/Project/ProjectServiceProvider.js +8 -0
- package/build/Project/Services/ProjectService.js +124 -0
- package/build/SubagentDrivenDevelopment/Commands/ChecksRecordCommand.js +35 -0
- package/build/SubagentDrivenDevelopment/Commands/ChecksRequireCommand.js +33 -0
- package/build/SubagentDrivenDevelopment/Commands/ClaimCommand.js +23 -0
- package/build/SubagentDrivenDevelopment/Commands/CorrectCommand.js +37 -0
- package/build/SubagentDrivenDevelopment/Commands/CreateCommand.js +26 -0
- package/build/SubagentDrivenDevelopment/Commands/FindingCreateCommand.js +39 -0
- package/build/SubagentDrivenDevelopment/Commands/FindingUpdateCommand.js +36 -0
- package/build/SubagentDrivenDevelopment/Commands/FinishCommand.js +23 -0
- package/build/SubagentDrivenDevelopment/Commands/ImplementCommand.js +23 -0
- package/build/SubagentDrivenDevelopment/Commands/NextCommand.js +21 -0
- package/build/SubagentDrivenDevelopment/Commands/ReadyCommand.js +21 -0
- package/build/SubagentDrivenDevelopment/Commands/RequirementsDecideCommand.js +33 -0
- package/build/SubagentDrivenDevelopment/Commands/ResumeCommand.js +31 -0
- package/build/SubagentDrivenDevelopment/Commands/ReviewCommand.js +55 -0
- package/build/SubagentDrivenDevelopment/Commands/ReviewRequireCommand.js +12 -0
- package/build/SubagentDrivenDevelopment/Commands/StatusCommand.js +21 -0
- package/build/SubagentDrivenDevelopment/Commands/SubmitCommand.js +59 -0
- package/build/SubagentDrivenDevelopment/Commands/TicketCommentCommand.js +24 -0
- package/build/SubagentDrivenDevelopment/Commands/TicketCreateCommand.js +25 -0
- package/build/SubagentDrivenDevelopment/Commands/TicketUpdateCommand.js +31 -0
- package/build/SubagentDrivenDevelopment/Commands/groups.js +36 -0
- package/build/SubagentDrivenDevelopment/Evidence/GitEvidence.js +449 -0
- package/build/SubagentDrivenDevelopment/Evidence/ReportEvidence.js +80 -0
- package/build/SubagentDrivenDevelopment/Models/Assignments.js +1 -0
- package/build/SubagentDrivenDevelopment/Models/Evidence.js +1 -0
- package/build/SubagentDrivenDevelopment/Models/Findings.js +1 -0
- package/build/SubagentDrivenDevelopment/Models/Options.js +1 -0
- package/build/SubagentDrivenDevelopment/Models/Workflow.js +16 -0
- package/build/SubagentDrivenDevelopment/Persistence/AssignmentSchema.js +155 -0
- package/build/SubagentDrivenDevelopment/Persistence/CheckSchema.js +71 -0
- package/build/SubagentDrivenDevelopment/Persistence/FeatureWorkspace.js +76 -0
- package/build/SubagentDrivenDevelopment/Persistence/FileSystem.js +28 -0
- package/build/SubagentDrivenDevelopment/Persistence/FindingSchema.js +81 -0
- package/build/SubagentDrivenDevelopment/Persistence/LedgerRepository.js +322 -0
- package/build/SubagentDrivenDevelopment/Persistence/PathSafety.js +62 -0
- package/build/SubagentDrivenDevelopment/Persistence/ProgressSchema.js +95 -0
- package/build/SubagentDrivenDevelopment/Persistence/ReadinessReader.js +40 -0
- package/build/SubagentDrivenDevelopment/Persistence/ReviewSchema.js +68 -0
- package/build/SubagentDrivenDevelopment/Persistence/TicketRepository.js +147 -0
- package/build/SubagentDrivenDevelopment/Persistence/WorkspaceTransaction.js +282 -0
- package/build/SubagentDrivenDevelopment/Policies/AcceptancePolicy.js +100 -0
- package/build/SubagentDrivenDevelopment/Policies/AssignmentPolicy.js +36 -0
- package/build/SubagentDrivenDevelopment/Policies/CheckPolicy.js +93 -0
- package/build/SubagentDrivenDevelopment/Policies/FindingPolicy.js +53 -0
- package/build/SubagentDrivenDevelopment/Policies/InputValidation.js +36 -0
- package/build/SubagentDrivenDevelopment/Policies/ReadinessPolicy.js +26 -0
- package/build/SubagentDrivenDevelopment/Policies/RequiredReviewers.js +12 -0
- package/build/SubagentDrivenDevelopment/Policies/ReviewPolicy.js +87 -0
- package/build/SubagentDrivenDevelopment/Policies/WorkflowPolicy.js +85 -0
- package/build/SubagentDrivenDevelopment/Services/AssignmentService.js +269 -0
- package/build/SubagentDrivenDevelopment/Services/ChecksService.js +319 -0
- package/build/SubagentDrivenDevelopment/Services/CorrectionService.js +273 -0
- package/build/SubagentDrivenDevelopment/Services/DeliveryCorrectionService.js +253 -0
- package/build/SubagentDrivenDevelopment/Services/DeliveryFindingService.js +302 -0
- package/build/SubagentDrivenDevelopment/Services/DeliveryService.js +160 -0
- package/build/SubagentDrivenDevelopment/Services/DeliverySubmissionService.js +273 -0
- package/build/SubagentDrivenDevelopment/Services/FeatureCreationService.js +138 -0
- package/build/SubagentDrivenDevelopment/Services/FeatureInspectionService.js +399 -0
- package/build/SubagentDrivenDevelopment/Services/FindingService.js +392 -0
- package/build/SubagentDrivenDevelopment/Services/IntegrationService.js +258 -0
- package/build/SubagentDrivenDevelopment/Services/ReadinessService.js +21 -0
- package/build/SubagentDrivenDevelopment/Services/RequirementsService.js +216 -0
- package/build/SubagentDrivenDevelopment/Services/ReviewService.js +471 -0
- package/build/SubagentDrivenDevelopment/Services/SubmissionService.js +299 -0
- package/build/SubagentDrivenDevelopment/Services/TicketService.js +186 -0
- package/build/SubagentDrivenDevelopment/SubagentDrivenDevelopmentServiceProvider.js +113 -0
- package/build/Support/Records.js +5 -0
- package/build/Support/Repository.js +139 -0
- package/build/Support/Stacks.js +10 -0
- package/build/TemplateRendering/Computed/ComputedContextService.js +13 -0
- package/build/TemplateRendering/Computed/ComputedVariableProvider.js +6 -0
- package/build/TemplateRendering/Computed/ComputedVariableProviders.js +6 -0
- package/build/TemplateRendering/Computed/Providers/InternalSkillDescriptionProvider.js +6 -0
- package/build/TemplateRendering/Computed/Providers/SpindlePackageManagerProvider.js +11 -0
- package/build/TemplateRendering/Computed/ResolveRenderContext.js +18 -0
- package/build/TemplateRendering/Rendering/RenderText.js +43 -0
- package/build/TemplateRendering/TemplateRenderingServiceProvider.js +8 -0
- package/build/Tooling/Commands/ToolingAddCommand.js +29 -0
- package/build/Tooling/Commands/ToolingListCommand.js +19 -0
- package/build/Tooling/Commands/ToolingRemoveCommand.js +19 -0
- package/build/Tooling/Commands/ToolingUpdateCommand.js +30 -0
- package/build/Tooling/Commands/groups.js +4 -0
- package/build/Tooling/Models/ToolingEntry.js +1 -0
- package/build/Tooling/Services/ToolingService.js +278 -0
- package/build/Tooling/ToolingServiceProvider.js +15 -0
- package/build/cli.js +36 -0
- package/build/index.js +31 -0
- package/package.json +54 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { BlueprintCommandOptions } from "./BlueprintCommandOptions.js";
|
|
3
|
+
import { parseConflictPolicy } from "./ConflictPolicy.js";
|
|
4
|
+
import { promptNewBlueprints, promptOutdated } 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 { Stacks } from "../../Support/Stacks.js";
|
|
10
|
+
export class UpdateCommand extends Command {
|
|
11
|
+
handlers = [];
|
|
12
|
+
reconciliationService;
|
|
13
|
+
static register(program, createApp) {
|
|
14
|
+
program
|
|
15
|
+
.command("update")
|
|
16
|
+
.description(`Re-render installed Blueprints (Skills, Agents, and Instructions) whose shipped version is newer.
|
|
17
|
+
Reads stacks and the Spindle package-manager command from .github/spindle.json and leaves it unchanged.
|
|
18
|
+
New shipped Blueprints are offered interactively; use
|
|
19
|
+
--include-new to install all of them without a prompt.`)
|
|
20
|
+
.addOption(BlueprintCommandOptions.conflictPolicyOption("Policy for outdated Blueprints"))
|
|
21
|
+
.addOption(BlueprintCommandOptions.noInteractiveOption("Never prompt; outdated Blueprints without --on-conflict are an error"))
|
|
22
|
+
.option("--include-new", "Install every newly shipped Blueprint without prompting")
|
|
23
|
+
.addHelpText("after", `
|
|
24
|
+
Requires .github/spindle.json; run \`spindle init\` first.
|
|
25
|
+
Installed Blueprints with a missing or non-semver version are skipped with a warning.
|
|
26
|
+
`)
|
|
27
|
+
.allowExcessArguments(false)
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
const interactive = options.interactive && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|
|
30
|
+
const policy = parseConflictPolicy(options.onConflict);
|
|
31
|
+
await (await (await createApp()).make(UpdateCommand)).run(interactive, policy, options.includeNew);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
constructor(app) {
|
|
35
|
+
super(app);
|
|
36
|
+
}
|
|
37
|
+
async boot() {
|
|
38
|
+
this.handlers = blueprintHandlers;
|
|
39
|
+
this.reconciliationService = await this.app.make(BlueprintReconciliationService);
|
|
40
|
+
}
|
|
41
|
+
async run(interactive, policy, includeNew = false) {
|
|
42
|
+
this.assertApplicationBooted();
|
|
43
|
+
const config = LoadProjectConfiguration.require(await LoadProjectConfiguration.refresh(this.app));
|
|
44
|
+
if (config.stacks.length === 0) {
|
|
45
|
+
throw new Error(`No Blueprint stacks are configured. Run \`spindle init --stack <${Stacks.supported.join("|")}>\` first.`);
|
|
46
|
+
}
|
|
47
|
+
const spindlePackageManager = config.config.spindle_package_manager;
|
|
48
|
+
if (spindlePackageManager === undefined) {
|
|
49
|
+
throw new Error('Missing "spindle_package_manager" in .github/spindle.json; add the preferred Spindle package-manager command before running `spindle update`.');
|
|
50
|
+
}
|
|
51
|
+
const outcomes = await this.reconciliationService.reconcile(this.handlers, {
|
|
52
|
+
mode: "update",
|
|
53
|
+
config: config.config,
|
|
54
|
+
includeNew,
|
|
55
|
+
chooseNew: interactive && !includeNew ? promptNewBlueprints : undefined,
|
|
56
|
+
conflictPolicy: policy,
|
|
57
|
+
chooseConflict: interactive && policy === undefined
|
|
58
|
+
? async (kind, name, installed, available) => promptOutdated(kind, name, installed, available)
|
|
59
|
+
: undefined,
|
|
60
|
+
resolveContext: async () => ({
|
|
61
|
+
stacks: config.stacks,
|
|
62
|
+
variables: {},
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
await LoadProjectConfiguration.refresh(this.app);
|
|
66
|
+
for (const outcome of outcomes) {
|
|
67
|
+
if (outcome.warning) {
|
|
68
|
+
console.error(chalk.yellow(outcome.warning));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const outcome of outcomes.filter((item) => item.status === "removed")) {
|
|
72
|
+
console.log(`${chalk.green("✔")} Removed ${outcome.kind.toLowerCase()} '${outcome.name}'`);
|
|
73
|
+
}
|
|
74
|
+
if (outcomes.length === 0) {
|
|
75
|
+
console.log(`${chalk.green("✔")} No Blueprints apply to the selected stacks`);
|
|
76
|
+
}
|
|
77
|
+
for (const kind of new Set(outcomes.map((outcome) => outcome.kind))) {
|
|
78
|
+
const ofKind = outcomes.filter((outcome) => outcome.kind === kind);
|
|
79
|
+
const added = ofKind.filter((outcome) => outcome.status === "installed").length;
|
|
80
|
+
const updated = ofKind.filter((outcome) => outcome.status === "updated").length;
|
|
81
|
+
const skipped = ofKind.filter((outcome) => outcome.status === "skipped").length;
|
|
82
|
+
const upToDate = ofKind.filter((outcome) => outcome.status === "up-to-date").length;
|
|
83
|
+
console.log(`${chalk.green("✔")} Added ${added}, updated ${updated}, skipped ${skipped}, up to date ${upToDate} ${kind.toLowerCase()}(s)`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { planVersionedUpdate, validateVersionedMetadata, } from "../../Versioning/BlueprintVersioning.js";
|
|
3
|
+
export const agentHandler = {
|
|
4
|
+
kind: "Agent",
|
|
5
|
+
catalogKind: "agents",
|
|
6
|
+
sourceDirectory: (blueprintSourceRoot) => join(blueprintSourceRoot, "agents"),
|
|
7
|
+
destinationDirectory: (githubDirectory) => join(githubDirectory, "agents"),
|
|
8
|
+
fileTarget: true,
|
|
9
|
+
targetPath: (destinationDirectory, name) => join(destinationDirectory, name),
|
|
10
|
+
validateMetadata: (relativePath, renderedText) => {
|
|
11
|
+
if (relativePath.toLowerCase().endsWith(".md")) {
|
|
12
|
+
validateVersionedMetadata("Agent", relativePath, relativePath, renderedText);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
planUpdate: (input) => {
|
|
16
|
+
const entry = input.sourceFiles[0].outputPath;
|
|
17
|
+
return entry.toLowerCase().endsWith(".md")
|
|
18
|
+
? planVersionedUpdate(input, "Agent", entry, (target) => target, "warning")
|
|
19
|
+
: Promise.resolve({ status: input.installed ? "conflict" : "new" });
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { agentHandler } from "./Agents/AgentHandler.js";
|
|
2
|
+
import { instructionHandler } from "./Instructions/InstructionHandler.js";
|
|
3
|
+
import { skillHandler } from "./Skills/SkillHandler.js";
|
|
4
|
+
export const blueprintHandlers = [skillHandler, agentHandler, instructionHandler];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { planVersionedUpdate, validateVersionedMetadata, } from "../../Versioning/BlueprintVersioning.js";
|
|
3
|
+
export const instructionHandler = {
|
|
4
|
+
kind: "Instruction",
|
|
5
|
+
catalogKind: "instructions",
|
|
6
|
+
sourceDirectory: (blueprintSourceRoot) => join(blueprintSourceRoot, "instructions"),
|
|
7
|
+
destinationDirectory: (githubDirectory) => join(githubDirectory, "instructions"),
|
|
8
|
+
fileTarget: true,
|
|
9
|
+
targetPath: (destinationDirectory, name) => join(destinationDirectory, name),
|
|
10
|
+
validateMetadata: (relativePath, renderedText) => {
|
|
11
|
+
if (relativePath.toLowerCase().endsWith(".md")) {
|
|
12
|
+
validateVersionedMetadata("Instruction", relativePath, relativePath, renderedText);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
planUpdate: (input) => {
|
|
16
|
+
const entry = input.sourceFiles[0].outputPath;
|
|
17
|
+
return entry.toLowerCase().endsWith(".md")
|
|
18
|
+
? planVersionedUpdate(input, "Instruction", entry, (target) => target, "warning")
|
|
19
|
+
: Promise.resolve({ status: input.installed ? "conflict" : "new" });
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { planVersionedUpdate, validateVersionedMetadata, } from "../../Versioning/BlueprintVersioning.js";
|
|
3
|
+
export const skillHandler = {
|
|
4
|
+
kind: "Skill",
|
|
5
|
+
catalogKind: "skills",
|
|
6
|
+
sourceDirectory: (blueprintSourceRoot) => join(blueprintSourceRoot, "skills"),
|
|
7
|
+
destinationDirectory: (githubDirectory) => join(githubDirectory, "skills"),
|
|
8
|
+
validateMetadata: (relativePath, renderedText) => validateVersionedMetadata("Skill", "SKILL.md", relativePath, renderedText),
|
|
9
|
+
planUpdate: (input) => planVersionedUpdate(input, "Skill", "SKILL.md", (target) => join(target, "SKILL.md"), "error"),
|
|
10
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { lstat, readdir } from "node:fs/promises";
|
|
2
|
+
import { join, relative, sep } from "node:path";
|
|
3
|
+
import { planBlueprintCatalog, blueprintCatalog, validateBlueprintCatalog, } from "../Catalog/BlueprintCatalog.js";
|
|
4
|
+
import { assertSafeInstallPaths } from "../Support/BlueprintFiles.js";
|
|
5
|
+
async function collectDestinationFiles(directory, result = []) {
|
|
6
|
+
let directoryStat;
|
|
7
|
+
try {
|
|
8
|
+
directoryStat = await lstat(directory);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error.code === "ENOENT")
|
|
12
|
+
return result;
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
if (directoryStat.isSymbolicLink()) {
|
|
16
|
+
throw new Error(`Refusing to reconcile selected directory '${directory}': symbolic-link traversal is unsafe.`);
|
|
17
|
+
}
|
|
18
|
+
if (!directoryStat.isDirectory()) {
|
|
19
|
+
throw new Error(`Refusing to reconcile selected directory '${directory}': expected a directory.`);
|
|
20
|
+
}
|
|
21
|
+
for (const entry of (await readdir(directory)).sort()) {
|
|
22
|
+
const path = join(directory, entry);
|
|
23
|
+
const stat = await lstat(path);
|
|
24
|
+
if (stat.isSymbolicLink()) {
|
|
25
|
+
throw new Error(`Refusing to reconcile selected directory '${directory}': symbolic link '${path}' is unsafe.`);
|
|
26
|
+
}
|
|
27
|
+
if (stat.isDirectory()) {
|
|
28
|
+
await collectDestinationFiles(path, result);
|
|
29
|
+
}
|
|
30
|
+
else if (stat.isFile()) {
|
|
31
|
+
result.push(path);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw new Error(`Refusing to reconcile selected directory '${directory}': '${path}' is not a regular file or directory.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export async function planBlueprintCatalogReconciliation(handlers, githubDirectory, blueprintSourceRoot, selectedStacks) {
|
|
40
|
+
const catalog = validateBlueprintCatalog(blueprintCatalog);
|
|
41
|
+
const handlerPlans = [];
|
|
42
|
+
for (const handler of handlers) {
|
|
43
|
+
const expansion = await planBlueprintCatalog(catalog, handler.catalogKind, handler.sourceDirectory(blueprintSourceRoot), selectedStacks);
|
|
44
|
+
const destinationDirectory = handler.destinationDirectory(githubDirectory);
|
|
45
|
+
const deletions = expansion.deletions.map((deletion) => ({
|
|
46
|
+
kind: handler.kind,
|
|
47
|
+
catalogKind: handler.catalogKind,
|
|
48
|
+
key: deletion.entry.key,
|
|
49
|
+
path: deletion.path,
|
|
50
|
+
target: handler.targetPath?.(destinationDirectory, deletion.path) ??
|
|
51
|
+
join(destinationDirectory, deletion.path),
|
|
52
|
+
directory: deletion.entry.directory,
|
|
53
|
+
reason: deletion.reason,
|
|
54
|
+
}));
|
|
55
|
+
const membershipCleanup = [];
|
|
56
|
+
for (const directory of expansion.directories) {
|
|
57
|
+
const directoryTarget = handler.targetPath?.(destinationDirectory, directory.path) ??
|
|
58
|
+
join(destinationDirectory, directory.path);
|
|
59
|
+
await assertSafeInstallPaths(githubDirectory, [directory.path], destinationDirectory, (name) => handler.targetPath?.(destinationDirectory, name) ?? join(destinationDirectory, name));
|
|
60
|
+
const sourceFiles = new Set(directory.sourceFiles);
|
|
61
|
+
const installedFiles = await collectDestinationFiles(directoryTarget);
|
|
62
|
+
for (const installedFile of installedFiles) {
|
|
63
|
+
const relativePath = relative(directoryTarget, installedFile).split(sep).join("/");
|
|
64
|
+
if (sourceFiles.has(relativePath))
|
|
65
|
+
continue;
|
|
66
|
+
const path = `${directory.path}/${relativePath}`;
|
|
67
|
+
membershipCleanup.push({
|
|
68
|
+
kind: handler.kind,
|
|
69
|
+
catalogKind: handler.catalogKind,
|
|
70
|
+
key: directory.entry.key,
|
|
71
|
+
path,
|
|
72
|
+
target: handler.targetPath?.(destinationDirectory, path) ?? join(destinationDirectory, path),
|
|
73
|
+
directory: false,
|
|
74
|
+
reason: "directory-membership",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
handlerPlans.push({
|
|
79
|
+
handler,
|
|
80
|
+
selections: expansion.selections,
|
|
81
|
+
catalogDeletions: expansion.deletions,
|
|
82
|
+
deletions,
|
|
83
|
+
membershipCleanup,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return handlerPlans;
|
|
87
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { lstat, rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { assertSafeInstallPaths } from "../Support/BlueprintFiles.js";
|
|
4
|
+
export async function validateRemovalTarget(githubDirectory, operation) {
|
|
5
|
+
const { handler, plan, expectedTarget } = operation;
|
|
6
|
+
const destinationDirectory = handler.destinationDirectory(githubDirectory);
|
|
7
|
+
const targetPath = (name) => handler.targetPath?.(destinationDirectory, name) ?? join(destinationDirectory, name);
|
|
8
|
+
await assertSafeInstallPaths(githubDirectory, [plan.path], destinationDirectory, targetPath);
|
|
9
|
+
try {
|
|
10
|
+
const stat = await lstat(plan.target);
|
|
11
|
+
if (stat.isSymbolicLink()) {
|
|
12
|
+
throw new Error(`Refusing to remove '${plan.target}': symbolic-link targets are unsafe.`);
|
|
13
|
+
}
|
|
14
|
+
if (expectedTarget === "directory" ? !stat.isDirectory() : !stat.isFile()) {
|
|
15
|
+
const expected = expectedTarget === "directory" ? "a directory" : "a regular file";
|
|
16
|
+
throw new Error(`Refusing to remove '${plan.target}': expected ${expected}.`);
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error.code === "ENOENT")
|
|
22
|
+
return false;
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function catalogRemovalOperation(operation) {
|
|
27
|
+
const { handler, deletion, plan } = operation;
|
|
28
|
+
const name = `${handler.kind} '${deletion.path}'`;
|
|
29
|
+
return {
|
|
30
|
+
handler,
|
|
31
|
+
plan,
|
|
32
|
+
expectedTarget: deletion.entry.directory ? "directory" : "file",
|
|
33
|
+
recursive: deletion.entry.directory,
|
|
34
|
+
validationDescription: `removal of ${name}`,
|
|
35
|
+
removalDescription: name,
|
|
36
|
+
completedName: name,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function membershipRemovalOperation(operation) {
|
|
40
|
+
const { handler, plan } = operation;
|
|
41
|
+
const name = `${handler.kind} '${plan.path}'`;
|
|
42
|
+
return {
|
|
43
|
+
handler,
|
|
44
|
+
plan,
|
|
45
|
+
expectedTarget: "file",
|
|
46
|
+
recursive: false,
|
|
47
|
+
validationDescription: `directory-membership cleanup of ${name}`,
|
|
48
|
+
removalDescription: `destination-only ${handler.kind} file '${plan.path}'`,
|
|
49
|
+
completedName: name,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export async function applyRemovalOperations(githubDirectory, operations, recordAppliedChange) {
|
|
53
|
+
const outcomes = [];
|
|
54
|
+
for (const operation of operations) {
|
|
55
|
+
let targetExists;
|
|
56
|
+
try {
|
|
57
|
+
targetExists = await validateRemovalTarget(githubDirectory, operation);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
throw new Error(`Failed to validate ${operation.validationDescription} at '${operation.plan.target}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
61
|
+
}
|
|
62
|
+
if (!targetExists)
|
|
63
|
+
continue;
|
|
64
|
+
try {
|
|
65
|
+
await rm(operation.plan.target, { recursive: operation.recursive });
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error(`Failed to remove ${operation.removalDescription} at '${operation.plan.target}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
69
|
+
}
|
|
70
|
+
recordAppliedChange(`removed ${operation.completedName}`);
|
|
71
|
+
outcomes.push({
|
|
72
|
+
kind: operation.handler.kind,
|
|
73
|
+
name: operation.plan.path,
|
|
74
|
+
status: "removed",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return outcomes;
|
|
78
|
+
}
|