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
@@ -52,6 +52,14 @@ split_task_key() {
52
52
  TASK_ID="$key_id"
53
53
  }
54
54
 
55
+ # okstra_ctl.interactive_cli 호출 공용 래퍼. 조회 로직은 전부 그 모듈에 있다 —
56
+ # 예전에는 이 파일이 파이썬 heredoc 6개(153줄)로 같은 일을 했고, 셸 문자열 안이라
57
+ # import 도 테스트도 닿지 않았다(docs/coding-rules.md R1).
58
+ _okstra_interactive_cli() {
59
+ PYTHONPATH="${OKSTRA_PYTHONPATH}${PYTHONPATH:+:$PYTHONPATH}" \
60
+ python3 -m okstra_ctl.interactive_cli "$@"
61
+ }
62
+
55
63
  resolve_task_root_for_shortcut() {
56
64
  local project_root="$1"
57
65
  local project_id="$2"
@@ -59,75 +67,9 @@ resolve_task_root_for_shortcut() {
59
67
  local task_id="$4"
60
68
 
61
69
  local resolved=""
62
- resolved="$(python3 - "$OKSTRA_PYTHONPATH" "$project_root" "$project_id" "$task_group" "$task_id" <<'PY'
63
- import json, os, sys
64
- from pathlib import Path
65
-
66
- # task root 의 slug 경로 구성은 okstra_ctl.paths.task_dir(SSOT) 에 위임한다.
67
- # 과거 이 heredoc 은 slugify 와 `.okstra/tasks/<slug>/<slug>` 구조를 자체
68
- # 재구현해 규칙 변경 시 silent drift 위험이 있었다. project-resolver.sh 와
69
- # 동일하게 $OKSTRA_PYTHONPATH 를 sys.path 에 올려 패키지를 import 한다.
70
- sys.path.insert(0, sys.argv[1])
71
- from okstra_ctl.paths import task_dir
72
-
73
- project_root = Path(sys.argv[2])
74
- project_id = sys.argv[3]
75
- task_group = sys.argv[4]
76
- task_id = sys.argv[5]
77
-
78
- requested_key = f"{project_id}:{task_group}:{task_id}"
79
- requested_key_ci = requested_key.lower()
80
-
81
- candidates = []
82
-
83
- catalog_path = project_root / ".okstra" / "discovery" / "task-catalog.json"
84
- catalog_keys = []
85
- if catalog_path.is_file():
86
- try:
87
- catalog = json.loads(catalog_path.read_text(encoding="utf-8"))
88
- except Exception as exc:
89
- sys.stderr.write(f"resolve_task_root: failed to parse {catalog_path}: {exc}\n")
90
- catalog = None
91
- if isinstance(catalog, dict):
92
- catalog_project_id = catalog.get("projectId")
93
- tasks = catalog.get("tasks") or []
94
- for entry in tasks:
95
- if not isinstance(entry, dict):
96
- continue
97
- entry_key = entry.get("taskKey") or ""
98
- if not isinstance(entry_key, str) or not entry_key:
99
- continue
100
- entry_belongs_to_project = (
101
- catalog_project_id == project_id
102
- or entry.get("projectId") == project_id
103
- or entry_key.startswith(f"{project_id}:")
104
- )
105
- if entry_belongs_to_project:
106
- catalog_keys.append(entry_key)
107
- if entry_key.lower() == requested_key_ci:
108
- rel = entry.get("taskRootPath") or entry.get("taskRoot")
109
- if isinstance(rel, str) and rel:
110
- abs_path = (project_root / rel).resolve() if not os.path.isabs(rel) else Path(rel)
111
- if abs_path.is_dir():
112
- print(f"OK\t{abs_path}")
113
- sys.exit(0)
114
- candidates.append(str(abs_path))
115
-
116
- slug_path = task_dir(project_root, task_group, task_id)
117
- if slug_path.is_dir():
118
- print(f"OK\t{slug_path}")
119
- sys.exit(0)
120
- candidates.append(str(slug_path))
121
-
122
- # Failure path: emit diagnostics so the wrapper can show them.
123
- print("MISSING")
124
- print(f"REQUESTED\t{requested_key}")
125
- for cand in candidates:
126
- print(f"TRIED\t{cand}")
127
- for key in sorted(set(catalog_keys)):
128
- print(f"AVAILABLE\t{key}")
129
- PY
130
- )"
70
+ resolved="$(_okstra_interactive_cli resolve-task-root \
71
+ --project-root "$project_root" --project-id "$project_id" \
72
+ --task-group "$task_group" --task-id "$task_id")"
131
73
 
