agentic-orchestrator 0.1.2 → 0.1.4

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 (300) hide show
  1. package/.claude/settings.local.json +15 -0
  2. package/CLAUDE.md +126 -0
  3. package/README.md +166 -25
  4. package/agentic/orchestrator/adapters.yaml +3 -0
  5. package/agentic/orchestrator/gates.yaml +47 -0
  6. package/agentic/orchestrator/policy.yaml +89 -0
  7. package/agentic/orchestrator/schemas/adapters.schema.json +12 -0
  8. package/agentic/orchestrator/schemas/gates.schema.json +6 -1
  9. package/agentic/orchestrator/schemas/index.schema.json +14 -0
  10. package/agentic/orchestrator/schemas/multi-project.schema.json +41 -0
  11. package/agentic/orchestrator/schemas/policy.schema.json +449 -52
  12. package/agentic/orchestrator/schemas/state.schema.json +16 -0
  13. package/agentic/orchestrator/tools/catalog.json +68 -0
  14. package/agentic/orchestrator/tools/schemas/input/cost.get.input.schema.json +10 -0
  15. package/agentic/orchestrator/tools/schemas/input/cost.record.input.schema.json +13 -0
  16. package/agentic/orchestrator/tools/schemas/input/feature.send_message.input.schema.json +11 -0
  17. package/agentic/orchestrator/tools/schemas/input/performance.get_analytics.input.schema.json +10 -0
  18. package/agentic/orchestrator/tools/schemas/input/performance.record_outcome.input.schema.json +18 -0
  19. package/agentic/orchestrator/tools/schemas/output/cost.get.output.schema.json +13 -0
  20. package/agentic/orchestrator/tools/schemas/output/cost.record.output.schema.json +13 -0
  21. package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +7 -0
  22. package/agentic/orchestrator/tools/schemas/output/feature.send_message.output.schema.json +23 -0
  23. package/agentic/orchestrator/tools/schemas/output/performance.get_analytics.output.schema.json +46 -0
  24. package/agentic/orchestrator/tools/schemas/output/performance.record_outcome.output.schema.json +10 -0
  25. package/agentic/orchestrator/tools.md +5 -0
  26. package/apps/control-plane/scripts/validate-architecture-rules.mjs +28 -2
  27. package/apps/control-plane/scripts/validate-docker-mcp-contract.mjs +12 -0
  28. package/apps/control-plane/scripts/validate-mcp-contracts.ts +92 -0
  29. package/apps/control-plane/src/application/adapters/adapter-registry.ts +169 -0
  30. package/apps/control-plane/src/application/multi-project-loader.ts +119 -0
  31. package/apps/control-plane/src/application/services/activity-monitor-service.ts +199 -0
  32. package/apps/control-plane/src/application/services/cost-tracking-service.ts +82 -0
  33. package/apps/control-plane/src/application/services/dependency-scheduler-service.ts +86 -0
  34. package/apps/control-plane/src/application/services/feature-deletion-service.ts +8 -7
  35. package/apps/control-plane/src/application/services/gate-interpolation-service.ts +15 -0
  36. package/apps/control-plane/src/application/services/gate-service.ts +38 -2
  37. package/apps/control-plane/src/application/services/instance-isolation-service.ts +18 -0
  38. package/apps/control-plane/src/application/services/issue-tracker-service.ts +469 -0
  39. package/apps/control-plane/src/application/services/merge-service.ts +67 -3
  40. package/apps/control-plane/src/application/services/notifier-service.ts +295 -0
  41. package/apps/control-plane/src/application/services/performance-analytics-service.ts +122 -0
  42. package/apps/control-plane/src/application/services/plan-service.ts +51 -0
  43. package/apps/control-plane/src/application/services/pr-monitor-service.ts +262 -0
  44. package/apps/control-plane/src/application/services/reactions-service.ts +175 -0
  45. package/apps/control-plane/src/application/services/reporting-service.ts +17 -2
  46. package/apps/control-plane/src/application/services/run-lease-service.ts +16 -38
  47. package/apps/control-plane/src/application/tools/tool-metadata.ts +4 -1
  48. package/apps/control-plane/src/cli/aop.ts +1 -1
  49. package/apps/control-plane/src/cli/attach-command-handler.ts +120 -0
  50. package/apps/control-plane/src/cli/cleanup-command-handler.ts +190 -0
  51. package/apps/control-plane/src/cli/cli-argument-parser.ts +69 -3
  52. package/apps/control-plane/src/cli/dashboard-command-handler.ts +57 -0
  53. package/apps/control-plane/src/cli/help-command-handler.ts +163 -0
  54. package/apps/control-plane/src/cli/init-command-handler.ts +609 -0
  55. package/apps/control-plane/src/cli/resume-command-handler.ts +1 -0
  56. package/apps/control-plane/src/cli/retry-command-handler.ts +138 -0
  57. package/apps/control-plane/src/cli/run-command-handler.ts +115 -3
  58. package/apps/control-plane/src/cli/send-command-handler.ts +65 -0
  59. package/apps/control-plane/src/cli/status-command-handler.ts +102 -2
  60. package/apps/control-plane/src/cli/types.ts +26 -1
  61. package/apps/control-plane/src/core/constants.ts +8 -2
  62. package/apps/control-plane/src/core/error-codes.ts +3 -1
  63. package/apps/control-plane/src/core/gates.ts +170 -50
  64. package/apps/control-plane/src/core/kernel.ts +280 -5
  65. package/apps/control-plane/src/core/path-layout.ts +12 -0
  66. package/apps/control-plane/src/core/tool-caller.ts +36 -0
  67. package/apps/control-plane/src/core/workspace-hooks.ts +87 -0
  68. package/apps/control-plane/src/interfaces/cli/bootstrap.ts +258 -9
  69. package/apps/control-plane/src/providers/providers.ts +235 -14
  70. package/apps/control-plane/src/supervisor/build-wave-executor.ts +129 -8
  71. package/apps/control-plane/src/supervisor/qa-wave-executor.ts +123 -5
  72. package/apps/control-plane/src/supervisor/run-coordinator.ts +143 -6
  73. package/apps/control-plane/src/supervisor/runtime.ts +135 -6
  74. package/apps/control-plane/src/supervisor/types.ts +12 -21
  75. package/apps/control-plane/src/supervisor/worker-decision-loop.ts +8 -0
  76. package/apps/control-plane/test/activity-monitor.spec.ts +294 -0
  77. package/apps/control-plane/test/adapter-registry.spec.ts +132 -0
  78. package/apps/control-plane/test/batch-operations.spec.ts +112 -0
  79. package/apps/control-plane/test/bootstrap-attach.spec.ts +102 -0
  80. package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +252 -0
  81. package/apps/control-plane/test/bootstrap.spec.ts +560 -0
  82. package/apps/control-plane/test/cleanup-command.spec.ts +301 -0
  83. package/apps/control-plane/test/cli-helpers.spec.ts +404 -1
  84. package/apps/control-plane/test/cli.unit.spec.ts +182 -1
  85. package/apps/control-plane/test/collision-queue.spec.ts +104 -1
  86. package/apps/control-plane/test/core-utils.spec.ts +175 -2
  87. package/apps/control-plane/test/cost-tracking.spec.ts +143 -0
  88. package/apps/control-plane/test/dashboard-api.integration.spec.ts +247 -0
  89. package/apps/control-plane/test/dashboard-client.spec.ts +116 -0
  90. package/apps/control-plane/test/dashboard-command.spec.ts +103 -0
  91. package/apps/control-plane/test/dependency-scheduler.spec.ts +189 -0
  92. package/apps/control-plane/test/epoch-tracking.spec.ts +4 -4
  93. package/apps/control-plane/test/feature-deletion-service.spec.ts +422 -0
  94. package/apps/control-plane/test/feature-lifecycle.spec.ts +202 -0
  95. package/apps/control-plane/test/git-spawn-error.spec.ts +24 -0
  96. package/apps/control-plane/test/incremental-gates.spec.ts +137 -0
  97. package/apps/control-plane/test/init-wizard.spec.ts +506 -0
  98. package/apps/control-plane/test/instance-isolation.spec.ts +83 -0
  99. package/apps/control-plane/test/issue-tracker.spec.ts +890 -0
  100. package/apps/control-plane/test/kernel.coverage.spec.ts +3 -5
  101. package/apps/control-plane/test/kernel.coverage2.spec.ts +871 -0
  102. package/apps/control-plane/test/kernel.spec.ts +13 -11
  103. package/apps/control-plane/test/lock-service.spec.ts +508 -0
  104. package/apps/control-plane/test/mcp-helpers.spec.ts +176 -0
  105. package/apps/control-plane/test/mcp.spec.ts +50 -15
  106. package/apps/control-plane/test/merge-service.spec.ts +67 -4
  107. package/apps/control-plane/test/multi-project.spec.ts +372 -0
  108. package/apps/control-plane/test/notifier-service.spec.ts +388 -0
  109. package/apps/control-plane/test/parallel-gates.spec.ts +312 -0
  110. package/apps/control-plane/test/patch-service.spec.ts +253 -0
  111. package/apps/control-plane/test/performance-analytics.spec.ts +338 -0
  112. package/apps/control-plane/test/planning-wave-executor.spec.ts +168 -0
  113. package/apps/control-plane/test/pr-monitor.spec.ts +385 -0
  114. package/apps/control-plane/test/providers.spec.ts +344 -1
  115. package/apps/control-plane/test/reactions.spec.ts +392 -0
  116. package/apps/control-plane/test/resume-command.spec.ts +390 -0
  117. package/apps/control-plane/test/run-coordinator.spec.ts +481 -2
  118. package/apps/control-plane/test/schema-date-time.spec.ts +46 -0
  119. package/apps/control-plane/test/service-retry-paths.spec.ts +30 -0
  120. package/apps/control-plane/test/services.spec.ts +95 -2
  121. package/apps/control-plane/test/session-management.spec.ts +450 -0
  122. package/apps/control-plane/test/spec-ingestion.spec.ts +190 -0
  123. package/apps/control-plane/test/supervisor-collaborators.spec.ts +699 -2
  124. package/apps/control-plane/test/supervisor.spec.ts +36 -30
  125. package/apps/control-plane/test/supervisor.unit.spec.ts +405 -0
  126. package/apps/control-plane/test/worker-decision-loop.spec.ts +57 -0
  127. package/apps/control-plane/test/workspace-hooks.spec.ts +177 -0
  128. package/apps/control-plane/vitest.config.ts +21 -5
  129. package/dist/apps/control-plane/application/adapters/adapter-registry.d.ts +44 -0
  130. package/dist/apps/control-plane/application/adapters/adapter-registry.js +76 -0
  131. package/dist/apps/control-plane/application/adapters/adapter-registry.js.map +1 -0
  132. package/dist/apps/control-plane/application/multi-project-loader.d.ts +31 -0
  133. package/dist/apps/control-plane/application/multi-project-loader.js +82 -0
  134. package/dist/apps/control-plane/application/multi-project-loader.js.map +1 -0
  135. package/dist/apps/control-plane/application/services/activity-monitor-service.d.ts +43 -0
  136. package/dist/apps/control-plane/application/services/activity-monitor-service.js +132 -0
  137. package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -0
  138. package/dist/apps/control-plane/application/services/cost-tracking-service.d.ts +28 -0
  139. package/dist/apps/control-plane/application/services/cost-tracking-service.js +48 -0
  140. package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -0
  141. package/dist/apps/control-plane/application/services/dependency-scheduler-service.d.ts +26 -0
  142. package/dist/apps/control-plane/application/services/dependency-scheduler-service.js +75 -0
  143. package/dist/apps/control-plane/application/services/dependency-scheduler-service.js.map +1 -0
  144. package/dist/apps/control-plane/application/services/feature-deletion-service.d.ts +2 -0
  145. package/dist/apps/control-plane/application/services/feature-deletion-service.js +6 -7
  146. package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
  147. package/dist/apps/control-plane/application/services/gate-interpolation-service.d.ts +7 -0
  148. package/dist/apps/control-plane/application/services/gate-interpolation-service.js +7 -0
  149. package/dist/apps/control-plane/application/services/gate-interpolation-service.js.map +1 -0
  150. package/dist/apps/control-plane/application/services/gate-service.js +32 -2
  151. package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
  152. package/dist/apps/control-plane/application/services/instance-isolation-service.d.ts +11 -0
  153. package/dist/apps/control-plane/application/services/instance-isolation-service.js +17 -0
  154. package/dist/apps/control-plane/application/services/instance-isolation-service.js.map +1 -0
  155. package/dist/apps/control-plane/application/services/issue-tracker-service.d.ts +65 -0
  156. package/dist/apps/control-plane/application/services/issue-tracker-service.js +358 -0
  157. package/dist/apps/control-plane/application/services/issue-tracker-service.js.map +1 -0
  158. package/dist/apps/control-plane/application/services/merge-service.d.ts +4 -0
  159. package/dist/apps/control-plane/application/services/merge-service.js +44 -2
  160. package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
  161. package/dist/apps/control-plane/application/services/notifier-service.d.ts +74 -0
  162. package/dist/apps/control-plane/application/services/notifier-service.js +212 -0
  163. package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -0
  164. package/dist/apps/control-plane/application/services/performance-analytics-service.d.ts +39 -0
  165. package/dist/apps/control-plane/application/services/performance-analytics-service.js +75 -0
  166. package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -0
  167. package/dist/apps/control-plane/application/services/plan-service.d.ts +1 -0
  168. package/dist/apps/control-plane/application/services/plan-service.js +53 -0
  169. package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
  170. package/dist/apps/control-plane/application/services/pr-monitor-service.d.ts +44 -0
  171. package/dist/apps/control-plane/application/services/pr-monitor-service.js +192 -0
  172. package/dist/apps/control-plane/application/services/pr-monitor-service.js.map +1 -0
  173. package/dist/apps/control-plane/application/services/reactions-service.d.ts +67 -0
  174. package/dist/apps/control-plane/application/services/reactions-service.js +114 -0
  175. package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -0
  176. package/dist/apps/control-plane/application/services/reporting-service.d.ts +1 -0
  177. package/dist/apps/control-plane/application/services/reporting-service.js +13 -2
  178. package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
  179. package/dist/apps/control-plane/application/services/run-lease-service.d.ts +2 -0
  180. package/dist/apps/control-plane/application/services/run-lease-service.js +14 -38
  181. package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
  182. package/dist/apps/control-plane/application/tools/tool-metadata.js +3 -1
  183. package/dist/apps/control-plane/application/tools/tool-metadata.js.map +1 -1
  184. package/dist/apps/control-plane/cli/aop.d.ts +1 -1
  185. package/dist/apps/control-plane/cli/aop.js +1 -1
  186. package/dist/apps/control-plane/cli/attach-command-handler.d.ts +12 -0
  187. package/dist/apps/control-plane/cli/attach-command-handler.js +98 -0
  188. package/dist/apps/control-plane/cli/attach-command-handler.js.map +1 -0
  189. package/dist/apps/control-plane/cli/cleanup-command-handler.d.ts +12 -0
  190. package/dist/apps/control-plane/cli/cleanup-command-handler.js +162 -0
  191. package/dist/apps/control-plane/cli/cleanup-command-handler.js.map +1 -0
  192. package/dist/apps/control-plane/cli/cli-argument-parser.js +73 -3
  193. package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
  194. package/dist/apps/control-plane/cli/dashboard-command-handler.d.ts +7 -0
  195. package/dist/apps/control-plane/cli/dashboard-command-handler.js +45 -0
  196. package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -0
  197. package/dist/apps/control-plane/cli/help-command-handler.d.ts +8 -0
  198. package/dist/apps/control-plane/cli/help-command-handler.js +146 -0
  199. package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -0
  200. package/dist/apps/control-plane/cli/init-command-handler.d.ts +26 -0
  201. package/dist/apps/control-plane/cli/init-command-handler.js +517 -0
  202. package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -0
  203. package/dist/apps/control-plane/cli/resume-command-handler.js +1 -1
  204. package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
  205. package/dist/apps/control-plane/cli/retry-command-handler.d.ts +8 -0
  206. package/dist/apps/control-plane/cli/retry-command-handler.js +111 -0
  207. package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -0
  208. package/dist/apps/control-plane/cli/run-command-handler.d.ts +5 -0
  209. package/dist/apps/control-plane/cli/run-command-handler.js +82 -3
  210. package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
  211. package/dist/apps/control-plane/cli/send-command-handler.d.ts +8 -0
  212. package/dist/apps/control-plane/cli/send-command-handler.js +55 -0
  213. package/dist/apps/control-plane/cli/send-command-handler.js.map +1 -0
  214. package/dist/apps/control-plane/cli/status-command-handler.d.ts +12 -1
  215. package/dist/apps/control-plane/cli/status-command-handler.js +55 -2
  216. package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
  217. package/dist/apps/control-plane/cli/types.d.ts +26 -1
  218. package/dist/apps/control-plane/cli/types.js +15 -1
  219. package/dist/apps/control-plane/cli/types.js.map +1 -1
  220. package/dist/apps/control-plane/core/constants.d.ts +6 -0
  221. package/dist/apps/control-plane/core/constants.js +8 -2
  222. package/dist/apps/control-plane/core/constants.js.map +1 -1
  223. package/dist/apps/control-plane/core/error-codes.d.ts +2 -0
  224. package/dist/apps/control-plane/core/error-codes.js +3 -1
  225. package/dist/apps/control-plane/core/error-codes.js.map +1 -1
  226. package/dist/apps/control-plane/core/gates.d.ts +4 -0
  227. package/dist/apps/control-plane/core/gates.js +140 -43
  228. package/dist/apps/control-plane/core/gates.js.map +1 -1
  229. package/dist/apps/control-plane/core/kernel.d.ts +50 -1
  230. package/dist/apps/control-plane/core/kernel.js +220 -7
  231. package/dist/apps/control-plane/core/kernel.js.map +1 -1
  232. package/dist/apps/control-plane/core/path-layout.d.ts +3 -0
  233. package/dist/apps/control-plane/core/path-layout.js +9 -0
  234. package/dist/apps/control-plane/core/path-layout.js.map +1 -1
  235. package/dist/apps/control-plane/core/tool-caller.d.ts +32 -0
  236. package/dist/apps/control-plane/core/tool-caller.js +2 -0
  237. package/dist/apps/control-plane/core/tool-caller.js.map +1 -0
  238. package/dist/apps/control-plane/core/workspace-hooks.d.ts +20 -0
  239. package/dist/apps/control-plane/core/workspace-hooks.js +69 -0
  240. package/dist/apps/control-plane/core/workspace-hooks.js.map +1 -0
  241. package/dist/apps/control-plane/interfaces/cli/bootstrap.js +245 -9
  242. package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
  243. package/dist/apps/control-plane/providers/providers.d.ts +42 -3
  244. package/dist/apps/control-plane/providers/providers.js +216 -5
  245. package/dist/apps/control-plane/providers/providers.js.map +1 -1
  246. package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +3 -0
  247. package/dist/apps/control-plane/supervisor/build-wave-executor.js +115 -6
  248. package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
  249. package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +3 -0
  250. package/dist/apps/control-plane/supervisor/qa-wave-executor.js +109 -5
  251. package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
  252. package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +15 -0
  253. package/dist/apps/control-plane/supervisor/run-coordinator.js +132 -6
  254. package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
  255. package/dist/apps/control-plane/supervisor/runtime.d.ts +3 -0
  256. package/dist/apps/control-plane/supervisor/runtime.js +110 -6
  257. package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
  258. package/dist/apps/control-plane/supervisor/types.d.ts +9 -16
  259. package/dist/apps/control-plane/supervisor/types.js.map +1 -1
  260. package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +3 -0
  261. package/dist/apps/control-plane/supervisor/worker-decision-loop.js +5 -0
  262. package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
  263. package/eslint.config.mjs +2 -1
  264. package/package.json +12 -2
  265. package/packages/web-dashboard/next-env.d.ts +5 -0
  266. package/packages/web-dashboard/next.config.js +7 -0
  267. package/packages/web-dashboard/package.json +26 -0
  268. package/packages/web-dashboard/src/app/api/actions/route.ts +64 -0
  269. package/packages/web-dashboard/src/app/api/events/route.ts +51 -0
  270. package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +256 -0
  271. package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +10 -0
  272. package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +25 -0
  273. package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +63 -0
  274. package/packages/web-dashboard/src/app/api/features/[id]/route.ts +16 -0
  275. package/packages/web-dashboard/src/app/api/projects/route.ts +31 -0
  276. package/packages/web-dashboard/src/app/api/status/route.ts +15 -0
  277. package/packages/web-dashboard/src/app/globals.css +2 -0
  278. package/packages/web-dashboard/src/app/layout.tsx +15 -0
  279. package/packages/web-dashboard/src/app/page.tsx +393 -0
  280. package/packages/web-dashboard/src/lib/aop-client.ts +244 -0
  281. package/packages/web-dashboard/src/lib/multi-project-config.ts +116 -0
  282. package/packages/web-dashboard/src/lib/orchestrator-tools.ts +284 -0
  283. package/packages/web-dashboard/src/lib/types.ts +58 -0
  284. package/packages/web-dashboard/tsconfig.json +40 -0
  285. package/packages/web-dashboard/vitest.config.ts +6 -0
  286. package/spec-files/completed/agentic_orchestrator_feature_gaps_closure_spec.md +1764 -0
  287. package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +348 -0
  288. package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +344 -0
  289. package/spec-files/outstanding/agentic_orchestrator_observability_integrity_diagnostics_spec.md +374 -0
  290. package/spec-files/outstanding/agentic_orchestrator_performance_improvements_spec.md +1059 -0
  291. package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +466 -0
  292. package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +198 -0
  293. package/spec-files/outstanding/agentic_orchestrator_validator_hardening_spec.md +365 -0
  294. package/spec-files/progress.md +481 -52
  295. /package/spec-files/{agentic_orchestrator_cli_delete_command_spec.md → completed/agentic_orchestrator_cli_delete_command_spec.md} +0 -0
  296. /package/spec-files/{agentic_orchestrator_dot_aop_generated_artifacts_spec.md → completed/agentic_orchestrator_dot_aop_generated_artifacts_spec.md} +0 -0
  297. /package/spec-files/{agentic_orchestrator_mcp_formalization_spec.md → completed/agentic_orchestrator_mcp_formalization_spec.md} +0 -0
  298. /package/spec-files/{agentic_orchestrator_oop_refactor_spec.md → completed/agentic_orchestrator_oop_refactor_spec.md} +0 -0
  299. /package/spec-files/{agentic_orchestrator_single_global_orchestrator_spec.md → completed/agentic_orchestrator_single_global_orchestrator_spec.md} +0 -0
  300. /package/spec-files/{agentic_orchestrator_spec.md → completed/agentic_orchestrator_spec.md} +0 -0
