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,285 @@
1
+ /**
2
+ * File Scanner
3
+ *
4
+ * Utility for scanning directories and detecting files based on patterns
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const { minimatch } = require('minimatch');
10
+
11
+ class FileScanner {
12
+ constructor(projectPath) {
13
+ this.projectPath = projectPath;
14
+ }
15
+
16
+ /**
17
+ * Find all markdown files in a directory (non-recursive)
18
+ *
19
+ * @param {string} dirPath - Directory path to scan
20
+ * @returns {Promise<string[]>} - Array of absolute file paths
21
+ */
22
+ async findMarkdownFiles(dirPath) {
23
+ try {
24
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
25
+ const mdFiles = [];
26
+
27
+ for (const entry of entries) {
28
+ if (entry.isFile() && entry.name.endsWith('.md')) {
29
+ mdFiles.push(path.join(dirPath, entry.name));
30
+ }
31
+ }
32
+
33
+ return mdFiles;
34
+ } catch (error) {
35
+ // If directory doesn't exist or can't be read, return empty array
36
+ return [];
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Find all markdown files in a directory recursively
42
+ *
43
+ * @param {string} dirPath - Directory path to scan
44
+ * @param {Object} options - Scan options
45
+ * @param {string[]} options.excludeDirs - Directory names to exclude (e.g., ['node_modules', '.git'])
46
+ * @returns {Promise<string[]>} - Array of absolute file paths
47
+ */
48
+ async findMarkdownFilesRecursive(dirPath, options = {}) {
49
+ const excludeDirs = options.excludeDirs || ['node_modules', '.git'];
50
+ const mdFiles = [];
51
+
52
+ try {
53
+ await this._scanRecursive(dirPath, mdFiles, excludeDirs);
54
+ return mdFiles;
55
+ } catch (error) {
56
+ // If directory doesn't exist or can't be read, return empty array
57
+ return [];
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Internal recursive scanning helper
63
+ *
64
+ * @private
65
+ */
66
+ async _scanRecursive(dirPath, results, excludeDirs) {
67
+ try {
68
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
69
+
70
+ for (const entry of entries) {
71
+ const fullPath = path.join(dirPath, entry.name);
72
+
73
+ if (entry.isDirectory()) {
74
+ // Skip excluded directories
75
+ if (!excludeDirs.includes(entry.name) && !entry.name.startsWith('.')) {
76
+ await this._scanRecursive(fullPath, results, excludeDirs);
77
+ }
78
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
79
+ results.push(fullPath);
80
+ }
81
+ }
82
+ } catch (error) {
83
+ // Skip directories that can't be read
84
+ return;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Match files against glob patterns
90
+ *
91
+ * @param {string[]} filePaths - Array of file paths to check
92
+ * @param {string[]} patterns - Array of glob patterns (e.g., ['*-SUMMARY.md', 'TEMP-*.md'])
93
+ * @returns {string[]} - Array of matching file paths
94
+ */
95
+ matchPatterns(filePaths, patterns) {
96
+ const matches = [];
97
+
98
+ for (const filePath of filePaths) {
99
+ const basename = path.basename(filePath);
100
+
101
+ for (const pattern of patterns) {
102
+ if (minimatch(basename, pattern, { nocase: false })) {
103
+ matches.push(filePath);
104
+ break; // Don't add the same file multiple times
105
+ }
106
+ }
107
+ }
108
+
109
+ return matches;
110
+ }
111
+
112
+ /**
113
+ * Check if a file matches any of the given patterns
114
+ *
115
+ * @param {string} filePath - File path to check
116
+ * @param {string[]} patterns - Array of glob patterns
117
+ * @returns {boolean} - True if file matches any pattern
118
+ */
119
+ matchesPattern(filePath, patterns) {
120
+ const basename = path.basename(filePath);
121
+
122
+ for (const pattern of patterns) {
123
+ if (minimatch(basename, pattern, { nocase: false })) {
124
+ return true;
125
+ }
126
+ }
127
+
128
+ return false;
129
+ }
130
+
131
+ /**
132
+ * Find all Spec directories in the project
133
+ *
134
+ * @returns {Promise<string[]>} - Array of Spec directory paths
135
+ */
136
+ async findSpecDirectories() {
137
+ const specsPath = path.join(this.projectPath, '.kiro/specs');
138
+
139
+ try {
140
+ const entries = await fs.readdir(specsPath, { withFileTypes: true });
141
+ const specDirs = [];
142
+
143
+ for (const entry of entries) {
144
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
145
+ specDirs.push(path.join(specsPath, entry.name));
146
+ }
147
+ }
148
+
149
+ return specDirs;
150
+ } catch (error) {
151
+ // If .kiro/specs doesn't exist, return empty array
152
+ return [];
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Get Spec directory by name
158
+ *
159
+ * @param {string} specName - Spec name
160
+ * @returns {string} - Spec directory path
161
+ */
162
+ getSpecDirectory(specName) {
163
+ return path.join(this.projectPath, '.kiro/specs', specName);
164
+ }
165
+
166
+ /**
167
+ * Check if a path exists
168
+ *
169
+ * @param {string} filePath - Path to check
170
+ * @returns {Promise<boolean>} - True if path exists
171
+ */
172
+ async exists(filePath) {
173
+ return await fs.pathExists(filePath);
174
+ }
175
+
176
+ /**
177
+ * Check if a path is a directory
178
+ *
179
+ * @param {string} dirPath - Path to check
180
+ * @returns {Promise<boolean>} - True if path is a directory
181
+ */
182
+ async isDirectory(dirPath) {
183
+ try {
184
+ const stat = await fs.stat(dirPath);
185
+ return stat.isDirectory();
186
+ } catch (error) {
187
+ return false;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Check if a path is a file
193
+ *
194
+ * @param {string} filePath - Path to check
195
+ * @returns {Promise<boolean>} - True if path is a file
196
+ */
197
+ async isFile(filePath) {
198
+ try {
199
+ const stat = await fs.stat(filePath);
200
+ return stat.isFile();
201
+ } catch (error) {
202
+ return false;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Get all files in a directory (non-recursive)
208
+ *
209
+ * @param {string} dirPath - Directory path
210
+ * @returns {Promise<string[]>} - Array of file paths
211
+ */
212
+ async getFiles(dirPath) {
213
+ try {
214
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
215
+ const files = [];
216
+
217
+ for (const entry of entries) {
218
+ if (entry.isFile()) {
219
+ files.push(path.join(dirPath, entry.name));
220
+ }
221
+ }
222
+
223
+ return files;
224
+ } catch (error) {
225
+ return [];
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Get all subdirectories in a directory (non-recursive)
231
+ *
232
+ * @param {string} dirPath - Directory path
233
+ * @returns {Promise<string[]>} - Array of subdirectory paths
234
+ */
235
+ async getSubdirectories(dirPath) {
236
+ try {
237
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
238
+ const dirs = [];
239
+
240
+ for (const entry of entries) {
241
+ if (entry.isDirectory()) {
242
+ dirs.push(path.join(dirPath, entry.name));
243
+ }
244
+ }
245
+
246
+ return dirs;
247
+ } catch (error) {
248
+ return [];
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Normalize path for cross-platform compatibility
254
+ *
255
+ * @param {string} filePath - Path to normalize
256
+ * @returns {string} - Normalized path
257
+ */
258
+ normalizePath(filePath) {
259
+ // First replace all backslashes with forward slashes for consistency
260
+ // Then use path.normalize to get platform-specific separators
261
+ return path.normalize(filePath.replace(/\\/g, '/'));
262
+ }
263
+
264
+ /**
265
+ * Get relative path from project root
266
+ *
267
+ * @param {string} filePath - Absolute file path
268
+ * @returns {string} - Relative path from project root
269
+ */
270
+ getRelativePath(filePath) {
271
+ return path.relative(this.projectPath, filePath);
272
+ }
273
+
274
+ /**
275
+ * Get absolute path from relative path
276
+ *
277
+ * @param {string} relativePath - Relative path from project root
278
+ * @returns {string} - Absolute path
279
+ */
280
+ getAbsolutePath(relativePath) {
281
+ return path.join(this.projectPath, relativePath);
282
+ }
283
+ }
284
+
285
+ module.exports = FileScanner;
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Hooks Manager
3
+ *
4
+ * Manages Git hooks for document governance
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+
10
+ class HooksManager {
11
+ constructor(projectPath) {
12
+ this.projectPath = projectPath;
13
+ this.gitDir = path.join(projectPath, '.git');
14
+ this.hooksDir = path.join(this.gitDir, 'hooks');
15
+ this.preCommitPath = path.join(this.hooksDir, 'pre-commit');
16
+ this.backupPath = path.join(this.hooksDir, 'pre-commit.backup');
17
+
18
+ // Marker to identify our hook content
19
+ this.hookMarkerStart = '# BEGIN kiro-spec-engine document governance';
20
+ this.hookMarkerEnd = '# END kiro-spec-engine document governance';
21
+ }
22
+
23
+ /**
24
+ * Check if Git hooks are installed
25
+ *
26
+ * @returns {Promise<Object>}
27
+ */
28
+ async checkHooksInstalled() {
29
+ try {
30
+ // Check if .git directory exists
31
+ if (!await fs.pathExists(this.gitDir)) {
32
+ return {
33
+ installed: false,
34
+ reason: 'not_git_repo',
35
+ message: 'Not a Git repository'
36
+ };
37
+ }
38
+
39
+ // Check if hooks directory exists
40
+ if (!await fs.pathExists(this.hooksDir)) {
41
+ return {
42
+ installed: false,
43
+ reason: 'no_hooks_dir',
44
+ message: 'Git hooks directory does not exist'
45
+ };
46
+ }
47
+
48
+ // Check if pre-commit hook exists
49
+ if (!await fs.pathExists(this.preCommitPath)) {
50
+ return {
51
+ installed: false,
52
+ reason: 'no_hook',
53
+ message: 'Pre-commit hook not installed'
54
+ };
55
+ }
56
+
57
+ // Check if our hook content is present
58
+ const content = await fs.readFile(this.preCommitPath, 'utf8');
59
+ const hasOurHook = content.includes(this.hookMarkerStart);
60
+
61
+ return {
62
+ installed: hasOurHook,
63
+ reason: hasOurHook ? 'installed' : 'other_hook',
64
+ message: hasOurHook
65
+ ? 'Document governance hook is installed'
66
+ : 'Pre-commit hook exists but is not ours',
67
+ hasExistingHook: !hasOurHook
68
+ };
69
+ } catch (error) {
70
+ return {
71
+ installed: false,
72
+ reason: 'error',
73
+ message: `Error checking hooks: ${error.message}`,
74
+ error: error.message
75
+ };
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Install pre-commit hook
81
+ *
82
+ * @returns {Promise<Object>}
83
+ */
84
+ async installHooks() {
85
+ try {
86
+ // Check if .git directory exists
87
+ if (!await fs.pathExists(this.gitDir)) {
88
+ return {
89
+ success: false,
90
+ reason: 'not_git_repo',
91
+ message: 'Not a Git repository. Initialize Git first with: git init'
92
+ };
93
+ }
94
+
95
+ // Create hooks directory if it doesn't exist
96
+ if (!await fs.pathExists(this.hooksDir)) {
97
+ await fs.ensureDir(this.hooksDir);
98
+ }
99
+
100
+ // Check if pre-commit hook already exists
101
+ let existingContent = '';
102
+ let hasExistingHook = false;
103
+
104
+ if (await fs.pathExists(this.preCommitPath)) {
105
+ existingContent = await fs.readFile(this.preCommitPath, 'utf8');
106
+
107
+ // Check if our hook is already installed
108
+ if (existingContent.includes(this.hookMarkerStart)) {
109
+ return {
110
+ success: true,
111
+ reason: 'already_installed',
112
+ message: 'Document governance hook is already installed'
113
+ };
114
+ }
115
+
116
+ hasExistingHook = true;
117
+
118
+ // Backup existing hook
119
+ await fs.writeFile(this.backupPath, existingContent);
120
+ }
121
+
122
+ // Generate our hook content
123
+ const ourHookContent = this.generateHookContent();
124
+
125
+ // Combine with existing hook if present
126
+ let finalContent;
127
+ if (hasExistingHook) {
128
+ // Preserve existing hook and add ours
129
+ finalContent = this.combineHooks(existingContent, ourHookContent);
130
+ } else {
131
+ // Just use our hook with shebang
132
+ finalContent = `#!/bin/sh\n\n${ourHookContent}`;
133
+ }
134
+
135
+ // Write the hook file
136
+ await fs.writeFile(this.preCommitPath, finalContent);
137
+
138
+ // Make it executable (Unix-like systems)
139
+ if (process.platform !== 'win32') {
140
+ await fs.chmod(this.preCommitPath, 0o755);
141
+ }
142
+
143
+ return {
144
+ success: true,
145
+ reason: hasExistingHook ? 'installed_with_preservation' : 'installed',
146
+ message: hasExistingHook
147
+ ? 'Document governance hook installed. Existing hook preserved and backed up.'
148
+ : 'Document governance hook installed successfully.',
149
+ backupCreated: hasExistingHook
150
+ };
151
+ } catch (error) {
152
+ return {
153
+ success: false,
154
+ reason: 'error',
155
+ message: `Failed to install hooks: ${error.message}`,
156
+ error: error.message
157
+ };
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Uninstall pre-commit hook
163
+ *
164
+ * @returns {Promise<Object>}
165
+ */
166
+ async uninstallHooks() {
167
+ try {
168
+ // Check if hook exists
169
+ if (!await fs.pathExists(this.preCommitPath)) {
170
+ return {
171
+ success: true,
172
+ reason: 'not_installed',
173
+ message: 'Document governance hook is not installed'
174
+ };
175
+ }
176
+
177
+ // Read current hook content
178
+ const content = await fs.readFile(this.preCommitPath, 'utf8');
179
+
180
+ // Check if our hook is present
181
+ if (!content.includes(this.hookMarkerStart)) {
182
+ return {
183
+ success: false,
184
+ reason: 'not_our_hook',
185
+ message: 'Pre-commit hook exists but is not ours. Manual removal required.'
186
+ };
187
+ }
188
+
189
+ // Remove our hook content
190
+ const newContent = this.removeOurHook(content);
191
+
192
+ // If nothing left (or just shebang), remove the file
193
+ const trimmedContent = newContent.trim();
194
+ if (trimmedContent === '' || trimmedContent === '#!/bin/sh') {
195
+ await fs.remove(this.preCommitPath);
196
+
197
+ // Restore backup if it exists
198
+ if (await fs.pathExists(this.backupPath)) {
199
+ await fs.remove(this.backupPath);
200
+ }
201
+
202
+ return {
203
+ success: true,
204
+ reason: 'removed',
205
+ message: 'Document governance hook removed successfully.'
206
+ };
207
+ } else {
208
+ // Write back the remaining content
209
+ await fs.writeFile(this.preCommitPath, newContent);
210
+
211
+ return {
212
+ success: true,
213
+ reason: 'removed_preserved',
214
+ message: 'Document governance hook removed. Other hooks preserved.'
215
+ };
216
+ }
217
+ } catch (error) {
218
+ return {
219
+ success: false,
220
+ reason: 'error',
221
+ message: `Failed to uninstall hooks: ${error.message}`,
222
+ error: error.message
223
+ };
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Generate hook content
229
+ *
230
+ * @returns {string}
231
+ */
232
+ generateHookContent() {
233
+ // Use Node.js to run validation
234
+ // This works on both Windows and Unix-like systems
235
+ return `${this.hookMarkerStart}
236
+
237
+ # Run document governance validation
238
+ node -e "
239
+ const path = require('path');
240
+ const ConfigManager = require('./lib/governance/config-manager');
241
+ const ValidationEngine = require('./lib/governance/validation-engine');
242
+
243
+ (async () => {
244
+ try {
245
+ const projectPath = process.cwd();
246
+ const configManager = new ConfigManager(projectPath);
247
+ const config = await configManager.load();
248
+ const validator = new ValidationEngine(projectPath, config);
249
+
250
+ // Validate root directory and all specs
251
+ const report = await validator.validate({ all: true });
252
+
253
+ if (!report.valid) {
254
+ console.error('\\n❌ Document governance validation failed!\\n');
255
+ console.error('Found ' + report.errors.length + ' error(s):\\n');
256
+
257
+ report.errors.forEach(err => {
258
+ console.error(' • ' + err.path);
259
+ console.error(' ' + err.message);
260
+ console.error(' → ' + err.recommendation + '\\n');
261
+ });
262
+
263
+ console.error('Fix these issues before committing:');
264
+ console.error(' kse doctor --docs # Diagnose issues');
265
+ console.error(' kse cleanup # Remove temporary files');
266
+ console.error(' kse validate --all # Validate structure\\n');
267
+
268
+ process.exit(1);
269
+ }
270
+ } catch (error) {
271
+ console.error('Error running document validation:', error.message);
272
+ // Don't block commit on validation errors
273
+ process.exit(0);
274
+ }
275
+ })();
276
+ "
277
+
278
+ ${this.hookMarkerEnd}
279
+ `;
280
+ }
281
+
282
+ /**
283
+ * Combine existing hook with our hook
284
+ *
285
+ * @param {string} existingContent - Existing hook content
286
+ * @param {string} ourContent - Our hook content
287
+ * @returns {string}
288
+ */
289
+ combineHooks(existingContent, ourContent) {
290
+ // Ensure shebang is present
291
+ let combined = existingContent;
292
+
293
+ if (!combined.startsWith('#!/')) {
294
+ combined = '#!/bin/sh\n\n' + combined;
295
+ }
296
+
297
+ // Add our hook at the end
298
+ combined += '\n\n' + ourContent;
299
+
300
+ return combined;
301
+ }
302
+
303
+ /**
304
+ * Remove our hook from combined content
305
+ *
306
+ * @param {string} content - Hook content
307
+ * @returns {string}
308
+ */
309
+ removeOurHook(content) {
310
+ const startIndex = content.indexOf(this.hookMarkerStart);
311
+ const endIndex = content.indexOf(this.hookMarkerEnd);
312
+
313
+ if (startIndex === -1 || endIndex === -1) {
314
+ return content;
315
+ }
316
+
317
+ // Remove our hook section (including markers and newlines)
318
+ const before = content.substring(0, startIndex).trimEnd();
319
+ const after = content.substring(endIndex + this.hookMarkerEnd.length).trimStart();
320
+
321
+ if (before && after) {
322
+ return before + '\n\n' + after;
323
+ } else if (before) {
324
+ return before;
325
+ } else if (after) {
326
+ return after;
327
+ } else {
328
+ return '';
329
+ }
330
+ }
331
+ }
332
+
333
+ module.exports = HooksManager;