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
|
@@ -456,8 +456,21 @@ def audit_runs(home: Path, *, now: dt.datetime) -> list[dict]:
|
|
|
456
456
|
return violations
|
|
457
457
|
|
|
458
458
|
|
|
459
|
+
_CLI_EPILOG = r"""Usage:
|
|
460
|
+
okstra run-audit
|
|
461
|
+
|
|
462
|
+
Walks the global run-index and checks each run's artifacts (run-manifest,
|
|
463
|
+
final-report data, worker results) against invariants that no error log
|
|
464
|
+
would catch: verification rounds that never ran, reports that never
|
|
465
|
+
appeared, rosters that came up short, approvals waiting past the window.
|
|
466
|
+
Read-only. Prints a JSON summary to stdout.
|
|
467
|
+
"""
|
|
468
|
+
|
|
469
|
+
|
|
459
470
|
def main(argv: list[str] | None = None) -> int:
|
|
460
471
|
parser = argparse.ArgumentParser(
|
|
472
|
+
epilog=_CLI_EPILOG,
|
|
473
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
461
474
|
prog="okstra run-audit",
|
|
462
475
|
description="런 아티팩트에서 불변식 위반을 찾는다 (읽기 전용).",
|
|
463
476
|
)
|
|
@@ -104,15 +104,3 @@ def _rewrite_slim(path: Path) -> int:
|
|
|
104
104
|
rewrite_jsonl(path, [slim_run_row(row) for row in rows])
|
|
105
105
|
return len(rows)
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
def reindex_slim(home: Path) -> int:
|
|
109
|
-
"""기존 run-index 파일들을 slim 으로 일괄 재작성. 멱등. 변환 row 총수 반환."""
|
|
110
|
-
total = 0
|
|
111
|
-
targets = [home / "recent.jsonl", home / "active.jsonl"]
|
|
112
|
-
projects = home / "projects"
|
|
113
|
-
if projects.is_dir():
|
|
114
|
-
targets += sorted(projects.glob("*/index.jsonl"))
|
|
115
|
-
for path in targets:
|
|
116
|
-
if path.is_file():
|
|
117
|
-
total += _rewrite_slim(path)
|
|
118
|
-
return total
|
|
@@ -10,6 +10,7 @@ okstra worker wrapper 호출이 자동 허용되도록 한다.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
+
import sys
|
|
13
14
|
import time
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from typing import Optional
|
|
@@ -69,9 +70,8 @@ def verify_installation(workspace_root: Path) -> None:
|
|
|
69
70
|
이 검사는 ~/.okstra 자산만을 본다; workspace_root 의 존재는 별도 검증.
|
|
70
71
|
|
|
71
72
|
`OKSTRA_SKIP_INSTALL_CHECK=1` 이면 설치 자산 검사를 건너뛴다 — 격리
|
|
72
|
-
OKSTRA_HOME 으로 subprocess 를 띄우는 테스트용 게이트(conftest 가
|
|
73
|
-
|
|
74
|
-
게이트와 무관하게 항상 수행한다.
|
|
73
|
+
OKSTRA_HOME 으로 subprocess 를 띄우는 테스트용 게이트(conftest 가 설정).
|
|
74
|
+
workspace_root 검증은 게이트와 무관하게 항상 수행한다.
|
|
75
75
|
"""
|
|
76
76
|
if os.environ.get("OKSTRA_SKIP_INSTALL_CHECK", "").strip():
|
|
77
77
|
missing = []
|
|
@@ -105,24 +105,34 @@ def cleanup_obsolete_generated_docs(
|
|
|
105
105
|
):
|
|
106
106
|
target = legacy_root / rel
|
|
107
107
|
if target.exists():
|
|
108
|
-
|
|
109
|
-
target.unlink()
|
|
110
|
-
except OSError:
|
|
111
|
-
pass
|
|
108
|
+
_unlink_deprecated(target)
|
|
112
109
|
obsolete = Path(instruction_set_dir) / "okstra-skill.md"
|
|
113
110
|
if obsolete.exists():
|
|
114
|
-
|
|
115
|
-
obsolete.unlink()
|
|
116
|
-
except OSError:
|
|
117
|
-
pass
|
|
111
|
+
_unlink_deprecated(obsolete)
|
|
118
112
|
okstra_dir = legacy_root / "okstra"
|
|
119
113
|
if okstra_dir.is_dir():
|
|
120
114
|
try:
|
|
121
115
|
okstra_dir.rmdir()
|
|
122
116
|
except OSError:
|
|
117
|
+
# expected-miss: 사용자가 이 디렉터리에 자기 파일을 두었으면 비어 있지
|
|
118
|
+
# 않아 rmdir 이 실패한다. 남의 파일을 지우지 않는 것이 맞는 동작이다.
|
|
123
119
|
pass
|
|
124
120
|
|
|
125
121
|
|
|
122
|
+
def _unlink_deprecated(target: Path) -> None:
|
|
123
|
+
"""이미 존재를 확인한 deprecated 파일을 지운다. 실패는 stderr 로 보고한다.
|
|
124
|
+
|
|
125
|
+
존재를 확인하고 부르므로 여기서 나는 OSError 는 권한·I/O 오류다. 조용히 넘기면
|
|
126
|
+
다음 run 이 같은 파일을 또 만나 같은 자리에서 또 실패하는데, 왜 안 지워지는지는
|
|
127
|
+
아무 데도 남지 않는다.
|
|
128
|
+
"""
|
|
129
|
+
try:
|
|
130
|
+
target.unlink()
|
|
131
|
+
except OSError as exc:
|
|
132
|
+
print(f"seeding: cannot remove the deprecated file {target} ({exc})",
|
|
133
|
+
file=sys.stderr)
|
|
134
|
+
|
|
135
|
+
|
|
126
136
|
def installed_settings_template_path() -> Path:
|
|
127
137
|
"""okstra install 이 만들어 둔 settings.local.json template 의 절대경로."""
|
|
128
138
|
return okstra_home() / "templates" / "settings.local.json"
|
|
@@ -20,7 +20,7 @@ def predict_next_run_seq(project_root: Path, task_group: str, task_id: str,
|
|
|
20
20
|
1. reports/ 의 final-report-<task_type>-<seq:03d>.md (완료된 run)
|
|
21
21
|
2. manifests/ 의 run-manifest-<task_type>-<seq:03d>.json (시작했지만 종료 전)
|
|
22
22
|
3. home/active.jsonl 의 같은 (project_id, group, task_id, task_type) row
|
|
23
|
-
(다른
|
|
23
|
+
(다른 prepare 프로세스가 이미 예약한 in-flight run) — home/project_id 가 주어진 경우만
|
|
24
24
|
|
|
25
25
|
이 셋의 max + 1 이 안전한 다음 seq.
|
|
26
26
|
"""
|
|
@@ -27,20 +27,26 @@ def _claude_projects_dir_for(cwd: Path) -> Path:
|
|
|
27
27
|
return Path.home() / ".claude" / "projects" / encoded
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def resolve_inproc_lead_session_id(
|
|
30
|
+
def resolve_inproc_lead_session_id(session_cwd: Path) -> str:
|
|
31
31
|
"""Best-effort detection of the running Claude session's id when okstra is
|
|
32
32
|
invoked render-only from inside a live session (the `okstra-run` skill
|
|
33
33
|
path). The current session's jsonl is being actively written to under
|
|
34
34
|
`~/.claude/projects/<encoded-cwd>/`, so the most recently modified file
|
|
35
35
|
in that directory is, with very high probability, the calling session.
|
|
36
36
|
|
|
37
|
+
인자는 **부르는 세션의 cwd** 다. 대상 프로젝트 루트를 넘기면 안 된다 —
|
|
38
|
+
`okstra preflight --cwd <다른 프로젝트>` 로 프로젝트 B 를 A 의 세션에서 몰 때
|
|
39
|
+
B 의 디렉터리에서 가장 최근 파일을 집으면 남의 세션 id 가 run manifest 에
|
|
40
|
+
박힌다(실측 2026-08-18). 그 id 는 실재하는 파일을 가리키므로 조용히 통과하고,
|
|
41
|
+
Phase 7 에서 리드 토큰과 PROGRESS 증거를 통째로 잃는다.
|
|
42
|
+
|
|
37
43
|
Returns the UUID stem on success, empty string on failure (directory
|
|
38
44
|
missing, no jsonl files, permission error). Callers must treat this as
|
|
39
45
|
best-effort — a failure does not invalidate the session, it just means
|
|
40
46
|
auto-detection could not confirm one.
|
|
41
47
|
"""
|
|
42
48
|
try:
|
|
43
|
-
d = _claude_projects_dir_for(
|
|
49
|
+
d = _claude_projects_dir_for(session_cwd)
|
|
44
50
|
if not d.exists():
|
|
45
51
|
return ""
|
|
46
52
|
candidates = [p for p in d.iterdir() if p.suffix == ".jsonl"]
|
|
@@ -95,24 +101,68 @@ def resolve_lead_session_id_for_run(
|
|
|
95
101
|
경로를 언급하므로 needle 에도 걸린다. 워커가 리드보다 늦게 끝나면 mtime
|
|
96
102
|
정렬에서 먼저 잡혀 워커 세션이 리드로 기록된다 — dispatch 가 발급한 id 를
|
|
97
103
|
호출자가 넘겨 그 세션들을 후보에서 뺀다.
|
|
104
|
+
|
|
105
|
+
프로젝트 디렉터리에서 아무도 안 잡히면 나머지 인코딩 디렉터리까지 넓힌다.
|
|
106
|
+
리드 세션의 cwd 가 대상 프로젝트 루트와 다를 수 있기 때문이다 —
|
|
107
|
+
`okstra preflight --cwd <다른 프로젝트>` 로 프로젝트 B 의 태스크를 A 의
|
|
108
|
+
세션에서 몰 때, transcript 는 A 로 인코딩된 디렉터리에 놓인다. 넓힌 패스는
|
|
109
|
+
run 디렉터리가 생기기 전에 마지막으로 쓰인 파일을 건너뛴다 — 그런 세션은
|
|
110
|
+
아직 존재하지 않던 경로를 언급할 수 없다.
|
|
98
111
|
"""
|
|
99
|
-
proj_dir = _claude_projects_dir_for(project_root)
|
|
100
|
-
try:
|
|
101
|
-
candidates = [p for p in proj_dir.iterdir() if p.suffix == ".jsonl"]
|
|
102
|
-
except OSError:
|
|
103
|
-
return ""
|
|
104
112
|
needle = str(run_dir)
|
|
105
113
|
excluded = set(exclude_session_ids)
|
|
106
|
-
for
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
for candidates in _lead_session_candidate_passes(project_root, run_dir):
|
|
115
|
+
for path in sorted(candidates, key=lambda p: p.stat().st_mtime, reverse=True):
|
|
116
|
+
if path.stem in excluded:
|
|
117
|
+
continue
|
|
118
|
+
if _session_has_agent_name(path):
|
|
119
|
+
continue
|
|
120
|
+
if _session_mentions(path, needle):
|
|
121
|
+
return path.stem
|
|
113
122
|
return ""
|
|
114
123
|
|
|
115
124
|
|
|
125
|
+
def _run_dir_created_at(run_dir: Path) -> float:
|
|
126
|
+
"""run 디렉터리가 생긴 시각. 넓힌 스캔의 하한이다."""
|
|
127
|
+
try:
|
|
128
|
+
st = run_dir.stat()
|
|
129
|
+
except OSError:
|
|
130
|
+
return 0.0
|
|
131
|
+
return float(getattr(st, "st_birthtime", st.st_ctime))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _lead_session_candidate_passes(project_root: Path, run_dir: Path):
|
|
135
|
+
"""후보 파일 묶음을 순서대로 내준다 — 프로젝트 디렉터리, 그다음 나머지.
|
|
136
|
+
|
|
137
|
+
첫 묶음에서 리드가 잡히면 두 번째는 열리지 않는다. 같은 cwd 로 도는 보통의
|
|
138
|
+
런은 예전과 같은 비용으로 끝나고, 넓은 스캔은 지금 통째로 실패하는
|
|
139
|
+
cross-project 런에서만 값을 치른다.
|
|
140
|
+
"""
|
|
141
|
+
proj_dir = _claude_projects_dir_for(project_root)
|
|
142
|
+
try:
|
|
143
|
+
yield [p for p in proj_dir.iterdir() if p.suffix == ".jsonl"]
|
|
144
|
+
except OSError:
|
|
145
|
+
yield []
|
|
146
|
+
floor = _run_dir_created_at(run_dir)
|
|
147
|
+
others: list[Path] = []
|
|
148
|
+
try:
|
|
149
|
+
for entry in proj_dir.parent.iterdir():
|
|
150
|
+
if not entry.is_dir() or entry == proj_dir:
|
|
151
|
+
continue
|
|
152
|
+
for path in entry.iterdir():
|
|
153
|
+
if path.suffix != ".jsonl":
|
|
154
|
+
continue
|
|
155
|
+
try:
|
|
156
|
+
if path.stat().st_mtime < floor:
|
|
157
|
+
continue
|
|
158
|
+
except OSError:
|
|
159
|
+
continue
|
|
160
|
+
others.append(path)
|
|
161
|
+
except OSError:
|
|
162
|
+
return
|
|
163
|
+
yield others
|
|
164
|
+
|
|
165
|
+
|
|
116
166
|
def record_observed_lead_session(project_root: Path, team_state_path: Path) -> str:
|
|
117
167
|
"""이 run 의 live lead 세션을 관측해 team-state 에 append(멱등). 이 run 을
|
|
118
168
|
다룬 lead 세션을 못 찾거나 중복이면 '' 반환. 재발급으로 갈린 세대를 축1 이
|
|
@@ -61,8 +61,26 @@ def _manifest_path(project_root: Path, entry: dict) -> Path:
|
|
|
61
61
|
return task_manifest_file(task_dir(project_root, group_seg, id_seg))
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
_CLI_EPILOG = r"""Usage:
|
|
65
|
+
okstra set-work-status <token> <status> [--note <text>] [--task-group <g>]
|
|
66
|
+
[--project-root <dir>] [--cwd <dir>] [--json]
|
|
67
|
+
|
|
68
|
+
<token> is a full task-key (<project-id>:<task-group>:<task-id>) or a bare
|
|
69
|
+
task-id. <status> is one of: todo | in-progress | blocked | done.
|
|
70
|
+
|
|
71
|
+
Updates workStatus + workStatusUpdatedAt in task-manifest.json (workStatusNote
|
|
72
|
+
only when --note is passed) using the same JSON serialization as the manifest
|
|
73
|
+
renderer. Output: JSON { ok, taskKey, previousWorkStatus, workStatus, ... };
|
|
74
|
+
ok:false stages: resolve | catalog | not-found | ambiguous (pick from
|
|
75
|
+
matches[]) | manifest-missing | manifest-invalid.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
|
|
64
79
|
def _parse_args(argv: list[str] | None):
|
|
65
80
|
parser = argparse.ArgumentParser(
|
|
81
|
+
prog="okstra set-work-status",
|
|
82
|
+
epilog=_CLI_EPILOG,
|
|
83
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
66
84
|
description="Set a task's user-managed workStatus in task-manifest.json."
|
|
67
85
|
)
|
|
68
86
|
parser.add_argument(
|
|
@@ -187,6 +187,16 @@ def _teardown_stage(project_id, task_group, task_id, task_wt, stage_n, row):
|
|
|
187
187
|
return ("torn_down", "")
|
|
188
188
|
|
|
189
189
|
|
|
190
|
+
_CLI_EPILOG = r"""Usage:
|
|
191
|
+
okstra integrate-stages --project-id <id> \
|
|
192
|
+
--task-group <g> --task-id <t> --plan-run-root <dir> \
|
|
193
|
+
--task-worktree-path <dir> [--stage-map-json '<json>']
|
|
194
|
+
|
|
195
|
+
Exit codes: 0 ok / 2 stage 간 merge 충돌 / 1 python 프로세스 비정상 종료(폴백)
|
|
196
|
+
"""
|
|
197
|
+
_CLI_DESCRIPTION = "Stage \ub4e4\uc744 task \ube0c\ub79c\uce58\uc5d0 \ud1b5\ud569 \uba38\uc9c0 + worktree \uc815\ub9ac."
|
|
198
|
+
|
|
199
|
+
|
|
190
200
|
def main(argv: list[str] | None = None) -> int:
|
|
191
201
|
import argparse
|
|
192
202
|
import json
|
|
@@ -194,7 +204,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
194
204
|
|
|
195
205
|
from .consumers import read_consumers
|
|
196
206
|
|
|
197
|
-
p = argparse.ArgumentParser(
|
|
207
|
+
p = argparse.ArgumentParser(
|
|
208
|
+
description=_CLI_DESCRIPTION,
|
|
209
|
+
epilog=_CLI_EPILOG,
|
|
210
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
211
|
+
prog="okstra integrate-stages")
|
|
198
212
|
p.add_argument("--project-id", required=True)
|
|
199
213
|
p.add_argument("--task-group", required=True)
|
|
200
214
|
p.add_argument("--task-id", required=True)
|
|
@@ -30,7 +30,7 @@ from .stage_map import (
|
|
|
30
30
|
load_task_stage_map,
|
|
31
31
|
)
|
|
32
32
|
from .stage_targets import stage_lifecycle_snapshot_from_state
|
|
33
|
-
from .
|
|
33
|
+
from .paths import infer_project_root
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def build_stage_ledger(task_root: Path) -> dict[str, Any] | None:
|
|
@@ -13,7 +13,7 @@ from .fixed_text import line, value_lines
|
|
|
13
13
|
from .md_table import is_separator_row, split_pipe_row
|
|
14
14
|
from .paths import RunRef
|
|
15
15
|
from .plan_run_root import list_implementation_planning_reports
|
|
16
|
-
from .
|
|
16
|
+
from .paths import infer_project_root
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
STAGE_MAP_HEADING = re.compile(r"^##\s+5\.5\s+Stage\s+Map\b", re.MULTILINE)
|
|
@@ -506,22 +506,63 @@ def load_task_stage_map(
|
|
|
506
506
|
) -> StageMapSnapshot:
|
|
507
507
|
"""완료된 stage 를 무엇으로 지었는지 답하는 Stage Map.
|
|
508
508
|
|
|
509
|
-
carry 사이드카가 가리키는 계획을
|
|
510
|
-
문서이기 때문이다. "어떤 stage
|
|
511
|
-
|
|
509
|
+
carry 사이드카가 가리키는 계획을 읽는다 — 그게 실행이 실제로 따른
|
|
510
|
+
문서이기 때문이다. 오직 그 질문에만 답한다. "어떤 stage 가 존재하나" 와
|
|
511
|
+
"어떤 번호가 이미 쓰였나" 는 최신 계획이 답하며, 그쪽을 물어야 하는
|
|
512
|
+
소비자는 `load_latest_plan_stage_map` 을 쓴다 — 계획을 고친 task 에서
|
|
513
|
+
carry 소스는 새로 붙은 stage 를 아직 모른다.
|
|
512
514
|
"""
|
|
513
515
|
carried = _unique_carry_source_paths(task_root)
|
|
514
516
|
if len(carried) > 1:
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
"implementation carries reference different source plans",
|
|
519
|
-
conflicting_paths=paths,
|
|
520
|
-
)
|
|
521
|
-
source = carried[0] if carried else _latest_plan_report(task_root)
|
|
517
|
+
source: Path | None = _reconcile_carried_sources(carried)
|
|
518
|
+
else:
|
|
519
|
+
source = carried[0] if carried else _latest_plan_report(task_root)
|
|
522
520
|
return _snapshot_for(source)
|
|
523
521
|
|
|
524
522
|
|
|
523
|
+
def _reconcile_carried_sources(carried: list[Path]) -> Path:
|
|
524
|
+
"""서로 다른 계획을 가리키는 carry 들을 하나로 접는다.
|
|
525
|
+
|
|
526
|
+
ADR-0016 은 계획 수정의 산출물을 새 planning 리포트로 정한다. 그래서 수정을
|
|
527
|
+
한 번이라도 거친 task 에서는 carry 들이 서로 다른 계획을 가리키는 것이
|
|
528
|
+
정상이다 — 먼저 끝난 stage 는 그때의 계획을, 그 뒤 stage 는 새 계획을
|
|
529
|
+
적는다. 이 모양을 무조건 충돌로 올리면 계획을 수정한 모든 task 가 Stage Map
|
|
530
|
+
을 영구히 잃는다.
|
|
531
|
+
|
|
532
|
+
ADR-0015 의 append-only 가 지켜졌다면 두 계획은 공유하는 번호에서 같은
|
|
533
|
+
작업을 가리킨다. 그 조건을 실제로 확인한 뒤에만 가장 긴 계획을 답으로 쓴다
|
|
534
|
+
— 확인 없이 하나를 고르면 번호 재배치가 조용히 통과하고 완료 커밋이 엉뚱한
|
|
535
|
+
stage 에 귀속된다.
|
|
536
|
+
"""
|
|
537
|
+
titles = {
|
|
538
|
+
path: {
|
|
539
|
+
record["stage_number"]: record["title"]
|
|
540
|
+
for record in stage_map_records(parse_stage_map_file(path))
|
|
541
|
+
}
|
|
542
|
+
for path in carried
|
|
543
|
+
}
|
|
544
|
+
conflicts = tuple(str(path) for path in carried)
|
|
545
|
+
for index, left in enumerate(carried):
|
|
546
|
+
for right in carried[index + 1:]:
|
|
547
|
+
renamed = [
|
|
548
|
+
number
|
|
549
|
+
for number in sorted(set(titles[left]) & set(titles[right]))
|
|
550
|
+
if titles[left][number] != titles[right][number]
|
|
551
|
+
]
|
|
552
|
+
if renamed:
|
|
553
|
+
raise StageMapError(
|
|
554
|
+
"plan-source-conflict",
|
|
555
|
+
"implementation carries reference plans that name different "
|
|
556
|
+
"work under the same stage number: "
|
|
557
|
+
+ ", ".join(f"stage {number}" for number in renamed),
|
|
558
|
+
conflicting_paths=conflicts,
|
|
559
|
+
)
|
|
560
|
+
# `_validate_stage_numbers` 가 stage 번호를 `1..N` 단조로 강제하므로 계획의
|
|
561
|
+
# 번호 집합은 언제나 앞이 막힌 구간이다. 그래서 가장 긴 계획이 나머지의
|
|
562
|
+
# superset 인 것은 따로 검사할 명제가 아니라 파서가 이미 보장하는 사실이다.
|
|
563
|
+
return max(carried, key=lambda path: len(titles[path]))
|
|
564
|
+
|
|
565
|
+
|
|
525
566
|
def load_latest_plan_stage_map(task_root: Path) -> StageMapSnapshot:
|
|
526
567
|
"""이 task 의 최신 계획 리포트가 선언한 Stage Map.
|
|
527
568
|
|
|
@@ -579,3 +620,8 @@ def _resolve_plan_path(task_root: Path, value: str) -> Path:
|
|
|
579
620
|
if task_relative.exists():
|
|
580
621
|
return task_relative
|
|
581
622
|
return project_relative
|
|
623
|
+
|
|
624
|
+
# ---- read-side view -------------------------------------------------------
|
|
625
|
+
# 예전에는 okstra_project.state 가 이 어댑터를 들고 okstra_ctl 을 함수 본문에서
|
|
626
|
+
# 지연 import 했다. 하위 계층이 상위를 되짚는 배치였다. 읽는 대상이 okstra_ctl 의
|
|
627
|
+
# Stage Map 과 consumer 상태이므로 소유자를 여기로 옮긴다.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""`okstra stage-map` 의 프로젝션 — 한 task 의 구현 계획 Stage Map 과 완료 stage.
|
|
2
|
+
|
|
3
|
+
원래 `src/commands/inspect/stage-map.mts` 의 문자열 리터럴 안에 있던 코드다
|
|
4
|
+
(docs/coding-rules.md R1 위반). 로직은 그대로 옮겼다.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from okstra_project import ResolverError, StateError, resolve_project_root
|
|
13
|
+
|
|
14
|
+
from .stage_map import render_stage_map_text
|
|
15
|
+
from .stage_map_view import stage_map_read_side_snapshot
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def emit(payload: dict, output_mode: str) -> None:
|
|
19
|
+
if output_mode == "text":
|
|
20
|
+
print(render_stage_map_text(payload))
|
|
21
|
+
else:
|
|
22
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_CLI_EPILOG = r"""Usage:
|
|
26
|
+
okstra stage-map <task-key> task-key is project-id:task-group:task-id
|
|
27
|
+
okstra stage-map <task-key> --cwd <dir> Resolve PROJECT_ROOT from <dir>
|
|
28
|
+
okstra stage-map <task-key> --project <dir> Use <dir> directly as PROJECT_ROOT
|
|
29
|
+
okstra stage-map <task-key> --text Emit fixed text fields for model use
|
|
30
|
+
|
|
31
|
+
Output: default and --json emit JSON { ok, taskKey, taskRoot, state, sourcePlanPath,
|
|
32
|
+
stages:[…], doneStages:[int], planning:{…} }; --text emits fixed count/name/value fields.
|
|
33
|
+
Each stage row carries stage_number, title, depends_on, step_count and exit_contract_summary; a
|
|
34
|
+
schema-v2 report adds that stage's sliceValue, acceptance and exitContract.
|
|
35
|
+
planning carries the report's task-level rows — rollbackStrategy, validationChecklist,
|
|
36
|
+
crossProjectDependencies, dependencyMigrationRisk, recommendedOption — so a consumer renders the
|
|
37
|
+
plan instead of re-summarising the report body. Both are absent for a schema-v1 report.
|
|
38
|
+
stages is [] when no implementation-planning Stage Map exists.
|
|
39
|
+
"""
|
|
40
|
+
_CLI_DESCRIPTION = "Dump a task's implementation-planning Stage Map + done stages."
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main(argv: list[str] | None = None) -> int:
|
|
44
|
+
parser = argparse.ArgumentParser(
|
|
45
|
+
description=_CLI_DESCRIPTION,
|
|
46
|
+
epilog=_CLI_EPILOG,
|
|
47
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
48
|
+
prog="okstra stage-map")
|
|
49
|
+
parser.add_argument("task_key", metavar="task-key",
|
|
50
|
+
help="project-id:task-group:task-id")
|
|
51
|
+
parser.add_argument("--project-root", "--project", default="",
|
|
52
|
+
help="use this directory as PROJECT_ROOT")
|
|
53
|
+
parser.add_argument("--cwd", default=".",
|
|
54
|
+
help="resolve PROJECT_ROOT starting from here")
|
|
55
|
+
mode = parser.add_mutually_exclusive_group()
|
|
56
|
+
mode.add_argument("--json", dest="output_mode", action="store_const",
|
|
57
|
+
const="json", default="json", help="emit JSON (default)")
|
|
58
|
+
mode.add_argument("--text", dest="output_mode", action="store_const",
|
|
59
|
+
const="text", help="emit fixed text fields")
|
|
60
|
+
args = parser.parse_args(argv)
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
resolved = resolve_project_root(explicit_root=args.project_root, cwd=args.cwd)
|
|
64
|
+
except ResolverError as exc:
|
|
65
|
+
emit({"ok": False, "stage": "resolve", "reason": str(exc)}, args.output_mode)
|
|
66
|
+
return 2
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
snapshot = stage_map_read_side_snapshot(Path(resolved), args.task_key)
|
|
70
|
+
except StateError as exc:
|
|
71
|
+
emit({
|
|
72
|
+
"ok": False,
|
|
73
|
+
"stage": getattr(exc, "stage", None) or "stage_map",
|
|
74
|
+
"reason": str(exc),
|
|
75
|
+
}, args.output_mode)
|
|
76
|
+
return 1
|
|
77
|
+
|
|
78
|
+
emit({"ok": True, **snapshot}, args.output_mode)
|
|
79
|
+
return 0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""stage-map inspect 용 read-side view.
|
|
2
|
+
|
|
3
|
+
Stage Map(okstra_ctl) 과 task identity(okstra_project) 를 한 자리에서 합친다.
|
|
4
|
+
전에는 이 함수가 okstra_project.state 안에 있었다 — 하위 계층이 okstra_ctl 을
|
|
5
|
+
함수 본문에서 지연 import 하는 배치였다. 그렇다고 stage_map 으로 옮기면
|
|
6
|
+
stage_map 이 okstra_project 를 끌어오고, okstra_project.state 가 다시
|
|
7
|
+
implementation_outcome → stage_map 으로 돌아와 순환이 된다.
|
|
8
|
+
|
|
9
|
+
그래서 소비자 쪽 얇은 조립 모듈을 따로 둔다. 이 모듈은 아무도 import 하지
|
|
10
|
+
않으므로 어느 순환에도 들어갈 수 없다. 소비자는 `okstra stage-map` 하나다.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from okstra_project import StateError, resolve_task_identity
|
|
17
|
+
|
|
18
|
+
from .consumers import read_stage_consumer_state
|
|
19
|
+
from .paths import RunRef
|
|
20
|
+
from .stage_map import (
|
|
21
|
+
PlanningDetail,
|
|
22
|
+
StageMapError,
|
|
23
|
+
load_latest_plan_stage_map,
|
|
24
|
+
load_planning_detail,
|
|
25
|
+
merge_planning_detail,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def stage_map_read_side_snapshot(project_root: Path, task_key: str) -> dict:
|
|
30
|
+
"""stage-map inspect 용 read-side view: Stage Map + done 처리된 stage 번호.
|
|
31
|
+
|
|
32
|
+
Stage Map 파싱과 planning run-root 위치를 caller 에게 노출하지 않는다 —
|
|
33
|
+
Node inspect 가 okstra_ctl 의 private 심볼을 import 하거나 `runs/` 경로를
|
|
34
|
+
직접 조립하지 않도록 하는 어댑터다.
|
|
35
|
+
"""
|
|
36
|
+
identity = resolve_task_identity(project_root, task_key)
|
|
37
|
+
task_root = Path(identity["taskRoot"])
|
|
38
|
+
try:
|
|
39
|
+
stage_snapshot = load_latest_plan_stage_map(task_root)
|
|
40
|
+
detail = (
|
|
41
|
+
load_planning_detail(Path(stage_snapshot.source_plan_path))
|
|
42
|
+
if stage_snapshot.source_plan_path
|
|
43
|
+
else PlanningDetail({}, {})
|
|
44
|
+
)
|
|
45
|
+
except StageMapError as exc:
|
|
46
|
+
raise StateError(str(exc), stage=exc.code) from exc
|
|
47
|
+
plan_run_root = RunRef.from_task_root(
|
|
48
|
+
task_root, "implementation-planning"
|
|
49
|
+
).run_dir
|
|
50
|
+
done: list[int] = []
|
|
51
|
+
if plan_run_root.is_dir():
|
|
52
|
+
done = sorted(
|
|
53
|
+
read_stage_consumer_state(
|
|
54
|
+
plan_run_root, recover_from_carry=True
|
|
55
|
+
).done_stages
|
|
56
|
+
)
|
|
57
|
+
return {
|
|
58
|
+
"taskKey": identity["taskKey"],
|
|
59
|
+
"taskRoot": identity["taskRoot"],
|
|
60
|
+
"state": stage_snapshot.state,
|
|
61
|
+
"sourcePlanPath": stage_snapshot.source_plan_path,
|
|
62
|
+
"stages": merge_planning_detail(stage_snapshot.stages, detail),
|
|
63
|
+
"doneStages": done,
|
|
64
|
+
"planning": detail.task_narratives,
|
|
65
|
+
}
|
|
@@ -14,7 +14,10 @@ from dataclasses import dataclass, replace
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any
|
|
16
16
|
|
|
17
|
+
from .plan_run_root import plan_run_root_from_approved_plan
|
|
18
|
+
from .prepare_error import PrepareError # noqa: F401 — 재노출(단일 참조점)
|
|
17
19
|
from .stage_integrate import IntegrateResult
|
|
20
|
+
from okstra_project.slug import slugify
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
RUN_STEP_BUDGET = 8
|
|
@@ -24,14 +27,6 @@ class StageTargetError(Exception):
|
|
|
24
27
|
"""Stage target selection or verification precondition failed."""
|
|
25
28
|
|
|
26
29
|
|
|
27
|
-
class PrepareError(Exception):
|
|
28
|
-
"""surface to caller — task bundle prepare failed.
|
|
29
|
-
|
|
30
|
-
Defined here(저수준 모듈)so both run.py(final-verification)와
|
|
31
|
-
container.py 가 whole-task 통합 헬퍼의 실패를 동일 타입으로 받을 수 있다.
|
|
32
|
-
run.py 는 이 클래스를 그대로 재노출한다(단일 참조점)."""
|
|
33
|
-
|
|
34
|
-
|
|
35
30
|
@dataclass
|
|
36
31
|
class FinalVerificationTarget:
|
|
37
32
|
scope: str # "whole-task" | "single-stage"
|
|
@@ -671,7 +666,6 @@ def resolve_and_integrate_whole_task(
|
|
|
671
666
|
) -> dict[str, Any]:
|
|
672
667
|
"""Locked whole-task integration interface shared with the container."""
|
|
673
668
|
from okstra_project.dirs import okstra_home
|
|
674
|
-
from okstra_project.state import slugify
|
|
675
669
|
|
|
676
670
|
from .locks import worktree_provision_mutex
|
|
677
671
|
|
|
@@ -734,7 +728,6 @@ def _read_final_verification_done_rows(
|
|
|
734
728
|
registry_coordinates: tuple[str, str, str],
|
|
735
729
|
) -> list[dict[str, Any]]:
|
|
736
730
|
from .consumers import backfill_done_from_carry, read_stage_consumer_state
|
|
737
|
-
from .plan_run_root import plan_run_root_from_approved_plan
|
|
738
731
|
from .stage_reconcile import auto_reconcile_best_effort
|
|
739
732
|
|
|
740
733
|
plan_run_root = plan_run_root_from_approved_plan(request.approved_plan_path)
|
|
@@ -755,7 +748,6 @@ def _read_final_verification_done_rows(
|
|
|
755
748
|
def _final_verification_registry_coordinates(
|
|
756
749
|
request: FinalVerificationTargetRequest,
|
|
757
750
|
) -> tuple[str, str, str]:
|
|
758
|
-
from okstra_project.state import slugify
|
|
759
751
|
|
|
760
752
|
def segment(value: str) -> str:
|
|
761
753
|
return slugify(value) or "_"
|
|
@@ -913,7 +905,6 @@ def acquire_final_verification_target(
|
|
|
913
905
|
) -> FinalVerificationTargetAcquisition:
|
|
914
906
|
"""Acquire a stable final-verification target behind one task-key lock."""
|
|
915
907
|
from okstra_project.dirs import okstra_home
|
|
916
|
-
from okstra_project.state import slugify
|
|
917
908
|
|
|
918
909
|
from .locks import worktree_provision_mutex
|
|
919
910
|
|