okstra 0.174.0 → 0.175.1

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 (374) hide show
  1. package/README.md +18 -9
  2. package/bin/okstra +8 -4
  3. package/dist/cli-registry.d.mts +16 -0
  4. package/dist/cli-registry.mjs +560 -0
  5. package/dist/cli-registry.mjs.map +1 -0
  6. package/dist/commands/execute/agent-prompt.d.mts +1 -0
  7. package/{src → dist}/commands/execute/agent-prompt.mjs +10 -11
  8. package/dist/commands/execute/agent-prompt.mjs.map +1 -0
  9. package/dist/commands/execute/codex-dispatch.d.mts +3 -0
  10. package/dist/commands/execute/codex-dispatch.mjs +6 -0
  11. package/dist/commands/execute/codex-dispatch.mjs.map +1 -0
  12. package/dist/commands/execute/codex-run.d.mts +3 -0
  13. package/{src → dist}/commands/execute/codex-run.mjs +30 -37
  14. package/dist/commands/execute/codex-run.mjs.map +1 -0
  15. package/dist/commands/execute/convergence.d.mts +1 -0
  16. package/{src → dist}/commands/execute/convergence.mjs +15 -16
  17. package/dist/commands/execute/convergence.mjs.map +1 -0
  18. package/dist/commands/execute/error-log.d.mts +1 -0
  19. package/{src → dist}/commands/execute/error-log.mjs +2 -3
  20. package/dist/commands/execute/error-log.mjs.map +1 -0
  21. package/dist/commands/execute/git-reconcile.d.mts +1 -0
  22. package/{src → dist}/commands/execute/git-reconcile.mjs +10 -11
  23. package/dist/commands/execute/git-reconcile.mjs.map +1 -0
  24. package/dist/commands/execute/handoff.d.mts +1 -0
  25. package/{src → dist}/commands/execute/handoff.mjs +10 -11
  26. package/dist/commands/execute/handoff.mjs.map +1 -0
  27. package/dist/commands/execute/incremental-carry.d.mts +1 -0
  28. package/{src → dist}/commands/execute/incremental-carry.mjs +2 -3
  29. package/dist/commands/execute/incremental-carry.mjs.map +1 -0
  30. package/dist/commands/execute/incremental-scope.d.mts +1 -0
  31. package/{src → dist}/commands/execute/incremental-scope.mjs +2 -3
  32. package/dist/commands/execute/incremental-scope.mjs.map +1 -0
  33. package/dist/commands/execute/integrate-stages.d.mts +1 -0
  34. package/{src → dist}/commands/execute/integrate-stages.mjs +10 -11
  35. package/dist/commands/execute/integrate-stages.mjs.map +1 -0
  36. package/dist/commands/execute/pane-title.d.mts +1 -0
  37. package/dist/commands/execute/pane-title.mjs +20 -0
  38. package/dist/commands/execute/pane-title.mjs.map +1 -0
  39. package/dist/commands/execute/plan-items.d.mts +1 -0
  40. package/dist/commands/execute/plan-items.mjs +9 -0
  41. package/dist/commands/execute/plan-items.mjs.map +1 -0
  42. package/dist/commands/execute/plan-validate.d.mts +1 -0
  43. package/dist/commands/execute/plan-validate.mjs +68 -0
  44. package/dist/commands/execute/plan-validate.mjs.map +1 -0
  45. package/dist/commands/execute/plan-verify.d.mts +1 -0
  46. package/{src → dist}/commands/execute/plan-verify.mjs +13 -16
  47. package/dist/commands/execute/plan-verify.mjs.map +1 -0
  48. package/dist/commands/execute/render-bundle.d.mts +3 -0
  49. package/{src → dist}/commands/execute/render-bundle.mjs +65 -61
  50. package/dist/commands/execute/render-bundle.mjs.map +1 -0
  51. package/dist/commands/execute/run.d.mts +24 -0
  52. package/dist/commands/execute/run.mjs +196 -0
  53. package/dist/commands/execute/run.mjs.map +1 -0
  54. package/dist/commands/execute/spawn-followups.d.mts +1 -0
  55. package/{src → dist}/commands/execute/spawn-followups.mjs +6 -7
  56. package/dist/commands/execute/spawn-followups.mjs.map +1 -0
  57. package/dist/commands/execute/team.d.mts +3 -0
  58. package/{src → dist}/commands/execute/team.mjs +29 -36
  59. package/dist/commands/execute/team.mjs.map +1 -0
  60. package/dist/commands/execute/token-usage.d.mts +1 -0
  61. package/{src → dist}/commands/execute/token-usage.mjs +2 -3
  62. package/dist/commands/execute/token-usage.mjs.map +1 -0
  63. package/dist/commands/execute/wizard.d.mts +8 -0
  64. package/dist/commands/execute/wizard.mjs +191 -0
  65. package/dist/commands/execute/wizard.mjs.map +1 -0
  66. package/dist/commands/execute/worker-audit-check.d.mts +1 -0
  67. package/{src → dist}/commands/execute/worker-audit-check.mjs +11 -12
  68. package/dist/commands/execute/worker-audit-check.mjs.map +1 -0
  69. package/dist/commands/execute/worker-dispatch.d.mts +7 -0
  70. package/{src → dist}/commands/execute/worker-dispatch.mjs +34 -46
  71. package/dist/commands/execute/worker-dispatch.mjs.map +1 -0
  72. package/dist/commands/execute/worker-state.d.mts +1 -0
  73. package/{src → dist}/commands/execute/worker-state.mjs +15 -16
  74. package/dist/commands/execute/worker-state.mjs.map +1 -0
  75. package/dist/commands/execute/worktree-lookup.d.mts +1 -0
  76. package/{src → dist}/commands/execute/worktree-lookup.mjs +38 -37
  77. package/dist/commands/execute/worktree-lookup.mjs.map +1 -0
  78. package/dist/commands/execute/worktree-status.d.mts +1 -0
  79. package/{src → dist}/commands/execute/worktree-status.mjs +52 -46
  80. package/dist/commands/execute/worktree-status.mjs.map +1 -0
  81. package/dist/commands/inspect/code-review.d.mts +1 -0
  82. package/{src → dist}/commands/inspect/code-review.mjs +16 -19
  83. package/dist/commands/inspect/code-review.mjs.map +1 -0
  84. package/dist/commands/inspect/container.d.mts +1 -0
  85. package/{src → dist}/commands/inspect/container.mjs +11 -13
  86. package/dist/commands/inspect/container.mjs.map +1 -0
  87. package/dist/commands/inspect/context-cost.d.mts +1 -0
  88. package/{src → dist}/commands/inspect/context-cost.mjs +11 -13
  89. package/dist/commands/inspect/context-cost.mjs.map +1 -0
  90. package/dist/commands/inspect/design-prep.d.mts +1 -0
  91. package/{src → dist}/commands/inspect/design-prep.mjs +10 -11
  92. package/dist/commands/inspect/design-prep.mjs.map +1 -0
  93. package/dist/commands/inspect/error-report.d.mts +1 -0
  94. package/{src → dist}/commands/inspect/error-report.mjs +11 -13
  95. package/dist/commands/inspect/error-report.mjs.map +1 -0
  96. package/dist/commands/inspect/error-zip.d.mts +1 -0
  97. package/{src → dist}/commands/inspect/error-zip.mjs +11 -12
  98. package/dist/commands/inspect/error-zip.mjs.map +1 -0
  99. package/dist/commands/inspect/log-report.d.mts +1 -0
  100. package/{src → dist}/commands/inspect/log-report.mjs +11 -13
  101. package/dist/commands/inspect/log-report.mjs.map +1 -0
  102. package/dist/commands/inspect/profile-show.d.mts +1 -0
  103. package/{src → dist}/commands/inspect/profile-show.mjs +10 -11
  104. package/dist/commands/inspect/profile-show.mjs.map +1 -0
  105. package/dist/commands/inspect/recap.d.mts +1 -0
  106. package/{src → dist}/commands/inspect/recap.mjs +11 -13
  107. package/dist/commands/inspect/recap.mjs.map +1 -0
  108. package/dist/commands/inspect/resolve-task-key.d.mts +1 -0
  109. package/{src → dist}/commands/inspect/resolve-task-key.mjs +11 -13
  110. package/dist/commands/inspect/resolve-task-key.mjs.map +1 -0
  111. package/dist/commands/inspect/rollup.d.mts +1 -0
  112. package/{src → dist}/commands/inspect/rollup.mjs +11 -13
  113. package/dist/commands/inspect/rollup.mjs.map +1 -0
  114. package/dist/commands/inspect/run-audit.d.mts +1 -0
  115. package/{src → dist}/commands/inspect/run-audit.mjs +11 -12
  116. package/dist/commands/inspect/run-audit.mjs.map +1 -0
  117. package/dist/commands/inspect/set-work-status.d.mts +1 -0
  118. package/{src → dist}/commands/inspect/set-work-status.mjs +11 -13
  119. package/dist/commands/inspect/set-work-status.mjs.map +1 -0
  120. package/dist/commands/inspect/stage-map.d.mts +1 -0
  121. package/dist/commands/inspect/stage-map.mjs +110 -0
  122. package/dist/commands/inspect/stage-map.mjs.map +1 -0
  123. package/dist/commands/inspect/task-list.d.mts +1 -0
  124. package/dist/commands/inspect/task-list.mjs +103 -0
  125. package/dist/commands/inspect/task-list.mjs.map +1 -0
  126. package/dist/commands/inspect/task-show.d.mts +1 -0
  127. package/dist/commands/inspect/task-show.mjs +108 -0
  128. package/dist/commands/inspect/task-show.mjs.map +1 -0
  129. package/dist/commands/inspect/time-report.d.mts +1 -0
  130. package/{src → dist}/commands/inspect/time-report.mjs +11 -13
  131. package/dist/commands/inspect/time-report.mjs.map +1 -0
  132. package/dist/commands/inspect/usage-report.d.mts +1 -0
  133. package/{src → dist}/commands/inspect/usage-report.mjs +11 -13
  134. package/dist/commands/inspect/usage-report.mjs.map +1 -0
  135. package/dist/commands/inspect/user-response.d.mts +1 -0
  136. package/{src → dist}/commands/inspect/user-response.mjs +10 -11
  137. package/dist/commands/inspect/user-response.mjs.map +1 -0
  138. package/dist/commands/inspect/worker-liveness.d.mts +1 -0
  139. package/{src → dist}/commands/inspect/worker-liveness.mjs +11 -13
  140. package/dist/commands/inspect/worker-liveness.mjs.map +1 -0
  141. package/dist/commands/lifecycle/check-project.d.mts +21 -0
  142. package/dist/commands/lifecycle/check-project.mjs +175 -0
  143. package/dist/commands/lifecycle/check-project.mjs.map +1 -0
  144. package/dist/commands/lifecycle/config.d.mts +1 -0
  145. package/dist/commands/lifecycle/config.mjs +369 -0
  146. package/dist/commands/lifecycle/config.mjs.map +1 -0
  147. package/dist/commands/lifecycle/doctor.d.mts +10 -0
  148. package/dist/commands/lifecycle/doctor.mjs +317 -0
  149. package/dist/commands/lifecycle/doctor.mjs.map +1 -0
  150. package/dist/commands/lifecycle/install.d.mts +17 -0
  151. package/dist/commands/lifecycle/install.mjs +1077 -0
  152. package/dist/commands/lifecycle/install.mjs.map +1 -0
  153. package/dist/commands/lifecycle/migrate.d.mts +1 -0
  154. package/{src → dist}/commands/lifecycle/migrate.mjs +10 -11
  155. package/dist/commands/lifecycle/migrate.mjs.map +1 -0
  156. package/dist/commands/lifecycle/model.d.mts +1 -0
  157. package/dist/commands/lifecycle/model.mjs +22 -0
  158. package/dist/commands/lifecycle/model.mjs.map +1 -0
  159. package/dist/commands/lifecycle/paths.d.mts +1 -0
  160. package/dist/commands/lifecycle/paths.mjs +102 -0
  161. package/dist/commands/lifecycle/paths.mjs.map +1 -0
  162. package/dist/commands/lifecycle/preflight.d.mts +1 -0
  163. package/dist/commands/lifecycle/preflight.mjs +124 -0
  164. package/dist/commands/lifecycle/preflight.mjs.map +1 -0
  165. package/dist/commands/lifecycle/setup.d.mts +1 -0
  166. package/dist/commands/lifecycle/setup.mjs +297 -0
  167. package/dist/commands/lifecycle/setup.mjs.map +1 -0
  168. package/dist/commands/lifecycle/uninstall.d.mts +4 -0
  169. package/dist/commands/lifecycle/uninstall.mjs +262 -0
  170. package/dist/commands/lifecycle/uninstall.mjs.map +1 -0
  171. package/dist/commands/manager.d.mts +3 -0
  172. package/{src → dist}/commands/manager.mjs +25 -32
  173. package/dist/commands/manager.mjs.map +1 -0
  174. package/dist/commands/memory/memory.d.mts +1 -0
  175. package/dist/commands/memory/memory.mjs +569 -0
  176. package/dist/commands/memory/memory.mjs.map +1 -0
  177. package/dist/commands/pr/pr.d.mts +33 -0
  178. package/dist/commands/pr/pr.mjs +296 -0
  179. package/dist/commands/pr/pr.mjs.map +1 -0
  180. package/dist/commands/report/agent-activity.d.mts +1 -0
  181. package/{src → dist}/commands/report/agent-activity.mjs +11 -12
  182. package/dist/commands/report/agent-activity.mjs.map +1 -0
  183. package/dist/commands/report/finalize.d.mts +4 -0
  184. package/{src → dist}/commands/report/finalize.mjs +25 -32
  185. package/dist/commands/report/finalize.mjs.map +1 -0
  186. package/dist/commands/report/inject-report-index.d.mts +1 -0
  187. package/{src → dist}/commands/report/inject-report-index.mjs +6 -7
  188. package/dist/commands/report/inject-report-index.mjs.map +1 -0
  189. package/dist/commands/report/render-final-report.d.mts +1 -0
  190. package/{src → dist}/commands/report/render-final-report.mjs +6 -7
  191. package/dist/commands/report/render-final-report.mjs.map +1 -0
  192. package/dist/commands/report/render-views.d.mts +1 -0
  193. package/{src → dist}/commands/report/render-views.mjs +6 -7
  194. package/dist/commands/report/render-views.mjs.map +1 -0
  195. package/dist/commands/report/translate.d.mts +1 -0
  196. package/{src → dist}/commands/report/translate.mjs +6 -7
  197. package/dist/commands/report/translate.mjs.map +1 -0
  198. package/dist/lib/helper-scripts.d.mts +3 -0
  199. package/{src → dist}/lib/helper-scripts.mjs +11 -14
  200. package/dist/lib/helper-scripts.mjs.map +1 -0
  201. package/dist/lib/host-registry-client.d.mts +25 -0
  202. package/dist/lib/host-registry-client.mjs +152 -0
  203. package/dist/lib/host-registry-client.mjs.map +1 -0
  204. package/dist/lib/install-assets.d.mts +8 -0
  205. package/{src → dist}/lib/install-assets.mjs +17 -20
  206. package/dist/lib/install-assets.mjs.map +1 -0
  207. package/dist/lib/okstra-dirs.d.mts +4 -0
  208. package/{src → dist}/lib/okstra-dirs.mjs +3 -6
  209. package/dist/lib/okstra-dirs.mjs.map +1 -0
  210. package/dist/lib/paths.d.mts +4 -0
  211. package/dist/lib/paths.mjs +78 -0
  212. package/dist/lib/paths.mjs.map +1 -0
  213. package/dist/lib/proc.d.mts +3 -0
  214. package/dist/lib/proc.mjs +31 -0
  215. package/dist/lib/proc.mjs.map +1 -0
  216. package/dist/lib/python-helper.d.mts +8 -0
  217. package/dist/lib/python-helper.mjs +123 -0
  218. package/dist/lib/python-helper.mjs.map +1 -0
  219. package/dist/lib/runtime-manifest.d.mts +7 -0
  220. package/dist/lib/runtime-manifest.mjs +73 -0
  221. package/dist/lib/runtime-manifest.mjs.map +1 -0
  222. package/dist/lib/skill-catalog.d.mts +4 -0
  223. package/dist/lib/skill-catalog.mjs +50 -0
  224. package/dist/lib/skill-catalog.mjs.map +1 -0
  225. package/dist/lib/types.d.mts +129 -0
  226. package/dist/lib/types.mjs +2 -0
  227. package/dist/lib/types.mjs.map +1 -0
  228. package/dist/lib/version.d.mts +2 -0
  229. package/dist/lib/version.mjs +27 -0
  230. package/dist/lib/version.mjs.map +1 -0
  231. package/docs/architecture/storage-model.md +4 -0
  232. package/docs/architecture.md +7 -1
  233. package/docs/cli.md +26 -6
  234. package/docs/contributor-change-matrix.md +2 -2
  235. package/docs/project-structure-overview.md +16 -7
  236. package/docs/task-process/README.md +2 -0
  237. package/docs/task-process/implementation-planning.md +1 -1
  238. package/docs/task-process/implementation.md +1 -1
  239. package/package.json +11 -5
  240. package/runtime/BUILD.json +2 -2
  241. package/runtime/agents/workers/claude-worker.md +2 -1
  242. package/runtime/agents/workers/report-writer-worker.md +3 -1
  243. package/runtime/agents/workers/translator-worker.md +3 -1
  244. package/runtime/bin/lib/okstra/cli.sh +12 -0
  245. package/runtime/bin/lib/okstra/globals.sh +3 -0
  246. package/runtime/bin/lib/okstra/usage.sh +4 -4
  247. package/runtime/bin/okstra-error-log.py +27 -0
  248. package/runtime/bin/okstra-provider-exec.py +217 -5
  249. package/runtime/bin/okstra.sh +10 -0
  250. package/runtime/prompts/lead/convergence.md +27 -18
  251. package/runtime/prompts/lead/okstra-lead-contract.md +3 -1
  252. package/runtime/prompts/lead/plan-body-verification.md +10 -3
  253. package/runtime/prompts/lead/team-contract.md +1 -1
  254. package/runtime/prompts/profiles/change-impact-analysis.md +16 -0
  255. package/runtime/prompts/profiles/error-analysis.md +20 -0
  256. package/runtime/prompts/profiles/feature-analysis.md +16 -0
  257. package/runtime/prompts/profiles/final-verification.md +16 -0
  258. package/runtime/prompts/profiles/implementation-option-selection.md +16 -0
  259. package/runtime/prompts/profiles/implementation-planning.md +20 -0
  260. package/runtime/prompts/profiles/implementation.md +15 -0
  261. package/runtime/prompts/profiles/improvement-discovery.md +16 -0
  262. package/runtime/prompts/profiles/project-analysis.md +16 -0
  263. package/runtime/prompts/profiles/release-handoff.md +4 -0
  264. package/runtime/prompts/profiles/requirements-discovery.md +20 -0
  265. package/runtime/prompts/wizard/prompts.ko.json +18 -0
  266. package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +8 -0
  267. package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +8 -0
  268. package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
  269. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +2 -2
  270. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +25 -5
  271. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
  272. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +4 -1
  273. package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
  274. package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +2 -2
  275. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +79 -11
  276. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +95 -25
  277. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +59 -14
  278. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +55 -9
  279. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +51 -12
  280. package/runtime/python/okstra_ctl/agent_activity.py +5 -1
  281. package/runtime/python/okstra_ctl/agent_invocation.py +608 -14
  282. package/runtime/python/okstra_ctl/agent_prompt_cli.py +249 -50
  283. package/runtime/python/okstra_ctl/application/resolve_assignment.py +53 -12
  284. package/runtime/python/okstra_ctl/assignment_environment.py +102 -0
  285. package/runtime/python/okstra_ctl/assignment_resolver.py +790 -0
  286. package/runtime/python/okstra_ctl/attempt_evidence.py +342 -0
  287. package/runtime/python/okstra_ctl/convergence.py +409 -3
  288. package/runtime/python/okstra_ctl/convergence_engine.py +248 -15
  289. package/runtime/python/okstra_ctl/convergence_store.py +170 -1
  290. package/runtime/python/okstra_ctl/dispatch_core.py +1092 -63
  291. package/runtime/python/okstra_ctl/dispatch_state.py +696 -11
  292. package/runtime/python/okstra_ctl/doctor.py +14 -0
  293. package/runtime/python/okstra_ctl/domain/host.py +32 -1
  294. package/runtime/python/okstra_ctl/domain/provider.py +212 -6
  295. package/runtime/python/okstra_ctl/domain/role.py +125 -0
  296. package/runtime/python/okstra_ctl/domain/wizard/interaction.py +13 -0
  297. package/runtime/python/okstra_ctl/domain/worker_exec.py +34 -1
  298. package/runtime/python/okstra_ctl/domain/worker_role.py +13 -3
  299. package/runtime/python/okstra_ctl/domain/worker_stream.py +24 -0
  300. package/runtime/python/okstra_ctl/error_log_write.py +9 -0
  301. package/runtime/python/okstra_ctl/error_report.py +21 -1
  302. package/runtime/python/okstra_ctl/execution_identity.py +529 -0
  303. package/runtime/python/okstra_ctl/execution_manifest.py +1281 -0
  304. package/runtime/python/okstra_ctl/execution_mutation_audit.py +619 -0
  305. package/runtime/python/okstra_ctl/index.py +6 -2
  306. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
  307. package/runtime/python/okstra_ctl/legacy_model_selection.py +490 -0
  308. package/runtime/python/okstra_ctl/model_cli.py +278 -0
  309. package/runtime/python/okstra_ctl/model_defaults.py +46 -0
  310. package/runtime/python/okstra_ctl/model_discovery.py +26 -7
  311. package/runtime/python/okstra_ctl/model_pool.py +501 -0
  312. package/runtime/python/okstra_ctl/models.py +47 -27
  313. package/runtime/python/okstra_ctl/mutation_recovery.py +293 -0
  314. package/runtime/python/okstra_ctl/pane_title.py +151 -0
  315. package/runtime/python/okstra_ctl/ports/host_model.py +48 -17
  316. package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
  317. package/runtime/python/okstra_ctl/registry/provider_registry.py +8 -4
  318. package/runtime/python/okstra_ctl/render.py +78 -10
  319. package/runtime/python/okstra_ctl/render_final_report.py +19 -0
  320. package/runtime/python/okstra_ctl/report_contract.py +39 -0
  321. package/runtime/python/okstra_ctl/report_finalize.py +16 -0
  322. package/runtime/python/okstra_ctl/report_html/render.py +1 -0
  323. package/runtime/python/okstra_ctl/role_requirements.py +217 -0
  324. package/runtime/python/okstra_ctl/run.py +1207 -258
  325. package/runtime/python/okstra_ctl/run_index_row.py +7 -1
  326. package/runtime/python/okstra_ctl/time_report.py +38 -4
  327. package/runtime/python/okstra_ctl/usage_identity.py +86 -0
  328. package/runtime/python/okstra_ctl/usage_report.py +15 -3
  329. package/runtime/python/okstra_ctl/wizard.py +1253 -62
  330. package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
  331. package/runtime/python/okstra_ctl/worker_request.py +7 -1
  332. package/runtime/python/okstra_ctl/worker_runner.py +130 -5
  333. package/runtime/python/okstra_ctl/workers.py +7 -5
  334. package/runtime/python/okstra_ctl/write_policy.py +571 -0
  335. package/runtime/schemas/convergence-groups-v2.0.schema.json +128 -0
  336. package/runtime/schemas/execution-manifest-v2.schema.json +340 -0
  337. package/runtime/schemas/final-report-v2.0.schema.json +25 -0
  338. package/runtime/skills/okstra-run/SKILL.md +9 -9
  339. package/runtime/templates/report-writer-prompt-preamble.md +2 -0
  340. package/runtime/templates/reports/final-report-v2.template.md +7 -1
  341. package/runtime/templates/reports/html/base.template.html +21 -0
  342. package/runtime/templates/reports/html/i18n/en.json +4 -0
  343. package/runtime/templates/reports/html/i18n/ko.json +4 -0
  344. package/runtime/templates/worker-prompt-preamble.md +6 -2
  345. package/runtime/validators/lib/fixtures.sh +49 -16
  346. package/runtime/validators/validate-run.py +429 -35
  347. package/runtime/validators/validate_session_conformance.py +25 -7
  348. package/src/cli-registry.mjs +0 -539
  349. package/src/commands/execute/codex-dispatch.mjs +0 -10
  350. package/src/commands/execute/plan-items.mjs +0 -9
  351. package/src/commands/execute/plan-validate.mjs +0 -68
  352. package/src/commands/execute/run.mjs +0 -208
  353. package/src/commands/execute/wizard.mjs +0 -167
  354. package/src/commands/inspect/stage-map.mjs +0 -98
  355. package/src/commands/inspect/task-list.mjs +0 -97
  356. package/src/commands/inspect/task-show.mjs +0 -100
  357. package/src/commands/lifecycle/check-project.mjs +0 -187
  358. package/src/commands/lifecycle/config.mjs +0 -385
  359. package/src/commands/lifecycle/doctor.mjs +0 -308
  360. package/src/commands/lifecycle/install.mjs +0 -1170
  361. package/src/commands/lifecycle/paths.mjs +0 -104
  362. package/src/commands/lifecycle/preflight.mjs +0 -125
  363. package/src/commands/lifecycle/setup.mjs +0 -333
  364. package/src/commands/lifecycle/uninstall.mjs +0 -279
  365. package/src/commands/memory/memory.mjs +0 -524
  366. package/src/commands/pr/pr.mjs +0 -261
  367. package/src/lib/host-registry-client.mjs +0 -176
  368. package/src/lib/paths.mjs +0 -86
  369. package/src/lib/proc.mjs +0 -31
  370. package/src/lib/python-helper.mjs +0 -142
  371. package/src/lib/runtime-manifest.mjs +0 -70
  372. package/src/lib/skill-catalog.mjs +0 -53
  373. package/src/lib/version.mjs +0 -20
  374. /package/{src → dist}/commands/pr/default.md +0 -0
