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
@@ -0,0 +1,408 @@
1
+ """프롬프트를 실제로 찍어 낸다 — run 에 매인 것과 독립 실행 두 갈래.
2
+
3
+ `--run-manifest` 가 있으면 run 갈래다: 매니페스트에서 신원을 확인하고, 필요하면
4
+ 동적 검증자를 예약하고, 그 run 의 산출물 경로로 프롬프트를 쓴다. 없으면 독립
5
+ 갈래다: 인자로 받은 audience·duty 를 스냅샷해 감사 가능한 명세를 만든다. 두
6
+ 갈래가 같은 파일에 있는 이유는 `_materialize` 가 둘 중 하나를 고르는 유일한
7
+ 분기점이기 때문이다.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import os
13
+ from pathlib import Path
14
+ import shutil
15
+ import tempfile
16
+ from typing import get_args
17
+
18
+ from ..invocation import (
19
+ AgentInstruction,
20
+ AgentInstructionSource,
21
+ AgentAudience,
22
+ AgentInvocationRequest,
23
+ AgentModelAssignment,
24
+ PreparedAgentInvocation,
25
+ agent_model_assignment_from_payload,
26
+ digest_duty_catalog,
27
+ invocation_execution_identity_from_manifest,
28
+ prepare_agent_invocation,
29
+ )
30
+ from ...assignment_environment import load_assignment_context
31
+ from ...assignment_resolver import AssignmentContext, resolve_dispatch_assignment
32
+ from ...path_hints import hydrate_active_run_context
33
+ from ...worker_prompt_headers import worker_prompt_headers
34
+ from ...report_inputs import report_narrative_path, uses_report_contract_v3
35
+ from ...dispatch_state import detect_terminal_backend
36
+ from .dynamic_verifier import (
37
+ _dynamic_verifier_source,
38
+ _reserve_dynamic_verifier_request,
39
+ )
40
+ from .inputs import (
41
+ AgentPromptCliError,
42
+ _authorized_path,
43
+ _exact_path,
44
+ _is_relative_to,
45
+ _is_slug,
46
+ _mapping,
47
+ _project_input,
48
+ _project_manifest_path,
49
+ _project_root,
50
+ _read_json_object,
51
+ _relative,
52
+ )
53
+ from .run_identity import _validate_run_identity
54
+
55
+
56
+ _AUDIENCES = frozenset(get_args(AgentAudience))
57
+
58
+
59
+ def _materialize(args: argparse.Namespace) -> PreparedAgentInvocation:
60
+ project_root = _project_root(args.project_root)
61
+ if args.run_manifest:
62
+ return _materialize_run(args, project_root)
63
+ return _materialize_standalone(args, project_root)
64
+
65
+
66
+ def _materialize_run(
67
+ args: argparse.Namespace,
68
+ project_root: Path,
69
+ ) -> PreparedAgentInvocation:
70
+ required = {
71
+ "worker-id": args.worker_id,
72
+ "dispatch-kind": args.dispatch_kind,
73
+ "assignment-ref": args.assignment_ref,
74
+ "result": args.result,
75
+ }
76
+ missing = [name for name, value in required.items() if not value]
77
+ if missing:
78
+ raise AgentPromptCliError(
79
+ f"run materialization requires: {', '.join('--' + name for name in missing)}"
80
+ )
81
+ forbidden = {
82
+ "host-runtime": args.host_runtime,
83
+ "provider": args.provider,
84
+ "model-role": args.model_role,
85
+ "model": args.model,
86
+ "purpose": args.purpose,
87
+ }
88
+ present = [name for name, value in forbidden.items() if value]
89
+ if present:
90
+ raise AgentPromptCliError(
91
+ f"run materialization forbids: {', '.join('--' + name for name in present)}"
92
+ )
93
+ manifest_path = _project_input(project_root, args.run_manifest, "run manifest")
94
+ manifest = _read_json_object(manifest_path, "run manifest")
95
+ contract = _mapping(manifest.get("agentContract"), "run agent contract")
96
+ authorized = _mapping(contract.get("authorizedPaths"), "authorized paths")
97
+
98
+ instruction_path = _authorized_path(
99
+ project_root,
100
+ args.instruction,
101
+ authorized.get("instructionRoots"),
102
+ "instruction",
103
+ must_exist=True,
104
+ )
105
+ prompt_path = _authorized_path(
106
+ project_root,
107
+ args.prompt,
108
+ authorized.get("promptRoots"),
109
+ "prompt",
110
+ must_exist=False,
111
+ )
112
+ result_path = _authorized_path(
113
+ project_root,
114
+ args.result,
115
+ authorized.get("resultRoots"),
116
+ "result",
117
+ must_exist=False,
118
+ )
119
+ if args.audience == "report-writer" and not args.audit_source:
120
+ # The report writer is the one audience whose result path is not its own
121
+ # worker result: it writes the report body, while the audit sidecar is
122
+ # derived from its `.md`. With both collapsed into one value the prompt
123
+ # loses its `**Worker Result Path:**` anchor and the writer puts the
124
+ # report where the audit file belongs — silently, because every header
125
+ # is still present and well-formed. The roster path derives both from
126
+ # the manifest; a dynamic call has to name them.
127
+ #
128
+ # Which artifact `--result` names depends on the report contract, and
129
+ # `dispatch_state.dispatch_result_path` is what decides it. Naming only
130
+ # the v2 answer here sent v3 runs to the data.json, so the narrative
131
+ # `report-finalize` assembles from was never written and the phase
132
+ # failed later, at a place that does not point back here.
133
+ if uses_report_contract_v3(manifest):
134
+ expected = report_narrative_path(project_root, manifest)
135
+ raise AgentPromptCliError(
136
+ "report-writer materialization requires --audit-source: under "
137
+ f"report contract 3.0 --result is the narrative ({expected}), "
138
+ "which `report-finalize` assembles the report data.json from, "
139
+ "and --audit-source the worker-result .md the audit sidecar is "
140
+ "derived from"
141
+ )
142
+ raise AgentPromptCliError(
143
+ "report-writer materialization requires --audit-source: under "
144
+ "report contract 2.0 --result is the report data.json, and "
145
+ "--audit-source the worker-result .md the audit sidecar is "
146
+ "derived from"
147
+ )
148
+ audit_source_path = (
149
+ _authorized_path(
150
+ project_root,
151
+ args.audit_source,
152
+ authorized.get("resultRoots"),
153
+ "audit source",
154
+ must_exist=False,
155
+ )
156
+ if args.audit_source
157
+ else result_path
158
+ )
159
+ _validate_run_identity(
160
+ manifest,
161
+ worker_id=args.worker_id,
162
+ dispatch_kind=args.dispatch_kind,
163
+ assignment_ref=args.assignment_ref,
164
+ audience=args.audience,
165
+ )
166
+ assignments = _mapping(
167
+ manifest.get("invocationAssignments"),
168
+ "run invocation assignments",
169
+ )
170
+ if args.assignment_ref not in assignments:
171
+ # 유효값은 이 매니페스트 안에만 있고 리드는 그것을 추측할 수 없다.
172
+ # 이름만 거절하면 읽는 쪽이 매니페스트를 직접 열어 키를 세게 된다.
173
+ raise AgentPromptCliError(
174
+ f"assignment reference is missing from run manifest: "
175
+ f"{args.assignment_ref}; this run declares "
176
+ + (", ".join(sorted(assignments)) or "no invocation assignment")
177
+ )
178
+ assignment_payload = assignments[args.assignment_ref]
179
+ assignment = agent_model_assignment_from_payload(assignment_payload)
180
+ dynamic_source = _dynamic_verifier_source(args, manifest)
181
+ identity = (
182
+ None
183
+ if dynamic_source is not None
184
+ else invocation_execution_identity_from_manifest(
185
+ manifest,
186
+ assignment=assignment,
187
+ assignment_ref=args.assignment_ref,
188
+ duty_id=args.audience,
189
+ )
190
+ )
191
+ duty_root = _project_manifest_path(
192
+ project_root,
193
+ contract.get("dutyRootPath"),
194
+ "duty root",
195
+ must_exist=True,
196
+ )
197
+ if contract.get("catalogDigest") != digest_duty_catalog(duty_root):
198
+ raise AgentPromptCliError("run duty snapshot catalog digest does not match")
199
+ active_context_path = _project_manifest_path(
200
+ project_root,
201
+ manifest.get("activeRunContextPath"),
202
+ "active run context",
203
+ must_exist=True,
204
+ )
205
+ active_context = hydrate_active_run_context(
206
+ _read_json_object(active_context_path, "active run context")
207
+ )
208
+ prompt_rel = _relative(project_root, prompt_path)
209
+ result_rel = _relative(project_root, result_path)
210
+ audit_rel = _relative(project_root, audit_source_path)
211
+ anchor_lines = tuple(worker_prompt_headers(
212
+ project_root=project_root,
213
+ prompt_rel=prompt_rel,
214
+ result_rel=result_rel,
215
+ audit_source_rel=audit_rel,
216
+ worker_id=args.worker_id,
217
+ dispatch_kind=args.dispatch_kind,
218
+ manifest=manifest,
219
+ active_context=active_context,
220
+ ))
221
+ request = AgentInvocationRequest(
222
+ invocation_id=args.invocation_id,
223
+ worker_id=args.worker_id if identity is None else None,
224
+ audience=args.audience,
225
+ assignment_ref=args.assignment_ref,
226
+ purpose=None,
227
+ assignment=assignment,
228
+ instruction=AgentInstruction(
229
+ anchor_lines=anchor_lines,
230
+ body=instruction_path.read_text(encoding="utf-8"),
231
+ source_paths=(AgentInstructionSource(
232
+ kind="project",
233
+ path=_relative(project_root, instruction_path),
234
+ ),),
235
+ ),
236
+ project_root=project_root,
237
+ run_manifest_path=manifest_path,
238
+ duty_root=duty_root,
239
+ prompt_path=prompt_path,
240
+ metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
241
+ dispatch_kind=args.dispatch_kind,
242
+ participant_ref=identity.participant_ref if identity is not None else None,
243
+ role_execution_ref=(
244
+ identity.role_execution_ref if identity is not None else None
245
+ ),
246
+ duty_id=identity.duty_id if identity is not None else None,
247
+ invocation_ref=args.invocation_id if identity is not None else None,
248
+ attempt=1,
249
+ replace_undispatched=args.replace_undispatched,
250
+ )
251
+ if dynamic_source is not None:
252
+ request = _reserve_dynamic_verifier_request(
253
+ request,
254
+ args=args,
255
+ manifest=manifest,
256
+ manifest_path=manifest_path,
257
+ source_role_execution_ref=dynamic_source,
258
+ )
259
+ return prepare_agent_invocation(request)
260
+
261
+
262
+ def _materialize_standalone(
263
+ args: argparse.Namespace,
264
+ project_root: Path,
265
+ ) -> PreparedAgentInvocation:
266
+ required = {
267
+ "host-runtime": args.host_runtime,
268
+ "provider": args.provider,
269
+ "model-role": args.model_role,
270
+ "purpose": args.purpose,
271
+ }
272
+ missing = [name for name, value in required.items() if not value]
273
+ if missing:
274
+ raise AgentPromptCliError(
275
+ "standalone materialization requires: "
276
+ + ", ".join("--" + name for name in missing)
277
+ )
278
+ forbidden = {
279
+ "worker-id": args.worker_id,
280
+ "dispatch-kind": args.dispatch_kind,
281
+ "assignment-ref": args.assignment_ref,
282
+ "result": args.result,
283
+ "audit-source": args.audit_source,
284
+ "source-role-execution-ref": args.source_role_execution_ref,
285
+ }
286
+ present = [name for name, value in forbidden.items() if value]
287
+ if present:
288
+ raise AgentPromptCliError(
289
+ "standalone materialization forbids: "
290
+ + ", ".join("--" + name for name in present)
291
+ )
292
+ if not _is_slug(args.purpose) or not _is_slug(args.invocation_id):
293
+ raise AgentPromptCliError("standalone purpose and invocation ID must be slugs")
294
+ if args.audience not in _AUDIENCES:
295
+ raise AgentPromptCliError(f"unknown duty audience: {args.audience}")
296
+ root = project_root / ".okstra" / "agent-invocations" / args.purpose
297
+ if not root.is_dir():
298
+ raise AgentPromptCliError(f"standalone invocation root not found: {root}")
299
+ resolved_root = root.resolve(strict=True)
300
+ if not _is_relative_to(resolved_root, project_root):
301
+ raise AgentPromptCliError("standalone invocation root escapes project root")
302
+ root = resolved_root
303
+ expected_instruction = root / f"{args.invocation_id}.instructions.md"
304
+ expected_prompt = root / f"{args.invocation_id}.prompt.md"
305
+ instruction_path = _exact_path(args.instruction, expected_instruction, True, "instruction")
306
+ prompt_path = _exact_path(args.prompt, expected_prompt, False, "prompt")
307
+ assignment_context = load_assignment_context(
308
+ host_runtime=args.host_runtime,
309
+ terminal_backend=args.terminal_backend or detect_terminal_backend(),
310
+ execution_provider_ids=(args.provider,),
311
+ include_native_provider=False,
312
+ )
313
+ assignment = _standalone_assignment(
314
+ context=assignment_context,
315
+ provider=args.provider,
316
+ model_role=args.model_role,
317
+ model=args.model,
318
+ )
319
+ duty_root = root / f"{args.invocation_id}.duty-contracts"
320
+ _snapshot_standalone_duties(duty_root)
321
+ return prepare_agent_invocation(AgentInvocationRequest(
322
+ invocation_id=args.invocation_id,
323
+ worker_id=None,
324
+ audience=args.audience,
325
+ assignment_ref=None,
326
+ purpose=args.purpose,
327
+ assignment=assignment,
328
+ instruction=AgentInstruction(
329
+ anchor_lines=(),
330
+ body=instruction_path.read_text(encoding="utf-8"),
331
+ source_paths=(AgentInstructionSource(
332
+ kind="project",
333
+ path=_relative(project_root, instruction_path),
334
+ ),),
335
+ ),
336
+ project_root=project_root,
337
+ run_manifest_path=None,
338
+ duty_root=duty_root,
339
+ prompt_path=prompt_path,
340
+ metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
341
+ dispatch_kind="standalone",
342
+ participant_ref=None,
343
+ role_execution_ref=None,
344
+ duty_id=None,
345
+ invocation_ref=None,
346
+ attempt=1,
347
+ ))
348
+
349
+
350
+ def _standalone_assignment(
351
+ *,
352
+ context: AssignmentContext,
353
+ provider: str,
354
+ model_role: str,
355
+ model: str,
356
+ ) -> AgentModelAssignment:
357
+ host_runtime = context.environment.host_descriptor.id
358
+ resolved = resolve_dispatch_assignment(
359
+ context=context,
360
+ host_runtime=host_runtime,
361
+ role=model_role,
362
+ duty_id=model_role,
363
+ provider=provider,
364
+ model=model,
365
+ )
366
+ binding = resolved.binding
367
+ if binding is None:
368
+ raise AgentPromptCliError("standalone assignment requires a model binding")
369
+ return AgentModelAssignment(
370
+ provider=resolved.provider_id,
371
+ model=resolved.display_name,
372
+ model_execution_value=binding.resolved_execution_value,
373
+ runner=binding.runner,
374
+ host_runtime=host_runtime,
375
+ host_model_value=binding.host_model_value,
376
+ )
377
+
378
+
379
+ def _snapshot_standalone_duties(destination: Path) -> None:
380
+ # 부모 개수를 세면 체크아웃(`<root>/scripts/okstra_ctl/agent/prompt_cli/`)
381
+ # 에서만 맞는다 — 설치본은 패키지가 `~/.okstra/lib/python/` 이라 prompts 가
382
+ # 한 단계 위(`~/.okstra/prompts/`)에 있다. duties 를 실제로 가진 루트를
383
+ # 탐색해서 해소한다.
384
+ from ...paths import find_asset_root
385
+
386
+ duties_relative = ("prompts", "duties")
387
+ root = find_asset_root(duties_relative, is_present=Path.is_dir)
388
+ if root is None:
389
+ raise AgentPromptCliError(
390
+ "duty contract source not found: no prompts/duties under "
391
+ "OKSTRA_HOME or this checkout"
392
+ )
393
+ source = root.joinpath(*duties_relative)
394
+ if destination.exists():
395
+ if not destination.is_dir() or digest_duty_catalog(destination) != digest_duty_catalog(source):
396
+ raise AgentPromptCliError("standalone duty snapshot conflicts with existing files")
397
+ return
398
+ temporary = Path(tempfile.mkdtemp(prefix=f".{destination.name}.", dir=destination.parent))
399
+ try:
400
+ shutil.copytree(source, temporary, dirs_exist_ok=True)
401
+ try:
402
+ os.rename(temporary, destination)
403
+ except FileExistsError:
404
+ if digest_duty_catalog(destination) != digest_duty_catalog(source):
405
+ raise AgentPromptCliError("standalone duty snapshot publication conflict")
406
+ finally:
407
+ if temporary.exists():
408
+ shutil.rmtree(temporary)
@@ -0,0 +1,197 @@
1
+ """찍어 낸 명세와 워커가 낸 결과를 잇는다.
2
+
3
+ materialize 가 만든 명세에 대해, 이 층은 그 뒤에 오는 것들을 다룬다 — 디스패치
4
+ 기록, 결과 링크, 거절, 완료 표시, 검증. 전부 이미 존재하는 명세를 전제하고,
5
+ 새 명세를 만들지 않는다.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import argparse
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+
13
+ from ..invocation import (
14
+ AgentModelAssignment,
15
+ agent_model_assignment_from_payload,
16
+ materialize_standalone_result,
17
+ publish_standalone_completion,
18
+ verify_standalone_completion,
19
+ verify_agent_invocation,
20
+ )
21
+ from ...dispatch_state import (
22
+ link_agent_dispatch_result,
23
+ record_verified_agent_dispatch,
24
+ abandon_agent_dispatch_attempt,
25
+ reject_agent_dispatch_result,
26
+ )
27
+ from .emit import _emit
28
+ from .inputs import (
29
+ AgentPromptCliError,
30
+ _is_relative_to,
31
+ _mapping,
32
+ _project_input,
33
+ _project_root,
34
+ _read_json_object,
35
+ )
36
+
37
+
38
+ def _record_dispatch(args: argparse.Namespace) -> None:
39
+ project_root = _project_root(args.project_root)
40
+ record = record_verified_agent_dispatch(
41
+ project_root=project_root,
42
+ run_manifest_path=_project_input(
43
+ project_root, args.run_manifest, "run manifest"
44
+ ),
45
+ metadata_path=_project_input(
46
+ project_root, args.metadata, "agent invocation metadata"
47
+ ),
48
+ enforcement_mode=args.enforcement_mode,
49
+ )
50
+ _emit(record, args.json)
51
+
52
+
53
+ def _reject_result(args: argparse.Namespace) -> None:
54
+ project_root = _project_root(args.project_root)
55
+ row = reject_agent_dispatch_result(
56
+ project_root=project_root,
57
+ run_manifest_path=_project_input(
58
+ project_root, args.run_manifest, "run manifest"
59
+ ),
60
+ dispatch_id=args.dispatch_id,
61
+ superseded_by=args.superseded_by,
62
+ reason=args.reason,
63
+ )
64
+ _emit(row, args.json)
65
+
66
+
67
+ def _abandon_attempt(args: argparse.Namespace) -> None:
68
+ project_root = _project_root(args.project_root)
69
+ row = abandon_agent_dispatch_attempt(
70
+ project_root=project_root,
71
+ run_manifest_path=_project_input(
72
+ project_root, args.run_manifest, "run manifest"
73
+ ),
74
+ invocation_ref=args.invocation_ref,
75
+ reason=args.reason,
76
+ )
77
+ _emit(row, args.json)
78
+
79
+
80
+ def _link_result(args: argparse.Namespace) -> None:
81
+ project_root = _project_root(args.project_root)
82
+ link = link_agent_dispatch_result(
83
+ project_root=project_root,
84
+ run_manifest_path=_project_input(
85
+ project_root, args.run_manifest, "run manifest"
86
+ ),
87
+ dispatch_id=args.dispatch_id,
88
+ result_path=_project_input(project_root, args.result, "agent result"),
89
+ )
90
+ _emit(link, args.json)
91
+
92
+
93
+ def _verify(args: argparse.Namespace) -> None:
94
+ project_root = _project_root(args.project_root)
95
+ metadata_path = _project_input(project_root, args.metadata, "metadata")
96
+ metadata = _read_json_object(metadata_path, "metadata")
97
+ contract_source = _mapping(metadata.get("contractSource"), "contract source")
98
+ mode = contract_source.get("mode")
99
+ expected_manifest: Path | None = None
100
+ expected_assignment: AgentModelAssignment | None = None
101
+ if mode == "run":
102
+ if not args.run_manifest:
103
+ raise AgentPromptCliError("run invocation verification requires --run-manifest")
104
+ expected_manifest = _project_input(project_root, args.run_manifest, "run manifest")
105
+ manifest = _read_json_object(expected_manifest, "run manifest")
106
+ assignments = _mapping(manifest.get("invocationAssignments"), "run assignments")
107
+ reference = metadata.get("assignmentRef")
108
+ if not isinstance(reference, str) or reference not in assignments:
109
+ raise AgentPromptCliError("assignment reference is missing from run manifest")
110
+ expected_assignment = agent_model_assignment_from_payload(assignments[reference])
111
+ elif mode == "standalone":
112
+ if args.run_manifest:
113
+ raise AgentPromptCliError("standalone invocation verification forbids --run-manifest")
114
+ else:
115
+ raise AgentPromptCliError("contract source mode is invalid")
116
+ errors = verify_agent_invocation(
117
+ metadata_path,
118
+ project_root=project_root,
119
+ expected_run_manifest_path=expected_manifest,
120
+ expected_assignment=expected_assignment,
121
+ )
122
+ if errors:
123
+ raise AgentPromptCliError("; ".join(errors))
124
+
125
+
126
+ def _materialize_result(args: argparse.Namespace) -> None:
127
+ project_root = _project_root(args.project_root)
128
+ metadata_path = _project_input(project_root, args.metadata, "metadata")
129
+ root = project_root / ".okstra" / "agent-invocations" / args.purpose
130
+ temporary_root = root / ".tmp"
131
+ returned_body_path = _project_input(
132
+ project_root,
133
+ args.returned_body_file,
134
+ "returned body",
135
+ )
136
+ if not temporary_root.is_dir() or not _is_relative_to(
137
+ returned_body_path,
138
+ temporary_root.resolve(strict=True),
139
+ ):
140
+ raise AgentPromptCliError(
141
+ "returned body file must be inside the standalone purpose .tmp directory"
142
+ )
143
+ result = materialize_standalone_result(
144
+ project_root=project_root,
145
+ purpose=args.purpose,
146
+ metadata_path=metadata_path,
147
+ returned_body=returned_body_path.read_bytes(),
148
+ )
149
+ _emit({
150
+ "ok": True,
151
+ "purpose": result.purpose,
152
+ "invocationId": result.invocation_id,
153
+ "metadataPath": str(result.prompt_metadata_path),
154
+ "resultPath": str(result.result_path),
155
+ "resultEnvelopeDigest": result.result_envelope_digest,
156
+ }, args.json)
157
+
158
+
159
+ def _complete(args: argparse.Namespace) -> None:
160
+ project_root = _project_root(args.project_root)
161
+ metadata_path = _project_input(project_root, args.metadata, "metadata")
162
+ completion = publish_standalone_completion(
163
+ project_root=project_root,
164
+ purpose=args.purpose,
165
+ metadata_path=metadata_path,
166
+ completed_at=datetime.now(timezone.utc),
167
+ )
168
+ _emit({
169
+ "ok": True,
170
+ "purpose": args.purpose,
171
+ "metadataPath": str(metadata_path),
172
+ "completionPath": str(completion),
173
+ }, args.json)
174
+
175
+
176
+ def _verify_completion(args: argparse.Namespace) -> None:
177
+ project_root = _project_root(args.project_root)
178
+ completion_path = _project_input(
179
+ project_root,
180
+ args.completion,
181
+ "completion",
182
+ )
183
+ verified = verify_standalone_completion(
184
+ completion_path,
185
+ project_root=project_root,
186
+ expected_purpose=args.purpose,
187
+ )
188
+ _emit({
189
+ "ok": True,
190
+ "purpose": verified.purpose,
191
+ "invocationId": verified.invocation_id,
192
+ "metadataPath": str(verified.prompt_metadata_path),
193
+ "resultPath": str(verified.result_path),
194
+ "completionPath": str(verified.completion_path),
195
+ "resultEnvelopeDigest": verified.result_envelope_digest,
196
+ "returnedBody": verified.returned_body,
197
+ }, args.json)