okstra 0.186.7 → 0.187.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (541) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-registry.d.mts +88 -1
  3. package/dist/cli-registry.mjs +68 -111
  4. package/dist/cli-registry.mjs.map +1 -1
  5. package/dist/commands/execute/render-bundle.mjs +0 -1
  6. package/dist/commands/execute/render-bundle.mjs.map +1 -1
  7. package/dist/commands/execute/run.mjs +8 -3
  8. package/dist/commands/execute/run.mjs.map +1 -1
  9. package/dist/commands/lifecycle/check-project.mjs +1 -14
  10. package/dist/commands/lifecycle/check-project.mjs.map +1 -1
  11. package/dist/commands/lifecycle/config.mjs +38 -40
  12. package/dist/commands/lifecycle/config.mjs.map +1 -1
  13. package/dist/commands/lifecycle/doctor.d.mts +22 -7
  14. package/dist/commands/lifecycle/doctor.mjs +77 -49
  15. package/dist/commands/lifecycle/doctor.mjs.map +1 -1
  16. package/dist/commands/lifecycle/install.d.mts +12 -10
  17. package/dist/commands/lifecycle/install.mjs +104 -39
  18. package/dist/commands/lifecycle/install.mjs.map +1 -1
  19. package/dist/commands/lifecycle/paths.mjs +8 -3
  20. package/dist/commands/lifecycle/paths.mjs.map +1 -1
  21. package/dist/commands/lifecycle/preflight.mjs +2 -1
  22. package/dist/commands/lifecycle/preflight.mjs.map +1 -1
  23. package/dist/commands/lifecycle/setup.mjs +22 -36
  24. package/dist/commands/lifecycle/setup.mjs.map +1 -1
  25. package/dist/commands/lifecycle/uninstall.d.mts +4 -2
  26. package/dist/commands/lifecycle/uninstall.mjs +59 -15
  27. package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
  28. package/dist/commands/memory/memory.mjs +7 -1
  29. package/dist/commands/memory/memory.mjs.map +1 -1
  30. package/dist/lib/helper-scripts.d.mts +1 -1
  31. package/dist/lib/helper-scripts.mjs +10 -18
  32. package/dist/lib/helper-scripts.mjs.map +1 -1
  33. package/dist/lib/host-config.d.mts +72 -0
  34. package/dist/lib/host-config.mjs +404 -0
  35. package/dist/lib/host-config.mjs.map +1 -0
  36. package/dist/lib/host-registry-client.d.mts +2 -2
  37. package/dist/lib/host-registry-client.mjs +0 -3
  38. package/dist/lib/host-registry-client.mjs.map +1 -1
  39. package/dist/lib/install-assets.d.mts +1 -0
  40. package/dist/lib/install-assets.mjs +4 -0
  41. package/dist/lib/install-assets.mjs.map +1 -1
  42. package/dist/lib/proc.d.mts +2 -0
  43. package/dist/lib/proc.mjs +12 -0
  44. package/dist/lib/proc.mjs.map +1 -1
  45. package/dist/lib/python-command.d.mts +2 -0
  46. package/dist/lib/python-command.mjs +52 -0
  47. package/dist/lib/python-command.mjs.map +1 -0
  48. package/dist/lib/python-helper.d.mts +2 -5
  49. package/dist/lib/python-helper.mjs +3 -52
  50. package/dist/lib/python-helper.mjs.map +1 -1
  51. package/dist/lib/runtime-payload.d.mts +23 -0
  52. package/dist/lib/runtime-payload.mjs +57 -0
  53. package/dist/lib/runtime-payload.mjs.map +1 -0
  54. package/dist/lib/types.d.mts +24 -13
  55. package/docs/architecture/storage-model.md +21 -5
  56. package/docs/architecture.md +37 -36
  57. package/docs/cli.md +55 -76
  58. package/docs/coding-rules.md +295 -0
  59. package/docs/container.md +10 -36
  60. package/docs/contributor-change-matrix.md +1 -1
  61. package/docs/for-ai/skills/okstra-code-review.md +0 -1
  62. package/docs/for-ai/skills/okstra-container-build.md +8 -41
  63. package/docs/for-ai/skills/okstra-inspect.md +4 -4
  64. package/docs/for-ai/skills/okstra-manager.md +2 -2
  65. package/docs/for-ai/skills/okstra-rollup.md +0 -1
  66. package/docs/for-ai/skills/okstra-run.md +3 -3
  67. package/docs/for-ai/skills/okstra-user-response.md +0 -1
  68. package/docs/performance-improvement-plan-v2.md +1 -1
  69. package/docs/project-structure-overview.md +62 -62
  70. package/docs/task-process/README.md +3 -3
  71. package/docs/task-process/common-flow.md +1 -1
  72. package/docs/task-process/error-analysis.md +3 -3
  73. package/docs/task-process/implementation-planning.md +3 -1
  74. package/docs/task-process/release-handoff.md +1 -1
  75. package/package.json +3 -2
  76. package/runtime/BUILD.json +2 -2
  77. package/runtime/agents/workers/claude-worker.md +6 -11
  78. package/runtime/agents/workers/report-writer-worker.md +1 -1
  79. package/runtime/bin/lib/okstra/cli.sh +4 -0
  80. package/runtime/bin/lib/okstra/globals.sh +2 -0
  81. package/runtime/bin/lib/okstra/interactive.sh +26 -173
  82. package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
  83. package/runtime/bin/lib/okstra/usage.sh +3 -3
  84. package/runtime/bin/okstra-compact-reminder.sh +1 -5
  85. package/runtime/bin/okstra-error-log.py +19 -2
  86. package/runtime/bin/okstra-import-check.py +26 -0
  87. package/runtime/bin/okstra-inject-report-index.py +5 -4
  88. package/runtime/bin/okstra-provider-exec.py +22 -17
  89. package/runtime/bin/okstra-render-final-report.py +16 -6
  90. package/runtime/bin/okstra-render-report-views.py +25 -18
  91. package/runtime/bin/okstra-report-translate.py +30 -18
  92. package/runtime/bin/okstra-spawn-followups.py +4 -0
  93. package/runtime/bin/okstra-token-usage.py +3 -0
  94. package/runtime/bin/okstra.sh +4 -2
  95. package/runtime/bin/okstra_bootstrap.py +58 -0
  96. package/runtime/prompts/coding-preflight/overview.md +1 -1
  97. package/runtime/prompts/duties/planning-worker.md +1 -1
  98. package/runtime/prompts/launch.template.md +35 -9
  99. package/runtime/prompts/lead/convergence.md +96 -87
  100. package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
  101. package/runtime/prompts/lead/plan-body-verification.md +65 -46
  102. package/runtime/prompts/lead/report-writer.md +34 -4
  103. package/runtime/prompts/lead/team-contract.md +4 -1
  104. package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
  105. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  106. package/runtime/prompts/profiles/_common-contract.md +3 -3
  107. package/runtime/prompts/profiles/_coverage-critic.md +1 -1
  108. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
  109. package/runtime/prompts/profiles/_implementation-executor.md +3 -1
  110. package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
  111. package/runtime/prompts/profiles/error-analysis.md +4 -3
  112. package/runtime/prompts/profiles/final-verification.md +2 -2
  113. package/runtime/prompts/profiles/implementation-planning.md +22 -17
  114. package/runtime/prompts/profiles/implementation.md +3 -2
  115. package/runtime/prompts/profiles/requirements-discovery.md +2 -1
  116. package/runtime/prompts/wizard/prompts.ko.json +29 -8
  117. package/runtime/python/okstra_ctl/__init__.py +6 -27
  118. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
  119. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
  120. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
  121. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +40 -22
  122. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -21
  123. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
  124. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
  125. package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
  126. package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
  127. package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
  128. package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +12 -1
  129. package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
  130. package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
  131. package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
  132. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +215 -0
  133. package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
  134. package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
  135. package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
  136. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +408 -0
  137. package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
  138. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
  139. package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
  140. package/runtime/python/okstra_ctl/approval_decisions.py +260 -8
  141. package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
  142. package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
  143. package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
  144. package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
  145. package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
  146. package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
  147. package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
  148. package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
  149. package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
  150. package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
  151. package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
  152. package/runtime/python/okstra_ctl/cmux.py +38 -31
  153. package/runtime/python/okstra_ctl/code_review_target.py +163 -1
  154. package/runtime/python/okstra_ctl/conformance.py +23 -0
  155. package/runtime/python/okstra_ctl/container.py +38 -421
  156. package/runtime/python/okstra_ctl/context_cost.py +16 -2
  157. package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
  158. package/runtime/python/okstra_ctl/convergence.py +101 -15
  159. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
  160. package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
  161. package/runtime/python/okstra_ctl/convergence_store.py +5 -29
  162. package/runtime/python/okstra_ctl/design_prep.py +108 -12
  163. package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
  164. package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
  165. package/runtime/python/okstra_ctl/dispatch_core.py +102 -25
  166. package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
  167. package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
  168. package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
  169. package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -1
  170. package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
  171. package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
  172. package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
  173. package/runtime/python/okstra_ctl/error_log_core.py +1 -1
  174. package/runtime/python/okstra_ctl/error_report.py +14 -0
  175. package/runtime/python/okstra_ctl/error_zip.py +18 -2
  176. package/runtime/python/okstra_ctl/execution_identity.py +100 -7
  177. package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
  178. package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
  179. package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
  180. package/runtime/python/okstra_ctl/final_report_schema.py +90 -16
  181. package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
  182. package/runtime/python/okstra_ctl/handoff.py +24 -1
  183. package/runtime/python/okstra_ctl/ids.py +6 -16
  184. package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
  185. package/runtime/python/okstra_ctl/implementation_options.py +25 -11
  186. package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
  187. package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
  188. package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
  189. package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
  190. package/runtime/python/okstra_ctl/index.py +2 -2
  191. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
  192. package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
  193. package/runtime/python/okstra_ctl/json_boundary.py +10 -0
  194. package/runtime/python/okstra_ctl/listing.py +0 -91
  195. package/runtime/python/okstra_ctl/locks.py +5 -19
  196. package/runtime/python/okstra_ctl/log_report.py +14 -0
  197. package/runtime/python/okstra_ctl/manager_cli.py +22 -3
  198. package/runtime/python/okstra_ctl/manager_launch.py +4 -8
  199. package/runtime/python/okstra_ctl/material.py +2 -2
  200. package/runtime/python/okstra_ctl/migrate.py +23 -1
  201. package/runtime/python/okstra_ctl/model_cli.py +19 -5
  202. package/runtime/python/okstra_ctl/model_discovery.py +46 -47
  203. package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
  204. package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
  205. package/runtime/python/okstra_ctl/model_io/references.py +370 -0
  206. package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
  207. package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
  208. package/runtime/python/okstra_ctl/model_pool.py +10 -6
  209. package/runtime/python/okstra_ctl/models.py +8 -8
  210. package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
  211. package/runtime/python/okstra_ctl/next_phase.py +121 -69
  212. package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
  213. package/runtime/python/okstra_ctl/pane_title.py +11 -8
  214. package/runtime/python/okstra_ctl/path_hints.py +36 -11
  215. package/runtime/python/okstra_ctl/paths.py +76 -8
  216. package/runtime/python/okstra_ctl/plan_items.py +132 -16
  217. package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
  218. package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
  219. package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
  220. package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
  221. package/runtime/python/okstra_ctl/prepare_error.py +20 -0
  222. package/runtime/python/okstra_ctl/prior_planning.py +157 -0
  223. package/runtime/python/okstra_ctl/profile_show.py +18 -1
  224. package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
  225. package/runtime/python/okstra_ctl/recap.py +22 -1
  226. package/runtime/python/okstra_ctl/reconcile.py +84 -0
  227. package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
  228. package/runtime/python/okstra_ctl/render.py +98 -32
  229. package/runtime/python/okstra_ctl/render_final_report.py +3 -7
  230. package/runtime/python/okstra_ctl/report_assembly.py +297 -7
  231. package/runtime/python/okstra_ctl/report_contract.py +30 -7
  232. package/runtime/python/okstra_ctl/report_finalize.py +206 -15
  233. package/runtime/python/okstra_ctl/report_html/common.py +2 -2
  234. package/runtime/python/okstra_ctl/report_html/render.py +8 -12
  235. package/runtime/python/okstra_ctl/report_language.py +8 -4
  236. package/runtime/python/okstra_ctl/report_narrative.py +90 -3
  237. package/runtime/python/okstra_ctl/report_projections.py +8 -2
  238. package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
  239. package/runtime/python/okstra_ctl/report_translation.py +2 -35
  240. package/runtime/python/okstra_ctl/report_views.py +4 -22
  241. package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
  242. package/runtime/python/okstra_ctl/rollup.py +13 -0
  243. package/runtime/python/okstra_ctl/run.py +639 -138
  244. package/runtime/python/okstra_ctl/run_audit.py +13 -0
  245. package/runtime/python/okstra_ctl/run_index_row.py +0 -12
  246. package/runtime/python/okstra_ctl/seeding.py +21 -11
  247. package/runtime/python/okstra_ctl/sequence.py +1 -1
  248. package/runtime/python/okstra_ctl/session.py +64 -14
  249. package/runtime/python/okstra_ctl/set_work_status.py +18 -0
  250. package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
  251. package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
  252. package/runtime/python/okstra_ctl/stage_map.py +57 -11
  253. package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
  254. package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
  255. package/runtime/python/okstra_ctl/stage_targets.py +3 -12
  256. package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
  257. package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
  258. package/runtime/python/okstra_ctl/task_target.py +4 -16
  259. package/runtime/python/okstra_ctl/team.py +49 -2
  260. package/runtime/python/okstra_ctl/time_report.py +17 -2
  261. package/runtime/python/okstra_ctl/usage_report.py +11 -0
  262. package/runtime/python/okstra_ctl/user_response.py +55 -218
  263. package/runtime/python/okstra_ctl/user_response_values.py +242 -0
  264. package/runtime/python/okstra_ctl/validation_contract.py +3 -0
  265. package/runtime/python/okstra_ctl/verification_target.py +68 -0
  266. package/runtime/python/okstra_ctl/wizard.py +457 -92
  267. package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
  268. package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
  269. package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
  270. package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
  271. package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
  272. package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
  273. package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
  274. package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
  275. package/runtime/python/okstra_ctl/worker_request.py +2 -1
  276. package/runtime/python/okstra_ctl/worker_runner.py +16 -9
  277. package/runtime/python/okstra_ctl/worker_state.py +16 -1
  278. package/runtime/python/okstra_ctl/workflow.py +18 -1
  279. package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
  280. package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
  281. package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
  282. package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
  283. package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
  284. package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
  285. package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
  286. package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
  287. package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
  288. package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
  289. package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
  290. package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
  291. package/runtime/python/okstra_ctl/write_policy.py +90 -213
  292. package/runtime/python/okstra_project/__init__.py +0 -4
  293. package/runtime/python/okstra_project/dirs.py +2 -2
  294. package/runtime/python/okstra_project/phase_pointer.py +84 -0
  295. package/runtime/python/okstra_project/slug.py +24 -0
  296. package/runtime/python/okstra_project/state.py +22 -230
  297. package/runtime/python/okstra_token_usage/claude.py +9 -1
  298. package/runtime/python/okstra_token_usage/cli.py +3 -1
  299. package/runtime/python/okstra_token_usage/collect.py +71 -10
  300. package/runtime/python/okstra_token_usage/cursor.py +2 -0
  301. package/runtime/python/okstra_token_usage/grok.py +1 -5
  302. package/runtime/python/okstra_token_usage/paths.py +26 -0
  303. package/runtime/python/okstra_token_usage/pricing.py +19 -7
  304. package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
  305. package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
  306. package/runtime/schemas/final-report-v2.0.schema.json +9 -26
  307. package/runtime/schemas/final-report-v3.0.schema.json +173 -41
  308. package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
  309. package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
  310. package/runtime/skills/okstra-container-build/SKILL.md +16 -47
  311. package/runtime/skills/okstra-inspect/facets/history.md +1 -1
  312. package/runtime/skills/okstra-inspect/facets/status.md +7 -6
  313. package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
  314. package/runtime/skills/okstra-run/SKILL.md +7 -5
  315. package/runtime/templates/report-writer-prompt-preamble.md +1 -1
  316. package/runtime/templates/reports/brief.template.md +6 -2
  317. package/runtime/templates/reports/error-analysis-input.template.md +2 -0
  318. package/runtime/templates/reports/final-verification-input.template.md +2 -0
  319. package/runtime/templates/reports/implementation-input.template.md +7 -1
  320. package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
  321. package/runtime/templates/reports/quick-input.template.md +2 -0
  322. package/runtime/templates/reports/release-handoff-input.template.md +6 -1
  323. package/runtime/templates/reports/report.js +20 -3
  324. package/runtime/templates/reports/schedule.template.md +2 -0
  325. package/runtime/templates/reports/settings.template.json +0 -10
  326. package/runtime/templates/reports/task-brief.template.md +3 -0
  327. package/runtime/templates/reports/user-response.template.md +7 -3
  328. package/runtime/validators/checks/fixtures-01.py +57 -0
  329. package/runtime/validators/checks/fixtures-02.py +565 -0
  330. package/runtime/validators/checks/runners-01.py +108 -0
  331. package/runtime/validators/checks/validate-assets-01.py +60 -0
  332. package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
  333. package/runtime/validators/checks/validate-tasks-01.py +46 -0
  334. package/runtime/validators/checks/validate-tasks-02.py +85 -0
  335. package/runtime/validators/checks/validate-tasks-03.py +61 -0
  336. package/runtime/validators/checks/validate-tasks-04.py +118 -0
  337. package/runtime/validators/forbidden_actions.py +73 -3
  338. package/runtime/validators/lib/common.sh +5 -0
  339. package/runtime/validators/lib/fixtures.sh +7 -591
  340. package/runtime/validators/lib/paths.sh +13 -0
  341. package/runtime/validators/lib/runners.sh +6 -104
  342. package/runtime/validators/lib/summary.sh +1 -1
  343. package/runtime/validators/lib/validate-assets.sh +6 -56
  344. package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
  345. package/runtime/validators/lib/validate-tasks.sh +9 -294
  346. package/runtime/validators/validate-implementation-plan-stages.py +4 -4
  347. package/runtime/validators/validate-run.py +1369 -2654
  348. package/runtime/validators/validate-workflow.sh +56 -16
  349. package/runtime/validators/validate_improvement_report.py +2 -1
  350. package/runtime/validators/validate_session_conformance.py +295 -49
  351. package/dist/commands/execute/agent-prompt.d.mts +0 -1
  352. package/dist/commands/execute/agent-prompt.mjs +0 -24
  353. package/dist/commands/execute/agent-prompt.mjs.map +0 -1
  354. package/dist/commands/execute/codex-dispatch.d.mts +0 -3
  355. package/dist/commands/execute/codex-dispatch.mjs +0 -6
  356. package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
  357. package/dist/commands/execute/codex-run.d.mts +0 -3
  358. package/dist/commands/execute/codex-run.mjs +0 -62
  359. package/dist/commands/execute/codex-run.mjs.map +0 -1
  360. package/dist/commands/execute/convergence.d.mts +0 -1
  361. package/dist/commands/execute/convergence.mjs +0 -38
  362. package/dist/commands/execute/convergence.mjs.map +0 -1
  363. package/dist/commands/execute/error-log.d.mts +0 -1
  364. package/dist/commands/execute/error-log.mjs +0 -18
  365. package/dist/commands/execute/error-log.mjs.map +0 -1
  366. package/dist/commands/execute/git-reconcile.d.mts +0 -1
  367. package/dist/commands/execute/git-reconcile.mjs +0 -30
  368. package/dist/commands/execute/git-reconcile.mjs.map +0 -1
  369. package/dist/commands/execute/handoff.d.mts +0 -1
  370. package/dist/commands/execute/handoff.mjs +0 -31
  371. package/dist/commands/execute/handoff.mjs.map +0 -1
  372. package/dist/commands/execute/incremental-carry.d.mts +0 -1
  373. package/dist/commands/execute/incremental-carry.mjs +0 -20
  374. package/dist/commands/execute/incremental-carry.mjs.map +0 -1
  375. package/dist/commands/execute/incremental-scope.d.mts +0 -1
  376. package/dist/commands/execute/incremental-scope.mjs +0 -29
  377. package/dist/commands/execute/incremental-scope.mjs.map +0 -1
  378. package/dist/commands/execute/integrate-stages.d.mts +0 -1
  379. package/dist/commands/execute/integrate-stages.mjs +0 -24
  380. package/dist/commands/execute/integrate-stages.mjs.map +0 -1
  381. package/dist/commands/execute/pane-title.d.mts +0 -1
  382. package/dist/commands/execute/pane-title.mjs +0 -20
  383. package/dist/commands/execute/pane-title.mjs.map +0 -1
  384. package/dist/commands/execute/plan-items.d.mts +0 -1
  385. package/dist/commands/execute/plan-items.mjs +0 -9
  386. package/dist/commands/execute/plan-items.mjs.map +0 -1
  387. package/dist/commands/execute/plan-validate.d.mts +0 -1
  388. package/dist/commands/execute/plan-validate.mjs +0 -68
  389. package/dist/commands/execute/plan-validate.mjs.map +0 -1
  390. package/dist/commands/execute/plan-verify.d.mts +0 -1
  391. package/dist/commands/execute/plan-verify.mjs +0 -43
  392. package/dist/commands/execute/plan-verify.mjs.map +0 -1
  393. package/dist/commands/execute/spawn-followups.d.mts +0 -1
  394. package/dist/commands/execute/spawn-followups.mjs +0 -22
  395. package/dist/commands/execute/spawn-followups.mjs.map +0 -1
  396. package/dist/commands/execute/team.d.mts +0 -3
  397. package/dist/commands/execute/team.mjs +0 -66
  398. package/dist/commands/execute/team.mjs.map +0 -1
  399. package/dist/commands/execute/token-usage.d.mts +0 -1
  400. package/dist/commands/execute/token-usage.mjs +0 -19
  401. package/dist/commands/execute/token-usage.mjs.map +0 -1
  402. package/dist/commands/execute/worker-audit-check.d.mts +0 -1
  403. package/dist/commands/execute/worker-audit-check.mjs +0 -34
  404. package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
  405. package/dist/commands/execute/worker-dispatch.d.mts +0 -7
  406. package/dist/commands/execute/worker-dispatch.mjs +0 -64
  407. package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
  408. package/dist/commands/execute/worker-state.d.mts +0 -1
  409. package/dist/commands/execute/worker-state.mjs +0 -28
  410. package/dist/commands/execute/worker-state.mjs.map +0 -1
  411. package/dist/commands/execute/worktree-lookup.d.mts +0 -1
  412. package/dist/commands/execute/worktree-lookup.mjs +0 -92
  413. package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
  414. package/dist/commands/execute/worktree-status.d.mts +0 -1
  415. package/dist/commands/execute/worktree-status.mjs +0 -121
  416. package/dist/commands/execute/worktree-status.mjs.map +0 -1
  417. package/dist/commands/inspect/code-review.d.mts +0 -1
  418. package/dist/commands/inspect/code-review.mjs +0 -32
  419. package/dist/commands/inspect/code-review.mjs.map +0 -1
  420. package/dist/commands/inspect/container.d.mts +0 -1
  421. package/dist/commands/inspect/container.mjs +0 -25
  422. package/dist/commands/inspect/container.mjs.map +0 -1
  423. package/dist/commands/inspect/context-cost.d.mts +0 -1
  424. package/dist/commands/inspect/context-cost.mjs +0 -25
  425. package/dist/commands/inspect/context-cost.mjs.map +0 -1
  426. package/dist/commands/inspect/design-prep.d.mts +0 -1
  427. package/dist/commands/inspect/design-prep.mjs +0 -22
  428. package/dist/commands/inspect/design-prep.mjs.map +0 -1
  429. package/dist/commands/inspect/error-report.d.mts +0 -1
  430. package/dist/commands/inspect/error-report.mjs +0 -25
  431. package/dist/commands/inspect/error-report.mjs.map +0 -1
  432. package/dist/commands/inspect/error-zip.d.mts +0 -1
  433. package/dist/commands/inspect/error-zip.mjs +0 -24
  434. package/dist/commands/inspect/error-zip.mjs.map +0 -1
  435. package/dist/commands/inspect/log-report.d.mts +0 -1
  436. package/dist/commands/inspect/log-report.mjs +0 -26
  437. package/dist/commands/inspect/log-report.mjs.map +0 -1
  438. package/dist/commands/inspect/model-io.d.mts +0 -1
  439. package/dist/commands/inspect/model-io.mjs +0 -25
  440. package/dist/commands/inspect/model-io.mjs.map +0 -1
  441. package/dist/commands/inspect/profile-show.d.mts +0 -1
  442. package/dist/commands/inspect/profile-show.mjs +0 -28
  443. package/dist/commands/inspect/profile-show.mjs.map +0 -1
  444. package/dist/commands/inspect/recap.d.mts +0 -1
  445. package/dist/commands/inspect/recap.mjs +0 -30
  446. package/dist/commands/inspect/recap.mjs.map +0 -1
  447. package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
  448. package/dist/commands/inspect/resolve-task-key.mjs +0 -24
  449. package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
  450. package/dist/commands/inspect/rollup.d.mts +0 -1
  451. package/dist/commands/inspect/rollup.mjs +0 -25
  452. package/dist/commands/inspect/rollup.mjs.map +0 -1
  453. package/dist/commands/inspect/run-audit.d.mts +0 -1
  454. package/dist/commands/inspect/run-audit.mjs +0 -25
  455. package/dist/commands/inspect/run-audit.mjs.map +0 -1
  456. package/dist/commands/inspect/set-work-status.d.mts +0 -1
  457. package/dist/commands/inspect/set-work-status.mjs +0 -29
  458. package/dist/commands/inspect/set-work-status.mjs.map +0 -1
  459. package/dist/commands/inspect/stage-map.d.mts +0 -1
  460. package/dist/commands/inspect/stage-map.mjs +0 -131
  461. package/dist/commands/inspect/stage-map.mjs.map +0 -1
  462. package/dist/commands/inspect/task-list.d.mts +0 -1
  463. package/dist/commands/inspect/task-list.mjs +0 -149
  464. package/dist/commands/inspect/task-list.mjs.map +0 -1
  465. package/dist/commands/inspect/task-show.d.mts +0 -1
  466. package/dist/commands/inspect/task-show.mjs +0 -108
  467. package/dist/commands/inspect/task-show.mjs.map +0 -1
  468. package/dist/commands/inspect/time-report.d.mts +0 -1
  469. package/dist/commands/inspect/time-report.mjs +0 -24
  470. package/dist/commands/inspect/time-report.mjs.map +0 -1
  471. package/dist/commands/inspect/usage-report.d.mts +0 -1
  472. package/dist/commands/inspect/usage-report.mjs +0 -23
  473. package/dist/commands/inspect/usage-report.mjs.map +0 -1
  474. package/dist/commands/inspect/user-response.d.mts +0 -1
  475. package/dist/commands/inspect/user-response.mjs +0 -35
  476. package/dist/commands/inspect/user-response.mjs.map +0 -1
  477. package/dist/commands/inspect/worker-liveness.d.mts +0 -1
  478. package/dist/commands/inspect/worker-liveness.mjs +0 -45
  479. package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
  480. package/dist/commands/lifecycle/contract-check.d.mts +0 -1
  481. package/dist/commands/lifecycle/contract-check.mjs +0 -18
  482. package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
  483. package/dist/commands/lifecycle/migrate.d.mts +0 -1
  484. package/dist/commands/lifecycle/migrate.mjs +0 -30
  485. package/dist/commands/lifecycle/migrate.mjs.map +0 -1
  486. package/dist/commands/lifecycle/model.d.mts +0 -1
  487. package/dist/commands/lifecycle/model.mjs +0 -22
  488. package/dist/commands/lifecycle/model.mjs.map +0 -1
  489. package/dist/commands/manager.d.mts +0 -3
  490. package/dist/commands/manager.mjs +0 -50
  491. package/dist/commands/manager.mjs.map +0 -1
  492. package/dist/commands/report/agent-activity.d.mts +0 -1
  493. package/dist/commands/report/agent-activity.mjs +0 -20
  494. package/dist/commands/report/agent-activity.mjs.map +0 -1
  495. package/dist/commands/report/approval-decision.d.mts +0 -1
  496. package/dist/commands/report/approval-decision.mjs +0 -21
  497. package/dist/commands/report/approval-decision.mjs.map +0 -1
  498. package/dist/commands/report/design-snapshot.d.mts +0 -1
  499. package/dist/commands/report/design-snapshot.mjs +0 -19
  500. package/dist/commands/report/design-snapshot.mjs.map +0 -1
  501. package/dist/commands/report/finalize.d.mts +0 -4
  502. package/dist/commands/report/finalize.mjs +0 -64
  503. package/dist/commands/report/finalize.mjs.map +0 -1
  504. package/dist/commands/report/inject-report-index.d.mts +0 -1
  505. package/dist/commands/report/inject-report-index.mjs +0 -21
  506. package/dist/commands/report/inject-report-index.mjs.map +0 -1
  507. package/dist/commands/report/render-final-report.d.mts +0 -1
  508. package/dist/commands/report/render-final-report.mjs +0 -23
  509. package/dist/commands/report/render-final-report.mjs.map +0 -1
  510. package/dist/commands/report/render-views.d.mts +0 -1
  511. package/dist/commands/report/render-views.mjs +0 -27
  512. package/dist/commands/report/render-views.mjs.map +0 -1
  513. package/dist/commands/report/translate.d.mts +0 -1
  514. package/dist/commands/report/translate.mjs +0 -33
  515. package/dist/commands/report/translate.mjs.map +0 -1
  516. package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
  517. package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
  518. package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
  519. package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
  520. package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
  521. package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
  522. package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
  523. package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
  524. package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
  525. package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
  526. package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
  527. package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
  528. package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
  529. package/runtime/bin/okstra-central.sh +0 -152
  530. package/runtime/bin/okstra-incremental-carry.py +0 -10
  531. package/runtime/bin/okstra-incremental-scope.py +0 -10
  532. package/runtime/bin/okstra-team-reconcile.sh +0 -36
  533. package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
  534. package/runtime/python/okstra_ctl/batch.py +0 -60
  535. package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
  536. package/runtime/python/okstra_ctl/container_registry.py +0 -72
  537. package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
  538. package/runtime/python/okstra_ctl/resolver.py +0 -54
  539. package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
  540. package/runtime/python/okstra_ctl/tmux.py +0 -134
  541. package/runtime/python/okstra_ctl/worktree.py +0 -1099