@@ -0,0 +1,120 @@
1
+ import { ERROR_CODES } from '../core/error-codes.js';
2
+ import { STATUS, TOOLS } from '../core/constants.js';
3
+ import type { AppError, WorkerProvider } from '../providers/providers.js';
4
+ import type { AopKernel } from '../core/kernel.js';
5
+ import type { ToolClient } from '../mcp/tool-client.js';
6
+ import type { CliOptions } from './types.js';
7
+ import { callCliTool } from './tooling.js';
8
+
9
+ interface FeatureStatePayload {
10
+ front_matter: {
11
+ status: string;
12
+ };
13
+ }
14
+
15
+ function isValidFeatureId(value: string): boolean {
16
+ return /^[a-z0-9_][a-z0-9_-]*$/.test(value);
17
+ }
18
+
19
+ function invalidCliArgs(details: Record<string, unknown>): never {
20
+ const error = new Error(ERROR_CODES.INVALID_CLI_ARGS) as AppError;
21
+ error.code = ERROR_CODES.INVALID_CLI_ARGS;
22
+ error.details = details;
23
+ throw error;
24
+ }
25
+
26
+ function selectSessionRole(status: string): 'planner' | 'builder' | 'qa' {
27
+ if (status === STATUS.PLANNING) {
28
+ return 'planner';
29
+ }
30
+ if (status === STATUS.BUILDING) {
31
+ return 'builder';
32
+ }
33
+ return 'qa';
34
+ }
35
+
36
+ export class AttachCommandHandler {
37
+ private readonly toolClient: ToolClient;
38
+ private readonly runId: string;
39
+ private readonly kernel: AopKernel;
40
+ private readonly provider: WorkerProvider;
41
+
42
+ constructor(toolClient: ToolClient, runId: string, kernel: AopKernel, provider: WorkerProvider) {
43
+ this.toolClient = toolClient;
44
+ this.runId = runId;
45
+ this.kernel = kernel;
46
+ this.provider = provider;
47
+ }
48
+
49
+ async execute(options: CliOptions): Promise<unknown> {
50
+ const featureId = options.feature_id;
51
+ if (!featureId) {
52
+ invalidCliArgs({
53
+ reason: '<feature_id> is required for attach',
54
+ expected: 'aop attach <feature_id>'
55
+ });
56
+ }
57
+ if (!isValidFeatureId(featureId)) {
58
+ invalidCliArgs({
59
+ reason: 'Invalid feature id',
60
+ provided: featureId,
61
+ expected_pattern: '^[a-z0-9_][a-z0-9_-]*$'
62
+ });
63
+ }
64
+
65
+ const runtimeSessions = await this.kernel.getRuntimeSessions();
66
+ const featureSessions = runtimeSessions.feature_sessions?.[featureId];
67
+ if (!featureSessions) {
68
+ invalidCliArgs({
69
+ reason: `No active session cluster found for ${featureId}`,
70
+ feature_id: featureId
71
+ });
72
+ }
73
+
74
+ const rawState = await callCliTool(this.toolClient, this.runId, TOOLS.FEATURE_STATE_GET, {
75
+ feature_id: featureId
76
+ });
77
+ const state = rawState.data as unknown as FeatureStatePayload;
78
+ const status = state.front_matter.status;
79
+ const role = selectSessionRole(status);
80
+ const sessionByRole = {
81
+ planner: featureSessions.planner_session_id,
82
+ builder: featureSessions.builder_session_id,
83
+ qa: featureSessions.qa_session_id
84
+ };
85
+ const selectedSessionId = sessionByRole[role];
86
+ const sessionId =
87
+ selectedSessionId && selectedSessionId !== 'unassigned'
88
+ ? selectedSessionId
89
+ : runtimeSessions.orchestrator_session_id;
90
+
91
+ if (!sessionId || sessionId === 'unknown' || sessionId === 'unassigned') {
92
+ invalidCliArgs({
93
+ reason: `No attachable session found for ${featureId}`,
94
+ feature_id: featureId
95
+ });
96
+ }
97
+
98
+ if (typeof this.provider.attachToSession !== 'function') {
99
+ invalidCliArgs({
100
+ reason: `Provider ${this.provider.selection.provider} does not support interactive attach`,
101
+ feature_id: featureId,
102
+ provider: this.provider.selection.provider
103
+ });
104
+ }
105
+
106
+ await this.provider.attachToSession(sessionId);
107
+
108
+ return {
109
+ ok: true,
110
+ data: {
111
+ command: 'attach',
112
+ feature_id: featureId,
113
+ status,
114
+ role,
115
+ session_id: sessionId,
116
+ attached: true
117
+ }
118
+ };
119
+ }
120
+ }
@@ -0,0 +1,190 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { parseFrontMatter } from '../core/frontmatter.js';
4
+ import { TOOLS } from '../core/constants.js';
5
+ import type { ToolClient } from '../mcp/tool-client.js';
6
+ import type { CliOptions } from './types.js';
7
+ import { callCliTool } from './tooling.js';
8
+
9
+ const DEFAULT_GRACE_PERIOD_SECONDS = 3600;
10
+ const TERMINAL_STATUSES = new Set(['merged', 'failed']);
11
+
12
+ interface CleanupDetail {
13
+ feature_id: string;
14
+ reason: string;
15
+ }
16
+
17
+ interface FeatureIndex {
18
+ active?: string[];
19
+ blocked?: string[];
20
+ merged?: string[];
21
+ }
22
+
23
+ export class CleanupCommandHandler {
24
+ private readonly toolClient: ToolClient;
25
+ private readonly runId: string;
26
+ private readonly repoRoot: string;
27
+ private readonly gracePeriodSeconds: number;
28
+ private readonly autoAfterMerge: boolean;
29
+
30
+ constructor(
31
+ toolClient: ToolClient,
32
+ runId: string,
33
+ repoRoot: string,
34
+ gracePeriodSeconds = DEFAULT_GRACE_PERIOD_SECONDS,
35
+ autoAfterMerge = false
36
+ ) {
37
+ this.toolClient = toolClient;
38
+ this.runId = runId;
39
+ this.repoRoot = repoRoot;
40
+ this.gracePeriodSeconds = gracePeriodSeconds;
41
+ this.autoAfterMerge = autoAfterMerge;
42
+ }
43
+
44
+ private async isRunLeaseInactive(): Promise<boolean> {
45
+ const runtimeRoot = path.join(this.repoRoot, '.aop', 'runtime');
46
+ const candidateLeasePaths = [
47
+ path.join(runtimeRoot, 'default', 'run-lease.json'),
48
+ path.join(runtimeRoot, 'run-lease.json')
49
+ ];
50
+
51
+ try {
52
+ const dirs = await fs.readdir(runtimeRoot, { withFileTypes: true });
53
+ for (const dir of dirs) {
54
+ if (dir.isDirectory()) {
55
+ candidateLeasePaths.push(path.join(runtimeRoot, dir.name, 'run-lease.json'));
56
+ }
57
+ }
58
+ } catch {
59
+ return true;
60
+ }
61
+
62
+ for (const leasePath of candidateLeasePaths) {
63
+ try {
64
+ const raw = await fs.readFile(leasePath, 'utf8');
65
+ const lease = JSON.parse(raw) as { run_id?: string; lease_expires_at?: string };
66
+ const runId = typeof lease.run_id === 'string' ? lease.run_id : 'none';
67
+ const leaseExpiresAt = typeof lease.lease_expires_at === 'string' ? lease.lease_expires_at : null;
68
+ const leaseExpiryMs = leaseExpiresAt ? new Date(leaseExpiresAt).getTime() : NaN;
69
+ if (runId !== 'none' && Number.isFinite(leaseExpiryMs) && leaseExpiryMs > Date.now()) {
70
+ return false;
71
+ }
72
+ } catch {
73
+ // Try next candidate lease file
74
+ }
75
+ }
76
+ return true;
77
+ }
78
+
79
+ async execute(options: CliOptions): Promise<unknown> {
80
+ const dryRun = options.dry_run ?? false;
81
+ const yes = options.yes ?? false;
82
+
83
+ const indexPath = path.join(this.repoRoot, '.aop', 'features', 'index.json');
84
+ let indexData: FeatureIndex = {};
85
+ try {
86
+ const raw = await fs.readFile(indexPath, 'utf8');
87
+ indexData = JSON.parse(raw) as FeatureIndex;
88
+ } catch {
89
+ // No index yet; nothing to clean
90
+ }
91
+
92
+ const allIndexedIds = new Set([
93
+ ...(indexData.active ?? []),
94
+ ...(indexData.blocked ?? []),
95
+ ...(indexData.merged ?? [])
96
+ ]);
97
+
98
+ const eligible: CleanupDetail[] = [];
99
+ const skipped: CleanupDetail[] = [];
100
+ const runLeaseInactive = await this.isRunLeaseInactive();
101
+
102
+ // Evaluate active + blocked (+ merged when auto_after_merge) for terminal status past grace period.
103
+ const candidateIds = [
104
+ ...(indexData.active ?? []),
105
+ ...(indexData.blocked ?? []),
106
+ ...(this.autoAfterMerge ? (indexData.merged ?? []) : [])
107
+ ];
108
+ for (const featureId of candidateIds) {
109
+ const statePath = path.join(this.repoRoot, '.aop', 'features', featureId, 'state.md');
110
+ try {
111
+ const raw = await fs.readFile(statePath, 'utf8');
112
+ const parsed = parseFrontMatter(raw);
113
+ const fm = parsed.frontMatter as { status?: string; last_updated?: string };
114
+ if (TERMINAL_STATUSES.has(fm.status ?? '') && fm.last_updated) {
115
+ const ageSeconds = (Date.now() - new Date(fm.last_updated).getTime()) / 1000;
116
+ if (ageSeconds > this.gracePeriodSeconds && runLeaseInactive) {
117
+ eligible.push({ feature_id: featureId, reason: `terminal status: ${fm.status}` });
118
+ continue;
119
+ }
120
+ if (!runLeaseInactive) {
121
+ skipped.push({ feature_id: featureId, reason: 'run lease still active' });
122
+ continue;
123
+ }
124
+ }
125
+ skipped.push({ feature_id: featureId, reason: 'not eligible' });
126
+ } catch {
127
+ if (this.autoAfterMerge && (indexData.merged ?? []).includes(featureId) && runLeaseInactive) {
128
+ eligible.push({ feature_id: featureId, reason: 'merged residue with missing state' });
129
+ continue;
130
+ }
131
+ skipped.push({ feature_id: featureId, reason: 'state unreadable' });
132
+ }
133
+ }
134
+
135
+ // Check for orphan worktrees (exist in .worktrees/ but not in index)
136
+ const worktreesRoot = path.join(this.repoRoot, '.worktrees');
137
+ try {
138
+ const entries = await fs.readdir(worktreesRoot, { withFileTypes: true });
139
+ for (const entry of entries) {
140
+ if (!entry.isDirectory()) {
141
+ continue;
142
+ }
143
+ if (!allIndexedIds.has(entry.name)) {
144
+ eligible.push({ feature_id: entry.name, reason: 'orphan worktree' });
145
+ }
146
+ }
147
+ } catch {
148
+ // No worktrees directory; skip orphan check
149
+ }
150
+
151
+ if (dryRun || !yes) {
152
+ return {
153
+ ok: true,
154
+ data: {
155
+ would_clean: eligible,
156
+ cleaned: [],
157
+ skipped
158
+ }
159
+ };
160
+ }
161
+
162
+ // Perform actual deletion
163
+ const cleaned: CleanupDetail[] = [];
164
+ const failedToClean: CleanupDetail[] = [];
165
+
166
+ for (const item of eligible) {
167
+ try {
168
+ await callCliTool(this.toolClient, this.runId, TOOLS.FEATURE_DELETE, {
169
+ feature_id: item.feature_id,
170
+ dry_run: false,
171
+ confirm: true,
172
+ remove_worktree: true,
173
+ remove_branch: 'none'
174
+ });
175
+ cleaned.push(item);
176
+ } catch {
177
+ failedToClean.push(item);
178
+ }
179
+ }
180
+
181
+ return {
182
+ ok: true,
183
+ data: {
184
+ would_clean: eligible,
185
+ cleaned,
186
+ skipped: [...skipped, ...failedToClean]
187
+ }
188
+ };
189
+ }
190
+ }
@@ -1,5 +1,6 @@
1
1
  import { ERROR_CODES } from '../core/error-codes.js';
