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.
- 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 +104 -39
- 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 +37 -36
- 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 +25 -18
- 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/convergence.md +96 -87
- 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 +34 -4
- 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 +40 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -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} +12 -1
- 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 +215 -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 +408 -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 +260 -8
- 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 +16 -2
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +101 -15
- 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 +102 -25
- package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
- 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 +21 -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/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 +90 -16
- 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 +25 -11
- 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 +3 -7
- 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 +206 -15
- 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 +90 -3
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- 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/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 +16 -9
- 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/claude.py +9 -1
- package/runtime/python/okstra_token_usage/cli.py +3 -1
- package/runtime/python/okstra_token_usage/collect.py +71 -10
- 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 +19 -7
- 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 +1 -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 +1369 -2654
- 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
|
@@ -42,11 +42,15 @@ from dataclasses import dataclass
|
|
|
42
42
|
from pathlib import Path
|
|
43
43
|
from typing import Any, Callable, Mapping, Sequence
|
|
44
44
|
|
|
45
|
-
from .
|
|
45
|
+
from .agent.activity import ActivityProjectionError, project_agent_activity
|
|
46
46
|
from .report_contract import apply_execution_roles
|
|
47
47
|
from .report_assembly import ReportAssemblyError, assemble_report
|
|
48
48
|
from .dispatch_state import DispatchError, link_agent_dispatch_result
|
|
49
|
-
from .final_report_paths import
|
|
49
|
+
from .final_report_paths import (
|
|
50
|
+
final_report_data_path,
|
|
51
|
+
final_report_markdown_path,
|
|
52
|
+
sidecar_source_rel,
|
|
53
|
+
)
|
|
50
54
|
from .paths import task_dir, task_manifest_file
|
|
51
55
|
from .release_gate import release_handoff_allowed
|
|
52
56
|
from .json_boundary import JsonBoundaryError, load_owned_object, write_owned_object_atomic
|
|
@@ -57,6 +61,16 @@ from .stage_targets import (
|
|
|
57
61
|
)
|
|
58
62
|
from .session import observe_lead_session
|
|
59
63
|
|
|
64
|
+
# 포인터 값 타입만 쓴다. `okstra_project.phase_pointer` 는 okstra 안의
|
|
65
|
+
# 어떤 것도 import 하지 않는 leaf 라 순환이 없다 — 그 모듈 도크스트링.
|
|
66
|
+
from okstra_project.phase_pointer import (
|
|
67
|
+
STATUS_BLOCKED,
|
|
68
|
+
STATUS_PENDING,
|
|
69
|
+
STATUS_READY,
|
|
70
|
+
STATUS_TERMINAL,
|
|
71
|
+
promote as promote_next_phase,
|
|
72
|
+
)
|
|
73
|
+
|
|
60
74
|
|
|
61
75
|
STEP_PROJECT_ACTIVITY = "project-activity"
|
|
62
76
|
STEP_CHECK_SOURCE = "check-source"
|
|
@@ -120,13 +134,6 @@ def resolve_optional_path(project_root: Path, value: Any) -> Path | None:
|
|
|
120
134
|
return resolve_project_path(project_root, value)
|
|
121
135
|
|
|
122
136
|
|
|
123
|
-
def project_relative_path(project_root: Path, path: Path) -> str:
|
|
124
|
-
try:
|
|
125
|
-
return path.relative_to(project_root).as_posix()
|
|
126
|
-
except ValueError:
|
|
127
|
-
return str(path)
|
|
128
|
-
|
|
129
|
-
|
|
130
137
|
def task_group(manifest: Mapping[str, Any]) -> str:
|
|
131
138
|
value = string_value(manifest.get("taskGroup"))
|
|
132
139
|
if value:
|
|
@@ -337,8 +344,11 @@ def build_commands(ctx: FinalizeContext) -> list[tuple[str, list[str]]]:
|
|
|
337
344
|
ctx.task_type,
|
|
338
345
|
"--seq",
|
|
339
346
|
ctx.seq,
|
|
347
|
+
# 사이드카가 되짚는 기준은 태스크 루트다. 프로젝트 루트
|
|
348
|
+
# 기준으로 넘기던 동안 HTML Export 가 만든 사이드카는
|
|
349
|
+
# 방향 선택 게이트를 통과할 수 없었다.
|
|
340
350
|
"--source-report",
|
|
341
|
-
|
|
351
|
+
sidecar_source_rel(markdown_path),
|
|
342
352
|
],
|
|
343
353
|
),
|
|
344
354
|
(
|
|
@@ -491,9 +501,47 @@ def run_finalize(
|
|
|
491
501
|
steps.append(step_payload(name, command, result))
|
|
492
502
|
if result.returncode != 0 and not first_failure:
|
|
493
503
|
first_failure = f"{name} failed with exit code {result.returncode}"
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
504
|
+
pointer, pointer_error = _recorded_next_phase(ctx)
|
|
505
|
+
payload: dict[str, Any] = {
|
|
506
|
+
"ok": not first_failure,
|
|
507
|
+
"reason": first_failure,
|
|
508
|
+
"steps": steps,
|
|
509
|
+
"nextRecommendedPhase": pointer,
|
|
510
|
+
}
|
|
511
|
+
if pointer_error:
|
|
512
|
+
payload["nextRecommendedPhaseError"] = pointer_error
|
|
513
|
+
# closeout 이 실제로 건넬 명령. 표를 리드의 기억에 맡기지 않는다.
|
|
514
|
+
payload["nextCommand"] = closeout_command(payload)
|
|
515
|
+
return payload
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _recorded_next_phase(ctx: FinalizeContext) -> tuple[dict[str, str], str]:
|
|
519
|
+
"""`validate-run` 이 방금 태스크 매니페스트에 쓴 다음 phase 포인터.
|
|
520
|
+
|
|
521
|
+
리드의 closeout 표는 이 포인터의 `status` / `rationale` 로 분기하는데,
|
|
522
|
+
포인터는 리드가 쓰는 필드가 아니고(`prompts/lead/report-writer.md`
|
|
523
|
+
"Nobody writes this pointer by hand"), 이 시퀀스의 결과에도 실리지
|
|
524
|
+
않았다. 값 없이 표만 받은 리드에게 남는 행동은 상태를 늘어놓고 턴을
|
|
525
|
+
끝내는 것뿐이다.
|
|
526
|
+
|
|
527
|
+
여기서 다시 계산하지 않는다 — 투영은 `validate-run` 의
|
|
528
|
+
`update_workflow_metadata` 가 하고, 이 함수는 그것이 파일에 남긴 값을
|
|
529
|
+
읽어 옮기기만 한다. `--only` 로 `validate-run` 을 건너뛴 호출에서는
|
|
530
|
+
이전 run 이 남긴 값이 그대로 읽히므로, 이번 시퀀스가 그 단계를 돌았는지는
|
|
531
|
+
`steps` 로 판단한다.
|
|
532
|
+
|
|
533
|
+
읽기가 실패하면 값을 지어내지 않고 사유를 함께 돌려준다.
|
|
534
|
+
"""
|
|
535
|
+
try:
|
|
536
|
+
manifest = load_owned_object(
|
|
537
|
+
ctx.task_manifest_path, artifact="task-manifest"
|
|
538
|
+
)
|
|
539
|
+
except (JsonBoundaryError, OSError) as exc:
|
|
540
|
+
return promote_next_phase(None), f"{ctx.task_manifest_path}: {exc}"
|
|
541
|
+
workflow = manifest.get("workflow")
|
|
542
|
+
if not isinstance(workflow, Mapping):
|
|
543
|
+
return promote_next_phase(None), ""
|
|
544
|
+
return promote_next_phase(workflow.get("nextRecommendedPhase")), ""
|
|
497
545
|
|
|
498
546
|
|
|
499
547
|
def _run_finalize_step(
|
|
@@ -529,6 +577,7 @@ def _run_project_activity(
|
|
|
529
577
|
try:
|
|
530
578
|
if ctx.report_contract_version == "3.0":
|
|
531
579
|
assembled = assemble_report(ctx.project_root, ctx.manifest_path)
|
|
580
|
+
_point_task_manifest_at_report(ctx)
|
|
532
581
|
count = len(assembled.get("agentActivity") or [])
|
|
533
582
|
else:
|
|
534
583
|
rows = project_agent_activity(
|
|
@@ -556,6 +605,34 @@ def write_execution_roles(ctx: FinalizeContext) -> None:
|
|
|
556
605
|
write_owned_object_atomic(ctx.data_path, updated, artifact="final report record")
|
|
557
606
|
|
|
558
607
|
|
|
608
|
+
def _point_task_manifest_at_report(ctx: FinalizeContext) -> None:
|
|
609
|
+
"""게시한 data.json 을 latestReport 로 올린다.
|
|
610
|
+
|
|
611
|
+
render-only prepare 는 기존 포인터를 보존한다. 조립이 새 리포트를 썼는데도
|
|
612
|
+
task-manifest 가 예전 seq 를 가리키면 검사가 통과해도 상태가 004 에 남는다.
|
|
613
|
+
"""
|
|
614
|
+
path = ctx.task_manifest_path
|
|
615
|
+
if not path.is_file() or not ctx.data_path.is_file():
|
|
616
|
+
return
|
|
617
|
+
try:
|
|
618
|
+
payload = load_owned_object(path, artifact="task manifest")
|
|
619
|
+
except (OSError, JsonBoundaryError):
|
|
620
|
+
return
|
|
621
|
+
if not isinstance(payload, Mapping):
|
|
622
|
+
return
|
|
623
|
+
try:
|
|
624
|
+
relative = ctx.data_path.resolve().relative_to(
|
|
625
|
+
ctx.project_root.resolve()
|
|
626
|
+
).as_posix()
|
|
627
|
+
except ValueError:
|
|
628
|
+
relative = str(ctx.data_path)
|
|
629
|
+
if payload.get("latestReportRecordPath") == relative:
|
|
630
|
+
return
|
|
631
|
+
updated = dict(payload)
|
|
632
|
+
updated["latestReportRecordPath"] = relative
|
|
633
|
+
write_owned_object_atomic(path, updated, artifact="task manifest")
|
|
634
|
+
|
|
635
|
+
|
|
559
636
|
def _link_lead_result_for_validation(ctx: FinalizeContext) -> None:
|
|
560
637
|
"""Link the lead-authored synthesis artifact before Phase 7 validation."""
|
|
561
638
|
manifest = _load_manifest(ctx.manifest_path)
|
|
@@ -566,8 +643,11 @@ def _link_lead_result_for_validation(ctx: FinalizeContext) -> None:
|
|
|
566
643
|
lead_dispatches = [
|
|
567
644
|
row for row in (team_state.get("agentDispatches") or [])
|
|
568
645
|
if isinstance(row, Mapping)
|
|
569
|
-
and
|
|
570
|
-
|
|
646
|
+
and (
|
|
647
|
+
row.get("audience") == "lead"
|
|
648
|
+
or row.get("workerId") == "lead"
|
|
649
|
+
or str(row.get("assignmentRef") or "") in {"lead", "lead/lead"}
|
|
650
|
+
)
|
|
571
651
|
]
|
|
572
652
|
if len(lead_dispatches) != 1:
|
|
573
653
|
return
|
|
@@ -621,8 +701,41 @@ def _context_from_args(args: argparse.Namespace) -> FinalizeContext:
|
|
|
621
701
|
)
|
|
622
702
|
|
|
623
703
|
|
|
704
|
+
_CLI_EPILOG = r"""Usage:
|
|
705
|
+
okstra report-finalize --project-root <dir> --run-manifest <path> \
|
|
706
|
+
--report <final-report-<task-type>-<seq>.md> [--team-state <path>]
|
|
707
|
+
|
|
708
|
+
Runs the six Phase 7 steps in their contractual order against one final-report:
|
|
709
|
+
|
|
710
|
+
1. project-activity project the run's activity events into the data.json
|
|
711
|
+
2. check-source verify the data.json is the English SSOT
|
|
712
|
+
3. token-usage substitute real token/cost numbers into the data.json
|
|
713
|
+
4. render-views write the schema-v2 task-specific *.html sibling; v1
|
|
714
|
+
keeps the legacy conditional interactive view
|
|
715
|
+
5. spawn-followups turn section 4 rows into task stubs
|
|
716
|
+
6. validate-run validate the finished run artifacts
|
|
717
|
+
|
|
718
|
+
Every step is idempotent, so re-running after a fixed failure is safe. The
|
|
719
|
+
sequence stops at the first non-zero exit and reports which step failed, except
|
|
720
|
+
token-usage: its input is the lead session log, so a failure there does not
|
|
721
|
+
take the html, follow-ups and validation after it down with it. Whenever a step
|
|
722
|
+
exits non-zero the command prints the --only flags that resume the sequence
|
|
723
|
+
from the earliest failing step — follow those rather than rerunning the failing
|
|
724
|
+
step alone, which would leave the html rendered before the tokens landed.
|
|
725
|
+
|
|
726
|
+
This is the same code path the Codex lead adapter runs automatically after its
|
|
727
|
+
report-writer completes, so a Claude-led and a Codex-led run finalize
|
|
728
|
+
identically.
|
|
729
|
+
|
|
730
|
+
--workspace-root is owned by this command.
|
|
731
|
+
"""
|
|
732
|
+
|
|
733
|
+
|
|
624
734
|
def _parser() -> argparse.ArgumentParser:
|
|
625
735
|
parser = argparse.ArgumentParser(
|
|
736
|
+
prog="okstra report-finalize",
|
|
737
|
+
epilog=_CLI_EPILOG,
|
|
738
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
626
739
|
description="Run the Phase 7 report post-processing sequence.",
|
|
627
740
|
)
|
|
628
741
|
parser.add_argument("--project-root", required=True)
|
|
@@ -691,6 +804,80 @@ def _recovery_step_names(
|
|
|
691
804
|
return []
|
|
692
805
|
|
|
693
806
|
|
|
807
|
+
def closeout_command(result: Mapping[str, Any]) -> dict[str, str]:
|
|
808
|
+
"""이 run 이 사용자에게 건네야 할 명령.
|
|
809
|
+
|
|
810
|
+
`prompts/launch.template.md` "User closeout (BLOCKING)" 의 표를 코드로
|
|
811
|
+
내린 것이다. 그 표는 문서에만 있었고, 표가 분기하는 포인터는 리드에게
|
|
812
|
+
도착하지도 않았다 — 규칙이 있고 집행이 없는 자리였다. 여기서 판정하면
|
|
813
|
+
리드가 표를 기억해 따라갈 필요가 없고, 리드가 침묵해도 명령은
|
|
814
|
+
`report-finalize` 출력에 남는다.
|
|
815
|
+
|
|
816
|
+
산문을 해석하지 않는다. `blocked` / `pending` 의 근거 문장은 이미 무엇을
|
|
817
|
+
실행할지 말하고 있으므로(`okstra_ctl.next_phase` 의 승인 차단 근거,
|
|
818
|
+
`validators/validate-run.py` 의 검증 실패 근거), 그 문장을 그대로 인용할
|
|
819
|
+
자리로 넘기고 명령 칸은 비운다. 근거에서 명령을 다시 뽑아내는 것은
|
|
820
|
+
기록된 값의 재구현이다.
|
|
821
|
+
|
|
822
|
+
돌려주는 것은 `command` 와 `note` 두 칸이다. `command` 가 비면 근거
|
|
823
|
+
문장이 그 자리를 대신한다.
|
|
824
|
+
"""
|
|
825
|
+
failed_validate = any(
|
|
826
|
+
step.get("name") == STEP_VALIDATE_RUN and step.get("exitCode") != 0
|
|
827
|
+
for step in (result.get("steps") or [])
|
|
828
|
+
if isinstance(step, Mapping)
|
|
829
|
+
)
|
|
830
|
+
if failed_validate:
|
|
831
|
+
return {
|
|
832
|
+
"command": "/okstra-run",
|
|
833
|
+
"note": "validate-run failed — name the blocking cause in one line, "
|
|
834
|
+
"then re-run this same phase",
|
|
835
|
+
}
|
|
836
|
+
pointer = result.get("nextRecommendedPhase")
|
|
837
|
+
if not isinstance(pointer, Mapping):
|
|
838
|
+
return {"command": "/okstra-inspect status", "note": "no pointer recorded"}
|
|
839
|
+
status = str(pointer.get("status") or "").strip()
|
|
840
|
+
phase = str(pointer.get("phase") or "").strip()
|
|
841
|
+
rationale = str(pointer.get("rationale") or "").strip()
|
|
842
|
+
if status == STATUS_READY and phase:
|
|
843
|
+
return {"command": f"/okstra-run → {phase}", "note": ""}
|
|
844
|
+
if status == STATUS_TERMINAL:
|
|
845
|
+
return {
|
|
846
|
+
"command": "",
|
|
847
|
+
"note": "the lifecycle ends here — say the task is finished, name any "
|
|
848
|
+
"follow-up tasks this run registered, and do not send the user "
|
|
849
|
+
"to /okstra-inspect",
|
|
850
|
+
}
|
|
851
|
+
if status in (STATUS_BLOCKED, STATUS_PENDING) and rationale:
|
|
852
|
+
return {
|
|
853
|
+
"command": "",
|
|
854
|
+
"note": "quote the rationale above and issue the command it names",
|
|
855
|
+
}
|
|
856
|
+
return {"command": "/okstra-inspect status", "note": ""}
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
def _next_phase_summary_lines(result: Mapping[str, Any]) -> list[str]:
|
|
860
|
+
"""다음 phase 포인터와 그것이 정하는 명령을 사람이 읽는 줄로."""
|
|
861
|
+
pointer = result.get("nextRecommendedPhase")
|
|
862
|
+
if not isinstance(pointer, Mapping):
|
|
863
|
+
return []
|
|
864
|
+
lines = [
|
|
865
|
+
f"next phase status: {pointer.get('status') or '-'}",
|
|
866
|
+
f"next phase: {pointer.get('phase') or '-'}",
|
|
867
|
+
]
|
|
868
|
+
rationale = str(pointer.get("rationale") or "").strip()
|
|
869
|
+
if rationale:
|
|
870
|
+
lines.append(f"next phase rationale: {rationale}")
|
|
871
|
+
error = str(result.get("nextRecommendedPhaseError") or "").strip()
|
|
872
|
+
if error:
|
|
873
|
+
lines.append(f"next phase pointer unreadable: {error}")
|
|
874
|
+
closeout = closeout_command(result)
|
|
875
|
+
lines.append(f"next command: {closeout['command'] or '-'}")
|
|
876
|
+
if closeout["note"]:
|
|
877
|
+
lines.append(f"next command note: {closeout['note']}")
|
|
878
|
+
return lines
|
|
879
|
+
|
|
880
|
+
|
|
694
881
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
695
882
|
args = _parser().parse_args(argv)
|
|
696
883
|
try:
|
|
@@ -708,6 +895,10 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
708
895
|
print("finalize steps:", file=sys.stderr)
|
|
709
896
|
for line in _step_summary_lines(result, order):
|
|
710
897
|
print(line, file=sys.stderr)
|
|
898
|
+
# closeout 이 분기하는 값. JSON 을 파싱하지 않고 훑는 리드에게도 보이도록
|
|
899
|
+
# 요약 줄로 한 번 더 낸다.
|
|
900
|
+
for line in _next_phase_summary_lines(result):
|
|
901
|
+
print(line, file=sys.stderr)
|
|
711
902
|
if not result["ok"]:
|
|
712
903
|
print(f"error: {result['reason']}", file=sys.stderr)
|
|
713
904
|
recovery = _recovery_step_names(result, order)
|
|
@@ -68,8 +68,8 @@ def _own_section_ids(data: dict, omitted_fields: tuple[str, ...] = ()) -> set[st
|
|
|
68
68
|
|
|
69
69
|
The ledger is the fallback home for a cited row, so it must not claim an id
|
|
70
70
|
that has one — two elements with the same anchor send half the links to the
|
|
71
|
-
wrong place. `crossVerification.consensus` numbers its rows `
|
|
72
|
-
|
|
71
|
+
wrong place. `crossVerification.consensus` numbers its rows `CV-001`, a
|
|
72
|
+
namespace of its own, so a `C-NNN` in the report has exactly one home.
|
|
73
73
|
|
|
74
74
|
`omitted_fields` names task-block fields the HTML template does not render,
|
|
75
75
|
so their ids do not count as anchored.
|
|
@@ -69,25 +69,21 @@ def _report_meta(data: dict, run_meta: HtmlRunMeta) -> dict[str, object]:
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def _localize(data: dict, data_path: Path) -> tuple[dict, str]:
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
renders in English; that keeps a half-finished translation readable, and
|
|
78
|
-
the counts are printed because a silently half-empty sidecar otherwise
|
|
79
|
-
ships looking finished.
|
|
72
|
+
"""이 리포트 언어의 번역 사이드카를 메모리 복사본에 덮어쓴다.
|
|
73
|
+
|
|
74
|
+
data.json 은 영어 정본이고 고치지 않는다. 사람이 읽는 HTML 만 독자 언어다.
|
|
75
|
+
사이드카가 빠진 포인터는 영어로 남긴다. 사이드카 파일 자체가 없으면
|
|
76
|
+
크롬만 번역되고 본문은 영어로 나가므로 렌더를 거부한다.
|
|
80
77
|
"""
|
|
81
78
|
lang = str((data.get("meta") or {}).get("reportLanguage") or "en")
|
|
82
79
|
if lang == "en":
|
|
83
80
|
return data, lang
|
|
84
81
|
sidecar_file = translation_sidecar_path(data_path, lang)
|
|
85
82
|
if not sidecar_file.is_file():
|
|
86
|
-
|
|
87
|
-
f"
|
|
88
|
-
"
|
|
83
|
+
raise HtmlRenderError(
|
|
84
|
+
f"no {lang} translation sidecar at {sidecar_file.name}; "
|
|
85
|
+
"human HTML cannot fall back to the English source"
|
|
89
86
|
)
|
|
90
|
-
return data, lang
|
|
91
87
|
payload = load_owned_object(sidecar_file, artifact="translation sidecar")
|
|
92
88
|
strings = payload.get("strings")
|
|
93
89
|
if not isinstance(strings, dict):
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
"""Report-language resolution
|
|
1
|
+
"""Report-language resolution — the one place the precedence lives.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Two surfaces need the answer and must agree: the `**Report Language:**` line
|
|
4
|
+
both dispatchers stamp into the report-writer prompt, and `reportLanguage` in
|
|
5
|
+
the run manifest, which report assembly copies into `meta.reportLanguage` and
|
|
6
|
+
the HTML renderer reads. When only the prompt called this, a project could ask
|
|
7
|
+
for `ko`, get a Korean-instructed writer, and still ship an English report.
|
|
8
|
+
|
|
9
|
+
Precedence: project config → global config → inferred from the task brief.
|
|
6
10
|
"""
|
|
7
11
|
from __future__ import annotations
|
|
8
12
|
|
|
@@ -38,8 +38,25 @@ class _Node:
|
|
|
38
38
|
self.children: list[_Node] = []
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
_NARRATIVE_SCHEMA_RELATIVE = ("schemas", "report-narrative-v3.0.schema.json")
|
|
42
|
+
|
|
43
|
+
|
|
41
44
|
def _narrative_schema_path() -> Path:
|
|
42
|
-
|
|
45
|
+
"""schemas 를 실제로 가진 루트에서 해소한다.
|
|
46
|
+
|
|
47
|
+
부모 개수를 세면 체크아웃에서만 맞는다 — 설치본은 패키지가
|
|
48
|
+
`~/.okstra/lib/python/` 이고 schemas 는 `~/.okstra/schemas/` 라 한 단계
|
|
49
|
+
어긋나서, 설치본으로 실행할 때 서사 파싱이 스키마 없음으로 죽었다.
|
|
50
|
+
"""
|
|
51
|
+
from .paths import find_asset_root
|
|
52
|
+
|
|
53
|
+
root = find_asset_root(_NARRATIVE_SCHEMA_RELATIVE)
|
|
54
|
+
if root is None:
|
|
55
|
+
raise NarrativeContractError(
|
|
56
|
+
"could not locate report-narrative-v3.0.schema.json. Set OKSTRA_HOME "
|
|
57
|
+
"or run from a checkout that contains schemas/."
|
|
58
|
+
)
|
|
59
|
+
return root.joinpath(*_NARRATIVE_SCHEMA_RELATIVE)
|
|
43
60
|
|
|
44
61
|
|
|
45
62
|
def _narrative_schema() -> dict[str, Any]:
|
|
@@ -50,6 +67,72 @@ def _allowed_top_level() -> frozenset[str]:
|
|
|
50
67
|
return frozenset(_narrative_schema().get("properties", {}))
|
|
51
68
|
|
|
52
69
|
|
|
70
|
+
# 완성 리포트 스키마가 작성자 소유 블록 안에서 required 로 거는 기계 소유 필드.
|
|
71
|
+
# `writer_owned_data` 가 떼어내고 `_NESTED_FORBIDDEN` 이 저작을 막는 바로 그
|
|
72
|
+
# 이름들이라, 값 제약을 그대로 쓰면 정상 서사가 전부 "필수 필드 없음" 으로
|
|
73
|
+
# 깨진다. 앞의 둘은 `_NESTED_FORBIDDEN` 에서 파생시켜 두 목록이 갈라지지
|
|
74
|
+
# 않게 한다.
|
|
75
|
+
_MACHINE_OWNED_NESTED = frozenset(
|
|
76
|
+
{path.rsplit(".", 1)[-1] for path in _NESTED_FORBIDDEN} | {"designSurfaceCoverage"}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _without_machine_owned_required(node: Any, *, negated: bool = False) -> Any:
|
|
81
|
+
"""`required` 목록에서 기계 소유 필드 이름만 뺀 스키마 사본.
|
|
82
|
+
|
|
83
|
+
`not` 아래는 건드리지 않는다. 거기서 `required: [designPreparation]` 은
|
|
84
|
+
"이 필드가 있으면 안 된다" 는 뜻이고 서사에는 원래 없으니 이미 만족한다.
|
|
85
|
+
이름을 빼면 `not: {required: []}` 가 되는데, 빈 `required` 는 모든 객체가
|
|
86
|
+
만족하므로 그 `not` 은 항상 거짓이 된다 — 통과해야 할 분기를 통과 불가로
|
|
87
|
+
뒤집는다. 실제로 `direction-invalidated` 계획 분기가 그렇게 죽었다.
|
|
88
|
+
"""
|
|
89
|
+
if isinstance(node, list):
|
|
90
|
+
return [_without_machine_owned_required(item, negated=negated) for item in node]
|
|
91
|
+
if not isinstance(node, dict):
|
|
92
|
+
return node
|
|
93
|
+
result: dict[str, Any] = {}
|
|
94
|
+
for key, value in node.items():
|
|
95
|
+
if key == "required" and isinstance(value, list) and not negated:
|
|
96
|
+
result[key] = [
|
|
97
|
+
name for name in value if name not in _MACHINE_OWNED_NESTED
|
|
98
|
+
]
|
|
99
|
+
else:
|
|
100
|
+
result[key] = _without_machine_owned_required(
|
|
101
|
+
value, negated=negated or key == "not"
|
|
102
|
+
)
|
|
103
|
+
return result
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _writer_owned_schema(schema: Mapping[str, Any]) -> dict[str, Any]:
|
|
107
|
+
"""작성자가 쓴 서사에 걸 값 제약 — 완성 리포트 스키마에서 잘라 온다.
|
|
108
|
+
|
|
109
|
+
`report-narrative-v3.0.schema.json` 은 최상위 **이름** 허용목록이고 값은
|
|
110
|
+
전부 `{"type": "object"}` 스텁이다. 그 스텁으로만 검증하면 enum 밖 값과
|
|
111
|
+
빠진 필수 필드가 서사 단계를 통과하고, Phase 7 조립이 완성 리포트 스키마에
|
|
112
|
+
부딪힐 때에야 거절된다 — 작성기 워커가 이미 끝난 뒤라 되돌릴 방법이 없다.
|
|
113
|
+
실측(2026-08-26, stage 10 run 002): `verdictCard.direction` 에 enum 에 없는
|
|
114
|
+
`proceed` 가, `humanSummary` 에 필수 `whyItMatters` 가 빠진 채로 서사가
|
|
115
|
+
통과했고 `report-finalize` 의 `project-activity` 가 exit 1 로 떨어졌다.
|
|
116
|
+
|
|
117
|
+
그래서 이름 소유권은 서사 스키마에서, 값 제약은 넘겨받은 완성 리포트
|
|
118
|
+
스키마에서 가져온다. 두 벌을 만들지 않으므로 드리프트가 생기지 않는다.
|
|
119
|
+
서사는 부분 문서다 — 최상위 `required` 는 싣지 않는다. 이 run 의 task
|
|
120
|
+
블록만 있고 나머지 task-type 블록과 기계 소유 최상위 필드는 없기 때문이다.
|
|
121
|
+
"""
|
|
122
|
+
allowed = _allowed_top_level()
|
|
123
|
+
properties = {
|
|
124
|
+
key: value
|
|
125
|
+
for key, value in schema.get("properties", {}).items()
|
|
126
|
+
if key in allowed
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"additionalProperties": False,
|
|
131
|
+
"properties": _without_machine_owned_required(properties),
|
|
132
|
+
"$defs": _without_machine_owned_required(schema.get("$defs", {})),
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
53
136
|
def writer_owned_data(data: Mapping[str, Any]) -> dict[str, Any]:
|
|
54
137
|
"""완성 리포트에서 보고서 작성자 소유 필드만 복사한다."""
|
|
55
138
|
owned = {
|
|
@@ -331,7 +414,11 @@ def _parse_object(node: _Node, schema_node: Any, index: SchemaIndex, path: str)
|
|
|
331
414
|
|
|
332
415
|
|
|
333
416
|
def parse_narrative(markdown: str, schema: Mapping[str, Any]) -> dict[str, Any]:
|
|
334
|
-
"""Markdown을 작성자 소유 자료로
|
|
417
|
+
"""Markdown을 작성자 소유 자료로 읽고, 소유권 표면과 값 제약을 검증한다.
|
|
418
|
+
|
|
419
|
+
`schema` 는 완성 리포트 스키마다. 이름·타입 해석과 값 검증이 모두 그
|
|
420
|
+
한 벌에서 나온다(`_writer_owned_schema`).
|
|
421
|
+
"""
|
|
335
422
|
root = _parse_tree(markdown)
|
|
336
423
|
index = SchemaIndex(schema)
|
|
337
424
|
result = _parse_object(root, schema, index, "")
|
|
@@ -345,7 +432,7 @@ def parse_narrative(markdown: str, schema: Mapping[str, Any]) -> dict[str, Any]:
|
|
|
345
432
|
f"owner=report-writer cannot author fields: {labels}; "
|
|
346
433
|
f"writer-owned top-level fields: {owned}"
|
|
347
434
|
)
|
|
348
|
-
errors = validate(result,
|
|
435
|
+
errors = validate(result, _writer_owned_schema(schema))
|
|
349
436
|
if errors:
|
|
350
437
|
raise NarrativeContractError("; ".join(errors))
|
|
351
438
|
return result
|
|
@@ -168,6 +168,9 @@ def _worker_details(team_state: Mapping[str, Any]) -> list[dict[str, Any]]:
|
|
|
168
168
|
usage = worker.get("usage") if isinstance(worker.get("usage"), Mapping) else {}
|
|
169
169
|
row = {"label": _text(worker.get("role") or worker.get("workerId"), "Worker")}
|
|
170
170
|
_populate_usage(row, usage)
|
|
171
|
+
# 작업 시간은 executionStatus 칸이다. workerDetails 스키마는
|
|
172
|
+
# durationMs 를 허용하지 않아 조립이 additionalProperties 로 거절한다.
|
|
173
|
+
row.pop("durationMs", None)
|
|
171
174
|
for key in ("totalTokens", "cacheReadTokens", "billableTokens", "costUsd", "cliTotalTokens", "cliCostUsd"):
|
|
172
175
|
row.setdefault(key, None)
|
|
173
176
|
result.append(row)
|
|
@@ -231,6 +234,9 @@ def project_design(
|
|
|
231
234
|
def _round_history(state: Mapping[str, Any]) -> dict[str, Any]:
|
|
232
235
|
if not (state.get("config") or {}).get("enabled", True):
|
|
233
236
|
return {"disabled": True}
|
|
237
|
+
skip_reason = state.get("round2SkippedReason", "not-skipped")
|
|
238
|
+
if skip_reason == "auto-disabled":
|
|
239
|
+
skip_reason = "single-analyser-only"
|
|
234
240
|
rows = []
|
|
235
241
|
for row in state.get("roundHistory") or []:
|
|
236
242
|
if not isinstance(row, Mapping):
|
|
@@ -243,7 +249,7 @@ def _round_history(state: Mapping[str, Any]) -> dict[str, Any]:
|
|
|
243
249
|
"dispatches": json.dumps(row.get("dispatches") or [], ensure_ascii=False),
|
|
244
250
|
"skippedWorkers": json.dumps(row.get("skippedWorkers") or [], ensure_ascii=False),
|
|
245
251
|
})
|
|
246
|
-
return {"rounds": rows, "round2SkippedReason":
|
|
252
|
+
return {"rounds": rows, "round2SkippedReason": skip_reason}
|
|
247
253
|
|
|
248
254
|
|
|
249
255
|
def _source_items(finding: Mapping[str, Any]) -> list[str]:
|
|
@@ -265,7 +271,7 @@ def project_convergence(state: Mapping[str, Any]) -> dict[str, Any]:
|
|
|
265
271
|
ticket_id = _text(ticket_ids[0] if ticket_ids else "unknown", "unknown")
|
|
266
272
|
if finding.get("classification") in {"full-consensus", "partial-consensus"}:
|
|
267
273
|
row = {
|
|
268
|
-
"id": f"
|
|
274
|
+
"id": f"CV-{len(consensus) + 1:03d}",
|
|
269
275
|
"ticketId": ticket_id,
|
|
270
276
|
"statement": _text(finding.get("summary"), "Converged finding"),
|
|
271
277
|
"sourceItems": _source_items(finding),
|