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
|
@@ -1,35 +1,94 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""로스터 worker_id 어휘와 그로부터 나오는 아티팩트 경로."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Any, Mapping
|
|
6
6
|
|
|
7
|
+
from .domain.role import ROLE_DEFINITIONS
|
|
7
8
|
from .models import provider_ids
|
|
8
9
|
|
|
10
|
+
# worker_id 접미사로 쓰이는 역할 토큰 — 역할 카탈로그가 정본이다.
|
|
11
|
+
# 이 모듈은 leaf 로 남아야 한다(`worker_prompt_body` 를 끌어오면
|
|
12
|
+
# `run_context` ↔ `path_hints` 순환이 된다). 그래서 고정 worker_id 인
|
|
13
|
+
# `report-writer` 는 이름으로 특수 처리하지 않는다 — 마지막 하이픈 뒤가
|
|
14
|
+
# `writer` 라 어느 역할 토큰과도 맞지 않아 자연히 접미사 없음으로 떨어진다.
|
|
15
|
+
_ROLE_SUFFIX_TOKENS = frozenset(
|
|
16
|
+
definition.id for definition in ROLE_DEFINITIONS
|
|
17
|
+
)
|
|
9
18
|
|
|
10
|
-
def artifact_worker_ids() -> list[str]:
|
|
11
|
-
"""All analysis worker ids plus the non-analysis report writer slot."""
|
|
12
|
-
return [*provider_ids("analyser"), "report-writer"]
|
|
13
19
|
|
|
20
|
+
def worker_role_suffix(worker_id: str) -> str:
|
|
21
|
+
"""worker_id 에서 provider 뒤에 붙은 역할 접미사. 없으면 빈 문자열.
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
`claude-verifier` → `verifier`, `claude-verifier-2` → `verifier-2`,
|
|
24
|
+
`claude` → `""`, `report-writer` → `""`.
|
|
25
|
+
"""
|
|
26
|
+
stem, separator, tail = worker_id.rpartition("-")
|
|
27
|
+
ordinal = ""
|
|
28
|
+
if separator and tail.isdigit():
|
|
29
|
+
ordinal, worker_id = f"-{tail}", stem
|
|
30
|
+
_, separator, role = worker_id.rpartition("-")
|
|
31
|
+
if not separator or role not in _ROLE_SUFFIX_TOKENS:
|
|
32
|
+
return ""
|
|
33
|
+
return f"{role}{ordinal}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def worker_provider_id(worker_id: str) -> str:
|
|
37
|
+
"""역할 접미사가 붙은 worker_id 에서 provider id 를 되돌린다.
|
|
38
|
+
|
|
39
|
+
한 provider 가 로스터에서 두 슬롯 이상을 차지하면 슬롯마다
|
|
40
|
+
`claude-implementer` · `claude-verifier` 처럼 역할이 붙는다. 그 접미사를 떼면
|
|
41
|
+
provider registry 가 아는 id 로 돌아간다 — 접미사가 없는 id 는 그대로 남는다.
|
|
42
|
+
"""
|
|
43
|
+
suffix = worker_role_suffix(worker_id)
|
|
44
|
+
return worker_id[: -(len(suffix) + 1)] if suffix else worker_id
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def roster_worker_ids(ctx: Mapping[str, Any]) -> list[str]:
|
|
48
|
+
"""이 런이 실제로 여는 worker_id 목록.
|
|
49
|
+
|
|
50
|
+
같은 provider 가 실행자와 검증자를 겸하면 로스터에 `claude` 와 `claude-2` 가
|
|
51
|
+
함께 서므로, provider registry 목록으로는 두 번째 슬롯의 경로를 만들 수 없다.
|
|
52
|
+
로스터를 싣지 않은 ctx(경로 힌트에서 되살린 레거시 컨텍스트)에서는 registry
|
|
53
|
+
목록으로 돌아간다 — 그 경우 접미사 id 는 애초에 등장하지 않는다.
|
|
54
|
+
"""
|
|
55
|
+
roster = [
|
|
56
|
+
part.strip()
|
|
57
|
+
for part in str(ctx.get("RECOMMENDED_ANALYSERS", "") or "").split(",")
|
|
58
|
+
if part.strip()
|
|
59
|
+
]
|
|
60
|
+
return roster or [*provider_ids("analyser"), "report-writer"]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def worker_artifact_paths(
|
|
64
|
+
ctx: Mapping[str, Any], worker_id: str, *, relative: bool
|
|
65
|
+
) -> dict[str, str]:
|
|
66
|
+
"""worker_id 하나의 prompt/result/errors 경로.
|
|
67
|
+
|
|
68
|
+
경로는 id 에서 직접 만들어지므로 로스터에 없는 id 로도 부를 수 있다 —
|
|
69
|
+
payload 로만 전달된 워커 행을 되살릴 때 필요하다.
|
|
70
|
+
"""
|
|
19
71
|
prompt_root = _context_root(ctx, "RUN_PROMPTS", relative)
|
|
20
72
|
result_root = _context_root(ctx, "WORKER_RESULTS", relative)
|
|
21
73
|
task_type = str(ctx.get("TASK_TYPE_SEGMENT", ""))
|
|
22
74
|
prompt_suffix = f"-{task_type}-{ctx.get('RUN_PROMPTS_SEQ', '')}"
|
|
23
75
|
result_suffix = f"-{task_type}-{ctx.get('WORKER_RESULTS_SEQ', '')}"
|
|
24
76
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
77
|
+
"promptPath": str(prompt_root / f"{worker_id}-worker-prompt{prompt_suffix}.md"),
|
|
78
|
+
"resultPath": str(result_root / f"{worker_id}-worker{result_suffix}.md"),
|
|
79
|
+
"errorsSidecarPath": str(
|
|
80
|
+
result_root / f"{worker_id}-worker-errors{result_suffix}.json"
|
|
81
|
+
),
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def artifacts_from_context(
|
|
86
|
+
ctx: Mapping[str, Any], *, relative: bool
|
|
87
|
+
) -> dict[str, dict[str, str]]:
|
|
88
|
+
"""이 런의 로스터 worker_id 별 prompt/result/errors 경로."""
|
|
89
|
+
return {
|
|
90
|
+
worker_id: worker_artifact_paths(ctx, worker_id, relative=relative)
|
|
91
|
+
for worker_id in roster_worker_ids(ctx)
|
|
33
92
|
}
|
|
34
93
|
|
|
35
94
|
|
|
@@ -18,8 +18,30 @@ from okstra_ctl.worker_audit_ledger import (
|
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
_CLI_EPILOG = r"""Usage:
|
|
22
|
+
okstra worker-audit-check --run-dir <runs/<task-type>/> --task-type <type> \
|
|
23
|
+
--seq <nnn> [--worker <id>]
|
|
24
|
+
|
|
25
|
+
--run-dir the run directory; worker-results/ and prompts/ hang off it
|
|
26
|
+
--worker check only this worker (default: every worker in the run)
|
|
27
|
+
|
|
28
|
+
Emits one JSON object — `{ok, failures[]}` — and exits 2 when failures[] is
|
|
29
|
+
non-empty, 0 otherwise.
|
|
30
|
+
|
|
31
|
+
Runs the Phase 7 audit-sidecar rules now, while the worker session is still
|
|
32
|
+
alive: that every result file carries no `## 0. Reading Confirmation` heading,
|
|
33
|
+
that its audit sidecar exists, and that every backticked `path:line` citation
|
|
34
|
+
has a matching Evidence read row in that sidecar.
|
|
35
|
+
|
|
36
|
+
Call it right after collecting a worker result. The same failure at Phase 7
|
|
37
|
+
leaves only a retroactive edit — which breaks the audit chain — or a failed run.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
|
|
21
41
|
def _parser() -> argparse.ArgumentParser:
|
|
22
42
|
parser = argparse.ArgumentParser(
|
|
43
|
+
epilog=_CLI_EPILOG,
|
|
44
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
23
45
|
prog="okstra worker-audit-check",
|
|
24
46
|
description="Check one run's worker audit sidecars (read-only).",
|
|
25
47
|
)
|
|
@@ -65,8 +65,29 @@ def _backend_payload(backend_plan, *, dry_run: bool) -> dict[str, Any]:
|
|
|
65
65
|
return payload
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
_CLI_EPILOG = r"""Usage:
|
|
69
|
+
okstra worker-dispatch --project-root <dir> --run-manifest <path> \
|
|
70
|
+
[--workers <cli-assigned-worker-ids>] [--dry-run] \
|
|
71
|
+
[--idle-timeout-seconds <n>]
|
|
72
|
+
|
|
73
|
+
This command reads a prepared run manifest and dispatches only assignments
|
|
74
|
+
whose persisted runner is 'cli-wrapper'. It verifies each invocation contract
|
|
75
|
+
before execution and uses the persisted provider, model, and registered CLI.
|
|
76
|
+
Native-session assignments remain owned by the active host session.
|
|
77
|
+
|
|
78
|
+
Missing worker prompt files are generated automatically from the immutable run snapshot.
|
|
79
|
+
Existing prompt and metadata files are never overwritten.
|
|
80
|
+
When report-writer completes, this command also runs the idempotent post-report
|
|
81
|
+
steps: token-usage substitution, render-views, spawn-followups, and validate-run.
|
|
82
|
+
|
|
83
|
+
--workspace-root and --okstra-bin are owned by this command.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
|
|
68
87
|
def _parser() -> argparse.ArgumentParser:
|
|
69
88
|
parser = argparse.ArgumentParser(
|
|
89
|
+
epilog=_CLI_EPILOG,
|
|
90
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
70
91
|
prog="okstra worker-dispatch",
|
|
71
92
|
description="Dispatch verified CLI-backed workers for a prepared run.",
|
|
72
93
|
)
|
|
@@ -404,8 +404,41 @@ def probe_target(team_state_value: str, worker_id: str) -> ProbeTarget:
|
|
|
404
404
|
return ProbeTarget(mode, artifact, dispatched_at, result_path)
|
|
405
405
|
|
|
406
406
|
|
|
407
|
+
_CLI_EPILOG = r"""Usage:
|
|
408
|
+
okstra worker-liveness [--team-state <path> --worker <worker-id>]...
|
|
409
|
+
[--max-idle <seconds>] [--launch-grace <seconds>] [--json]
|
|
410
|
+
okstra worker-liveness --wait [--team-state <path> --worker <worker-id>]...
|
|
411
|
+
[--interval <seconds>] [--timeout <seconds>]
|
|
412
|
+
|
|
413
|
+
--wait polls until every named worker's persisted resultPath lands (exit 0), one
|
|
414
|
+
worker probes unhealthy (exit 1), or --timeout passes (exit 2).
|
|
415
|
+
Defaults: --interval 20, --timeout 2400. Run it as a background
|
|
416
|
+
command and branch on the exit code. Use this instead of writing a
|
|
417
|
+
poll loop: both the "is it done" test (the persisted resultPath, not a
|
|
418
|
+
filename you assemble) and the "is it dead" test live in here, and a
|
|
419
|
+
hand-written loop re-derives them and gets one wrong. A worker row
|
|
420
|
+
without a resultPath is refused rather than waited on by guess.
|
|
421
|
+
|
|
422
|
+
--team-state and --worker select one pending worker. The worker row's
|
|
423
|
+
livenessMode picks the probe: audit-heartbeat reads the in-process
|
|
424
|
+
worker audit sidecar path and reports stalled past the heartbeat
|
|
425
|
+
cadence; wrapper-status reports did-not-launch when no prompt sibling
|
|
426
|
+
.log or .status.json exists past the launch grace. Both graces begin
|
|
427
|
+
at workers[].startedAt, never at an artifact mtime — the audit sidecar
|
|
428
|
+
is reused on re-dispatch, so the previous attempt's last heartbeat is
|
|
429
|
+
not this dispatch's signal.
|
|
430
|
+
|
|
431
|
+
Output: JSON { ok, checkedAt, probes[], unhealthy[] }, plus { outcome, pending[],
|
|
432
|
+
waitedSeconds } under --wait. Exit 1 when any worker is stalled or did not
|
|
433
|
+
launch, so a caller can branch on the exit code. Read-only: it reports, it never
|
|
434
|
+
kills or re-dispatches.
|
|
435
|
+
"""
|
|
436
|
+
|
|
437
|
+
|
|
407
438
|
def main(argv: list[str] | None = None) -> int:
|
|
408
439
|
parser = argparse.ArgumentParser(
|
|
440
|
+
epilog=_CLI_EPILOG,
|
|
441
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
409
442
|
prog="okstra worker-liveness",
|
|
410
443
|
description="Report whether pending workers are still alive (read-only).",
|
|
411
444
|
)
|
|
@@ -22,6 +22,7 @@ def analysis_prompt_body(
|
|
|
22
22
|
worker_id: str,
|
|
23
23
|
model: str,
|
|
24
24
|
plan: PromptPlan,
|
|
25
|
+
approved_plan_path: str = "",
|
|
25
26
|
) -> list[str]:
|
|
26
27
|
"""Render the provider-neutral body for an initial analysis audience."""
|
|
27
28
|
label = analysis_worker_label(worker_id)
|
|
@@ -40,7 +41,7 @@ def analysis_prompt_body(
|
|
|
40
41
|
f"- Task type: `{_require_string(manifest, 'taskType')}`",
|
|
41
42
|
"",
|
|
42
43
|
"## Inputs",
|
|
43
|
-
*analysis_input_lines(manifest, active_context, plan),
|
|
44
|
+
*analysis_input_lines(manifest, active_context, plan, approved_plan_path),
|
|
44
45
|
"",
|
|
45
46
|
mcp_pointer_line(),
|
|
46
47
|
"",
|
|
@@ -54,10 +55,22 @@ def analysis_input_lines(
|
|
|
54
55
|
manifest: Mapping[str, Any],
|
|
55
56
|
active_context: Mapping[str, Any],
|
|
56
57
|
plan: PromptPlan,
|
|
58
|
+
approved_plan_path: str = "",
|
|
57
59
|
) -> list[str]:
|
|
58
60
|
if plan.packet_only:
|
|
59
61
|
packet_path = instruction_path(manifest, active_context, "analysisPacketPath")
|
|
60
|
-
|
|
62
|
+
# 승인 계획은 `## Inputs` 에 실어야 한다. 워커의 읽기 범위는 이 절과
|
|
63
|
+
# `[Required reading]`·검증 대상 경로만 허용하는데(`**Read scope:**`),
|
|
64
|
+
# 패킷은 Tier 1 을 "원 브리프/승인 계획의 `validation` 세트" 로 정의하고
|
|
65
|
+
# 승인 계획의 requirements·scope 까지 요구한다. 경로가 여기 없으면 범위를
|
|
66
|
+
# 지키는 워커는 그 요구를 만족시킬 방법이 없다 — 실측(2026-08-26,
|
|
67
|
+
# `fontsninja-nlpvibe` final-verification): 범위를 지킨 검증자는 Tier 1 을
|
|
68
|
+
# 무엇으로 볼지 몰라 `tsc --noEmit` 으로 대체했고, 범위를 넘은 검증자만
|
|
69
|
+
# 계약대로의 산출물을 냈다.
|
|
70
|
+
return existing_input_lines((
|
|
71
|
+
("Primary analysis packet", packet_path),
|
|
72
|
+
("Approved plan", approved_plan_path),
|
|
73
|
+
))
|
|
61
74
|
inputs = [
|
|
62
75
|
("Primary analysis packet", instruction_path(manifest, active_context, "analysisPacketPath")),
|
|
63
76
|
("Task brief", instruction_path(manifest, active_context, "taskBriefPath")),
|
|
@@ -221,6 +221,47 @@ def validate_analysis_prompt_set(prompts: Mapping[str, str]) -> list[str]:
|
|
|
221
221
|
return [f"normalized initial analysis prompts differ across workers: {workers}"]
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
# reverify 응답 계약 블록. `prompts/lead/convergence.md`
|
|
225
|
+
# §"Required reverify output contract (BLOCKING)" 가 정본이고, 리드는 그 블록을
|
|
226
|
+
# 변종별 응답 형식 뒤에 그대로 덧붙인다.
|
|
227
|
+
#
|
|
228
|
+
# 바이트 단위로 비교하지 않는다 — 손으로 복사하는 블록이라 공백·줄바꿈이 흔들리고,
|
|
229
|
+
# 그 흔들림으로 디스패치를 막으면 규칙이 아니라 서식을 강제하게 된다. 세 항목이
|
|
230
|
+
# 각각 무엇을 요구하는지 식별하는 토큰으로 본다.
|
|
231
|
+
_OUTPUT_CONTRACT_HEADING = "## Output Contract"
|
|
232
|
+
_OUTPUT_CONTRACT_CLAUSES = (
|
|
233
|
+
("result-path write", ("Result Path", "before returning")),
|
|
234
|
+
("audit sidecar write", ("Audit sidecar path", "before returning")),
|
|
235
|
+
("no inline-only response", ("inline",)),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _validate_output_contract_block(text: str) -> list[str]:
|
|
240
|
+
"""응답 계약 블록이 프롬프트에 실려 있는지.
|
|
241
|
+
|
|
242
|
+
빠지면 워커가 결과를 파일로 쓰지 않고 인라인으로만 답하는 경로가 열린다 —
|
|
243
|
+
그 run 은 결과 파일이 없는 채로 dispatch 만 성공한 것처럼 보인다.
|
|
244
|
+
"""
|
|
245
|
+
if _OUTPUT_CONTRACT_HEADING not in text:
|
|
246
|
+
return [
|
|
247
|
+
f"`{_OUTPUT_CONTRACT_HEADING}` block is required "
|
|
248
|
+
"(convergence.md §\"Required reverify output contract\")"
|
|
249
|
+
]
|
|
250
|
+
tail = text.split(_OUTPUT_CONTRACT_HEADING, 1)[1]
|
|
251
|
+
missing = [
|
|
252
|
+
label
|
|
253
|
+
for label, tokens in _OUTPUT_CONTRACT_CLAUSES
|
|
254
|
+
if not all(token.lower() in tail.lower() for token in tokens)
|
|
255
|
+
]
|
|
256
|
+
if missing:
|
|
257
|
+
return [
|
|
258
|
+
"output contract block is missing its "
|
|
259
|
+
+ ", ".join(missing)
|
|
260
|
+
+ " clause"
|
|
261
|
+
]
|
|
262
|
+
return []
|
|
263
|
+
|
|
264
|
+
|
|
224
265
|
def validate_reverify_prompt(
|
|
225
266
|
text: str,
|
|
226
267
|
*,
|
|
@@ -268,6 +309,7 @@ def validate_reverify_prompt(
|
|
|
268
309
|
and boundary_position > first_heading.start()
|
|
269
310
|
):
|
|
270
311
|
errors.append("phase boundary block must precede reverify instructions")
|
|
312
|
+
errors.extend(_validate_output_contract_block(normalized))
|
|
271
313
|
return errors
|
|
272
314
|
|
|
273
315
|
|
|
@@ -351,7 +393,9 @@ def validate_initial_prompt_records(
|
|
|
351
393
|
)
|
|
352
394
|
if plan.equality_group:
|
|
353
395
|
group = equality_groups.setdefault(plan.equality_group, {})
|
|
354
|
-
|
|
396
|
+
# 최초 프롬프트의 동등성만 비교한다. 같은 역할의 교정 호출은 최초
|
|
397
|
+
# assignment 를 재사용할 수 있지만 지시문은 의도적으로 달라진다.
|
|
398
|
+
group.setdefault(record.worker_id, text)
|
|
355
399
|
for prompts in equality_groups.values():
|
|
356
400
|
errors.extend(validate_analysis_prompt_set(prompts))
|
|
357
401
|
return errors
|
|
@@ -365,15 +409,34 @@ def _validate_model_header(text: str, expected_model: str | None) -> list[str]:
|
|
|
365
409
|
"""
|
|
366
410
|
if expected_model is None:
|
|
367
411
|
return []
|
|
368
|
-
|
|
369
|
-
model = _model_value(_header_values(task_text, MODEL_HEADER))
|
|
412
|
+
model = _model_value(_header_values(text, MODEL_HEADER))
|
|
370
413
|
if model is None:
|
|
371
414
|
return ["exactly one non-empty **Model:** <label>, <model> header is required"]
|
|
372
|
-
if model
|
|
415
|
+
if not _model_header_matches(model, expected_model):
|
|
373
416
|
return [f"prompt model does not match requested model: {expected_model}"]
|
|
374
417
|
return []
|
|
375
418
|
|
|
376
419
|
|
|
420
|
+
def validate_prompt_model_header(text: str, expected_model: str) -> list[str]:
|
|
421
|
+
"""`**Model:**` 헤더가 이 디스패치가 실제로 돌릴 모델을 가리키는가.
|
|
422
|
+
|
|
423
|
+
재료화는 호출자가 넘긴 모델로 판정한다. 그 값이 옳아도 프롬프트 본문의
|
|
424
|
+
헤더가 다르면 어긋남은 `validate-run` 에서야 드러나는데, 그때는 프롬프트가
|
|
425
|
+
이미 나가고 다이제스트가 기록된 뒤라 그 run 안에서 고칠 수 없다 — 프롬프트를
|
|
426
|
+
고치면 다이제스트 위조가 된다. `record-dispatch` 는 워커가 돌기 전 마지막
|
|
427
|
+
지점이고, 거기서는 **기록된 배정값** 을 쓸 수 있다.
|
|
428
|
+
|
|
429
|
+
묻는 것은 "적혀 있다면 이 모델인가" 하나다. 헤더가 없는 것은 여기서 볼
|
|
430
|
+
문제가 아니다 — 어떤 audience 가 그 헤더를 실어야 하는지는 프롬프트 계약이
|
|
431
|
+
audience 를 알고 판정한다. 여기서 부재까지 막으면 헤더를 요구하지 않는
|
|
432
|
+
디스패치가 전부 막힌다.
|
|
433
|
+
"""
|
|
434
|
+
task_text = text.split("\n\n## Task Instructions\n\n", 1)[-1]
|
|
435
|
+
if _model_value(_header_values(task_text, MODEL_HEADER)) is None:
|
|
436
|
+
return []
|
|
437
|
+
return _validate_model_header(text, expected_model)
|
|
438
|
+
|
|
439
|
+
|
|
377
440
|
def _validate_record_metadata(text: str, record: PromptRecord) -> list[str]:
|
|
378
441
|
errors = [
|
|
379
442
|
*_validate_delivery_mode(
|
|
@@ -462,13 +525,41 @@ def _header_values(text: str, prefix: str) -> list[str]:
|
|
|
462
525
|
]
|
|
463
526
|
|
|
464
527
|
|
|
528
|
+
def _model_header_matches(got: str, expected: str) -> bool:
|
|
529
|
+
"""표시 alias 와 실행 id 를 같은 요청으로 본다.
|
|
530
|
+
|
|
531
|
+
헤더는 `opus-5` 이고 잡의 실행 값은 `claude-opus-5` 인 경우가 있다.
|
|
532
|
+
콤마 형식의 두 번째 칸과 실행 값이 문자열로 다를 뿐이면 거절하지 않는다.
|
|
533
|
+
|
|
534
|
+
`<provider>/<model>` 표기도 받는다. 위저드가 사용자에게 모델을 보여 줄 때
|
|
535
|
+
쓰는 표기가 정확히 그것(`claude/sonnet`)이라, 지시문에 그대로 옮겨 적는 것이
|
|
536
|
+
자연스러운 실수가 아니라 자연스러운 선택이다. provider 는 이 헤더의 판정
|
|
537
|
+
대상이 아니다 — 별도의 `**Provider:**` 헤더가 담당한다. 그래서 앞의 한 칸을
|
|
538
|
+
떼고 모델끼리 비교한다. 다른 모델이면 떼고 나서도 안 맞으므로 이 관용이
|
|
539
|
+
불일치를 가리지는 않는다(`claude/opus-5` 대 `sonnet` 은 그대로 실패).
|
|
540
|
+
"""
|
|
541
|
+
if got == expected:
|
|
542
|
+
return True
|
|
543
|
+
got_l, expected_l = got.lower(), expected.lower()
|
|
544
|
+
if got_l == expected_l:
|
|
545
|
+
return True
|
|
546
|
+
if expected_l.endswith("-" + got_l) or got_l.endswith("-" + expected_l):
|
|
547
|
+
return True
|
|
548
|
+
if "/" in got_l:
|
|
549
|
+
return _model_header_matches(got_l.rsplit("/", 1)[1], expected_l)
|
|
550
|
+
return False
|
|
551
|
+
|
|
552
|
+
|
|
465
553
|
def _model_value(values: list[str]) -> str | None:
|
|
466
554
|
if len(values) != 1:
|
|
467
555
|
return None
|
|
468
|
-
|
|
469
|
-
if
|
|
556
|
+
raw = values[0].strip()
|
|
557
|
+
if not raw:
|
|
470
558
|
return None
|
|
471
|
-
|
|
559
|
+
parts = [part.strip() for part in raw.rsplit(",", 1)]
|
|
560
|
+
if len(parts) == 2 and all(parts):
|
|
561
|
+
return parts[1]
|
|
562
|
+
return raw
|
|
472
563
|
|
|
473
564
|
|
|
474
565
|
def _resolve_record_plan(
|
|
@@ -82,7 +82,7 @@ PLAIN_FILE_WRITE_HEADER = (
|
|
|
82
82
|
"brain folder, so an artifact write under `<PROJECT_ROOT>/.okstra/` is "
|
|
83
83
|
"rejected and the run ends with no result file."
|
|
84
84
|
)
|
|
85
|
-
|
|
85
|
+
ANTIGRAVITY_PROVIDER = "antigravity"
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
def worker_prompt_headers(
|
|
@@ -141,7 +141,7 @@ def worker_prompt_headers(
|
|
|
141
141
|
f"**Errors sidecar path:** {errors_sidecar_path}",
|
|
142
142
|
READ_SCOPE_HEADER,
|
|
143
143
|
])
|
|
144
|
-
if worker_id ==
|
|
144
|
+
if _worker_provider(manifest, worker_id) == ANTIGRAVITY_PROVIDER:
|
|
145
145
|
headers.append(PLAIN_FILE_WRITE_HEADER)
|
|
146
146
|
if _string_value(manifest.get("taskType")) == "improvement-discovery":
|
|
147
147
|
headers.append(
|
|
@@ -153,6 +153,28 @@ def worker_prompt_headers(
|
|
|
153
153
|
return headers
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
def _worker_provider(manifest: Mapping[str, Any], worker_id: str) -> str:
|
|
157
|
+
"""이 워커를 실행할 공급자.
|
|
158
|
+
|
|
159
|
+
`agy` 의 artifact store 는 공급자의 성질이지 워커 칸 이름의 성질이 아니다.
|
|
160
|
+
종전에는 `worker_id == "antigravity"` 로 걸렀는데, 워커 id 가 공급자 이름과
|
|
161
|
+
같은 것은 기본 로스터뿐이다 — 역할 접미사가 붙은 칸(`antigravity-planner`
|
|
162
|
+
등)은 전부 이 안전장치를 못 받았고, 그 프롬프트를 재검증에 쓰려던 리드는
|
|
163
|
+
계약(`prompts/lead/convergence.md` §"Required reverify-prompt anchor
|
|
164
|
+
headers")대로 라운드를 중단해야 했다.
|
|
165
|
+
|
|
166
|
+
로스터 행을 못 찾으면 종전 규칙으로 떨어진다 — 그 자리에선 공급자를 알
|
|
167
|
+
방법이 없고, 헤더를 빼면 계약이 fail-closed 로 막는다.
|
|
168
|
+
"""
|
|
169
|
+
workers = manifest.get("workerAssignments")
|
|
170
|
+
if isinstance(workers, list):
|
|
171
|
+
for row in workers:
|
|
172
|
+
if isinstance(row, Mapping) and row.get("workerId") == worker_id:
|
|
173
|
+
value = row.get("provider")
|
|
174
|
+
return value if isinstance(value, str) else ""
|
|
175
|
+
return worker_id
|
|
176
|
+
|
|
177
|
+
|
|
156
178
|
def _final_verification_target_headers(
|
|
157
179
|
active_context: Mapping[str, Any],
|
|
158
180
|
) -> list[str]:
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from typing import Any, Literal, Mapping
|
|
6
6
|
|
|
7
|
-
from .
|
|
7
|
+
from .agent.invocation import AgentAudience
|
|
8
8
|
from .analysis_inputs import ANALYSIS_TASK_TYPES
|
|
9
9
|
|
|
10
10
|
|
|
@@ -90,6 +90,10 @@ class PromptPlan:
|
|
|
90
90
|
required_headers: tuple[str, ...]
|
|
91
91
|
max_body_lines: int | None
|
|
92
92
|
max_directive_lines: int | None
|
|
93
|
+
# 이 audience 의 `## Inputs` 가 승인 계획을 함께 열거하는가. 승인 계획을
|
|
94
|
+
# 기준으로 판정하라고 요구하는 phase 만 참이다 — 없는 phase 에 실으면
|
|
95
|
+
# 열거만 되고 열 파일이 없는 줄이 된다.
|
|
96
|
+
include_approved_plan: bool = False
|
|
93
97
|
|
|
94
98
|
|
|
95
99
|
def resolve_prompt_plan(
|
|
@@ -149,6 +153,7 @@ def resolve_prompt_plan(
|
|
|
149
153
|
duty_audience=analysis_duty,
|
|
150
154
|
equality_group=analysis_equality_group,
|
|
151
155
|
packet_only=True,
|
|
156
|
+
include_approved_plan=True,
|
|
152
157
|
required_headers=FINAL_VERIFICATION_HEADERS,
|
|
153
158
|
max_body_lines=96,
|
|
154
159
|
max_directive_lines=40,
|
|
@@ -191,6 +196,7 @@ def _plan(
|
|
|
191
196
|
duty_audience: AgentAudience | None = None,
|
|
192
197
|
equality_group: str | None = None,
|
|
193
198
|
packet_only: bool = False,
|
|
199
|
+
include_approved_plan: bool = False,
|
|
194
200
|
allow_coding_preflight: bool = False,
|
|
195
201
|
required_headers: tuple[str, ...] = (),
|
|
196
202
|
max_body_lines: int | None = None,
|
|
@@ -201,6 +207,7 @@ def _plan(
|
|
|
201
207
|
duty_audience=duty_audience or _duty_audience(audience),
|
|
202
208
|
equality_group=equality_group,
|
|
203
209
|
packet_only=packet_only,
|
|
210
|
+
include_approved_plan=include_approved_plan,
|
|
204
211
|
allow_coding_preflight=allow_coding_preflight,
|
|
205
212
|
required_headers=_worker_facing_headers(audience, required_headers),
|
|
206
213
|
max_body_lines=max_body_lines,
|
|
@@ -261,14 +268,22 @@ def critic_assignment_ref(task_type: str) -> str:
|
|
|
261
268
|
|
|
262
269
|
|
|
263
270
|
def _executor_worker_id(manifest: Mapping[str, Any]) -> str | None:
|
|
271
|
+
"""실행자의 **worker_id**. provider 이름이 아니다.
|
|
272
|
+
|
|
273
|
+
한 provider 가 실행자와 검증자를 겸하면 슬롯마다 역할이 붙어 실행자의 id 는
|
|
274
|
+
`codex-implementer` 가 된다. 여기서 provider(`codex`)를 돌려주면 실행자가
|
|
275
|
+
자기 자신과 매칭되지 않아 검증자 프롬프트로 실체화되고, 그 사실은
|
|
276
|
+
`agent invocation duty does not match expected audience` 로 디스패치 단계에서야
|
|
277
|
+
드러난다.
|
|
278
|
+
"""
|
|
264
279
|
team_contract = manifest.get("teamContract")
|
|
265
280
|
if not isinstance(team_contract, Mapping):
|
|
266
281
|
return None
|
|
267
282
|
executor = team_contract.get("executor")
|
|
268
283
|
if not isinstance(executor, Mapping):
|
|
269
284
|
return None
|
|
270
|
-
|
|
271
|
-
return
|
|
285
|
+
worker_id = executor.get("workerId")
|
|
286
|
+
return worker_id.strip() if isinstance(worker_id, str) and worker_id.strip() else None
|
|
272
287
|
|
|
273
288
|
|
|
274
289
|
def _required_string(payload: Mapping[str, Any], key: str) -> str:
|
|
@@ -54,7 +54,8 @@ def build_request(
|
|
|
54
54
|
project_root=root,
|
|
55
55
|
worktree_path=worktree,
|
|
56
56
|
# Nobody is at the keyboard to answer an approval prompt, so the gate is
|
|
57
|
-
# open
|
|
57
|
+
# open. The write scope tells the worker where it belongs; nothing in the
|
|
58
|
+
# CLI stops it leaving, so the run checks that after the fact.
|
|
58
59
|
policy=ExecutionPolicy(
|
|
59
60
|
auto_approve=True,
|
|
60
61
|
write_scope=write_scope(root, worktree, role),
|
|
@@ -10,6 +10,7 @@ SIGTERM a healthy worker in the middle of a long reasoning stretch.
|
|
|
10
10
|
"""
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import dataclasses
|
|
13
14
|
import json
|
|
14
15
|
import os
|
|
15
16
|
import selectors
|
|
@@ -21,6 +22,7 @@ from typing import Any, Callable, Mapping
|
|
|
21
22
|
|
|
22
23
|
from .domain.provider import ServedModelAttestation, ServedModelNormalizer
|
|
23
24
|
from .domain.worker_exec import (
|
|
25
|
+
NO_RESULT_EXIT_CODE,
|
|
24
26
|
SERVED_MODEL_MISMATCH_EXIT_CODE,
|
|
25
27
|
ExecCommand,
|
|
26
28
|
ExecutionStrategy,
|
|
@@ -226,11 +228,9 @@ def _with_served_model_observation(
|
|
|
226
228
|
observation.record(observed)
|
|
227
229
|
return observed
|
|
228
230
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
join_adjacent_text=presentation.join_adjacent_text,
|
|
233
|
-
)
|
|
231
|
+
# 필드를 손으로 옮기지 않는다 — 그렇게 하던 동안 어댑터가 선언한
|
|
232
|
+
# `is_conclusion` 이 여기서 떨어져 나가, grok 의 종결 판정이 무효였다.
|
|
233
|
+
return dataclasses.replace(presentation, observe=observe)
|
|
234
234
|
|
|
235
235
|
|
|
236
236
|
class _ServedModelObservation:
|
|
@@ -393,11 +393,16 @@ def _pump(
|
|
|
393
393
|
strategy.flush(transcript)
|
|
394
394
|
|
|
395
395
|
exit_code = process.wait()
|
|
396
|
-
if
|
|
397
|
-
# JSON 스트림은
|
|
398
|
-
# 놓칠
|
|
396
|
+
if isinstance(strategy, JsonEvents) and not strategy.concluded():
|
|
397
|
+
# JSON 스트림은 그 어휘의 종결 이벤트로 끝나야 한다. 텍스트를 흘리는
|
|
398
|
+
# CLI 에는 놓칠 종결 이벤트가 없다. 무엇이 종결인지는 전략이 안다.
|
|
399
399
|
transcript.note("no result event in the CLI's output")
|
|
400
|
-
|
|
400
|
+
if exit_code == 0 and not timed_out:
|
|
401
|
+
# 실측(dev-10341, 한 CLI 4회): 종결 이벤트도 산출물도 없이 exit 0.
|
|
402
|
+
# 그대로 돌려주면 사이드카와 셸 소비자에게는 성공으로 읽힌다.
|
|
403
|
+
# CLI 자신의 비영 코드는 보존한다 — 그쪽이 더 구체적인 사실이다.
|
|
404
|
+
exit_code = NO_RESULT_EXIT_CODE
|
|
405
|
+
if closing_text is not None:
|
|
401
406
|
# Result 는 format_* 가 줄을 만들지 않는다. 아카이브 결론은 러너가 적는다.
|
|
402
407
|
# 상한 밖에 둔다 — 잘린 결론은 사후 분석 전체를 잃게 한다.
|
|
403
408
|
if isinstance(strategy, JsonEvents):
|
|
@@ -559,6 +564,8 @@ def _terminate(process: subprocess.Popen[bytes]) -> None:
|
|
|
559
564
|
try:
|
|
560
565
|
os.killpg(process.pid, signal.SIGKILL)
|
|
561
566
|
except ProcessLookupError:
|
|
567
|
+
# expected-miss: SIGTERM 유예 사이에 그룹이 스스로 끝난 경우다.
|
|
568
|
+
# 죽이려던 대상이 이미 없는 것은 성공이지 실패가 아니다.
|
|
562
569
|
pass
|
|
563
570
|
process.wait()
|
|
564
571
|
|
|
@@ -18,8 +18,23 @@ def _validated_team_state_path(value: str) -> Path:
|
|
|
18
18
|
return path
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
_CLI_EPILOG = r"""Usage:
|
|
22
|
+
okstra worker-state transition --team-state <path> --worker <worker-id> \
|
|
23
|
+
--status <in-progress|completed|timeout|error|not-run> \
|
|
24
|
+
[--reason <text>] [--model <execution-value>]
|
|
25
|
+
|
|
26
|
+
in-progress records startedAt and clears endedAt. completed, timeout, and error
|
|
27
|
+
record endedAt. timeout, error, and not-run require --reason.
|
|
28
|
+
"""
|
|
29
|
+
_CLI_DESCRIPTION = "Atomically transition persisted worker status."
|
|
30
|
+
|
|
31
|
+
|
|
21
32
|
def _parser() -> argparse.ArgumentParser:
|
|
22
|
-
parser = argparse.ArgumentParser(
|
|
33
|
+
parser = argparse.ArgumentParser(
|
|
34
|
+
description=_CLI_DESCRIPTION,
|
|
35
|
+
epilog=_CLI_EPILOG,
|
|
36
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
37
|
+
prog="okstra worker-state")
|
|
23
38
|
commands = parser.add_subparsers(dest="command", required=True)
|
|
24
39
|
transition = commands.add_parser(
|
|
25
40
|
"transition", help="atomically transition one worker status"
|
|
@@ -54,7 +54,7 @@ PHASE_RULES: dict[str, dict[str, str]] = {
|
|
|
54
54
|
" - top-N ranking (default 8, brief `candidate-cap` overrides within 1..12)\n"
|
|
55
55
|
" - per-candidate columns Lens / Scope / Severity / Effort / Consensus / Source workers / Recommended next-phase / Expected behavior after / Evidence (path:line)\n"
|
|
56
56
|
" - Phase 1.5 reflect-back grilling log at `runs/improvement-discovery/<seq>/state/phase-1.5-grilling.md`\n"
|
|
57
|
-
" - Phase 5.5 consensus classification (full / partial / contested / worker-unique)"
|
|
57
|
+
" - Phase 5.5 consensus classification (full / partial / contested / worker-unique / unverified)"
|
|
58
58
|
),
|
|
59
59
|
},
|
|
60
60
|
"project-analysis": {
|
|
@@ -173,6 +173,22 @@ def load_phase_forbidden(workspace_root: Path) -> dict[str, str]:
|
|
|
173
173
|
return {phase: render_forbidden(items) for phase, items in data.items()}
|
|
174
174
|
|
|
175
175
|
|
|
176
|
+
def phase_position(task_type: str) -> str:
|
|
177
|
+
"""이 phase 가 생애주기 몇 번째인지 — `"5 of 7"`.
|
|
178
|
+
|
|
179
|
+
리드는 자기가 어느 칸을 도는지만 알고 지도를 못 본다. 다음 phase 이름은
|
|
180
|
+
이 run 의 리포트가 정하므로 계속 감추지만(`WORKFLOW_NEXT_RECOMMENDED_PHASE`
|
|
181
|
+
가 빈 문자열인 이유), 위치를 감출 이유는 없다 — 위치를 모르면 중간 단계를
|
|
182
|
+
도는 run 이 자기가 마지막인 것처럼 결론을 낸다.
|
|
183
|
+
|
|
184
|
+
`PHASE_SEQUENCE` 밖의 사이드트랙 task-type(improvement-discovery 등)은
|
|
185
|
+
생애주기 칸이 없으므로 빈 문자열이다.
|
|
186
|
+
"""
|
|
187
|
+
if task_type not in PHASE_SEQUENCE:
|
|
188
|
+
return ""
|
|
189
|
+
return f"{PHASE_SEQUENCE.index(task_type) + 1} of {len(PHASE_SEQUENCE)}"
|
|
190
|
+
|
|
191
|
+
|
|
176
192
|
def compute_workflow_state(
|
|
177
193
|
*,
|
|
178
194
|
task_type: str,
|
|
@@ -219,6 +235,7 @@ def compute_workflow_state(
|
|
|
219
235
|
"WORKFLOW_WORK_CATEGORY": resolved_work_category,
|
|
220
236
|
"WORKFLOW_CURRENT_PHASE": task_type,
|
|
221
237
|
"WORKFLOW_CURRENT_PHASE_STATE": phase_state,
|
|
238
|
+
"WORKFLOW_PHASE_POSITION": phase_position(task_type),
|
|
222
239
|
# 값이 아니라 자리표시자다. 실제 포인터는 리포트 라우팅에서 투영돼
|
|
223
240
|
# 매니페스트의 `workflow.nextRecommendedPhase` 구조체로 저장된다.
|
|
224
241
|
# 이 ctx 값은 그 구조체로 대체되지 않는다 — 남은 소비자는
|