2
2
  import type { AppError } from '../providers/providers.js';
3
+ import { CliCommand } from './types.js';
3
4
  import type { CliOptions, ToolTransport } from './types.js';
4
5
 
5
6
  function parseOptionalBooleanToken(token: string | undefined): boolean | null {
@@ -15,10 +16,14 @@ function parseOptionalBooleanToken(token: string | undefined): boolean | null {
15
16
  export class CliArgumentParser {
16
17
  parse(argv: string[]): CliOptions {
17
18
  const [first, ...rest] = argv;
18
- const command = first !== undefined && !first.startsWith('-') ? first : 'run';
19
- const tokens = first !== undefined && !first.startsWith('-') ? rest : argv;
19
+
20
+ // Treat -h / --help anywhere as the help command
21
+ const isHelpFlag = first === '--help' || first === '-h';
22
+ const isKnownCommand = first !== undefined && !first.startsWith('-');
23
+ const rawCommand = isHelpFlag ? CliCommand.Help : isKnownCommand ? first : CliCommand.Run;
24
+ const tokens = isHelpFlag || isKnownCommand ? rest : argv;
20
25
  const options: CliOptions = {
21
- command: command ?? 'run'
26
+ command: rawCommand ?? CliCommand.Run
22
27
  };
23
28
 
24
29
  for (let index = 0; index < tokens.length; index += 1) {
@@ -45,6 +50,11 @@ export class CliArgumentParser {
45
50
  index += 1;
46
51
  continue;
47
52
  }
53
+ if (token === '--message') {
54
+ options.message = next;
55
+ index += 1;
56
+ continue;
57
+ }
48
58
  if (token === '--dry-run') {
49
59
  const parsed = parseOptionalBooleanToken(next);
50
60
  if (parsed === null) {
@@ -96,7 +106,63 @@ export class CliArgumentParser {
96
106
  }
97
107
  if (token === '--takeover-stale-run') {
98
108
  options.takeover_stale_run = true;
109
+ continue;
110
+ }
111
+ if (token === '--batch') {
112
+ options.batch = true;
113
+ continue;
114
+ }
115
+ if (token === '--summary') {
116
+ options.summary = true;
117
+ continue;
118
+ }
119
+ if (token === '--auto') {
120
+ options.auto = true;
121
+ continue;
122
+ }
123
+ if (token === '--force') {
124
+ options.force = true;
125
+ continue;
126
+ }
127
+ if (token === '--project') {
128
+ options.project = next;
129
+ index += 1;
130
+ continue;
131
+ }
132
+ if (token === '--all') {
133
+ options.all = true;
134
+ continue;
135
+ }
136
+ if (token === '--port') {
137
+ const parsed = Number(next);
138
+ if (!isNaN(parsed)) {
139
+ options.port = parsed;
140
+ index += 1;
141
+ }
142
+ continue;
143
+ }
144
+ if (token === '--foreground') {
145
+ options.foreground = true;
146
+ continue;
147
+ }
148
+ if (token === '--dev') {
149
+ options.dev = true;
150
+ continue;
151
+ }
152
+ if (token === '--help' || token === '-h') {
153
+ options.command = CliCommand.Help;
154
+ continue;
155
+ }
99
156
 
157
+ if (!token.startsWith('-')) {
158
+ if ((options.command === CliCommand.Send || options.command === CliCommand.Attach) && !options.feature_id) {
159
+ options.feature_id = token;
160
+ continue;
161
+ }
162
+ if (options.command === CliCommand.Send && !options.message) {
163
+ options.message = tokens.slice(index).join(' ');
164
+ break;
165
+ }
100
166
  }
101
167
  }
102
168
 
@@ -0,0 +1,57 @@
1
+ import { execFile, spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { promisify } from 'node:util';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const execFileAsync = promisify(execFile);
8
+
9
+ export class DashboardCommandHandler {
10
+ async execute(options: { port?: number; foreground?: boolean; dev?: boolean }): Promise<Record<string, unknown>> {
11
+ const port = options.port ?? 3000;
12
+ const repoRoot = path.resolve(__dirname, '../../../../');
13
+ const dashboardWorkspace = '@aop/web-dashboard';
14
+ const devMode = options.dev === true;
15
+ const foreground = options.foreground === true || devMode;
16
+
17
+ const env = { ...process.env, PORT: String(port), HOSTNAME: '0.0.0.0', AOP_ROOT: process.cwd() };
18
+
19
+ if (devMode) {
20
+ const child = spawn('npm', ['run', '--workspace', dashboardWorkspace, 'dev'], { cwd: repoRoot, env, stdio: 'inherit' });
21
+ await new Promise<void>((resolve, reject) => {
22
+ child.on('close', resolve);
23
+ child.on('error', reject);
24
+ });
25
+ return { ok: true, data: { message: 'Dashboard stopped', port, mode: 'dev' } };
26
+ }
27
+
28
+ await execFileAsync('npm', ['run', '--workspace', dashboardWorkspace, 'build'], { cwd: repoRoot, env });
29
+
30
+ if (foreground) {
31
+ const child = spawn('npm', ['run', '--workspace', dashboardWorkspace, 'start'], { cwd: repoRoot, env, stdio: 'inherit' });
32
+ await new Promise<void>((resolve, reject) => {
33
+ child.on('close', resolve);
34
+ child.on('error', reject);
35
+ });
36
+ return { ok: true, data: { message: 'Dashboard stopped', port, mode: 'production' } };
37
+ }
38
+
39
+ const child = spawn('npm', ['run', '--workspace', dashboardWorkspace, 'start'], {
40
+ cwd: repoRoot,
41
+ env,
42
+ detached: true,
43
+ stdio: 'ignore'
44
+ });
45
+ child.unref();
46
+ return {
47
+ ok: true,
48
+ data: {
49
+ message: `Dashboard started on http://localhost:${port}`,
50
+ port,
51
+ background: true,
52
+ built: true,
53
+ mode: 'production'
54
+ }
55
+ };
56
+ }
57
+ }
@@ -0,0 +1,163 @@
1
+ import { CliCommand } from './types.js';
2
+
3
+ interface CommandHelp {
4
+ usage: string;
5
+ description: string;
6
+ flags?: Array<{ flag: string; description: string }>;
7
+ }
8
+
9
+ const COMMAND_HELP: Record<CliCommand, CommandHelp> = {
10
+ [CliCommand.Run]: {
11
+ usage: 'aop run [flags]',
12
+ description: 'Ingest spec files and start the agent supervisor.',
13
+ flags: [
14
+ { flag: '-fi <PATH>', description: 'Input spec file path' },
15
+ { flag: '-fl <PATH>', description: 'Input spec folder path' },
16
+ { flag: '--batch', description: 'Batch-ingest all specs in the folder (skip already-active features)' },
17
+ { flag: '--agent-provider <name>', description: 'Override agent provider (claude, codex, gemini, …)' },
18
+ { flag: '--agent-model <name>', description: 'Override agent model' },
19
+ { flag: '--agent-config <PATH>', description: 'Path to agent config file' },
20
+ { flag: '--provider-config-env <var>', description: 'Env var name that holds provider API key' },
21
+ { flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' },
22
+ { flag: '--takeover-stale-run', description: 'Take over a stale run lease' },
23
+ { flag: '--project <name>', description: 'Select project from multi-project.yaml' }
24
+ ]
25
+ },
26
+ [CliCommand.Status]: {
27
+ usage: 'aop status [flags]',
28
+ description: 'Show live status of all tracked features.',
29
+ flags: [
30
+ { flag: '--summary', description: 'Print a condensed one-line-per-feature summary' },
31
+ { flag: '--all', description: 'Aggregate status across all projects in multi-project.yaml' },
32
+ { flag: '--project <name>', description: 'Scope to a specific project' }
33
+ ]
34
+ },
35
+ [CliCommand.Resume]: {
36
+ usage: 'aop resume [flags]',
37
+ description: 'Resume blocked or stalled features.',
38
+ flags: [
39
+ { flag: '--feature-id <id>', description: 'Resume a specific feature' },
40
+ { flag: '--force', description: 'Force-resume even if the feature is not blocked' },
41
+ { flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' }
42
+ ]
43
+ },
44
+ [CliCommand.Stop]: {
45
+ usage: 'aop stop',
46
+ description: 'Signal the running supervisor to stop gracefully.'
47
+ },
48
+ [CliCommand.Delete]: {
49
+ usage: 'aop delete [flags]',
50
+ description: 'Delete one or all features from the index.',
51
+ flags: [
52
+ { flag: '--feature-id <id>', description: 'Feature to delete' },
53
+ { flag: '--all', description: 'Delete all features' },
54
+ { flag: '--dry-run', description: 'Preview what would be deleted without making changes' }
55
+ ]
56
+ },
57
+ [CliCommand.Cleanup]: {
58
+ usage: 'aop cleanup [flags]',
59
+ description: 'Clean up merged or stale feature state and worktrees.',
60
+ flags: [
61
+ { flag: '--feature-id <id>', description: 'Clean up a specific feature' },
62
+ { flag: '--all', description: 'Clean up all eligible features' },
63
+ { flag: '--remove-worktree', description: 'Remove the git worktree after cleanup' },
64
+ { flag: '--remove-branch <none|safe|force>', description: 'Branch removal mode after cleanup' },
65
+ { flag: '--dry-run', description: 'Preview what would be cleaned without making changes' },
66
+ { flag: '--yes', description: 'Skip confirmation prompts' }
67
+ ]
68
+ },
69
+ [CliCommand.Init]: {
70
+ usage: 'aop init [flags]',
71
+ description: 'Initialise agentic orchestrator configuration in the current directory.',
72
+ flags: [
73
+ { flag: '--auto', description: 'Run non-interactively with defaults' },
74
+ { flag: '--force', description: 'Overwrite existing configuration' }
75
+ ]
76
+ },
77
+ [CliCommand.Dashboard]: {
78
+ usage: 'aop dashboard [flags]',
79
+ description: 'Start the web dashboard server.',
80
+ flags: [
81
+ { flag: '--port <number>', description: 'Port to listen on (default: 3000)' },
82
+ { flag: '--foreground', description: 'Keep the server in the foreground' },
83
+ { flag: '--dev', description: 'Start in Next.js dev mode' }
84
+ ]
85
+ },
86
+ [CliCommand.Retry]: {
87
+ usage: 'aop retry [flags]',
88
+ description: 'Retry a failed gate or step for a feature.',
89
+ flags: [
90
+ { flag: '--feature-id <id>', description: 'Feature to retry' },
91
+ { flag: '--force', description: 'Force retry even if the feature is not in a failed state' }
92
+ ]
93
+ },
94
+ [CliCommand.Send]: {
95
+ usage: 'aop send <feature-id> <message>',
96
+ description: 'Send a message to an active agent for a feature.',
97
+ flags: [
98
+ { flag: '--feature-id <id>', description: 'Target feature (can also be the first positional argument)' },
99
+ { flag: '--message <text>', description: 'Message to deliver (can also be the remaining positional arguments)' }
100
+ ]
101
+ },
102
+ [CliCommand.Attach]: {
103
+ usage: 'aop attach <feature-id>',
104
+ description: 'Attach to the running agent session for a feature (interactive).',
105
+ flags: [
106
+ { flag: '--feature-id <id>', description: 'Feature to attach to (can also be the first positional argument)' }
107
+ ]
108
+ },
109
+ [CliCommand.Help]: {
110
+ usage: 'aop help [command]',
111
+ description: 'Show this help text, or detailed help for a specific command.',
112
+ flags: [{ flag: '--help, -h', description: 'Can also be used with any command' }]
113
+ }
114
+ };
115
+
116
+ function pad(str: string, width: number): string {
117
+ return str + ' '.repeat(Math.max(0, width - str.length));
118
+ }
119
+
120
+ function renderCommand(cmd: CliCommand, help: CommandHelp): string {
121
+ const lines: string[] = [` ${pad(cmd, 12)}${help.description}`];
122
+ return lines.join('\n');
123
+ }
124
+
125
+ function renderCommandDetail(help: CommandHelp): string {
126
+ const lines: string[] = [`Usage: ${help.usage}`, '', ` ${help.description}`];
127
+ if (help.flags && help.flags.length > 0) {
128
+ lines.push('', 'Flags:');
129
+ const colWidth = Math.max(...help.flags.map((f) => f.flag.length)) + 4;
130
+ for (const { flag, description } of help.flags) {
131
+ lines.push(` ${pad(flag, colWidth)}${description}`);
132
+ }
133
+ }
134
+ return lines.join('\n');
135
+ }
136
+
137
+ export class HelpCommandHandler {
138
+ execute(subcommand?: string): { ok: boolean; data: { help: string } } {
139
+ const target = subcommand as CliCommand | undefined;
140
+
141
+ if (target && target in COMMAND_HELP) {
142
+ const help = renderCommandDetail(COMMAND_HELP[target]);
143
+ return { ok: true, data: { help } };
144
+ }
145
+
146
+ const header = [
147
+ 'aop — Agentic Orchestrator control plane',
148
+ '',
149
+ 'Usage: aop <command> [flags]',
150
+ '',
151
+ 'Commands:'
152
+ ];
153
+
154
+ const commandLines = (Object.entries(COMMAND_HELP) as Array<[CliCommand, CommandHelp]>).map(([cmd, help]) =>
155
+ renderCommand(cmd, help)
156
+ );
157
+
158
+ const footer = ['', 'Run `aop help <command>` for detailed help on any command.', 'Flags: --help, -h'];
159
+
160
+ const help = [...header, ...commandLines, ...footer].join('\n');
161
+ return { ok: true, data: { help } };
162
+ }
163
+ }