132
74
  local status=""
133
75
  status="$(printf '%s' "$resolved" | head -n 1 | awk -F '\t' '{print $1}')"
@@ -176,53 +118,17 @@ autofill_from_manifest() {
176
118
  return 0
177
119
  fi
178
120
 
179
- PYTHONPATH="$OKSTRA_PYTHONPATH:${PYTHONPATH-}" python3 - "$manifest_project_root" "$manifest_task_root" <<'PY' || true
180
- import sys
181
- from pathlib import Path
182
-
183
- from okstra_ctl.implementation_outcome import reconcile_implementation_outcome
184
-
185
- try:
186
- reconcile_implementation_outcome(Path(sys.argv[1]), Path(sys.argv[2]))
187
- except Exception:
188
- pass
189
- PY
121
+ _okstra_interactive_cli reconcile-outcome \
122
+ --project-root "$manifest_project_root" --task-root "$manifest_task_root" || true
190
123
 
191
- local need_brief_val need_type_val
192
- need_brief_val="$([[ -z "$BRIEF_PATH" ]] && printf '1' || printf '0')"
193
- need_type_val="$([[ -z "$TASK_TYPE" ]] && printf '1' || printf '0')"
194
124
  local autofill_output=""
195
- # autofill 은 편의 기능이라 실패해도 run 을 끊으면 안 된다. heredoc 이
196
- # okstra_ctl 을 import 하므로 설치가 깨지면 non-zero 로 끝나는데, okstra.sh 는
197
- # `set -euo pipefail` 이라 이 평범한 대입 하나가 run 을 통째로 중단시킨다.
198
- # 위 reconcile 호출(:189)이 같은 이유로 `|| true` 를 달고 있다.
199
- autofill_output="$(PYTHONPATH="$OKSTRA_PYTHONPATH:${PYTHONPATH-}" python3 - "$manifest_path" "$need_brief_val" "$need_type_val" <<'PY'
200
- import json, sys
201
-
202
- from okstra_ctl import next_phase
203
-
204
- path = sys.argv[1]
205
- need_brief = sys.argv[2] == "1"
206
- need_type = sys.argv[3] == "1"
207
- try:
208
- data = json.loads(open(path, "r", encoding="utf-8").read())
209
- except Exception as exc:
210
- sys.stderr.write(f"autofill_from_manifest: failed to parse {path}: {exc}\n")
211
- sys.exit(0)
212
-
213
- brief = ""
214
- task_type = ""
215
- if need_brief:
216
- brief = (data.get("taskBriefPath") or "").strip()
217
- if need_type:
218
- # 포인터 판정은 Python SSOT 가 갖는다 — `ready` 가 아니면 빈 문자열이라
219
- # 셸이 센티널 목록을 따로 들고 있을 이유가 없다.
220
- task_type = next_phase.autofill_task_type(data)
221
-
222
- print(f"BRIEF={brief}")
223
- print(f"TYPE={task_type}")
224
- PY
225
- )" || true
125
+ # autofill 은 편의 기능이라 실패해도 run 을 끊으면 안 된다. 모듈이 okstra_ctl 을
126
+ # import 하므로 설치가 깨지면 비-0 으로 끝나는데, okstra.sh 는 `set -euo pipefail`
127
+ # 이라 이 평범한 대입 하나가 run 을 통째로 중단시킨다. 위 reconcile 호출이 같은
128
+ # 이유로 `|| true` 를 달고 있다.
129
+ autofill_output="$(_okstra_interactive_cli autofill --manifest "$manifest_path" \
130
+ $( [[ -z "$BRIEF_PATH" ]] && printf -- "--need-brief" ) \
131
+ $( [[ -z "$TASK_TYPE" ]] && printf -- "--need-type" ))" || true
226
132
 
