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,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitignoreBackup - Creates backups before modifying .gitignore
|
|
3
|
+
*
|
|
4
|
+
* Provides backup creation, restoration, and management functionality
|
|
5
|
+
* with automatic cleanup of old backups.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const crypto = require('crypto');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} BackupInfo
|
|
14
|
+
* @property {string} id - Backup ID (e.g., 'gitignore-2026-01-30-143022')
|
|
15
|
+
* @property {string} created - ISO timestamp
|
|
16
|
+
* @property {string} path - Backup file path
|
|
17
|
+
* @property {number} size - File size in bytes
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} RestoreResult
|
|
22
|
+
* @property {boolean} success - Restoration succeeded
|
|
23
|
+
* @property {string} message - Result message
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
class GitignoreBackup {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.MAX_BACKUPS = 10;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates backup of .gitignore
|
|
33
|
+
*
|
|
34
|
+
* @param {string} projectPath - Project root path
|
|
35
|
+
* @returns {Promise<BackupInfo>}
|
|
36
|
+
*/
|
|
37
|
+
async createBackup(projectPath) {
|
|
38
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
39
|
+
|
|
40
|
+
// Check if .gitignore exists
|
|
41
|
+
if (!await fs.pathExists(gitignorePath)) {
|
|
42
|
+
throw new Error('.gitignore file does not exist');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Read .gitignore content
|
|
46
|
+
const content = await fs.readFile(gitignorePath, 'utf8');
|
|
47
|
+
const stats = await fs.stat(gitignorePath);
|
|
48
|
+
|
|
49
|
+
// Generate backup ID with timestamp
|
|
50
|
+
const timestamp = this.generateTimestamp();
|
|
51
|
+
const backupId = `gitignore-${timestamp}`;
|
|
52
|
+
|
|
53
|
+
// Create backup directory
|
|
54
|
+
const backupDir = path.join(projectPath, '.kiro', 'backups');
|
|
55
|
+
await fs.ensureDir(backupDir);
|
|
56
|
+
|
|
57
|
+
// Write backup file
|
|
58
|
+
const backupPath = path.join(backupDir, backupId);
|
|
59
|
+
await fs.writeFile(backupPath, content, 'utf8');
|
|
60
|
+
|
|
61
|
+
// Create metadata
|
|
62
|
+
const checksum = this.calculateChecksum(content);
|
|
63
|
+
const metadata = {
|
|
64
|
+
id: backupId,
|
|
65
|
+
created: new Date().toISOString(),
|
|
66
|
+
originalPath: '.gitignore',
|
|
67
|
+
size: stats.size,
|
|
68
|
+
checksum
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const metaPath = path.join(backupDir, `${backupId}.meta.json`);
|
|
72
|
+
await fs.writeFile(metaPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
73
|
+
|
|
74
|
+
// Cleanup old backups
|
|
75
|
+
await this.cleanupOldBackups(projectPath);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
id: backupId,
|
|
79
|
+
created: metadata.created,
|
|
80
|
+
path: backupPath,
|
|
81
|
+
size: stats.size
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Restores .gitignore from backup
|
|
87
|
+
*
|
|
88
|
+
* @param {string} projectPath - Project root path
|
|
89
|
+
* @param {string} backupId - Backup ID
|
|
90
|
+
* @returns {Promise<RestoreResult>}
|
|
91
|
+
*/
|
|
92
|
+
async restore(projectPath, backupId) {
|
|
93
|
+
const backupDir = path.join(projectPath, '.kiro', 'backups');
|
|
94
|
+
const backupPath = path.join(backupDir, backupId);
|
|
95
|
+
const metaPath = path.join(backupDir, `${backupId}.meta.json`);
|
|
96
|
+
|
|
97
|
+
// Check if backup exists
|
|
98
|
+
if (!await fs.pathExists(backupPath)) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
message: `Backup not found: ${backupId}`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Read backup content
|
|
106
|
+
const content = await fs.readFile(backupPath, 'utf8');
|
|
107
|
+
|
|
108
|
+
// Verify checksum if metadata exists
|
|
109
|
+
if (await fs.pathExists(metaPath)) {
|
|
110
|
+
const metadata = await fs.readJson(metaPath);
|
|
111
|
+
const checksum = this.calculateChecksum(content);
|
|
112
|
+
|
|
113
|
+
if (checksum !== metadata.checksum) {
|
|
114
|
+
return {
|
|
115
|
+
success: false,
|
|
116
|
+
message: 'Backup file is corrupted (checksum mismatch)'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Restore to original location
|
|
122
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
123
|
+
await fs.writeFile(gitignorePath, content, 'utf8');
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
message: `Successfully restored .gitignore from backup: ${backupId}`
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Lists available .gitignore backups
|
|
133
|
+
*
|
|
134
|
+
* @param {string} projectPath - Project root path
|
|
135
|
+
* @returns {Promise<BackupInfo[]>}
|
|
136
|
+
*/
|
|
137
|
+
async listBackups(projectPath) {
|
|
138
|
+
const backupDir = path.join(projectPath, '.kiro', 'backups');
|
|
139
|
+
|
|
140
|
+
if (!await fs.pathExists(backupDir)) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const files = await fs.readdir(backupDir);
|
|
145
|
+
const backups = [];
|
|
146
|
+
|
|
147
|
+
for (const file of files) {
|
|
148
|
+
if (file.startsWith('gitignore-') && !file.endsWith('.meta.json')) {
|
|
149
|
+
const backupPath = path.join(backupDir, file);
|
|
150
|
+
const metaPath = path.join(backupDir, `${file}.meta.json`);
|
|
151
|
+
|
|
152
|
+
let metadata = null;
|
|
153
|
+
if (await fs.pathExists(metaPath)) {
|
|
154
|
+
metadata = await fs.readJson(metaPath);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const stats = await fs.stat(backupPath);
|
|
158
|
+
|
|
159
|
+
backups.push({
|
|
160
|
+
id: file,
|
|
161
|
+
created: metadata ? metadata.created : stats.mtime.toISOString(),
|
|
162
|
+
path: backupPath,
|
|
163
|
+
size: stats.size
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Sort by creation time (newest first)
|
|
169
|
+
backups.sort((a, b) => new Date(b.created) - new Date(a.created));
|
|
170
|
+
|
|
171
|
+
return backups;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Cleans up old backups (keep last 10)
|
|
176
|
+
*
|
|
177
|
+
* @param {string} projectPath - Project root path
|
|
178
|
+
* @returns {Promise<void>}
|
|
179
|
+
*/
|
|
180
|
+
async cleanupOldBackups(projectPath) {
|
|
181
|
+
const backups = await this.listBackups(projectPath);
|
|
182
|
+
|
|
183
|
+
if (backups.length <= this.MAX_BACKUPS) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Remove oldest backups
|
|
188
|
+
const toRemove = backups.slice(this.MAX_BACKUPS);
|
|
189
|
+
|
|
190
|
+
for (const backup of toRemove) {
|
|
191
|
+
await fs.remove(backup.path);
|
|
192
|
+
|
|
193
|
+
// Remove metadata if exists
|
|
194
|
+
const metaPath = `${backup.path}.meta.json`;
|
|
195
|
+
if (await fs.pathExists(metaPath)) {
|
|
196
|
+
await fs.remove(metaPath);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Generates timestamp for backup ID
|
|
203
|
+
*
|
|
204
|
+
* @returns {string} - Timestamp in format YYYY-MM-DD-HHMMSS
|
|
205
|
+
*/
|
|
206
|
+
generateTimestamp() {
|
|
207
|
+
const now = new Date();
|
|
208
|
+
const year = now.getFullYear();
|
|
209
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
210
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
211
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
212
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
213
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
214
|
+
|
|
215
|
+
return `${year}-${month}-${day}-${hours}${minutes}${seconds}`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Calculates SHA-256 checksum of content
|
|
220
|
+
*
|
|
221
|
+
* @param {string} content - Content to hash
|
|
222
|
+
* @returns {string} - Hex checksum
|
|
223
|
+
*/
|
|
224
|
+
calculateChecksum(content) {
|
|
225
|
+
return crypto.createHash('sha256').update(content, 'utf8').digest('hex');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
module.exports = GitignoreBackup;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitignoreDetector - Analyzes .gitignore status
|
|
3
|
+
*
|
|
4
|
+
* Detects .gitignore file existence, parses content, identifies old patterns,
|
|
5
|
+
* and determines the appropriate fix strategy.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} GitignoreRule
|
|
13
|
+
* @property {string} pattern - Rule pattern (e.g., '.kiro/backups/')
|
|
14
|
+
* @property {string} type - 'exclusion' | 'negation' | 'comment'
|
|
15
|
+
* @property {number} line - Line number in file
|
|
16
|
+
* @property {boolean} isKiroRelated - Rule relates to .kiro/
|
|
17
|
+
* @property {boolean} isManaged - Rule is in kse-managed section
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} GitignoreStatus
|
|
22
|
+
* @property {boolean} exists - .gitignore file exists
|
|
23
|
+
* @property {string} status - 'missing' | 'old-pattern' | 'incomplete' | 'compliant'
|
|
24
|
+
* @property {string} strategy - 'add' | 'update' | 'skip'
|
|
25
|
+
* @property {string[]} oldPatterns - Old patterns found
|
|
26
|
+
* @property {string[]} missingRules - Missing layered rules
|
|
27
|
+
* @property {string} content - Current .gitignore content
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
class GitignoreDetector {
|
|
31
|
+
constructor() {
|
|
32
|
+
// Old patterns that indicate blanket exclusion
|
|
33
|
+
this.OLD_PATTERNS = [
|
|
34
|
+
/^\.kiro\/?\s*$/, // .kiro/ or .kiro
|
|
35
|
+
/^\.kiro\/\*\s*$/, // .kiro/*
|
|
36
|
+
/^\.kiro\/\*\*\s*$/ // .kiro/**
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
// Required layered rules (key patterns to check)
|
|
40
|
+
this.REQUIRED_RULES = [
|
|
41
|
+
'.kiro/steering/CURRENT_CONTEXT.md',
|
|
42
|
+
'.kiro/contexts/.active',
|
|
43
|
+
'.kiro/environments.json',
|
|
44
|
+
'.kiro/backups/',
|
|
45
|
+
'.kiro/logs/',
|
|
46
|
+
'.kiro/reports/'
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Analyzes .gitignore status
|
|
52
|
+
*
|
|
53
|
+
* @param {string} projectPath - Project root path
|
|
54
|
+
* @returns {Promise<GitignoreStatus>}
|
|
55
|
+
*/
|
|
56
|
+
async analyzeGitignore(projectPath) {
|
|
57
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
58
|
+
|
|
59
|
+
// Check if .gitignore exists
|
|
60
|
+
const fileExists = await this.exists(projectPath);
|
|
61
|
+
|
|
62
|
+
if (!fileExists) {
|
|
63
|
+
return {
|
|
64
|
+
exists: false,
|
|
65
|
+
status: 'missing',
|
|
66
|
+
strategy: 'add',
|
|
67
|
+
oldPatterns: [],
|
|
68
|
+
missingRules: [...this.REQUIRED_RULES],
|
|
69
|
+
content: ''
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Read and parse .gitignore
|
|
74
|
+
const content = await fs.readFile(gitignorePath, 'utf8');
|
|
75
|
+
const rules = this.parseGitignore(content);
|
|
76
|
+
|
|
77
|
+
// Check for old patterns
|
|
78
|
+
const oldPatterns = this.findOldPatterns(rules);
|
|
79
|
+
const hasOld = oldPatterns.length > 0;
|
|
80
|
+
|
|
81
|
+
// Check for layered strategy
|
|
82
|
+
const missingRules = this.findMissingRules(rules);
|
|
83
|
+
const hasLayered = missingRules.length === 0;
|
|
84
|
+
|
|
85
|
+
// Determine status and strategy
|
|
86
|
+
let status, strategy;
|
|
87
|
+
|
|
88
|
+
if (hasOld) {
|
|
89
|
+
status = 'old-pattern';
|
|
90
|
+
strategy = 'update';
|
|
91
|
+
} else if (!hasLayered) {
|
|
92
|
+
status = 'incomplete';
|
|
93
|
+
strategy = 'update';
|
|
94
|
+
} else {
|
|
95
|
+
status = 'compliant';
|
|
96
|
+
strategy = 'skip';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
exists: true,
|
|
101
|
+
status,
|
|
102
|
+
strategy,
|
|
103
|
+
oldPatterns,
|
|
104
|
+
missingRules,
|
|
105
|
+
content
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Checks if .gitignore exists
|
|
111
|
+
*
|
|
112
|
+
* @param {string} projectPath - Project root path
|
|
113
|
+
* @returns {Promise<boolean>}
|
|
114
|
+
*/
|
|
115
|
+
async exists(projectPath) {
|
|
116
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
117
|
+
return await fs.pathExists(gitignorePath);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parses .gitignore content into rules
|
|
122
|
+
*
|
|
123
|
+
* @param {string} content - .gitignore file content
|
|
124
|
+
* @returns {GitignoreRule[]}
|
|
125
|
+
*/
|
|
126
|
+
parseGitignore(content) {
|
|
127
|
+
const lines = content.split(/\r?\n/);
|
|
128
|
+
const rules = [];
|
|
129
|
+
let inManagedSection = false;
|
|
130
|
+
|
|
131
|
+
lines.forEach((line, index) => {
|
|
132
|
+
const trimmed = line.trim();
|
|
133
|
+
|
|
134
|
+
// Track kse-managed section
|
|
135
|
+
if (trimmed.includes('kse - DO NOT EDIT THIS SECTION')) {
|
|
136
|
+
inManagedSection = true;
|
|
137
|
+
} else if (trimmed.includes('End of kse-managed section')) {
|
|
138
|
+
inManagedSection = false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Determine rule type
|
|
142
|
+
let type = 'exclusion';
|
|
143
|
+
let pattern = trimmed;
|
|
144
|
+
|
|
145
|
+
if (trimmed.startsWith('#')) {
|
|
146
|
+
type = 'comment';
|
|
147
|
+
} else if (trimmed.startsWith('!')) {
|
|
148
|
+
type = 'negation';
|
|
149
|
+
pattern = trimmed.substring(1);
|
|
150
|
+
} else if (trimmed === '') {
|
|
151
|
+
return; // Skip blank lines
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check if .kiro-related
|
|
155
|
+
const isKiroRelated = pattern.includes('.kiro');
|
|
156
|
+
|
|
157
|
+
rules.push({
|
|
158
|
+
pattern: trimmed,
|
|
159
|
+
type,
|
|
160
|
+
line: index + 1,
|
|
161
|
+
isKiroRelated,
|
|
162
|
+
isManaged: inManagedSection
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return rules;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Finds old blanket exclusion patterns
|
|
171
|
+
*
|
|
172
|
+
* @param {GitignoreRule[]} rules - Parsed rules
|
|
173
|
+
* @returns {string[]} - Old patterns found
|
|
174
|
+
*/
|
|
175
|
+
findOldPatterns(rules) {
|
|
176
|
+
const oldPatterns = [];
|
|
177
|
+
|
|
178
|
+
for (const rule of rules) {
|
|
179
|
+
if (rule.type === 'exclusion' && rule.isKiroRelated) {
|
|
180
|
+
for (const pattern of this.OLD_PATTERNS) {
|
|
181
|
+
if (pattern.test(rule.pattern)) {
|
|
182
|
+
oldPatterns.push(rule.pattern);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return oldPatterns;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Finds missing layered rules
|
|
194
|
+
*
|
|
195
|
+
* @param {GitignoreRule[]} rules - Parsed rules
|
|
196
|
+
* @returns {string[]} - Missing rules
|
|
197
|
+
*/
|
|
198
|
+
findMissingRules(rules) {
|
|
199
|
+
const existingPatterns = rules
|
|
200
|
+
.filter(r => r.type === 'exclusion')
|
|
201
|
+
.map(r => r.pattern);
|
|
202
|
+
|
|
203
|
+
const missing = [];
|
|
204
|
+
|
|
205
|
+
for (const required of this.REQUIRED_RULES) {
|
|
206
|
+
const found = existingPatterns.some(pattern =>
|
|
207
|
+
pattern.includes(required) || required.includes(pattern)
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (!found) {
|
|
211
|
+
missing.push(required);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return missing;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Detects if .gitignore has old pattern
|
|
220
|
+
*
|
|
221
|
+
* @param {GitignoreRule[]} rules - Parsed rules
|
|
222
|
+
* @returns {boolean}
|
|
223
|
+
*/
|
|
224
|
+
hasOldPattern(rules) {
|
|
225
|
+
return this.findOldPatterns(rules).length > 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Checks if layered strategy is present
|
|
230
|
+
*
|
|
231
|
+
* @param {GitignoreRule[]} rules - Parsed rules
|
|
232
|
+
* @returns {boolean}
|
|
233
|
+
*/
|
|
234
|
+
hasLayeredStrategy(rules) {
|
|
235
|
+
return this.findMissingRules(rules).length === 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = GitignoreDetector;
|