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.
Files changed (336) hide show
  1. package/CHANGELOG.md +2513 -0
  2. package/LICENSE +21 -0
  3. package/README.md +765 -0
  4. package/README.zh.md +630 -0
  5. package/bin/kiro-spec-engine.js +796 -0
  6. package/bin/kse.js +3 -0
  7. package/bin/sce.js +3 -0
  8. package/bin/sco.js +3 -0
  9. package/docs/331-poc-adaptation-roadmap.md +156 -0
  10. package/docs/331-poc-dual-track-integration-guide.md +120 -0
  11. package/docs/331-poc-weekly-delivery-checklist.md +52 -0
  12. package/docs/OFFLINE_INSTALL.md +96 -0
  13. package/docs/README.md +279 -0
  14. package/docs/adopt-migration-guide.md +599 -0
  15. package/docs/adoption-guide.md +616 -0
  16. package/docs/agent-hooks-analysis.md +815 -0
  17. package/docs/architecture.md +733 -0
  18. package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
  19. package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
  20. package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
  21. package/docs/autonomous-control-guide.md +851 -0
  22. package/docs/command-reference.md +1368 -0
  23. package/docs/community.md +115 -0
  24. package/docs/cross-tool-guide.md +555 -0
  25. package/docs/developer-guide.md +619 -0
  26. package/docs/document-governance.md +865 -0
  27. package/docs/environment-management-guide.md +526 -0
  28. package/docs/examples/add-export-command/design.md +194 -0
  29. package/docs/examples/add-export-command/requirements.md +110 -0
  30. package/docs/examples/add-export-command/tasks.md +88 -0
  31. package/docs/examples/add-rest-api/design.md +855 -0
  32. package/docs/examples/add-rest-api/requirements.md +323 -0
  33. package/docs/examples/add-rest-api/tasks.md +355 -0
  34. package/docs/examples/add-user-dashboard/design.md +192 -0
  35. package/docs/examples/add-user-dashboard/requirements.md +143 -0
  36. package/docs/examples/add-user-dashboard/tasks.md +91 -0
  37. package/docs/faq.md +697 -0
  38. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
  39. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
  40. package/docs/images/wechat-qr.png +0 -0
  41. package/docs/integration-modes.md +529 -0
  42. package/docs/integration-philosophy.md +313 -0
  43. package/docs/knowledge-management-guide.md +263 -0
  44. package/docs/manual-workflows-guide.md +418 -0
  45. package/docs/moqui-capability-matrix.md +73 -0
  46. package/docs/moqui-template-core-library-playbook.md +109 -0
  47. package/docs/multi-agent-coordination-guide.md +553 -0
  48. package/docs/multi-repo-management-guide.md +1344 -0
  49. package/docs/quick-start-with-ai-tools.md +375 -0
  50. package/docs/quick-start.md +146 -0
  51. package/docs/release-checklist.md +121 -0
  52. package/docs/releases/README.md +13 -0
  53. package/docs/releases/v1.46.2-validation.md +45 -0
  54. package/docs/releases/v1.46.2.md +50 -0
  55. package/docs/scene-runtime-guide.md +347 -0
  56. package/docs/spec-collaboration-guide.md +369 -0
  57. package/docs/spec-locking-guide.md +225 -0
  58. package/docs/spec-numbering-guide.md +348 -0
  59. package/docs/spec-workflow.md +519 -0
  60. package/docs/steering-strategy-guide.md +196 -0
  61. package/docs/team-collaboration-guide.md +465 -0
  62. package/docs/testing-strategy.md +272 -0
  63. package/docs/tools/claude-guide.md +654 -0
  64. package/docs/tools/cursor-guide.md +706 -0
  65. package/docs/tools/generic-guide.md +446 -0
  66. package/docs/tools/kiro-guide.md +308 -0
  67. package/docs/tools/vscode-guide.md +445 -0
  68. package/docs/tools/windsurf-guide.md +391 -0
  69. package/docs/troubleshooting.md +1135 -0
  70. package/docs/upgrade-guide.md +639 -0
  71. package/docs/value-observability-guide.md +127 -0
  72. package/docs/zh/README.md +341 -0
  73. package/docs/zh/quick-start.md +764 -0
  74. package/docs/zh/release-checklist.md +121 -0
  75. package/docs/zh/releases/README.md +13 -0
  76. package/docs/zh/releases/v1.46.2-validation.md +45 -0
  77. package/docs/zh/releases/v1.46.2.md +50 -0
  78. package/docs/zh/spec-numbering-guide.md +348 -0
  79. package/docs/zh/tools/claude-guide.md +349 -0
  80. package/docs/zh/tools/cursor-guide.md +281 -0
  81. package/docs/zh/tools/generic-guide.md +499 -0
  82. package/docs/zh/tools/kiro-guide.md +342 -0
  83. package/docs/zh/tools/vscode-guide.md +449 -0
  84. package/docs/zh/tools/windsurf-guide.md +378 -0
  85. package/docs/zh/value-observability-guide.md +127 -0
  86. package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
  87. package/lib/adoption/adoption-logger.js +487 -0
  88. package/lib/adoption/adoption-strategy.js +538 -0
  89. package/lib/adoption/backup-manager.js +420 -0
  90. package/lib/adoption/conflict-resolver.js +410 -0
  91. package/lib/adoption/detection-engine.js +275 -0
  92. package/lib/adoption/diff-viewer.js +226 -0
  93. package/lib/adoption/error-formatter.js +509 -0
  94. package/lib/adoption/file-classifier.js +385 -0
  95. package/lib/adoption/progress-reporter.js +534 -0
  96. package/lib/adoption/smart-orchestrator.js +470 -0
  97. package/lib/adoption/strategy-selector.js +218 -0
  98. package/lib/adoption/summary-generator.js +493 -0
  99. package/lib/adoption/template-sync.js +605 -0
  100. package/lib/auto/autonomous-engine.js +485 -0
  101. package/lib/auto/checkpoint-manager.js +300 -0
  102. package/lib/auto/close-loop-runner.js +2476 -0
  103. package/lib/auto/config-schema.js +176 -0
  104. package/lib/auto/decision-engine.js +344 -0
  105. package/lib/auto/error-recovery-manager.js +580 -0
  106. package/lib/auto/goal-decomposer.js +278 -0
  107. package/lib/auto/progress-tracker.js +502 -0
  108. package/lib/auto/safety-manager.js +186 -0
  109. package/lib/auto/semantic-decomposer.js +137 -0
  110. package/lib/auto/state-manager.js +126 -0
  111. package/lib/auto/task-queue-manager.js +340 -0
  112. package/lib/backup/backup-system.js +372 -0
  113. package/lib/backup/selective-backup.js +207 -0
  114. package/lib/collab/agent-registry.js +240 -0
  115. package/lib/collab/collab-manager.js +285 -0
  116. package/lib/collab/contract-manager.js +320 -0
  117. package/lib/collab/coordinator.js +370 -0
  118. package/lib/collab/dependency-manager.js +280 -0
  119. package/lib/collab/index.js +20 -0
  120. package/lib/collab/integration-manager.js +202 -0
  121. package/lib/collab/merge-coordinator.js +252 -0
  122. package/lib/collab/metadata-manager.js +233 -0
  123. package/lib/collab/multi-agent-config.js +120 -0
  124. package/lib/collab/spec-lifecycle-manager.js +304 -0
  125. package/lib/collab/sync-barrier.js +88 -0
  126. package/lib/collab/visualizer.js +208 -0
  127. package/lib/commands/adopt.js +749 -0
  128. package/lib/commands/auto.js +19559 -0
  129. package/lib/commands/collab.js +275 -0
  130. package/lib/commands/context.js +99 -0
  131. package/lib/commands/docs.js +808 -0
  132. package/lib/commands/doctor.js +273 -0
  133. package/lib/commands/env.js +420 -0
  134. package/lib/commands/knowledge.js +309 -0
  135. package/lib/commands/lock.js +235 -0
  136. package/lib/commands/ops.js +409 -0
  137. package/lib/commands/orchestrate.js +446 -0
  138. package/lib/commands/prompt.js +105 -0
  139. package/lib/commands/repo.js +118 -0
  140. package/lib/commands/rollback.js +219 -0
  141. package/lib/commands/scene.js +15549 -0
  142. package/lib/commands/spec-bootstrap.js +147 -0
  143. package/lib/commands/spec-gate.js +157 -0
  144. package/lib/commands/spec-pipeline.js +205 -0
  145. package/lib/commands/status.js +321 -0
  146. package/lib/commands/task.js +199 -0
  147. package/lib/commands/templates.js +654 -0
  148. package/lib/commands/upgrade.js +231 -0
  149. package/lib/commands/value.js +569 -0
  150. package/lib/commands/watch.js +684 -0
  151. package/lib/commands/workflows.js +240 -0
  152. package/lib/commands/workspace-multi.js +325 -0
  153. package/lib/commands/workspace.js +189 -0
  154. package/lib/context/context-exporter.js +378 -0
  155. package/lib/context/prompt-generator.js +482 -0
  156. package/lib/data/moqui-capability-lexicon.json +45 -0
  157. package/lib/environment/backup-system.js +189 -0
  158. package/lib/environment/environment-manager.js +379 -0
  159. package/lib/environment/environment-registry.js +168 -0
  160. package/lib/gitignore/gitignore-backup.js +229 -0
  161. package/lib/gitignore/gitignore-detector.js +239 -0
  162. package/lib/gitignore/gitignore-integration.js +267 -0
  163. package/lib/gitignore/gitignore-transformer.js +193 -0
  164. package/lib/gitignore/layered-rules-template.js +42 -0
  165. package/lib/governance/archive-tool.js +284 -0
  166. package/lib/governance/cleanup-tool.js +237 -0
  167. package/lib/governance/config-manager.js +186 -0
  168. package/lib/governance/diagnostic-engine.js +271 -0
  169. package/lib/governance/doc-reference-checker.js +200 -0
  170. package/lib/governance/execution-logger.js +243 -0
  171. package/lib/governance/file-scanner.js +285 -0
  172. package/lib/governance/hooks-manager.js +333 -0
  173. package/lib/governance/reporter.js +337 -0
  174. package/lib/governance/validation-engine.js +181 -0
  175. package/lib/i18n.js +79 -0
  176. package/lib/knowledge/entry-manager.js +208 -0
  177. package/lib/knowledge/index-manager.js +261 -0
  178. package/lib/knowledge/knowledge-manager.js +273 -0
  179. package/lib/knowledge/template-manager.js +191 -0
  180. package/lib/lock/index.js +21 -0
  181. package/lib/lock/lock-file.js +192 -0
  182. package/lib/lock/lock-manager.js +321 -0
  183. package/lib/lock/machine-identifier.js +135 -0
  184. package/lib/lock/steering-file-lock.js +207 -0
  185. package/lib/lock/task-lock-manager.js +345 -0
  186. package/lib/operations/audit-logger.js +293 -0
  187. package/lib/operations/feedback-manager.js +1147 -0
  188. package/lib/operations/index.js +23 -0
  189. package/lib/operations/models/index.js +170 -0
  190. package/lib/operations/operations-manager.js +151 -0
  191. package/lib/operations/operations-validator.js +280 -0
  192. package/lib/operations/permission-manager.js +354 -0
  193. package/lib/operations/template-loader.js +143 -0
  194. package/lib/orchestrator/agent-spawner.js +629 -0
  195. package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
  196. package/lib/orchestrator/index.js +19 -0
  197. package/lib/orchestrator/orchestration-engine.js +1270 -0
  198. package/lib/orchestrator/orchestrator-config.js +173 -0
  199. package/lib/orchestrator/status-monitor.js +591 -0
  200. package/lib/python-checker.js +209 -0
  201. package/lib/repo/config-manager.js +580 -0
  202. package/lib/repo/errors/config-error.js +13 -0
  203. package/lib/repo/errors/git-error.js +15 -0
  204. package/lib/repo/errors/repo-error.js +14 -0
  205. package/lib/repo/git-operations.js +181 -0
  206. package/lib/repo/handlers/.gitkeep +1 -0
  207. package/lib/repo/handlers/exec-handler.js +155 -0
  208. package/lib/repo/handlers/health-handler.js +169 -0
  209. package/lib/repo/handlers/init-handler.js +197 -0
  210. package/lib/repo/handlers/status-handler.js +176 -0
  211. package/lib/repo/output-formatter.js +184 -0
  212. package/lib/repo/path-resolver.js +178 -0
  213. package/lib/repo/repo-manager.js +514 -0
  214. package/lib/scene-runtime/audit-emitter.js +59 -0
  215. package/lib/scene-runtime/binding-plugin-loader.js +351 -0
  216. package/lib/scene-runtime/binding-registry.js +349 -0
  217. package/lib/scene-runtime/eval-bridge.js +44 -0
  218. package/lib/scene-runtime/index.js +19 -0
  219. package/lib/scene-runtime/moqui-adapter.js +620 -0
  220. package/lib/scene-runtime/moqui-client.js +606 -0
  221. package/lib/scene-runtime/moqui-extractor.js +2029 -0
  222. package/lib/scene-runtime/plan-compiler.js +208 -0
  223. package/lib/scene-runtime/policy-gate.js +58 -0
  224. package/lib/scene-runtime/runtime-executor.js +358 -0
  225. package/lib/scene-runtime/scene-loader.js +96 -0
  226. package/lib/scene-runtime/scene-ontology.js +959 -0
  227. package/lib/scene-runtime/scene-template-linter.js +852 -0
  228. package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
  229. package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
  230. package/lib/spec/bootstrap/context-collector.js +48 -0
  231. package/lib/spec/bootstrap/draft-generator.js +158 -0
  232. package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
  233. package/lib/spec/bootstrap/trace-emitter.js +59 -0
  234. package/lib/spec/multi-spec-orchestrate.js +93 -0
  235. package/lib/spec/pipeline/constants.js +6 -0
  236. package/lib/spec/pipeline/stage-adapters.js +118 -0
  237. package/lib/spec/pipeline/stage-runner.js +146 -0
  238. package/lib/spec/pipeline/state-store.js +119 -0
  239. package/lib/spec-gate/engine/gate-engine.js +165 -0
  240. package/lib/spec-gate/policy/default-policy.js +22 -0
  241. package/lib/spec-gate/policy/policy-loader.js +103 -0
  242. package/lib/spec-gate/result-emitter.js +81 -0
  243. package/lib/spec-gate/rules/default-rules.js +156 -0
  244. package/lib/spec-gate/rules/rule-registry.js +51 -0
  245. package/lib/steering/adoption-config.js +164 -0
  246. package/lib/steering/compliance-auto-fixer.js +204 -0
  247. package/lib/steering/compliance-cache.js +99 -0
  248. package/lib/steering/compliance-error-reporter.js +70 -0
  249. package/lib/steering/context-sync-manager.js +273 -0
  250. package/lib/steering/index.js +92 -0
  251. package/lib/steering/spec-steering.js +230 -0
  252. package/lib/steering/steering-compliance-checker.js +73 -0
  253. package/lib/steering/steering-loader.js +144 -0
  254. package/lib/steering/steering-manager.js +289 -0
  255. package/lib/task/index.js +12 -0
  256. package/lib/task/task-claimer.js +489 -0
  257. package/lib/task/task-status-store.js +418 -0
  258. package/lib/templates/cache-manager.js +440 -0
  259. package/lib/templates/content-generalizer.js +247 -0
  260. package/lib/templates/frontmatter-generator.js +128 -0
  261. package/lib/templates/git-handler.js +471 -0
  262. package/lib/templates/metadata-collector.js +328 -0
  263. package/lib/templates/path-utils.js +144 -0
  264. package/lib/templates/registry-parser.js +505 -0
  265. package/lib/templates/spec-reader.js +216 -0
  266. package/lib/templates/template-applicator.js +249 -0
  267. package/lib/templates/template-creator.js +256 -0
  268. package/lib/templates/template-error.js +143 -0
  269. package/lib/templates/template-exporter.js +502 -0
  270. package/lib/templates/template-manager.js +782 -0
  271. package/lib/templates/template-validator.js +361 -0
  272. package/lib/upgrade/migration-engine.js +382 -0
  273. package/lib/upgrade/migrations/.gitkeep +52 -0
  274. package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
  275. package/lib/utils/file-diff.js +177 -0
  276. package/lib/utils/fs-utils.js +274 -0
  277. package/lib/utils/tool-detector.js +383 -0
  278. package/lib/utils/validation.js +324 -0
  279. package/lib/value/gate-summary-emitter.js +99 -0
  280. package/lib/value/metric-contract-loader.js +210 -0
  281. package/lib/value/risk-evaluator.js +117 -0
  282. package/lib/value/weekly-snapshot-builder.js +61 -0
  283. package/lib/version/version-checker.js +156 -0
  284. package/lib/version/version-manager.js +327 -0
  285. package/lib/watch/action-executor.js +458 -0
  286. package/lib/watch/event-debouncer.js +323 -0
  287. package/lib/watch/execution-logger.js +550 -0
  288. package/lib/watch/file-watcher.js +499 -0
  289. package/lib/watch/presets.js +266 -0
  290. package/lib/watch/watch-manager.js +533 -0
  291. package/lib/workspace/multi/global-config.js +150 -0
  292. package/lib/workspace/multi/index.js +22 -0
  293. package/lib/workspace/multi/path-utils.js +173 -0
  294. package/lib/workspace/multi/workspace-context-resolver.js +244 -0
  295. package/lib/workspace/multi/workspace-registry.js +196 -0
  296. package/lib/workspace/multi/workspace-state-manager.js +537 -0
  297. package/lib/workspace/multi/workspace.js +90 -0
  298. package/lib/workspace/workspace-manager.js +370 -0
  299. package/lib/workspace/workspace-sync.js +356 -0
  300. package/locales/en.json +114 -0
  301. package/locales/zh.json +114 -0
  302. package/package.json +102 -0
  303. package/template/.kiro/README.md +247 -0
  304. package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
  305. package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
  306. package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
  307. package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
  308. package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
  309. package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
  310. package/template/.kiro/steering/ENVIRONMENT.md +35 -0
  311. package/template/.kiro/steering/RULES_GUIDE.md +46 -0
  312. package/template/.kiro/templates/operations/default/change-impact.md +112 -0
  313. package/template/.kiro/templates/operations/default/deployment.md +91 -0
  314. package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
  315. package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
  316. package/template/.kiro/templates/operations/default/monitoring.md +135 -0
  317. package/template/.kiro/templates/operations/default/operations.md +135 -0
  318. package/template/.kiro/templates/operations/default/rollback.md +143 -0
  319. package/template/.kiro/templates/operations/default/tools.yaml +364 -0
  320. package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
  321. package/template/.kiro/tools/backup_manager.py +295 -0
  322. package/template/.kiro/tools/configuration_manager.py +218 -0
  323. package/template/.kiro/tools/document_evaluator.py +550 -0
  324. package/template/.kiro/tools/enhancement_logger.py +168 -0
  325. package/template/.kiro/tools/error_handler.py +335 -0
  326. package/template/.kiro/tools/improvement_identifier.py +444 -0
  327. package/template/.kiro/tools/modification_applicator.py +737 -0
  328. package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
  329. package/template/.kiro/tools/quality_scorer.py +305 -0
  330. package/template/.kiro/tools/report_generator.py +154 -0
  331. package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
  332. package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
  333. package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
  334. package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
  335. package/template/.kiro/tools/workflow_quality_gate.py +100 -0
  336. 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;