227
133
  local manifest_brief=""
228
134
  local manifest_type=""
@@ -304,19 +210,8 @@ find_latest_final_report() {
304
210
  }
305
211
 
306
212
  local found=""
307
- found="$(PYTHONPATH="$OKSTRA_PYTHONPATH:${PYTHONPATH-}" python3 - \
308
- "$task_root" "$task_type_filter" <<'PY'
309
- import sys
310
- from okstra_ctl.paths import RunRef
311
-
312
- task_root, task_type_filter = sys.argv[1:3]
313
- types = ((task_type_filter,) if task_type_filter
314
- else ("error-analysis", "requirements-discovery"))
315
- ref = RunRef.latest_under(task_root, types)
316
- if ref is not None:
317
- sys.stdout.write(f"{ref.report}\t{ref.task_type}")
318
- PY
319
- )" || return 1
213
+ found="$(_okstra_interactive_cli latest-report \
214
+ --task-root "$task_root" --task-type "$task_type_filter")" || return 1
320
215
 
321
216
  if [[ -z "$found" ]]; then
322
217
  printf 'resume-clarification: no final-report found for task %s:%s under %s/runs\n' \
@@ -386,12 +281,7 @@ run_resume_clarification() {
386
281
  exit 1
387
282
  fi
388
283
  local resume_brief_rel=""
389
- resume_brief_rel="$(python3 - "$manifest_file" <<'PY'
390
- import json, sys
391
- data = json.loads(open(sys.argv[1], "r", encoding="utf-8").read())
392
- print((data.get("taskBriefPath") or "").strip())
393
- PY
394
- )"
284
+ resume_brief_rel="$(_okstra_interactive_cli manifest-brief --manifest "$manifest_file")"
395
285
  if [[ -z "$resume_brief_rel" ]]; then
396
286
  printf 'resume-clarification: manifest missing taskBriefPath: %s\n' "$manifest_file" >&2
397
287
  exit 1
@@ -403,46 +293,9 @@ PY
403
293
  local resume_extra_args=()
404
294
  while IFS= read -r -d '' _arg; do
405
295
  resume_extra_args+=("$_arg")
406
- done < <(PYTHONPATH="$OKSTRA_PYTHONPATH:${PYTHONPATH-}" python3 - \
407
- "$PROJECT_ROOT" "$TASK_GROUP" "$TASK_ID" "$resolved_type" <<'PY'
408
- import sys
409
- from okstra_ctl.run_context import latest_run_inputs
410
- from okstra_ctl.ids import slugify_task_segment
411
-
412
- project_root, task_group, task_id, task_type = sys.argv[1:5]
413
- inputs = latest_run_inputs(
414
- project_root, task_group, task_id,
415
- phase_segment=slugify_task_segment(task_type))
416
-
417
-
418
- def emit(flag, value):
419
- if value:
420
- sys.stdout.write(flag + "\0" + value + "\0")
421
-
422
-
423
- def model(value):
424
- # 직전 run 의 모델 display 값. "default"/빈 값은 phase 기본값을 뜻하므로 넘기지
425
- # 않는다(명시 플래그로 고정하면 안 됨).
426
- return value if isinstance(value, str) and value not in ("", "default") else ""
427
-
428
-
429
- workers = inputs.get("workers")
430
- if isinstance(workers, list):
431
- workers = ",".join(w for w in workers if isinstance(w, str))
432
- elif not isinstance(workers, str):
433
- workers = ""
434
- emit("--workers", workers)
435
- emit("--lead-model", model(inputs.get("leadModel")))
436
- emit("--claude-model", model(inputs.get("claudeModel")))
437
- emit("--codex-model", model(inputs.get("codexModel")))
438
- emit("--antigravity-model", model(inputs.get("antigravityModel")))
439
- emit("--report-writer-model", model(inputs.get("reportWriterModel")))
440
- directive = inputs.get("directive")
441
- emit("--directive", directive if isinstance(directive, str) else "")
442
- related = inputs.get("relatedTasks")
443
- emit("--related-tasks", related if isinstance(related, str) else "")
444
- PY
445
- )
296
+ done < <(_okstra_interactive_cli resume-args \
297
+ --project-root "$PROJECT_ROOT" --task-group "$TASK_GROUP" \
298
+ --task-id "$TASK_ID" --task-type "$resolved_type")
446
299
 
