okstra 0.173.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 (402) 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/dist/commands/execute/team.mjs +56 -0
  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/dist/commands/execute/worktree-status.mjs +115 -0
  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/dist/commands/report/finalize.mjs +64 -0
  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 +17 -3
  232. package/docs/architecture.md +12 -22
  233. package/docs/cli.md +29 -8
  234. package/docs/container.md +1 -1
  235. package/docs/contributor-change-matrix.md +3 -3
  236. package/docs/project-structure-overview.md +29 -20
  237. package/docs/task-process/README.md +3 -1
  238. package/docs/task-process/implementation-planning.md +2 -2
  239. package/docs/task-process/implementation.md +1 -1
  240. package/package.json +11 -5
  241. package/runtime/BUILD.json +2 -2
  242. package/runtime/agents/workers/claude-worker.md +3 -2
  243. package/runtime/agents/workers/report-writer-worker.md +3 -1
  244. package/runtime/agents/workers/translator-worker.md +3 -1
  245. package/runtime/bin/lib/okstra/cli.sh +12 -0
  246. package/runtime/bin/lib/okstra/globals.sh +4 -1
  247. package/runtime/bin/lib/okstra/usage.sh +4 -4
  248. package/runtime/bin/okstra-error-log.py +27 -0
  249. package/runtime/bin/okstra-provider-exec.py +245 -16
  250. package/runtime/bin/okstra-trace-cleanup.sh +58 -129
  251. package/runtime/bin/okstra.sh +10 -0
  252. package/runtime/prompts/lead/adapters/cmux.md +2 -0
  253. package/runtime/prompts/lead/convergence.md +27 -18
  254. package/runtime/prompts/lead/okstra-lead-contract.md +4 -2
  255. package/runtime/prompts/lead/plan-body-verification.md +13 -6
  256. package/runtime/prompts/lead/report-writer.md +6 -6
  257. package/runtime/prompts/lead/team-contract.md +1 -1
  258. package/runtime/prompts/profiles/_common-contract.md +2 -2
  259. package/runtime/prompts/profiles/_implementation-executor.md +2 -0
  260. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  261. package/runtime/prompts/profiles/change-impact-analysis.md +16 -0
  262. package/runtime/prompts/profiles/error-analysis.md +21 -1
  263. package/runtime/prompts/profiles/feature-analysis.md +16 -0
  264. package/runtime/prompts/profiles/final-verification.md +16 -0
  265. package/runtime/prompts/profiles/implementation-option-selection.md +16 -0
  266. package/runtime/prompts/profiles/implementation-planning.md +32 -9
  267. package/runtime/prompts/profiles/implementation.md +17 -1
  268. package/runtime/prompts/profiles/improvement-discovery.md +16 -0
  269. package/runtime/prompts/profiles/project-analysis.md +16 -0
  270. package/runtime/prompts/profiles/release-handoff.md +5 -1
  271. package/runtime/prompts/profiles/requirements-discovery.md +20 -0
  272. package/runtime/prompts/wizard/prompts.ko.json +18 -0
  273. package/runtime/python/okstra_ctl/adapters/dispatch/__init__.py +1 -6
  274. package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +8 -0
  275. package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +8 -0
  276. package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
  277. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +2 -2
  278. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +25 -5
  279. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
  280. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +4 -1
  281. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +4 -4
  282. package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
  283. package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +2 -2
  284. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +79 -11
  285. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +100 -25
  286. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +59 -14
  287. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +55 -9
  288. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +51 -12
  289. package/runtime/python/okstra_ctl/agent_activity.py +5 -1
  290. package/runtime/python/okstra_ctl/agent_invocation.py +608 -14
  291. package/runtime/python/okstra_ctl/agent_prompt_cli.py +249 -50
  292. package/runtime/python/okstra_ctl/application/resolve_assignment.py +53 -12
  293. package/runtime/python/okstra_ctl/assignment_environment.py +102 -0
  294. package/runtime/python/okstra_ctl/assignment_resolver.py +790 -0
  295. package/runtime/python/okstra_ctl/attempt_evidence.py +342 -0
  296. package/runtime/python/okstra_ctl/conformance.py +68 -0
  297. package/runtime/python/okstra_ctl/convergence.py +409 -3
  298. package/runtime/python/okstra_ctl/convergence_engine.py +248 -15
  299. package/runtime/python/okstra_ctl/convergence_store.py +170 -1
  300. package/runtime/python/okstra_ctl/dispatch_core.py +1181 -102
  301. package/runtime/python/okstra_ctl/dispatch_state.py +835 -22
  302. package/runtime/python/okstra_ctl/doctor.py +16 -2
  303. package/runtime/python/okstra_ctl/domain/host.py +32 -1
  304. package/runtime/python/okstra_ctl/domain/provider.py +212 -6
  305. package/runtime/python/okstra_ctl/domain/role.py +125 -0
  306. package/runtime/python/okstra_ctl/domain/wizard/interaction.py +13 -0
  307. package/runtime/python/okstra_ctl/domain/worker_exec.py +39 -1
  308. package/runtime/python/okstra_ctl/domain/worker_role.py +13 -3
  309. package/runtime/python/okstra_ctl/domain/worker_stream.py +24 -0
  310. package/runtime/python/okstra_ctl/error_log_write.py +9 -0
  311. package/runtime/python/okstra_ctl/error_report.py +21 -1
  312. package/runtime/python/okstra_ctl/execution_identity.py +529 -0
  313. package/runtime/python/okstra_ctl/execution_manifest.py +1281 -0
  314. package/runtime/python/okstra_ctl/execution_mutation_audit.py +619 -0
  315. package/runtime/python/okstra_ctl/final_report_schema.py +5 -4
  316. package/runtime/python/okstra_ctl/index.py +6 -2
  317. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
  318. package/runtime/python/okstra_ctl/legacy_model_selection.py +490 -0
  319. package/runtime/python/okstra_ctl/model_cli.py +278 -0
  320. package/runtime/python/okstra_ctl/model_defaults.py +46 -0
  321. package/runtime/python/okstra_ctl/model_discovery.py +26 -7
  322. package/runtime/python/okstra_ctl/model_pool.py +501 -0
  323. package/runtime/python/okstra_ctl/models.py +47 -27
  324. package/runtime/python/okstra_ctl/mutation_recovery.py +293 -0
  325. package/runtime/python/okstra_ctl/pane_reclaim.py +13 -22
  326. package/runtime/python/okstra_ctl/pane_title.py +151 -0
  327. package/runtime/python/okstra_ctl/ports/host_model.py +48 -17
  328. package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
  329. package/runtime/python/okstra_ctl/registry/provider_registry.py +8 -4
  330. package/runtime/python/okstra_ctl/render.py +78 -10
  331. package/runtime/python/okstra_ctl/render_final_report.py +34 -19
  332. package/runtime/python/okstra_ctl/report_contract.py +39 -1
  333. package/runtime/python/okstra_ctl/report_finalize.py +84 -9
  334. package/runtime/python/okstra_ctl/report_html/render.py +1 -0
  335. package/runtime/python/okstra_ctl/role_requirements.py +217 -0
  336. package/runtime/python/okstra_ctl/run.py +1250 -260
  337. package/runtime/python/okstra_ctl/run_index_row.py +7 -1
  338. package/runtime/python/okstra_ctl/schema_excerpt.py +1 -1
  339. package/runtime/python/okstra_ctl/scope_provenance.py +1 -1
  340. package/runtime/python/okstra_ctl/session.py +69 -12
  341. package/runtime/python/okstra_ctl/team.py +51 -25
  342. package/runtime/python/okstra_ctl/time_report.py +38 -4
  343. package/runtime/python/okstra_ctl/tmux.py +19 -149
  344. package/runtime/python/okstra_ctl/usage_identity.py +86 -0
  345. package/runtime/python/okstra_ctl/usage_report.py +15 -3
  346. package/runtime/python/okstra_ctl/wizard.py +1253 -62
  347. package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
  348. package/runtime/python/okstra_ctl/worker_request.py +9 -1
  349. package/runtime/python/okstra_ctl/worker_runner.py +130 -5
  350. package/runtime/python/okstra_ctl/workers.py +7 -5
  351. package/runtime/python/okstra_ctl/worktree.py +69 -3
  352. package/runtime/python/okstra_ctl/write_policy.py +571 -0
  353. package/runtime/python/okstra_token_usage/cli.py +1 -1
  354. package/runtime/python/okstra_token_usage/collect.py +66 -6
  355. package/runtime/schemas/convergence-groups-v2.0.schema.json +128 -0
  356. package/runtime/schemas/execution-manifest-v2.schema.json +340 -0
  357. package/runtime/schemas/final-report-v2.0.schema.json +25 -0
  358. package/runtime/skills/okstra-run/SKILL.md +9 -9
  359. package/runtime/skills/okstra-setup/references/project-config.md +11 -0
  360. package/runtime/templates/report-writer-prompt-preamble.md +2 -0
  361. package/runtime/templates/reports/final-report-v2.template.md +7 -1
  362. package/runtime/templates/reports/html/base.template.html +21 -0
  363. package/runtime/templates/reports/html/i18n/en.json +4 -0
  364. package/runtime/templates/reports/html/i18n/ko.json +4 -0
  365. package/runtime/templates/reports/settings.template.json +0 -24
  366. package/runtime/templates/worker-prompt-preamble.md +6 -2
  367. package/runtime/validators/lib/fixtures.sh +98 -33
  368. package/runtime/validators/validate-implementation-plan-stages.py +63 -3
  369. package/runtime/validators/validate-run.py +443 -508
  370. package/runtime/validators/validate_session_conformance.py +26 -8
  371. package/runtime/bin/okstra-subagent-reclaim.sh +0 -26
  372. package/runtime/schemas/final-report-v1.0.schema.json +0 -6366
  373. package/runtime/templates/reports/final-report.template.md +0 -1258
  374. package/src/cli-registry.mjs +0 -532
  375. package/src/commands/execute/codex-dispatch.mjs +0 -10
  376. package/src/commands/execute/plan-items.mjs +0 -9
  377. package/src/commands/execute/plan-validate.mjs +0 -68
  378. package/src/commands/execute/run.mjs +0 -208
  379. package/src/commands/execute/team.mjs +0 -63
  380. package/src/commands/execute/wizard.mjs +0 -167
  381. package/src/commands/inspect/stage-map.mjs +0 -98
  382. package/src/commands/inspect/task-list.mjs +0 -97
  383. package/src/commands/inspect/task-show.mjs +0 -100
  384. package/src/commands/lifecycle/check-project.mjs +0 -187
  385. package/src/commands/lifecycle/config.mjs +0 -385
  386. package/src/commands/lifecycle/doctor.mjs +0 -308
  387. package/src/commands/lifecycle/install.mjs +0 -1172
  388. package/src/commands/lifecycle/paths.mjs +0 -104
  389. package/src/commands/lifecycle/preflight.mjs +0 -125
  390. package/src/commands/lifecycle/setup.mjs +0 -333
  391. package/src/commands/lifecycle/uninstall.mjs +0 -279
  392. package/src/commands/memory/memory.mjs +0 -524
  393. package/src/commands/pr/pr.mjs +0 -261
  394. package/src/commands/report/finalize.mjs +0 -64
  395. package/src/lib/host-registry-client.mjs +0 -176
  396. package/src/lib/paths.mjs +0 -86
  397. package/src/lib/proc.mjs +0 -31
  398. package/src/lib/python-helper.mjs +0 -142
  399. package/src/lib/runtime-manifest.mjs +0 -70
  400. package/src/lib/skill-catalog.mjs +0 -53
  401. package/src/lib/version.mjs +0 -20
  402. /package/{src → dist}/commands/pr/default.md +0 -0
