okstra 0.186.7 → 0.188.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.
- package/README.md +1 -1
- package/dist/cli-registry.d.mts +88 -1
- package/dist/cli-registry.mjs +68 -111
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.mjs +0 -1
- package/dist/commands/execute/render-bundle.mjs.map +1 -1
- package/dist/commands/execute/run.mjs +8 -3
- package/dist/commands/execute/run.mjs.map +1 -1
- package/dist/commands/lifecycle/check-project.mjs +1 -14
- package/dist/commands/lifecycle/check-project.mjs.map +1 -1
- package/dist/commands/lifecycle/config.mjs +38 -40
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/dist/commands/lifecycle/doctor.d.mts +22 -7
- package/dist/commands/lifecycle/doctor.mjs +77 -49
- package/dist/commands/lifecycle/doctor.mjs.map +1 -1
- package/dist/commands/lifecycle/install.d.mts +12 -10
- package/dist/commands/lifecycle/install.mjs +107 -40
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/paths.mjs +8 -3
- package/dist/commands/lifecycle/paths.mjs.map +1 -1
- package/dist/commands/lifecycle/preflight.mjs +2 -1
- package/dist/commands/lifecycle/preflight.mjs.map +1 -1
- package/dist/commands/lifecycle/setup.mjs +22 -36
- package/dist/commands/lifecycle/setup.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.d.mts +4 -2
- package/dist/commands/lifecycle/uninstall.mjs +59 -15
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/commands/memory/memory.mjs +7 -1
- package/dist/commands/memory/memory.mjs.map +1 -1
- package/dist/lib/helper-scripts.d.mts +1 -1
- package/dist/lib/helper-scripts.mjs +10 -18
- package/dist/lib/helper-scripts.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +72 -0
- package/dist/lib/host-config.mjs +404 -0
- package/dist/lib/host-config.mjs.map +1 -0
- package/dist/lib/host-registry-client.d.mts +2 -2
- package/dist/lib/host-registry-client.mjs +0 -3
- package/dist/lib/host-registry-client.mjs.map +1 -1
- package/dist/lib/install-assets.d.mts +1 -0
- package/dist/lib/install-assets.mjs +4 -0
- package/dist/lib/install-assets.mjs.map +1 -1
- package/dist/lib/proc.d.mts +2 -0
- package/dist/lib/proc.mjs +12 -0
- package/dist/lib/proc.mjs.map +1 -1
- package/dist/lib/python-command.d.mts +2 -0
- package/dist/lib/python-command.mjs +52 -0
- package/dist/lib/python-command.mjs.map +1 -0
- package/dist/lib/python-helper.d.mts +2 -5
- package/dist/lib/python-helper.mjs +3 -52
- package/dist/lib/python-helper.mjs.map +1 -1
- package/dist/lib/runtime-payload.d.mts +23 -0
- package/dist/lib/runtime-payload.mjs +57 -0
- package/dist/lib/runtime-payload.mjs.map +1 -0
- package/dist/lib/types.d.mts +24 -13
- package/docs/architecture/storage-model.md +21 -5
- package/docs/architecture.md +39 -38
- package/docs/cli.md +55 -76
- package/docs/coding-rules.md +295 -0
- package/docs/container.md +10 -36
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/for-ai/skills/okstra-code-review.md +0 -1
- package/docs/for-ai/skills/okstra-container-build.md +8 -41
- package/docs/for-ai/skills/okstra-inspect.md +4 -4
- package/docs/for-ai/skills/okstra-manager.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +0 -1
- package/docs/for-ai/skills/okstra-run.md +3 -3
- package/docs/for-ai/skills/okstra-user-response.md +0 -1
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +62 -62
- package/docs/task-process/README.md +3 -3
- package/docs/task-process/common-flow.md +1 -1
- package/docs/task-process/error-analysis.md +3 -3
- package/docs/task-process/implementation-planning.md +3 -1
- package/docs/task-process/release-handoff.md +1 -1
- package/package.json +3 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +6 -11
- package/runtime/agents/workers/report-writer-worker.md +1 -1
- package/runtime/bin/lib/okstra/cli.sh +4 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/interactive.sh +26 -173
- package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/bin/okstra-compact-reminder.sh +1 -5
- package/runtime/bin/okstra-error-log.py +19 -2
- package/runtime/bin/okstra-import-check.py +26 -0
- package/runtime/bin/okstra-inject-report-index.py +5 -4
- package/runtime/bin/okstra-provider-exec.py +22 -17
- package/runtime/bin/okstra-render-final-report.py +16 -6
- package/runtime/bin/okstra-render-report-views.py +47 -22
- package/runtime/bin/okstra-report-translate.py +30 -18
- package/runtime/bin/okstra-spawn-followups.py +4 -0
- package/runtime/bin/okstra-token-usage.py +3 -0
- package/runtime/bin/okstra.sh +4 -2
- package/runtime/bin/okstra_bootstrap.py +58 -0
- package/runtime/prompts/coding-preflight/overview.md +1 -1
- package/runtime/prompts/duties/planning-worker.md +1 -1
- package/runtime/prompts/launch.template.md +35 -9
- package/runtime/prompts/lead/adapters/cmux.md +3 -3
- package/runtime/prompts/lead/convergence.md +99 -88
- package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
- package/runtime/prompts/lead/plan-body-verification.md +65 -46
- package/runtime/prompts/lead/report-writer.md +35 -5
- package/runtime/prompts/lead/team-contract.md +4 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +3 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
- package/runtime/prompts/profiles/error-analysis.md +4 -3
- package/runtime/prompts/profiles/final-verification.md +2 -2
- package/runtime/prompts/profiles/implementation-planning.md +22 -17
- package/runtime/prompts/profiles/implementation.md +3 -2
- package/runtime/prompts/profiles/requirements-discovery.md +2 -1
- package/runtime/prompts/wizard/prompts.ko.json +29 -8
- package/runtime/python/okstra_ctl/__init__.py +6 -27
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +63 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +20 -21
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
- package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
- package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
- package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +16 -2
- package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +228 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +605 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
- package/runtime/python/okstra_ctl/approval_decisions.py +287 -10
- package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
- package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
- package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
- package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
- package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
- package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
- package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
- package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
- package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
- package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
- package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
- package/runtime/python/okstra_ctl/cmux.py +38 -31
- package/runtime/python/okstra_ctl/code_review_target.py +163 -1
- package/runtime/python/okstra_ctl/conformance.py +23 -0
- package/runtime/python/okstra_ctl/container.py +38 -421
- package/runtime/python/okstra_ctl/context_cost.py +32 -4
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +107 -16
- package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
- package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
- package/runtime/python/okstra_ctl/convergence_store.py +5 -29
- package/runtime/python/okstra_ctl/design_prep.py +108 -12
- package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
- package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
- package/runtime/python/okstra_ctl/dispatch_core.py +236 -49
- package/runtime/python/okstra_ctl/dispatch_state.py +417 -41
- package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +28 -1
- package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
- package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
- package/runtime/python/okstra_ctl/error_log_core.py +1 -1
- package/runtime/python/okstra_ctl/error_report.py +14 -0
- package/runtime/python/okstra_ctl/error_zip.py +18 -2
- package/runtime/python/okstra_ctl/exact_coverage.py +5 -0
- package/runtime/python/okstra_ctl/execution_identity.py +100 -7
- package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
- package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +319 -17
- package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
- package/runtime/python/okstra_ctl/handoff.py +24 -1
- package/runtime/python/okstra_ctl/ids.py +6 -16
- package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
- package/runtime/python/okstra_ctl/implementation_options.py +32 -13
- package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
- package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
- package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
- package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
- package/runtime/python/okstra_ctl/index.py +2 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
- package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
- package/runtime/python/okstra_ctl/json_boundary.py +10 -0
- package/runtime/python/okstra_ctl/listing.py +0 -91
- package/runtime/python/okstra_ctl/locks.py +5 -19
- package/runtime/python/okstra_ctl/log_report.py +14 -0
- package/runtime/python/okstra_ctl/manager_cli.py +22 -3
- package/runtime/python/okstra_ctl/manager_launch.py +4 -8
- package/runtime/python/okstra_ctl/material.py +2 -2
- package/runtime/python/okstra_ctl/migrate.py +23 -1
- package/runtime/python/okstra_ctl/model_cli.py +19 -5
- package/runtime/python/okstra_ctl/model_discovery.py +46 -47
- package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
- package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
- package/runtime/python/okstra_ctl/model_io/references.py +370 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
- package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
- package/runtime/python/okstra_ctl/model_pool.py +10 -6
- package/runtime/python/okstra_ctl/models.py +8 -8
- package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
- package/runtime/python/okstra_ctl/next_phase.py +121 -69
- package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
- package/runtime/python/okstra_ctl/pane_title.py +11 -8
- package/runtime/python/okstra_ctl/path_hints.py +36 -11
- package/runtime/python/okstra_ctl/paths.py +76 -8
- package/runtime/python/okstra_ctl/plan_items.py +132 -16
- package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
- package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
- package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
- package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
- package/runtime/python/okstra_ctl/prepare_error.py +20 -0
- package/runtime/python/okstra_ctl/prior_planning.py +157 -0
- package/runtime/python/okstra_ctl/profile_show.py +18 -1
- package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
- package/runtime/python/okstra_ctl/recap.py +22 -1
- package/runtime/python/okstra_ctl/reconcile.py +84 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
- package/runtime/python/okstra_ctl/render.py +98 -32
- package/runtime/python/okstra_ctl/render_final_report.py +4 -8
- package/runtime/python/okstra_ctl/report_assembly.py +297 -7
- package/runtime/python/okstra_ctl/report_contract.py +30 -7
- package/runtime/python/okstra_ctl/report_finalize.py +213 -16
- package/runtime/python/okstra_ctl/report_html/common.py +2 -2
- package/runtime/python/okstra_ctl/report_html/render.py +8 -12
- package/runtime/python/okstra_ctl/report_language.py +8 -4
- package/runtime/python/okstra_ctl/report_narrative.py +220 -34
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +393 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- package/runtime/python/okstra_ctl/report_view_artifacts.py +42 -2
- package/runtime/python/okstra_ctl/report_views.py +4 -22
- package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
- package/runtime/python/okstra_ctl/rollup.py +13 -0
- package/runtime/python/okstra_ctl/run.py +639 -138
- package/runtime/python/okstra_ctl/run_audit.py +13 -0
- package/runtime/python/okstra_ctl/run_index_row.py +0 -12
- package/runtime/python/okstra_ctl/seeding.py +21 -11
- package/runtime/python/okstra_ctl/sequence.py +1 -1
- package/runtime/python/okstra_ctl/session.py +64 -14
- package/runtime/python/okstra_ctl/set_work_status.py +18 -0
- package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
- package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
- package/runtime/python/okstra_ctl/stage_map.py +57 -11
- package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
- package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
- package/runtime/python/okstra_ctl/stage_targets.py +3 -12
- package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
- package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
- package/runtime/python/okstra_ctl/task_target.py +4 -16
- package/runtime/python/okstra_ctl/team.py +49 -2
- package/runtime/python/okstra_ctl/time_report.py +17 -2
- package/runtime/python/okstra_ctl/usage_report.py +11 -0
- package/runtime/python/okstra_ctl/user_response.py +55 -218
- package/runtime/python/okstra_ctl/user_response_values.py +242 -0
- package/runtime/python/okstra_ctl/validation_contract.py +3 -0
- package/runtime/python/okstra_ctl/verdict_blocks.py +28 -8
- package/runtime/python/okstra_ctl/verification_target.py +68 -0
- package/runtime/python/okstra_ctl/wizard.py +457 -92
- package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
- package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
- package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
- package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
- package/runtime/python/okstra_ctl/worker_request.py +2 -1
- package/runtime/python/okstra_ctl/worker_runner.py +58 -17
- package/runtime/python/okstra_ctl/worker_state.py +16 -1
- package/runtime/python/okstra_ctl/workflow.py +18 -1
- package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
- package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
- package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
- package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
- package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
- package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
- package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
- package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
- package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
- package/runtime/python/okstra_ctl/write_policy.py +90 -213
- package/runtime/python/okstra_project/__init__.py +0 -4
- package/runtime/python/okstra_project/dirs.py +2 -2
- package/runtime/python/okstra_project/phase_pointer.py +84 -0
- package/runtime/python/okstra_project/slug.py +24 -0
- package/runtime/python/okstra_project/state.py +22 -230
- package/runtime/python/okstra_token_usage/antigravity.py +50 -12
- package/runtime/python/okstra_token_usage/claude.py +9 -1
- package/runtime/python/okstra_token_usage/cli.py +3 -1
- package/runtime/python/okstra_token_usage/collect.py +171 -36
- package/runtime/python/okstra_token_usage/cursor.py +2 -0
- package/runtime/python/okstra_token_usage/grok.py +1 -5
- package/runtime/python/okstra_token_usage/paths.py +26 -0
- package/runtime/python/okstra_token_usage/pricing.py +23 -8
- package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
- package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
- package/runtime/schemas/final-report-v2.0.schema.json +9 -26
- package/runtime/schemas/final-report-v3.0.schema.json +173 -41
- package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
- package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
- package/runtime/skills/okstra-container-build/SKILL.md +16 -47
- package/runtime/skills/okstra-inspect/facets/history.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +7 -6
- package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +7 -5
- package/runtime/templates/report-writer-prompt-preamble.md +3 -1
- package/runtime/templates/reports/brief.template.md +6 -2
- package/runtime/templates/reports/error-analysis-input.template.md +2 -0
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/implementation-input.template.md +7 -1
- package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
- package/runtime/templates/reports/quick-input.template.md +2 -0
- package/runtime/templates/reports/release-handoff-input.template.md +6 -1
- package/runtime/templates/reports/report.js +20 -3
- package/runtime/templates/reports/schedule.template.md +2 -0
- package/runtime/templates/reports/settings.template.json +0 -10
- package/runtime/templates/reports/task-brief.template.md +3 -0
- package/runtime/templates/reports/user-response.template.md +7 -3
- package/runtime/validators/checks/fixtures-01.py +57 -0
- package/runtime/validators/checks/fixtures-02.py +565 -0
- package/runtime/validators/checks/runners-01.py +108 -0
- package/runtime/validators/checks/validate-assets-01.py +60 -0
- package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
- package/runtime/validators/checks/validate-tasks-01.py +46 -0
- package/runtime/validators/checks/validate-tasks-02.py +85 -0
- package/runtime/validators/checks/validate-tasks-03.py +61 -0
- package/runtime/validators/checks/validate-tasks-04.py +118 -0
- package/runtime/validators/forbidden_actions.py +73 -3
- package/runtime/validators/lib/common.sh +5 -0
- package/runtime/validators/lib/fixtures.sh +7 -591
- package/runtime/validators/lib/paths.sh +13 -0
- package/runtime/validators/lib/runners.sh +6 -104
- package/runtime/validators/lib/summary.sh +1 -1
- package/runtime/validators/lib/validate-assets.sh +6 -56
- package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
- package/runtime/validators/lib/validate-tasks.sh +9 -294
- package/runtime/validators/validate-implementation-plan-stages.py +4 -4
- package/runtime/validators/validate-run.py +1363 -2643
- package/runtime/validators/validate-workflow.sh +56 -16
- package/runtime/validators/validate_improvement_report.py +2 -1
- package/runtime/validators/validate_session_conformance.py +295 -49
- package/dist/commands/execute/agent-prompt.d.mts +0 -1
- package/dist/commands/execute/agent-prompt.mjs +0 -24
- package/dist/commands/execute/agent-prompt.mjs.map +0 -1
- package/dist/commands/execute/codex-dispatch.d.mts +0 -3
- package/dist/commands/execute/codex-dispatch.mjs +0 -6
- package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
- package/dist/commands/execute/codex-run.d.mts +0 -3
- package/dist/commands/execute/codex-run.mjs +0 -62
- package/dist/commands/execute/codex-run.mjs.map +0 -1
- package/dist/commands/execute/convergence.d.mts +0 -1
- package/dist/commands/execute/convergence.mjs +0 -38
- package/dist/commands/execute/convergence.mjs.map +0 -1
- package/dist/commands/execute/error-log.d.mts +0 -1
- package/dist/commands/execute/error-log.mjs +0 -18
- package/dist/commands/execute/error-log.mjs.map +0 -1
- package/dist/commands/execute/git-reconcile.d.mts +0 -1
- package/dist/commands/execute/git-reconcile.mjs +0 -30
- package/dist/commands/execute/git-reconcile.mjs.map +0 -1
- package/dist/commands/execute/handoff.d.mts +0 -1
- package/dist/commands/execute/handoff.mjs +0 -31
- package/dist/commands/execute/handoff.mjs.map +0 -1
- package/dist/commands/execute/incremental-carry.d.mts +0 -1
- package/dist/commands/execute/incremental-carry.mjs +0 -20
- package/dist/commands/execute/incremental-carry.mjs.map +0 -1
- package/dist/commands/execute/incremental-scope.d.mts +0 -1
- package/dist/commands/execute/incremental-scope.mjs +0 -29
- package/dist/commands/execute/incremental-scope.mjs.map +0 -1
- package/dist/commands/execute/integrate-stages.d.mts +0 -1
- package/dist/commands/execute/integrate-stages.mjs +0 -24
- package/dist/commands/execute/integrate-stages.mjs.map +0 -1
- package/dist/commands/execute/pane-title.d.mts +0 -1
- package/dist/commands/execute/pane-title.mjs +0 -20
- package/dist/commands/execute/pane-title.mjs.map +0 -1
- package/dist/commands/execute/plan-items.d.mts +0 -1
- package/dist/commands/execute/plan-items.mjs +0 -9
- package/dist/commands/execute/plan-items.mjs.map +0 -1
- package/dist/commands/execute/plan-validate.d.mts +0 -1
- package/dist/commands/execute/plan-validate.mjs +0 -68
- package/dist/commands/execute/plan-validate.mjs.map +0 -1
- package/dist/commands/execute/plan-verify.d.mts +0 -1
- package/dist/commands/execute/plan-verify.mjs +0 -43
- package/dist/commands/execute/plan-verify.mjs.map +0 -1
- package/dist/commands/execute/spawn-followups.d.mts +0 -1
- package/dist/commands/execute/spawn-followups.mjs +0 -22
- package/dist/commands/execute/spawn-followups.mjs.map +0 -1
- package/dist/commands/execute/team.d.mts +0 -3
- package/dist/commands/execute/team.mjs +0 -66
- package/dist/commands/execute/team.mjs.map +0 -1
- package/dist/commands/execute/token-usage.d.mts +0 -1
- package/dist/commands/execute/token-usage.mjs +0 -19
- package/dist/commands/execute/token-usage.mjs.map +0 -1
- package/dist/commands/execute/worker-audit-check.d.mts +0 -1
- package/dist/commands/execute/worker-audit-check.mjs +0 -34
- package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
- package/dist/commands/execute/worker-dispatch.d.mts +0 -7
- package/dist/commands/execute/worker-dispatch.mjs +0 -64
- package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
- package/dist/commands/execute/worker-state.d.mts +0 -1
- package/dist/commands/execute/worker-state.mjs +0 -28
- package/dist/commands/execute/worker-state.mjs.map +0 -1
- package/dist/commands/execute/worktree-lookup.d.mts +0 -1
- package/dist/commands/execute/worktree-lookup.mjs +0 -92
- package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
- package/dist/commands/execute/worktree-status.d.mts +0 -1
- package/dist/commands/execute/worktree-status.mjs +0 -121
- package/dist/commands/execute/worktree-status.mjs.map +0 -1
- package/dist/commands/inspect/code-review.d.mts +0 -1
- package/dist/commands/inspect/code-review.mjs +0 -32
- package/dist/commands/inspect/code-review.mjs.map +0 -1
- package/dist/commands/inspect/container.d.mts +0 -1
- package/dist/commands/inspect/container.mjs +0 -25
- package/dist/commands/inspect/container.mjs.map +0 -1
- package/dist/commands/inspect/context-cost.d.mts +0 -1
- package/dist/commands/inspect/context-cost.mjs +0 -25
- package/dist/commands/inspect/context-cost.mjs.map +0 -1
- package/dist/commands/inspect/design-prep.d.mts +0 -1
- package/dist/commands/inspect/design-prep.mjs +0 -22
- package/dist/commands/inspect/design-prep.mjs.map +0 -1
- package/dist/commands/inspect/error-report.d.mts +0 -1
- package/dist/commands/inspect/error-report.mjs +0 -25
- package/dist/commands/inspect/error-report.mjs.map +0 -1
- package/dist/commands/inspect/error-zip.d.mts +0 -1
- package/dist/commands/inspect/error-zip.mjs +0 -24
- package/dist/commands/inspect/error-zip.mjs.map +0 -1
- package/dist/commands/inspect/log-report.d.mts +0 -1
- package/dist/commands/inspect/log-report.mjs +0 -26
- package/dist/commands/inspect/log-report.mjs.map +0 -1
- package/dist/commands/inspect/model-io.d.mts +0 -1
- package/dist/commands/inspect/model-io.mjs +0 -25
- package/dist/commands/inspect/model-io.mjs.map +0 -1
- package/dist/commands/inspect/profile-show.d.mts +0 -1
- package/dist/commands/inspect/profile-show.mjs +0 -28
- package/dist/commands/inspect/profile-show.mjs.map +0 -1
- package/dist/commands/inspect/recap.d.mts +0 -1
- package/dist/commands/inspect/recap.mjs +0 -30
- package/dist/commands/inspect/recap.mjs.map +0 -1
- package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
- package/dist/commands/inspect/resolve-task-key.mjs +0 -24
- package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
- package/dist/commands/inspect/rollup.d.mts +0 -1
- package/dist/commands/inspect/rollup.mjs +0 -25
- package/dist/commands/inspect/rollup.mjs.map +0 -1
- package/dist/commands/inspect/run-audit.d.mts +0 -1
- package/dist/commands/inspect/run-audit.mjs +0 -25
- package/dist/commands/inspect/run-audit.mjs.map +0 -1
- package/dist/commands/inspect/set-work-status.d.mts +0 -1
- package/dist/commands/inspect/set-work-status.mjs +0 -29
- package/dist/commands/inspect/set-work-status.mjs.map +0 -1
- package/dist/commands/inspect/stage-map.d.mts +0 -1
- package/dist/commands/inspect/stage-map.mjs +0 -131
- package/dist/commands/inspect/stage-map.mjs.map +0 -1
- package/dist/commands/inspect/task-list.d.mts +0 -1
- package/dist/commands/inspect/task-list.mjs +0 -149
- package/dist/commands/inspect/task-list.mjs.map +0 -1
- package/dist/commands/inspect/task-show.d.mts +0 -1
- package/dist/commands/inspect/task-show.mjs +0 -108
- package/dist/commands/inspect/task-show.mjs.map +0 -1
- package/dist/commands/inspect/time-report.d.mts +0 -1
- package/dist/commands/inspect/time-report.mjs +0 -24
- package/dist/commands/inspect/time-report.mjs.map +0 -1
- package/dist/commands/inspect/usage-report.d.mts +0 -1
- package/dist/commands/inspect/usage-report.mjs +0 -23
- package/dist/commands/inspect/usage-report.mjs.map +0 -1
- package/dist/commands/inspect/user-response.d.mts +0 -1
- package/dist/commands/inspect/user-response.mjs +0 -35
- package/dist/commands/inspect/user-response.mjs.map +0 -1
- package/dist/commands/inspect/worker-liveness.d.mts +0 -1
- package/dist/commands/inspect/worker-liveness.mjs +0 -45
- package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
- package/dist/commands/lifecycle/contract-check.d.mts +0 -1
- package/dist/commands/lifecycle/contract-check.mjs +0 -18
- package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
- package/dist/commands/lifecycle/migrate.d.mts +0 -1
- package/dist/commands/lifecycle/migrate.mjs +0 -30
- package/dist/commands/lifecycle/migrate.mjs.map +0 -1
- package/dist/commands/lifecycle/model.d.mts +0 -1
- package/dist/commands/lifecycle/model.mjs +0 -22
- package/dist/commands/lifecycle/model.mjs.map +0 -1
- package/dist/commands/manager.d.mts +0 -3
- package/dist/commands/manager.mjs +0 -50
- package/dist/commands/manager.mjs.map +0 -1
- package/dist/commands/report/agent-activity.d.mts +0 -1
- package/dist/commands/report/agent-activity.mjs +0 -20
- package/dist/commands/report/agent-activity.mjs.map +0 -1
- package/dist/commands/report/approval-decision.d.mts +0 -1
- package/dist/commands/report/approval-decision.mjs +0 -21
- package/dist/commands/report/approval-decision.mjs.map +0 -1
- package/dist/commands/report/design-snapshot.d.mts +0 -1
- package/dist/commands/report/design-snapshot.mjs +0 -19
- package/dist/commands/report/design-snapshot.mjs.map +0 -1
- package/dist/commands/report/finalize.d.mts +0 -4
- package/dist/commands/report/finalize.mjs +0 -64
- package/dist/commands/report/finalize.mjs.map +0 -1
- package/dist/commands/report/inject-report-index.d.mts +0 -1
- package/dist/commands/report/inject-report-index.mjs +0 -21
- package/dist/commands/report/inject-report-index.mjs.map +0 -1
- package/dist/commands/report/render-final-report.d.mts +0 -1
- package/dist/commands/report/render-final-report.mjs +0 -23
- package/dist/commands/report/render-final-report.mjs.map +0 -1
- package/dist/commands/report/render-views.d.mts +0 -1
- package/dist/commands/report/render-views.mjs +0 -27
- package/dist/commands/report/render-views.mjs.map +0 -1
- package/dist/commands/report/translate.d.mts +0 -1
- package/dist/commands/report/translate.mjs +0 -33
- package/dist/commands/report/translate.mjs.map +0 -1
- package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
- package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
- package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
- package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
- package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
- package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
- package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
- package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
- package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
- package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
- package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
- package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
- package/runtime/bin/okstra-central.sh +0 -152
- package/runtime/bin/okstra-incremental-carry.py +0 -10
- package/runtime/bin/okstra-incremental-scope.py +0 -10
- package/runtime/bin/okstra-team-reconcile.sh +0 -36
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
- package/runtime/python/okstra_ctl/batch.py +0 -60
- package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
- package/runtime/python/okstra_ctl/container_registry.py +0 -72
- package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
- package/runtime/python/okstra_ctl/resolver.py +0 -54
- package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
- package/runtime/python/okstra_ctl/tmux.py +0 -134
- package/runtime/python/okstra_ctl/worktree.py +0 -1099
|
@@ -0,0 +1,605 @@
|
|
|
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 Any, Mapping, 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 ...final_report_paths import final_report_data_path
|
|
35
|
+
from ...report_inputs import report_narrative_path, uses_report_contract_v3
|
|
36
|
+
from ...report_synthesis_packet import (
|
|
37
|
+
ReportSynthesisPacketError,
|
|
38
|
+
materialize_report_synthesis_packet,
|
|
39
|
+
)
|
|
40
|
+
from ...worker_prompt_body import report_writer_input_lines
|
|
41
|
+
from ...dispatch_state import detect_terminal_backend
|
|
42
|
+
from .dynamic_verifier import (
|
|
43
|
+
_dynamic_verifier_source,
|
|
44
|
+
_reserve_dynamic_verifier_request,
|
|
45
|
+
)
|
|
46
|
+
from .inputs import (
|
|
47
|
+
AgentPromptCliError,
|
|
48
|
+
_authorized_path,
|
|
49
|
+
_exact_path,
|
|
50
|
+
_is_relative_to,
|
|
51
|
+
_is_slug,
|
|
52
|
+
_mapping,
|
|
53
|
+
_project_input,
|
|
54
|
+
_project_manifest_path,
|
|
55
|
+
_project_root,
|
|
56
|
+
_read_json_object,
|
|
57
|
+
_relative,
|
|
58
|
+
)
|
|
59
|
+
from .run_identity import _validate_run_identity
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_AUDIENCES = frozenset(get_args(AgentAudience))
|
|
63
|
+
# 결과 파일과 별개의 워커 결과 포인터를 가진 audience. 이들만 `--audit-source` 로
|
|
64
|
+
# 두 번째 경로를 받고, 프롬프트에 `**Worker Result Path:**` 앵커가 생긴다.
|
|
65
|
+
# 나머지 audience 의 결과는 하나뿐이고 감사 사이드카는 그 이름에서 파생된다.
|
|
66
|
+
_POINTER_AUDIENCES = frozenset({"report-writer", "translator"})
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _materialize(args: argparse.Namespace) -> PreparedAgentInvocation:
|
|
70
|
+
project_root = _project_root(args.project_root)
|
|
71
|
+
if args.run_manifest:
|
|
72
|
+
return _materialize_run(args, project_root)
|
|
73
|
+
return _materialize_standalone(args, project_root)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _materialize_run(
|
|
77
|
+
args: argparse.Namespace,
|
|
78
|
+
project_root: Path,
|
|
79
|
+
) -> PreparedAgentInvocation:
|
|
80
|
+
required = {
|
|
81
|
+
"worker-id": args.worker_id,
|
|
82
|
+
"dispatch-kind": args.dispatch_kind,
|
|
83
|
+
"assignment-ref": args.assignment_ref,
|
|
84
|
+
"result": args.result,
|
|
85
|
+
}
|
|
86
|
+
missing = [name for name, value in required.items() if not value]
|
|
87
|
+
if missing:
|
|
88
|
+
raise AgentPromptCliError(
|
|
89
|
+
f"run materialization requires: {', '.join('--' + name for name in missing)}"
|
|
90
|
+
)
|
|
91
|
+
forbidden = {
|
|
92
|
+
"host-runtime": args.host_runtime,
|
|
93
|
+
"provider": args.provider,
|
|
94
|
+
"model-role": args.model_role,
|
|
95
|
+
"model": args.model,
|
|
96
|
+
"purpose": args.purpose,
|
|
97
|
+
}
|
|
98
|
+
present = [name for name, value in forbidden.items() if value]
|
|
99
|
+
if present:
|
|
100
|
+
raise AgentPromptCliError(
|
|
101
|
+
f"run materialization forbids: {', '.join('--' + name for name in present)}"
|
|
102
|
+
)
|
|
103
|
+
manifest_path = _project_input(project_root, args.run_manifest, "run manifest")
|
|
104
|
+
manifest = _read_json_object(manifest_path, "run manifest")
|
|
105
|
+
contract = _mapping(manifest.get("agentContract"), "run agent contract")
|
|
106
|
+
authorized = _mapping(contract.get("authorizedPaths"), "authorized paths")
|
|
107
|
+
|
|
108
|
+
instruction_path = _authorized_path(
|
|
109
|
+
project_root,
|
|
110
|
+
args.instruction,
|
|
111
|
+
authorized.get("instructionRoots"),
|
|
112
|
+
"instruction",
|
|
113
|
+
must_exist=True,
|
|
114
|
+
)
|
|
115
|
+
prompt_path = _authorized_path(
|
|
116
|
+
project_root,
|
|
117
|
+
args.prompt,
|
|
118
|
+
authorized.get("promptRoots"),
|
|
119
|
+
"prompt",
|
|
120
|
+
must_exist=False,
|
|
121
|
+
)
|
|
122
|
+
result_path = _authorized_path(
|
|
123
|
+
project_root,
|
|
124
|
+
args.result,
|
|
125
|
+
authorized.get("resultRoots"),
|
|
126
|
+
"result",
|
|
127
|
+
must_exist=False,
|
|
128
|
+
)
|
|
129
|
+
audit_source_path = (
|
|
130
|
+
_authorized_path(
|
|
131
|
+
project_root,
|
|
132
|
+
args.audit_source,
|
|
133
|
+
authorized.get("resultRoots"),
|
|
134
|
+
"audit source",
|
|
135
|
+
must_exist=False,
|
|
136
|
+
)
|
|
137
|
+
if args.audit_source
|
|
138
|
+
else None
|
|
139
|
+
)
|
|
140
|
+
if args.audience not in _POINTER_AUDIENCES:
|
|
141
|
+
# 결과가 하나뿐인 audience 다. 두 번째 경로는 워커(`**Result Path:**` 에
|
|
142
|
+
# 쓴다)와 수집기(jobs-file 의 workerResultPath 를 기다린다)에게 서로 다른
|
|
143
|
+
# 파일을 말하는 것밖에 못 한다. 실측(2026-09-02, fontsninja-v3-site
|
|
144
|
+
# dev-10626-1 error-analysis r04): 리드가 reverify 에 `-worker-` 이름을
|
|
145
|
+
# `--audit-source` 로 따로 넘겨 검증 디스패치 9건 중 8건이 결과를 다
|
|
146
|
+
# 쓰고도 `required worker artifact was not produced` 로 끝났다.
|
|
147
|
+
if (
|
|
148
|
+
audit_source_path is not None
|
|
149
|
+
and _normalized(audit_source_path) != _normalized(result_path)
|
|
150
|
+
):
|
|
151
|
+
raise AgentPromptCliError(
|
|
152
|
+
f"{args.audience} materialization forbids --audit-source: this "
|
|
153
|
+
"audience writes one result and its audit sidecar derives from "
|
|
154
|
+
"that result's name. Name --result with the canonical `-worker-` "
|
|
155
|
+
"token instead (reverify: "
|
|
156
|
+
"<worker-id>-worker-reverify-r<N>-<task-type>-<seq>.md) and put "
|
|
157
|
+
"the same path in the jobs file's workerResultPath"
|
|
158
|
+
)
|
|
159
|
+
audit_source_path = result_path
|
|
160
|
+
elif args.audience == "report-writer":
|
|
161
|
+
if audit_source_path is None:
|
|
162
|
+
# The report writer is the one audience whose result path is not its
|
|
163
|
+
# own worker result: it writes the report body, while the audit
|
|
164
|
+
# sidecar is derived from its `.md`. With both collapsed into one
|
|
165
|
+
# value the prompt loses its `**Worker Result Path:**` anchor and the
|
|
166
|
+
# writer puts the report where the audit file belongs — silently,
|
|
167
|
+
# because every header is still present and well-formed. The roster
|
|
168
|
+
# path derives both from the manifest; a dynamic call has to name
|
|
169
|
+
# them.
|
|
170
|
+
#
|
|
171
|
+
# Which artifact `--result` names depends on the report contract, and
|
|
172
|
+
# `dispatch_state.dispatch_result_path` is what decides it. Naming
|
|
173
|
+
# only the v2 answer here sent v3 runs to the data.json, so the
|
|
174
|
+
# narrative `report-finalize` assembles from was never written and
|
|
175
|
+
# the phase failed later, at a place that does not point back here.
|
|
176
|
+
if uses_report_contract_v3(manifest):
|
|
177
|
+
expected = report_narrative_path(project_root, manifest)
|
|
178
|
+
raise AgentPromptCliError(
|
|
179
|
+
"report-writer materialization requires --audit-source: "
|
|
180
|
+
f"under report contract 3.0 --result is the narrative "
|
|
181
|
+
f"({expected}), which `report-finalize` assembles the report "
|
|
182
|
+
"data.json from, and --audit-source the worker-result .md "
|
|
183
|
+
"the audit sidecar is derived from"
|
|
184
|
+
)
|
|
185
|
+
raise AgentPromptCliError(
|
|
186
|
+
"report-writer materialization requires --audit-source: under "
|
|
187
|
+
"report contract 2.0 --result is the report data.json, and "
|
|
188
|
+
"--audit-source the worker-result .md the audit sidecar is "
|
|
189
|
+
"derived from"
|
|
190
|
+
)
|
|
191
|
+
_validate_report_writer_paths(
|
|
192
|
+
project_root,
|
|
193
|
+
manifest,
|
|
194
|
+
worker_id=args.worker_id,
|
|
195
|
+
result_path=result_path,
|
|
196
|
+
audit_source_path=audit_source_path,
|
|
197
|
+
)
|
|
198
|
+
elif audit_source_path is None:
|
|
199
|
+
audit_source_path = result_path
|
|
200
|
+
_validate_run_identity(
|
|
201
|
+
manifest,
|
|
202
|
+
worker_id=args.worker_id,
|
|
203
|
+
dispatch_kind=args.dispatch_kind,
|
|
204
|
+
assignment_ref=args.assignment_ref,
|
|
205
|
+
audience=args.audience,
|
|
206
|
+
)
|
|
207
|
+
assignments = _mapping(
|
|
208
|
+
manifest.get("invocationAssignments"),
|
|
209
|
+
"run invocation assignments",
|
|
210
|
+
)
|
|
211
|
+
if args.assignment_ref not in assignments:
|
|
212
|
+
# 유효값은 이 매니페스트 안에만 있고 리드는 그것을 추측할 수 없다.
|
|
213
|
+
# 이름만 거절하면 읽는 쪽이 매니페스트를 직접 열어 키를 세게 된다.
|
|
214
|
+
raise AgentPromptCliError(
|
|
215
|
+
f"assignment reference is missing from run manifest: "
|
|
216
|
+
f"{args.assignment_ref}; this run declares "
|
|
217
|
+
+ (", ".join(sorted(assignments)) or "no invocation assignment")
|
|
218
|
+
)
|
|
219
|
+
assignment_payload = assignments[args.assignment_ref]
|
|
220
|
+
assignment = agent_model_assignment_from_payload(assignment_payload)
|
|
221
|
+
dynamic_source = _dynamic_verifier_source(args, manifest)
|
|
222
|
+
identity = (
|
|
223
|
+
None
|
|
224
|
+
if dynamic_source is not None
|
|
225
|
+
else invocation_execution_identity_from_manifest(
|
|
226
|
+
manifest,
|
|
227
|
+
assignment=assignment,
|
|
228
|
+
assignment_ref=args.assignment_ref,
|
|
229
|
+
duty_id=args.audience,
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
duty_root = _project_manifest_path(
|
|
233
|
+
project_root,
|
|
234
|
+
contract.get("dutyRootPath"),
|
|
235
|
+
"duty root",
|
|
236
|
+
must_exist=True,
|
|
237
|
+
)
|
|
238
|
+
if contract.get("catalogDigest") != digest_duty_catalog(duty_root):
|
|
239
|
+
raise AgentPromptCliError("run duty snapshot catalog digest does not match")
|
|
240
|
+
active_context_path = _project_manifest_path(
|
|
241
|
+
project_root,
|
|
242
|
+
manifest.get("activeRunContextPath"),
|
|
243
|
+
"active run context",
|
|
244
|
+
must_exist=True,
|
|
245
|
+
)
|
|
246
|
+
active_context = hydrate_active_run_context(
|
|
247
|
+
_read_json_object(active_context_path, "active run context")
|
|
248
|
+
)
|
|
249
|
+
prompt_rel = _relative(project_root, prompt_path)
|
|
250
|
+
result_rel = _relative(project_root, result_path)
|
|
251
|
+
audit_rel = _relative(project_root, audit_source_path)
|
|
252
|
+
anchor_lines = tuple(worker_prompt_headers(
|
|
253
|
+
project_root=project_root,
|
|
254
|
+
prompt_rel=prompt_rel,
|
|
255
|
+
result_rel=result_rel,
|
|
256
|
+
audit_source_rel=audit_rel,
|
|
257
|
+
worker_id=args.worker_id,
|
|
258
|
+
dispatch_kind=args.dispatch_kind,
|
|
259
|
+
manifest=manifest,
|
|
260
|
+
active_context=active_context,
|
|
261
|
+
))
|
|
262
|
+
body = instruction_path.read_text(encoding="utf-8")
|
|
263
|
+
if args.audience == "report-writer":
|
|
264
|
+
body = _with_inputs_section(
|
|
265
|
+
body,
|
|
266
|
+
_report_writer_input_lines(
|
|
267
|
+
project_root,
|
|
268
|
+
manifest,
|
|
269
|
+
active_context,
|
|
270
|
+
narrative_path=result_path,
|
|
271
|
+
),
|
|
272
|
+
)
|
|
273
|
+
request = AgentInvocationRequest(
|
|
274
|
+
invocation_id=args.invocation_id,
|
|
275
|
+
worker_id=args.worker_id if identity is None else None,
|
|
276
|
+
audience=args.audience,
|
|
277
|
+
assignment_ref=args.assignment_ref,
|
|
278
|
+
purpose=None,
|
|
279
|
+
assignment=assignment,
|
|
280
|
+
instruction=AgentInstruction(
|
|
281
|
+
anchor_lines=anchor_lines,
|
|
282
|
+
body=body,
|
|
283
|
+
source_paths=(AgentInstructionSource(
|
|
284
|
+
kind="project",
|
|
285
|
+
path=_relative(project_root, instruction_path),
|
|
286
|
+
),),
|
|
287
|
+
),
|
|
288
|
+
project_root=project_root,
|
|
289
|
+
run_manifest_path=manifest_path,
|
|
290
|
+
duty_root=duty_root,
|
|
291
|
+
prompt_path=prompt_path,
|
|
292
|
+
metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
|
|
293
|
+
dispatch_kind=args.dispatch_kind,
|
|
294
|
+
participant_ref=identity.participant_ref if identity is not None else None,
|
|
295
|
+
role_execution_ref=(
|
|
296
|
+
identity.role_execution_ref if identity is not None else None
|
|
297
|
+
),
|
|
298
|
+
duty_id=identity.duty_id if identity is not None else None,
|
|
299
|
+
invocation_ref=args.invocation_id if identity is not None else None,
|
|
300
|
+
attempt=1,
|
|
301
|
+
replace_undispatched=args.replace_undispatched,
|
|
302
|
+
)
|
|
303
|
+
if dynamic_source is not None:
|
|
304
|
+
request = _reserve_dynamic_verifier_request(
|
|
305
|
+
request,
|
|
306
|
+
args=args,
|
|
307
|
+
manifest=manifest,
|
|
308
|
+
manifest_path=manifest_path,
|
|
309
|
+
source_role_execution_ref=dynamic_source,
|
|
310
|
+
)
|
|
311
|
+
return prepare_agent_invocation(request)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _normalized(path: Path) -> Path:
|
|
315
|
+
return Path(os.path.normpath(path))
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _validate_report_writer_paths(
|
|
319
|
+
project_root: Path,
|
|
320
|
+
manifest: Mapping[str, Any],
|
|
321
|
+
*,
|
|
322
|
+
worker_id: str,
|
|
323
|
+
result_path: Path,
|
|
324
|
+
audit_source_path: Path,
|
|
325
|
+
) -> None:
|
|
326
|
+
"""report-writer 의 두 경로를 run 이 이미 정한 값에 못 박는다.
|
|
327
|
+
|
|
328
|
+
`--result` 는 조립이 읽는 서술문 경로다: 계약 3.0 이면 매니페스트의
|
|
329
|
+
`reportNarrativePath`, 2.0 이면 `expectedReportRecordPath` 의 data.json.
|
|
330
|
+
다른 경로에 쓴 서술문은 `report-finalize` 가 읽지 않는다. `--audit-source`
|
|
331
|
+
는 명부(team-state `workers[].resultPath`)의 워커 결과다: `okstra team
|
|
332
|
+
await` 는 그 파일이 있어야 명부 행을 completed 로 적는다. 실측(2026-09-02,
|
|
333
|
+
fontsninja-v3-site dev-10626-1 r04): 리드가 재시도마다 `-a2`/`-a3` 접미를
|
|
334
|
+
붙인 경로를 넘겨 서술문 세 벌이 조립 밖에 쌓였고, 결국 손으로 `cp` 했다.
|
|
335
|
+
교정 디스패치는 프롬프트 경로와 invocation ID 만 새로 하고 이 두 경로는
|
|
336
|
+
그대로 쓴다.
|
|
337
|
+
"""
|
|
338
|
+
if uses_report_contract_v3(manifest):
|
|
339
|
+
expected_result = report_narrative_path(project_root, manifest)
|
|
340
|
+
what = "the narrative report-finalize assembles from (run manifest reportNarrativePath)"
|
|
341
|
+
else:
|
|
342
|
+
expected_result = final_report_data_path(_project_manifest_path(
|
|
343
|
+
project_root,
|
|
344
|
+
manifest.get("expectedReportRecordPath"),
|
|
345
|
+
"expected report record",
|
|
346
|
+
must_exist=False,
|
|
347
|
+
))
|
|
348
|
+
what = "the report data.json (run manifest expectedReportRecordPath)"
|
|
349
|
+
if _normalized(result_path) != _normalized(expected_result):
|
|
350
|
+
raise AgentPromptCliError(
|
|
351
|
+
f"report-writer --result must be {what}: expected {expected_result}, "
|
|
352
|
+
f"got {result_path}. A corrective dispatch reuses this path with a "
|
|
353
|
+
"fresh prompt path and invocation ID"
|
|
354
|
+
)
|
|
355
|
+
roster_result = _roster_result_path(project_root, manifest, worker_id)
|
|
356
|
+
if (
|
|
357
|
+
roster_result is not None
|
|
358
|
+
and _normalized(audit_source_path) != _normalized(roster_result)
|
|
359
|
+
):
|
|
360
|
+
raise AgentPromptCliError(
|
|
361
|
+
"report-writer --audit-source must be the roster's worker result "
|
|
362
|
+
f"(team-state workers[].resultPath): expected {roster_result}, got "
|
|
363
|
+
f"{audit_source_path}. `okstra team await` records the roster row "
|
|
364
|
+
"completed only when that file exists"
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _load_team_state(project_root: Path, manifest: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
369
|
+
"""매니페스트가 가리키는 team-state. 없으면 빈 매핑."""
|
|
370
|
+
team_state_value = manifest.get("teamStatePath")
|
|
371
|
+
if not isinstance(team_state_value, str) or not team_state_value:
|
|
372
|
+
return {}
|
|
373
|
+
team_state_path = Path(team_state_value)
|
|
374
|
+
if not team_state_path.is_absolute():
|
|
375
|
+
team_state_path = project_root / team_state_path
|
|
376
|
+
if not team_state_path.is_file():
|
|
377
|
+
return {}
|
|
378
|
+
return _read_json_object(team_state_path, "team state")
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def _report_writer_input_lines(
|
|
382
|
+
project_root: Path,
|
|
383
|
+
manifest: Mapping[str, Any],
|
|
384
|
+
active_context: Mapping[str, Any],
|
|
385
|
+
*,
|
|
386
|
+
narrative_path: Path,
|
|
387
|
+
) -> list[str]:
|
|
388
|
+
"""report-writer 의 `## Inputs` 줄. 로스터 경로(`worker_prompt_body`)와 같은 규칙.
|
|
389
|
+
|
|
390
|
+
계약 3.0 이면 합성 묶음을 여기서 만들고 그 한 줄을 싣는다; 그 전 계약은
|
|
391
|
+
옛 목록이다. 실측(2026-09-02, fontsninja-v3-site dev-10626-1 r04): run
|
|
392
|
+
갈래의 프롬프트에는 이 절이 없어, 작성자가 "읽을 게 없다"며 서술문을
|
|
393
|
+
거부했고 리드가 경로 22개를 손으로 열거하고서야 통과했다. 두 갈래가 같은
|
|
394
|
+
입력 표면을 내야 하는 이유다.
|
|
395
|
+
"""
|
|
396
|
+
team_state = _load_team_state(project_root, manifest)
|
|
397
|
+
if not uses_report_contract_v3(manifest):
|
|
398
|
+
return report_writer_input_lines(manifest, active_context, team_state)
|
|
399
|
+
try:
|
|
400
|
+
_, markdown_path = materialize_report_synthesis_packet(
|
|
401
|
+
project_root=project_root,
|
|
402
|
+
manifest=manifest,
|
|
403
|
+
active_context=active_context,
|
|
404
|
+
team_state=team_state,
|
|
405
|
+
narrative_path=narrative_path,
|
|
406
|
+
)
|
|
407
|
+
except ReportSynthesisPacketError as exc:
|
|
408
|
+
defects = "; ".join(
|
|
409
|
+
f"owner={issue.owner} source={issue.label} path={issue.path} "
|
|
410
|
+
f"reason={issue.reason}"
|
|
411
|
+
for issue in exc.issues
|
|
412
|
+
)
|
|
413
|
+
raise AgentPromptCliError(
|
|
414
|
+
f"report synthesis packet contract defects: {defects}"
|
|
415
|
+
) from exc
|
|
416
|
+
return [f"- Report synthesis packet: `{_relative(project_root, markdown_path)}`"]
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def _with_inputs_section(body: str, input_lines: list[str]) -> str:
|
|
420
|
+
"""런타임 소유 입력 줄을 본문의 `## Inputs` 첫머리에 넣는다.
|
|
421
|
+
|
|
422
|
+
리드가 이미 그 절을 썼으면 그 제목 바로 아래에 끼워 한 절로 두고, 없으면
|
|
423
|
+
머리의 `**…:**` 헤더 블록 뒤에 절을 새로 연다.
|
|
424
|
+
"""
|
|
425
|
+
lines = body.splitlines()
|
|
426
|
+
for index, line in enumerate(lines):
|
|
427
|
+
if line.strip() == "## Inputs":
|
|
428
|
+
merged = lines[: index + 1] + input_lines + lines[index + 1 :]
|
|
429
|
+
return "\n".join(merged) + "\n"
|
|
430
|
+
insert_at = 0
|
|
431
|
+
while insert_at < len(lines) and (
|
|
432
|
+
not lines[insert_at].strip() or lines[insert_at].startswith("**")
|
|
433
|
+
):
|
|
434
|
+
insert_at += 1
|
|
435
|
+
section = ["## Inputs", *input_lines, ""]
|
|
436
|
+
if insert_at and lines[insert_at - 1].strip():
|
|
437
|
+
section = ["", *section]
|
|
438
|
+
return "\n".join(lines[:insert_at] + section + lines[insert_at:]) + "\n"
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def _roster_result_path(
|
|
442
|
+
project_root: Path, manifest: Mapping[str, Any], worker_id: str,
|
|
443
|
+
) -> Path | None:
|
|
444
|
+
"""명부가 이 워커에 적어 둔 `resultPath`. 행이 없으면 None."""
|
|
445
|
+
workers = _load_team_state(project_root, manifest).get("workers")
|
|
446
|
+
if not isinstance(workers, list):
|
|
447
|
+
return None
|
|
448
|
+
for row in workers:
|
|
449
|
+
if not isinstance(row, Mapping) or row.get("workerId") != worker_id:
|
|
450
|
+
continue
|
|
451
|
+
value = row.get("resultPath")
|
|
452
|
+
if not isinstance(value, str) or not value.strip():
|
|
453
|
+
return None
|
|
454
|
+
path = Path(value.strip())
|
|
455
|
+
return path if path.is_absolute() else project_root / path
|
|
456
|
+
return None
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _materialize_standalone(
|
|
460
|
+
args: argparse.Namespace,
|
|
461
|
+
project_root: Path,
|
|
462
|
+
) -> PreparedAgentInvocation:
|
|
463
|
+
required = {
|
|
464
|
+
"host-runtime": args.host_runtime,
|
|
465
|
+
"provider": args.provider,
|
|
466
|
+
"model-role": args.model_role,
|
|
467
|
+
"purpose": args.purpose,
|
|
468
|
+
}
|
|
469
|
+
missing = [name for name, value in required.items() if not value]
|
|
470
|
+
if missing:
|
|
471
|
+
raise AgentPromptCliError(
|
|
472
|
+
"standalone materialization requires: "
|
|
473
|
+
+ ", ".join("--" + name for name in missing)
|
|
474
|
+
)
|
|
475
|
+
forbidden = {
|
|
476
|
+
"worker-id": args.worker_id,
|
|
477
|
+
"dispatch-kind": args.dispatch_kind,
|
|
478
|
+
"assignment-ref": args.assignment_ref,
|
|
479
|
+
"result": args.result,
|
|
480
|
+
"audit-source": args.audit_source,
|
|
481
|
+
"source-role-execution-ref": args.source_role_execution_ref,
|
|
482
|
+
}
|
|
483
|
+
present = [name for name, value in forbidden.items() if value]
|
|
484
|
+
if present:
|
|
485
|
+
raise AgentPromptCliError(
|
|
486
|
+
"standalone materialization forbids: "
|
|
487
|
+
+ ", ".join("--" + name for name in present)
|
|
488
|
+
)
|
|
489
|
+
if not _is_slug(args.purpose) or not _is_slug(args.invocation_id):
|
|
490
|
+
raise AgentPromptCliError("standalone purpose and invocation ID must be slugs")
|
|
491
|
+
if args.audience not in _AUDIENCES:
|
|
492
|
+
raise AgentPromptCliError(f"unknown duty audience: {args.audience}")
|
|
493
|
+
root = project_root / ".okstra" / "agent-invocations" / args.purpose
|
|
494
|
+
if not root.is_dir():
|
|
495
|
+
raise AgentPromptCliError(f"standalone invocation root not found: {root}")
|
|
496
|
+
resolved_root = root.resolve(strict=True)
|
|
497
|
+
if not _is_relative_to(resolved_root, project_root):
|
|
498
|
+
raise AgentPromptCliError("standalone invocation root escapes project root")
|
|
499
|
+
root = resolved_root
|
|
500
|
+
expected_instruction = root / f"{args.invocation_id}.instructions.md"
|
|
501
|
+
expected_prompt = root / f"{args.invocation_id}.prompt.md"
|
|
502
|
+
instruction_path = _exact_path(args.instruction, expected_instruction, True, "instruction")
|
|
503
|
+
prompt_path = _exact_path(args.prompt, expected_prompt, False, "prompt")
|
|
504
|
+
assignment_context = load_assignment_context(
|
|
505
|
+
host_runtime=args.host_runtime,
|
|
506
|
+
terminal_backend=args.terminal_backend or detect_terminal_backend(),
|
|
507
|
+
execution_provider_ids=(args.provider,),
|
|
508
|
+
include_native_provider=False,
|
|
509
|
+
)
|
|
510
|
+
assignment = _standalone_assignment(
|
|
511
|
+
context=assignment_context,
|
|
512
|
+
provider=args.provider,
|
|
513
|
+
model_role=args.model_role,
|
|
514
|
+
model=args.model,
|
|
515
|
+
)
|
|
516
|
+
duty_root = root / f"{args.invocation_id}.duty-contracts"
|
|
517
|
+
_snapshot_standalone_duties(duty_root)
|
|
518
|
+
return prepare_agent_invocation(AgentInvocationRequest(
|
|
519
|
+
invocation_id=args.invocation_id,
|
|
520
|
+
worker_id=None,
|
|
521
|
+
audience=args.audience,
|
|
522
|
+
assignment_ref=None,
|
|
523
|
+
purpose=args.purpose,
|
|
524
|
+
assignment=assignment,
|
|
525
|
+
instruction=AgentInstruction(
|
|
526
|
+
anchor_lines=(),
|
|
527
|
+
body=instruction_path.read_text(encoding="utf-8"),
|
|
528
|
+
source_paths=(AgentInstructionSource(
|
|
529
|
+
kind="project",
|
|
530
|
+
path=_relative(project_root, instruction_path),
|
|
531
|
+
),),
|
|
532
|
+
),
|
|
533
|
+
project_root=project_root,
|
|
534
|
+
run_manifest_path=None,
|
|
535
|
+
duty_root=duty_root,
|
|
536
|
+
prompt_path=prompt_path,
|
|
537
|
+
metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
|
|
538
|
+
dispatch_kind="standalone",
|
|
539
|
+
participant_ref=None,
|
|
540
|
+
role_execution_ref=None,
|
|
541
|
+
duty_id=None,
|
|
542
|
+
invocation_ref=None,
|
|
543
|
+
attempt=1,
|
|
544
|
+
))
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _standalone_assignment(
|
|
548
|
+
*,
|
|
549
|
+
context: AssignmentContext,
|
|
550
|
+
provider: str,
|
|
551
|
+
model_role: str,
|
|
552
|
+
model: str,
|
|
553
|
+
) -> AgentModelAssignment:
|
|
554
|
+
host_runtime = context.environment.host_descriptor.id
|
|
555
|
+
resolved = resolve_dispatch_assignment(
|
|
556
|
+
context=context,
|
|
557
|
+
host_runtime=host_runtime,
|
|
558
|
+
role=model_role,
|
|
559
|
+
duty_id=model_role,
|
|
560
|
+
provider=provider,
|
|
561
|
+
model=model,
|
|
562
|
+
)
|
|
563
|
+
binding = resolved.binding
|
|
564
|
+
if binding is None:
|
|
565
|
+
raise AgentPromptCliError("standalone assignment requires a model binding")
|
|
566
|
+
return AgentModelAssignment(
|
|
567
|
+
provider=resolved.provider_id,
|
|
568
|
+
model=resolved.display_name,
|
|
569
|
+
model_execution_value=binding.resolved_execution_value,
|
|
570
|
+
runner=binding.runner,
|
|
571
|
+
host_runtime=host_runtime,
|
|
572
|
+
host_model_value=binding.host_model_value,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _snapshot_standalone_duties(destination: Path) -> None:
|
|
577
|
+
# 부모 개수를 세면 체크아웃(`<root>/scripts/okstra_ctl/agent/prompt_cli/`)
|
|
578
|
+
# 에서만 맞는다 — 설치본은 패키지가 `~/.okstra/lib/python/` 이라 prompts 가
|
|
579
|
+
# 한 단계 위(`~/.okstra/prompts/`)에 있다. duties 를 실제로 가진 루트를
|
|
580
|
+
# 탐색해서 해소한다.
|
|
581
|
+
from ...paths import find_asset_root
|
|
582
|
+
|
|
583
|
+
duties_relative = ("prompts", "duties")
|
|
584
|
+
root = find_asset_root(duties_relative, is_present=Path.is_dir)
|
|
585
|
+
if root is None:
|
|
586
|
+
raise AgentPromptCliError(
|
|
587
|
+
"duty contract source not found: no prompts/duties under "
|
|
588
|
+
"OKSTRA_HOME or this checkout"
|
|
589
|
+
)
|
|
590
|
+
source = root.joinpath(*duties_relative)
|
|
591
|
+
if destination.exists():
|
|
592
|
+
if not destination.is_dir() or digest_duty_catalog(destination) != digest_duty_catalog(source):
|
|
593
|
+
raise AgentPromptCliError("standalone duty snapshot conflicts with existing files")
|
|
594
|
+
return
|
|
595
|
+
temporary = Path(tempfile.mkdtemp(prefix=f".{destination.name}.", dir=destination.parent))
|
|
596
|
+
try:
|
|
597
|
+
shutil.copytree(source, temporary, dirs_exist_ok=True)
|
|
598
|
+
try:
|
|
599
|
+
os.rename(temporary, destination)
|
|
600
|
+
except FileExistsError:
|
|
601
|
+
if digest_duty_catalog(destination) != digest_duty_catalog(source):
|
|
602
|
+
raise AgentPromptCliError("standalone duty snapshot publication conflict")
|
|
603
|
+
finally:
|
|
604
|
+
if temporary.exists():
|
|
605
|
+
shutil.rmtree(temporary)
|