447
300
  if [[ "${OKSTRA_RESUME_CLARIFICATION_DRY_RUN:-false}" == "true" ]]; then
448
301
  printf 'resume-clarification (dry-run):\n' >&2
@@ -1,59 +1,36 @@
1
1
  # shellcheck shell=bash
2
2
 
3
- # bash wrappers around scripts/okstra_project resolver. okstra.sh 가 시작 시
4
- # PROJECT_ROOT 를 확정하고 <PROJECT_ROOT>/.okstra/project.json 을
5
- # upsert 한다. 과거 conf 파일 모델은 폐기되었다.
3
+ # scripts/okstra_project 리졸버의 bash 래퍼. okstra.sh 가 시작 시 PROJECT_ROOT 를
4
+ # 확정하고 <PROJECT_ROOT>/.okstra/project.json 을 upsert 한다. 과거 conf 파일
5
+ # 모델은 폐기되었다.
6
+ #
7
+ # 해석 자체는 `okstra_ctl.project_setup_cli` 한 곳에만 있다. 예전에는 이 파일이
8
+ # 파이썬 heredoc 4개로 같은 해석을 다시 적었고, TS 쪽(config/setup/check-project)
9
+ # 도 각자 한 벌씩 더 갖고 있었다 — 갈라져도 아무도 몰랐다.
6
10
 
7
- # 절대경로(또는 빈 문자열) 를 stdout 으로 출력한다. 실패 시 stderr 에 메시지를
8
- # 남기고 비-0 종료. autofill 처럼 best-effort 호출자가 에러를 무시할 수 있도록
9
- # strict/safe 두 종류를 분리한다.
11
+ # PYTHONPATH 는 호출 시점의 $OKSTRA_PYTHONPATH 를 앞에 둔다(설치본/레포 양쪽).
12
+ _okstra_project_cli() {
13
+ PYTHONPATH="${OKSTRA_PYTHONPATH}${PYTHONPATH:+:$PYTHONPATH}" \
14
+ python3 -m okstra_ctl.project_setup_cli "$@"
15
+ }
16
+
17
+ # 절대경로를 stdout 으로. 실패 시 stderr 에 메시지를 남기고 비-0 종료.
10
18
  resolve_project_root_strict() {
11
- local explicit="${1-}"
12
- python3 - "$OKSTRA_PYTHONPATH" "$explicit" <<'PY'
13
- import os, sys
14
- sys.path.insert(0, sys.argv[1])
15
- from okstra_project import resolve_project_root, ResolverError
16
- explicit = sys.argv[2] if len(sys.argv) > 2 else ""
17
- try:
18
- p = resolve_project_root(explicit_root=explicit, cwd=os.getcwd())
19
- except ResolverError as exc:
20
- sys.stderr.write(f"resolve_project_root: {exc}\n")
21
- sys.exit(1)
22
- print(p)
23
- PY
19
+ _okstra_project_cli resolve-root \
20
+ --explicit-root "${1-}" --cwd "$PWD" \
21
+ --on-error fail --error-prefix "resolve_project_root: " --error-code 1
24
22
  }
25
23
 
26
24
  # 실패해도 0 으로 종료하고 stdout 은 빈 문자열(autofill 등 best-effort 경로용).