@@ -1,261 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import { execFileSync } from "node:child_process";
3
- import { fileURLToPath } from "node:url";
4
- import { dirname, join, resolve } from "node:path";
5
- import { createInterface } from "node:readline/promises";
6
- import { stdin as input, stdout as output } from "node:process";
7
- import { resolveOkstraHome } from "../../lib/paths.mjs";
8
-
9
- const NAME_RE = /^[A-Za-z0-9._-]+$/;
10
- const DEFAULT_TEMPLATE_PATH = join(
11
- dirname(fileURLToPath(import.meta.url)),
12
- "default.md",
13
- );
14
-
15
- const USAGE = `okstra pr — PR body templates and PR generation
16
-
17
- Usage:
18
- okstra pr template list [--json]
19
- okstra pr template show <name|default> [--json]
20
- okstra pr template add --name <name> (--content <text> | --file <path>) [--yes]
21
- okstra pr template path
22
- okstra pr branches [--json]
23
- okstra pr gen --base <ref> [--template <name|default>] [--json]
24
- `;
25
-
26
- export function isValidTemplateName(name) {
27
- return (
28
- typeof name === "string" &&
29
- NAME_RE.test(name) &&
30
- name !== "." &&
31
- name !== ".."
32
- );
33
- }
34
-
35
- export function templateDir(home) {
36
- return join(home, "template", "pr");
37
- }
38
-
39
- export async function listTemplates(home) {
40
- let entries;
41
- try {
42
- entries = await fs.readdir(templateDir(home));
43
- } catch (err) {
44
- if (err.code === "ENOENT") return [];
45
- throw err;
46
- }
47
- return entries
48
- .filter((f) => f.endsWith(".md"))
49
- .map((f) => f.slice(0, -3))
50
- .sort();
51
- }
52
-
53
- async function readBundledDefault() {
54
- return fs.readFile(DEFAULT_TEMPLATE_PATH, "utf8");
55
- }
56
-
57
- export async function readTemplate(home, name) {
58
- if (!name || name === "default") return readBundledDefault();
59
- if (!isValidTemplateName(name)) throw new Error(`invalid template name: ${name}`);
60
- try {
61
- return await fs.readFile(join(templateDir(home), `${name}.md`), "utf8");
62
- } catch (err) {
63
- if (err.code === "ENOENT") return readBundledDefault();
64
- throw err;
65
- }
66
- }
67
-
68
- export async function addTemplate(home, name, content, opts = {}) {
69
- if (!isValidTemplateName(name)) throw new Error(`invalid template name: ${name}`);
70
- const dir = templateDir(home);
71
- await fs.mkdir(dir, { recursive: true });
72
- const target = join(dir, `${name}.md`);
73
- if (!opts.force) {
74
- try {
75
- await fs.access(target);
76
- throw new Error(`template exists: ${name} (use --yes to overwrite)`);
77
- } catch (err) {
78
- if (err.code !== "ENOENT") throw err;
79
- }
80
- }
81
- await fs.writeFile(target, content, "utf8");
82
- return target;
83
- }
84
-
85
- function takeValue(args, i, flag) {
86
- const v = args[i + 1];
87
- if (!v || v.startsWith("--")) throw new Error(`${flag} requires a value`);
88
- return v;
89
- }
90
-
91
- async function readAddContent(opts) {
92
- if (opts.content !== null) return opts.content;
93
- if (opts.file !== null) return fs.readFile(resolve(opts.file), "utf8");
94
- throw new Error("template add requires --content or --file");
95
- }
96
-
97
- async function confirm(question) {
98
- const rl = createInterface({ input, output });
99
- try {
100
- const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();
101
- return answer === "y" || answer === "yes";
102
- } finally {
103
- rl.close();
104
- }
105
- }
106
-
107
- async function cmdTemplate(args, home) {
108
- const sub = args[0];
109
- const rest = args.slice(1);
110
- const json = rest.includes("--json");
111
- if (sub === "list") {
112
- const names = await listTemplates(home);
113
- if (json) output.write(JSON.stringify({ templates: names }) + "\n");
114
- else output.write(names.length ? names.join("\n") + "\n" : "(no templates)\n");
115
- return 0;
116
- }
117
- if (sub === "show") {
118
- const name = rest.find((a) => !a.startsWith("--"));
119
- if (!name) throw new Error("template show requires a name");
120
- const body = await readTemplate(home, name);
121
- output.write(json ? JSON.stringify({ name, body }) + "\n" : body);
122
- return 0;
123
- }
124
- if (sub === "path") {
125
- output.write(templateDir(home) + "\n");
126
- return 0;
127
- }
128
- if (sub === "add") {
129
- const opts = { name: null, content: null, file: null, yes: false };
130
- for (let i = 0; i < rest.length; i++) {
131
- const flag = rest[i];
132
- if (flag === "--name") opts.name = takeValue(rest, i++, flag);
133
- else if (flag === "--content") opts.content = takeValue(rest, i++, flag);
134
- else if (flag === "--file") opts.file = takeValue(rest, i++, flag);
135
- else if (flag === "--yes") opts.yes = true;
136
- else throw new Error(`unknown flag ${flag}`);
137
- }
138
- if (!opts.name) throw new Error("template add requires --name");
139
- const content = await readAddContent(opts);
140
- const dir = templateDir(home);
141
- const target = join(dir, `${opts.name}.md`);
142
- let force = opts.yes;
143
- if (!force && isValidTemplateName(opts.name)) {
144
- let exists = false;
145
- try {
146
- await fs.access(target);
147
- exists = true;
148
- } catch (err) {
149
- if (err.code !== "ENOENT") throw err;
150
- }
151
- if (exists) {
152
- if (!process.stdin.isTTY) {
153
- throw new Error(`template exists: ${opts.name} (use --yes to overwrite)`);
154
- }
155
- force = await confirm(`Overwrite existing template ${opts.name}?`);
156
- if (!force) { output.write("aborted\n"); return 1; }
157
- }
158
- }
159
- const saved = await addTemplate(home, opts.name, content, { force: true });
160
- output.write(`saved: ${saved}\n`);
161
- return 0;
162
- }
163
- throw new Error(`unknown template subcommand: ${sub ?? "(none)"}`);
164
- }
165
-
166
- function tryGit(cwd, args) {
167
- try {
168
- return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
169
- } catch {
170
- return null;
171
- }
172
- }
173
-
174
- export function recommendBranches(cwd) {
175
- const currentBranch = tryGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
176
- if (currentBranch === null) return { currentBranch: null, recommended: [] };
177
- const ordered = [];
178
- const remoteDefault = tryGit(cwd, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
179
- if (remoteDefault) {
180
- const bare = remoteDefault.replace(/^origin\//, "");
181
- if (tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${bare}^{commit}`]) !== null) ordered.push(bare);
182
- else if (tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${remoteDefault}^{commit}`]) !== null) ordered.push(remoteDefault);
183
- }
184
- for (const b of ["main", "master", "develop"]) {
185
- const local = tryGit(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${b}`]);
186
- if (local !== null) ordered.push(b);
187
- }
188
- const recent = tryGit(cwd, [
189
- "for-each-ref", "--sort=-committerdate", "--format=%(refname:short)", "refs/heads",
190
- ]);
191
- if (recent) ordered.push(...recent.split("\n").filter(Boolean));
192
- const recommended = [];
193
- for (const b of ordered) {
194
- if (b && b !== currentBranch && !recommended.includes(b)) recommended.push(b);
195
- }
196
- return { currentBranch, recommended };
197
- }
198
-
199
- function cmdBranches(args, cwd) {
200
- const json = args.includes("--json");
201
- const r = recommendBranches(cwd);
202
- if (json) output.write(JSON.stringify(r) + "\n");
203
- else output.write((r.recommended.join("\n") || "(no branches)") + "\n");
204
- return 0;
205
- }
206
-
207
- export async function buildGenBundle({ cwd, home, base, templateName }) {
208
- if (!base) throw new Error("gen requires --base");
209
- const verified = tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${base}^{commit}`]);
210
- if (verified === null) throw new Error(`base ref not found: ${base}`);
211
- const currentBranch = tryGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
212
- const logRaw = tryGit(cwd, [
213
- "log", "--reverse", "--format=%h%x09%s", `${base}..HEAD`,
214
- ]) || "";
215
- const commits = logRaw
216
- .split("\n")
217
- .filter(Boolean)
218
- .map((line) => {
219
- const tab = line.indexOf("\t");
220
- return { hash: line.slice(0, tab), subject: line.slice(tab + 1) };
221
- });
222
- const diffStat = tryGit(cwd, ["diff", "--stat", `${base}...HEAD`]) || "";
223
- const template = await readTemplate(home, templateName);
224
- const resolvedName = templateName && templateName !== "default"
225
- ? templateName
226
- : "default";
227
- return { base, currentBranch, templateName: resolvedName, template, commits, diffStat };
228
- }
229
-
230
- async function cmdGen(args, cwd, home) {
231
- const opts = { base: null, template: "default" };
232
- for (let i = 0; i < args.length; i++) {
233
- const flag = args[i];
234
- if (flag === "--base") opts.base = takeValue(args, i++, flag);
235
- else if (flag === "--template") opts.template = takeValue(args, i++, flag);
236
- else if (flag === "--json") continue;
237
- else throw new Error(`unknown flag ${flag}`);
238
- }
239
- const bundle = await buildGenBundle({ cwd, home, base: opts.base, templateName: opts.template });
240
- output.write(JSON.stringify(bundle) + "\n");
241
- return 0;
242
- }
243
-
244
- export async function run(args) {
245
- if (args.length === 0 || args.includes("--help")) {
246
- output.write(USAGE);
247
- return 0;
248
- }
249
- const home = resolveOkstraHome();
250
- const sub = args[0];
251
- const rest = args.slice(1);
252
- try {
253
- if (sub === "template") return await cmdTemplate(rest, home);
254
- if (sub === "branches") return cmdBranches(rest, process.cwd());
255
- if (sub === "gen") return await cmdGen(rest, process.cwd(), home);
256
- throw new Error(`unknown pr subcommand: ${sub}`);
257
- } catch (err) {
258
- process.stderr.write(`error: ${err.message}\n`);
259
- return 1;
260
- }
261
- }
@@ -1,64 +0,0 @@
1
- import { runPythonModule } from "../../lib/python-helper.mjs";
2
- import { resolvePaths } from "../../lib/paths.mjs";
3
-
4
- const USAGE = `okstra report-finalize — run the Phase 7 post-report sequence
5
-
6
- Usage:
7
- okstra report-finalize --project-root <dir> --run-manifest <path> \\
8
- --report <final-report-<task-type>-<seq>.md> [--team-state <path>]
9
-
10
- Runs the four Phase 7 steps in their contractual order against one final-report:
11
-
12
- 1. token-usage substitute real token/cost numbers into the data.json
13
- 2. render-views write the schema-v2 task-specific *.html sibling; v1
14
- keeps the legacy conditional interactive view
15
- 3. spawn-followups turn section 4 rows into task stubs
16
- 4. validate-run validate the finished run artifacts
17
-
18
- Every step is idempotent, so re-running after a fixed failure is safe. The
19
- sequence stops at the first non-zero exit and reports which step failed.
20
-
21
- This is the same code path the Codex lead adapter runs automatically after its
22
- report-writer completes, so a Claude-led and a Codex-led run finalize
23
- identically.
24
-
25
- --workspace-root is owned by this command.
26
- `;
27
-
28
- const OWNED_FLAGS = new Set(["--workspace-root"]);
29
-
30
- function isOwnedFlag(arg) {
31
- if (OWNED_FLAGS.has(arg)) return true;
32
- return [...OWNED_FLAGS].some((flag) => arg.startsWith(`${flag}=`));
33
- }
34
-
35
- export function buildReportFinalizeArgs(args, paths) {
36
- return ["--workspace-root", paths.workspace, ...args];
37
- }
38
-
39
- export async function run(args) {
40
- if (args.includes("--help") || args.includes("-h")) {
41
- process.stdout.write(USAGE);
42
- return 0;
43
- }
44
- if (args.length === 0) {
45
- process.stdout.write(USAGE);
46
- return 2;
47
- }
48
-
49
- const forbidden = args.find(isOwnedFlag);
50
- if (forbidden) {
51
- process.stderr.write(
52
- `error: ${forbidden} is set by 'okstra report-finalize' itself — remove it from your args\n`,
53
- );
54
- return 2;
55
- }
56
-
57
- const paths = await resolvePaths();
58
- const result = await runPythonModule({
59
- module: "okstra_ctl.report_finalize",
60
- args: buildReportFinalizeArgs(args, paths),
61
- stdio: "inherit-stdout",
62
- });
63
- return result.code;
64
- }
@@ -1,176 +0,0 @@
1
- import { homedir } from "node:os";
2
-
3
- import { runPythonModule } from "./python-helper.mjs";
4
-
5
- export const RUNTIME_AUTO = "auto";
6
-
7
- const HOST_REQUEST_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
8
- const PLAIN_TEXT_INPUT = "plain_text_input";
9
-
10
- export class HostRegistryClientError extends Error {
11
- constructor(message) {
12
- super(message);
13
- this.name = "HostRegistryClientError";
14
- }
15
- }
16
-
17
- async function callHosts(runPython, args) {
18
- const result = await runPython({
19
- module: "okstra_ctl.entrypoints.hosts",
20
- args,
21
- stdio: "capture",
22
- });
23
- if (result.code !== 0) {
24
- const detail = String(result.stderr || "").trim() || `Python exited ${result.code}`;
25
- throw new HostRegistryClientError(detail);
26
- }
27
- const stdout = String(result.stdout || "").trim();
28
- if (!stdout) throw new HostRegistryClientError("host registry returned empty stdout");
29
- try {
30
- return JSON.parse(stdout);
31
- } catch (error) {
32
- throw new HostRegistryClientError(`host registry returned invalid JSON: ${error.message}`);
33
- }
34
- }
35
-
36
- function resolutionContext(env = {}, capabilities = {}) {
37
- return {
38
- env: { OKSTRA_RUNTIME_HOST: String(env?.OKSTRA_RUNTIME_HOST ?? "") },
39
- capabilities: {
40
- claudeSkillHandoff: capabilities?.claudeSkillHandoff === true,
41
- tmuxAvailable: capabilities?.tmuxAvailable === true,
42
- },
43
- };
44
- }
45
-
46
- export function createHostRegistryClient({ runPython = runPythonModule } = {}) {
47
- return {
48
- async catalog() {
49
- return await callHosts(runPython, ["catalog", "--json"]);
50
- },
51
- async resolveHostRuntime({ requestedRuntime, command, env, capabilities }) {
52
- return await callHosts(runPython, [
53
- "resolve",
54
- "--requested", requestedRuntime,
55
- "--command", command,
56
- "--context-json", JSON.stringify(resolutionContext(env, capabilities)),
57
- ]);
58
- },
59
- async probeHost({
60
- hostRuntime,
61
- entryMode,
62
- projectRoot,
63
- homeDir,
64
- availableFunctions = [],
65
- }) {
66
- const args = [
67
- "probe",
68
- "--host", hostRuntime,
69
- "--entry-mode", entryMode,
70
- "--project-root", projectRoot,
71
- "--home-dir", homeDir,
72
- ];
73
- for (const availableFunction of availableFunctions) {
74
- args.push("--available-function", availableFunction);
75
- }
76
- return await callHosts(runPython, args);
77
- },
78
- };
79
- }
80
-
81
- const hostRegistryClient = createHostRegistryClient();
82
-
83
- export function normalizeHostRequest(value) {
84
- const runtime = String(value ?? "").trim() || RUNTIME_AUTO;
85
- if (!HOST_REQUEST_PATTERN.test(runtime)) {
86
- throw new Error(
87
- `invalid runtime '${runtime}' (expected auto, all, or a lowercase host ID)`,
88
- );
89
- }
90
- return runtime;
91
- }
92
-
93
- function failedResolution(requestedRuntime, error) {
94
- return {
95
- ok: false,
96
- requestedRuntime,
97
- resolvedRuntime: null,
98
- launchMode: null,
99
- installTargets: [],
100
- host: "unknown",
101
- confidence: "low",
102
- reason: error.message,
103
- fallbackFrom: null,
104
- warnings: [],
105
- };
106
- }
107
-
108
- function catalogResolution(catalog) {
109
- const hosts = Array.isArray(catalog?.hosts) ? catalog.hosts : [];
110
- const catalogHostIds = hosts.map((host) => host.id);
111
- const installTargets = Array.from(new Set(
112
- hosts.flatMap((host) => host.install_targets ?? host.installTargets ?? []),
113
- )).sort();
114
- return {
115
- ok: true,
116
- requestedRuntime: "all",
117
- resolvedRuntime: "all",
118
- launchMode: "catalog",
119
- installTargets,
120
- catalogHostIds,
121
- host: "explicit",
122
- confidence: "high",
123
- reason: "All registered host runtimes requested.",
124
- fallbackFrom: null,
125
- warnings: [],
126
- };
127
- }
128
-
129
- export async function loadHostCatalog() {
130
- return await hostRegistryClient.catalog();
131
- }
132
-
133
- export async function resolveHostRuntime(options) {
134
- return await hostRegistryClient.resolveHostRuntime(options);
135
- }
136
-
137
- export async function probeHost(options) {
138
- return await hostRegistryClient.probeHost(options);
139
- }
140
-
141
- export async function resolveRuntime({
142
- requestedRuntime = RUNTIME_AUTO,
143
- command = "run",
144
- env = {},
145
- capabilities = {},
146
- } = {}) {
147
- const request = normalizeHostRequest(requestedRuntime);
148
- try {
149
- if (request === "all") return catalogResolution(await loadHostCatalog());
150
- return await resolveHostRuntime({
151
- requestedRuntime: request,
152
- command,
153
- env,
154
- capabilities,
155
- });
156
- } catch (error) {
157
- if (!(error instanceof HostRegistryClientError)) throw error;
158
- return failedResolution(request, error);
159
- }
160
- }
161
-
162
- export async function checkRuntimeReadiness({
163
- runtime,
164
- projectRoot,
165
- homeDir = homedir(),
166
- hostRegistryClient = { probeHost },
167
- }) {
168
- if (!runtime) return { runtime: "auto", status: "ready", checks: [] };
169
- return await hostRegistryClient.probeHost({
170
- hostRuntime: runtime,
171
- entryMode: "current-session",
172
- projectRoot,
173
- homeDir,
174
- availableFunctions: [PLAIN_TEXT_INPUT],
175
- });
176
- }
package/src/lib/paths.mjs DELETED
@@ -1,86 +0,0 @@
1
- import { homedir, tmpdir } from "node:os";
2
- import { join } from "node:path";
3
- import { existsSync } from "node:fs";
4
- import { getPackageRoot, getPackageVersion } from "./version.mjs";
5
-
6
- function isStaleTmpHome(p) {
7
- // tests/conftest.py creates the isolated home as `<tmp_path>/.okstra-isolated`
8
- // under the system temp dir. Only a deleted one (env leaked, dir gone) heals;
9
- // a soon-to-be-created `.okstra` temp home or a custom home is left untouched.
10
- if (!p.endsWith("/.okstra-isolated")) return false;
11
- const roots = [tmpdir(), "/tmp", "/private/tmp", "/var/folders", "/private/var/folders"];
12
- return roots.some(
13
- (r) => r && (p === r || p.startsWith(r.replace(/\/+$/, "") + "/")),
14
- );
15
- }
16
-
17
- // Resolve OKSTRA_HOME, healing a leaked value: when it points at a missing
18
- // system-temp path (e.g. a deleted pytest-isolated home), warn and fall back
19
- // to ~/.okstra instead of operating on the dead directory.
20
- export function resolveOkstraHome() {
21
- const raw = process.env.OKSTRA_HOME?.trim();
22
- if (!raw) return join(homedir(), ".okstra");
23
- if (!existsSync(raw) && isStaleTmpHome(raw)) {
24
- process.stderr.write(
25
- `⚠ OKSTRA_HOME=${raw} points to a missing temp dir (leaked test value); falling back to ~/.okstra\n`,
26
- );
27
- return join(homedir(), ".okstra");
28
- }
29
- return raw;
30
- }
31
-
32
- export async function resolvePaths() {
33
- const home = resolveOkstraHome();
34
- const pkgRoot = getPackageRoot();
35
- const devLink = await readSimpleFile(join(home, "dev-link"));
36
- const runtimeRoot = devLink || join(pkgRoot, "runtime");
37
- return {
38
- agents: join(runtimeRoot, "agents"),
39
- workspace: runtimeRoot,
40
- pythonpath: join(home, "lib", "python"),
41
- bin: join(home, "bin"),
42
- home,
43
- package: await getPackageVersion(),
44
- version: await readSimpleFile(join(home, "version")),
45
- "dev-link": devLink || "",
46
- };
47
- }
48
-
49
- function workspacePythonpath(paths) {
50
- const candidates = [
51
- join(paths.workspace, "python"),
52
- join(paths.workspace, "scripts"),
53
- ];
54
- return candidates.find((candidate) => existsSync(candidate)) || "";
55
- }
56
-
57
- // Compose the PYTHONPATH spawned python3 subprocesses should see.
58
- //
59
- // Precedence (first wins):
60
- // 1. process.env.PYTHONPATH (user override — e.g. in-repo `PYTHONPATH=scripts`
61
- // for dev work without re-running `okstra install`).
62
- // 2. The package/dev-link workspace runtime selected by `okstra paths`.
63
- // 3. The installed user-runtime path (~/.okstra/lib/python).
64
- //
65
- // This is a colon-joined string suitable for direct assignment into the child
66
- // process env. Empty segments are dropped so a missing env var does not produce
67
- // a leading ':' (which Python treats as 'current directory').
68
- export function buildPythonpath(paths) {
69
- const fragments = [
70
- process.env.PYTHONPATH,
71
- workspacePythonpath(paths),
72
- paths.pythonpath,
73
- ].filter(
74
- (s) => typeof s === "string" && s.length > 0,
75
- );
76
- return fragments.join(":");
77
- }
78
-
79
- async function readSimpleFile(path) {
80
- try {
81
- const { readFile } = await import("node:fs/promises");
82
- return (await readFile(path, "utf8")).trim();
83
- } catch {
84
- return "";
85
- }
86
- }
package/src/lib/proc.mjs DELETED
@@ -1,31 +0,0 @@
1
- // Shared filesystem / subprocess helpers used by the Node command modules.
2
- // Extracted to one place so a fix lands once instead of in each command file.
3
- import { spawn } from "node:child_process";
4
- import { promises as fs } from "node:fs";
5
-
6
- export async function fileExists(p) {
7
- try {
8
- await fs.access(p);
9
- return true;
10
- } catch {
11
- return false;
12
- }
13
- }
14
-
15
- // Run `cmd args`, capturing stdout/stderr. `env` holds *additional* vars that
16
- // are merged over the inherited process.env. Never rejects — failures resolve
17
- // with { code: -1, stderr: <message> }.
18
- export function runProcess(cmd, args, env = {}) {
19
- return new Promise((resolve) => {
20
- const child = spawn(cmd, args, {
21
- stdio: ["ignore", "pipe", "pipe"],
22
- env: { ...process.env, ...env },
23
- });
24
- let stdout = "";
25
- let stderr = "";
26
- child.stdout.on("data", (b) => (stdout += b.toString()));
27
- child.stderr.on("data", (b) => (stderr += b.toString()));
28
- child.on("error", (err) => resolve({ code: -1, stdout, stderr: err.message }));
29
- child.on("close", (code) => resolve({ code, stdout, stderr }));
30
- });
31
- }