@@ -1,68 +0,0 @@
1
- import { runPythonSnippet, emitJsonError } from "../../lib/python-helper.mjs";
2
-
3
- const USAGE = `okstra plan-validate — verify an approved-plan file has a recognised approval marker
4
-
5
- Usage:
6
- okstra plan-validate <plan-path>
7
-
8
- Output: JSON { ok: true, planPath } on success.
9
- On failure: { ok: false, reason } with non-zero exit code.
10
-
11
- Replaces the \`from okstra_ctl.run import _validate_approved_plan\` heredoc
12
- pattern. Use this in flows that need to confirm a plan was approved
13
- without invoking the full prepare_task_bundle pipeline.
14
- `;
15
-
16
- function parseArgs(args) {
17
- const positional = args.filter((a) => !a.startsWith("--"));
18
- const unknown = args.filter((a) => a.startsWith("--"));
19
- if (unknown.length) throw new Error(`unknown argument '${unknown[0]}'`);
20
- if (positional.length !== 1) {
21
- throw new Error("expected exactly one positional argument: <plan-path>");
22
- }
23
- return { planPath: positional[0] };
24
- }
25
-
26
- const SCRIPT = `
27
- import json, sys
28
- from okstra_ctl.run import _validate_approved_plan, PrepareError
29
-
30
- path = sys.argv[1]
31
- try:
32
- _validate_approved_plan(path)
33
- except PrepareError as e:
34
- print(json.dumps({"ok": False, "stage": "validation", "reason": str(e), "planPath": path}))
35
- sys.exit(1)
36
-
37
- print(json.dumps({"ok": True, "planPath": path}))
38
- `;
39
-
40
- export async function run(args) {
41
- if (args.includes("--help") || args.includes("-h")) {
42
- process.stdout.write(USAGE);
43
- return 0;
44
- }
45
- let opts;
46
- try {
47
- opts = parseArgs(args);
48
- } catch (err) {
49
- process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
50
- return 2;
51
- }
52
-
53
- const result = await runPythonSnippet({
54
- script: SCRIPT,
55
- args: [opts.planPath],
56
- });
57
-
58
- if (result.code !== 0 && !result.stdout.trim()) {
59
- emitJsonError({
60
- stage: "python",
61
- reason: `python invocation failed: ${result.stderr.trim() || "no output"}`,
62
- });
63
- return 1;
64
- }
65
-
66
- process.stdout.write(result.stdout);
67
- return result.code === 0 ? 0 : result.code;
68
- }
@@ -1,208 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { join } from "node:path";
4
-
5
- import { runEnsureInstalled } from "../lifecycle/install.mjs";
6
- import { runPythonModule } from "../../lib/python-helper.mjs";
7
- import { resolvePaths } from "../../lib/paths.mjs";
8
- import { resolveRuntime } from "../../lib/host-registry-client.mjs";
9
-
10
- const USAGE = `okstra run — host-aware okstra execution front door
11
-
12
- Usage:
13
- okstra run [<host-id-or-alias>] --project-root <dir> \\
14
- --project-id <id> --task-group <tg> --task-id <tid> --task-type <type> \\
15
- [--lead-runtime auto|<host-id-or-alias>] [--yes]
16
-
17
- The leading word selects the lead and is an alias for --lead-runtime, so
18
- 'okstra run codex' starts a Codex lead. Naming a lead starts that CLI with the
19
- prepared prompt; 'external' instead orchestrates an all-CLI run through okstra
20
- team. Starting a lead whose CLI sandboxes itself asks for confirmation first,
21
- which --yes answers.
22
- `;
23
-
24
- function flagValue(args, flag) {
25
- const equals = args.find((arg) => arg.startsWith(`${flag}=`));
26
- if (equals) return equals.slice(flag.length + 1);
27
- const index = args.indexOf(flag);
28
- return index >= 0 ? args[index + 1] : "";
29
- }
30
-
31
- export function positionalRuntime(args) {
32
- const first = args[0];
33
- return !first || first.startsWith("-") ? "" : first;
34
- }
35
-
36
- export function requestedRuntimeFromArgs(args) {
37
- return flagValue(args, "--lead-runtime") || positionalRuntime(args) || "auto";
38
- }
39
-
40
- export function withoutRuntimeSelection(args) {
41
- const rest = positionalRuntime(args) ? args.slice(1) : args;
42
- const out = [];
43
- for (let i = 0; i < rest.length; i += 1) {
44
- const arg = rest[i];
45
- if (arg === "--lead-runtime") {
46
- i += 1;
47
- continue;
48
- }
49
- if (arg.startsWith("--lead-runtime=")) continue;
50
- out.push(arg);
51
- }
52
- return out;
53
- }
54
-
55
- export function extractLabel(stdout, label) {
56
- const prefix = `${label}:`;
57
- const line = String(stdout || "").split("\n").find((item) => item.startsWith(prefix));
58
- return line ? line.slice(prefix.length).trim() : "";
59
- }
60
-
61
- function projectRootFromArgs(args) {
62
- return flagValue(args, "--project-root");
63
- }
64
-
65
- function renderArgs(args, resolution) {
66
- return [
67
- "--lead-runtime", resolution.resolvedRuntime,
68
- "--lead-runtime-request", resolution.requestedRuntime,
69
- "--runtime-resolution-json", JSON.stringify(resolution),
70
- ...withoutRuntimeSelection(args),
71
- ];
72
- }
73
-
74
- export function buildRunPlan({ args, paths, resolution, runManifestPath = "" }) {
75
- void paths;
76
- const projectRoot = projectRootFromArgs(args);
77
- if (resolution.launchMode === "team") {
78
- return {
79
- ok: true,
80
- kind: "team",
81
- reason: resolution.reason,
82
- commands: [
83
- { name: "render-bundle", args: renderArgs(args, resolution), capture: true },
84
- { name: "team dispatch", args: ["dispatch", "--project-root", projectRoot, "--run-manifest", runManifestPath], capture: false },
85
- { name: "team await", args: ["await", "--project-root", projectRoot, "--run-manifest", runManifestPath], capture: false },
86
- ],
87
- };
88
- }
89
-
90
- if (resolution.launchMode === "lead") {
91
- return {
92
- ok: true,
93
- kind: "launch-lead",
94
- reason: resolution.reason,
95
- // Handed to okstra.sh, which owns input collection and the launch. Only
96
- // the runtime is decided here; everything else is passed through so the
97
- // launcher can prompt for whatever is still missing.
98
- // --launch-only: open the host and stop. Task inputs are collected by the
99
- // okstra-run skill inside the session, which is how the Claude Code path
100
- // has always worked — demanding a task id out here asks for it before the
101
- // user has a session to pick one in.
102
- commands: [
103
- {
104
- name: "launcher",
105
- args: [
106
- "--launch-only",
107
- "--lead-runtime", resolution.resolvedRuntime,
108
- ...withoutRuntimeSelection(args),
109
- ],
110
- capture: false,
111
- },
112
- ],
113
- };
114
- }
115
-
116
- return { ok: false, reason: `unsupported launch mode: ${resolution.launchMode}`, commands: [] };
117
- }
118
-
119
- async function ensureRuntime(requestedRuntime) {
120
- return await runEnsureInstalled(["--runtime", requestedRuntime, "-q"]);
121
- }
122
-
123
- async function runRenderCommand(command, paths) {
124
- const result = await runPythonModule({
125
- module: "okstra_ctl.run",
126
- args: ["--workspace-root", paths.workspace, "--render-only", ...command.args],
127
- stdio: "capture",
128
- });
129
- process.stdout.write(result.stdout);
130
- if (result.stderr) process.stderr.write(result.stderr);
131
- return result;
132
- }
133
-
134
- async function launchLead(command, paths) {
135
- // okstra.sh already collects missing task inputs, prepares the bundle, asks
136
- // about a sandbox waiver, and execs the lead. Reimplementing any of that here
137
- // would give the two front doors separate answers to the same questions —
138
- // most visibly, this one had no way to ask for a task id and simply forwarded
139
- // the gap to python's argument parser.
140
- const launcher = join(paths.bin, "okstra.sh");
141
- if (!existsSync(launcher)) {
142
- process.stderr.write(
143
- `error: launcher not found at ${launcher} — run 'okstra install'\n`,
144
- );
145
- return 1;
146
- }
147
- const started = spawnSync(launcher, command.args, { stdio: "inherit" });
148
- if (started.error) {
149
- process.stderr.write(`error: could not start the launcher: ${started.error.message}\n`);
150
- return 1;
151
- }
152
- return started.status ?? 1;
153
- }
154
-
155
- async function runTeam(args) {
156
- const { run: runTeamCommand } = await import("./team.mjs");
157
- return await runTeamCommand(args);
158
- }
159
-
160
- export async function run(args) {
161
- if (args.includes("--help") || args.includes("-h")) {
162
- process.stdout.write(USAGE);
163
- return 0;
164
- }
165
-
166
- const paths = await resolvePaths();
167
- const requestedRuntime = requestedRuntimeFromArgs(args);
168
- const resolution = await resolveRuntime({
169
- requestedRuntime,
170
- command: "run",
171
- env: process.env,
172
- capabilities: { tmuxAvailable: Boolean(process.env.TMUX) },
173
- });
174
- if (!resolution.ok) {
175
- process.stderr.write(`error: ${resolution.reason}\n`);
176
- return 2;
177
- }
178
-
179
- const firstPlan = buildRunPlan({ args, paths, resolution });
180
- if (!firstPlan.ok) {
181
- process.stderr.write(`error: ${firstPlan.reason}\n`);
182
- return 2;
183
- }
184
-
185
- const ensureCode = await ensureRuntime(requestedRuntime);
186
- if (ensureCode !== 0) return ensureCode;
187
-
188
- if (firstPlan.kind === "launch-lead") {
189
- return await launchLead(firstPlan.commands[0], paths);
190
- }
191
-
192
- const render = firstPlan.commands[0];
193
- const prepared = await runRenderCommand(render, paths);
194
- if (prepared.code !== 0) return prepared.code ?? 1;
195
-
196
- const runManifestPath = extractLabel(prepared.stdout, "okstra run manifest");
197
- if (!runManifestPath) {
198
- process.stderr.write("error: render output did not include 'okstra run manifest:'\n");
199
- return 1;
200
- }
201
-
202
- const plan = buildRunPlan({ args, paths, resolution, runManifestPath });
203
- for (const command of plan.commands.slice(1)) {
204
- const code = await runTeam(command.args);
205
- if (code !== 0) return code;
206
- }
207
- return 0;
208
- }
@@ -1,167 +0,0 @@
1
- import { mkdtempSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
-
5
- import { runPythonModule } from "../../lib/python-helper.mjs";
6
- import { resolvePaths } from "../../lib/paths.mjs";
7
-
8
- const USAGE = `okstra wizard — interactive okstra-run input collector
9
-
10
- Used by the okstra-run skill to drive the per-step prompt loop. Each
11
- subcommand round-trips a JSON state file held by the skill.
12
-
13
- Subcommands:
14
- new-state-file print a fresh absolute state-file path on stdout (no I/O on the file itself)
15
- init seed a fresh wizard state and emit the first prompt
16
- step submit an answer (or fetch the current prompt) and emit next
17
- render-args emit the final --flag/value map for 'okstra render-bundle'
18
- confirmation emit the multi-line confirmation echo block
19
- outcome emit render args, persistence actions, and confirmation text
20
-
21
- Usage:
22
- okstra wizard new-state-file
23
- okstra wizard init --state-file <path> --project-root <p> --project-id <id> --host-runtime <runtime> \\
24
- --entry-mode current-session --available-function <semantic-name>
25
- okstra wizard step --state-file <path> (--answer <value> | --no-submit)
26
- okstra wizard render-args --state-file <path>
27
- okstra wizard confirmation --state-file <path>
28
- okstra wizard outcome --state-file <path>
29
-
30
- 'init' auto-fills --workspace-root from 'okstra paths --field workspace',
31
- so callers do not pass it.
32
-
33
- All subcommands emit a single JSON object on stdout. On validation failure
34
- 'step' returns {ok:false, error, current} so the skill can re-prompt.
35
- `;
36
-
37
- // Only the flags listed here are boolean; every other wizard flag takes a
38
- // value, so the token after it is always its value — even free-text answers
39
- // that begin with "--". A heuristic that rejects "--"-prefixed values would
40
- // make legitimate directive/base-ref answers unsubmittable. The inline
41
- // "--key=value" form lets callers pass any value (including empty)
42
- // unambiguously.
43
- const BOOLEAN_FLAGS = new Set(["no-submit"]);
44
-
45
- export function parseFlags(args) {
46
- const out = {};
47
- const setFlag = (key, value) => {
48
- if (key === "available-function") {
49
- out[key] = [...(out[key] ?? []), value];
50
- return;
51
- }
52
- out[key] = value;
53
- };
54
- for (let i = 0; i < args.length; i += 1) {
55
- const a = args[i];
56
- if (!a.startsWith("--")) {
57
- throw new Error(`unexpected positional argument: ${a}`);
58
- }
59
- const eq = a.indexOf("=");
60
- if (eq !== -1) {
61
- setFlag(a.slice(2, eq), a.slice(eq + 1));
62
- continue;
63
- }
64
- const key = a.slice(2);
65
- if (BOOLEAN_FLAGS.has(key)) {
66
- out[key] = true;
67
- continue;
68
- }
69
- if (i + 1 >= args.length) {
70
- throw new Error(`flag --${key} requires a value`);
71
- }
72
- setFlag(key, args[i + 1]);
73
- i += 1;
74
- }
75
- return out;
76
- }
77
-
78
- export function buildPythonArgs(sub, flags, workspaceRoot = "") {
79
- const pyArgs = [sub, "--state-file", flags["state-file"]];
80
- if (sub === "init") {
81
- pyArgs.push("--workspace-root", workspaceRoot);
82
- pyArgs.push("--project-root", flags["project-root"]);
83
- pyArgs.push("--project-id", flags["project-id"]);
84
- if (flags["host-runtime"]) {
85
- pyArgs.push("--host-runtime", flags["host-runtime"]);
86
- }
87
- for (const value of flags["available-function"] ?? []) {
88
- pyArgs.push("--available-function", value);
89
- }
90
- pyArgs.push("--entry-mode", flags["entry-mode"] ?? "current-session");
91
- } else if (sub === "step") {
92
- if (flags["no-submit"]) {
93
- pyArgs.push("--no-submit");
94
- }
95
- if (flags.answer !== undefined) {
96
- pyArgs.push("--answer", flags.answer);
97
- }
98
- }
99
- return pyArgs;
100
- }
101
-
102
- export async function run(args) {
103
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
104
- process.stdout.write(USAGE);
105
- return args.length === 0 ? 2 : 0;
106
- }
107
-
108
- const [sub, ...rest] = args;
109
- if (!["new-state-file", "init", "step", "render-args", "confirmation", "outcome"].includes(sub)) {
110
- process.stderr.write(`error: unknown wizard subcommand '${sub}'\n\n${USAGE}`);
111
- return 2;
112
- }
113
-
114
- if (sub === "new-state-file") {
115
- if (rest.length > 0) {
116
- process.stderr.write("error: new-state-file takes no arguments\n");
117
- return 2;
118
- }
119
- const dir = mkdtempSync(join(tmpdir(), "okstra-wizard-"));
120
- process.stdout.write(join(dir, "state.json") + "\n");
121
- return 0;
122
- }
123
-
124
- let flags;
125
- try {
126
- flags = parseFlags(rest);
127
- } catch (err) {
128
- process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
129
- return 2;
130
- }
131
-
132
- if (!flags["state-file"]) {
133
- process.stderr.write("error: --state-file is required\n");
134
- return 2;
135
- }
136
-
137
- let workspaceRoot = "";
138
- if (sub === "init") {
139
- if (!flags["project-root"] || !flags["project-id"]) {
140
- process.stderr.write("error: init requires --project-root and --project-id\n");
141
- return 2;
142
- }
143
- const paths = await resolvePaths();
144
- workspaceRoot = paths.workspace;
145
- }
146
- const pyArgs = buildPythonArgs(sub, flags, workspaceRoot);
147
-
148
- const result = await runPythonModule({
149
- module: "okstra_ctl.wizard",
150
- args: pyArgs,
151
- stdio: "capture",
152
- });
153
-
154
- if (result.code !== 0 && !result.stdout.trim()) {
155
- process.stdout.write(
156
- JSON.stringify(
157
- { ok: false, stage: "python", reason: result.stderr.trim() || "no output" },
158
- null,
159
- 2,
160
- ) + "\n",
161
- );
162
- return 1;
163
- }
164
-
165
- process.stdout.write(result.stdout);
166
- return result.code === 0 ? 0 : result.code;
167
- }
@@ -1,98 +0,0 @@
1
- import { runPythonSnippet, emitJsonError } from "../../lib/python-helper.mjs";
2
-
3
- const USAGE = `okstra stage-map — dump a task's implementation-planning Stage Map + done stages
4
-
5
- Usage:
6
- okstra stage-map <task-key> task-key is project-id:task-group:task-id
7
- okstra stage-map <task-key> --cwd <dir> Resolve PROJECT_ROOT from <dir>
8
- okstra stage-map <task-key> --project <dir> Use <dir> directly as PROJECT_ROOT
9
-
10
- Output: JSON { ok, taskKey, taskRoot, state, sourcePlanPath, stages:[…], doneStages:[int], planning:{…} }.
11
- Each stage row carries stage_number, title, depends_on, step_count and exit_contract_summary; a
12
- schema-v2 report adds that stage's sliceValue, acceptance and exitContract.
13
- planning carries the report's task-level rows — rollbackStrategy, validationChecklist,
14
- crossProjectDependencies, dependencyMigrationRisk, recommendedOption — so a consumer renders the
15
- plan instead of re-summarising the report body. Both are absent for a schema-v1 report.
16
- stages is [] when no implementation-planning Stage Map exists.
17
- `;
18
-
19
- function parseArgs(args) {
20
- const opts = { cwd: process.cwd(), projectRoot: "", taskKey: "" };
21
- const positional = [];
22
- for (let i = 0; i < args.length; i++) {
23
- const a = args[i];
24
- if (a === "--cwd") {
25
- opts.cwd = args[++i];
26
- if (!opts.cwd) throw new Error("--cwd requires a path");
27
- } else if (a === "--project") {
28
- opts.projectRoot = args[++i];
29
- if (!opts.projectRoot) throw new Error("--project requires a path");
30
- } else if (a === "--json") {
31
- // JSON is always emitted; accept the flag for parity with sibling commands.
32
- } else if (a.startsWith("--")) {
33
- throw new Error(`unknown argument '${a}'`);
34
- } else {
35
- positional.push(a);
36
- }
37
- }
38
- if (positional.length !== 1) {
39
- throw new Error("expected exactly one positional argument: <task-key>");
40
- }
41
- opts.taskKey = positional[0];
42
- return opts;
43
- }
44
-
45
- const SCRIPT = `
46
- import json, sys
47
- from pathlib import Path
48
- from okstra_project import (
49
- resolve_project_root, stage_map_read_side_snapshot, ResolverError, StateError,
50
- )
51
-
52
- explicit, cwd, task_key = sys.argv[1], sys.argv[2], sys.argv[3]
53
-
54
- try:
55
- pr = resolve_project_root(explicit_root=explicit, cwd=cwd)
56
- except ResolverError as e:
57
- print(json.dumps({"ok": False, "stage": "resolve", "reason": str(e)}))
58
- sys.exit(2)
59
-
60
- try:
61
- snapshot = stage_map_read_side_snapshot(Path(pr), task_key)
62
- except StateError as e:
63
- print(json.dumps({
64
- "ok": False,
65
- "stage": getattr(e, "stage", None) or "stage_map",
66
- "reason": str(e),
67
- }))
68
- sys.exit(1)
69
-
70
- print(json.dumps({"ok": True, **snapshot}, ensure_ascii=False, indent=2))
71
- `;
72
-
73
- export async function run(args) {
74
- if (args.includes("--help") || args.includes("-h")) {
75
- process.stdout.write(USAGE);
76
- return 0;
77
- }
78
- let opts;
79
- try {
80
- opts = parseArgs(args);
81
- } catch (err) {
82
- process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
83
- return 2;
84
- }
85
- const result = await runPythonSnippet({
86
- script: SCRIPT,
87
- args: [opts.projectRoot, opts.cwd, opts.taskKey],
88
- });
89
- if (result.code !== 0 && !result.stdout.trim()) {
90
- emitJsonError({
91
- stage: "python",
92
- reason: `python invocation failed: ${result.stderr.trim() || "no output"}`,
93
- });
94
- return 1;
95
- }
96
- process.stdout.write(result.stdout);
97
- return result.code === 0 ? 0 : result.code;
98
- }
@@ -1,97 +0,0 @@
1
- import { runPythonSnippet, emitJsonError } from "../../lib/python-helper.mjs";
2
-
3
- const USAGE = `okstra task-list — list okstra tasks registered in this project
4
-
5
- Usage:
6
- okstra task-list Resolve PROJECT_ROOT from cwd, list tasks
7
- okstra task-list --cwd <dir> Start resolution from <dir> instead of cwd
8
- okstra task-list --project <dir> Use <dir> directly as PROJECT_ROOT
9
- okstra task-list --task-type <type> Filter by taskType
10
- okstra task-list --latest-run-status <s> Filter by latestRunStatus
11
- okstra task-list --task-group <group> Filter by taskGroup
12
- okstra task-list --limit <N> Keep the first N (catalog is updatedAt desc)
13
-
14
- Output: JSON { ok, projectRoot, tasks: [...], latest: {...}|null }.
15
- Filters are AND-combined and all optional.
16
-
17
- Replaces the common pattern of loading okstra_project and calling
18
- list_project_tasks + read_latest_task from a python heredoc.
19
- `;
20
-
21
- function parseArgs(args) {
22
- const opts = { cwd: process.cwd(), projectRoot: "", taskType: "", latestRunStatus: "", taskGroup: "", limit: "" };
23
- const valued = {
24
- "--cwd": "cwd", "--project": "projectRoot", "--task-type": "taskType",
25
- "--latest-run-status": "latestRunStatus", "--task-group": "taskGroup", "--limit": "limit",
26
- };
27
- for (let i = 0; i < args.length; i++) {
28
- const a = args[i];
29
- const key = valued[a];
30
- if (!key) throw new Error(`unknown argument '${a}'`);
31
- const v = args[++i];
32
- if (v === undefined || v === "") throw new Error(`${a} requires a value`);
33
- opts[key] = v;
34
- }
35
- return opts;
36
- }
37
-
38
- const SCRIPT = `
39
- import json, sys
40
- from pathlib import Path
41
- from okstra_project import (
42
- list_project_tasks, read_latest_task,
43
- resolve_project_root, ResolverError,
44
- )
45
-
46
- explicit = sys.argv[1]
47
- cwd = sys.argv[2]
48
- task_type = sys.argv[3] or None
49
- latest_run_status = sys.argv[4] or None
50
- task_group = sys.argv[5] or None
51
- limit = int(sys.argv[6]) if sys.argv[6] else None
52
- try:
53
- pr = resolve_project_root(explicit_root=explicit, cwd=cwd)
54
- except ResolverError as e:
55
- print(json.dumps({"ok": False, "stage": "resolve", "reason": str(e)}))
56
- sys.exit(2)
57
-
58
- pr_path = Path(pr)
59
- print(json.dumps({
60
- "ok": True,
61
- "projectRoot": str(pr_path),
62
- "tasks": list_project_tasks(
63
- pr_path, task_type=task_type, latest_run_status=latest_run_status,
64
- task_group=task_group, limit=limit),
65
- "latest": read_latest_task(pr_path),
66
- }, default=str))
67
- `;
68
-
69
- export async function run(args) {
70
- if (args.includes("--help") || args.includes("-h")) {
71
- process.stdout.write(USAGE);
72
- return 0;
73
- }
74
- let opts;
75
- try {
76
- opts = parseArgs(args);
77
- } catch (err) {
78
- process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
79
- return 2;
80
- }
81
-
82
- const result = await runPythonSnippet({
83
- script: SCRIPT,
84
- args: [opts.projectRoot, opts.cwd, opts.taskType, opts.latestRunStatus, opts.taskGroup, opts.limit],
85
- });
86
-
87
- if (result.code !== 0 && !result.stdout.trim()) {
88
- emitJsonError({
89
- stage: "python",
90
- reason: `python invocation failed: ${result.stderr.trim() || "no output"}`,
91
- });
92
- return 1;
93
- }
94
-
95
- process.stdout.write(result.stdout);
96
- return result.code === 0 ? 0 : result.code;
97
- }