27
25
  resolve_project_root_safe() {
28
- local explicit="${1-}"
29
- python3 - "$OKSTRA_PYTHONPATH" "$explicit" <<'PY'
30
- import os, sys
31
- sys.path.insert(0, sys.argv[1])
32
- from okstra_project import resolve_project_root, ResolverError
33
- explicit = sys.argv[2] if len(sys.argv) > 2 else ""
34
- try:
35
- p = resolve_project_root(explicit_root=explicit, cwd=os.getcwd())
36
- except ResolverError:
37
- sys.exit(0)
38
- print(p)
39
- PY
26
+ _okstra_project_cli resolve-root \
27
+ --explicit-root "${1-}" --cwd "$PWD" --on-error empty
40
28
  }
41
29
 
42
30
  # project.json upsert. 충돌(projectId 불일치) 시 비-0 종료 + stderr 메시지.
43
31
  upsert_project_json() {
44
- local project_root="$1"
45
- local project_id="$2"
46
- python3 - "$OKSTRA_PYTHONPATH" "$project_root" "$project_id" <<'PY'
47
- import sys
48
- sys.path.insert(0, sys.argv[1])
49
- from pathlib import Path
50
- from okstra_project import upsert_project_json, ResolverError
51
- try:
52
- upsert_project_json(Path(sys.argv[2]), sys.argv[3])
53
- except ResolverError as exc:
54
- sys.stderr.write(f"project.json upsert failed: {exc}\n")
55
- sys.exit(1)
56
- PY
32
+ _okstra_project_cli upsert \
33
+ --project-root "$1" --project-id "$2" --format strict
57
34
  }
58
35
 
59
36
  # `okstra setup` 이 이미 기록한 값을 다시 묻지 않기 위한 자동 채움. 프로젝트
@@ -61,23 +38,8 @@ PY
61
38
  autofill_from_project_json() {
62
39
  [[ -n "$PROJECT_ID" && -n "$PROJECT_ROOT" ]] && return 0
63
40
  local resolved
64
- resolved="$(python3 - "$OKSTRA_PYTHONPATH" "$PROJECT_ROOT_OVERRIDE" <<'PY' || true
65
- import json, sys
66
- from pathlib import Path
67
- sys.path.insert(0, sys.argv[1])
68
- from okstra_project import project_json_path
69
- from okstra_project.resolver import resolve_project_root
70
- try:
71
- root = resolve_project_root(explicit_root=sys.argv[2] or "")
72
- except Exception:
73
- sys.exit(0)
74
- path = project_json_path(Path(root))
75
- if not path.is_file():
76
- sys.exit(0)
77
- data = json.loads(path.read_text(encoding="utf-8"))
78
- print(f"{data.get('projectId', '')}\t{root}")
79
- PY
80
- )"
41
+ resolved="$(_okstra_project_cli project-json \
42
+ --explicit-root "$PROJECT_ROOT_OVERRIDE" || true)"
81
43
  [[ -z "$resolved" ]] && return 0
82
44
  [[ -z "$PROJECT_ID" ]] && PROJECT_ID="${resolved%%$'\t'*}"
83
45
  [[ -z "$PROJECT_ROOT" ]] && PROJECT_ROOT="${resolved##*$'\t'}"
@@ -11,7 +11,7 @@ summary:
11
11
 
12
12
  Skills, worker agents, and the codex wrapper are installed once per user under
13
13
  ~/.claude and ~/.okstra by scripts/okstra-install.sh. The user's settings.json
14
- is never modified; okstra-ctl prepare provisions the project's
14
+ is never modified; `okstra setup` and the prepare path provision the project's
15
15
  .claude/settings.local.json as a symlink to ~/.okstra/templates/settings.local.json,
16
16
  which Claude Code auto-loads.
17
17
 
@@ -99,7 +99,7 @@ options:
99
99
  --claude-model Model for Claude worker. Default: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
100
100
  --codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6-sol
101
101
  --antigravity-model Model for Antigravity worker. Default: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
102
- --worker-model Provider-qualified worker override CSV, e.g. grok=grok-4.5,kimi=kimi-k3.
102
+ --worker-model Provider-qualified worker override CSV, e.g. grok=grok-4.6,kimi=kimi-k3.
103
103
  --report-writer-provider
