scene-capability-engine 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/CHANGELOG.md +2513 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/README.zh.md +630 -0
- package/bin/kiro-spec-engine.js +796 -0
- package/bin/kse.js +3 -0
- package/bin/sce.js +3 -0
- package/bin/sco.js +3 -0
- package/docs/331-poc-adaptation-roadmap.md +156 -0
- package/docs/331-poc-dual-track-integration-guide.md +120 -0
- package/docs/331-poc-weekly-delivery-checklist.md +52 -0
- package/docs/OFFLINE_INSTALL.md +96 -0
- package/docs/README.md +279 -0
- package/docs/adopt-migration-guide.md +599 -0
- package/docs/adoption-guide.md +616 -0
- package/docs/agent-hooks-analysis.md +815 -0
- package/docs/architecture.md +733 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
- package/docs/autonomous-control-guide.md +851 -0
- package/docs/command-reference.md +1368 -0
- package/docs/community.md +115 -0
- package/docs/cross-tool-guide.md +555 -0
- package/docs/developer-guide.md +619 -0
- package/docs/document-governance.md +865 -0
- package/docs/environment-management-guide.md +526 -0
- package/docs/examples/add-export-command/design.md +194 -0
- package/docs/examples/add-export-command/requirements.md +110 -0
- package/docs/examples/add-export-command/tasks.md +88 -0
- package/docs/examples/add-rest-api/design.md +855 -0
- package/docs/examples/add-rest-api/requirements.md +323 -0
- package/docs/examples/add-rest-api/tasks.md +355 -0
- package/docs/examples/add-user-dashboard/design.md +192 -0
- package/docs/examples/add-user-dashboard/requirements.md +143 -0
- package/docs/examples/add-user-dashboard/tasks.md +91 -0
- package/docs/faq.md +697 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
- package/docs/images/wechat-qr.png +0 -0
- package/docs/integration-modes.md +529 -0
- package/docs/integration-philosophy.md +313 -0
- package/docs/knowledge-management-guide.md +263 -0
- package/docs/manual-workflows-guide.md +418 -0
- package/docs/moqui-capability-matrix.md +73 -0
- package/docs/moqui-template-core-library-playbook.md +109 -0
- package/docs/multi-agent-coordination-guide.md +553 -0
- package/docs/multi-repo-management-guide.md +1344 -0
- package/docs/quick-start-with-ai-tools.md +375 -0
- package/docs/quick-start.md +146 -0
- package/docs/release-checklist.md +121 -0
- package/docs/releases/README.md +13 -0
- package/docs/releases/v1.46.2-validation.md +45 -0
- package/docs/releases/v1.46.2.md +50 -0
- package/docs/scene-runtime-guide.md +347 -0
- package/docs/spec-collaboration-guide.md +369 -0
- package/docs/spec-locking-guide.md +225 -0
- package/docs/spec-numbering-guide.md +348 -0
- package/docs/spec-workflow.md +519 -0
- package/docs/steering-strategy-guide.md +196 -0
- package/docs/team-collaboration-guide.md +465 -0
- package/docs/testing-strategy.md +272 -0
- package/docs/tools/claude-guide.md +654 -0
- package/docs/tools/cursor-guide.md +706 -0
- package/docs/tools/generic-guide.md +446 -0
- package/docs/tools/kiro-guide.md +308 -0
- package/docs/tools/vscode-guide.md +445 -0
- package/docs/tools/windsurf-guide.md +391 -0
- package/docs/troubleshooting.md +1135 -0
- package/docs/upgrade-guide.md +639 -0
- package/docs/value-observability-guide.md +127 -0
- package/docs/zh/README.md +341 -0
- package/docs/zh/quick-start.md +764 -0
- package/docs/zh/release-checklist.md +121 -0
- package/docs/zh/releases/README.md +13 -0
- package/docs/zh/releases/v1.46.2-validation.md +45 -0
- package/docs/zh/releases/v1.46.2.md +50 -0
- package/docs/zh/spec-numbering-guide.md +348 -0
- package/docs/zh/tools/claude-guide.md +349 -0
- package/docs/zh/tools/cursor-guide.md +281 -0
- package/docs/zh/tools/generic-guide.md +499 -0
- package/docs/zh/tools/kiro-guide.md +342 -0
- package/docs/zh/tools/vscode-guide.md +449 -0
- package/docs/zh/tools/windsurf-guide.md +378 -0
- package/docs/zh/value-observability-guide.md +127 -0
- package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
- package/lib/adoption/adoption-logger.js +487 -0
- package/lib/adoption/adoption-strategy.js +538 -0
- package/lib/adoption/backup-manager.js +420 -0
- package/lib/adoption/conflict-resolver.js +410 -0
- package/lib/adoption/detection-engine.js +275 -0
- package/lib/adoption/diff-viewer.js +226 -0
- package/lib/adoption/error-formatter.js +509 -0
- package/lib/adoption/file-classifier.js +385 -0
- package/lib/adoption/progress-reporter.js +534 -0
- package/lib/adoption/smart-orchestrator.js +470 -0
- package/lib/adoption/strategy-selector.js +218 -0
- package/lib/adoption/summary-generator.js +493 -0
- package/lib/adoption/template-sync.js +605 -0
- package/lib/auto/autonomous-engine.js +485 -0
- package/lib/auto/checkpoint-manager.js +300 -0
- package/lib/auto/close-loop-runner.js +2476 -0
- package/lib/auto/config-schema.js +176 -0
- package/lib/auto/decision-engine.js +344 -0
- package/lib/auto/error-recovery-manager.js +580 -0
- package/lib/auto/goal-decomposer.js +278 -0
- package/lib/auto/progress-tracker.js +502 -0
- package/lib/auto/safety-manager.js +186 -0
- package/lib/auto/semantic-decomposer.js +137 -0
- package/lib/auto/state-manager.js +126 -0
- package/lib/auto/task-queue-manager.js +340 -0
- package/lib/backup/backup-system.js +372 -0
- package/lib/backup/selective-backup.js +207 -0
- package/lib/collab/agent-registry.js +240 -0
- package/lib/collab/collab-manager.js +285 -0
- package/lib/collab/contract-manager.js +320 -0
- package/lib/collab/coordinator.js +370 -0
- package/lib/collab/dependency-manager.js +280 -0
- package/lib/collab/index.js +20 -0
- package/lib/collab/integration-manager.js +202 -0
- package/lib/collab/merge-coordinator.js +252 -0
- package/lib/collab/metadata-manager.js +233 -0
- package/lib/collab/multi-agent-config.js +120 -0
- package/lib/collab/spec-lifecycle-manager.js +304 -0
- package/lib/collab/sync-barrier.js +88 -0
- package/lib/collab/visualizer.js +208 -0
- package/lib/commands/adopt.js +749 -0
- package/lib/commands/auto.js +19559 -0
- package/lib/commands/collab.js +275 -0
- package/lib/commands/context.js +99 -0
- package/lib/commands/docs.js +808 -0
- package/lib/commands/doctor.js +273 -0
- package/lib/commands/env.js +420 -0
- package/lib/commands/knowledge.js +309 -0
- package/lib/commands/lock.js +235 -0
- package/lib/commands/ops.js +409 -0
- package/lib/commands/orchestrate.js +446 -0
- package/lib/commands/prompt.js +105 -0
- package/lib/commands/repo.js +118 -0
- package/lib/commands/rollback.js +219 -0
- package/lib/commands/scene.js +15549 -0
- package/lib/commands/spec-bootstrap.js +147 -0
- package/lib/commands/spec-gate.js +157 -0
- package/lib/commands/spec-pipeline.js +205 -0
- package/lib/commands/status.js +321 -0
- package/lib/commands/task.js +199 -0
- package/lib/commands/templates.js +654 -0
- package/lib/commands/upgrade.js +231 -0
- package/lib/commands/value.js +569 -0
- package/lib/commands/watch.js +684 -0
- package/lib/commands/workflows.js +240 -0
- package/lib/commands/workspace-multi.js +325 -0
- package/lib/commands/workspace.js +189 -0
- package/lib/context/context-exporter.js +378 -0
- package/lib/context/prompt-generator.js +482 -0
- package/lib/data/moqui-capability-lexicon.json +45 -0
- package/lib/environment/backup-system.js +189 -0
- package/lib/environment/environment-manager.js +379 -0
- package/lib/environment/environment-registry.js +168 -0
- package/lib/gitignore/gitignore-backup.js +229 -0
- package/lib/gitignore/gitignore-detector.js +239 -0
- package/lib/gitignore/gitignore-integration.js +267 -0
- package/lib/gitignore/gitignore-transformer.js +193 -0
- package/lib/gitignore/layered-rules-template.js +42 -0
- package/lib/governance/archive-tool.js +284 -0
- package/lib/governance/cleanup-tool.js +237 -0
- package/lib/governance/config-manager.js +186 -0
- package/lib/governance/diagnostic-engine.js +271 -0
- package/lib/governance/doc-reference-checker.js +200 -0
- package/lib/governance/execution-logger.js +243 -0
- package/lib/governance/file-scanner.js +285 -0
- package/lib/governance/hooks-manager.js +333 -0
- package/lib/governance/reporter.js +337 -0
- package/lib/governance/validation-engine.js +181 -0
- package/lib/i18n.js +79 -0
- package/lib/knowledge/entry-manager.js +208 -0
- package/lib/knowledge/index-manager.js +261 -0
- package/lib/knowledge/knowledge-manager.js +273 -0
- package/lib/knowledge/template-manager.js +191 -0
- package/lib/lock/index.js +21 -0
- package/lib/lock/lock-file.js +192 -0
- package/lib/lock/lock-manager.js +321 -0
- package/lib/lock/machine-identifier.js +135 -0
- package/lib/lock/steering-file-lock.js +207 -0
- package/lib/lock/task-lock-manager.js +345 -0
- package/lib/operations/audit-logger.js +293 -0
- package/lib/operations/feedback-manager.js +1147 -0
- package/lib/operations/index.js +23 -0
- package/lib/operations/models/index.js +170 -0
- package/lib/operations/operations-manager.js +151 -0
- package/lib/operations/operations-validator.js +280 -0
- package/lib/operations/permission-manager.js +354 -0
- package/lib/operations/template-loader.js +143 -0
- package/lib/orchestrator/agent-spawner.js +629 -0
- package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
- package/lib/orchestrator/index.js +19 -0
- package/lib/orchestrator/orchestration-engine.js +1270 -0
- package/lib/orchestrator/orchestrator-config.js +173 -0
- package/lib/orchestrator/status-monitor.js +591 -0
- package/lib/python-checker.js +209 -0
- package/lib/repo/config-manager.js +580 -0
- package/lib/repo/errors/config-error.js +13 -0
- package/lib/repo/errors/git-error.js +15 -0
- package/lib/repo/errors/repo-error.js +14 -0
- package/lib/repo/git-operations.js +181 -0
- package/lib/repo/handlers/.gitkeep +1 -0
- package/lib/repo/handlers/exec-handler.js +155 -0
- package/lib/repo/handlers/health-handler.js +169 -0
- package/lib/repo/handlers/init-handler.js +197 -0
- package/lib/repo/handlers/status-handler.js +176 -0
- package/lib/repo/output-formatter.js +184 -0
- package/lib/repo/path-resolver.js +178 -0
- package/lib/repo/repo-manager.js +514 -0
- package/lib/scene-runtime/audit-emitter.js +59 -0
- package/lib/scene-runtime/binding-plugin-loader.js +351 -0
- package/lib/scene-runtime/binding-registry.js +349 -0
- package/lib/scene-runtime/eval-bridge.js +44 -0
- package/lib/scene-runtime/index.js +19 -0
- package/lib/scene-runtime/moqui-adapter.js +620 -0
- package/lib/scene-runtime/moqui-client.js +606 -0
- package/lib/scene-runtime/moqui-extractor.js +2029 -0
- package/lib/scene-runtime/plan-compiler.js +208 -0
- package/lib/scene-runtime/policy-gate.js +58 -0
- package/lib/scene-runtime/runtime-executor.js +358 -0
- package/lib/scene-runtime/scene-loader.js +96 -0
- package/lib/scene-runtime/scene-ontology.js +959 -0
- package/lib/scene-runtime/scene-template-linter.js +852 -0
- package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
- package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
- package/lib/spec/bootstrap/context-collector.js +48 -0
- package/lib/spec/bootstrap/draft-generator.js +158 -0
- package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
- package/lib/spec/bootstrap/trace-emitter.js +59 -0
- package/lib/spec/multi-spec-orchestrate.js +93 -0
- package/lib/spec/pipeline/constants.js +6 -0
- package/lib/spec/pipeline/stage-adapters.js +118 -0
- package/lib/spec/pipeline/stage-runner.js +146 -0
- package/lib/spec/pipeline/state-store.js +119 -0
- package/lib/spec-gate/engine/gate-engine.js +165 -0
- package/lib/spec-gate/policy/default-policy.js +22 -0
- package/lib/spec-gate/policy/policy-loader.js +103 -0
- package/lib/spec-gate/result-emitter.js +81 -0
- package/lib/spec-gate/rules/default-rules.js +156 -0
- package/lib/spec-gate/rules/rule-registry.js +51 -0
- package/lib/steering/adoption-config.js +164 -0
- package/lib/steering/compliance-auto-fixer.js +204 -0
- package/lib/steering/compliance-cache.js +99 -0
- package/lib/steering/compliance-error-reporter.js +70 -0
- package/lib/steering/context-sync-manager.js +273 -0
- package/lib/steering/index.js +92 -0
- package/lib/steering/spec-steering.js +230 -0
- package/lib/steering/steering-compliance-checker.js +73 -0
- package/lib/steering/steering-loader.js +144 -0
- package/lib/steering/steering-manager.js +289 -0
- package/lib/task/index.js +12 -0
- package/lib/task/task-claimer.js +489 -0
- package/lib/task/task-status-store.js +418 -0
- package/lib/templates/cache-manager.js +440 -0
- package/lib/templates/content-generalizer.js +247 -0
- package/lib/templates/frontmatter-generator.js +128 -0
- package/lib/templates/git-handler.js +471 -0
- package/lib/templates/metadata-collector.js +328 -0
- package/lib/templates/path-utils.js +144 -0
- package/lib/templates/registry-parser.js +505 -0
- package/lib/templates/spec-reader.js +216 -0
- package/lib/templates/template-applicator.js +249 -0
- package/lib/templates/template-creator.js +256 -0
- package/lib/templates/template-error.js +143 -0
- package/lib/templates/template-exporter.js +502 -0
- package/lib/templates/template-manager.js +782 -0
- package/lib/templates/template-validator.js +361 -0
- package/lib/upgrade/migration-engine.js +382 -0
- package/lib/upgrade/migrations/.gitkeep +52 -0
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
- package/lib/utils/file-diff.js +177 -0
- package/lib/utils/fs-utils.js +274 -0
- package/lib/utils/tool-detector.js +383 -0
- package/lib/utils/validation.js +324 -0
- package/lib/value/gate-summary-emitter.js +99 -0
- package/lib/value/metric-contract-loader.js +210 -0
- package/lib/value/risk-evaluator.js +117 -0
- package/lib/value/weekly-snapshot-builder.js +61 -0
- package/lib/version/version-checker.js +156 -0
- package/lib/version/version-manager.js +327 -0
- package/lib/watch/action-executor.js +458 -0
- package/lib/watch/event-debouncer.js +323 -0
- package/lib/watch/execution-logger.js +550 -0
- package/lib/watch/file-watcher.js +499 -0
- package/lib/watch/presets.js +266 -0
- package/lib/watch/watch-manager.js +533 -0
- package/lib/workspace/multi/global-config.js +150 -0
- package/lib/workspace/multi/index.js +22 -0
- package/lib/workspace/multi/path-utils.js +173 -0
- package/lib/workspace/multi/workspace-context-resolver.js +244 -0
- package/lib/workspace/multi/workspace-registry.js +196 -0
- package/lib/workspace/multi/workspace-state-manager.js +537 -0
- package/lib/workspace/multi/workspace.js +90 -0
- package/lib/workspace/workspace-manager.js +370 -0
- package/lib/workspace/workspace-sync.js +356 -0
- package/locales/en.json +114 -0
- package/locales/zh.json +114 -0
- package/package.json +102 -0
- package/template/.kiro/README.md +247 -0
- package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
- package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
- package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
- package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
- package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
- package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
- package/template/.kiro/steering/ENVIRONMENT.md +35 -0
- package/template/.kiro/steering/RULES_GUIDE.md +46 -0
- package/template/.kiro/templates/operations/default/change-impact.md +112 -0
- package/template/.kiro/templates/operations/default/deployment.md +91 -0
- package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
- package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
- package/template/.kiro/templates/operations/default/monitoring.md +135 -0
- package/template/.kiro/templates/operations/default/operations.md +135 -0
- package/template/.kiro/templates/operations/default/rollback.md +143 -0
- package/template/.kiro/templates/operations/default/tools.yaml +364 -0
- package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
- package/template/.kiro/tools/backup_manager.py +295 -0
- package/template/.kiro/tools/configuration_manager.py +218 -0
- package/template/.kiro/tools/document_evaluator.py +550 -0
- package/template/.kiro/tools/enhancement_logger.py +168 -0
- package/template/.kiro/tools/error_handler.py +335 -0
- package/template/.kiro/tools/improvement_identifier.py +444 -0
- package/template/.kiro/tools/modification_applicator.py +737 -0
- package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
- package/template/.kiro/tools/quality_scorer.py +305 -0
- package/template/.kiro/tools/report_generator.py +154 -0
- package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
- package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
- package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
- package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
- package/template/.kiro/tools/workflow_quality_gate.py +100 -0
- package/template/README.md +111 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const DEFAULT_METRIC_DIRECTIONS = {
|
|
2
|
+
ttfv_minutes: 'lower',
|
|
3
|
+
batch_success_rate: 'higher',
|
|
4
|
+
cycle_reduction_rate: 'higher',
|
|
5
|
+
manual_takeover_rate: 'lower'
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function parsePeriodKey(period) {
|
|
9
|
+
const match = /^(\d{4})-W(\d{2})$/.exec(period || '');
|
|
10
|
+
if (!match) {
|
|
11
|
+
return Number.MAX_SAFE_INTEGER;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const year = Number(match[1]);
|
|
15
|
+
const week = Number(match[2]);
|
|
16
|
+
return (year * 100) + week;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isWorse(current, previous, direction) {
|
|
20
|
+
if (!Number.isFinite(current) || !Number.isFinite(previous)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (direction === 'lower') {
|
|
25
|
+
return current > previous;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return current < previous;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class RiskEvaluator {
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.metricDirections = {
|
|
34
|
+
...DEFAULT_METRIC_DIRECTIONS,
|
|
35
|
+
...(options.metricDirections || {})
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
evaluate(options = {}) {
|
|
40
|
+
const {
|
|
41
|
+
historySnapshots = [],
|
|
42
|
+
currentSnapshot
|
|
43
|
+
} = options;
|
|
44
|
+
|
|
45
|
+
if (!currentSnapshot || typeof currentSnapshot !== 'object' || !currentSnapshot.period) {
|
|
46
|
+
throw new Error('currentSnapshot with valid period is required');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const dedupedByPeriod = new Map();
|
|
50
|
+
historySnapshots.forEach(snapshot => {
|
|
51
|
+
if (snapshot && snapshot.period) {
|
|
52
|
+
dedupedByPeriod.set(snapshot.period, snapshot);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
dedupedByPeriod.set(currentSnapshot.period, currentSnapshot);
|
|
56
|
+
|
|
57
|
+
const snapshots = Array.from(dedupedByPeriod.values())
|
|
58
|
+
.sort((left, right) => parsePeriodKey(left.period) - parsePeriodKey(right.period));
|
|
59
|
+
|
|
60
|
+
const details = {};
|
|
61
|
+
const streaks = {};
|
|
62
|
+
|
|
63
|
+
Object.entries(this.metricDirections).forEach(([metricId, direction]) => {
|
|
64
|
+
details[metricId] = {
|
|
65
|
+
better_direction: direction,
|
|
66
|
+
max_consecutive_worse: 0,
|
|
67
|
+
triggered: false
|
|
68
|
+
};
|
|
69
|
+
streaks[metricId] = 0;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
for (let index = 1; index < snapshots.length; index += 1) {
|
|
73
|
+
const previous = snapshots[index - 1];
|
|
74
|
+
const current = snapshots[index];
|
|
75
|
+
|
|
76
|
+
Object.entries(this.metricDirections).forEach(([metricId, direction]) => {
|
|
77
|
+
const currentValue = Number(current[metricId]);
|
|
78
|
+
const previousValue = Number(previous[metricId]);
|
|
79
|
+
|
|
80
|
+
if (isWorse(currentValue, previousValue, direction)) {
|
|
81
|
+
streaks[metricId] += 1;
|
|
82
|
+
} else {
|
|
83
|
+
streaks[metricId] = 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
details[metricId].max_consecutive_worse = Math.max(
|
|
87
|
+
details[metricId].max_consecutive_worse,
|
|
88
|
+
streaks[metricId]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (streaks[metricId] >= 2) {
|
|
92
|
+
details[metricId].triggered = true;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const triggeredMetrics = Object.entries(details)
|
|
98
|
+
.filter(([, value]) => value.triggered)
|
|
99
|
+
.map(([metricId]) => metricId);
|
|
100
|
+
|
|
101
|
+
const reasons = triggeredMetrics.map(metricId => (
|
|
102
|
+
`${metricId} worsened for 2 consecutive weeks`
|
|
103
|
+
));
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
evaluated_period: currentSnapshot.period,
|
|
107
|
+
risk_level: triggeredMetrics.length > 0 ? 'high' : 'medium',
|
|
108
|
+
triggered_metrics: triggeredMetrics,
|
|
109
|
+
reasons,
|
|
110
|
+
details
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = RiskEvaluator;
|
|
116
|
+
module.exports.parsePeriodKey = parsePeriodKey;
|
|
117
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const PERIOD_REGEX = /^\d{4}-W(0[1-9]|[1-4]\d|5[0-3])$/;
|
|
2
|
+
|
|
3
|
+
function isValidPeriod(period) {
|
|
4
|
+
return typeof period === 'string' && PERIOD_REGEX.test(period.trim());
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
class WeeklySnapshotBuilder {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.now = typeof options.now === 'function'
|
|
10
|
+
? options.now
|
|
11
|
+
: (() => new Date().toISOString());
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
build(options = {}) {
|
|
15
|
+
const {
|
|
16
|
+
period,
|
|
17
|
+
metrics,
|
|
18
|
+
notes = '',
|
|
19
|
+
contract
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
if (!isValidPeriod(period)) {
|
|
23
|
+
throw new Error(`Invalid period format: ${period}. Expected YYYY-WNN.`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!contract || !Array.isArray(contract.metrics)) {
|
|
27
|
+
throw new Error('Metric contract is required to build snapshot');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!metrics || typeof metrics !== 'object') {
|
|
31
|
+
throw new Error('Snapshot metrics input must be an object');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const metricValues = {};
|
|
35
|
+
contract.metrics.forEach(metric => {
|
|
36
|
+
if (!Object.prototype.hasOwnProperty.call(metrics, metric.id)) {
|
|
37
|
+
throw new Error(`Missing metric value: ${metric.id}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const numericValue = Number(metrics[metric.id]);
|
|
41
|
+
if (!Number.isFinite(numericValue)) {
|
|
42
|
+
throw new Error(`Metric value must be numeric: ${metric.id}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
metricValues[metric.id] = numericValue;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
period,
|
|
50
|
+
...metricValues,
|
|
51
|
+
risk_level: 'medium',
|
|
52
|
+
reasons: [],
|
|
53
|
+
notes,
|
|
54
|
+
generated_at: this.now()
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = WeeklySnapshotBuilder;
|
|
60
|
+
module.exports.isValidPeriod = isValidPeriod;
|
|
61
|
+
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Checker
|
|
3
|
+
*
|
|
4
|
+
* Automatically detects version mismatches between project and installed kse.
|
|
5
|
+
* Displays warnings and upgrade suggestions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const VersionManager = require('./version-manager');
|
|
10
|
+
|
|
11
|
+
class VersionChecker {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.versionManager = new VersionManager();
|
|
14
|
+
this.suppressWarnings = false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks for version mismatch and displays warning if needed
|
|
19
|
+
*
|
|
20
|
+
* @param {string} projectPath - Absolute path to project root
|
|
21
|
+
* @param {Object} options - Check options
|
|
22
|
+
* @param {boolean} options.noVersionCheck - Suppress warnings
|
|
23
|
+
* @returns {Promise<VersionCheckResult>}
|
|
24
|
+
*/
|
|
25
|
+
async checkVersion(projectPath, options = {}) {
|
|
26
|
+
const { noVersionCheck = false } = options;
|
|
27
|
+
|
|
28
|
+
if (noVersionCheck || this.suppressWarnings) {
|
|
29
|
+
return { mismatch: false, shouldUpgrade: false };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Read project version
|
|
34
|
+
const projectVersionInfo = await this.versionManager.readVersion(projectPath);
|
|
35
|
+
|
|
36
|
+
if (!projectVersionInfo) {
|
|
37
|
+
// No version.json - project might not be initialized
|
|
38
|
+
return { mismatch: false, shouldUpgrade: false };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const projectVersion = projectVersionInfo['kse-version'];
|
|
42
|
+
|
|
43
|
+
// Get current kse version
|
|
44
|
+
const packageJson = require('../../package.json');
|
|
45
|
+
const kseVersion = packageJson.version;
|
|
46
|
+
|
|
47
|
+
// Check if upgrade is needed
|
|
48
|
+
const needsUpgrade = this.versionManager.needsUpgrade(projectVersion, kseVersion);
|
|
49
|
+
|
|
50
|
+
if (needsUpgrade) {
|
|
51
|
+
this.displayWarning(projectVersion, kseVersion);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
mismatch: needsUpgrade,
|
|
56
|
+
shouldUpgrade: needsUpgrade,
|
|
57
|
+
projectVersion,
|
|
58
|
+
kseVersion
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
// Silently fail - don't block commands if version check fails
|
|
62
|
+
return { mismatch: false, shouldUpgrade: false, error: error.message };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Displays version mismatch warning
|
|
68
|
+
*
|
|
69
|
+
* @param {string} projectVersion - Project version
|
|
70
|
+
* @param {string} kseVersion - Current kse version
|
|
71
|
+
*/
|
|
72
|
+
displayWarning(projectVersion, kseVersion) {
|
|
73
|
+
console.log();
|
|
74
|
+
console.log(chalk.yellow('⚠️ Version Mismatch Detected'));
|
|
75
|
+
console.log(chalk.gray(' Project initialized with kse'), chalk.cyan(`v${projectVersion}`));
|
|
76
|
+
console.log(chalk.gray(' Current kse version:'), chalk.cyan(`v${kseVersion}`));
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.blue('💡 Tip:'), chalk.gray('Run'), chalk.cyan('kse upgrade'), chalk.gray('to update project templates'));
|
|
79
|
+
console.log(chalk.gray(' Or use'), chalk.cyan('--no-version-check'), chalk.gray('to suppress this warning'));
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Checks version and displays detailed information
|
|
85
|
+
*
|
|
86
|
+
* @param {string} projectPath - Absolute path to project root
|
|
87
|
+
* @returns {Promise<void>}
|
|
88
|
+
*/
|
|
89
|
+
async displayVersionInfo(projectPath) {
|
|
90
|
+
try {
|
|
91
|
+
const projectVersionInfo = await this.versionManager.readVersion(projectPath);
|
|
92
|
+
|
|
93
|
+
if (!projectVersionInfo) {
|
|
94
|
+
console.log(chalk.yellow('⚠️ No version information found'));
|
|
95
|
+
console.log(chalk.gray(' This project may not be initialized with kse'));
|
|
96
|
+
console.log(chalk.gray(' Run'), chalk.cyan('kse adopt'), chalk.gray('to adopt this project'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const packageJson = require('../../package.json');
|
|
101
|
+
const kseVersion = packageJson.version;
|
|
102
|
+
|
|
103
|
+
console.log(chalk.blue('📦 Version Information'));
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(chalk.gray('Project:'));
|
|
106
|
+
console.log(` kse version: ${chalk.cyan(projectVersionInfo['kse-version'])}`);
|
|
107
|
+
console.log(` Template version: ${chalk.cyan(projectVersionInfo['template-version'])}`);
|
|
108
|
+
console.log(` Created: ${chalk.gray(new Date(projectVersionInfo.created).toLocaleString())}`);
|
|
109
|
+
console.log(` Last upgraded: ${chalk.gray(new Date(projectVersionInfo['last-upgraded']).toLocaleString())}`);
|
|
110
|
+
|
|
111
|
+
console.log();
|
|
112
|
+
console.log(chalk.gray('Installed:'));
|
|
113
|
+
console.log(` kse version: ${chalk.cyan(kseVersion)}`);
|
|
114
|
+
|
|
115
|
+
if (projectVersionInfo['upgrade-history'].length > 0) {
|
|
116
|
+
console.log();
|
|
117
|
+
console.log(chalk.gray('Upgrade History:'));
|
|
118
|
+
projectVersionInfo['upgrade-history'].forEach((entry, index) => {
|
|
119
|
+
const icon = entry.success ? chalk.green('✅') : chalk.red('❌');
|
|
120
|
+
const date = new Date(entry.date).toLocaleString();
|
|
121
|
+
console.log(` ${icon} ${entry.from} → ${entry.to} (${date})`);
|
|
122
|
+
if (entry.error) {
|
|
123
|
+
console.log(` ${chalk.red('Error:')} ${entry.error}`);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log();
|
|
129
|
+
|
|
130
|
+
const needsUpgrade = this.versionManager.needsUpgrade(
|
|
131
|
+
projectVersionInfo['kse-version'],
|
|
132
|
+
kseVersion
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (needsUpgrade) {
|
|
136
|
+
console.log(chalk.yellow('⚠️ Upgrade available'));
|
|
137
|
+
console.log(chalk.gray(' Run'), chalk.cyan('kse upgrade'), chalk.gray('to update to'), chalk.cyan(`v${kseVersion}`));
|
|
138
|
+
} else {
|
|
139
|
+
console.log(chalk.green('✅ Project is up to date'));
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.log(chalk.red('❌ Error:'), error.message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Suppresses version check warnings
|
|
148
|
+
*
|
|
149
|
+
* @param {boolean} suppress - Whether to suppress warnings
|
|
150
|
+
*/
|
|
151
|
+
setSuppressWarnings(suppress) {
|
|
152
|
+
this.suppressWarnings = suppress;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = VersionChecker;
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages version tracking, compatibility checking, and upgrade path calculation
|
|
5
|
+
* for the kiro-spec-engine project adoption and upgrade system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const semver = require('semver');
|
|
10
|
+
const { readJSON, writeJSON, pathExists } = require('../utils/fs-utils');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Compatibility matrix defining which versions can work together
|
|
14
|
+
* Format: { version: { compatible: [versions], breaking: boolean } }
|
|
15
|
+
*/
|
|
16
|
+
const COMPATIBILITY_MATRIX = {
|
|
17
|
+
'1.0.0': { compatible: ['1.0.0', '1.1.0', '1.2.0'], breaking: false },
|
|
18
|
+
'1.1.0': { compatible: ['1.0.0', '1.1.0', '1.2.0'], breaking: false },
|
|
19
|
+
'1.2.0': { compatible: ['1.0.0', '1.1.0', '1.2.0'], breaking: false },
|
|
20
|
+
'2.0.0': { compatible: ['2.0.0'], breaking: true, migration: 'required' }
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
class VersionManager {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.versionFileName = 'version.json';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Gets the path to version.json in a project
|
|
30
|
+
*
|
|
31
|
+
* @param {string} projectPath - Absolute path to project root
|
|
32
|
+
* @returns {string} - Absolute path to version.json
|
|
33
|
+
*/
|
|
34
|
+
getVersionFilePath(projectPath) {
|
|
35
|
+
return path.join(projectPath, '.kiro', this.versionFileName);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reads version information from project
|
|
40
|
+
*
|
|
41
|
+
* @param {string} projectPath - Absolute path to project root
|
|
42
|
+
* @returns {Promise<VersionInfo|null>} - Version info or null if not found
|
|
43
|
+
*/
|
|
44
|
+
async readVersion(projectPath) {
|
|
45
|
+
const versionPath = this.getVersionFilePath(projectPath);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const exists = await pathExists(versionPath);
|
|
49
|
+
if (!exists) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const versionInfo = await readJSON(versionPath);
|
|
54
|
+
|
|
55
|
+
// Validate structure
|
|
56
|
+
if (!this.isValidVersionInfo(versionInfo)) {
|
|
57
|
+
throw new Error('Invalid version.json structure');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return versionInfo;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error(`Failed to read version file: ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Writes version information to project
|
|
68
|
+
*
|
|
69
|
+
* @param {string} projectPath - Absolute path to project root
|
|
70
|
+
* @param {VersionInfo} versionInfo - Version information to write
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
async writeVersion(projectPath, versionInfo) {
|
|
74
|
+
const versionPath = this.getVersionFilePath(projectPath);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
// Validate structure before writing
|
|
78
|
+
if (!this.isValidVersionInfo(versionInfo)) {
|
|
79
|
+
throw new Error('Invalid version info structure');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await writeJSON(versionPath, versionInfo, { spaces: 2 });
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw new Error(`Failed to write version file: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates initial version info for a new project
|
|
90
|
+
*
|
|
91
|
+
* @param {string} kseVersion - Current kse version
|
|
92
|
+
* @param {string} templateVersion - Template version (default: same as kse)
|
|
93
|
+
* @returns {VersionInfo}
|
|
94
|
+
*/
|
|
95
|
+
createVersionInfo(kseVersion, templateVersion = null) {
|
|
96
|
+
const now = new Date().toISOString();
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
'kse-version': kseVersion,
|
|
100
|
+
'template-version': templateVersion || kseVersion,
|
|
101
|
+
'created': now,
|
|
102
|
+
'last-upgraded': now,
|
|
103
|
+
'upgrade-history': []
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Validates version info structure
|
|
109
|
+
*
|
|
110
|
+
* @param {Object} versionInfo - Version info to validate
|
|
111
|
+
* @returns {boolean}
|
|
112
|
+
*/
|
|
113
|
+
isValidVersionInfo(versionInfo) {
|
|
114
|
+
if (!versionInfo || typeof versionInfo !== 'object') {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const requiredFields = [
|
|
119
|
+
'kse-version',
|
|
120
|
+
'template-version',
|
|
121
|
+
'created',
|
|
122
|
+
'last-upgraded',
|
|
123
|
+
'upgrade-history'
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
for (const field of requiredFields) {
|
|
127
|
+
if (!(field in versionInfo)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Validate upgrade-history is an array
|
|
133
|
+
if (!Array.isArray(versionInfo['upgrade-history'])) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Checks if upgrade is needed
|
|
142
|
+
*
|
|
143
|
+
* @param {string} projectVersion - Current project version
|
|
144
|
+
* @param {string} kseVersion - Installed kse version
|
|
145
|
+
* @returns {boolean}
|
|
146
|
+
*/
|
|
147
|
+
needsUpgrade(projectVersion, kseVersion) {
|
|
148
|
+
if (!projectVersion || !kseVersion) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Use semver for comparison
|
|
154
|
+
return semver.lt(projectVersion, kseVersion);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
// If semver comparison fails, do string comparison
|
|
157
|
+
return projectVersion !== kseVersion;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Checks compatibility between versions
|
|
163
|
+
*
|
|
164
|
+
* @param {string} fromVersion - Source version
|
|
165
|
+
* @param {string} toVersion - Target version
|
|
166
|
+
* @returns {CompatibilityResult}
|
|
167
|
+
*/
|
|
168
|
+
checkCompatibility(fromVersion, toVersion) {
|
|
169
|
+
// If versions are the same, always compatible
|
|
170
|
+
if (fromVersion === toVersion) {
|
|
171
|
+
return {
|
|
172
|
+
compatible: true,
|
|
173
|
+
breaking: false,
|
|
174
|
+
migration: 'none'
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check compatibility matrix first
|
|
179
|
+
const fromInfo = COMPATIBILITY_MATRIX[fromVersion];
|
|
180
|
+
|
|
181
|
+
if (fromInfo) {
|
|
182
|
+
const isCompatible = fromInfo.compatible.includes(toVersion);
|
|
183
|
+
return {
|
|
184
|
+
compatible: isCompatible,
|
|
185
|
+
breaking: !isCompatible || fromInfo.breaking,
|
|
186
|
+
migration: !isCompatible ? 'required' : 'none'
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Fallback: semver-based compatibility for versions not in matrix
|
|
191
|
+
try {
|
|
192
|
+
const fromMajor = semver.major(fromVersion);
|
|
193
|
+
const toMajor = semver.major(toVersion);
|
|
194
|
+
|
|
195
|
+
if (fromMajor === toMajor) {
|
|
196
|
+
// Same major version — compatible, non-breaking
|
|
197
|
+
return {
|
|
198
|
+
compatible: true,
|
|
199
|
+
breaking: false,
|
|
200
|
+
migration: 'none'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Different major version — breaking change
|
|
205
|
+
return {
|
|
206
|
+
compatible: false,
|
|
207
|
+
breaking: true,
|
|
208
|
+
migration: 'required'
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
// Invalid semver — assume incompatible
|
|
212
|
+
return {
|
|
213
|
+
compatible: false,
|
|
214
|
+
breaking: true,
|
|
215
|
+
migration: 'unknown',
|
|
216
|
+
message: `Unknown source version: ${fromVersion}`
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Calculates upgrade path for version gap
|
|
223
|
+
* Returns array of intermediate versions to upgrade through
|
|
224
|
+
*
|
|
225
|
+
* @param {string} fromVersion - Current version
|
|
226
|
+
* @param {string} toVersion - Target version
|
|
227
|
+
* @returns {string[]} - Array of versions in upgrade order (including from and to)
|
|
228
|
+
*/
|
|
229
|
+
calculateUpgradePath(fromVersion, toVersion) {
|
|
230
|
+
// If same version, no upgrade needed
|
|
231
|
+
if (fromVersion === toVersion) {
|
|
232
|
+
return [fromVersion];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Get all versions from compatibility matrix
|
|
236
|
+
const allVersions = Object.keys(COMPATIBILITY_MATRIX).sort((a, b) => {
|
|
237
|
+
try {
|
|
238
|
+
return semver.compare(a, b);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return a.localeCompare(b);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Find indices
|
|
245
|
+
const fromIndex = allVersions.indexOf(fromVersion);
|
|
246
|
+
const toIndex = allVersions.indexOf(toVersion);
|
|
247
|
+
|
|
248
|
+
// If both versions are in the matrix, use the matrix path
|
|
249
|
+
if (fromIndex !== -1 && toIndex !== -1) {
|
|
250
|
+
if (fromIndex > toIndex) {
|
|
251
|
+
throw new Error('Cannot downgrade versions');
|
|
252
|
+
}
|
|
253
|
+
return allVersions.slice(fromIndex, toIndex + 1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Fallback: semver-based direct upgrade for versions not in matrix
|
|
257
|
+
try {
|
|
258
|
+
const from = semver.valid(fromVersion);
|
|
259
|
+
const to = semver.valid(toVersion);
|
|
260
|
+
|
|
261
|
+
if (!from) {
|
|
262
|
+
throw new Error(`Unknown source version: ${fromVersion}`);
|
|
263
|
+
}
|
|
264
|
+
if (!to) {
|
|
265
|
+
throw new Error(`Unknown target version: ${toVersion}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (semver.gt(fromVersion, toVersion)) {
|
|
269
|
+
throw new Error('Cannot downgrade versions');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Direct upgrade path
|
|
273
|
+
return [fromVersion, toVersion];
|
|
274
|
+
} catch (error) {
|
|
275
|
+
// Re-throw our own errors
|
|
276
|
+
if (error.message.includes('Unknown') || error.message.includes('downgrade')) {
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
throw new Error(`Unknown source version: ${fromVersion}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Adds an upgrade entry to version history
|
|
285
|
+
*
|
|
286
|
+
* @param {VersionInfo} versionInfo - Current version info
|
|
287
|
+
* @param {string} fromVersion - Version upgraded from
|
|
288
|
+
* @param {string} toVersion - Version upgraded to
|
|
289
|
+
* @param {boolean} success - Whether upgrade succeeded
|
|
290
|
+
* @param {string} error - Error message if failed
|
|
291
|
+
* @returns {VersionInfo} - Updated version info
|
|
292
|
+
*/
|
|
293
|
+
addUpgradeHistory(versionInfo, fromVersion, toVersion, success, error = null) {
|
|
294
|
+
const entry = {
|
|
295
|
+
from: fromVersion,
|
|
296
|
+
to: toVersion,
|
|
297
|
+
date: new Date().toISOString(),
|
|
298
|
+
success
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
if (error) {
|
|
302
|
+
entry.error = error;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
versionInfo['upgrade-history'].push(entry);
|
|
306
|
+
|
|
307
|
+
// Update version and last-upgraded if successful
|
|
308
|
+
if (success) {
|
|
309
|
+
versionInfo['kse-version'] = toVersion;
|
|
310
|
+
versionInfo['template-version'] = toVersion;
|
|
311
|
+
versionInfo['last-upgraded'] = entry.date;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return versionInfo;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Gets the compatibility matrix
|
|
319
|
+
*
|
|
320
|
+
* @returns {Object} - Compatibility matrix
|
|
321
|
+
*/
|
|
322
|
+
getCompatibilityMatrix() {
|
|
323
|
+
return { ...COMPATIBILITY_MATRIX };
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
module.exports = VersionManager;
|