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,181 @@
1
+ const simpleGit = require('simple-git');
2
+ const GitError = require('./errors/git-error');
3
+
4
+ /**
5
+ * GitOperations - Low-level Git operations wrapper around simple-git
6
+ *
7
+ * Provides a clean interface for Git operations with consistent error handling
8
+ * and cross-platform compatibility.
9
+ */
10
+ class GitOperations {
11
+ /**
12
+ * Create a simple-git instance for a repository
13
+ * @param {string} repoPath - Path to the Git repository
14
+ * @returns {SimpleGit} Configured simple-git instance
15
+ */
16
+ createGitInstance(repoPath) {
17
+ return simpleGit(repoPath);
18
+ }
19
+
20
+ /**
21
+ * Check if path is a valid Git repository
22
+ * @param {string} path - Path to check
23
+ * @returns {Promise<boolean>} True if path contains a valid Git repository
24
+ */
25
+ async isGitRepo(path) {
26
+ try {
27
+ const fs = require('fs').promises;
28
+ const pathModule = require('path');
29
+
30
+ // Check if .git directory exists
31
+ const gitDir = pathModule.join(path, '.git');
32
+ const stats = await fs.stat(gitDir);
33
+
34
+ // Verify it's a directory (not a file, which can occur in Git worktrees)
35
+ if (!stats.isDirectory()) {
36
+ return false;
37
+ }
38
+
39
+ // Optional: Verify with git command for additional validation
40
+ // This ensures the .git directory is valid and not corrupted
41
+ try {
42
+ const git = this.createGitInstance(path);
43
+ await git.revparse(['--git-dir']);
44
+ } catch (gitError) {
45
+ // .git directory exists but git command failed
46
+ // Still treat as repository since .git directory is the authoritative indicator
47
+ // This handles cases like corrupted repos that still have .git structure
48
+ }
49
+
50
+ return true;
51
+ } catch (error) {
52
+ // If we can't access .git directory (ENOENT, EACCES, etc.), it's not a repo
53
+ return false;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get repository status
59
+ * @param {string} repoPath - Path to the Git repository
60
+ * @returns {Promise<StatusSummary>} Status summary from simple-git
61
+ * @throws {GitError} If status retrieval fails
62
+ */
63
+ async getStatus(repoPath) {
64
+ try {
65
+ const git = this.createGitInstance(repoPath);
66
+ return await git.status();
67
+ } catch (error) {
68
+ throw new GitError(
69
+ `Failed to get status for repository at ${repoPath}`,
70
+ 'status',
71
+ null,
72
+ error.message
73
+ );
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Get current branch name
79
+ * @param {string} repoPath - Path to the Git repository
80
+ * @returns {Promise<string>} Current branch name
81
+ * @throws {GitError} If branch retrieval fails
82
+ */
83
+ async getCurrentBranch(repoPath) {
84
+ try {
85
+ const git = this.createGitInstance(repoPath);
86
+ const status = await git.status();
87
+ return status.current;
88
+ } catch (error) {
89
+ throw new GitError(
90
+ `Failed to get current branch for repository at ${repoPath}`,
91
+ 'branch',
92
+ null,
93
+ error.message
94
+ );
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Get remote URL
100
+ * @param {string} repoPath - Path to the Git repository
101
+ * @param {string} remoteName - Name of the remote (default: 'origin')
102
+ * @returns {Promise<string|null>} Remote URL or null if remote doesn't exist
103
+ * @throws {GitError} If remote retrieval fails
104
+ */
105
+ async getRemoteUrl(repoPath, remoteName = 'origin') {
106
+ try {
107
+ const git = this.createGitInstance(repoPath);
108
+ const remotes = await git.getRemotes(true);
109
+ const remote = remotes.find(r => r.name === remoteName);
110
+ return remote ? remote.refs.fetch : null;
111
+ } catch (error) {
112
+ throw new GitError(
113
+ `Failed to get remote URL for ${remoteName} in repository at ${repoPath}`,
114
+ 'remote',
115
+ null,
116
+ error.message
117
+ );
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Get all remotes
123
+ * @param {string} repoPath - Path to the Git repository
124
+ * @returns {Promise<Array<{name: string, refs: {fetch: string, push: string}}>>} Array of remotes
125
+ * @throws {GitError} If remotes retrieval fails
126
+ */
127
+ async getRemotes(repoPath) {
128
+ try {
129
+ const git = this.createGitInstance(repoPath);
130
+ return await git.getRemotes(true);
131
+ } catch (error) {
132
+ throw new GitError(
133
+ `Failed to get remotes for repository at ${repoPath}`,
134
+ 'remote',
135
+ null,
136
+ error.message
137
+ );
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Check if remote is reachable
143
+ * @param {string} repoPath - Path to the Git repository
144
+ * @param {string} remoteName - Name of the remote (default: 'origin')
145
+ * @returns {Promise<boolean>} True if remote is reachable
146
+ */
147
+ async isRemoteReachable(repoPath, remoteName = 'origin') {
148
+ try {
149
+ const git = this.createGitInstance(repoPath);
150
+ // Use ls-remote to check if remote is reachable
151
+ await git.listRemote([remoteName]);
152
+ return true;
153
+ } catch (error) {
154
+ return false;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Execute raw Git command
160
+ * @param {string} repoPath - Path to the Git repository
161
+ * @param {string[]} args - Git command arguments
162
+ * @returns {Promise<string>} Command output
163
+ * @throws {GitError} If command execution fails
164
+ */
165
+ async execRaw(repoPath, args) {
166
+ try {
167
+ const git = this.createGitInstance(repoPath);
168
+ const result = await git.raw(args);
169
+ return result;
170
+ } catch (error) {
171
+ throw new GitError(
172
+ `Failed to execute git command: git ${args.join(' ')}`,
173
+ `git ${args.join(' ')}`,
174
+ error.exitCode || null,
175
+ error.message
176
+ );
177
+ }
178
+ }
179
+ }
180
+
181
+ module.exports = GitOperations;
@@ -0,0 +1 @@
1
+ # Placeholder for command handlers
@@ -0,0 +1,155 @@
1
+ const RepoManager = require('../repo-manager');
2
+ const ConfigManager = require('../config-manager');
3
+ const OutputFormatter = require('../output-formatter');
4
+
5
+ /**
6
+ * ExecHandler - Handles batch command execution across repositories
7
+ *
8
+ * Executes Git commands across all configured repositories with
9
+ * support for dry-run mode and detailed result reporting.
10
+ */
11
+ class ExecHandler {
12
+ /**
13
+ * Create a new ExecHandler
14
+ * @param {string} projectRoot - The project root directory
15
+ */
16
+ constructor(projectRoot) {
17
+ this.projectRoot = projectRoot;
18
+ this.repoManager = new RepoManager(projectRoot);
19
+ this.configManager = new ConfigManager(projectRoot);
20
+ this.formatter = new OutputFormatter();
21
+ }
22
+
23
+ /**
24
+ * Execute command across repositories
25
+ * @param {string} command - Git command to execute (without 'git' prefix)
26
+ * @param {Object} options - Execution options
27
+ * @param {boolean} options.dryRun - Show commands without executing
28
+ * @returns {Promise<void>}
29
+ */
30
+ async execute(command, options = {}) {
31
+ const { dryRun = false } = options;
32
+
33
+ if (!command || command.trim().length === 0) {
34
+ console.log(this.formatter.error('Command is required'));
35
+ throw new Error('Command is required');
36
+ }
37
+
38
+ // Load configuration
39
+ let config;
40
+ try {
41
+ config = await this.configManager.loadConfig();
42
+ } catch (error) {
43
+ console.log(this.formatter.error(error.message));
44
+ throw error;
45
+ }
46
+
47
+ if (config.repositories.length === 0) {
48
+ console.log(this.formatter.warning('No repositories configured'));
49
+ return;
50
+ }
51
+
52
+ // Dry-run mode: just display what would be executed
53
+ if (dryRun) {
54
+ console.log(this.formatter.info('Dry-run mode: Commands that would be executed:'));
55
+ console.log('');
56
+ config.repositories.forEach(repo => {
57
+ console.log(`${this.formatter.info('Repository:')} ${repo.name} (${repo.path})`);
58
+ console.log(` Command: git ${command}`);
59
+ console.log('');
60
+ });
61
+ return;
62
+ }
63
+
64
+ // Execute command in all repositories
65
+ const progress = this.formatter.createProgress('Executing command...');
66
+ progress.start();
67
+
68
+ let results;
69
+ try {
70
+ results = await this.repoManager.execInAllRepos(config.repositories, command);
71
+ progress.stop();
72
+ } catch (error) {
73
+ progress.fail('Failed to execute command');
74
+ throw error;
75
+ }
76
+
77
+ // Display results
78
+ this.displayResults(results);
79
+
80
+ // Display summary
81
+ this.displaySummary(results);
82
+ }
83
+
84
+ /**
85
+ * Display execution results
86
+ * @param {Array<Object>} results - Array of execution results
87
+ */
88
+ displayResults(results) {
89
+ console.log('\n' + this.formatter.info('Execution Results'));
90
+ console.log('='.repeat(80));
91
+
92
+ results.forEach((result, index) => {
93
+ if (index > 0) {
94
+ console.log('\n' + '-'.repeat(80));
95
+ }
96
+
97
+ console.log(`\n${this.formatter.info('Repository:')} ${result.name} (${result.path})`);
98
+ console.log(`${this.formatter.info('Command:')} git ${result.command}`);
99
+
100
+ if (result.success) {
101
+ console.log(this.formatter.success('Status: Success'));
102
+ if (result.output && result.output.length > 0) {
103
+ console.log('\nOutput:');
104
+ console.log(result.output);
105
+ } else {
106
+ console.log(this.formatter.info('(No output)'));
107
+ }
108
+ } else {
109
+ console.log(this.formatter.error(`Status: Failed (exit code: ${result.exitCode})`));
110
+ if (result.error) {
111
+ console.log('\nError:');
112
+ console.log(this.formatter.error(result.error));
113
+ }
114
+ }
115
+ });
116
+
117
+ console.log('\n' + '='.repeat(80));
118
+ }
119
+
120
+ /**
121
+ * Display execution summary
122
+ * @param {Array<Object>} results - Array of execution results
123
+ */
124
+ displaySummary(results) {
125
+ const successCount = results.filter(r => r.success).length;
126
+ const failureCount = results.filter(r => !r.success).length;
127
+ const totalCount = results.length;
128
+
129
+ console.log('\n' + this.formatter.info('Summary'));
130
+ console.log(` Total repositories: ${totalCount}`);
131
+ console.log(` ${this.formatter.success(`Successful: ${successCount}`)}`);
132
+
133
+ if (failureCount > 0) {
134
+ console.log(` ${this.formatter.error(`Failed: ${failureCount}`)}`);
135
+
136
+ // List failed repositories
137
+ const failedRepos = results.filter(r => !r.success);
138
+ console.log('\nFailed repositories:');
139
+ failedRepos.forEach(result => {
140
+ console.log(` - ${result.name} (${result.path}): ${result.error}`);
141
+ });
142
+ }
143
+
144
+ // Display exit codes for failed commands
145
+ const failedWithExitCodes = results.filter(r => !r.success && r.exitCode !== 0);
146
+ if (failedWithExitCodes.length > 0) {
147
+ console.log('\nExit codes:');
148
+ failedWithExitCodes.forEach(result => {
149
+ console.log(` - ${result.name}: ${result.exitCode}`);
150
+ });
151
+ }
152
+ }
153
+ }
154
+
155
+ module.exports = ExecHandler;
@@ -0,0 +1,169 @@
1
+ const RepoManager = require('../repo-manager');
2
+ const ConfigManager = require('../config-manager');
3
+ const OutputFormatter = require('../output-formatter');
4
+
5
+ /**
6
+ * HealthHandler - Handles repository health check command
7
+ *
8
+ * Performs comprehensive health checks on all configured repositories
9
+ * including path validation, Git repository verification, remote
10
+ * reachability, and branch existence.
11
+ */
12
+ class HealthHandler {
13
+ /**
14
+ * Create a new HealthHandler
15
+ * @param {string} projectRoot - The project root directory
16
+ */
17
+ constructor(projectRoot) {
18
+ this.projectRoot = projectRoot;
19
+ this.repoManager = new RepoManager(projectRoot);
20
+ this.configManager = new ConfigManager(projectRoot);
21
+ this.formatter = new OutputFormatter();
22
+ }
23
+
24
+ /**
25
+ * Execute health check
26
+ * @param {Object} options - Health check options
27
+ * @returns {Promise<void>}
28
+ */
29
+ async execute(options = {}) {
30
+ // Load configuration
31
+ let config;
32
+ try {
33
+ config = await this.configManager.loadConfig();
34
+ } catch (error) {
35
+ console.log(this.formatter.error(error.message));
36
+ throw error;
37
+ }
38
+
39
+ if (config.repositories.length === 0) {
40
+ console.log(this.formatter.warning('No repositories configured'));
41
+ return;
42
+ }
43
+
44
+ // Perform health checks
45
+ const progress = this.formatter.createProgress('Performing health checks...');
46
+ progress.start();
47
+
48
+ let results;
49
+ try {
50
+ results = await this.repoManager.checkAllReposHealth(config.repositories);
51
+ progress.stop();
52
+ } catch (error) {
53
+ progress.fail('Failed to perform health checks');
54
+ throw error;
55
+ }
56
+
57
+ // Display results
58
+ this.displayResults(results);
59
+
60
+ // Display summary
61
+ this.displaySummary(results);
62
+ }
63
+
64
+ /**
65
+ * Display health check results
66
+ * @param {Array<Object>} results - Array of health check results
67
+ */
68
+ displayResults(results) {
69
+ console.log('\n' + this.formatter.info('Health Check Results'));
70
+ console.log('='.repeat(80));
71
+
72
+ results.forEach((result, index) => {
73
+ if (index > 0) {
74
+ console.log('\n' + '-'.repeat(80));
75
+ }
76
+
77
+ console.log(`\n${this.formatter.info('Repository:')} ${result.name} (${result.path})`);
78
+
79
+ // Overall health status
80
+ if (result.healthy) {
81
+ console.log(this.formatter.success('Status: Healthy ✓'));
82
+ } else {
83
+ console.log(this.formatter.error('Status: Unhealthy ✗'));
84
+ }
85
+
86
+ // Display individual checks
87
+ console.log('\nChecks:');
88
+ console.log(` Path exists: ${this._formatCheckResult(result.checks.pathExists)}`);
89
+ console.log(` Is Git repository: ${this._formatCheckResult(result.checks.isGitRepo)}`);
90
+
91
+ if (result.checks.remoteReachable !== null) {
92
+ console.log(` Remote reachable: ${this._formatCheckResult(result.checks.remoteReachable)}`);
93
+ }
94
+
95
+ if (result.checks.branchExists !== null) {
96
+ console.log(` Branch exists: ${this._formatCheckResult(result.checks.branchExists)}`);
97
+ }
98
+
99
+ // Display errors
100
+ if (result.errors.length > 0) {
101
+ console.log('\n' + this.formatter.error('Errors:'));
102
+ result.errors.forEach(error => {
103
+ console.log(` ${this.formatter.error('•')} ${error}`);
104
+ });
105
+ }
106
+
107
+ // Display warnings
108
+ if (result.warnings.length > 0) {
109
+ console.log('\n' + this.formatter.warning('Warnings:'));
110
+ result.warnings.forEach(warning => {
111
+ console.log(` ${this.formatter.warning('•')} ${warning}`);
112
+ });
113
+ }
114
+ });
115
+
116
+ console.log('\n' + '='.repeat(80));
117
+ }
118
+
119
+ /**
120
+ * Display health summary
121
+ * @param {Array<Object>} results - Array of health check results
122
+ */
123
+ displaySummary(results) {
124
+ const healthyCount = results.filter(r => r.healthy).length;
125
+ const unhealthyCount = results.filter(r => !r.healthy).length;
126
+ const totalCount = results.length;
127
+
128
+ console.log('\n' + this.formatter.info('Overall Health Summary'));
129
+ console.log(` Total repositories: ${totalCount}`);
130
+ console.log(` ${this.formatter.success(`Healthy: ${healthyCount}`)}`);
131
+
132
+ if (unhealthyCount > 0) {
133
+ console.log(` ${this.formatter.error(`Unhealthy: ${unhealthyCount}`)}`);
134
+
135
+ // List unhealthy repositories
136
+ const unhealthyRepos = results.filter(r => !r.healthy);
137
+ console.log('\nUnhealthy repositories:');
138
+ unhealthyRepos.forEach(result => {
139
+ const mainError = result.errors.length > 0 ? result.errors[0] : 'Unknown error';
140
+ console.log(` - ${result.name} (${result.path}): ${mainError}`);
141
+ });
142
+ } else {
143
+ console.log('\n' + this.formatter.success('All repositories are healthy! 🎉'));
144
+ }
145
+
146
+ // Display warning summary
147
+ const reposWithWarnings = results.filter(r => r.warnings.length > 0);
148
+ if (reposWithWarnings.length > 0) {
149
+ console.log('\n' + this.formatter.warning(`${reposWithWarnings.length} ${reposWithWarnings.length === 1 ? 'repository has' : 'repositories have'} warnings:`));
150
+ reposWithWarnings.forEach(result => {
151
+ console.log(` - ${result.name}: ${result.warnings.length} ${result.warnings.length === 1 ? 'warning' : 'warnings'}`);
152
+ });
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Format check result as colored string
158
+ * @private
159
+ * @param {boolean} passed - Whether the check passed
160
+ * @returns {string} Formatted check result
161
+ */
162
+ _formatCheckResult(passed) {
163
+ return passed
164
+ ? this.formatter.success('✓ Pass')
165
+ : this.formatter.error('✗ Fail');
166
+ }
167
+ }
168
+
169
+ module.exports = HealthHandler;
@@ -0,0 +1,197 @@
1
+ const readline = require('readline');
2
+ const RepoManager = require('../repo-manager');
3
+ const ConfigManager = require('../config-manager');
4
+ const OutputFormatter = require('../output-formatter');
5
+
6
+ /**
7
+ * InitHandler - Handles repository initialization command
8
+ *
9
+ * Scans the project directory for Git repositories and creates
10
+ * the project-repos.json configuration file.
11
+ */
12
+ class InitHandler {
13
+ /**
14
+ * Create a new InitHandler
15
+ * @param {string} projectRoot - The project root directory
16
+ */
17
+ constructor(projectRoot) {
18
+ this.projectRoot = projectRoot;
19
+ this.repoManager = new RepoManager(projectRoot);
20
+ this.configManager = new ConfigManager(projectRoot);
21
+ this.formatter = new OutputFormatter();
22
+ }
23
+
24
+ /**
25
+ * Execute repository initialization
26
+ * @param {Object} options - Initialization options
27
+ * @param {boolean} options.yes - Skip confirmation prompts
28
+ * @param {number} options.maxDepth - Maximum scan depth
29
+ * @param {string[]} options.exclude - Directories to exclude
30
+ * @param {boolean} options.nested - Enable nested repository scanning (default: true)
31
+ * @returns {Promise<Object>} Initialization result
32
+ */
33
+ async execute(options = {}) {
34
+ const { yes = false, maxDepth = 3, exclude = ['.kiro'], nested = true } = options;
35
+
36
+ // Check if configuration already exists
37
+ const configExists = await this.configManager.configExists();
38
+
39
+ if (configExists && !yes) {
40
+ const shouldOverwrite = await this.confirmOverwrite();
41
+ if (!shouldOverwrite) {
42
+ console.log(this.formatter.info('Initialization cancelled'));
43
+ return { cancelled: true, discovered: [], nestedMode: nested };
44
+ }
45
+ }
46
+
47
+ // Scan for repositories
48
+ const scanMode = nested ? 'nested' : 'non-nested';
49
+ const progress = this.formatter.createProgress(`Scanning for Git repositories (${scanMode} mode)...`);
50
+ progress.start();
51
+
52
+ let discovered;
53
+ try {
54
+ discovered = await this.repoManager.discoverRepositories(this.projectRoot, {
55
+ maxDepth,
56
+ exclude,
57
+ nested
58
+ });
59
+ progress.succeed(`Found ${discovered.length} Git ${discovered.length === 1 ? 'repository' : 'repositories'} (${scanMode} scanning)`);
60
+ } catch (error) {
61
+ progress.fail('Failed to scan for repositories');
62
+ throw error;
63
+ }
64
+
65
+ if (discovered.length === 0) {
66
+ console.log(this.formatter.warning('No Git repositories found in the project directory'));
67
+ return { cancelled: false, discovered: [], nestedMode: nested };
68
+ }
69
+
70
+ // Create configuration
71
+ const config = {
72
+ version: '1.0',
73
+ repositories: discovered.map(repo => ({
74
+ name: repo.name,
75
+ path: repo.path,
76
+ remote: repo.remote,
77
+ defaultBranch: repo.branch,
78
+ parent: repo.parent || null // Include parent field
79
+ })),
80
+ settings: {
81
+ nestedMode: nested // Store nested mode setting
82
+ }
83
+ };
84
+
85
+ // Save configuration
86
+ try {
87
+ await this.configManager.saveConfig(config);
88
+ } catch (error) {
89
+ console.log(this.formatter.error(`Failed to save configuration: ${error.message}`));
90
+
91
+ // Display detailed validation errors if available
92
+ if (error.details && error.details.errors && Array.isArray(error.details.errors)) {
93
+ console.log(this.formatter.error('\nValidation errors:'));
94
+ error.details.errors.forEach((err, index) => {
95
+ console.log(this.formatter.error(` ${index + 1}. ${err}`));
96
+ });
97
+ }
98
+
99
+ throw error;
100
+ }
101
+
102
+ // Display summary
103
+ this.displaySummary({ discovered, configPath: this.configManager.getConfigPath(), nestedMode: nested });
104
+
105
+ return { cancelled: false, discovered, nestedMode: nested };
106
+ }
107
+
108
+ /**
109
+ * Prompt user for confirmation if config exists
110
+ * @returns {Promise<boolean>} True if user confirms overwrite
111
+ */
112
+ async confirmOverwrite() {
113
+ const rl = readline.createInterface({
114
+ input: process.stdin,
115
+ output: process.stdout
116
+ });
117
+
118
+ return new Promise((resolve) => {
119
+ rl.question(
120
+ this.formatter.warning('Configuration file already exists. Overwrite? (y/N): '),
121
+ (answer) => {
122
+ rl.close();
123
+ const normalized = answer.trim().toLowerCase();
124
+ resolve(normalized === 'y' || normalized === 'yes');
125
+ }
126
+ );
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Display initialization summary
132
+ * @param {Object} result - Initialization result
133
+ * @param {Array} result.discovered - Discovered repositories
134
+ * @param {string} result.configPath - Configuration file path
135
+ * @param {boolean} result.nestedMode - Whether nested scanning was enabled
136
+ */
137
+ displaySummary(result) {
138
+ const { discovered, configPath, nestedMode } = result;
139
+
140
+ console.log('\n' + this.formatter.success('Repository configuration initialized'));
141
+ console.log(this.formatter.info(`Configuration saved to: ${configPath}`));
142
+ console.log(this.formatter.info(`Scan mode: ${nestedMode ? 'nested' : 'non-nested'}`));
143
+ console.log('\nDiscovered repositories:');
144
+
145
+ // Display table of discovered repositories with parent column
146
+ const hasNestedRepos = discovered.some(r => r.parent);
147
+ const headers = hasNestedRepos
148
+ ? ['Name', 'Path', 'Branch', 'Has Remote', 'Parent']
149
+ : ['Name', 'Path', 'Branch', 'Has Remote'];
150
+
151
+ const tableData = discovered.map(repo => {
152
+ const row = [
153
+ repo.name,
154
+ repo.path,
155
+ repo.branch,
156
+ repo.hasRemote ? '✓' : '✗'
157
+ ];
158
+ if (hasNestedRepos) {
159
+ row.push(repo.parent || '');
160
+ }
161
+ return row;
162
+ });
163
+
164
+ const table = this.formatter.formatTable([], {
165
+ head: headers,
166
+ rows: tableData
167
+ });
168
+
169
+ console.log(table);
170
+
171
+ // Display warnings for repos without remotes
172
+ const reposWithoutRemotes = discovered.filter(r => !r.hasRemote);
173
+ if (reposWithoutRemotes.length > 0) {
174
+ console.log('\n' + this.formatter.warning(
175
+ `${reposWithoutRemotes.length} ${reposWithoutRemotes.length === 1 ? 'repository' : 'repositories'} without remote URLs:`
176
+ ));
177
+ reposWithoutRemotes.forEach(repo => {
178
+ console.log(` - ${repo.name} (${repo.path})`);
179
+ });
180
+ }
181
+
182
+ // Display nested repository info
183
+ if (hasNestedRepos) {
184
+ const nestedRepos = discovered.filter(r => r.parent);
185
+ console.log('\n' + this.formatter.info(
186
+ `Found ${nestedRepos.length} nested ${nestedRepos.length === 1 ? 'repository' : 'repositories'}`
187
+ ));
188
+ }
189
+
190
+ console.log('\nNext steps:');
191
+ console.log(' • Run "kse repo status" to view repository status');
192
+ console.log(' • Run "kse repo health" to check repository health');
193
+ console.log(' • Run "kse repo exec <command>" to execute commands across all repos');
194
+ }
195
+ }
196
+
197
+ module.exports = InitHandler;