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
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""메인 체크아웃의 공유 상태를 새 worktree 안에 재현한다.
|
|
2
|
+
|
|
3
|
+
`sync_config` 가 고른 목록을 실제로 심링크(또는 스냅샷 복사)하는 층이다. 방식이
|
|
4
|
+
세 가지이고 이유가 각각 다르다 — 디렉터리 통째 심링크는 새로 생기는 최상위
|
|
5
|
+
항목이 메인으로 가게 하고, 자식별 심링크는 git 이 심링크된 디렉터리를 파일
|
|
6
|
+
하나로 보는 탓에 `.claude` 가 `?? .claude` 로 뜨는 것을 막으며, 스냅샷 복사는
|
|
7
|
+
쓰기 핸들을 공유하지 않으려는 픽스처용이다.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import shutil
|
|
13
|
+
import stat
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from ..seeding import (
|
|
17
|
+
SettingsLinkError,
|
|
18
|
+
ensure_project_settings_symlink,
|
|
19
|
+
)
|
|
20
|
+
from .sync_config import (
|
|
21
|
+
CHILD_LINKED_SYNC_DIRS,
|
|
22
|
+
_resolve_snapshot_files,
|
|
23
|
+
_resolve_sync_dirs,
|
|
24
|
+
_resolve_sync_files,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _link_sync_dirs(source_root: Path, worktree_path: Path) -> list[str]:
|
|
29
|
+
"""Symlink each configured dir from `source_root` (the MAIN
|
|
30
|
+
worktree) into the new worktree.
|
|
31
|
+
|
|
32
|
+
Skip rules:
|
|
33
|
+
- Source missing in `source_root` → silently skipped.
|
|
34
|
+
- Target path already exists in worktree (e.g. tracked content
|
|
35
|
+
checked out by `git worktree add`) → skipped to avoid clobbering
|
|
36
|
+
version-controlled files.
|
|
37
|
+
- Parent directories are created as needed for nested entries.
|
|
38
|
+
|
|
39
|
+
Entries listed in `CHILD_LINKED_SYNC_DIRS` are materialised as a real
|
|
40
|
+
directory of per-child symlinks instead (see that constant).
|
|
41
|
+
|
|
42
|
+
Returns a list of human-readable notes (one per linked entry) so the
|
|
43
|
+
caller can include them in the provisioning note.
|
|
44
|
+
"""
|
|
45
|
+
notes: list[str] = []
|
|
46
|
+
for rel in _resolve_sync_dirs(source_root):
|
|
47
|
+
src = (source_root / rel).resolve()
|
|
48
|
+
if not src.exists():
|
|
49
|
+
continue
|
|
50
|
+
dst = worktree_path / rel
|
|
51
|
+
if dst.exists() or dst.is_symlink():
|
|
52
|
+
continue
|
|
53
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
54
|
+
if rel in CHILD_LINKED_SYNC_DIRS and src.is_dir():
|
|
55
|
+
_link_dir_children(src, dst)
|
|
56
|
+
notes.append(rel)
|
|
57
|
+
continue
|
|
58
|
+
try:
|
|
59
|
+
os.symlink(src, dst)
|
|
60
|
+
except FileExistsError:
|
|
61
|
+
continue
|
|
62
|
+
notes.append(rel)
|
|
63
|
+
return notes
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _link_dir_children(src: Path, dst: Path) -> None:
|
|
67
|
+
"""Create `dst` as a real directory whose entries symlink to `src`'s
|
|
68
|
+
children, so git sees the same directory shape it sees in the main
|
|
69
|
+
checkout (`CHILD_LINKED_SYNC_DIRS`).
|
|
70
|
+
|
|
71
|
+
Each link points at the MAIN checkout's child rather than its resolved
|
|
72
|
+
target, so a child that is itself a symlink (e.g. `.claude/settings.local.json`
|
|
73
|
+
→ `~/.okstra/templates/settings.local.json`) keeps following whatever the
|
|
74
|
+
main checkout currently points at. An unreadable source or a child that
|
|
75
|
+
cannot be linked degrades to "that child is absent in this worktree" —
|
|
76
|
+
provisioning is not worth failing over host config.
|
|
77
|
+
"""
|
|
78
|
+
dst.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
try:
|
|
80
|
+
children = sorted(src.iterdir())
|
|
81
|
+
except OSError:
|
|
82
|
+
return
|
|
83
|
+
for child in children:
|
|
84
|
+
link = dst / child.name
|
|
85
|
+
if link.exists() or link.is_symlink():
|
|
86
|
+
continue
|
|
87
|
+
try:
|
|
88
|
+
os.symlink(child, link)
|
|
89
|
+
except OSError:
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _link_sync_files(source_root: Path, worktree_path: Path) -> list[str]:
|
|
94
|
+
"""File-level counterpart to `_link_sync_dirs` (FU-V2).
|
|
95
|
+
|
|
96
|
+
Same skip rules: missing source → skipped silently; pre-existing dst
|
|
97
|
+
(tracked content checked out by `git worktree add`) → skipped to avoid
|
|
98
|
+
clobbering. Symlinks (not copies) keep secrets out of duplicate files —
|
|
99
|
+
the link points back to the MAIN worktree's `.env` so rotating the file
|
|
100
|
+
there is reflected in every active task without re-provisioning.
|
|
101
|
+
"""
|
|
102
|
+
notes: list[str] = []
|
|
103
|
+
for rel in _resolve_sync_files(source_root):
|
|
104
|
+
src = (source_root / rel).resolve()
|
|
105
|
+
if not src.exists() or not src.is_file():
|
|
106
|
+
continue
|
|
107
|
+
dst = worktree_path / rel
|
|
108
|
+
if dst.exists() or dst.is_symlink():
|
|
109
|
+
continue
|
|
110
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
try:
|
|
112
|
+
os.symlink(src, dst)
|
|
113
|
+
except FileExistsError:
|
|
114
|
+
continue
|
|
115
|
+
notes.append(rel)
|
|
116
|
+
return notes
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def sync_file_key_names(source_root: Path) -> dict[str, list[str]]:
|
|
120
|
+
"""공유되는 sync 파일마다 그 안의 **키 이름**만 모은다 (값은 절대 읽지 않는다).
|
|
121
|
+
|
|
122
|
+
`.env` 는 gitignore 대상이라 브랜치에 속하지 않고, `_link_sync_files` 가 메인
|
|
123
|
+
체크아웃의 것을 각 worktree 에 심링크로 건다. 값 회전은 그 설계가 노린 것이지만
|
|
124
|
+
**키 이름 변경**은 아직 옛 이름을 읽는 모든 브랜치를 한꺼번에 깨뜨린다 — 코드는
|
|
125
|
+
브랜치별로 격리되지만 `.env` 는 격리되지 않기 때문이다. 그 사고를 알아보려면
|
|
126
|
+
프로비저닝 시점의 이름 집합을 남겨야 한다.
|
|
127
|
+
|
|
128
|
+
`KEY=` 꼴이 아닌 파일은 빈 목록이 되어 드리프트 판정에서 자연히 빠진다 —
|
|
129
|
+
sync 파일 목록은 프로젝트가 바꿀 수 있으므로 `.env` 형식을 전제하지 않는다.
|
|
130
|
+
"""
|
|
131
|
+
keys: dict[str, list[str]] = {}
|
|
132
|
+
for rel in _resolve_sync_files(source_root):
|
|
133
|
+
src = (source_root / rel).resolve()
|
|
134
|
+
if not src.is_file():
|
|
135
|
+
continue
|
|
136
|
+
try:
|
|
137
|
+
text = src.read_text(encoding="utf-8")
|
|
138
|
+
except (OSError, UnicodeDecodeError):
|
|
139
|
+
continue
|
|
140
|
+
found = []
|
|
141
|
+
for line in text.splitlines():
|
|
142
|
+
stripped = line.strip().removeprefix("export ").lstrip()
|
|
143
|
+
if not stripped or stripped.startswith("#"):
|
|
144
|
+
continue
|
|
145
|
+
name, separator, _ = stripped.partition("=")
|
|
146
|
+
name = name.strip()
|
|
147
|
+
if separator and name and all(
|
|
148
|
+
ch.isalnum() or ch == "_" for ch in name
|
|
149
|
+
):
|
|
150
|
+
found.append(name)
|
|
151
|
+
keys[rel] = sorted(set(found))
|
|
152
|
+
return keys
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def describe_sync_key_drift(
|
|
156
|
+
recorded: object, current: dict[str, list[str]]
|
|
157
|
+
) -> str:
|
|
158
|
+
"""프로비저닝 때 기록한 키 이름 집합과 지금을 대조해 한 줄로 알린다.
|
|
159
|
+
|
|
160
|
+
기록이 없으면(그 전에 만들어진 worktree) 빈 문자열 — 알 수 없는 것을 사고로
|
|
161
|
+
보고하지 않는다. 차단이 아니라 알림인 이유는 키 추가가 정상 작업이기 때문이다.
|
|
162
|
+
"""
|
|
163
|
+
if not isinstance(recorded, dict):
|
|
164
|
+
return ""
|
|
165
|
+
parts: list[str] = []
|
|
166
|
+
for rel in sorted(set(recorded) | set(current)):
|
|
167
|
+
before = set(recorded.get(rel) or [])
|
|
168
|
+
after = set(current.get(rel) or [])
|
|
169
|
+
removed = sorted(before - after)
|
|
170
|
+
added = sorted(after - before)
|
|
171
|
+
if not removed and not added:
|
|
172
|
+
continue
|
|
173
|
+
detail = []
|
|
174
|
+
if removed:
|
|
175
|
+
detail.append(f"gone: {', '.join(removed)}")
|
|
176
|
+
if added:
|
|
177
|
+
detail.append(f"new: {', '.join(added)}")
|
|
178
|
+
parts.append(f"{rel} ({'; '.join(detail)})")
|
|
179
|
+
if not parts:
|
|
180
|
+
return ""
|
|
181
|
+
return (
|
|
182
|
+
"shared-env drift — " + "; ".join(parts) + ". This file is symlinked "
|
|
183
|
+
"from the main checkout into every task worktree, so a renamed key "
|
|
184
|
+
"breaks every branch still reading the old name at once, and it shows "
|
|
185
|
+
"up as verifier sessions failing to boot while the executor passes. "
|
|
186
|
+
"Key names only; values are never recorded."
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _seed_worktree_settings_symlink(worktree_path: Path) -> None:
|
|
191
|
+
"""Seed `.claude/settings.local.json` in the worker worktree so dispatched
|
|
192
|
+
Claude / codex / antigravity sessions inherit the okstra read-only / write
|
|
193
|
+
allowlist. Mirrors the main-project seeding done in `run.py` — needed
|
|
194
|
+
because `_link_sync_dirs` skips `.claude/` whenever `git worktree add`
|
|
195
|
+
already materialised the directory (e.g. tracked `.claude/handoff-*.md`).
|
|
196
|
+
Failures degrade to stderr warning so worktree provisioning still
|
|
197
|
+
succeeds.
|
|
198
|
+
"""
|
|
199
|
+
try:
|
|
200
|
+
link = ensure_project_settings_symlink(project_root=worktree_path)
|
|
201
|
+
except SettingsLinkError as exc:
|
|
202
|
+
print(
|
|
203
|
+
f"okstra-settings: failed to seed worker worktree symlink at "
|
|
204
|
+
f"{worktree_path / '.claude/settings.local.json'} — worker dispatch "
|
|
205
|
+
f"may be blocked by Claude Code permissions. ({exc})",
|
|
206
|
+
file=__import__("sys").stderr,
|
|
207
|
+
)
|
|
208
|
+
return
|
|
209
|
+
if link is None:
|
|
210
|
+
print(
|
|
211
|
+
"okstra-settings: ~/.okstra/templates/settings.local.json missing — "
|
|
212
|
+
"re-run 'npx okstra@latest install' (0.14.0+) to provision the "
|
|
213
|
+
"symlink target.",
|
|
214
|
+
file=__import__("sys").stderr,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _copy_snapshot_files(source_root: Path, worktree_path: Path) -> list[str]:
|
|
219
|
+
"""Copy fixture files from MAIN → task worktree as read-only snapshots
|
|
220
|
+
(FU-V3).
|
|
221
|
+
|
|
222
|
+
Unlike `_link_sync_files`, this materialises a fresh on-disk copy and
|
|
223
|
+
chmods it to `0o444` so the verifier can read the same rows the
|
|
224
|
+
executor saw without sharing a writable handle that would corrupt the
|
|
225
|
+
main worktree's copy. Skip rules mirror the symlink helpers (missing
|
|
226
|
+
source → skipped silently; pre-existing dst → skipped to avoid
|
|
227
|
+
clobbering tracked content).
|
|
228
|
+
"""
|
|
229
|
+
notes: list[str] = []
|
|
230
|
+
for rel in _resolve_snapshot_files(source_root):
|
|
231
|
+
src = (source_root / rel).resolve()
|
|
232
|
+
if not src.exists() or not src.is_file():
|
|
233
|
+
continue
|
|
234
|
+
dst = worktree_path / rel
|
|
235
|
+
if dst.exists() or dst.is_symlink():
|
|
236
|
+
continue
|
|
237
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
238
|
+
shutil.copy2(src, dst)
|
|
239
|
+
try:
|
|
240
|
+
os.chmod(dst, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
|
|
241
|
+
except OSError:
|
|
242
|
+
# chmod failure (exotic filesystems, root-squashed mounts) does
|
|
243
|
+
# not invalidate the snapshot itself — it just means the read-
|
|
244
|
+
# only contract is best-effort. Surface in notes so the operator
|
|
245
|
+
# can audit if a verifier later mutates the file.
|
|
246
|
+
notes.append(f"{rel} (rw-fallback)")
|
|
247
|
+
continue
|
|
248
|
+
notes.append(rel)
|
|
249
|
+
return notes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""task-key 를 worktree 경로와 브랜치 이름으로 옮긴다.
|
|
2
|
+
|
|
3
|
+
경로도 브랜치도 파일 시스템과 git 참조 양쪽에서 안전한 문자만 남겨야 하고,
|
|
4
|
+
브랜치는 work-category 별 namespace 아래로 들어간다. 순수 문자열 계산이라
|
|
5
|
+
디스크도 git 도 보지 않는다 — 그래서 provision 전에 미리 보여 줄 수 있다.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from okstra_project.dirs import okstra_home
|
|
12
|
+
|
|
13
|
+
from ..ids import _safe_fs_segment
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Work-category → branch namespace (slash-prefixed). Mirrors the values
|
|
17
|
+
# accepted by `--work-category` (bugfix / feature / refactor / ops /
|
|
18
|
+
# improvement); `feature` and `improvement` share the `feature/` namespace,
|
|
19
|
+
# and any unset/unrecognised category falls back to `task/`.
|
|
20
|
+
_WORK_CATEGORY_NAMESPACE = {
|
|
21
|
+
"feature": "feature",
|
|
22
|
+
"improvement": "feature",
|
|
23
|
+
"bugfix": "fix",
|
|
24
|
+
"refactor": "refactor",
|
|
25
|
+
"ops": "ops",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _safe_segment(value: str) -> str:
|
|
30
|
+
"""Sanitise a single path/branch segment.
|
|
31
|
+
|
|
32
|
+
Forbidden chars (`/`, `:`, spaces, anything outside `[a-z0-9-]`)
|
|
33
|
+
are collapsed to `-`. Empty result becomes `_` so we never create
|
|
34
|
+
an empty path component. Delegates to the canonical slugifier in
|
|
35
|
+
`ids.py` to stay in lock-step with run-id / manifest segmentation.
|
|
36
|
+
"""
|
|
37
|
+
return _safe_fs_segment(value)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _work_category_namespace(work_category: str) -> str:
|
|
41
|
+
key = (work_category or "").strip().lower()
|
|
42
|
+
return _WORK_CATEGORY_NAMESPACE.get(key, "task")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def compute_worktree_path(
|
|
46
|
+
*,
|
|
47
|
+
project_id: str,
|
|
48
|
+
task_group_segment: str,
|
|
49
|
+
task_id_segment: str,
|
|
50
|
+
stage_number: Optional[int] = None,
|
|
51
|
+
group_id: Optional[str] = None,
|
|
52
|
+
) -> Path:
|
|
53
|
+
"""Pure path computation. One worktree dir per task-key, or per
|
|
54
|
+
`<task-key>/stage-<N>` when stage_number is given (implementation
|
|
55
|
+
stage isolation). Uses `OKSTRA_HOME` when set (test hook), else
|
|
56
|
+
`~/.okstra`."""
|
|
57
|
+
if stage_number is not None and group_id is not None:
|
|
58
|
+
raise ValueError("stage_number and group_id are mutually exclusive")
|
|
59
|
+
base = okstra_home()
|
|
60
|
+
path = (
|
|
61
|
+
base / "worktrees"
|
|
62
|
+
/ _safe_segment(project_id)
|
|
63
|
+
/ _safe_segment(task_group_segment)
|
|
64
|
+
/ _safe_segment(task_id_segment)
|
|
65
|
+
)
|
|
66
|
+
if stage_number is not None:
|
|
67
|
+
path = path / f"stage-{stage_number}"
|
|
68
|
+
if group_id is not None:
|
|
69
|
+
path = path / f"group-{group_id}"
|
|
70
|
+
return path
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def compute_branch_name(
|
|
74
|
+
*,
|
|
75
|
+
work_category: str,
|
|
76
|
+
task_id_segment: str,
|
|
77
|
+
stage_number: Optional[int] = None,
|
|
78
|
+
group_id: Optional[str] = None,
|
|
79
|
+
) -> str:
|
|
80
|
+
"""One branch per task-key as `<namespace>/<task-id>`, or
|
|
81
|
+
`<namespace>/<task-id>-s<N>` for an implementation stage worktree. The
|
|
82
|
+
namespace is a controlled constant so its slash is preserved; only the
|
|
83
|
+
task-id segment is sanitised."""
|
|
84
|
+
if stage_number is not None and group_id is not None:
|
|
85
|
+
raise ValueError("stage_number and group_id are mutually exclusive")
|
|
86
|
+
name = f"{_work_category_namespace(work_category)}/{_safe_segment(task_id_segment)}"
|
|
87
|
+
if stage_number is not None:
|
|
88
|
+
name = f"{name}-s{stage_number}"
|
|
89
|
+
if group_id is not None:
|
|
90
|
+
name = f"{name}-{group_id}"
|
|
91
|
+
return name
|