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,128 @@
1
+ /**
2
+ * FrontmatterGenerator - Generates YAML frontmatter for template files
3
+ */
4
+
5
+ const yaml = require('js-yaml');
6
+
7
+ class FrontmatterGenerator {
8
+ constructor() {}
9
+
10
+ /**
11
+ * Generates YAML frontmatter
12
+ * @param {Object} metadata - Template metadata
13
+ * @returns {string} YAML frontmatter block
14
+ */
15
+ generateFrontmatter(metadata) {
16
+ const frontmatterData = {
17
+ name: metadata.name,
18
+ category: metadata.category,
19
+ description: metadata.description,
20
+ tags: metadata.tags || [],
21
+ author: metadata.author,
22
+ created_at: metadata.created_at,
23
+ updated_at: metadata.updated_at,
24
+ version: metadata.version,
25
+ kse_version: metadata.kse_version
26
+ };
27
+
28
+ // Add optional fields if present
29
+ if (metadata.difficulty) {
30
+ frontmatterData.difficulty = metadata.difficulty;
31
+ }
32
+ if (metadata.applicable_scenarios) {
33
+ frontmatterData.applicable_scenarios = metadata.applicable_scenarios;
34
+ }
35
+
36
+ try {
37
+ const yamlContent = yaml.dump(frontmatterData, {
38
+ indent: 2,
39
+ lineWidth: -1,
40
+ noRefs: true
41
+ });
42
+
43
+ return `---\n${yamlContent}---\n`;
44
+ } catch (error) {
45
+ throw new Error(`Failed to generate YAML frontmatter: ${error.message}`);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Adds frontmatter to file content
51
+ * @param {string} content - Original content
52
+ * @param {string} frontmatter - YAML frontmatter
53
+ * @returns {string} Content with frontmatter
54
+ */
55
+ addFrontmatter(content, frontmatter) {
56
+ // Remove existing frontmatter if present
57
+ const withoutFrontmatter = this.removeFrontmatter(content);
58
+
59
+ // Add new frontmatter
60
+ return frontmatter + '\n' + withoutFrontmatter;
61
+ }
62
+
63
+ /**
64
+ * Removes existing frontmatter from content
65
+ * @param {string} content - Content with possible frontmatter
66
+ * @returns {string} Content without frontmatter
67
+ */
68
+ removeFrontmatter(content) {
69
+ // Check if content starts with frontmatter
70
+ if (!content.trim().startsWith('---')) {
71
+ return content;
72
+ }
73
+
74
+ // Find the closing ---
75
+ const lines = content.split('\n');
76
+ let endIndex = -1;
77
+
78
+ for (let i = 1; i < lines.length; i++) {
79
+ if (lines[i].trim() === '---') {
80
+ endIndex = i;
81
+ break;
82
+ }
83
+ }
84
+
85
+ if (endIndex === -1) {
86
+ // No closing ---, return original content
87
+ return content;
88
+ }
89
+
90
+ // Return content after frontmatter
91
+ return lines.slice(endIndex + 1).join('\n').trim();
92
+ }
93
+
94
+ /**
95
+ * Validates YAML syntax
96
+ * @param {string} yamlContent - YAML content
97
+ * @returns {Object} Validation result
98
+ */
99
+ validateYaml(yamlContent) {
100
+ try {
101
+ yaml.load(yamlContent);
102
+ return {
103
+ valid: true,
104
+ errors: []
105
+ };
106
+ } catch (error) {
107
+ return {
108
+ valid: false,
109
+ errors: [error.message]
110
+ };
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Formats array fields for YAML
116
+ * @param {Array} items - Array items
117
+ * @returns {string} Formatted YAML array
118
+ */
119
+ formatArrayField(items) {
120
+ if (!Array.isArray(items) || items.length === 0) {
121
+ return '[]';
122
+ }
123
+
124
+ return items.map(item => ` - ${item}`).join('\n');
125
+ }
126
+ }
127
+
128
+ module.exports = FrontmatterGenerator;
@@ -0,0 +1,471 @@
1
+ /**
2
+ * GitHandler - Handles Git operations for template repositories
3
+ *
4
+ * Provides functionality for cloning, updating, and managing Git repositories
5
+ * containing template libraries.
6
+ */
7
+
8
+ const { execSync, exec } = require('child_process');
9
+ const fs = require('fs-extra');
10
+ const path = require('path');
11
+ const { GitError } = require('./template-error');
12
+
13
+ class GitHandler {
14
+ constructor() {
15
+ this.gitAvailable = null;
16
+ }
17
+
18
+ /**
19
+ * Checks if Git is installed and available
20
+ *
21
+ * @returns {boolean} True if Git is available
22
+ */
23
+ isGitInstalled() {
24
+ if (this.gitAvailable !== null) {
25
+ return this.gitAvailable;
26
+ }
27
+
28
+ try {
29
+ execSync('git --version', { stdio: 'ignore' });
30
+ this.gitAvailable = true;
31
+ return true;
32
+ } catch (error) {
33
+ this.gitAvailable = false;
34
+ return false;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Clones a Git repository
40
+ *
41
+ * @param {string} url - Repository URL
42
+ * @param {string} targetPath - Local path to clone to
43
+ * @param {Object} options - Clone options
44
+ * @param {boolean} options.shallow - Use shallow clone (--depth 1)
45
+ * @param {string} options.branch - Branch to clone
46
+ * @returns {Promise<void>}
47
+ */
48
+ async cloneRepository(url, targetPath, options = {}) {
49
+ const { shallow = true, branch = null } = options;
50
+
51
+ // Check Git installation
52
+ if (!this.isGitInstalled()) {
53
+ throw new GitError(
54
+ 'Git is not installed or not in PATH',
55
+ {
56
+ url,
57
+ targetPath,
58
+ suggestion: 'Install Git from https://git-scm.com/'
59
+ }
60
+ );
61
+ }
62
+
63
+ // Ensure target directory doesn't exist
64
+ if (await fs.pathExists(targetPath)) {
65
+ throw new GitError(
66
+ 'Target directory already exists',
67
+ {
68
+ targetPath,
69
+ suggestion: 'Remove the directory or choose a different path'
70
+ }
71
+ );
72
+ }
73
+
74
+ // Build clone command
75
+ let command = 'git clone';
76
+
77
+ if (shallow) {
78
+ command += ' --depth 1';
79
+ }
80
+
81
+ if (branch) {
82
+ command += ` --branch ${branch}`;
83
+ }
84
+
85
+ command += ` "${url}" "${targetPath}"`;
86
+
87
+ // Execute clone
88
+ return new Promise((resolve, reject) => {
89
+ exec(command, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
90
+ if (error) {
91
+ // Classify error type
92
+ const errorMessage = stderr || error.message;
93
+
94
+ if (errorMessage.includes('Authentication failed') ||
95
+ errorMessage.includes('could not read Username')) {
96
+ reject(new GitError(
97
+ 'Git authentication failed',
98
+ {
99
+ url,
100
+ error: errorMessage,
101
+ suggestion: 'Check repository URL and authentication credentials'
102
+ }
103
+ ));
104
+ } else if (errorMessage.includes('Repository not found') ||
105
+ errorMessage.includes('not found')) {
106
+ reject(new GitError(
107
+ 'Repository not found',
108
+ {
109
+ url,
110
+ error: errorMessage,
111
+ suggestion: 'Verify the repository URL is correct'
112
+ }
113
+ ));
114
+ } else if (errorMessage.includes('Connection') ||
115
+ errorMessage.includes('network') ||
116
+ errorMessage.includes('timeout')) {
117
+ reject(new GitError(
118
+ 'Network error during clone',
119
+ {
120
+ url,
121
+ error: errorMessage,
122
+ suggestion: 'Check your internet connection and try again'
123
+ }
124
+ ));
125
+ } else {
126
+ reject(new GitError(
127
+ 'Git clone failed',
128
+ {
129
+ url,
130
+ targetPath,
131
+ error: errorMessage
132
+ }
133
+ ));
134
+ }
135
+ } else {
136
+ resolve();
137
+ }
138
+ });
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Checks if a directory is a Git repository
144
+ *
145
+ * @param {string} repoPath - Path to check
146
+ * @returns {Promise<boolean>}
147
+ */
148
+ async isGitRepository(repoPath) {
149
+ const gitDir = path.join(repoPath, '.git');
150
+ return await fs.pathExists(gitDir);
151
+ }
152
+
153
+ /**
154
+ * Gets the remote URL of a Git repository
155
+ *
156
+ * @param {string} repoPath - Repository path
157
+ * @returns {Promise<string>} Remote URL
158
+ */
159
+ async getRemoteUrl(repoPath) {
160
+ if (!await this.isGitRepository(repoPath)) {
161
+ throw new GitError(
162
+ 'Not a Git repository',
163
+ { repoPath }
164
+ );
165
+ }
166
+
167
+ try {
168
+ const url = execSync('git remote get-url origin', {
169
+ cwd: repoPath,
170
+ encoding: 'utf8'
171
+ }).trim();
172
+
173
+ return url;
174
+ } catch (error) {
175
+ throw new GitError(
176
+ 'Failed to get remote URL',
177
+ {
178
+ repoPath,
179
+ error: error.message
180
+ }
181
+ );
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Gets the current commit hash
187
+ *
188
+ * @param {string} repoPath - Repository path
189
+ * @returns {Promise<string>} Commit hash
190
+ */
191
+ async getCurrentCommit(repoPath) {
192
+ if (!await this.isGitRepository(repoPath)) {
193
+ throw new GitError(
194
+ 'Not a Git repository',
195
+ { repoPath }
196
+ );
197
+ }
198
+
199
+ try {
200
+ const hash = execSync('git rev-parse HEAD', {
201
+ cwd: repoPath,
202
+ encoding: 'utf8'
203
+ }).trim();
204
+
205
+ return hash;
206
+ } catch (error) {
207
+ throw new GitError(
208
+ 'Failed to get current commit',
209
+ {
210
+ repoPath,
211
+ error: error.message
212
+ }
213
+ );
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Pulls latest changes from remote
219
+ *
220
+ * @param {string} repoPath - Repository path
221
+ * @returns {Promise<void>}
222
+ */
223
+ async pullUpdates(repoPath) {
224
+ if (!await this.isGitRepository(repoPath)) {
225
+ throw new GitError(
226
+ 'Not a Git repository',
227
+ { repoPath }
228
+ );
229
+ }
230
+
231
+ return new Promise((resolve, reject) => {
232
+ exec('git pull', { cwd: repoPath }, (error, stdout, stderr) => {
233
+ if (error) {
234
+ const errorMessage = stderr || error.message;
235
+
236
+ if (errorMessage.includes('conflict') || errorMessage.includes('CONFLICT')) {
237
+ reject(new GitError(
238
+ 'Merge conflict during pull',
239
+ {
240
+ repoPath,
241
+ error: errorMessage,
242
+ suggestion: 'Resolve conflicts manually or clear cache and re-download'
243
+ }
244
+ ));
245
+ } else if (errorMessage.includes('Authentication') ||
246
+ errorMessage.includes('Permission denied')) {
247
+ reject(new GitError(
248
+ 'Authentication failed during pull',
249
+ {
250
+ repoPath,
251
+ error: errorMessage,
252
+ suggestion: 'Check repository access permissions'
253
+ }
254
+ ));
255
+ } else {
256
+ reject(new GitError(
257
+ 'Git pull failed',
258
+ {
259
+ repoPath,
260
+ error: errorMessage
261
+ }
262
+ ));
263
+ }
264
+ } else {
265
+ resolve();
266
+ }
267
+ });
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Checks out a specific version (tag or commit)
273
+ *
274
+ * @param {string} repoPath - Repository path
275
+ * @param {string} version - Tag name or commit hash
276
+ * @returns {Promise<void>}
277
+ */
278
+ async checkoutVersion(repoPath, version) {
279
+ if (!await this.isGitRepository(repoPath)) {
280
+ throw new GitError(
281
+ 'Not a Git repository',
282
+ { repoPath }
283
+ );
284
+ }
285
+
286
+ return new Promise((resolve, reject) => {
287
+ exec(`git checkout ${version}`, { cwd: repoPath }, (error, stdout, stderr) => {
288
+ if (error) {
289
+ const errorMessage = stderr || error.message;
290
+
291
+ if (errorMessage.includes('did not match') ||
292
+ errorMessage.includes('pathspec')) {
293
+ reject(new GitError(
294
+ 'Version not found',
295
+ {
296
+ repoPath,
297
+ version,
298
+ error: errorMessage,
299
+ suggestion: 'Check that the tag or commit exists'
300
+ }
301
+ ));
302
+ } else {
303
+ reject(new GitError(
304
+ 'Git checkout failed',
305
+ {
306
+ repoPath,
307
+ version,
308
+ error: errorMessage
309
+ }
310
+ ));
311
+ }
312
+ } else {
313
+ resolve();
314
+ }
315
+ });
316
+ });
317
+ }
318
+
319
+ /**
320
+ * Gets list of available tags
321
+ *
322
+ * @param {string} repoPath - Repository path
323
+ * @returns {Promise<string[]>} Array of tag names
324
+ */
325
+ async getTags(repoPath) {
326
+ if (!await this.isGitRepository(repoPath)) {
327
+ throw new GitError(
328
+ 'Not a Git repository',
329
+ { repoPath }
330
+ );
331
+ }
332
+
333
+ try {
334
+ const output = execSync('git tag', {
335
+ cwd: repoPath,
336
+ encoding: 'utf8'
337
+ });
338
+
339
+ const tags = output.trim().split('\n').filter(tag => tag.length > 0);
340
+ return tags;
341
+ } catch (error) {
342
+ throw new GitError(
343
+ 'Failed to get tags',
344
+ {
345
+ repoPath,
346
+ error: error.message
347
+ }
348
+ );
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Gets the current branch name
354
+ *
355
+ * @param {string} repoPath - Repository path
356
+ * @returns {Promise<string>} Branch name
357
+ */
358
+ async getCurrentBranch(repoPath) {
359
+ if (!await this.isGitRepository(repoPath)) {
360
+ throw new GitError(
361
+ 'Not a Git repository',
362
+ { repoPath }
363
+ );
364
+ }
365
+
366
+ try {
367
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
368
+ cwd: repoPath,
369
+ encoding: 'utf8'
370
+ }).trim();
371
+
372
+ return branch;
373
+ } catch (error) {
374
+ throw new GitError(
375
+ 'Failed to get current branch',
376
+ {
377
+ repoPath,
378
+ error: error.message
379
+ }
380
+ );
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Validates repository structure
386
+ *
387
+ * @param {string} repoPath - Repository path
388
+ * @returns {Promise<Object>} Validation result
389
+ */
390
+ async validateRepository(repoPath) {
391
+ const result = {
392
+ valid: true,
393
+ errors: [],
394
+ warnings: []
395
+ };
396
+
397
+ // Check if it's a Git repository
398
+ if (!await this.isGitRepository(repoPath)) {
399
+ result.valid = false;
400
+ result.errors.push('Not a Git repository');
401
+ return result;
402
+ }
403
+
404
+ // Check if template-registry.json exists
405
+ const registryPath = path.join(repoPath, 'template-registry.json');
406
+ if (!await fs.pathExists(registryPath)) {
407
+ result.valid = false;
408
+ result.errors.push('Missing template-registry.json');
409
+ }
410
+
411
+ // Check if README.md exists
412
+ const readmePath = path.join(repoPath, 'README.md');
413
+ if (!await fs.pathExists(readmePath)) {
414
+ result.warnings.push('Missing README.md');
415
+ }
416
+
417
+ // Check if CONTRIBUTING.md exists
418
+ const contributingPath = path.join(repoPath, 'CONTRIBUTING.md');
419
+ if (!await fs.pathExists(contributingPath)) {
420
+ result.warnings.push('Missing CONTRIBUTING.md');
421
+ }
422
+
423
+ return result;
424
+ }
425
+
426
+ /**
427
+ * Gets repository version information
428
+ *
429
+ * @param {string} repoPath - Repository path
430
+ * @returns {Promise<Object>} Version info
431
+ */
432
+ async getRepoVersion(repoPath) {
433
+ if (!await this.isGitRepository(repoPath)) {
434
+ throw new GitError(
435
+ 'Not a Git repository',
436
+ { repoPath }
437
+ );
438
+ }
439
+
440
+ const commit = await this.getCurrentCommit(repoPath);
441
+ const branch = await this.getCurrentBranch(repoPath);
442
+ const tags = await this.getTags(repoPath);
443
+
444
+ // Find if current commit has a tag
445
+ let currentTag = null;
446
+ for (const tag of tags) {
447
+ try {
448
+ const tagCommit = execSync(`git rev-list -n 1 ${tag}`, {
449
+ cwd: repoPath,
450
+ encoding: 'utf8'
451
+ }).trim();
452
+
453
+ if (tagCommit === commit) {
454
+ currentTag = tag;
455
+ break;
456
+ }
457
+ } catch (error) {
458
+ // Ignore errors for individual tags
459
+ }
460
+ }
461
+
462
+ return {
463
+ commit,
464
+ branch,
465
+ tag: currentTag,
466
+ allTags: tags
467
+ };
468
+ }
469
+ }
470
+
471
+ module.exports = GitHandler;