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,320 @@
1
+ const fs = require('fs').promises;
2
+ const path = require('path');
3
+
4
+ /**
5
+ * ContractManager handles interface contract definition and verification
6
+ */
7
+ class ContractManager {
8
+ constructor(workspaceRoot, metadataManager) {
9
+ this.workspaceRoot = workspaceRoot;
10
+ this.metadataManager = metadataManager;
11
+ this.specsDir = path.join(workspaceRoot, '.kiro', 'specs');
12
+ }
13
+
14
+ /**
15
+ * Define an interface contract for a spec
16
+ * @param {string} specName - Name of the spec
17
+ * @param {Object} contract - Contract definition
18
+ * @returns {Promise<void>}
19
+ */
20
+ async defineContract(specName, contract) {
21
+ // Validate contract structure
22
+ this._validateContract(contract);
23
+
24
+ const contractPath = this._getContractPath(specName, contract.interfaces[0].name);
25
+ const contractDir = path.dirname(contractPath);
26
+
27
+ // Ensure interfaces directory exists
28
+ await fs.mkdir(contractDir, { recursive: true });
29
+
30
+ // Write contract
31
+ const content = JSON.stringify(contract, null, 2);
32
+ await fs.writeFile(contractPath, content, 'utf8');
33
+
34
+ // Update metadata to include this interface
35
+ await this.metadataManager.atomicUpdate(specName, (metadata) => {
36
+ if (!metadata.interfaces) {
37
+ metadata.interfaces = { provides: [], consumes: [] };
38
+ }
39
+
40
+ const interfaceName = `${contract.interfaces[0].name}.json`;
41
+ if (!metadata.interfaces.provides.includes(interfaceName)) {
42
+ metadata.interfaces.provides.push(interfaceName);
43
+ }
44
+
45
+ return metadata;
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Read an interface contract
51
+ * @param {string} specName - Name of the spec
52
+ * @param {string} interfaceName - Name of the interface
53
+ * @returns {Promise<Object|null>} Contract or null if not found
54
+ */
55
+ async readContract(specName, interfaceName) {
56
+ const contractPath = this._getContractPath(specName, interfaceName);
57
+
58
+ try {
59
+ const content = await fs.readFile(contractPath, 'utf8');
60
+ return JSON.parse(content);
61
+ } catch (error) {
62
+ if (error.code === 'ENOENT') {
63
+ return null;
64
+ }
65
+ throw new Error(`Failed to read contract ${interfaceName} for ${specName}: ${error.message}`);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Verify that a spec's implementation matches its contracts
71
+ * @param {string} specName - Name of the spec
72
+ * @returns {Promise<Object>} Verification result
73
+ */
74
+ async verifyImplementation(specName) {
75
+ const metadata = await this.metadataManager.readMetadata(specName);
76
+
77
+ if (!metadata || !metadata.interfaces || !metadata.interfaces.provides) {
78
+ return {
79
+ valid: true,
80
+ message: 'No interfaces to verify'
81
+ };
82
+ }
83
+
84
+ const results = [];
85
+
86
+ for (const interfaceFile of metadata.interfaces.provides) {
87
+ const interfaceName = path.basename(interfaceFile, '.json');
88
+ const contract = await this.readContract(specName, interfaceName);
89
+
90
+ if (!contract) {
91
+ results.push({
92
+ interface: interfaceName,
93
+ valid: false,
94
+ error: 'Contract file not found'
95
+ });
96
+ continue;
97
+ }
98
+
99
+ // Try to verify implementation
100
+ const verification = await this._verifyJSImplementation(specName, contract);
101
+ results.push({
102
+ interface: interfaceName,
103
+ ...verification
104
+ });
105
+ }
106
+
107
+ const allValid = results.every(r => r.valid);
108
+
109
+ return {
110
+ valid: allValid,
111
+ results,
112
+ message: allValid ? 'All interfaces verified' : 'Some interfaces have mismatches'
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Verify JavaScript/TypeScript implementation against contract
118
+ * @param {string} specName - Name of the spec
119
+ * @param {Object} contract - Contract definition
120
+ * @returns {Promise<Object>} Verification result
121
+ */
122
+ async _verifyJSImplementation(specName, contract) {
123
+ const libPath = path.join(this.specsDir, specName, 'lib');
124
+
125
+ try {
126
+ // Check if lib directory exists
127
+ await fs.access(libPath);
128
+ } catch (error) {
129
+ return {
130
+ valid: false,
131
+ error: 'Implementation directory not found (lib/)',
132
+ mismatches: []
133
+ };
134
+ }
135
+
136
+ const mismatches = [];
137
+
138
+ for (const interfaceDef of contract.interfaces) {
139
+ // Try to find the implementation file
140
+ const possibleFiles = [
141
+ path.join(libPath, `${interfaceDef.name.toLowerCase()}.js`),
142
+ path.join(libPath, `${this._kebabCase(interfaceDef.name)}.js`),
143
+ path.join(libPath, 'index.js')
144
+ ];
145
+
146
+ let implementationFound = false;
147
+ let implementationContent = '';
148
+
149
+ for (const filePath of possibleFiles) {
150
+ try {
151
+ implementationContent = await fs.readFile(filePath, 'utf8');
152
+ implementationFound = true;
153
+ break;
154
+ } catch (error) {
155
+ // Try next file
156
+ }
157
+ }
158
+
159
+ if (!implementationFound) {
160
+ mismatches.push({
161
+ type: 'missing-implementation',
162
+ interface: interfaceDef.name,
163
+ message: `Implementation file not found`
164
+ });
165
+ continue;
166
+ }
167
+
168
+ // Check for exported members
169
+ for (const exportDef of interfaceDef.exports) {
170
+ if (exportDef.required) {
171
+ // Simple check: look for the export name in the file
172
+ const exportPattern = new RegExp(`(module\\.exports\\s*=|exports\\.${exportDef.name}|export\\s+(function|class|const)\\s+${exportDef.name})`, 'i');
173
+
174
+ if (!exportPattern.test(implementationContent)) {
175
+ mismatches.push({
176
+ type: 'missing-export',
177
+ interface: interfaceDef.name,
178
+ export: exportDef.name,
179
+ message: `Required export '${exportDef.name}' not found`
180
+ });
181
+ }
182
+ }
183
+ }
184
+ }
185
+
186
+ return {
187
+ valid: mismatches.length === 0,
188
+ mismatches
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Detect breaking changes between two contract versions
194
+ * @param {Object} oldContract - Old contract version
195
+ * @param {Object} newContract - New contract version
196
+ * @returns {Array<Object>} List of breaking changes
197
+ */
198
+ detectBreakingChanges(oldContract, newContract) {
199
+ const breakingChanges = [];
200
+
201
+ // Check for removed interfaces
202
+ for (const oldInterface of oldContract.interfaces) {
203
+ const newInterface = newContract.interfaces.find(i => i.name === oldInterface.name);
204
+
205
+ if (!newInterface) {
206
+ breakingChanges.push({
207
+ type: 'interface-removed',
208
+ interface: oldInterface.name,
209
+ message: `Interface '${oldInterface.name}' was removed`
210
+ });
211
+ continue;
212
+ }
213
+
214
+ // Check for removed exports
215
+ for (const oldExport of oldInterface.exports) {
216
+ if (oldExport.required) {
217
+ const newExport = newInterface.exports.find(e => e.name === oldExport.name);
218
+
219
+ if (!newExport) {
220
+ breakingChanges.push({
221
+ type: 'export-removed',
222
+ interface: oldInterface.name,
223
+ export: oldExport.name,
224
+ message: `Required export '${oldExport.name}' was removed`
225
+ });
226
+ } else if (oldExport.signature && newExport.signature && oldExport.signature !== newExport.signature) {
227
+ breakingChanges.push({
228
+ type: 'signature-changed',
229
+ interface: oldInterface.name,
230
+ export: oldExport.name,
231
+ oldSignature: oldExport.signature,
232
+ newSignature: newExport.signature,
233
+ message: `Signature changed for '${oldExport.name}'`
234
+ });
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ return breakingChanges;
241
+ }
242
+
243
+ /**
244
+ * Get all specs that consume a specific interface
245
+ * @param {string} providerSpec - Spec that provides the interface
246
+ * @param {string} interfaceName - Name of the interface
247
+ * @returns {Promise<Array<string>>} List of consumer spec names
248
+ */
249
+ async getConsumers(providerSpec, interfaceName) {
250
+ const allSpecs = await this.metadataManager.listAllMetadata();
251
+ const consumers = [];
252
+
253
+ const interfaceRef = `${providerSpec}/interfaces/${interfaceName}.json`;
254
+
255
+ for (const { name, metadata } of allSpecs) {
256
+ if (metadata.interfaces && metadata.interfaces.consumes) {
257
+ if (metadata.interfaces.consumes.includes(interfaceRef)) {
258
+ consumers.push(name);
259
+ }
260
+ }
261
+ }
262
+
263
+ return consumers;
264
+ }
265
+
266
+ /**
267
+ * Validate contract structure
268
+ * @param {Object} contract - Contract to validate
269
+ * @throws {Error} If contract is invalid
270
+ */
271
+ _validateContract(contract) {
272
+ if (!contract.version) {
273
+ throw new Error('Contract must have a version');
274
+ }
275
+
276
+ if (!contract.spec) {
277
+ throw new Error('Contract must specify the spec name');
278
+ }
279
+
280
+ if (!contract.interfaces || !Array.isArray(contract.interfaces)) {
281
+ throw new Error('Contract must have an interfaces array');
282
+ }
283
+
284
+ for (const interfaceDef of contract.interfaces) {
285
+ if (!interfaceDef.name) {
286
+ throw new Error('Each interface must have a name');
287
+ }
288
+
289
+ if (!interfaceDef.type || !['class', 'function', 'module', 'object'].includes(interfaceDef.type)) {
290
+ throw new Error(`Invalid interface type: ${interfaceDef.type}`);
291
+ }
292
+
293
+ if (!interfaceDef.exports || !Array.isArray(interfaceDef.exports)) {
294
+ throw new Error(`Interface ${interfaceDef.name} must have an exports array`);
295
+ }
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Get contract file path
301
+ * @param {string} specName - Name of the spec
302
+ * @param {string} interfaceName - Name of the interface
303
+ * @returns {string}
304
+ */
305
+ _getContractPath(specName, interfaceName) {
306
+ const fileName = interfaceName.endsWith('.json') ? interfaceName : `${interfaceName}.json`;
307
+ return path.join(this.specsDir, specName, 'interfaces', fileName);
308
+ }
309
+
310
+ /**
311
+ * Convert string to kebab-case
312
+ * @param {string} str
313
+ * @returns {string}
314
+ */
315
+ _kebabCase(str) {
316
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
317
+ }
318
+ }
319
+
320
+ module.exports = ContractManager;
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Coordinator - Optional central task assignment and progress tracking
3
+ *
4
+ * When coordinator mode is enabled (via MultiAgentConfig), provides:
5
+ * - Ready task computation based on task dependencies within a Spec
6
+ * - Task assignment to requesting Agents (unlocked + ready tasks)
7
+ * - Progress summary across all Specs and Agents
8
+ * - Coordination log persistence to coordination-log.json
9
+ *
10
+ * When coordinator mode is NOT enabled, all methods are no-ops (zero overhead).
11
+ *
12
+ * Task dependency model (within a single Spec's tasks.md):
13
+ * - A parent task (e.g. "4") depends on all its sub-tasks ("4.1", "4.2", …)
14
+ * - A task with no sub-tasks and no incomplete parent dependency is ready
15
+ * if its status is "not-started"
16
+ *
17
+ * Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6
18
+ */
19
+
20
+ const fs = require('fs').promises;
21
+ const path = require('path');
22
+ const fsUtils = require('../utils/fs-utils');
23
+ const { MultiAgentConfig } = require('./multi-agent-config');
24
+
25
+ const TaskClaimer = require('../task/task-claimer');
26
+
27
+ const CONFIG_DIR = '.kiro/config';
28
+ const SPECS_DIR = '.kiro/specs';
29
+ const LOG_FILENAME = 'coordination-log.json';
30
+
31
+ class Coordinator {
32
+ /**
33
+ * @param {string} workspaceRoot
34
+ * @param {import('./dependency-manager')} dependencyManager
35
+ * @param {import('./agent-registry').AgentRegistry} agentRegistry
36
+ * @param {import('../lock/task-lock-manager').TaskLockManager} taskLockManager
37
+ * @param {import('./spec-lifecycle-manager').SpecLifecycleManager} [specLifecycleManager]
38
+ * @param {import('./sync-barrier').SyncBarrier} [syncBarrier]
39
+ */
40
+ constructor(workspaceRoot, dependencyManager, agentRegistry, taskLockManager, specLifecycleManager, syncBarrier) {
41
+ this._workspaceRoot = workspaceRoot;
42
+ this._dependencyManager = dependencyManager;
43
+ this._agentRegistry = agentRegistry;
44
+ this._taskLockManager = taskLockManager;
45
+ this._specLifecycleManager = specLifecycleManager || null;
46
+ this._syncBarrier = syncBarrier || null;
47
+ this._multiAgentConfig = new MultiAgentConfig(workspaceRoot);
48
+ this._taskClaimer = new TaskClaimer();
49
+ this._specsDir = path.join(workspaceRoot, SPECS_DIR);
50
+ this._logPath = path.join(workspaceRoot, CONFIG_DIR, LOG_FILENAME);
51
+ this._configDir = path.join(workspaceRoot, CONFIG_DIR);
52
+ }
53
+
54
+
55
+ // ── Public API ─────────────────────────────────────────────────────
56
+
57
+ /**
58
+ * Get tasks that are ready to execute within a Spec.
59
+ *
60
+ * A task is "ready" when:
61
+ * 1. Its status is "not-started"
62
+ * 2. All of its sub-tasks (if any) are completed (parent depends on children)
63
+ * 3. It is not currently locked by any Agent
64
+ *
65
+ * Returns [] when coordinator is not enabled (Req 6.5).
66
+ *
67
+ * @param {string} specName
68
+ * @returns {Promise<Array<object>>} Ready tasks
69
+ */
70
+ async getReadyTasks(specName) {
71
+ const enabled = await this._multiAgentConfig.isCoordinatorEnabled();
72
+ if (!enabled) return [];
73
+
74
+ const tasks = await this._parseSpecTasks(specName);
75
+ if (!tasks || tasks.length === 0) return [];
76
+
77
+ const lockedTasks = await this._taskLockManager.listLockedTasks(specName);
78
+ const lockedIds = new Set(lockedTasks.map((t) => t.taskId));
79
+
80
+ const readyTasks = [];
81
+
82
+ for (const task of tasks) {
83
+ // Only consider not-started tasks
84
+ if (task.status !== 'not-started') continue;
85
+
86
+ // Skip locked tasks
87
+ if (lockedIds.has(task.taskId)) continue;
88
+
89
+ // Check if this is a parent task with sub-tasks
90
+ const subTasks = this._getSubTasks(tasks, task.taskId);
91
+ if (subTasks.length > 0) {
92
+ // Parent task: ready only when ALL sub-tasks are completed
93
+ const allSubsCompleted = subTasks.every((st) => st.status === 'completed');
94
+ if (!allSubsCompleted) continue;
95
+ }
96
+
97
+ // Check if this task's parent (if any) has other incomplete prerequisites
98
+ // A sub-task (e.g. "4.1") is ready if it has no further sub-tasks of its own
99
+ // and its own status is not-started (parent completion is handled above)
100
+
101
+ readyTasks.push(task);
102
+ }
103
+
104
+ return readyTasks;
105
+ }
106
+
107
+ /**
108
+ * Assign a ready, unlocked task to the requesting Agent.
109
+ *
110
+ * Picks the first available ready task across all Specs, locks it,
111
+ * and returns the assignment. Returns null if no tasks are available
112
+ * or coordinator is not enabled (Req 6.5).
113
+ *
114
+ * @param {string} agentId
115
+ * @returns {Promise<{specName: string, taskId: string, task: object}|null>}
116
+ */
117
+ async assignTask(agentId) {
118
+ const enabled = await this._multiAgentConfig.isCoordinatorEnabled();
119
+ if (!enabled) return null;
120
+
121
+ const specNames = await this._listSpecNames();
122
+
123
+ for (const specName of specNames) {
124
+ // SyncBarrier: check before accessing tasks for this Spec
125
+ if (this._syncBarrier) {
126
+ const switchResult = await this._syncBarrier.prepareSwitch(specName);
127
+ if (!switchResult.ready) {
128
+ console.warn(`[Coordinator] SyncBarrier: ${switchResult.error}`);
129
+ }
130
+ }
131
+
132
+ const readyTasks = await this.getReadyTasks(specName);
133
+ if (readyTasks.length === 0) continue;
134
+
135
+ // Pick the first ready task
136
+ const task = readyTasks[0];
137
+
138
+ // Attempt to lock it
139
+ const lockResult = await this._taskLockManager.acquireTaskLock(
140
+ specName,
141
+ task.taskId,
142
+ agentId,
143
+ { reason: 'coordinator-assignment' }
144
+ );
145
+
146
+ if (lockResult.success) {
147
+ await this.logAssignment(agentId, specName, task.taskId, 'assign');
148
+ return { specName, taskId: task.taskId, task };
149
+ }
150
+ // Lock failed (race condition) – try next task
151
+ }
152
+
153
+ return null;
154
+ }
155
+
156
+ /**
157
+ * Mark a task as completed and compute newly ready tasks.
158
+ *
159
+ * Returns { newReadyTasks: [] } when coordinator is not enabled (Req 6.5).
160
+ *
161
+ * @param {string} specName
162
+ * @param {string} taskId
163
+ * @param {string} agentId
164
+ * @returns {Promise<{newReadyTasks: Array<object>}>}
165
+ */
166
+ async completeTask(specName, taskId, agentId) {
167
+ const enabled = await this._multiAgentConfig.isCoordinatorEnabled();
168
+ if (!enabled) return { newReadyTasks: [] };
169
+
170
+ // Release the task lock
171
+ await this._taskLockManager.releaseTaskLock(specName, taskId, agentId);
172
+
173
+ // Log completion
174
+ await this.logAssignment(agentId, specName, taskId, 'complete');
175
+
176
+ // Compute newly ready tasks (tasks that became ready after this completion)
177
+ const newReadyTasks = await this.getReadyTasks(specName);
178
+
179
+ // Check if Spec is now fully completed
180
+ if (this._specLifecycleManager) {
181
+ await this._specLifecycleManager.checkCompletion(specName);
182
+ }
183
+
184
+ return { newReadyTasks };
185
+ }
186
+
187
+ /**
188
+ * Get progress summary across all Specs and Agents.
189
+ *
190
+ * Returns empty summary when coordinator is not enabled (Req 6.5).
191
+ *
192
+ * @returns {Promise<{specs: object, agents: object}>}
193
+ */
194
+ async getProgress() {
195
+ const enabled = await this._multiAgentConfig.isCoordinatorEnabled();
196
+ if (!enabled) return { specs: {}, agents: {} };
197
+
198
+ const specNames = await this._listSpecNames();
199
+ const specsProgress = {};
200
+
201
+ for (const specName of specNames) {
202
+ const tasks = await this._parseSpecTasks(specName);
203
+ if (!tasks || tasks.length === 0) continue;
204
+
205
+ let totalTasks = 0;
206
+ let completedTasks = 0;
207
+ let inProgressTasks = 0;
208
+
209
+ for (const task of tasks) {
210
+ totalTasks++;
211
+ if (task.status === 'completed') completedTasks++;
212
+ else if (task.status === 'in-progress') inProgressTasks++;
213
+ }
214
+
215
+ specsProgress[specName] = {
216
+ totalTasks,
217
+ completedTasks,
218
+ inProgressTasks,
219
+ percentage: totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0,
220
+ };
221
+ }
222
+
223
+ // Agent progress
224
+ const agentsProgress = {};
225
+ const activeAgents = await this._agentRegistry.getActiveAgents();
226
+
227
+ for (const agent of activeAgents) {
228
+ // Count completed tasks from the coordination log
229
+ const completedCount = await this._countAgentCompletions(agent.agentId);
230
+
231
+ agentsProgress[agent.agentId] = {
232
+ status: agent.status,
233
+ currentTask: agent.currentTask || null,
234
+ completedCount,
235
+ };
236
+ }
237
+
238
+ return { specs: specsProgress, agents: agentsProgress };
239
+ }
240
+
241
+ /**
242
+ * Persist a coordination log entry to coordination-log.json.
243
+ *
244
+ * No-op when coordinator is not enabled (Req 6.5).
245
+ *
246
+ * @param {string} agentId
247
+ * @param {string} specName
248
+ * @param {string} taskId
249
+ * @param {'assign'|'complete'|'release'|'timeout'} action
250
+ * @returns {Promise<void>}
251
+ */
252
+ async logAssignment(agentId, specName, taskId, action) {
253
+ const enabled = await this._multiAgentConfig.isCoordinatorEnabled();
254
+ if (!enabled) return;
255
+
256
+ const entry = {
257
+ timestamp: new Date().toISOString(),
258
+ agentId,
259
+ action,
260
+ specName,
261
+ taskId,
262
+ details: {},
263
+ };
264
+
265
+ await fsUtils.ensureDirectory(this._configDir);
266
+
267
+ let log = [];
268
+ try {
269
+ const exists = await fsUtils.pathExists(this._logPath);
270
+ if (exists) {
271
+ log = await fsUtils.readJSON(this._logPath);
272
+ if (!Array.isArray(log)) log = [];
273
+ }
274
+ } catch (_err) {
275
+ // Corrupted log – start fresh
276
+ log = [];
277
+ }
278
+
279
+ log.push(entry);
280
+ await fsUtils.writeJSON(this._logPath, log);
281
+ }
282
+
283
+ // ── Private helpers ────────────────────────────────────────────────
284
+
285
+ /**
286
+ * Parse tasks.md for a given Spec using TaskClaimer.
287
+ * @param {string} specName
288
+ * @returns {Promise<Array<object>|null>}
289
+ * @private
290
+ */
291
+ async _parseSpecTasks(specName) {
292
+ const tasksPath = path.join(this._specsDir, specName, 'tasks.md');
293
+ const exists = await fsUtils.pathExists(tasksPath);
294
+ if (!exists) return null;
295
+
296
+ try {
297
+ return await this._taskClaimer.parseTasks(tasksPath);
298
+ } catch (_err) {
299
+ return null;
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Get direct sub-tasks of a parent task.
305
+ * E.g. for parent "4", returns tasks "4.1", "4.2", etc.
306
+ * Does NOT return deeper descendants (e.g. "4.1.1").
307
+ *
308
+ * @param {Array<object>} tasks - All parsed tasks
309
+ * @param {string} parentId - Parent task ID (e.g. "4")
310
+ * @returns {Array<object>}
311
+ * @private
312
+ */
313
+ _getSubTasks(tasks, parentId) {
314
+ const prefix = parentId + '.';
315
+ return tasks.filter((t) => {
316
+ if (!t.taskId.startsWith(prefix)) return false;
317
+ // Only direct children: "4.1" is a child of "4", but "4.1.1" is not
318
+ const remainder = t.taskId.slice(prefix.length);
319
+ return /^\d+$/.test(remainder);
320
+ });
321
+ }
322
+
323
+ /**
324
+ * List all Spec directory names that contain a tasks.md file.
325
+ * @returns {Promise<string[]>}
326
+ * @private
327
+ */
328
+ async _listSpecNames() {
329
+ let entries;
330
+ try {
331
+ entries = await fs.readdir(this._specsDir, { withFileTypes: true });
332
+ } catch (err) {
333
+ if (err.code === 'ENOENT') return [];
334
+ throw err;
335
+ }
336
+
337
+ const specNames = [];
338
+ for (const entry of entries) {
339
+ if (!entry.isDirectory()) continue;
340
+ const tasksPath = path.join(this._specsDir, entry.name, 'tasks.md');
341
+ const exists = await fsUtils.pathExists(tasksPath);
342
+ if (exists) {
343
+ specNames.push(entry.name);
344
+ }
345
+ }
346
+ return specNames;
347
+ }
348
+
349
+ /**
350
+ * Count the number of 'complete' actions for an agent in the coordination log.
351
+ * @param {string} agentId
352
+ * @returns {Promise<number>}
353
+ * @private
354
+ */
355
+ async _countAgentCompletions(agentId) {
356
+ try {
357
+ const exists = await fsUtils.pathExists(this._logPath);
358
+ if (!exists) return 0;
359
+
360
+ const log = await fsUtils.readJSON(this._logPath);
361
+ if (!Array.isArray(log)) return 0;
362
+
363
+ return log.filter((e) => e.agentId === agentId && e.action === 'complete').length;
364
+ } catch (_err) {
365
+ return 0;
366
+ }
367
+ }
368
+ }
369
+
370
+ module.exports = { Coordinator };