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,591 @@
1
+ /**
2
+ * Status Monitor — Orchestration State Tracker
3
+ *
4
+ * Parses Codex JSON Lines events, tracks per-Spec execution status,
5
+ * computes aggregate orchestration state, and synchronises progress
6
+ * to SpecLifecycleManager and ContextSyncManager.
7
+ *
8
+ * Requirements: 4.1 (maintain per-agent status), 4.2 (parse JSON Lines events),
9
+ * 4.3 (update SpecLifecycleManager on completion),
10
+ * 4.4 (update ContextSyncManager on completion),
11
+ * 4.5 (return summary report with statuses, progress, batch info)
12
+ */
13
+
14
+ const VALID_SPEC_STATUSES = new Set([
15
+ 'pending', 'running', 'completed', 'failed', 'timeout', 'skipped',
16
+ ]);
17
+
18
+ const VALID_ORCHESTRATION_STATUSES = new Set([
19
+ 'idle', 'running', 'completed', 'failed', 'stopped',
20
+ ]);
21
+
22
+ /**
23
+ * Maps Codex JSON Lines event types to internal handling.
24
+ * item.* events are matched by prefix.
25
+ * @type {Set<string>}
26
+ */
27
+ const KNOWN_EVENT_TYPES = new Set([
28
+ 'thread.started',
29
+ 'turn.started',
30
+ 'turn.completed',
31
+ 'error',
32
+ ]);
33
+
34
+ class StatusMonitor {
35
+ /**
36
+ * @param {import('../collab/spec-lifecycle-manager').SpecLifecycleManager} specLifecycleManager
37
+ * @param {import('../steering/context-sync-manager').ContextSyncManager} contextSyncManager
38
+ */
39
+ constructor(specLifecycleManager, contextSyncManager) {
40
+ this._specLifecycleManager = specLifecycleManager;
41
+ this._contextSyncManager = contextSyncManager;
42
+
43
+ /** @type {'idle'|'running'|'completed'|'failed'|'stopped'} */
44
+ this._orchestrationStatus = 'idle';
45
+ /** @type {string|null} */
46
+ this._startedAt = null;
47
+ /** @type {string|null} */
48
+ this._completedAt = null;
49
+ /** @type {number} */
50
+ this._currentBatch = 0;
51
+ /** @type {number} */
52
+ this._totalBatches = 0;
53
+
54
+ /**
55
+ * Per-Spec execution status.
56
+ * @type {Map<string, {status: string, batch: number, agentId: string|null, retryCount: number, error: string|null, turnCount: number}>}
57
+ */
58
+ this._specs = new Map();
59
+
60
+ /**
61
+ * Rate-limit telemetry summary.
62
+ * @type {{signalCount: number, retryCount: number, totalBackoffMs: number, lastSignalAt: string|null, lastSpecName: string|null, lastRetryCount: number, lastDelayMs: number, lastLaunchHoldMs: number, lastError: string|null, launchBudgetPerMinute: number|null, launchBudgetWindowMs: number|null, launchBudgetUsed: number, launchBudgetHoldCount: number, lastLaunchBudgetHoldMs: number, lastLaunchBudgetHoldAt: string|null}}
63
+ */
64
+ this._rateLimit = {
65
+ signalCount: 0,
66
+ retryCount: 0,
67
+ totalBackoffMs: 0,
68
+ lastSignalAt: null,
69
+ lastSpecName: null,
70
+ lastRetryCount: 0,
71
+ lastDelayMs: 0,
72
+ lastLaunchHoldMs: 0,
73
+ lastError: null,
74
+ launchBudgetPerMinute: null,
75
+ launchBudgetWindowMs: null,
76
+ launchBudgetUsed: 0,
77
+ launchBudgetHoldCount: 0,
78
+ lastLaunchBudgetHoldMs: 0,
79
+ lastLaunchBudgetHoldAt: null,
80
+ };
81
+
82
+ /**
83
+ * Parallelism telemetry summary.
84
+ * @type {{adaptive: boolean|null, maxParallel: number|null, effectiveMaxParallel: number|null, floor: number|null, throttledCount: number, recoveredCount: number, lastReason: string|null, lastThrottledAt: string|null, lastRecoveredAt: string|null}}
85
+ */
86
+ this._parallel = {
87
+ adaptive: null,
88
+ maxParallel: null,
89
+ effectiveMaxParallel: null,
90
+ floor: null,
91
+ throttledCount: 0,
92
+ recoveredCount: 0,
93
+ lastReason: null,
94
+ lastThrottledAt: null,
95
+ lastRecoveredAt: null,
96
+ };
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Public API
101
+ // ---------------------------------------------------------------------------
102
+
103
+ /**
104
+ * Register a Spec for tracking before execution begins.
105
+ *
106
+ * @param {string} specName
107
+ * @param {number} batch - Batch number this Spec belongs to
108
+ */
109
+ initSpec(specName, batch) {
110
+ this._specs.set(specName, {
111
+ status: 'pending',
112
+ batch: batch || 0,
113
+ agentId: null,
114
+ retryCount: 0,
115
+ error: null,
116
+ turnCount: 0,
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Update the execution status of a specific Spec.
122
+ *
123
+ * @param {string} specName
124
+ * @param {string} status - One of VALID_SPEC_STATUSES
125
+ * @param {string|null} [agentId=null]
126
+ * @param {string|null} [error=null]
127
+ */
128
+ updateSpecStatus(specName, status, agentId = null, error = null) {
129
+ const entry = this._specs.get(specName);
130
+ if (!entry) {
131
+ // Unknown spec — initialise on the fly
132
+ this._specs.set(specName, {
133
+ status: VALID_SPEC_STATUSES.has(status) ? status : 'pending',
134
+ batch: 0,
135
+ agentId,
136
+ retryCount: 0,
137
+ error,
138
+ turnCount: 0,
139
+ });
140
+ return;
141
+ }
142
+
143
+ if (VALID_SPEC_STATUSES.has(status)) {
144
+ entry.status = status;
145
+ }
146
+ if (agentId !== null && agentId !== undefined) {
147
+ entry.agentId = agentId;
148
+ }
149
+ if (error !== null && error !== undefined) {
150
+ entry.error = error;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Increment the retry count for a Spec.
156
+ *
157
+ * @param {string} specName
158
+ */
159
+ incrementRetry(specName) {
160
+ const entry = this._specs.get(specName);
161
+ if (entry) {
162
+ entry.retryCount++;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Record a rate-limit retry/backoff signal.
168
+ *
169
+ * @param {object} data
170
+ * @param {string} [data.specName]
171
+ * @param {number} [data.retryCount]
172
+ * @param {number} [data.retryDelayMs]
173
+ * @param {number} [data.launchHoldMs]
174
+ * @param {string} [data.error]
175
+ */
176
+ recordRateLimitEvent(data = {}) {
177
+ const delay = Number(data.retryDelayMs);
178
+ const retryCount = Number(data.retryCount);
179
+ const launchHoldMs = Number(data.launchHoldMs);
180
+
181
+ this._rateLimit.signalCount++;
182
+ this._rateLimit.retryCount++;
183
+ this._rateLimit.totalBackoffMs += Number.isFinite(delay) && delay > 0 ? Math.round(delay) : 0;
184
+ this._rateLimit.lastSignalAt = new Date().toISOString();
185
+
186
+ if (typeof data.specName === 'string' && data.specName.trim()) {
187
+ this._rateLimit.lastSpecName = data.specName.trim();
188
+ }
189
+ if (Number.isFinite(retryCount) && retryCount >= 0) {
190
+ this._rateLimit.lastRetryCount = Math.floor(retryCount);
191
+ }
192
+ this._rateLimit.lastDelayMs = Number.isFinite(delay) && delay > 0 ? Math.round(delay) : 0;
193
+ this._rateLimit.lastLaunchHoldMs = Number.isFinite(launchHoldMs) && launchHoldMs >= 0
194
+ ? Math.round(launchHoldMs)
195
+ : 0;
196
+ if (data.error !== undefined && data.error !== null) {
197
+ this._rateLimit.lastError = `${data.error}`;
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Update launch-budget telemetry.
203
+ *
204
+ * @param {object} data
205
+ * @param {'hold'} [data.event]
206
+ * @param {number} [data.budgetPerMinute]
207
+ * @param {number} [data.windowMs]
208
+ * @param {number} [data.used]
209
+ * @param {number} [data.holdMs]
210
+ */
211
+ updateLaunchBudgetTelemetry(data = {}) {
212
+ const budgetPerMinute = Number(data.budgetPerMinute);
213
+ const windowMs = Number(data.windowMs);
214
+ const used = Number(data.used);
215
+ const holdMs = Number(data.holdMs);
216
+
217
+ if (Number.isFinite(budgetPerMinute) && budgetPerMinute >= 0) {
218
+ this._rateLimit.launchBudgetPerMinute = Math.floor(budgetPerMinute);
219
+ }
220
+ if (Number.isFinite(windowMs) && windowMs > 0) {
221
+ this._rateLimit.launchBudgetWindowMs = Math.round(windowMs);
222
+ }
223
+ if (Number.isFinite(used) && used >= 0) {
224
+ this._rateLimit.launchBudgetUsed = Math.floor(used);
225
+ }
226
+ this._rateLimit.lastLaunchBudgetHoldMs = Number.isFinite(holdMs) && holdMs >= 0
227
+ ? Math.round(holdMs)
228
+ : 0;
229
+ if (data.event === 'hold') {
230
+ this._rateLimit.launchBudgetHoldCount += 1;
231
+ this._rateLimit.lastLaunchBudgetHoldAt = new Date().toISOString();
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Update adaptive parallel telemetry.
237
+ *
238
+ * @param {object} data
239
+ * @param {'throttled'|'recovered'} [data.event]
240
+ * @param {string} [data.reason]
241
+ * @param {number} [data.maxParallel]
242
+ * @param {number} [data.effectiveMaxParallel]
243
+ * @param {number} [data.floor]
244
+ * @param {boolean} [data.adaptive]
245
+ */
246
+ updateParallelTelemetry(data = {}) {
247
+ if (typeof data.adaptive === 'boolean') {
248
+ this._parallel.adaptive = data.adaptive;
249
+ }
250
+
251
+ const maxParallel = Number(data.maxParallel);
252
+ if (Number.isFinite(maxParallel) && maxParallel > 0) {
253
+ this._parallel.maxParallel = Math.floor(maxParallel);
254
+ }
255
+
256
+ const effective = Number(data.effectiveMaxParallel);
257
+ if (Number.isFinite(effective) && effective > 0) {
258
+ this._parallel.effectiveMaxParallel = Math.floor(effective);
259
+ }
260
+
261
+ const floor = Number(data.floor);
262
+ if (Number.isFinite(floor) && floor > 0) {
263
+ this._parallel.floor = Math.floor(floor);
264
+ }
265
+
266
+ if (typeof data.reason === 'string' && data.reason.trim()) {
267
+ this._parallel.lastReason = data.reason.trim();
268
+ }
269
+
270
+ if (data.event === 'throttled') {
271
+ this._parallel.throttledCount++;
272
+ this._parallel.lastThrottledAt = new Date().toISOString();
273
+ } else if (data.event === 'recovered') {
274
+ this._parallel.recoveredCount++;
275
+ this._parallel.lastRecoveredAt = new Date().toISOString();
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Set the overall orchestration state.
281
+ *
282
+ * @param {'idle'|'running'|'completed'|'failed'|'stopped'} state
283
+ */
284
+ setOrchestrationState(state) {
285
+ if (!VALID_ORCHESTRATION_STATUSES.has(state)) {
286
+ return;
287
+ }
288
+ this._orchestrationStatus = state;
289
+
290
+ if (state === 'running' && !this._startedAt) {
291
+ this._startedAt = new Date().toISOString();
292
+ }
293
+ if (state === 'completed' || state === 'failed' || state === 'stopped') {
294
+ this._completedAt = new Date().toISOString();
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Set batch progress information.
300
+ *
301
+ * @param {number} current - Current batch index (1-based)
302
+ * @param {number} total - Total number of batches
303
+ */
304
+ setBatchInfo(current, total) {
305
+ this._currentBatch = typeof current === 'number' ? current : 0;
306
+ this._totalBatches = typeof total === 'number' ? total : 0;
307
+ }
308
+
309
+ /**
310
+ * Handle a Codex JSON Lines event for a specific agent.
311
+ * Gracefully handles invalid/malformed events — never throws.
312
+ *
313
+ * Supported event types:
314
+ * - thread.started: marks the agent's Spec as running
315
+ * - turn.started / turn.completed: tracks turn progress
316
+ * - item.*: generic item events (logged)
317
+ * - error: records error information
318
+ *
319
+ * @param {string} agentId
320
+ * @param {*} event - Parsed or raw event (string or object)
321
+ */
322
+ handleEvent(agentId, event) {
323
+ try {
324
+ const parsed = this._parseEvent(event);
325
+ if (!parsed) return;
326
+
327
+ // Find the Spec associated with this agentId
328
+ const specName = this._findSpecByAgentId(agentId);
329
+
330
+ this._processEvent(specName, agentId, parsed);
331
+ } catch (_err) {
332
+ // Graceful handling — never throw (Req 4.2)
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Return the full orchestration status report.
338
+ * Computes aggregate stats from the per-Spec map.
339
+ *
340
+ * @returns {object} OrchestrationStatus
341
+ */
342
+ getOrchestrationStatus() {
343
+ const specs = Object.create(null);
344
+ let completedSpecs = 0;
345
+ let failedSpecs = 0;
346
+ let runningSpecs = 0;
347
+
348
+ for (const [specName, entry] of this._specs) {
349
+ specs[specName] = {
350
+ status: entry.status,
351
+ batch: entry.batch,
352
+ agentId: entry.agentId,
353
+ retryCount: entry.retryCount,
354
+ error: entry.error,
355
+ };
356
+
357
+ if (entry.status === 'completed') completedSpecs++;
358
+ else if (entry.status === 'failed' || entry.status === 'timeout') failedSpecs++;
359
+ else if (entry.status === 'running') runningSpecs++;
360
+ }
361
+
362
+ return {
363
+ status: this._orchestrationStatus,
364
+ startedAt: this._startedAt,
365
+ completedAt: this._completedAt,
366
+ totalSpecs: this._specs.size,
367
+ completedSpecs,
368
+ failedSpecs,
369
+ runningSpecs,
370
+ currentBatch: this._currentBatch,
371
+ totalBatches: this._totalBatches,
372
+ specs,
373
+ rateLimit: { ...this._rateLimit },
374
+ parallel: { ...this._parallel },
375
+ };
376
+ }
377
+
378
+ /**
379
+ * Return the execution status of a specific Spec.
380
+ *
381
+ * @param {string} specName
382
+ * @returns {object|null} SpecExecutionStatus or null if not tracked
383
+ */
384
+ getSpecStatus(specName) {
385
+ const entry = this._specs.get(specName);
386
+ if (!entry) return null;
387
+
388
+ return {
389
+ status: entry.status,
390
+ batch: entry.batch,
391
+ agentId: entry.agentId,
392
+ retryCount: entry.retryCount,
393
+ error: entry.error,
394
+ };
395
+ }
396
+
397
+ /**
398
+ * Synchronise a Spec's completion status to external systems:
399
+ * - SpecLifecycleManager: transition Spec status
400
+ * - ContextSyncManager: update progress entry
401
+ *
402
+ * Failures are logged but do not propagate (non-fatal).
403
+ *
404
+ * @param {string} specName
405
+ * @param {string} status - 'completed' | 'failed' | 'timeout' etc.
406
+ * @returns {Promise<void>}
407
+ */
408
+ async syncExternalStatus(specName, status) {
409
+ // --- SpecLifecycleManager (Req 4.3) ---
410
+ if (this._specLifecycleManager) {
411
+ try {
412
+ const lifecycleStatus = this._mapToLifecycleStatus(status);
413
+ if (lifecycleStatus) {
414
+ await this._specLifecycleManager.transition(specName, lifecycleStatus);
415
+ }
416
+ } catch (err) {
417
+ console.warn(
418
+ `[StatusMonitor] Failed to update SpecLifecycleManager for ${specName}: ${err.message}`
419
+ );
420
+ }
421
+ }
422
+
423
+ // --- ContextSyncManager (Req 4.4) ---
424
+ if (this._contextSyncManager) {
425
+ try {
426
+ const progress = status === 'completed' ? 100 : 0;
427
+ const summary = this._buildProgressSummary(specName, status);
428
+ await this._contextSyncManager.updateSpecProgress(specName, {
429
+ status,
430
+ progress,
431
+ summary,
432
+ });
433
+ } catch (err) {
434
+ console.warn(
435
+ `[StatusMonitor] Failed to update ContextSyncManager for ${specName}: ${err.message}`
436
+ );
437
+ }
438
+ }
439
+ }
440
+
441
+ // ---------------------------------------------------------------------------
442
+ // Private helpers
443
+ // ---------------------------------------------------------------------------
444
+
445
+ /**
446
+ * Parse a raw event into a normalised object.
447
+ * Accepts both string (JSON) and pre-parsed objects.
448
+ * Returns null for invalid/unparseable input.
449
+ *
450
+ * @param {*} event
451
+ * @returns {object|null}
452
+ * @private
453
+ */
454
+ _parseEvent(event) {
455
+ if (!event) return null;
456
+
457
+ // Already an object
458
+ if (typeof event === 'object' && event !== null) {
459
+ return event.type ? event : null;
460
+ }
461
+
462
+ // String — attempt JSON parse
463
+ if (typeof event === 'string') {
464
+ try {
465
+ const parsed = JSON.parse(event);
466
+ return parsed && typeof parsed === 'object' && parsed.type ? parsed : null;
467
+ } catch (_err) {
468
+ return null;
469
+ }
470
+ }
471
+
472
+ return null;
473
+ }
474
+
475
+ /**
476
+ * Find the Spec name associated with a given agentId.
477
+ *
478
+ * @param {string} agentId
479
+ * @returns {string|null}
480
+ * @private
481
+ */
482
+ _findSpecByAgentId(agentId) {
483
+ for (const [specName, entry] of this._specs) {
484
+ if (entry.agentId === agentId) {
485
+ return specName;
486
+ }
487
+ }
488
+ return null;
489
+ }
490
+
491
+ /**
492
+ * Process a parsed event and update internal state.
493
+ *
494
+ * @param {string|null} specName
495
+ * @param {string} agentId
496
+ * @param {object} event
497
+ * @private
498
+ */
499
+ _processEvent(specName, agentId, event) {
500
+ const type = event.type;
501
+ if (!type || typeof type !== 'string') return;
502
+
503
+ if (type === 'thread.started') {
504
+ if (specName) {
505
+ this._updateEntryStatus(specName, 'running');
506
+ }
507
+ } else if (type === 'turn.started') {
508
+ // Track turn activity
509
+ if (specName) {
510
+ const entry = this._specs.get(specName);
511
+ if (entry) {
512
+ entry.turnCount++;
513
+ }
514
+ }
515
+ } else if (type === 'turn.completed') {
516
+ // Turn completed — no status change, just tracking
517
+ } else if (type === 'error') {
518
+ if (specName) {
519
+ const errorMsg = event.message || event.error || 'Unknown error';
520
+ const entry = this._specs.get(specName);
521
+ if (entry) {
522
+ entry.error = errorMsg;
523
+ }
524
+ }
525
+ } else if (type.startsWith('item.')) {
526
+ // item.* events — generic progress tracking, no status change
527
+ }
528
+ // Unknown event types are silently ignored
529
+ }
530
+
531
+ /**
532
+ * Update a Spec entry's status if the Spec is tracked.
533
+ *
534
+ * @param {string} specName
535
+ * @param {string} status
536
+ * @private
537
+ */
538
+ _updateEntryStatus(specName, status) {
539
+ const entry = this._specs.get(specName);
540
+ if (entry && VALID_SPEC_STATUSES.has(status)) {
541
+ entry.status = status;
542
+ }
543
+ }
544
+
545
+ /**
546
+ * Map an orchestrator status to a SpecLifecycleManager status.
547
+ * Returns null if no mapping exists.
548
+ *
549
+ * @param {string} status
550
+ * @returns {string|null}
551
+ * @private
552
+ */
553
+ _mapToLifecycleStatus(status) {
554
+ switch (status) {
555
+ case 'running':
556
+ return 'in-progress';
557
+ case 'completed':
558
+ return 'completed';
559
+ // failed/timeout/skipped have no direct lifecycle mapping
560
+ default:
561
+ return null;
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Build a human-readable progress summary for ContextSyncManager.
567
+ *
568
+ * @param {string} specName
569
+ * @param {string} status
570
+ * @returns {string}
571
+ * @private
572
+ */
573
+ _buildProgressSummary(specName, status) {
574
+ switch (status) {
575
+ case 'completed':
576
+ return `Spec ${specName} completed successfully`;
577
+ case 'failed':
578
+ return `Spec ${specName} failed`;
579
+ case 'timeout':
580
+ return `Spec ${specName} timed out`;
581
+ case 'skipped':
582
+ return `Spec ${specName} skipped (dependency failed)`;
583
+ case 'running':
584
+ return `Spec ${specName} in progress`;
585
+ default:
586
+ return `Spec ${specName}: ${status}`;
587
+ }
588
+ }
589
+ }
590
+
591
+ module.exports = { StatusMonitor, VALID_SPEC_STATUSES, VALID_ORCHESTRATION_STATUSES };