104
104
  Provider for report writer. Supported: claude, codex. Default: claude.
105
105
  --report-writer-model
@@ -136,7 +136,7 @@ model defaults:
136
136
  Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6-sol
137
137
  Antigravity worker: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
138
138
  Grok worker: grok-4.6
139
- Kimi worker: kimi-k2.7-code (analyser) or kimi-k3 (critic)
139
+ Kimi worker: kimi-k3
140
140
  Implementation executor: OKSTRA_DEFAULT_EXECUTOR or claude (one of: claude | codex | antigravity | grok | kimi)
141
141
 
142
142
  output:
@@ -16,11 +16,7 @@ home="${OKSTRA_HOME:-$HOME/.okstra}"
16
16
  export PYTHONPATH="${_dir}:${home}/lib/python${PYTHONPATH:+:$PYTHONPATH}"
17
17
 
18
18
  _stdin="$(cat 2>/dev/null || true)"
19
- cwd="$(printf '%s' "$_stdin" | python3 -c 'import json,sys
20
- try:
21
- print(json.load(sys.stdin).get("cwd","") or "")
22
- except Exception:
23
- pass' 2>/dev/null || true)"
19
+ cwd="$(printf '%s' "$_stdin" | python3 -m okstra_ctl.pane_reclaim --cwd-from-hook-stdin 2>/dev/null || true)"
24
20
  [ -n "$cwd" ] || cwd="$PWD"
25
21
 
26
22
  while IFS= read -r run_dir; do
@@ -8,9 +8,15 @@ re-exports the writer's names so the contract tests keep reading one module.
8
8
  from __future__ import annotations
9
9
 
10
10
  import argparse
11
+ import sys
11
12
  from pathlib import Path
12
13
 
