@polymorphism-tech/morph-spec 2.4.0 → 3.0.0
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/CLAUDE.md +158 -26
- package/LICENSE +72 -72
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +8 -0
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-deploy.md +529 -0
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -227
- package/content/.claude/commands/morph-troubleshoot.md +122 -122
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/infra/azure-deploy-specialist.md +699 -0
- package/content/.claude/skills/level-0-meta/README.md +7 -0
- package/content/.claude/skills/{checklists → level-0-meta}/morph-checklist.md +117 -117
- package/content/.claude/skills/level-1-workflows/README.md +7 -0
- package/content/.claude/skills/{workflows → level-1-workflows}/morph-replicate.md +213 -213
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-clarify.md +131 -131
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-design.md +213 -205
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-setup.md +106 -92
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-tasks.md +164 -164
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-uiux.md +169 -138
- package/content/.claude/skills/level-2-domains/README.md +14 -0
- package/content/.claude/skills/{specialists → level-2-domains/quality}/testing-specialist.md +126 -126
- package/content/.claude/skills/level-3-technologies/README.md +7 -0
- package/content/.claude/skills/level-4-patterns/README.md +7 -0
- package/content/.claude/skills/specialists/prompt-engineer.md +189 -0
- package/content/.claude/skills/specialists/seo-growth-hacker.md +320 -0
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +742 -358
- package/content/.morph/config/config.template.json +33 -0
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/enforcement-pipeline.md +668 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -158
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -95
- package/content/.morph/examples/scheduled-reports/spec.md +267 -267
- package/content/.morph/examples/state-v3.json +188 -188
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +158 -0
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/hooks/task-completed.js +73 -0
- package/content/.morph/hooks/teammate-idle.js +68 -0
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -220
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-teams-workflow.md +474 -0
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/CONTEXT-FEATURE.md +276 -0
- package/content/.morph/templates/CONTEXT.md +170 -0
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/clarify-questions.md +159 -159
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -74
- package/content/.morph/templates/contracts/Entities.cs +25 -25
- package/content/.morph/templates/contracts/Queries.cs +74 -74
- package/content/.morph/templates/contracts/README.md +74 -74
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/azure-pipelines-deploy.yml +480 -0
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -426
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/templates.md +418 -418
- package/package.json +1 -1
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +83 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -193
- package/src/commands/create-story.js +351 -351
- package/src/commands/deploy.js +780 -0
- package/src/commands/detect-agents.js +34 -6
- package/src/commands/detect.js +104 -104
- package/src/commands/generate-context.js +40 -0
- package/src/commands/generate.js +149 -149
- package/src/commands/lint-fluent.js +352 -352
- package/src/commands/rollback-phase.js +185 -185
- package/src/commands/session-summary.js +291 -291
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/troubleshoot.js +222 -222
- package/src/commands/validate-blazor-state.js +210 -210
- package/src/commands/validate-blazor.js +156 -156
- package/src/commands/validate-css.js +84 -84
- package/src/commands/validate-phase.js +221 -221
- package/src/lib/blazor-concurrency-analyzer.js +288 -288
- package/src/lib/blazor-state-validator.js +291 -291
- package/src/lib/blazor-validator.js +374 -374
- package/src/lib/context-generator.js +513 -0
- package/src/lib/css-validator.js +352 -352
- package/src/lib/design-system-detector.js +187 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/design-system-scaffolder.js +299 -0
- package/src/lib/hook-executor.js +256 -0
- package/src/lib/learning-system.js +520 -520
- package/src/lib/mockup-generator.js +366 -366
- package/src/lib/spec-validator.js +258 -0
- package/src/lib/standards-context-injector.js +287 -0
- package/src/lib/team-orchestrator.js +322 -0
- package/src/lib/troubleshoot-grep.js +194 -194
- package/src/lib/troubleshoot-index.js +144 -144
- package/src/lib/ui-detector.js +350 -350
- package/src/lib/validation-runner.js +65 -13
- package/src/lib/validators/architecture-validator.js +387 -387
- package/src/lib/validators/design-system-validator.js +231 -0
- package/src/lib/validators/package-validator.js +360 -360
- package/src/lib/validators/ui-contrast-validator.js +422 -422
- package/src/utils/file-copier.js +9 -1
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- /package/content/.claude/skills/{checklists → level-0-meta}/code-review.md +0 -0
- /package/content/.claude/skills/{checklists → level-0-meta}/simulation-checklist.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/ai-agents}/ai-system-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/po-pm-advisor.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/standards-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/dotnet-senior.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ef-modeler.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/hangfire-orchestrator.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ms-agent-expert.md +0 -0
- /package/content/.claude/skills/{stacks/dotnet-blazor.md → level-2-domains/frontend/blazor-builder.md} +0 -0
- /package/content/.claude/skills/{stacks/dotnet-nextjs.md → level-2-domains/frontend/nextjs-expert.md} +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/frontend}/ui-ux-designer.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/infrastructure}/azure-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/bicep-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/container-specialist.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/devops-engineer.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/asaas-financial.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/azure-identity.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/clerk-auth.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/resend-email.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/quality}/code-analyzer.md +0 -0
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Rollback Phase Command
|
|
3
|
-
*
|
|
4
|
-
* Rolls back a feature to a previous phase, marking outputs as draft.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* morph-spec rollback <feature-name> <target-phase>
|
|
8
|
-
*
|
|
9
|
-
* Example:
|
|
10
|
-
* morph-spec rollback scheduled-reports design
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import chalk from 'chalk';
|
|
16
|
-
import { loadState, saveState, getFeature, updateFeature } from '../lib/state-manager.js';
|
|
17
|
-
|
|
18
|
-
// Phase order
|
|
19
|
-
const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get phase index
|
|
23
|
-
*/
|
|
24
|
-
function getPhaseIndex(phase) {
|
|
25
|
-
return PHASE_ORDER.indexOf(phase);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get outputs that should be marked as draft when rolling back
|
|
30
|
-
*/
|
|
31
|
-
function getOutputsToReset(fromPhase, toPhase) {
|
|
32
|
-
const fromIndex = getPhaseIndex(fromPhase);
|
|
33
|
-
const toIndex = getPhaseIndex(toPhase);
|
|
34
|
-
|
|
35
|
-
// Map phases to their outputs
|
|
36
|
-
const phaseOutputs = {
|
|
37
|
-
'proposal': ['proposal'],
|
|
38
|
-
'setup': [],
|
|
39
|
-
'uiux': ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
|
|
40
|
-
'design': ['spec', 'contracts', 'decisions'],
|
|
41
|
-
'clarify': [],
|
|
42
|
-
'tasks': ['tasks'],
|
|
43
|
-
'implement': ['recap'],
|
|
44
|
-
'sync': []
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const outputsToReset = [];
|
|
48
|
-
|
|
49
|
-
// Collect all outputs from phases after target
|
|
50
|
-
for (let i = toIndex + 1; i <= fromIndex; i++) {
|
|
51
|
-
const phase = PHASE_ORDER[i];
|
|
52
|
-
if (phaseOutputs[phase]) {
|
|
53
|
-
outputsToReset.push(...phaseOutputs[phase]);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return outputsToReset;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Main command handler
|
|
62
|
-
*/
|
|
63
|
-
export async function rollbackPhaseCommand(feature, targetPhase, options = {}) {
|
|
64
|
-
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
65
|
-
console.log(chalk.cyan('║ MORPH-SPEC ROLLBACK ║'));
|
|
66
|
-
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
67
|
-
|
|
68
|
-
// Validate target phase
|
|
69
|
-
if (!PHASE_ORDER.includes(targetPhase)) {
|
|
70
|
-
console.log(chalk.red(`❌ Invalid phase: ${targetPhase}`));
|
|
71
|
-
console.log(chalk.gray('\nValid phases:'));
|
|
72
|
-
PHASE_ORDER.forEach(p => console.log(chalk.gray(` - ${p}`)));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Get current feature state
|
|
77
|
-
let featureState;
|
|
78
|
-
try {
|
|
79
|
-
featureState = getFeature(feature);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
82
|
-
console.log(chalk.gray(' Run: morph-spec state list'));
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!featureState) {
|
|
87
|
-
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const currentPhase = featureState.phase || 'proposal';
|
|
92
|
-
const currentIndex = getPhaseIndex(currentPhase);
|
|
93
|
-
const targetIndex = getPhaseIndex(targetPhase);
|
|
94
|
-
|
|
95
|
-
// Check if rollback makes sense
|
|
96
|
-
if (targetIndex >= currentIndex) {
|
|
97
|
-
console.log(chalk.yellow(`⚠️ Cannot rollback: target phase '${targetPhase}' is not before current phase '${currentPhase}'`));
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Get outputs to reset
|
|
102
|
-
const outputsToReset = getOutputsToReset(currentPhase, targetPhase);
|
|
103
|
-
|
|
104
|
-
// Show what will happen
|
|
105
|
-
console.log(chalk.gray('Feature:'), feature);
|
|
106
|
-
console.log(chalk.gray('Current Phase:'), currentPhase);
|
|
107
|
-
console.log(chalk.gray('Target Phase:'), targetPhase);
|
|
108
|
-
console.log('');
|
|
109
|
-
|
|
110
|
-
if (outputsToReset.length > 0) {
|
|
111
|
-
console.log(chalk.yellow('Outputs that will be marked as draft:'));
|
|
112
|
-
outputsToReset.forEach(o => {
|
|
113
|
-
console.log(chalk.gray(` - ${o}`));
|
|
114
|
-
});
|
|
115
|
-
console.log('');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Confirm unless --force
|
|
119
|
-
if (!options.force) {
|
|
120
|
-
console.log(chalk.yellow('⚠️ This will:'));
|
|
121
|
-
console.log(chalk.gray(' 1. Set phase back to: ' + targetPhase));
|
|
122
|
-
console.log(chalk.gray(' 2. Reset task progress'));
|
|
123
|
-
console.log(chalk.gray(' 3. Mark outputs as not created (files remain on disk)'));
|
|
124
|
-
console.log('');
|
|
125
|
-
console.log(chalk.gray('Run with --force to confirm.'));
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Perform rollback
|
|
130
|
-
try {
|
|
131
|
-
const state = loadState();
|
|
132
|
-
|
|
133
|
-
// Update phase
|
|
134
|
-
state.features[feature].phase = targetPhase;
|
|
135
|
-
state.features[feature].status = 'in_progress';
|
|
136
|
-
state.features[feature].updatedAt = new Date().toISOString();
|
|
137
|
-
|
|
138
|
-
// Reset outputs
|
|
139
|
-
for (const output of outputsToReset) {
|
|
140
|
-
if (state.features[feature].outputs[output]) {
|
|
141
|
-
state.features[feature].outputs[output].created = false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Reset tasks if rolling back before tasks phase
|
|
146
|
-
if (targetIndex < getPhaseIndex('tasks')) {
|
|
147
|
-
state.features[feature].tasks = {
|
|
148
|
-
total: 0,
|
|
149
|
-
completed: 0,
|
|
150
|
-
inProgress: 0,
|
|
151
|
-
pending: 0
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Add checkpoint for rollback
|
|
156
|
-
state.features[feature].checkpoints = state.features[feature].checkpoints || [];
|
|
157
|
-
state.features[feature].checkpoints.push({
|
|
158
|
-
timestamp: new Date().toISOString(),
|
|
159
|
-
phase: targetPhase,
|
|
160
|
-
completedTasks: 0,
|
|
161
|
-
note: `Rollback from ${currentPhase} to ${targetPhase}`
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Track skipped phases (if any were skipped)
|
|
165
|
-
if (!state.features[feature].skippedPhases) {
|
|
166
|
-
state.features[feature].skippedPhases = [];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
saveState(state);
|
|
170
|
-
|
|
171
|
-
console.log(chalk.green('✅ Rollback completed!'));
|
|
172
|
-
console.log('');
|
|
173
|
-
console.log(chalk.gray('Current state:'));
|
|
174
|
-
console.log(chalk.gray(` Phase: ${targetPhase}`));
|
|
175
|
-
console.log(chalk.gray(` Status: in_progress`));
|
|
176
|
-
console.log('');
|
|
177
|
-
console.log(chalk.cyan('Next steps:'));
|
|
178
|
-
console.log(chalk.gray(` 1. Review and update outputs for phase: ${targetPhase}`));
|
|
179
|
-
console.log(chalk.gray(` 2. Run: morph-spec session-summary ${feature}`));
|
|
180
|
-
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.log(chalk.red(`❌ Rollback failed: ${error.message}`));
|
|
183
|
-
process.exit(1);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC Rollback Phase Command
|
|
3
|
+
*
|
|
4
|
+
* Rolls back a feature to a previous phase, marking outputs as draft.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* morph-spec rollback <feature-name> <target-phase>
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* morph-spec rollback scheduled-reports design
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { loadState, saveState, getFeature, updateFeature } from '../lib/state-manager.js';
|
|
17
|
+
|
|
18
|
+
// Phase order
|
|
19
|
+
const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get phase index
|
|
23
|
+
*/
|
|
24
|
+
function getPhaseIndex(phase) {
|
|
25
|
+
return PHASE_ORDER.indexOf(phase);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get outputs that should be marked as draft when rolling back
|
|
30
|
+
*/
|
|
31
|
+
function getOutputsToReset(fromPhase, toPhase) {
|
|
32
|
+
const fromIndex = getPhaseIndex(fromPhase);
|
|
33
|
+
const toIndex = getPhaseIndex(toPhase);
|
|
34
|
+
|
|
35
|
+
// Map phases to their outputs
|
|
36
|
+
const phaseOutputs = {
|
|
37
|
+
'proposal': ['proposal'],
|
|
38
|
+
'setup': [],
|
|
39
|
+
'uiux': ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
|
|
40
|
+
'design': ['spec', 'contracts', 'decisions'],
|
|
41
|
+
'clarify': [],
|
|
42
|
+
'tasks': ['tasks'],
|
|
43
|
+
'implement': ['recap'],
|
|
44
|
+
'sync': []
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const outputsToReset = [];
|
|
48
|
+
|
|
49
|
+
// Collect all outputs from phases after target
|
|
50
|
+
for (let i = toIndex + 1; i <= fromIndex; i++) {
|
|
51
|
+
const phase = PHASE_ORDER[i];
|
|
52
|
+
if (phaseOutputs[phase]) {
|
|
53
|
+
outputsToReset.push(...phaseOutputs[phase]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return outputsToReset;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Main command handler
|
|
62
|
+
*/
|
|
63
|
+
export async function rollbackPhaseCommand(feature, targetPhase, options = {}) {
|
|
64
|
+
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
65
|
+
console.log(chalk.cyan('║ MORPH-SPEC ROLLBACK ║'));
|
|
66
|
+
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
67
|
+
|
|
68
|
+
// Validate target phase
|
|
69
|
+
if (!PHASE_ORDER.includes(targetPhase)) {
|
|
70
|
+
console.log(chalk.red(`❌ Invalid phase: ${targetPhase}`));
|
|
71
|
+
console.log(chalk.gray('\nValid phases:'));
|
|
72
|
+
PHASE_ORDER.forEach(p => console.log(chalk.gray(` - ${p}`)));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get current feature state
|
|
77
|
+
let featureState;
|
|
78
|
+
try {
|
|
79
|
+
featureState = getFeature(feature);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
82
|
+
console.log(chalk.gray(' Run: morph-spec state list'));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!featureState) {
|
|
87
|
+
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const currentPhase = featureState.phase || 'proposal';
|
|
92
|
+
const currentIndex = getPhaseIndex(currentPhase);
|
|
93
|
+
const targetIndex = getPhaseIndex(targetPhase);
|
|
94
|
+
|
|
95
|
+
// Check if rollback makes sense
|
|
96
|
+
if (targetIndex >= currentIndex) {
|
|
97
|
+
console.log(chalk.yellow(`⚠️ Cannot rollback: target phase '${targetPhase}' is not before current phase '${currentPhase}'`));
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get outputs to reset
|
|
102
|
+
const outputsToReset = getOutputsToReset(currentPhase, targetPhase);
|
|
103
|
+
|
|
104
|
+
// Show what will happen
|
|
105
|
+
console.log(chalk.gray('Feature:'), feature);
|
|
106
|
+
console.log(chalk.gray('Current Phase:'), currentPhase);
|
|
107
|
+
console.log(chalk.gray('Target Phase:'), targetPhase);
|
|
108
|
+
console.log('');
|
|
109
|
+
|
|
110
|
+
if (outputsToReset.length > 0) {
|
|
111
|
+
console.log(chalk.yellow('Outputs that will be marked as draft:'));
|
|
112
|
+
outputsToReset.forEach(o => {
|
|
113
|
+
console.log(chalk.gray(` - ${o}`));
|
|
114
|
+
});
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Confirm unless --force
|
|
119
|
+
if (!options.force) {
|
|
120
|
+
console.log(chalk.yellow('⚠️ This will:'));
|
|
121
|
+
console.log(chalk.gray(' 1. Set phase back to: ' + targetPhase));
|
|
122
|
+
console.log(chalk.gray(' 2. Reset task progress'));
|
|
123
|
+
console.log(chalk.gray(' 3. Mark outputs as not created (files remain on disk)'));
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(chalk.gray('Run with --force to confirm.'));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Perform rollback
|
|
130
|
+
try {
|
|
131
|
+
const state = loadState();
|
|
132
|
+
|
|
133
|
+
// Update phase
|
|
134
|
+
state.features[feature].phase = targetPhase;
|
|
135
|
+
state.features[feature].status = 'in_progress';
|
|
136
|
+
state.features[feature].updatedAt = new Date().toISOString();
|
|
137
|
+
|
|
138
|
+
// Reset outputs
|
|
139
|
+
for (const output of outputsToReset) {
|
|
140
|
+
if (state.features[feature].outputs[output]) {
|
|
141
|
+
state.features[feature].outputs[output].created = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Reset tasks if rolling back before tasks phase
|
|
146
|
+
if (targetIndex < getPhaseIndex('tasks')) {
|
|
147
|
+
state.features[feature].tasks = {
|
|
148
|
+
total: 0,
|
|
149
|
+
completed: 0,
|
|
150
|
+
inProgress: 0,
|
|
151
|
+
pending: 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Add checkpoint for rollback
|
|
156
|
+
state.features[feature].checkpoints = state.features[feature].checkpoints || [];
|
|
157
|
+
state.features[feature].checkpoints.push({
|
|
158
|
+
timestamp: new Date().toISOString(),
|
|
159
|
+
phase: targetPhase,
|
|
160
|
+
completedTasks: 0,
|
|
161
|
+
note: `Rollback from ${currentPhase} to ${targetPhase}`
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Track skipped phases (if any were skipped)
|
|
165
|
+
if (!state.features[feature].skippedPhases) {
|
|
166
|
+
state.features[feature].skippedPhases = [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
saveState(state);
|
|
170
|
+
|
|
171
|
+
console.log(chalk.green('✅ Rollback completed!'));
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(chalk.gray('Current state:'));
|
|
174
|
+
console.log(chalk.gray(` Phase: ${targetPhase}`));
|
|
175
|
+
console.log(chalk.gray(` Status: in_progress`));
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log(chalk.cyan('Next steps:'));
|
|
178
|
+
console.log(chalk.gray(` 1. Review and update outputs for phase: ${targetPhase}`));
|
|
179
|
+
console.log(chalk.gray(` 2. Run: morph-spec session-summary ${feature}`));
|
|
180
|
+
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.log(chalk.red(`❌ Rollback failed: ${error.message}`));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
}
|