@@ -1,345 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- _okstra_ctl_rerun() {
4
- local yes="false" dry_run="false" use_filter="false"
5
- local project="all" task_group="all" status="all" since=""
6
- local project_set="false" task_group_set="false"
7
- local max_spawn="${OKSTRA_CTL_MAX_SPAWN:-10}"
8
- local from_stdin="false" use_last="false"
9
- local -a explicit=()
10
- local ignore_brief_drift="false"
11
- while [[ $# -gt 0 ]]; do
12
- case "$1" in
13
- --yes) yes="true"; shift ;;
14
- --dry-run) dry_run="true"; shift ;;
15
- --filter) use_filter="true"; shift ;;
16
- --project) project="$2"; project_set="true"; shift 2 ;;
17
- --task-group) task_group="$2"; task_group_set="true"; shift 2 ;;
18
- --status) status="$2"; shift 2 ;;
19
- --since) since="$2"; shift 2 ;;
20
- --max-spawn) max_spawn="$2"; shift 2 ;;
21
- --ignore-brief-drift) ignore_brief_drift="true"; shift ;;
22
- last) use_last="true"; shift ;;
23
- -) from_stdin="true"; shift ;;
24
- *) explicit+=("$1"); shift ;;
25
- esac
26
- done
27
- # tmux 부재 검사는 실제 spawn 이 일어나는 경우에만. --dry-run 은 CI/최소 환경에서도
28
- # 안전 미리보기를 제공해야 하므로 우회한다.
29
- if [[ "$dry_run" != "true" ]] && ! command -v tmux >/dev/null 2>&1; then
30
- printf 'rerun: tmux is required but not found\n' >&2; exit 2
31
- fi
32
- # 'last' selector 는 부작용 있는 명령이므로 모호한 기본값을 거부한다.
33
- # 사용자는 --project / --task-group 을 반드시 명시해야 한다 ('all' 와일드카드 허용).
34
- if [[ "$use_last" == "true" ]]; then
35
- if [[ "$project_set" != "true" || "$task_group_set" != "true" ]]; then
36
- printf 'rerun last: --project 와 --task-group 을 반드시 지정해 주십시오 (all 와일드카드 명시 가능)\n' >&2
37
- exit 2
38
- fi
39
- fi
40
-
41
- # stdin selector('-') 사용 시 호출자의 파이프 데이터를 미리 읽어 env 로 전달.
42
- # python3 - <<'PY' 는 stdin 을 heredoc 으로 사용하므로 자식 프로세스 안에서는
43
- # sys.stdin 이 EOF 가 되어 caller 의 piped runId 들을 읽을 수 없다.
44
- local stdin_payload=""
45
- if [[ "$from_stdin" == "true" ]]; then
46
- stdin_payload="$(cat)"
47
- fi
48
-
49
- OKSTRA_HOME_RESOLVED="$(okstra_central_home)" \
50
- OKSTRA_CTL_LIB_DIR="$SCRIPT_DIR" \
51
- OKSTRA_SCRIPT="$SCRIPT_DIR/okstra.sh" \
52
- OK_YES="$yes" OK_DRY="$dry_run" OK_FILTER="$use_filter" \
53
- OK_PROJECT="$project" OK_TG="$task_group" OK_STATUS="$status" \
54
- OK_SINCE="$since" OK_MAX="$max_spawn" OK_LAST="$use_last" \
55
- OK_STDIN="$from_stdin" OK_STDIN_DATA="$stdin_payload" \
56
- OK_IGNORE_BRIEF_DRIFT="$ignore_brief_drift" \
57
- OK_EXPLICIT_JSON="$(printf '%s\n' "${explicit[@]:-}" | python3 -c 'import json,sys; print(json.dumps([l.strip() for l in sys.stdin if l.strip()]))')" \
58
- python3 - <<'PY'
59
- import fcntl, hashlib, json, os, subprocess, sys, time
60
- sys.path.insert(0, os.environ["OKSTRA_CTL_LIB_DIR"])
61
- from pathlib import Path
62
- from okstra_ctl import (
63
- expand_selectors, find_row_by_run_id, load_invocation,
64
- predict_next_run_seq, build_run_id, build_tmux_command,
65
- run_id_to_session_name, task_lock_filename, make_batch_id,
66
- write_batch_meta, ResolveError, central_lock,
67
- reserve_run_in_active, remove_reservation,
68
- slugify_task_segment,
69
- )
70
-
71
- home = Path(os.environ["OKSTRA_HOME_RESOLVED"])
72
- explicit = json.loads(os.environ["OK_EXPLICIT_JSON"])
73
- use_filter = os.environ["OK_FILTER"] == "true"
74
- use_last = os.environ["OK_LAST"] == "true"
75
- from_stdin = os.environ["OK_STDIN"] == "true"
76
- max_spawn = int(os.environ["OK_MAX"])
77
- yes = os.environ["OK_YES"] == "true"
78
- dry = os.environ["OK_DRY"] == "true"
79
-
80
- try:
81
- targets = expand_selectors(
82
- home, explicit=explicit, use_filter=use_filter,
83
- project=os.environ["OK_PROJECT"], task_group=os.environ["OK_TG"],
84
- status=os.environ["OK_STATUS"], since=os.environ["OK_SINCE"],
85
- last=use_last, from_stdin=from_stdin,
86
- stdin_data=os.environ.get("OK_STDIN_DATA", ""),
87
- )
88
- except ResolveError as e:
89
- print(f"rerun: {e}", file=sys.stderr); sys.exit(2)
90
-
91
- if not targets:
92
- print("rerun: no targets selected", file=sys.stderr); sys.exit(2)
93
- if len(targets) > max_spawn:
94
- print(f"매칭 결과 {len(targets)}건은 임계({max_spawn})를 초과합니다. "
95
- f"--max-spawn {len(targets)} 로 재실행하거나 선택자를 좁혀 주십시오.",
96
- file=sys.stderr); sys.exit(2)
97
- if len(targets) > 1 and not yes and not dry:
98
- print("rerun targets:")
99
- for t in targets: print(f" - {t}")
100
- print("재실행하려면 --yes 를 추가해 주십시오.", file=sys.stderr); sys.exit(2)
101
-
102
- ignore_brief_drift = os.environ.get("OK_IGNORE_BRIEF_DRIFT") == "true"
103
-
104
- # 현재 okstra-ctl 프로세스의 OKSTRA_HOME / 명시적 ctl-only override 만 base 에
105
- # 둔다. 각 target 의 inv["envOverrides"](원본 run 시점에 캡처된 환경변수) 를
106
- # 로드 시점에 layer 한다.
107
- extra_env_base = {"OKSTRA_HOME": str(home)}
108
- for key in ("OKSTRA_CTL_SKIP_RECONCILE", "OKSTRA_CTL_SKIP_BACKFILL"):
109
- if os.environ.get(key):
110
- extra_env_base[key] = os.environ[key]
111
-
112
-
113
- def _brief_sha256(brief_path):
114
- try:
115
- with open(brief_path, "rb") as f:
116
- return hashlib.sha256(f.read()).hexdigest()
117
- except OSError:
118
- return None
119
-
120
-
121
- def _brief_path_from_argv(argv, cwd, project_root):
122
- """invocation argv 에서 --task-brief 값을 찾아 절대 경로화한다.
123
- okstra.sh resolve_brief_path 의 lookup 순서(cwd-relative 우선,
124
- PROJECT_ROOT fallback) 를 동일하게 mirror 한다 — 그렇지 않으면 사용자가
125
- 프로젝트 밖에서 project-relative --task-brief 로 실행한 run 의 drift
126
- 검사가 'brief missing' 으로 잘못 skip 된다.
127
- """
128
- for i, tok in enumerate(argv):
129
- if tok == "--task-brief" and i + 1 < len(argv):
130
- raw = argv[i + 1]
131
- p = Path(raw)
132
- if p.is_absolute():
133
- return p if p.is_file() else None
134
- cwd_rel = Path(cwd) / p if cwd else None
135
- if cwd_rel and cwd_rel.is_file():
136
- return cwd_rel
137
- root_rel = Path(project_root) / p if project_root else None
138
- if root_rel and root_rel.is_file():
139
- return root_rel
140
- return None
141
- return None
142
-
143
-
144
- batch_id = make_batch_id()
145
- items = []
146
- spawned = skipped = rejected = 0
147
- # 같은 (project, group, task_id, task_type) 에 속한 다중 rerun 이 같은 batch 내에서
148
- # 같은 seq 를 받지 않도록 메모리상 reservation 추적. tmux spawn 후 detached okstra 가
149
- # 디스크에 manifest/report 를 쓰기 전에 락이 풀리므로 filesystem-only 예측은 충돌한다.
150
- batch_reserved = {}
151
- for original in targets:
152
- row = find_row_by_run_id(home, original)
153
- # implementation 은 stage 격리 task-type 이다. 한 run = 런타임에 live
154
- # registry/consumers 상태로 auto-resolve 되는 단일 stage(stage_targets.resolve_effective_stages)
155
- # 이므로, cmd-rerun 은 spawn 전에 어느 stage-<N> 가 선택될지 알 수 없어
156
- # runs/implementation/stage-<N> 경로도 per-stage run_seq 도 예측할 수 없다.
157
- # OKSTRA_RUN_SEQ_OVERRIDE(run 전체에 단일 seq) 는 per-stage seq 카운터와
158
- # 구조적으로 양립 불가하고, 원본 invocation 재생은 진짜 rerun 이 아니다
159
- # (forced --stage N 은 이미 done 이라 거부되고, --stage auto 는 다른 ready
160
- # stage 로 조용히 전진한다). 따라서 선예약/spawn 이전에 거부하고 신규
161
- # implementation run 으로 안내한다.
162
- if row and slugify_task_segment(row.get("taskType", "")) == "implementation":
163
- items.append({"originalRunId": original, "newRunId": None,
164
- "newRunSeq": None, "sessionName": None,
165
- "status": "rejected", "spawnedAt": None,
166
- "skipReason": "implementation 은 stage 격리되어 okstra-ctl rerun 으로 "
167
- "재실행할 수 없습니다. 다음 ready stage 를 실행하려면 "
168
- "새 implementation run 을 시작하십시오 "
169
- "(okstra.sh --task-type implementation --stage auto)."})
170
- rejected += 1
171
- continue
172
- inv = (load_invocation(home, row["projectId"], row["taskGroup"],
173
- row["taskId"], row["taskType"], row["runSeq"])
174
- if row else None)
175
- if inv is None or inv.get("backfilled") or not Path(row["projectRoot"]).is_dir():
176
- items.append({"originalRunId": original, "newRunId": None,
177
- "newRunSeq": None, "sessionName": None,
178
- "status": "skipped", "spawnedAt": None,
179
- "skipReason": "no invocation / backfilled / project root missing"})
180
- skipped += 1
181
- continue
182
- # brief drift 검사: 원래 run 시점에 캡처한 briefSha256 과 현재 brief 파일의
183
- # 해시가 다르면, --ignore-brief-drift 가 없는 한 skip 하고 사유를 기록한다.
184
- # 그렇지 않으면 batch/--yes 재실행이 다른 입력으로 silently 분석을 수행한다.
185
- recorded_sha = inv.get("briefSha256") or ""
186
- if recorded_sha and not ignore_brief_drift:
187
- brief_abs = _brief_path_from_argv(inv.get("argv", []),
188
- inv.get("cwd", ""),
189
- row["projectRoot"])
190
- current_sha = _brief_sha256(brief_abs) if brief_abs else None
191
- if current_sha is None:
192
- items.append({"originalRunId": original, "newRunId": None,
193
- "newRunSeq": None, "sessionName": None,
194
- "status": "skipped", "spawnedAt": None,
195
- "skipReason": "brief missing for drift check"})
196
- skipped += 1
197
- continue
198
- if current_sha != recorded_sha:
199
- items.append({"originalRunId": original, "newRunId": None,
200
- "newRunSeq": None, "sessionName": None,
201
- "status": "skipped", "spawnedAt": None,
202
- "skipReason": "brief drift (use --ignore-brief-drift to override)"})
203
- skipped += 1
204
- continue
205
- lock = home / ".locks" / task_lock_filename(
206
- row["projectId"], row["taskGroup"], row["taskId"], row["taskType"])
207
- lock.parent.mkdir(parents=True, exist_ok=True); lock.touch()
208
- with lock.open("r+") as lf:
209
- fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
210
- rkey = (row["projectId"], row["taskGroup"], row["taskId"], row["taskType"])
211
- used = batch_reserved.setdefault(rkey, set())
212
- # 중앙 인덱스(active.jsonl) 와 manifest 디렉터리까지 함께 보고 다음 seq 를 계산.
213
- # 다른 okstra-ctl 프로세스가 이미 예약했거나 in-flight 인 run 의 seq 도 회피된다.
214
- with central_lock(home):
215
- next_seq = predict_next_run_seq(
216
- Path(row["projectRoot"]),
217
- row["taskGroup"], row["taskId"], row["taskType"],
218
- home=home, project_id=row["projectId"])
219
- while next_seq in used:
220
- next_seq += 1
221
- used.add(next_seq)
222
- new_run_id = build_run_id(row["projectId"], row["taskGroup"],
223
- row["taskId"], row["taskType"], next_seq)
224
- session = run_id_to_session_name(new_run_id)
225
- # dry-run 이 아닌 경우 reservation 을 중앙 인덱스에 영속한다.
226
- # 후속 okstra-ctl 호출이 즉시 이 seq 를 회피할 수 있게 된다.
227
- if not dry:
228
- # rerun 시 새 run 의 RUN_DIR 은 같은 task-type 디렉터리, FINAL_REPORT 는 새 seq.
229
- # okstra.sh 는 디렉터리 segment 를 slugify_value 로 정규화하므로
230
- # (공백/대문자/`/` 등이 포함된 raw taskGroup/taskId 그대로 쓰면
231
- # 실제 디스크 경로와 어긋나 tail -F 가 영구 wait 하거나 startup
232
- # 실패 시 row 가 잘못된 경로를 가리킨다) 같은 슬러그로 예측 경로를
233
- # 만든다. 정상 spawn 시 record_start 가 RUN_DIR_RELATIVE_PATH 로
234
- # 정확 값을 다시 update 한다.
235
- slug_group = slugify_task_segment(row["taskGroup"])
236
- slug_task = slugify_task_segment(row["taskId"])
237
- slug_type = slugify_task_segment(row["taskType"])
238
- base_run = (".okstra/tasks/"
239
- f"{slug_group}/{slug_task}/runs/{slug_type}")
240
- final_rel = (f"{base_run}/reports/"
241
- f"final-report-{slug_type}-{next_seq:03d}.md")
242
- # 예약 시점에 final status 경로도 best-effort 로 박아 둔다.
243
- # RUN_STATUS_SEQ 는 RUN_MANIFESTS_SEQ 와 별개 카운터지만,
244
- # 정상 run 에선 두 카운터가 함께 advance 한다(render-only/
245
- # 실패 prep 만 manifest 만 advance). 추후 record_start 가
246
- # 정확한 finalStatusRel 로 row 를 update 하므로 여기서 값을
247
- # 비워 두면 spawn 직후 tail 이 status dir 부재로 race-fail
248
- # 한다 — 기대 경로를 미리 채워 tail -F 가 등장 대기하게 한다.
249
- final_status_rel = (f"{base_run}/status/"
250
- f"final-{slug_type}-{next_seq:03d}.status")
251
- reserve_run_in_active(
252
- home, project_id=row["projectId"],
253
- project_root=row["projectRoot"],
254
- task_group=row["taskGroup"], task_id=row["taskId"],
255
- task_type=row["taskType"], run_seq=next_seq,
256
- when=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
257
- run_dir_rel=base_run, final_report_record_rel=final_rel,
258
- final_status_rel=final_status_rel,
259
- )
260
- # 원본 invocation 시점에 캡처된 envOverrides 를 base 에 layer 한다.
261
- # 신규 모델은 PROJECT_ROOT 를 project.json 에서 자기 해석하므로
262
- # invocation-specific 환경변수 override 가 사실상 사라졌지만, 호환을
263
- # 위해 envOverrides 가 dict 형태로 남아있을 수 있다. base(현재 ctl
264
- # 환경) 키와 충돌하면 base 가 우선해 사용자의 OKSTRA_HOME 등이 보존된다.
265
- target_env = {}
266
- for k, v in (inv.get("envOverrides") or {}).items():
267
- if isinstance(v, str):
268
- target_env[k] = v
269
- target_env.update(extra_env_base)
270
- cmd = build_tmux_command(session_name=session, cwd=inv["cwd"],
271
- run_seq=next_seq, argv=inv["argv"],
272
- okstra_script=os.environ["OKSTRA_SCRIPT"],
273
- extra_env=target_env)
274
- if dry:
275
- items.append({"originalRunId": original, "newRunId": new_run_id,
276
- "newRunSeq": next_seq, "sessionName": session,
277
- "status": "dry-run", "spawnedAt": None,
278
- "skipReason": None})
279
- continue
280
- # 핵심 모델: tmux 세션을 detached 로 띄우고 즉시 다음 대상으로 넘어간다.
281
- rc = subprocess.run(cmd, capture_output=True, text=True)
282
- if rc.returncode != 0:
283
- # spawn 실패 시 reservation 을 정리한다(중앙 인덱스 누수 방지).
284
- with central_lock(home):
285
- remove_reservation(
286
- home, project_id=row["projectId"],
287
- task_group=row["taskGroup"], task_id=row["taskId"],
288
- task_type=row["taskType"], run_seq=next_seq,
289
- )
290
- items.append({"originalRunId": original, "newRunId": new_run_id,
291
- "newRunSeq": next_seq, "sessionName": session,
292
- "status": "skipped", "spawnedAt": None,
293
- "skipReason": f"tmux: {rc.stderr.strip()}"})
294
- skipped += 1
295
- continue
296
- items.append({"originalRunId": original, "newRunId": new_run_id,
297
- "newRunSeq": next_seq, "sessionName": session,
298
- "status": "spawned",
299
- "spawnedAt": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
300
- "skipReason": None})
301
- spawned += 1
302
-
303
- selector_raw = (
304
- explicit
305
- + (["--filter", "--project", os.environ["OK_PROJECT"],
306
- "--task-group", os.environ["OK_TG"],
307
- "--status", os.environ["OK_STATUS"], "--since", os.environ["OK_SINCE"]]
308
- if use_filter else [])
309
- + (["last"] if use_last else [])
310
- + (["-"] if from_stdin else [])
311
- )
312
- write_batch_meta(home, batch_id, {
313
- "batchId": batch_id,
314
- "createdAt": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
315
- "selectorRaw": selector_raw, "maxSpawn": max_spawn,
316
- "items": items,
317
- "summary": {"total": len(targets), "spawned": spawned,
318
- "skipped": skipped, "rejected": rejected},
319
- })
320
-
321
- dry_run_count = sum(1 for it in items if it["status"] == "dry-run")
322
- if dry_run_count:
323
- print(f"batch {batch_id} dry-run: {dry_run_count} skipped: {skipped} rejected: {rejected}")
324
- else:
325
- print(f"batch {batch_id} spawned: {spawned} skipped: {skipped} rejected: {rejected}")
326
- print()
327
- header = ("RUN-ID", "SESSION-NAME", "ATTACH")
328
- rows = []
329
- # dry-run 도 미리보기 대상이다 — preview 의 본래 목적이 spawn 없이 target/
330
- # reservation 을 보여주는 것이므로 spawned 와 동일하게 row 에 포함한다.
331
- for it in items:
332
- if it["status"] in ("spawned", "dry-run"):
333
- attach = (f"tmux attach -t {it['sessionName']}"
334
- if it["status"] == "spawned" else "(dry-run)")
335
- rows.append((it["newRunId"] or "-", it["sessionName"] or "-", attach))
336
- if rows:
337
- table = [header] + rows
338
- widths = [max(len(t[i]) for t in table) for i in range(3)]
339
- for t in table:
340
- print(" ".join(c.ljust(widths[i]) for i, c in enumerate(t)))
341
- print()
342
- print(f"monitor batch : okstra-ctl batch status {batch_id}")
343
- print( "list sessions : tmux ls | grep ^okstra-")
344
- PY
345
- }
@@ -1,27 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- _okstra_ctl_show() {
4
- if [[ $# -lt 1 ]]; then
5
- printf 'show: missing <runId-or-prefix>\n' >&2; exit 2
6
- fi
7
- OKSTRA_HOME_RESOLVED="$(okstra_central_home)" \
8
- OKSTRA_CTL_LIB_DIR="$SCRIPT_DIR" \
9
- OK_QUERY="$1" \
10
- python3 - <<'PY'
11
- import os, sys
12
- sys.path.insert(0, os.environ["OKSTRA_CTL_LIB_DIR"])
13
- from pathlib import Path
14
- from okstra_ctl import resolve_run_id, find_row_by_run_id, format_show, ResolveError
15
- home = Path(os.environ["OKSTRA_HOME_RESOLVED"])
16
- try:
17
- rid = resolve_run_id(home, os.environ["OK_QUERY"])
18
- except ResolveError as e:
19
- print(f"show: {e}", file=sys.stderr)
20
- for c in e.candidates: print(f" - {c}", file=sys.stderr)
21
- sys.exit(2)
22
- row = find_row_by_run_id(home, rid)
23
- if row is None:
24
- print(f"show: row not found for {rid}", file=sys.stderr); sys.exit(2)
25
- print(format_show(row), end="")
26
- PY
27
- }
@@ -1,92 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- _okstra_ctl_tail() {
4
- if [[ $# -lt 1 ]]; then
5
- printf 'tail: missing <runId-or-prefix> | active\n' >&2; exit 2
6
- fi
7
- if [[ "$1" == "active" ]]; then
8
- OKSTRA_HOME_RESOLVED="$(okstra_central_home)" \
9
- OKSTRA_CTL_LIB_DIR="$SCRIPT_DIR" \
10
- python3 - <<'PY'
11
- import os, sys
12
- sys.path.insert(0, os.environ["OKSTRA_CTL_LIB_DIR"])
13
- from pathlib import Path
14
- from okstra_ctl import read_run_index, format_runs_table
15
- # tail active 는 active.jsonl 자체를 보여줘야 한다 — running 외에도
16
- # in-progress(backfill), reserving(rerun 예약), 그리고 어떤 비-터미널
17
- # 상태든 active 에 들어있는 것은 사용자가 모니터링해야 할 대상이다.
18
- # 디스크 row 는 slim(파생 taskType 없음)이라 read_run_index 로 hydrate 해야
19
- # format_runs_table 의 TASK-TYPE 열이 채워진다.
20
- rows = sorted(read_run_index(Path(os.environ["OKSTRA_HOME_RESOLVED"]) / "active.jsonl"),
21
- key=lambda r: r.get("startedAt", ""), reverse=True)
22
- print(format_runs_table(rows), end="")
23
- PY
24
- return 0
25
- fi
26
- # 정확한 status 파일 경로는 row 의 finalStatusRel(RUN_STATUS_SEQ 기반,
27
- # record_start 시점에 박힘) 에서 가져온다. RUN_STATUS_SEQ 와
28
- # RUN_MANIFESTS_SEQ 는 별개 카운터이므로 row["runSeq"] 로 추정하면
29
- # render-only 가 manifest seq 만 advance 한 직후의 실행에서 어긋난다.
30
- # finalStatusRel 이 없을 때만 (구식 row) runDirRel/taskType/runSeq 로
31
- # fallback 하고, 그래도 없으면 expected status 파일이 아직 만들어지지
32
- # 않았어도 tail -F 로 wait 한다(`tail -F` 는 by-name 으로 파일 등장을
33
- # 감지한다).
34
- local resolved resolve_rc
35
- resolved="$(OKSTRA_HOME_RESOLVED="$(okstra_central_home)" \
36
- OKSTRA_CTL_LIB_DIR="$SCRIPT_DIR" \
37
- OK_QUERY="$1" python3 -c '
38
- import os, sys
39
- sys.path.insert(0, os.environ["OKSTRA_CTL_LIB_DIR"])
40
- from pathlib import Path
41
- from okstra_ctl import resolve_run_id, find_row_by_run_id, ResolveError, resolve_under_root
42
- home = Path(os.environ["OKSTRA_HOME_RESOLVED"])
43
- try:
44
- rid = resolve_run_id(home, os.environ["OK_QUERY"])
45
- except ResolveError as e:
46
- print(f"tail: {e}", file=sys.stderr)
47
- for c in e.candidates: print(f" - {c}", file=sys.stderr)
48
- sys.exit(2)
49
- row = find_row_by_run_id(home, rid)
50
- if row is None:
51
- print(f"tail: row not found for {rid}", file=sys.stderr); sys.exit(2)
52
- project_root = Path(row["projectRoot"])
53
- run_dir = resolve_under_root(project_root, row.get("runDirRel"))
54
- if run_dir is None:
55
- print("tail: runDirRel escapes project root", file=sys.stderr); sys.exit(2)
56
- status_rel = row.get("finalStatusRel") or ""
57
- status_abs = str(project_root / status_rel) if status_rel else ""
58
- print(run_dir)
59
- print(row.get("taskType", ""))
60
- print(int(row.get("runSeq", 0)))
61
- print(status_abs)
62
- ')"
63
- resolve_rc=$?
64
- # resolve 단계가 ResolveError/누락 row 로 exit≠0 한 경우 stderr 의 깔끔한
65
- # `tail: ...` 메시지를 살리고 fallback glob 으로 넘어가지 않는다.
66
- if [[ $resolve_rc -ne 0 ]]; then exit "$resolve_rc"; fi
67
- local rid task_type seq status_abs
68
- rid="$(printf '%s\n' "$resolved" | sed -n '1p')"
69
- task_type="$(printf '%s\n' "$resolved" | sed -n '2p')"
70
- seq="$(printf '%s\n' "$resolved" | sed -n '3p')"
71
- status_abs="$(printf '%s\n' "$resolved" | sed -n '4p')"
72
- if [[ -n "$status_abs" ]]; then
73
- # row 가 정식 경로를 알고 있으면 그것만 tail. 아직 파일이 없어도
74
- # `tail -F` 가 등장을 기다리므로, active 진입 직후 호출도 정상.
75
- exec tail -F "$status_abs"
76
- fi
77
- # 구식 row(이전 버전에서 작성되어 finalStatusRel 누락) — runSeq 로 glob.
78
- if [[ ! -d "$rid/status" ]]; then
79
- printf 'tail: status dir missing: %s/status\n' "$rid" >&2; exit 2
80
- fi
81
- local seq_pad
82
- seq_pad="$(printf '%03d' "$seq")"
83
- shopt -s nullglob
84
- local matches=("$rid/status/"*"-${task_type}-${seq_pad}".*)
85
- shopt -u nullglob
86
- if [[ ${#matches[@]} -eq 0 ]]; then
87
- # 매니페스트 카운터가 status 카운터를 앞섰을 수 있으므로 정확
88
- # 매칭이 없어도 가장 그럴듯한 expected 경로로 wait 한다.
89
- exec tail -F "$rid/status/final-${task_type}-${seq_pad}.status"
90
- fi
91
- exec tail -F "${matches[@]}"
92
- }
@@ -1,41 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- main() {
4
- if [[ $# -eq 0 ]]; then
5
- usage
6
- exit 2
7
- fi
8
- case "$1" in
9
- -h|--help)
10
- cat <<'HELP'
11
- okstra-ctl: okstra Control Center CLI.
12
-
13
- Subcommands: projects, list, show, open, tail, rerun, batch, reconcile, reindex.
14
- HELP
15
- usage
16
- exit 0
17
- ;;
18
- projects|list|show|open|tail|rerun|batch|reconcile|reindex)
19
- local sub="$1"; shift
20
- # reindex 는 사용자가 명시적으로 지정한 --project 필터를 가지므로,
21
- # 이 경로에서 자동(unqualified) backfill 을 추가로 돌리면 사용자
22
- # scope 을 무시하고 모든 프로젝트를 스캔하게 된다. reindex 자체가
23
- # backfill 을 수행하므로 prepare 의 자동 backfill 단계는 건너뛴다.
24
- if [[ "$sub" == "reindex" ]]; then
25
- OKSTRA_CTL_SKIP_BACKFILL=1 _okstra_ctl_prepare
26
- elif [[ "$sub" == "reconcile" ]]; then
27
- # 사용자 --project 필터를 보존하기 위해 prepare 의 unscoped
28
- # reconcile 단계를 건너뛴다(서브커맨드 본체가 스코프 reconcile 수행).
29
- OKSTRA_CTL_SKIP_RECONCILE=1 _okstra_ctl_prepare
30
- else
31
- _okstra_ctl_prepare
32
- fi
33
- "_okstra_ctl_${sub}" "$@"
34
- ;;
35
- *)
36
- printf 'unknown subcommand: %s\n' "$1" >&2
37
- usage
38
- exit 2
39
- ;;
40
- esac
41
- }
@@ -1,31 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- _okstra_ctl_prepare() {
4
- okstra_central_bootstrap
5
- local home; home="$(okstra_central_home)"
6
- if [[ "${OKSTRA_CTL_SKIP_BACKFILL:-0}" != "1" ]]; then
7
- if ! OKSTRA_STATE_PATH="$home/state.json" python3 -c '
8
- import json, os, sys
9
- from pathlib import Path
10
- state = Path(os.environ["OKSTRA_STATE_PATH"])
11
- data = json.loads(state.read_text()) if state.is_file() else {}
12
- sys.exit(0 if data.get("backfilledAt") else 1)
13
- '; then
14
- _okstra_ctl_reindex >/dev/null 2>&1 || true
15
- fi
16
- fi
17
- if [[ "${OKSTRA_CTL_SKIP_RECONCILE:-0}" == "1" ]]; then
18
- return 0
19
- fi
20
- OKSTRA_HOME_RESOLVED="$home" \
21
- OKSTRA_CTL_LIB_DIR="$SCRIPT_DIR" \
22
- python3 - <<'PY'
23
- import os, sys
24
- sys.path.insert(0, os.environ["OKSTRA_CTL_LIB_DIR"])
25
- from pathlib import Path
26
- from okstra_ctl import reconcile_active, reconcile_recent
27
- home = Path(os.environ["OKSTRA_HOME_RESOLVED"])
28
- reconcile_active(home)
29
- reconcile_recent(home)
30
- PY
31
- }
@@ -1,23 +0,0 @@
1
- # shellcheck shell=bash
2
-
3
- usage() {
4
- cat >&2 <<'USAGE'
5
- usage:
6
- okstra-ctl projects [--sort recent|name|count] [--active]
7
- okstra-ctl list [--project <id|all>] [--task-group <name|all>]
8
- [--status running|completed|failed|all]
9
- [--since <duration|date>] [--limit N]
10
- okstra-ctl show <taskId-or-prefix>
11
- okstra-ctl open <taskId-or-prefix>
12
- okstra-ctl tail <taskId-or-prefix> | active
13
- okstra-ctl rerun <selector> [<selector> ...]
14
- [--filter --project <id|all> --task-group <name|all>
15
- --status ... --since ...]
16
- [--max-spawn N] [--dry-run] [--yes]
17
- okstra-ctl batch list
18
- okstra-ctl batch status <batch-id>
19
- okstra-ctl reconcile [--project <id|all>]
20
- okstra-ctl reindex [--project <id|all>]
21
- okstra-ctl --help
22
- USAGE
23
- }