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,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages mandatory backup creation and validation for adoption process.
|
|
5
|
+
* Ensures all modifications are preceded by verified backups.
|
|
6
|
+
*
|
|
7
|
+
* Core Responsibilities:
|
|
8
|
+
* - Create selective backups of files to be modified
|
|
9
|
+
* - Validate backup integrity (file count, size, content)
|
|
10
|
+
* - Provide backup metadata for rollback
|
|
11
|
+
* - Abort operations if backup fails
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fs = require('fs-extra');
|
|
16
|
+
const crypto = require('crypto');
|
|
17
|
+
const SelectiveBackup = require('../backup/selective-backup');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Backup Manager for mandatory backup operations
|
|
21
|
+
*/
|
|
22
|
+
class BackupManager {
|
|
23
|
+
constructor(dependencies = {}) {
|
|
24
|
+
// Support dependency injection for testing
|
|
25
|
+
this.selectiveBackup = dependencies.selectiveBackup || new SelectiveBackup();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates mandatory backup before modifications
|
|
30
|
+
*
|
|
31
|
+
* This method MUST be called before any file modifications during adoption.
|
|
32
|
+
* If backup creation or validation fails, the adoption process MUST be aborted.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} projectPath - Absolute path to project root
|
|
35
|
+
* @param {string[]} filesToModify - Relative paths of files to backup (from .kiro/)
|
|
36
|
+
* @param {Object} options - Backup options
|
|
37
|
+
* @param {string} options.type - Backup type (default: 'adopt-smart')
|
|
38
|
+
* @param {boolean} options.validateContent - Validate file content hashes (default: true)
|
|
39
|
+
* @returns {Promise<BackupResult>}
|
|
40
|
+
* @throws {Error} If backup creation or validation fails
|
|
41
|
+
*/
|
|
42
|
+
async createMandatoryBackup(projectPath, filesToModify, options = {}) {
|
|
43
|
+
const {
|
|
44
|
+
type = 'adopt-smart',
|
|
45
|
+
validateContent = true
|
|
46
|
+
} = options;
|
|
47
|
+
|
|
48
|
+
// Validate inputs
|
|
49
|
+
if (!projectPath) {
|
|
50
|
+
throw new Error('Project path is required');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!Array.isArray(filesToModify)) {
|
|
54
|
+
throw new Error('filesToModify must be an array');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// If no files to modify, return null (no backup needed)
|
|
58
|
+
if (filesToModify.length === 0) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Create selective backup using existing system
|
|
64
|
+
const backup = await this.selectiveBackup.createSelectiveBackup(
|
|
65
|
+
projectPath,
|
|
66
|
+
filesToModify,
|
|
67
|
+
{ type }
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Ensure backup has required properties
|
|
71
|
+
if (!backup || !backup.id) {
|
|
72
|
+
throw new Error('Backup creation returned invalid result');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Transform to standardized BackupResult format
|
|
76
|
+
const backupResult = {
|
|
77
|
+
id: backup.id,
|
|
78
|
+
location: backup.path || backup.backupPath,
|
|
79
|
+
filesCount: backup.fileCount || (backup.files ? backup.files.length : 0),
|
|
80
|
+
totalSize: backup.totalSize || 0,
|
|
81
|
+
timestamp: backup.created ? new Date(backup.created) : new Date(),
|
|
82
|
+
type: backup.type || type,
|
|
83
|
+
files: backup.files || []
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Validate backup integrity
|
|
87
|
+
const validation = await this.validateBackup(backupResult, {
|
|
88
|
+
validateContent,
|
|
89
|
+
originalPath: projectPath
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!validation.success) {
|
|
93
|
+
throw new Error(`Backup validation failed: ${validation.error}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Add validation info to result
|
|
97
|
+
backupResult.validated = true;
|
|
98
|
+
backupResult.validationDetails = {
|
|
99
|
+
filesVerified: validation.filesVerified,
|
|
100
|
+
contentVerified: validation.contentVerified,
|
|
101
|
+
timestamp: new Date()
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return backupResult;
|
|
105
|
+
|
|
106
|
+
} catch (error) {
|
|
107
|
+
// Wrap error with context
|
|
108
|
+
throw new Error(`Failed to create mandatory backup: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Validates backup integrity
|
|
114
|
+
*
|
|
115
|
+
* Performs comprehensive validation of backup to ensure it can be used for rollback:
|
|
116
|
+
* 1. Backup directory exists
|
|
117
|
+
* 2. File count matches expected
|
|
118
|
+
* 3. All files exist in backup
|
|
119
|
+
* 4. File sizes match (optional)
|
|
120
|
+
* 5. Content hashes match (optional)
|
|
121
|
+
*
|
|
122
|
+
* @param {BackupResult} backup - Backup result to validate
|
|
123
|
+
* @param {Object} options - Validation options
|
|
124
|
+
* @param {boolean} options.validateContent - Validate file content hashes (default: false)
|
|
125
|
+
* @param {string} options.originalPath - Original project path for content validation
|
|
126
|
+
* @returns {Promise<ValidationResult>}
|
|
127
|
+
*/
|
|
128
|
+
async validateBackup(backup, options = {}) {
|
|
129
|
+
const {
|
|
130
|
+
validateContent = false,
|
|
131
|
+
originalPath = null
|
|
132
|
+
} = options;
|
|
133
|
+
|
|
134
|
+
// Handle null backup (no backup needed)
|
|
135
|
+
if (!backup) {
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
filesVerified: 0,
|
|
139
|
+
contentVerified: false,
|
|
140
|
+
message: 'No backup to validate'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
// Validation 1: Backup has required properties
|
|
146
|
+
if (!backup.location) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: 'Backup location not specified',
|
|
150
|
+
filesVerified: 0,
|
|
151
|
+
contentVerified: false
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Validation 2: Backup directory exists
|
|
156
|
+
const exists = await fs.pathExists(backup.location);
|
|
157
|
+
if (!exists) {
|
|
158
|
+
return {
|
|
159
|
+
success: false,
|
|
160
|
+
error: 'Backup directory not found',
|
|
161
|
+
filesVerified: 0,
|
|
162
|
+
contentVerified: false
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Validation 3: Files subdirectory exists
|
|
167
|
+
const filesDir = path.join(backup.location, 'files');
|
|
168
|
+
const filesDirExists = await fs.pathExists(filesDir);
|
|
169
|
+
if (!filesDirExists) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: 'Backup files directory not found',
|
|
173
|
+
filesVerified: 0,
|
|
174
|
+
contentVerified: false
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Validation 4: Verify file count
|
|
179
|
+
const expectedCount = backup.filesCount || 0;
|
|
180
|
+
const actualFiles = backup.files || [];
|
|
181
|
+
|
|
182
|
+
if (actualFiles.length !== expectedCount) {
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
error: `File count mismatch: expected ${expectedCount}, found ${actualFiles.length}`,
|
|
186
|
+
filesVerified: 0,
|
|
187
|
+
contentVerified: false
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Validation 5: Verify each file exists in backup
|
|
192
|
+
let filesVerified = 0;
|
|
193
|
+
for (const filePath of actualFiles) {
|
|
194
|
+
const backupFilePath = path.join(filesDir, filePath);
|
|
195
|
+
const fileExists = await fs.pathExists(backupFilePath);
|
|
196
|
+
|
|
197
|
+
if (!fileExists) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: `File missing from backup: ${filePath}`,
|
|
201
|
+
filesVerified,
|
|
202
|
+
contentVerified: false
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
filesVerified++;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Validation 6: Optional content validation
|
|
210
|
+
let contentVerified = false;
|
|
211
|
+
if (validateContent && originalPath) {
|
|
212
|
+
const contentValidation = await this._validateContent(
|
|
213
|
+
originalPath,
|
|
214
|
+
backup.location,
|
|
215
|
+
actualFiles
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
if (!contentValidation.success) {
|
|
219
|
+
return {
|
|
220
|
+
success: false,
|
|
221
|
+
error: contentValidation.error,
|
|
222
|
+
filesVerified,
|
|
223
|
+
contentVerified: false
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
contentVerified = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// All validations passed
|
|
231
|
+
return {
|
|
232
|
+
success: true,
|
|
233
|
+
filesVerified,
|
|
234
|
+
contentVerified,
|
|
235
|
+
message: `Backup validated: ${filesVerified} files verified`
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
} catch (error) {
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
error: `Validation error: ${error.message}`,
|
|
242
|
+
filesVerified: 0,
|
|
243
|
+
contentVerified: false
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Validates backup content matches original files
|
|
250
|
+
*
|
|
251
|
+
* @param {string} originalPath - Original project path
|
|
252
|
+
* @param {string} backupPath - Backup directory path
|
|
253
|
+
* @param {string[]} files - Files to validate
|
|
254
|
+
* @returns {Promise<ContentValidationResult>}
|
|
255
|
+
* @private
|
|
256
|
+
*/
|
|
257
|
+
async _validateContent(originalPath, backupPath, files) {
|
|
258
|
+
try {
|
|
259
|
+
const filesDir = path.join(backupPath, 'files');
|
|
260
|
+
|
|
261
|
+
for (const filePath of files) {
|
|
262
|
+
const originalFilePath = path.join(originalPath, '.kiro', filePath);
|
|
263
|
+
const backupFilePath = path.join(filesDir, filePath);
|
|
264
|
+
|
|
265
|
+
// Check if original file still exists
|
|
266
|
+
const originalExists = await fs.pathExists(originalFilePath);
|
|
267
|
+
if (!originalExists) {
|
|
268
|
+
// Original file may have been deleted, skip validation
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Compare file sizes
|
|
273
|
+
const originalStats = await fs.stat(originalFilePath);
|
|
274
|
+
const backupStats = await fs.stat(backupFilePath);
|
|
275
|
+
|
|
276
|
+
if (originalStats.size !== backupStats.size) {
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
error: `File size mismatch for ${filePath}: original ${originalStats.size}, backup ${backupStats.size}`
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Compare content hashes for critical files
|
|
284
|
+
if (this._isCriticalFile(filePath)) {
|
|
285
|
+
const originalHash = await this._calculateFileHash(originalFilePath);
|
|
286
|
+
const backupHash = await this._calculateFileHash(backupFilePath);
|
|
287
|
+
|
|
288
|
+
if (originalHash !== backupHash) {
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
error: `Content hash mismatch for ${filePath}`
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return { success: true };
|
|
298
|
+
|
|
299
|
+
} catch (error) {
|
|
300
|
+
return {
|
|
301
|
+
success: false,
|
|
302
|
+
error: `Content validation error: ${error.message}`
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Determines if a file is critical and requires hash validation
|
|
309
|
+
*
|
|
310
|
+
* @param {string} filePath - File path
|
|
311
|
+
* @returns {boolean}
|
|
312
|
+
* @private
|
|
313
|
+
*/
|
|
314
|
+
_isCriticalFile(filePath) {
|
|
315
|
+
const criticalPatterns = [
|
|
316
|
+
'steering/CORE_PRINCIPLES.md',
|
|
317
|
+
'steering/ENVIRONMENT.md',
|
|
318
|
+
'version.json',
|
|
319
|
+
'adoption-config.json'
|
|
320
|
+
];
|
|
321
|
+
|
|
322
|
+
return criticalPatterns.some(pattern => filePath.includes(pattern));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Calculates SHA-256 hash of a file
|
|
327
|
+
*
|
|
328
|
+
* @param {string} filePath - File path
|
|
329
|
+
* @returns {Promise<string>} - Hex hash string
|
|
330
|
+
* @private
|
|
331
|
+
*/
|
|
332
|
+
async _calculateFileHash(filePath) {
|
|
333
|
+
return new Promise((resolve, reject) => {
|
|
334
|
+
const hash = crypto.createHash('sha256');
|
|
335
|
+
const stream = fs.createReadStream(filePath);
|
|
336
|
+
|
|
337
|
+
stream.on('data', data => hash.update(data));
|
|
338
|
+
stream.on('end', () => resolve(hash.digest('hex')));
|
|
339
|
+
stream.on('error', reject);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Gets backup information
|
|
345
|
+
*
|
|
346
|
+
* @param {string} projectPath - Project path
|
|
347
|
+
* @param {string} backupId - Backup ID
|
|
348
|
+
* @returns {Promise<BackupInfo>}
|
|
349
|
+
*/
|
|
350
|
+
async getBackupInfo(projectPath, backupId) {
|
|
351
|
+
const backupPath = path.join(projectPath, '.kiro', 'backups', backupId);
|
|
352
|
+
|
|
353
|
+
// Check if backup exists
|
|
354
|
+
const exists = await fs.pathExists(backupPath);
|
|
355
|
+
if (!exists) {
|
|
356
|
+
throw new Error(`Backup not found: ${backupId}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Read metadata
|
|
360
|
+
const metadataPath = path.join(backupPath, 'metadata.json');
|
|
361
|
+
const metadataExists = await fs.pathExists(metadataPath);
|
|
362
|
+
|
|
363
|
+
if (!metadataExists) {
|
|
364
|
+
throw new Error(`Backup metadata not found: ${backupId}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const metadata = await fs.readJson(metadataPath);
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
id: metadata.id || backupId,
|
|
371
|
+
type: metadata.type,
|
|
372
|
+
created: metadata.created,
|
|
373
|
+
filesCount: metadata.fileCount || 0,
|
|
374
|
+
totalSize: metadata.totalSize || 0,
|
|
375
|
+
files: metadata.files || [],
|
|
376
|
+
location: backupPath
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @typedef {Object} BackupResult
|
|
383
|
+
* @property {string} id - Unique backup identifier
|
|
384
|
+
* @property {string} location - Absolute path to backup directory
|
|
385
|
+
* @property {number} filesCount - Number of files backed up
|
|
386
|
+
* @property {number} totalSize - Total size of backed up files in bytes
|
|
387
|
+
* @property {Date} timestamp - Backup creation timestamp
|
|
388
|
+
* @property {string} type - Backup type (e.g., 'adopt-smart')
|
|
389
|
+
* @property {string[]} files - List of backed up file paths
|
|
390
|
+
* @property {boolean} validated - Whether backup has been validated
|
|
391
|
+
* @property {Object} validationDetails - Validation details
|
|
392
|
+
*/
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* @typedef {Object} ValidationResult
|
|
396
|
+
* @property {boolean} success - Whether validation succeeded
|
|
397
|
+
* @property {number} filesVerified - Number of files verified
|
|
398
|
+
* @property {boolean} contentVerified - Whether content was verified
|
|
399
|
+
* @property {string} [error] - Error message if validation failed
|
|
400
|
+
* @property {string} [message] - Success message if validation passed
|
|
401
|
+
*/
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @typedef {Object} ContentValidationResult
|
|
405
|
+
* @property {boolean} success - Whether content validation succeeded
|
|
406
|
+
* @property {string} [error] - Error message if validation failed
|
|
407
|
+
*/
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* @typedef {Object} BackupInfo
|
|
411
|
+
* @property {string} id - Backup identifier
|
|
412
|
+
* @property {string} type - Backup type
|
|
413
|
+
* @property {string} created - Creation timestamp (ISO string)
|
|
414
|
+
* @property {number} filesCount - Number of files
|
|
415
|
+
* @property {number} totalSize - Total size in bytes
|
|
416
|
+
* @property {string[]} files - List of file paths
|
|
417
|
+
* @property {string} location - Backup directory path
|
|
418
|
+
*/
|
|
419
|
+
|
|
420
|
+
module.exports = BackupManager;
|