13
- from okstra_ctl.error_log_write import (
14
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
15
+ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
16
+
17
+ prefer_colocated_modules(__file__, "okstra_ctl/error_log_write.py")
18
+
19
+ from okstra_ctl.error_log_write import ( # noqa: E402
14
20
  ALLOWED_AGENT_ROLES,
15
21
  ALLOWED_AGENTS,
16
22
  ALLOWED_CAUSES,
@@ -48,8 +54,19 @@ __all__ = [
48
54
  ]
49
55
 
50
56
 
57
+ _CLI_EPILOG = r"""Usage:
58
+ okstra error-log <subcommand> [...] # e.g. append-observed / append-from-worker
59
+
60
+ See `okstra error-log append-observed --help` for that subcommand's options.
61
+ """
62
+
63
+
51
64
  def _build_parser():
52
- p = argparse.ArgumentParser(description="OKSTRA error log helper")
65
+ p = argparse.ArgumentParser(
66
+ prog="okstra error-log",
67
+ epilog=_CLI_EPILOG,
68
+ formatter_class=argparse.RawDescriptionHelpFormatter,
69
+ description="OKSTRA error log helper")
53
70
  sub = p.add_subparsers(dest="cmd", required=True)
54
71
 
55
72
  obs = sub.add_parser("append-observed",
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python3
2
+ """한 모듈이 현재 PYTHONPATH 로 import 되는지 확인한다 — `okstra doctor` 전용.
3
+
4
+ 별도 파일인 이유: 이 프로브는 `okstra_ctl` 자체의 import 가능성도 검사한다.
5
+ `python3 -m okstra_ctl.<x>` 로 부르면 검사 대상이 못 뜰 때 프로브도 같이 죽어
6
+ "모듈이 없다"와 "프로브가 없다"를 구분할 수 없다. 그래서 okstra 를 import 하지
7
+ 않는 독립 파일로 두고 경로로 호출한다.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import importlib
12
+ import sys
13
+
14
+
15
+ def main(argv: list[str]) -> int:
16
+ if len(argv) != 1:
17
+ sys.stderr.write("usage: okstra-import-check.py <module>\n")
18
+ return 2
19
+ name = argv[0]
20
+ module = importlib.import_module(name)
21
+ print(getattr(module, "__name__", name))
22
+ return 0
23
+
24
+
25
+ if __name__ == "__main__":
26
+ raise SystemExit(main(sys.argv[1:]))
@@ -21,10 +21,10 @@ import argparse
21
21
  import sys
22
22
  from pathlib import Path
23
23
 
24
- _HERE = Path(__file__).resolve().parent
25
- # Make ``okstra_ctl`` importable for in-repo invocation (the installed
26
- # runtime adds ``~/.okstra/lib/python`` via the wrapper scripts).
27
- sys.path.insert(0, str(_HERE))
24
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
25
+ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
26
+
27
+ prefer_colocated_modules(__file__, "okstra_ctl/render_final_report.py")
28
28
 
29
29
  from okstra_ctl.i18n import SUPPORTED_LANGS # noqa: E402
30
30
  from okstra_ctl.render_final_report import ( # noqa: E402
@@ -35,6 +35,7 @@ from okstra_ctl.render_final_report import ( # noqa: E402
35
35
 
36
36
  def main(argv: list[str]) -> int:
37
37
  parser = argparse.ArgumentParser(
38
+ prog="okstra inject-report-index",
38
39
  description="Inject the top-of-report index + scroll anchors into a free-form markdown report.",
39
40
  )
40
41
  parser.add_argument(
@@ -9,23 +9,16 @@ write scope in the order the CLIs are told it, and the role's idle budget.
9
9
  from __future__ import annotations
10
10
 
11
11
  import json
12
- import os
13
12
  import shutil
14
13
  import sys
15
14
  from dataclasses import dataclass
16
15
  from pathlib import Path
17
16
  from typing import Any, Callable, Mapping
18
17
 
19
- _HERE = Path(__file__).resolve().parent
20
- # ``okstra_ctl`` sits beside this file in the repo (``scripts/``) but under
21
- # ``~/.okstra/lib/python/`` once installed, and the four-line shell entrypoints
22
- # that exec this script set no PYTHONPATH. Offer both, repo first.
23
- _HOME_LIB = (
24
- Path(os.environ.get("OKSTRA_HOME", str(Path.home() / ".okstra"))) / "lib" / "python"
25
- )
26
- sys.path.insert(0, str(_HERE))
27
- if _HOME_LIB.is_dir() and str(_HOME_LIB) not in sys.path:
28
- sys.path.append(str(_HOME_LIB))
18
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
19
+ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
20
+
21
+ prefer_colocated_modules(__file__, "okstra_ctl/domain/provider.py")
29
22
 
30
23
  from okstra_ctl.domain.provider import ( # noqa: E402
31
24
  ProviderSpec,
@@ -54,7 +47,7 @@ from okstra_ctl.write_policy import ( # noqa: E402
54
47
  write_policy_from_payload,
55
48
  )
56
49
  from okstra_ctl.model_pool import ModelPool # noqa: E402
57
- from okstra_ctl.agent_invocation import ( # noqa: E402
50
+ from okstra_ctl.agent.invocation import ( # noqa: E402
58
51
  AgentInvocationError,
59
52
  agent_model_assignment_from_payload,
60
53
  invocation_metadata_identity,
@@ -259,11 +252,12 @@ def _v2_status_extra(
259
252
  recorded = project_root / recorded
260
253
  if recorded.resolve(strict=False) != prompt_path.resolve(strict=True):
261
254
  raise PreflightError(64, "invocation metadata prompt does not match wrapper")
262
- role_execution, invocation, pool = _execution_authority(
255
+ role_execution, attempt_row, pool = _execution_authority(
263
256
  metadata=metadata,
264
257
  project_root=project_root,
265
258
  role_execution_ref=identity.role_execution_ref,
266
259
  invocation_ref=identity.invocation_ref,
260
+ attempt=identity.attempt,
267
261
  )
268
262
  binding = role_execution.binding
269
263
  if (
@@ -290,9 +284,9 @@ def _v2_status_extra(
290
284
  return ""
291
285
 
292
286
  try:
293
- write_policy = write_policy_from_payload(invocation.write_policy)
287
+ write_policy = write_policy_from_payload(attempt_row.write_policy)
294
288
  write_enforcement = write_enforcement_from_payload(
295
- invocation.write_enforcement
289
+ attempt_row.write_enforcement
296
290
  )
297
291
  except ValueError as exc:
298
292
  raise PreflightError(64, f"invocation write contract is invalid: {exc}") from exc
@@ -312,7 +306,7 @@ def _v2_status_extra(
312
306
  "level": "unknown",
313
307
  "source": "unavailable",
314
308
  },
315
- "writePolicyDigest": invocation.write_policy_digest,
309
+ "writePolicyDigest": attempt_row.write_policy_digest,
316
310
  "writeEnforcement": write_enforcement.to_payload(),
317
311
  }, verify_attestation, write_policy, write_enforcement)
318
312
 
@@ -323,6 +317,7 @@ def _execution_authority(
323
317
  project_root: Path,
324
318
  role_execution_ref: str,
325
319
  invocation_ref: str,
320
+ attempt: int,
326
321
  ):
327
322
  source = metadata.get("contractSource")
328
323
  manifest_raw = source.get("runManifestPath") if isinstance(source, Mapping) else None
@@ -353,9 +348,19 @@ def _execution_authority(
353
348
  raise PreflightError(
354
349
  64, "invocation metadata invocation does not match run manifest"
355
350
  )
351
+ # 쓰기 계약은 이 시도의 행에 있다. invocation 으로 찾으면 재시도가 1회차의
352
+ # 허용 경로를 물고 자기 로그·상태 사이드카를 못 쓴다.
353
+ attempt_row = next((
354
+ row for row in manifest.attempts
355
+ if row.invocation_ref == invocation_ref and row.attempt == attempt
356
+ ), None)
357
+ if attempt_row is None:
358
+ raise PreflightError(
359
+ 64, "invocation metadata attempt does not match run manifest"
360
+ )
356
361
  return (
357
362
  role_execution,
358
- invocation,
363
+ attempt_row,
359
364
  ModelPool.from_registry(default_provider_registry()),
360
365
  )
361
366
 
@@ -19,12 +19,10 @@ import argparse
19
19
  import sys
20
20
  from pathlib import Path
21
21
 
22
- _HERE = Path(__file__).resolve().parent
23
- # Make ``okstra_ctl`` and ``okstra_vendor`` importable when running from
24
- # repo (``scripts/`` is the parent of these packages). The installed
25
- # runtime adds ``~/.okstra/lib/python`` to PYTHONPATH via the wrapper
26
- # scripts; for in-repo invocation we add ``scripts/`` explicitly.
27
- sys.path.insert(0, str(_HERE))
22
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
23
+ from okstra_bootstrap import prefer_colocated_modules # noqa: E402
24
+
25
+ prefer_colocated_modules(__file__, "okstra_ctl/render_final_report.py")
28
26
 
29
27
  from okstra_ctl.final_report_paths import final_report_markdown_path # noqa: E402
30
28
  from okstra_ctl.render_final_report import ( # noqa: E402
@@ -34,8 +32,20 @@ from okstra_ctl.render_final_report import ( # noqa: E402
34
32
  )
35
33
 
36
34
 
35
+ _CLI_EPILOG = r"""Usage:
36
+ okstra render-final-report <path-to-final-report.data.json>
37
+
38
+ schemaVersion 1.0
39
+ keeps the legacy Markdown template; schemaVersion 2.0 selects the full reading
40
+ copy template. Human HTML is rendered separately from the same data.json.
41
+ """
42
+
43
+
37
44
  def main(argv: list[str]) -> int:
38
45
  parser = argparse.ArgumentParser(
46
+ prog="okstra render-final-report",
47
+ epilog=_CLI_EPILOG,
48
+ formatter_class=argparse.RawDescriptionHelpFormatter,
39
49
  description="Render a final-report markdown from its JSON SSOT.",
40
50
  )
41
51
  parser.add_argument(