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,605 @@
1
+ /**
2
+ * Template Sync System
3
+ *
4
+ * Automatically synchronizes template files with project files.
5
+ * Detects content differences and updates only changed files.
6
+ * Preserves user-specific files like CURRENT_CONTEXT.md.
7
+ */
8
+
9
+ const path = require('path');
10
+ const crypto = require('crypto');
11
+ const fs = require('fs-extra');
12
+ const { pathExists } = require('../utils/fs-utils');
13
+ const { FileClassifier, FileCategory } = require('./file-classifier');
14
+
15
+ /**
16
+ * Template Sync System
17
+ *
18
+ * Compares template files with project files and synchronizes
19
+ * only the files that have changed.
20
+ */
21
+ class TemplateSync {
22
+ constructor() {
23
+ this.fileClassifier = new FileClassifier();
24
+
25
+ // Template files to sync (relative to .kiro/)
26
+ this.templateFiles = [
27
+ 'steering/CORE_PRINCIPLES.md',
28
+ 'steering/ENVIRONMENT.md',
29
+ 'steering/RULES_GUIDE.md',
30
+ 'tools/ultrawork_enhancer.py',
31
+ 'README.md',
32
+ 'ultrawork-application-guide.md',
33
+ 'ultrawork-integration-summary.md',
34
+ 'sisyphus-deep-dive.md'
35
+ ];
36
+
37
+ // Files to always preserve (never sync)
38
+ this.preserveFiles = [
39
+ 'steering/CURRENT_CONTEXT.md'
40
+ ];
41
+ }
42
+
43
+ /**
44
+ * Detect differences between template and project files
45
+ *
46
+ * @param {string} projectPath - Absolute path to project root
47
+ * @param {string} templatePath - Absolute path to template directory
48
+ * @returns {Promise<SyncReport>} Sync report with differences
49
+ */
50
+ async detectTemplateDifferences(projectPath, templatePath) {
51
+ const differences = {
52
+ missing: [], // Files that don't exist in project
53
+ different: [], // Files with different content
54
+ identical: [], // Files with identical content
55
+ preserved: [], // Files that should be preserved
56
+ errors: [] // Files that couldn't be compared
57
+ };
58
+
59
+ const kiroPath = path.join(projectPath, '.kiro');
60
+
61
+ for (const templateFile of this.templateFiles) {
62
+ try {
63
+ // Check if file should be preserved
64
+ if (this.shouldPreserve(templateFile)) {
65
+ differences.preserved.push({
66
+ path: templateFile,
67
+ reason: 'User-specific file'
68
+ });
69
+ continue;
70
+ }
71
+
72
+ const projectFilePath = path.join(kiroPath, templateFile);
73
+ const templateFilePath = path.join(templatePath, templateFile);
74
+
75
+ // Check if template file exists
76
+ const templateExists = await pathExists(templateFilePath);
77
+ if (!templateExists) {
78
+ differences.errors.push({
79
+ path: templateFile,
80
+ error: 'Template file not found'
81
+ });
82
+ continue;
83
+ }
84
+
85
+ // Check if project file exists
86
+ const projectExists = await pathExists(projectFilePath);
87
+ if (!projectExists) {
88
+ differences.missing.push({
89
+ path: templateFile,
90
+ templatePath: templateFilePath,
91
+ projectPath: projectFilePath
92
+ });
93
+ continue;
94
+ }
95
+
96
+ // Compare file contents
97
+ const isDifferent = await this.compareFiles(projectFilePath, templateFilePath);
98
+
99
+ if (isDifferent) {
100
+ differences.different.push({
101
+ path: templateFile,
102
+ templatePath: templateFilePath,
103
+ projectPath: projectFilePath
104
+ });
105
+ } else {
106
+ differences.identical.push({
107
+ path: templateFile
108
+ });
109
+ }
110
+ } catch (error) {
111
+ differences.errors.push({
112
+ path: templateFile,
113
+ error: error.message
114
+ });
115
+ }
116
+ }
117
+
118
+ return {
119
+ differences,
120
+ summary: {
121
+ total: this.templateFiles.length,
122
+ missing: differences.missing.length,
123
+ different: differences.different.length,
124
+ identical: differences.identical.length,
125
+ preserved: differences.preserved.length,
126
+ errors: differences.errors.length,
127
+ needsSync: differences.missing.length + differences.different.length
128
+ }
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Compare two files for differences
134
+ *
135
+ * @param {string} file1Path - Path to first file
136
+ * @param {string} file2Path - Path to second file
137
+ * @returns {Promise<boolean>} True if files are different
138
+ */
139
+ async compareFiles(file1Path, file2Path) {
140
+ try {
141
+ // Check if either file is binary
142
+ const isBinary1 = await this.isBinaryFile(file1Path);
143
+ const isBinary2 = await this.isBinaryFile(file2Path);
144
+
145
+ if (isBinary1 || isBinary2) {
146
+ // For binary files, compare file sizes and hashes
147
+ return await this.compareBinaryFiles(file1Path, file2Path);
148
+ } else {
149
+ // For text files, compare content hashes
150
+ return await this.compareTextFiles(file1Path, file2Path);
151
+ }
152
+ } catch (error) {
153
+ throw new Error(`Failed to compare files: ${error.message}`);
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Compare text files by content hash
159
+ *
160
+ * @param {string} file1Path - Path to first file
161
+ * @param {string} file2Path - Path to second file
162
+ * @returns {Promise<boolean>} True if files are different
163
+ */
164
+ async compareTextFiles(file1Path, file2Path) {
165
+ try {
166
+ const content1 = await fs.readFile(file1Path, 'utf8');
167
+ const content2 = await fs.readFile(file2Path, 'utf8');
168
+
169
+ // Normalize line endings for comparison
170
+ const normalized1 = this.normalizeLineEndings(content1);
171
+ const normalized2 = this.normalizeLineEndings(content2);
172
+
173
+ // Compare hashes
174
+ const hash1 = this.calculateHash(normalized1);
175
+ const hash2 = this.calculateHash(normalized2);
176
+
177
+ return hash1 !== hash2;
178
+ } catch (error) {
179
+ throw new Error(`Failed to compare text files: ${error.message}`);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Compare binary files by size and hash
185
+ *
186
+ * @param {string} file1Path - Path to first file
187
+ * @param {string} file2Path - Path to second file
188
+ * @returns {Promise<boolean>} True if files are different
189
+ */
190
+ async compareBinaryFiles(file1Path, file2Path) {
191
+ try {
192
+ // Compare file sizes first (quick check)
193
+ const stats1 = await fs.stat(file1Path);
194
+ const stats2 = await fs.stat(file2Path);
195
+
196
+ if (stats1.size !== stats2.size) {
197
+ return true; // Different sizes = different files
198
+ }
199
+
200
+ // Compare content hashes
201
+ const content1 = await fs.readFile(file1Path);
202
+ const content2 = await fs.readFile(file2Path);
203
+
204
+ const hash1 = this.calculateHash(content1);
205
+ const hash2 = this.calculateHash(content2);
206
+
207
+ return hash1 !== hash2;
208
+ } catch (error) {
209
+ throw new Error(`Failed to compare binary files: ${error.message}`);
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Check if a file is binary
215
+ *
216
+ * @param {string} filePath - Path to file
217
+ * @returns {Promise<boolean>} True if file is binary
218
+ */
219
+ async isBinaryFile(filePath) {
220
+ try {
221
+ // Check file extension first
222
+ const ext = path.extname(filePath).toLowerCase();
223
+ const textExtensions = ['.md', '.txt', '.json', '.js', '.py', '.yml', '.yaml', '.xml', '.html', '.css'];
224
+
225
+ if (textExtensions.includes(ext)) {
226
+ return false;
227
+ }
228
+
229
+ // For unknown extensions, read first few bytes
230
+ const buffer = Buffer.alloc(512);
231
+ const fd = await fs.open(filePath, 'r');
232
+
233
+ try {
234
+ const { bytesRead } = await fs.read(fd, buffer, 0, 512, 0);
235
+
236
+ // Check for null bytes (common in binary files)
237
+ for (let i = 0; i < bytesRead; i++) {
238
+ if (buffer[i] === 0) {
239
+ return true;
240
+ }
241
+ }
242
+
243
+ return false;
244
+ } finally {
245
+ await fs.close(fd);
246
+ }
247
+ } catch (error) {
248
+ // If we can't determine, assume text
249
+ return false;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Normalize line endings to LF
255
+ *
256
+ * @param {string} content - File content
257
+ * @returns {string} Normalized content
258
+ */
259
+ normalizeLineEndings(content) {
260
+ return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
261
+ }
262
+
263
+ /**
264
+ * Calculate SHA-256 hash of content
265
+ *
266
+ * @param {string|Buffer} content - Content to hash
267
+ * @returns {string} Hex hash
268
+ */
269
+ calculateHash(content) {
270
+ return crypto.createHash('sha256').update(content).digest('hex');
271
+ }
272
+
273
+ /**
274
+ * Check if a file should be preserved
275
+ *
276
+ * @param {string} filePath - File path relative to .kiro/
277
+ * @returns {boolean} True if file should be preserved
278
+ */
279
+ shouldPreserve(filePath) {
280
+ const normalized = this.normalizeFilePath(filePath);
281
+ return this.preserveFiles.some(preserve =>
282
+ normalized === preserve || normalized.endsWith('/' + preserve)
283
+ );
284
+ }
285
+
286
+ /**
287
+ * Normalize file path
288
+ *
289
+ * @param {string} filePath - File path
290
+ * @returns {string} Normalized path
291
+ */
292
+ normalizeFilePath(filePath) {
293
+ return filePath.replace(/\\/g, '/');
294
+ }
295
+
296
+ /**
297
+ * Synchronize templates to project
298
+ *
299
+ * @param {string} projectPath - Absolute path to project root
300
+ * @param {string} templatePath - Absolute path to template directory
301
+ * @param {Object} options - Sync options
302
+ * @param {boolean} options.dryRun - Preview without executing
303
+ * @param {Function} options.onProgress - Progress callback
304
+ * @returns {Promise<SyncResult>} Sync result
305
+ */
306
+ async syncTemplates(projectPath, templatePath, options = {}) {
307
+ const { dryRun = false, onProgress = null } = options;
308
+
309
+ // Detect differences first
310
+ const report = await this.detectTemplateDifferences(projectPath, templatePath);
311
+
312
+ if (dryRun) {
313
+ return {
314
+ dryRun: true,
315
+ report,
316
+ synced: [],
317
+ errors: []
318
+ };
319
+ }
320
+
321
+ const synced = [];
322
+ const errors = [];
323
+ const kiroPath = path.join(projectPath, '.kiro');
324
+
325
+ // Sync missing files
326
+ for (const missing of report.differences.missing) {
327
+ try {
328
+ if (onProgress) {
329
+ onProgress({
330
+ type: 'create',
331
+ file: missing.path,
332
+ status: 'in-progress'
333
+ });
334
+ }
335
+
336
+ // Ensure directory exists
337
+ const targetDir = path.dirname(missing.projectPath);
338
+ await fs.ensureDir(targetDir);
339
+
340
+ // Copy file
341
+ await fs.copy(missing.templatePath, missing.projectPath);
342
+
343
+ synced.push({
344
+ path: missing.path,
345
+ action: 'created'
346
+ });
347
+
348
+ if (onProgress) {
349
+ onProgress({
350
+ type: 'create',
351
+ file: missing.path,
352
+ status: 'complete'
353
+ });
354
+ }
355
+ } catch (error) {
356
+ errors.push({
357
+ path: missing.path,
358
+ error: error.message
359
+ });
360
+
361
+ if (onProgress) {
362
+ onProgress({
363
+ type: 'create',
364
+ file: missing.path,
365
+ status: 'error',
366
+ error: error.message
367
+ });
368
+ }
369
+ }
370
+ }
371
+
372
+ // Sync different files
373
+ for (const different of report.differences.different) {
374
+ try {
375
+ if (onProgress) {
376
+ onProgress({
377
+ type: 'update',
378
+ file: different.path,
379
+ status: 'in-progress'
380
+ });
381
+ }
382
+
383
+ // Ensure directory exists
384
+ const targetDir = path.dirname(different.projectPath);
385
+ await fs.ensureDir(targetDir);
386
+
387
+ // Copy file (overwrite)
388
+ await fs.copy(different.templatePath, different.projectPath);
389
+
390
+ synced.push({
391
+ path: different.path,
392
+ action: 'updated'
393
+ });
394
+
395
+ if (onProgress) {
396
+ onProgress({
397
+ type: 'update',
398
+ file: different.path,
399
+ status: 'complete'
400
+ });
401
+ }
402
+ } catch (error) {
403
+ errors.push({
404
+ path: different.path,
405
+ error: error.message
406
+ });
407
+
408
+ if (onProgress) {
409
+ onProgress({
410
+ type: 'update',
411
+ file: different.path,
412
+ status: 'error',
413
+ error: error.message
414
+ });
415
+ }
416
+ }
417
+ }
418
+
419
+ return {
420
+ dryRun: false,
421
+ report,
422
+ synced,
423
+ errors,
424
+ summary: {
425
+ total: synced.length + errors.length,
426
+ synced: synced.length,
427
+ errors: errors.length,
428
+ created: synced.filter(s => s.action === 'created').length,
429
+ updated: synced.filter(s => s.action === 'updated').length
430
+ }
431
+ };
432
+ }
433
+
434
+ /**
435
+ * Get sync report summary as formatted string
436
+ *
437
+ * @param {SyncReport} report - Sync report
438
+ * @returns {string} Formatted summary
439
+ */
440
+ formatSyncReport(report) {
441
+ const lines = [];
442
+
443
+ lines.push('Template Sync Report:');
444
+ lines.push(` Total templates: ${report.summary.total}`);
445
+ lines.push(` Needs sync: ${report.summary.needsSync}`);
446
+ lines.push(` Missing: ${report.summary.missing}`);
447
+ lines.push(` Different: ${report.summary.different}`);
448
+ lines.push(` Up-to-date: ${report.summary.identical}`);
449
+ lines.push(` Preserved: ${report.summary.preserved}`);
450
+
451
+ if (report.summary.errors > 0) {
452
+ lines.push(` Errors: ${report.summary.errors}`);
453
+ }
454
+
455
+ if (report.differences.missing.length > 0) {
456
+ lines.push('');
457
+ lines.push('Missing files:');
458
+ report.differences.missing.forEach(file => {
459
+ lines.push(` - ${file.path}`);
460
+ });
461
+ }
462
+
463
+ if (report.differences.different.length > 0) {
464
+ lines.push('');
465
+ lines.push('Different files:');
466
+ report.differences.different.forEach(file => {
467
+ lines.push(` - ${file.path}`);
468
+ });
469
+ }
470
+
471
+ if (report.differences.preserved.length > 0) {
472
+ lines.push('');
473
+ lines.push('Preserved files:');
474
+ report.differences.preserved.forEach(file => {
475
+ lines.push(` - ${file.path} (${file.reason})`);
476
+ });
477
+ }
478
+
479
+ if (report.differences.errors.length > 0) {
480
+ lines.push('');
481
+ lines.push('Errors:');
482
+ report.differences.errors.forEach(file => {
483
+ lines.push(` - ${file.path}: ${file.error}`);
484
+ });
485
+ }
486
+
487
+ return lines.join('\n');
488
+ }
489
+
490
+ /**
491
+ * Get sync result summary as formatted string
492
+ *
493
+ * @param {SyncResult} result - Sync result
494
+ * @returns {string} Formatted summary
495
+ */
496
+ formatSyncResult(result) {
497
+ const lines = [];
498
+
499
+ if (result.dryRun) {
500
+ lines.push('Dry Run - No changes made');
501
+ lines.push('');
502
+ lines.push(this.formatSyncReport(result.report));
503
+ return lines.join('\n');
504
+ }
505
+
506
+ lines.push('Template Sync Complete:');
507
+ lines.push(` Total: ${result.summary.total}`);
508
+ lines.push(` Synced: ${result.summary.synced}`);
509
+ lines.push(` Created: ${result.summary.created}`);
510
+ lines.push(` Updated: ${result.summary.updated}`);
511
+
512
+ if (result.summary.errors > 0) {
513
+ lines.push(` Errors: ${result.summary.errors}`);
514
+ }
515
+
516
+ if (result.synced.length > 0) {
517
+ lines.push('');
518
+ lines.push('Synced files:');
519
+ result.synced.forEach(file => {
520
+ const icon = file.action === 'created' ? '✨' : '📝';
521
+ lines.push(` ${icon} ${file.path} (${file.action})`);
522
+ });
523
+ }
524
+
525
+ if (result.errors.length > 0) {
526
+ lines.push('');
527
+ lines.push('Errors:');
528
+ result.errors.forEach(file => {
529
+ lines.push(` ❌ ${file.path}: ${file.error}`);
530
+ });
531
+ }
532
+
533
+ return lines.join('\n');
534
+ }
535
+
536
+ /**
537
+ * Get list of template files
538
+ *
539
+ * @returns {string[]} Template file paths
540
+ */
541
+ getTemplateFiles() {
542
+ return [...this.templateFiles];
543
+ }
544
+
545
+ /**
546
+ * Get list of preserved files
547
+ *
548
+ * @returns {string[]} Preserved file paths
549
+ */
550
+ getPreservedFiles() {
551
+ return [...this.preserveFiles];
552
+ }
553
+
554
+ /**
555
+ * Add template file to sync list
556
+ *
557
+ * @param {string} filePath - File path relative to .kiro/
558
+ */
559
+ addTemplateFile(filePath) {
560
+ const normalized = this.normalizeFilePath(filePath);
561
+ if (!this.templateFiles.includes(normalized)) {
562
+ this.templateFiles.push(normalized);
563
+ }
564
+ }
565
+
566
+ /**
567
+ * Remove template file from sync list
568
+ *
569
+ * @param {string} filePath - File path relative to .kiro/
570
+ */
571
+ removeTemplateFile(filePath) {
572
+ const normalized = this.normalizeFilePath(filePath);
573
+ const index = this.templateFiles.indexOf(normalized);
574
+ if (index !== -1) {
575
+ this.templateFiles.splice(index, 1);
576
+ }
577
+ }
578
+
579
+ /**
580
+ * Add file to preserve list
581
+ *
582
+ * @param {string} filePath - File path relative to .kiro/
583
+ */
584
+ addPreservedFile(filePath) {
585
+ const normalized = this.normalizeFilePath(filePath);
586
+ if (!this.preserveFiles.includes(normalized)) {
587
+ this.preserveFiles.push(normalized);
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Remove file from preserve list
593
+ *
594
+ * @param {string} filePath - File path relative to .kiro/
595
+ */
596
+ removePreservedFile(filePath) {
597
+ const normalized = this.normalizeFilePath(filePath);
598
+ const index = this.preserveFiles.indexOf(normalized);
599
+ if (index !== -1) {
600
+ this.preserveFiles.splice(index, 1);
601
+ }
602
+ }
603
+ }
604
+
605
+ module.exports = TemplateSync;