okstra 0.174.0 → 0.176.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 +18 -9
- package/bin/okstra +8 -4
- package/dist/cli-registry.d.mts +16 -0
- package/dist/cli-registry.mjs +560 -0
- package/dist/cli-registry.mjs.map +1 -0
- package/dist/commands/execute/agent-prompt.d.mts +1 -0
- package/{src → dist}/commands/execute/agent-prompt.mjs +10 -11
- package/dist/commands/execute/agent-prompt.mjs.map +1 -0
- package/dist/commands/execute/codex-dispatch.d.mts +3 -0
- package/dist/commands/execute/codex-dispatch.mjs +6 -0
- package/dist/commands/execute/codex-dispatch.mjs.map +1 -0
- package/dist/commands/execute/codex-run.d.mts +3 -0
- package/{src → dist}/commands/execute/codex-run.mjs +30 -37
- package/dist/commands/execute/codex-run.mjs.map +1 -0
- package/dist/commands/execute/convergence.d.mts +1 -0
- package/{src → dist}/commands/execute/convergence.mjs +15 -16
- package/dist/commands/execute/convergence.mjs.map +1 -0
- package/dist/commands/execute/error-log.d.mts +1 -0
- package/{src → dist}/commands/execute/error-log.mjs +2 -3
- package/dist/commands/execute/error-log.mjs.map +1 -0
- package/dist/commands/execute/git-reconcile.d.mts +1 -0
- package/{src → dist}/commands/execute/git-reconcile.mjs +10 -11
- package/dist/commands/execute/git-reconcile.mjs.map +1 -0
- package/dist/commands/execute/handoff.d.mts +1 -0
- package/{src → dist}/commands/execute/handoff.mjs +10 -11
- package/dist/commands/execute/handoff.mjs.map +1 -0
- package/dist/commands/execute/incremental-carry.d.mts +1 -0
- package/{src → dist}/commands/execute/incremental-carry.mjs +2 -3
- package/dist/commands/execute/incremental-carry.mjs.map +1 -0
- package/dist/commands/execute/incremental-scope.d.mts +1 -0
- package/{src → dist}/commands/execute/incremental-scope.mjs +2 -3
- package/dist/commands/execute/incremental-scope.mjs.map +1 -0
- package/dist/commands/execute/integrate-stages.d.mts +1 -0
- package/{src → dist}/commands/execute/integrate-stages.mjs +10 -11
- package/dist/commands/execute/integrate-stages.mjs.map +1 -0
- package/dist/commands/execute/pane-title.d.mts +1 -0
- package/dist/commands/execute/pane-title.mjs +20 -0
- package/dist/commands/execute/pane-title.mjs.map +1 -0
- package/dist/commands/execute/plan-items.d.mts +1 -0
- package/dist/commands/execute/plan-items.mjs +9 -0
- package/dist/commands/execute/plan-items.mjs.map +1 -0
- package/dist/commands/execute/plan-validate.d.mts +1 -0
- package/dist/commands/execute/plan-validate.mjs +68 -0
- package/dist/commands/execute/plan-validate.mjs.map +1 -0
- package/dist/commands/execute/plan-verify.d.mts +1 -0
- package/{src → dist}/commands/execute/plan-verify.mjs +13 -16
- package/dist/commands/execute/plan-verify.mjs.map +1 -0
- package/dist/commands/execute/render-bundle.d.mts +3 -0
- package/{src → dist}/commands/execute/render-bundle.mjs +65 -61
- package/dist/commands/execute/render-bundle.mjs.map +1 -0
- package/dist/commands/execute/run.d.mts +24 -0
- package/dist/commands/execute/run.mjs +196 -0
- package/dist/commands/execute/run.mjs.map +1 -0
- package/dist/commands/execute/spawn-followups.d.mts +1 -0
- package/{src → dist}/commands/execute/spawn-followups.mjs +6 -7
- package/dist/commands/execute/spawn-followups.mjs.map +1 -0
- package/dist/commands/execute/team.d.mts +3 -0
- package/{src → dist}/commands/execute/team.mjs +29 -36
- package/dist/commands/execute/team.mjs.map +1 -0
- package/dist/commands/execute/token-usage.d.mts +1 -0
- package/{src → dist}/commands/execute/token-usage.mjs +2 -3
- package/dist/commands/execute/token-usage.mjs.map +1 -0
- package/dist/commands/execute/wizard.d.mts +8 -0
- package/dist/commands/execute/wizard.mjs +191 -0
- package/dist/commands/execute/wizard.mjs.map +1 -0
- package/dist/commands/execute/worker-audit-check.d.mts +1 -0
- package/{src → dist}/commands/execute/worker-audit-check.mjs +11 -12
- package/dist/commands/execute/worker-audit-check.mjs.map +1 -0
- package/dist/commands/execute/worker-dispatch.d.mts +7 -0
- package/{src → dist}/commands/execute/worker-dispatch.mjs +34 -46
- package/dist/commands/execute/worker-dispatch.mjs.map +1 -0
- package/dist/commands/execute/worker-state.d.mts +1 -0
- package/{src → dist}/commands/execute/worker-state.mjs +15 -16
- package/dist/commands/execute/worker-state.mjs.map +1 -0
- package/dist/commands/execute/worktree-lookup.d.mts +1 -0
- package/{src → dist}/commands/execute/worktree-lookup.mjs +38 -37
- package/dist/commands/execute/worktree-lookup.mjs.map +1 -0
- package/dist/commands/execute/worktree-status.d.mts +1 -0
- package/{src → dist}/commands/execute/worktree-status.mjs +52 -46
- package/dist/commands/execute/worktree-status.mjs.map +1 -0
- package/dist/commands/inspect/code-review.d.mts +1 -0
- package/{src → dist}/commands/inspect/code-review.mjs +16 -19
- package/dist/commands/inspect/code-review.mjs.map +1 -0
- package/dist/commands/inspect/container.d.mts +1 -0
- package/{src → dist}/commands/inspect/container.mjs +11 -13
- package/dist/commands/inspect/container.mjs.map +1 -0
- package/dist/commands/inspect/context-cost.d.mts +1 -0
- package/{src → dist}/commands/inspect/context-cost.mjs +11 -13
- package/dist/commands/inspect/context-cost.mjs.map +1 -0
- package/dist/commands/inspect/design-prep.d.mts +1 -0
- package/{src → dist}/commands/inspect/design-prep.mjs +10 -11
- package/dist/commands/inspect/design-prep.mjs.map +1 -0
- package/dist/commands/inspect/error-report.d.mts +1 -0
- package/{src → dist}/commands/inspect/error-report.mjs +11 -13
- package/dist/commands/inspect/error-report.mjs.map +1 -0
- package/dist/commands/inspect/error-zip.d.mts +1 -0
- package/{src → dist}/commands/inspect/error-zip.mjs +11 -12
- package/dist/commands/inspect/error-zip.mjs.map +1 -0
- package/dist/commands/inspect/log-report.d.mts +1 -0
- package/{src → dist}/commands/inspect/log-report.mjs +11 -13
- package/dist/commands/inspect/log-report.mjs.map +1 -0
- package/dist/commands/inspect/profile-show.d.mts +1 -0
- package/{src → dist}/commands/inspect/profile-show.mjs +10 -11
- package/dist/commands/inspect/profile-show.mjs.map +1 -0
- package/dist/commands/inspect/recap.d.mts +1 -0
- package/{src → dist}/commands/inspect/recap.mjs +11 -13
- package/dist/commands/inspect/recap.mjs.map +1 -0
- package/dist/commands/inspect/resolve-task-key.d.mts +1 -0
- package/{src → dist}/commands/inspect/resolve-task-key.mjs +11 -13
- package/dist/commands/inspect/resolve-task-key.mjs.map +1 -0
- package/dist/commands/inspect/rollup.d.mts +1 -0
- package/{src → dist}/commands/inspect/rollup.mjs +11 -13
- package/dist/commands/inspect/rollup.mjs.map +1 -0
- package/dist/commands/inspect/run-audit.d.mts +1 -0
- package/{src → dist}/commands/inspect/run-audit.mjs +11 -12
- package/dist/commands/inspect/run-audit.mjs.map +1 -0
- package/dist/commands/inspect/set-work-status.d.mts +1 -0
- package/{src → dist}/commands/inspect/set-work-status.mjs +11 -13
- package/dist/commands/inspect/set-work-status.mjs.map +1 -0
- package/dist/commands/inspect/stage-map.d.mts +1 -0
- package/dist/commands/inspect/stage-map.mjs +110 -0
- package/dist/commands/inspect/stage-map.mjs.map +1 -0
- package/dist/commands/inspect/task-list.d.mts +1 -0
- package/dist/commands/inspect/task-list.mjs +103 -0
- package/dist/commands/inspect/task-list.mjs.map +1 -0
- package/dist/commands/inspect/task-show.d.mts +1 -0
- package/dist/commands/inspect/task-show.mjs +108 -0
- package/dist/commands/inspect/task-show.mjs.map +1 -0
- package/dist/commands/inspect/time-report.d.mts +1 -0
- package/{src → dist}/commands/inspect/time-report.mjs +11 -13
- package/dist/commands/inspect/time-report.mjs.map +1 -0
- package/dist/commands/inspect/usage-report.d.mts +1 -0
- package/{src → dist}/commands/inspect/usage-report.mjs +11 -13
- package/dist/commands/inspect/usage-report.mjs.map +1 -0
- package/dist/commands/inspect/user-response.d.mts +1 -0
- package/{src → dist}/commands/inspect/user-response.mjs +10 -11
- package/dist/commands/inspect/user-response.mjs.map +1 -0
- package/dist/commands/inspect/worker-liveness.d.mts +1 -0
- package/{src → dist}/commands/inspect/worker-liveness.mjs +11 -13
- package/dist/commands/inspect/worker-liveness.mjs.map +1 -0
- package/dist/commands/lifecycle/check-project.d.mts +21 -0
- package/dist/commands/lifecycle/check-project.mjs +175 -0
- package/dist/commands/lifecycle/check-project.mjs.map +1 -0
- package/dist/commands/lifecycle/config.d.mts +1 -0
- package/dist/commands/lifecycle/config.mjs +369 -0
- package/dist/commands/lifecycle/config.mjs.map +1 -0
- package/dist/commands/lifecycle/doctor.d.mts +10 -0
- package/dist/commands/lifecycle/doctor.mjs +317 -0
- package/dist/commands/lifecycle/doctor.mjs.map +1 -0
- package/dist/commands/lifecycle/install.d.mts +17 -0
- package/dist/commands/lifecycle/install.mjs +1077 -0
- package/dist/commands/lifecycle/install.mjs.map +1 -0
- package/dist/commands/lifecycle/migrate.d.mts +1 -0
- package/{src → dist}/commands/lifecycle/migrate.mjs +10 -11
- package/dist/commands/lifecycle/migrate.mjs.map +1 -0
- package/dist/commands/lifecycle/model.d.mts +1 -0
- package/dist/commands/lifecycle/model.mjs +22 -0
- package/dist/commands/lifecycle/model.mjs.map +1 -0
- package/dist/commands/lifecycle/paths.d.mts +1 -0
- package/dist/commands/lifecycle/paths.mjs +102 -0
- package/dist/commands/lifecycle/paths.mjs.map +1 -0
- package/dist/commands/lifecycle/preflight.d.mts +1 -0
- package/dist/commands/lifecycle/preflight.mjs +124 -0
- package/dist/commands/lifecycle/preflight.mjs.map +1 -0
- package/dist/commands/lifecycle/setup.d.mts +1 -0
- package/dist/commands/lifecycle/setup.mjs +297 -0
- package/dist/commands/lifecycle/setup.mjs.map +1 -0
- package/dist/commands/lifecycle/uninstall.d.mts +4 -0
- package/dist/commands/lifecycle/uninstall.mjs +262 -0
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -0
- package/dist/commands/manager.d.mts +3 -0
- package/{src → dist}/commands/manager.mjs +25 -32
- package/dist/commands/manager.mjs.map +1 -0
- package/dist/commands/memory/memory.d.mts +1 -0
- package/dist/commands/memory/memory.mjs +569 -0
- package/dist/commands/memory/memory.mjs.map +1 -0
- package/dist/commands/pr/pr.d.mts +33 -0
- package/dist/commands/pr/pr.mjs +296 -0
- package/dist/commands/pr/pr.mjs.map +1 -0
- package/dist/commands/report/agent-activity.d.mts +1 -0
- package/{src → dist}/commands/report/agent-activity.mjs +11 -12
- package/dist/commands/report/agent-activity.mjs.map +1 -0
- package/dist/commands/report/finalize.d.mts +4 -0
- package/{src → dist}/commands/report/finalize.mjs +25 -32
- package/dist/commands/report/finalize.mjs.map +1 -0
- package/dist/commands/report/inject-report-index.d.mts +1 -0
- package/{src → dist}/commands/report/inject-report-index.mjs +6 -7
- package/dist/commands/report/inject-report-index.mjs.map +1 -0
- package/dist/commands/report/render-final-report.d.mts +1 -0
- package/{src → dist}/commands/report/render-final-report.mjs +6 -7
- package/dist/commands/report/render-final-report.mjs.map +1 -0
- package/dist/commands/report/render-views.d.mts +1 -0
- package/{src → dist}/commands/report/render-views.mjs +6 -7
- package/dist/commands/report/render-views.mjs.map +1 -0
- package/dist/commands/report/translate.d.mts +1 -0
- package/{src → dist}/commands/report/translate.mjs +6 -7
- package/dist/commands/report/translate.mjs.map +1 -0
- package/dist/lib/helper-scripts.d.mts +3 -0
- package/{src → dist}/lib/helper-scripts.mjs +11 -14
- package/dist/lib/helper-scripts.mjs.map +1 -0
- package/dist/lib/host-registry-client.d.mts +25 -0
- package/dist/lib/host-registry-client.mjs +152 -0
- package/dist/lib/host-registry-client.mjs.map +1 -0
- package/dist/lib/install-assets.d.mts +8 -0
- package/{src → dist}/lib/install-assets.mjs +17 -20
- package/dist/lib/install-assets.mjs.map +1 -0
- package/dist/lib/okstra-dirs.d.mts +4 -0
- package/{src → dist}/lib/okstra-dirs.mjs +3 -6
- package/dist/lib/okstra-dirs.mjs.map +1 -0
- package/dist/lib/paths.d.mts +4 -0
- package/dist/lib/paths.mjs +78 -0
- package/dist/lib/paths.mjs.map +1 -0
- package/dist/lib/proc.d.mts +3 -0
- package/dist/lib/proc.mjs +31 -0
- package/dist/lib/proc.mjs.map +1 -0
- package/dist/lib/python-helper.d.mts +8 -0
- package/dist/lib/python-helper.mjs +123 -0
- package/dist/lib/python-helper.mjs.map +1 -0
- package/dist/lib/runtime-manifest.d.mts +7 -0
- package/dist/lib/runtime-manifest.mjs +73 -0
- package/dist/lib/runtime-manifest.mjs.map +1 -0
- package/dist/lib/skill-catalog.d.mts +4 -0
- package/dist/lib/skill-catalog.mjs +50 -0
- package/dist/lib/skill-catalog.mjs.map +1 -0
- package/dist/lib/types.d.mts +129 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/lib/types.mjs.map +1 -0
- package/dist/lib/version.d.mts +2 -0
- package/dist/lib/version.mjs +27 -0
- package/dist/lib/version.mjs.map +1 -0
- package/docs/architecture/storage-model.md +6 -2
- package/docs/architecture.md +29 -20
- package/docs/cli.md +40 -16
- package/docs/contributor-change-matrix.md +2 -2
- package/docs/for-ai/skills/okstra-inspect.md +2 -3
- package/docs/for-ai/skills/okstra-rollup.md +1 -0
- package/docs/project-structure-overview.md +72 -62
- package/docs/task-process/README.md +12 -8
- package/docs/task-process/common-flow.md +13 -16
- package/docs/task-process/error-analysis.md +9 -10
- package/docs/task-process/final-verification.md +7 -7
- package/docs/task-process/implementation-planning.md +9 -9
- package/docs/task-process/implementation.md +6 -6
- package/docs/task-process/release-handoff.md +8 -7
- package/docs/task-process/requirements-discovery.md +8 -8
- package/package.json +11 -5
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +2 -1
- package/runtime/agents/workers/report-writer-worker.md +3 -1
- package/runtime/agents/workers/translator-worker.md +3 -1
- package/runtime/bin/lib/okstra/cli.sh +12 -0
- package/runtime/bin/lib/okstra/globals.sh +3 -0
- package/runtime/bin/lib/okstra/interactive.sh +12 -6
- package/runtime/bin/lib/okstra/usage.sh +7 -6
- package/runtime/bin/okstra-error-log.py +27 -0
- package/runtime/bin/okstra-provider-exec.py +217 -5
- package/runtime/bin/okstra-spawn-followups.py +4 -2
- package/runtime/bin/okstra.sh +10 -0
- package/runtime/prompts/launch.template.md +2 -2
- package/runtime/prompts/lead/context-loader.md +1 -2
- package/runtime/prompts/lead/convergence.md +27 -18
- package/runtime/prompts/lead/okstra-lead-contract.md +6 -5
- package/runtime/prompts/lead/plan-body-verification.md +10 -3
- package/runtime/prompts/lead/report-writer.md +15 -1
- package/runtime/prompts/lead/team-contract.md +17 -13
- package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
- package/runtime/prompts/profiles/_implementation-executor.md +0 -3
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -7
- package/runtime/prompts/profiles/change-impact-analysis.md +20 -0
- package/runtime/prompts/profiles/error-analysis.md +27 -1
- package/runtime/prompts/profiles/feature-analysis.md +20 -0
- package/runtime/prompts/profiles/final-verification.md +20 -1
- package/runtime/prompts/profiles/implementation-option-selection.md +20 -0
- package/runtime/prompts/profiles/implementation-planning.md +26 -0
- package/runtime/prompts/profiles/implementation.md +19 -0
- package/runtime/prompts/profiles/improvement-discovery.md +21 -1
- package/runtime/prompts/profiles/project-analysis.md +20 -0
- package/runtime/prompts/profiles/release-handoff.md +4 -0
- package/runtime/prompts/profiles/requirements-discovery.md +27 -1
- package/runtime/prompts/wizard/prompts.ko.json +35 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +8 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +8 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +25 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +4 -1
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +2 -2
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +79 -11
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +95 -25
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +59 -14
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +55 -9
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +51 -12
- package/runtime/python/okstra_ctl/adapters/runtime/__init__.py +1 -0
- package/runtime/python/okstra_ctl/adapters/runtime/assembly.py +27 -0
- package/runtime/python/okstra_ctl/adapters/runtime/cli_wrapper.py +49 -0
- package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +74 -0
- package/runtime/python/okstra_ctl/agent_activity.py +5 -1
- package/runtime/python/okstra_ctl/agent_invocation.py +608 -14
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +249 -50
- package/runtime/python/okstra_ctl/application/open_worker.py +29 -0
- package/runtime/python/okstra_ctl/application/resolve_assignment.py +53 -12
- package/runtime/python/okstra_ctl/assignment_environment.py +102 -0
- package/runtime/python/okstra_ctl/assignment_resolver.py +790 -0
- package/runtime/python/okstra_ctl/attempt_evidence.py +342 -0
- package/runtime/python/okstra_ctl/convergence.py +409 -3
- package/runtime/python/okstra_ctl/convergence_engine.py +248 -15
- package/runtime/python/okstra_ctl/convergence_store.py +170 -1
- package/runtime/python/okstra_ctl/dispatch_core.py +1204 -155
- package/runtime/python/okstra_ctl/dispatch_state.py +696 -11
- package/runtime/python/okstra_ctl/doctor.py +14 -0
- package/runtime/python/okstra_ctl/domain/host.py +34 -1
- package/runtime/python/okstra_ctl/domain/provider.py +212 -6
- package/runtime/python/okstra_ctl/domain/role.py +125 -0
- package/runtime/python/okstra_ctl/domain/wizard/interaction.py +18 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +34 -1
- package/runtime/python/okstra_ctl/domain/worker_role.py +13 -3
- package/runtime/python/okstra_ctl/domain/worker_runtime.py +44 -0
- package/runtime/python/okstra_ctl/domain/worker_stream.py +24 -0
- package/runtime/python/okstra_ctl/error_log_write.py +9 -0
- package/runtime/python/okstra_ctl/error_report.py +21 -1
- package/runtime/python/okstra_ctl/execution_identity.py +529 -0
- package/runtime/python/okstra_ctl/execution_manifest.py +1281 -0
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +619 -0
- package/runtime/python/okstra_ctl/implementation_outcome.py +21 -5
- package/runtime/python/okstra_ctl/index.py +6 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
- package/runtime/python/okstra_ctl/legacy_model_selection.py +578 -0
- package/runtime/python/okstra_ctl/manager_sync.py +4 -1
- package/runtime/python/okstra_ctl/model_cli.py +278 -0
- package/runtime/python/okstra_ctl/model_defaults.py +46 -0
- package/runtime/python/okstra_ctl/model_discovery.py +26 -7
- package/runtime/python/okstra_ctl/model_pool.py +501 -0
- package/runtime/python/okstra_ctl/models.py +47 -27
- package/runtime/python/okstra_ctl/mutation_recovery.py +293 -0
- package/runtime/python/okstra_ctl/next_phase.py +236 -0
- package/runtime/python/okstra_ctl/pane_title.py +151 -0
- package/runtime/python/okstra_ctl/ports/host_model.py +48 -17
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
- package/runtime/python/okstra_ctl/ports/worker_runtime.py +26 -0
- package/runtime/python/okstra_ctl/recap.py +4 -1
- package/runtime/python/okstra_ctl/registry/provider_registry.py +8 -4
- package/runtime/python/okstra_ctl/render.py +124 -57
- package/runtime/python/okstra_ctl/render_final_report.py +19 -0
- package/runtime/python/okstra_ctl/report_contract.py +39 -0
- package/runtime/python/okstra_ctl/report_finalize.py +16 -0
- package/runtime/python/okstra_ctl/report_html/render.py +1 -0
- package/runtime/python/okstra_ctl/role_requirements.py +210 -0
- package/runtime/python/okstra_ctl/rollup.py +4 -1
- package/runtime/python/okstra_ctl/run.py +1210 -258
- package/runtime/python/okstra_ctl/run_index_row.py +7 -1
- package/runtime/python/okstra_ctl/stage_fix_carry.py +17 -1
- package/runtime/python/okstra_ctl/team.py +14 -18
- package/runtime/python/okstra_ctl/time_report.py +38 -4
- package/runtime/python/okstra_ctl/usage_identity.py +86 -0
- package/runtime/python/okstra_ctl/usage_report.py +15 -3
- package/runtime/python/okstra_ctl/wizard.py +1449 -66
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
- package/runtime/python/okstra_ctl/worker_prompt_body.py +18 -2
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +40 -9
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +16 -1
- package/runtime/python/okstra_ctl/worker_request.py +7 -1
- package/runtime/python/okstra_ctl/worker_runner.py +130 -5
- package/runtime/python/okstra_ctl/workers.py +7 -5
- package/runtime/python/okstra_ctl/workflow.py +18 -32
- package/runtime/python/okstra_ctl/worktree.py +3 -3
- package/runtime/python/okstra_ctl/worktree_registry.py +5 -4
- package/runtime/python/okstra_ctl/write_policy.py +571 -0
- package/runtime/python/okstra_project/state.py +54 -6
- package/runtime/schemas/convergence-groups-v2.0.schema.json +128 -0
- package/runtime/schemas/execution-manifest-v2.schema.json +340 -0
- package/runtime/schemas/final-report-v2.0.schema.json +68 -5
- package/runtime/skills/okstra-inspect/facets/recap.md +2 -0
- package/runtime/skills/okstra-inspect/facets/report.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +15 -13
- package/runtime/skills/okstra-rollup/SKILL.md +1 -0
- package/runtime/skills/okstra-run/SKILL.md +14 -14
- package/runtime/templates/implementation-worker-preamble.md +3 -18
- package/runtime/templates/project-docs/task-index.template.md +0 -1
- package/runtime/templates/report-writer-prompt-preamble.md +2 -0
- package/runtime/templates/reports/final-report-v2.template.md +7 -1
- package/runtime/templates/reports/html/base.template.html +21 -0
- package/runtime/templates/reports/html/i18n/en.json +4 -0
- package/runtime/templates/reports/html/i18n/ko.json +4 -0
- package/runtime/templates/reports/html/macros/forms.html +5 -4
- package/runtime/templates/reports/html/tasks/final-verification.template.html +1 -1
- package/runtime/templates/reports/html/tasks/implementation.template.html +1 -1
- package/runtime/templates/worker-prompt-preamble.md +6 -35
- package/runtime/validators/lib/fixtures.sh +49 -16
- package/runtime/validators/validate-run.py +486 -134
- package/runtime/validators/validate_session_conformance.py +25 -7
- package/src/cli-registry.mjs +0 -539
- package/src/commands/execute/codex-dispatch.mjs +0 -10
- package/src/commands/execute/plan-items.mjs +0 -9
- package/src/commands/execute/plan-validate.mjs +0 -68
- package/src/commands/execute/run.mjs +0 -208
- package/src/commands/execute/wizard.mjs +0 -167
- package/src/commands/inspect/stage-map.mjs +0 -98
- package/src/commands/inspect/task-list.mjs +0 -97
- package/src/commands/inspect/task-show.mjs +0 -100
- package/src/commands/lifecycle/check-project.mjs +0 -187
- package/src/commands/lifecycle/config.mjs +0 -385
- package/src/commands/lifecycle/doctor.mjs +0 -308
- package/src/commands/lifecycle/install.mjs +0 -1170
- package/src/commands/lifecycle/paths.mjs +0 -104
- package/src/commands/lifecycle/preflight.mjs +0 -125
- package/src/commands/lifecycle/setup.mjs +0 -333
- package/src/commands/lifecycle/uninstall.mjs +0 -279
- package/src/commands/memory/memory.mjs +0 -524
- package/src/commands/pr/pr.mjs +0 -261
- package/src/lib/host-registry-client.mjs +0 -176
- package/src/lib/paths.mjs +0 -86
- package/src/lib/proc.mjs +0 -31
- package/src/lib/python-helper.mjs +0 -142
- package/src/lib/runtime-manifest.mjs +0 -70
- package/src/lib/skill-catalog.mjs +0 -53
- package/src/lib/version.mjs +0 -20
- /package/{src → dist}/commands/pr/default.md +0 -0
package/src/commands/pr/pr.mjs
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
|
-
import { createInterface } from "node:readline/promises";
|
|
6
|
-
import { stdin as input, stdout as output } from "node:process";
|
|
7
|
-
import { resolveOkstraHome } from "../../lib/paths.mjs";
|
|
8
|
-
|
|
9
|
-
const NAME_RE = /^[A-Za-z0-9._-]+$/;
|
|
10
|
-
const DEFAULT_TEMPLATE_PATH = join(
|
|
11
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
12
|
-
"default.md",
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const USAGE = `okstra pr — PR body templates and PR generation
|
|
16
|
-
|
|
17
|
-
Usage:
|
|
18
|
-
okstra pr template list [--json]
|
|
19
|
-
okstra pr template show <name|default> [--json]
|
|
20
|
-
okstra pr template add --name <name> (--content <text> | --file <path>) [--yes]
|
|
21
|
-
okstra pr template path
|
|
22
|
-
okstra pr branches [--json]
|
|
23
|
-
okstra pr gen --base <ref> [--template <name|default>] [--json]
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
export function isValidTemplateName(name) {
|
|
27
|
-
return (
|
|
28
|
-
typeof name === "string" &&
|
|
29
|
-
NAME_RE.test(name) &&
|
|
30
|
-
name !== "." &&
|
|
31
|
-
name !== ".."
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function templateDir(home) {
|
|
36
|
-
return join(home, "template", "pr");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export async function listTemplates(home) {
|
|
40
|
-
let entries;
|
|
41
|
-
try {
|
|
42
|
-
entries = await fs.readdir(templateDir(home));
|
|
43
|
-
} catch (err) {
|
|
44
|
-
if (err.code === "ENOENT") return [];
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
return entries
|
|
48
|
-
.filter((f) => f.endsWith(".md"))
|
|
49
|
-
.map((f) => f.slice(0, -3))
|
|
50
|
-
.sort();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function readBundledDefault() {
|
|
54
|
-
return fs.readFile(DEFAULT_TEMPLATE_PATH, "utf8");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export async function readTemplate(home, name) {
|
|
58
|
-
if (!name || name === "default") return readBundledDefault();
|
|
59
|
-
if (!isValidTemplateName(name)) throw new Error(`invalid template name: ${name}`);
|
|
60
|
-
try {
|
|
61
|
-
return await fs.readFile(join(templateDir(home), `${name}.md`), "utf8");
|
|
62
|
-
} catch (err) {
|
|
63
|
-
if (err.code === "ENOENT") return readBundledDefault();
|
|
64
|
-
throw err;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function addTemplate(home, name, content, opts = {}) {
|
|
69
|
-
if (!isValidTemplateName(name)) throw new Error(`invalid template name: ${name}`);
|
|
70
|
-
const dir = templateDir(home);
|
|
71
|
-
await fs.mkdir(dir, { recursive: true });
|
|
72
|
-
const target = join(dir, `${name}.md`);
|
|
73
|
-
if (!opts.force) {
|
|
74
|
-
try {
|
|
75
|
-
await fs.access(target);
|
|
76
|
-
throw new Error(`template exists: ${name} (use --yes to overwrite)`);
|
|
77
|
-
} catch (err) {
|
|
78
|
-
if (err.code !== "ENOENT") throw err;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
await fs.writeFile(target, content, "utf8");
|
|
82
|
-
return target;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function takeValue(args, i, flag) {
|
|
86
|
-
const v = args[i + 1];
|
|
87
|
-
if (!v || v.startsWith("--")) throw new Error(`${flag} requires a value`);
|
|
88
|
-
return v;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function readAddContent(opts) {
|
|
92
|
-
if (opts.content !== null) return opts.content;
|
|
93
|
-
if (opts.file !== null) return fs.readFile(resolve(opts.file), "utf8");
|
|
94
|
-
throw new Error("template add requires --content or --file");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function confirm(question) {
|
|
98
|
-
const rl = createInterface({ input, output });
|
|
99
|
-
try {
|
|
100
|
-
const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();
|
|
101
|
-
return answer === "y" || answer === "yes";
|
|
102
|
-
} finally {
|
|
103
|
-
rl.close();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function cmdTemplate(args, home) {
|
|
108
|
-
const sub = args[0];
|
|
109
|
-
const rest = args.slice(1);
|
|
110
|
-
const json = rest.includes("--json");
|
|
111
|
-
if (sub === "list") {
|
|
112
|
-
const names = await listTemplates(home);
|
|
113
|
-
if (json) output.write(JSON.stringify({ templates: names }) + "\n");
|
|
114
|
-
else output.write(names.length ? names.join("\n") + "\n" : "(no templates)\n");
|
|
115
|
-
return 0;
|
|
116
|
-
}
|
|
117
|
-
if (sub === "show") {
|
|
118
|
-
const name = rest.find((a) => !a.startsWith("--"));
|
|
119
|
-
if (!name) throw new Error("template show requires a name");
|
|
120
|
-
const body = await readTemplate(home, name);
|
|
121
|
-
output.write(json ? JSON.stringify({ name, body }) + "\n" : body);
|
|
122
|
-
return 0;
|
|
123
|
-
}
|
|
124
|
-
if (sub === "path") {
|
|
125
|
-
output.write(templateDir(home) + "\n");
|
|
126
|
-
return 0;
|
|
127
|
-
}
|
|
128
|
-
if (sub === "add") {
|
|
129
|
-
const opts = { name: null, content: null, file: null, yes: false };
|
|
130
|
-
for (let i = 0; i < rest.length; i++) {
|
|
131
|
-
const flag = rest[i];
|
|
132
|
-
if (flag === "--name") opts.name = takeValue(rest, i++, flag);
|
|
133
|
-
else if (flag === "--content") opts.content = takeValue(rest, i++, flag);
|
|
134
|
-
else if (flag === "--file") opts.file = takeValue(rest, i++, flag);
|
|
135
|
-
else if (flag === "--yes") opts.yes = true;
|
|
136
|
-
else throw new Error(`unknown flag ${flag}`);
|
|
137
|
-
}
|
|
138
|
-
if (!opts.name) throw new Error("template add requires --name");
|
|
139
|
-
const content = await readAddContent(opts);
|
|
140
|
-
const dir = templateDir(home);
|
|
141
|
-
const target = join(dir, `${opts.name}.md`);
|
|
142
|
-
let force = opts.yes;
|
|
143
|
-
if (!force && isValidTemplateName(opts.name)) {
|
|
144
|
-
let exists = false;
|
|
145
|
-
try {
|
|
146
|
-
await fs.access(target);
|
|
147
|
-
exists = true;
|
|
148
|
-
} catch (err) {
|
|
149
|
-
if (err.code !== "ENOENT") throw err;
|
|
150
|
-
}
|
|
151
|
-
if (exists) {
|
|
152
|
-
if (!process.stdin.isTTY) {
|
|
153
|
-
throw new Error(`template exists: ${opts.name} (use --yes to overwrite)`);
|
|
154
|
-
}
|
|
155
|
-
force = await confirm(`Overwrite existing template ${opts.name}?`);
|
|
156
|
-
if (!force) { output.write("aborted\n"); return 1; }
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const saved = await addTemplate(home, opts.name, content, { force: true });
|
|
160
|
-
output.write(`saved: ${saved}\n`);
|
|
161
|
-
return 0;
|
|
162
|
-
}
|
|
163
|
-
throw new Error(`unknown template subcommand: ${sub ?? "(none)"}`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function tryGit(cwd, args) {
|
|
167
|
-
try {
|
|
168
|
-
return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
169
|
-
} catch {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function recommendBranches(cwd) {
|
|
175
|
-
const currentBranch = tryGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
176
|
-
if (currentBranch === null) return { currentBranch: null, recommended: [] };
|
|
177
|
-
const ordered = [];
|
|
178
|
-
const remoteDefault = tryGit(cwd, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
179
|
-
if (remoteDefault) {
|
|
180
|
-
const bare = remoteDefault.replace(/^origin\//, "");
|
|
181
|
-
if (tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${bare}^{commit}`]) !== null) ordered.push(bare);
|
|
182
|
-
else if (tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${remoteDefault}^{commit}`]) !== null) ordered.push(remoteDefault);
|
|
183
|
-
}
|
|
184
|
-
for (const b of ["main", "master", "develop"]) {
|
|
185
|
-
const local = tryGit(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${b}`]);
|
|
186
|
-
if (local !== null) ordered.push(b);
|
|
187
|
-
}
|
|
188
|
-
const recent = tryGit(cwd, [
|
|
189
|
-
"for-each-ref", "--sort=-committerdate", "--format=%(refname:short)", "refs/heads",
|
|
190
|
-
]);
|
|
191
|
-
if (recent) ordered.push(...recent.split("\n").filter(Boolean));
|
|
192
|
-
const recommended = [];
|
|
193
|
-
for (const b of ordered) {
|
|
194
|
-
if (b && b !== currentBranch && !recommended.includes(b)) recommended.push(b);
|
|
195
|
-
}
|
|
196
|
-
return { currentBranch, recommended };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function cmdBranches(args, cwd) {
|
|
200
|
-
const json = args.includes("--json");
|
|
201
|
-
const r = recommendBranches(cwd);
|
|
202
|
-
if (json) output.write(JSON.stringify(r) + "\n");
|
|
203
|
-
else output.write((r.recommended.join("\n") || "(no branches)") + "\n");
|
|
204
|
-
return 0;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export async function buildGenBundle({ cwd, home, base, templateName }) {
|
|
208
|
-
if (!base) throw new Error("gen requires --base");
|
|
209
|
-
const verified = tryGit(cwd, ["rev-parse", "--verify", "--quiet", `${base}^{commit}`]);
|
|
210
|
-
if (verified === null) throw new Error(`base ref not found: ${base}`);
|
|
211
|
-
const currentBranch = tryGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
212
|
-
const logRaw = tryGit(cwd, [
|
|
213
|
-
"log", "--reverse", "--format=%h%x09%s", `${base}..HEAD`,
|
|
214
|
-
]) || "";
|
|
215
|
-
const commits = logRaw
|
|
216
|
-
.split("\n")
|
|
217
|
-
.filter(Boolean)
|
|
218
|
-
.map((line) => {
|
|
219
|
-
const tab = line.indexOf("\t");
|
|
220
|
-
return { hash: line.slice(0, tab), subject: line.slice(tab + 1) };
|
|
221
|
-
});
|
|
222
|
-
const diffStat = tryGit(cwd, ["diff", "--stat", `${base}...HEAD`]) || "";
|
|
223
|
-
const template = await readTemplate(home, templateName);
|
|
224
|
-
const resolvedName = templateName && templateName !== "default"
|
|
225
|
-
? templateName
|
|
226
|
-
: "default";
|
|
227
|
-
return { base, currentBranch, templateName: resolvedName, template, commits, diffStat };
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
async function cmdGen(args, cwd, home) {
|
|
231
|
-
const opts = { base: null, template: "default" };
|
|
232
|
-
for (let i = 0; i < args.length; i++) {
|
|
233
|
-
const flag = args[i];
|
|
234
|
-
if (flag === "--base") opts.base = takeValue(args, i++, flag);
|
|
235
|
-
else if (flag === "--template") opts.template = takeValue(args, i++, flag);
|
|
236
|
-
else if (flag === "--json") continue;
|
|
237
|
-
else throw new Error(`unknown flag ${flag}`);
|
|
238
|
-
}
|
|
239
|
-
const bundle = await buildGenBundle({ cwd, home, base: opts.base, templateName: opts.template });
|
|
240
|
-
output.write(JSON.stringify(bundle) + "\n");
|
|
241
|
-
return 0;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export async function run(args) {
|
|
245
|
-
if (args.length === 0 || args.includes("--help")) {
|
|
246
|
-
output.write(USAGE);
|
|
247
|
-
return 0;
|
|
248
|
-
}
|
|
249
|
-
const home = resolveOkstraHome();
|
|
250
|
-
const sub = args[0];
|
|
251
|
-
const rest = args.slice(1);
|
|
252
|
-
try {
|
|
253
|
-
if (sub === "template") return await cmdTemplate(rest, home);
|
|
254
|
-
if (sub === "branches") return cmdBranches(rest, process.cwd());
|
|
255
|
-
if (sub === "gen") return await cmdGen(rest, process.cwd(), home);
|
|
256
|
-
throw new Error(`unknown pr subcommand: ${sub}`);
|
|
257
|
-
} catch (err) {
|
|
258
|
-
process.stderr.write(`error: ${err.message}\n`);
|
|
259
|
-
return 1;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
|
|
3
|
-
import { runPythonModule } from "./python-helper.mjs";
|
|
4
|
-
|
|
5
|
-
export const RUNTIME_AUTO = "auto";
|
|
6
|
-
|
|
7
|
-
const HOST_REQUEST_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
8
|
-
const PLAIN_TEXT_INPUT = "plain_text_input";
|
|
9
|
-
|
|
10
|
-
export class HostRegistryClientError extends Error {
|
|
11
|
-
constructor(message) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.name = "HostRegistryClientError";
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function callHosts(runPython, args) {
|
|
18
|
-
const result = await runPython({
|
|
19
|
-
module: "okstra_ctl.entrypoints.hosts",
|
|
20
|
-
args,
|
|
21
|
-
stdio: "capture",
|
|
22
|
-
});
|
|
23
|
-
if (result.code !== 0) {
|
|
24
|
-
const detail = String(result.stderr || "").trim() || `Python exited ${result.code}`;
|
|
25
|
-
throw new HostRegistryClientError(detail);
|
|
26
|
-
}
|
|
27
|
-
const stdout = String(result.stdout || "").trim();
|
|
28
|
-
if (!stdout) throw new HostRegistryClientError("host registry returned empty stdout");
|
|
29
|
-
try {
|
|
30
|
-
return JSON.parse(stdout);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
throw new HostRegistryClientError(`host registry returned invalid JSON: ${error.message}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function resolutionContext(env = {}, capabilities = {}) {
|
|
37
|
-
return {
|
|
38
|
-
env: { OKSTRA_RUNTIME_HOST: String(env?.OKSTRA_RUNTIME_HOST ?? "") },
|
|
39
|
-
capabilities: {
|
|
40
|
-
claudeSkillHandoff: capabilities?.claudeSkillHandoff === true,
|
|
41
|
-
tmuxAvailable: capabilities?.tmuxAvailable === true,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function createHostRegistryClient({ runPython = runPythonModule } = {}) {
|
|
47
|
-
return {
|
|
48
|
-
async catalog() {
|
|
49
|
-
return await callHosts(runPython, ["catalog", "--json"]);
|
|
50
|
-
},
|
|
51
|
-
async resolveHostRuntime({ requestedRuntime, command, env, capabilities }) {
|
|
52
|
-
return await callHosts(runPython, [
|
|
53
|
-
"resolve",
|
|
54
|
-
"--requested", requestedRuntime,
|
|
55
|
-
"--command", command,
|
|
56
|
-
"--context-json", JSON.stringify(resolutionContext(env, capabilities)),
|
|
57
|
-
]);
|
|
58
|
-
},
|
|
59
|
-
async probeHost({
|
|
60
|
-
hostRuntime,
|
|
61
|
-
entryMode,
|
|
62
|
-
projectRoot,
|
|
63
|
-
homeDir,
|
|
64
|
-
availableFunctions = [],
|
|
65
|
-
}) {
|
|
66
|
-
const args = [
|
|
67
|
-
"probe",
|
|
68
|
-
"--host", hostRuntime,
|
|
69
|
-
"--entry-mode", entryMode,
|
|
70
|
-
"--project-root", projectRoot,
|
|
71
|
-
"--home-dir", homeDir,
|
|
72
|
-
];
|
|
73
|
-
for (const availableFunction of availableFunctions) {
|
|
74
|
-
args.push("--available-function", availableFunction);
|
|
75
|
-
}
|
|
76
|
-
return await callHosts(runPython, args);
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const hostRegistryClient = createHostRegistryClient();
|
|
82
|
-
|
|
83
|
-
export function normalizeHostRequest(value) {
|
|
84
|
-
const runtime = String(value ?? "").trim() || RUNTIME_AUTO;
|
|
85
|
-
if (!HOST_REQUEST_PATTERN.test(runtime)) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
`invalid runtime '${runtime}' (expected auto, all, or a lowercase host ID)`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
return runtime;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function failedResolution(requestedRuntime, error) {
|
|
94
|
-
return {
|
|
95
|
-
ok: false,
|
|
96
|
-
requestedRuntime,
|
|
97
|
-
resolvedRuntime: null,
|
|
98
|
-
launchMode: null,
|
|
99
|
-
installTargets: [],
|
|
100
|
-
host: "unknown",
|
|
101
|
-
confidence: "low",
|
|
102
|
-
reason: error.message,
|
|
103
|
-
fallbackFrom: null,
|
|
104
|
-
warnings: [],
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function catalogResolution(catalog) {
|
|
109
|
-
const hosts = Array.isArray(catalog?.hosts) ? catalog.hosts : [];
|
|
110
|
-
const catalogHostIds = hosts.map((host) => host.id);
|
|
111
|
-
const installTargets = Array.from(new Set(
|
|
112
|
-
hosts.flatMap((host) => host.install_targets ?? host.installTargets ?? []),
|
|
113
|
-
)).sort();
|
|
114
|
-
return {
|
|
115
|
-
ok: true,
|
|
116
|
-
requestedRuntime: "all",
|
|
117
|
-
resolvedRuntime: "all",
|
|
118
|
-
launchMode: "catalog",
|
|
119
|
-
installTargets,
|
|
120
|
-
catalogHostIds,
|
|
121
|
-
host: "explicit",
|
|
122
|
-
confidence: "high",
|
|
123
|
-
reason: "All registered host runtimes requested.",
|
|
124
|
-
fallbackFrom: null,
|
|
125
|
-
warnings: [],
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export async function loadHostCatalog() {
|
|
130
|
-
return await hostRegistryClient.catalog();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export async function resolveHostRuntime(options) {
|
|
134
|
-
return await hostRegistryClient.resolveHostRuntime(options);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export async function probeHost(options) {
|
|
138
|
-
return await hostRegistryClient.probeHost(options);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export async function resolveRuntime({
|
|
142
|
-
requestedRuntime = RUNTIME_AUTO,
|
|
143
|
-
command = "run",
|
|
144
|
-
env = {},
|
|
145
|
-
capabilities = {},
|
|
146
|
-
} = {}) {
|
|
147
|
-
const request = normalizeHostRequest(requestedRuntime);
|
|
148
|
-
try {
|
|
149
|
-
if (request === "all") return catalogResolution(await loadHostCatalog());
|
|
150
|
-
return await resolveHostRuntime({
|
|
151
|
-
requestedRuntime: request,
|
|
152
|
-
command,
|
|
153
|
-
env,
|
|
154
|
-
capabilities,
|
|
155
|
-
});
|
|
156
|
-
} catch (error) {
|
|
157
|
-
if (!(error instanceof HostRegistryClientError)) throw error;
|
|
158
|
-
return failedResolution(request, error);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export async function checkRuntimeReadiness({
|
|
163
|
-
runtime,
|
|
164
|
-
projectRoot,
|
|
165
|
-
homeDir = homedir(),
|
|
166
|
-
hostRegistryClient = { probeHost },
|
|
167
|
-
}) {
|
|
168
|
-
if (!runtime) return { runtime: "auto", status: "ready", checks: [] };
|
|
169
|
-
return await hostRegistryClient.probeHost({
|
|
170
|
-
hostRuntime: runtime,
|
|
171
|
-
entryMode: "current-session",
|
|
172
|
-
projectRoot,
|
|
173
|
-
homeDir,
|
|
174
|
-
availableFunctions: [PLAIN_TEXT_INPUT],
|
|
175
|
-
});
|
|
176
|
-
}
|
package/src/lib/paths.mjs
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { homedir, tmpdir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import { getPackageRoot, getPackageVersion } from "./version.mjs";
|
|
5
|
-
|
|
6
|
-
function isStaleTmpHome(p) {
|
|
7
|
-
// tests/conftest.py creates the isolated home as `<tmp_path>/.okstra-isolated`
|
|
8
|
-
// under the system temp dir. Only a deleted one (env leaked, dir gone) heals;
|
|
9
|
-
// a soon-to-be-created `.okstra` temp home or a custom home is left untouched.
|
|
10
|
-
if (!p.endsWith("/.okstra-isolated")) return false;
|
|
11
|
-
const roots = [tmpdir(), "/tmp", "/private/tmp", "/var/folders", "/private/var/folders"];
|
|
12
|
-
return roots.some(
|
|
13
|
-
(r) => r && (p === r || p.startsWith(r.replace(/\/+$/, "") + "/")),
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Resolve OKSTRA_HOME, healing a leaked value: when it points at a missing
|
|
18
|
-
// system-temp path (e.g. a deleted pytest-isolated home), warn and fall back
|
|
19
|
-
// to ~/.okstra instead of operating on the dead directory.
|
|
20
|
-
export function resolveOkstraHome() {
|
|
21
|
-
const raw = process.env.OKSTRA_HOME?.trim();
|
|
22
|
-
if (!raw) return join(homedir(), ".okstra");
|
|
23
|
-
if (!existsSync(raw) && isStaleTmpHome(raw)) {
|
|
24
|
-
process.stderr.write(
|
|
25
|
-
`⚠ OKSTRA_HOME=${raw} points to a missing temp dir (leaked test value); falling back to ~/.okstra\n`,
|
|
26
|
-
);
|
|
27
|
-
return join(homedir(), ".okstra");
|
|
28
|
-
}
|
|
29
|
-
return raw;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function resolvePaths() {
|
|
33
|
-
const home = resolveOkstraHome();
|
|
34
|
-
const pkgRoot = getPackageRoot();
|
|
35
|
-
const devLink = await readSimpleFile(join(home, "dev-link"));
|
|
36
|
-
const runtimeRoot = devLink || join(pkgRoot, "runtime");
|
|
37
|
-
return {
|
|
38
|
-
agents: join(runtimeRoot, "agents"),
|
|
39
|
-
workspace: runtimeRoot,
|
|
40
|
-
pythonpath: join(home, "lib", "python"),
|
|
41
|
-
bin: join(home, "bin"),
|
|
42
|
-
home,
|
|
43
|
-
package: await getPackageVersion(),
|
|
44
|
-
version: await readSimpleFile(join(home, "version")),
|
|
45
|
-
"dev-link": devLink || "",
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function workspacePythonpath(paths) {
|
|
50
|
-
const candidates = [
|
|
51
|
-
join(paths.workspace, "python"),
|
|
52
|
-
join(paths.workspace, "scripts"),
|
|
53
|
-
];
|
|
54
|
-
return candidates.find((candidate) => existsSync(candidate)) || "";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Compose the PYTHONPATH spawned python3 subprocesses should see.
|
|
58
|
-
//
|
|
59
|
-
// Precedence (first wins):
|
|
60
|
-
// 1. process.env.PYTHONPATH (user override — e.g. in-repo `PYTHONPATH=scripts`
|
|
61
|
-
// for dev work without re-running `okstra install`).
|
|
62
|
-
// 2. The package/dev-link workspace runtime selected by `okstra paths`.
|
|
63
|
-
// 3. The installed user-runtime path (~/.okstra/lib/python).
|
|
64
|
-
//
|
|
65
|
-
// This is a colon-joined string suitable for direct assignment into the child
|
|
66
|
-
// process env. Empty segments are dropped so a missing env var does not produce
|
|
67
|
-
// a leading ':' (which Python treats as 'current directory').
|
|
68
|
-
export function buildPythonpath(paths) {
|
|
69
|
-
const fragments = [
|
|
70
|
-
process.env.PYTHONPATH,
|
|
71
|
-
workspacePythonpath(paths),
|
|
72
|
-
paths.pythonpath,
|
|
73
|
-
].filter(
|
|
74
|
-
(s) => typeof s === "string" && s.length > 0,
|
|
75
|
-
);
|
|
76
|
-
return fragments.join(":");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function readSimpleFile(path) {
|
|
80
|
-
try {
|
|
81
|
-
const { readFile } = await import("node:fs/promises");
|
|
82
|
-
return (await readFile(path, "utf8")).trim();
|
|
83
|
-
} catch {
|
|
84
|
-
return "";
|
|
85
|
-
}
|
|
86
|
-
}
|
package/src/lib/proc.mjs
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Shared filesystem / subprocess helpers used by the Node command modules.
|
|
2
|
-
// Extracted to one place so a fix lands once instead of in each command file.
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import { promises as fs } from "node:fs";
|
|
5
|
-
|
|
6
|
-
export async function fileExists(p) {
|
|
7
|
-
try {
|
|
8
|
-
await fs.access(p);
|
|
9
|
-
return true;
|
|
10
|
-
} catch {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Run `cmd args`, capturing stdout/stderr. `env` holds *additional* vars that
|
|
16
|
-
// are merged over the inherited process.env. Never rejects — failures resolve
|
|
17
|
-
// with { code: -1, stderr: <message> }.
|
|
18
|
-
export function runProcess(cmd, args, env = {}) {
|
|
19
|
-
return new Promise((resolve) => {
|
|
20
|
-
const child = spawn(cmd, args, {
|
|
21
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
22
|
-
env: { ...process.env, ...env },
|
|
23
|
-
});
|
|
24
|
-
let stdout = "";
|
|
25
|
-
let stderr = "";
|
|
26
|
-
child.stdout.on("data", (b) => (stdout += b.toString()));
|
|
27
|
-
child.stderr.on("data", (b) => (stderr += b.toString()));
|
|
28
|
-
child.on("error", (err) => resolve({ code: -1, stdout, stderr: err.message }));
|
|
29
|
-
child.on("close", (code) => resolve({ code, stdout, stderr }));
|
|
30
|
-
});
|
|
31
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { join, resolve as resolvePath } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { buildPythonpath, resolvePaths } from "./paths.mjs";
|
|
6
|
-
|
|
7
|
-
export function resolveInstalledScript(paths, scriptName) {
|
|
8
|
-
// Prefer the installed copy under ~/.okstra/bin (what production users run);
|
|
9
|
-
// fall back to the in-repo source when invoked from a checkout that has not
|
|
10
|
-
// been installed (dev / CI).
|
|
11
|
-
const installed = join(paths.bin, scriptName);
|
|
12
|
-
if (existsSync(installed)) return installed;
|
|
13
|
-
const repoRoot = fileURLToPath(new URL("../..", import.meta.url));
|
|
14
|
-
const dev = resolvePath(repoRoot, "scripts", scriptName);
|
|
15
|
-
return existsSync(dev) ? dev : null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function resolveInstalledValidator(paths, validatorName) {
|
|
19
|
-
// `okstra install` lands the validators tree at ~/.okstra/lib/validators;
|
|
20
|
-
// a checkout that has not been installed still has the in-repo source.
|
|
21
|
-
const installed = join(paths.home, "lib", "validators", validatorName);
|
|
22
|
-
if (existsSync(installed)) return installed;
|
|
23
|
-
const repoRoot = fileURLToPath(new URL("../..", import.meta.url));
|
|
24
|
-
const dev = resolvePath(repoRoot, "validators", validatorName);
|
|
25
|
-
return existsSync(dev) ? dev : null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function spawnPythonEntry(entry, args, paths) {
|
|
29
|
-
return await new Promise((resolve) => {
|
|
30
|
-
const child = spawn("python3", [entry, ...args], {
|
|
31
|
-
stdio: "inherit",
|
|
32
|
-
env: { ...process.env, PYTHONPATH: buildPythonpath(paths) },
|
|
33
|
-
});
|
|
34
|
-
child.on("error", (err) => {
|
|
35
|
-
process.stderr.write(`error: failed to spawn python3: ${err.message}\n`);
|
|
36
|
-
resolve(1);
|
|
37
|
-
});
|
|
38
|
-
child.on("close", (code) => resolve(typeof code === "number" ? code : 1));
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Thin spawn shim shared by every `okstra <cmd>` subcommand that fronts a
|
|
43
|
-
// `scripts/okstra-*.py` entry point. Centralizing it keeps PYTHONPATH wiring
|
|
44
|
-
// and installed/dev resolution in one place so skills call `okstra <cmd>`
|
|
45
|
-
// instead of emitting `python3 "$HOME/..."` (which breaks `Bash(okstra:*)`
|
|
46
|
-
// permission matching and prompts on every call).
|
|
47
|
-
export async function runInstalledScript({ scriptName, args, usage, emptyArgsCode = 2 }) {
|
|
48
|
-
if (args.length === 0) {
|
|
49
|
-
process.stdout.write(usage);
|
|
50
|
-
return emptyArgsCode;
|
|
51
|
-
}
|
|
52
|
-
// Only a bare `--help` / `-h` prints the wrapper usage. A `--help` that
|
|
53
|
-
// follows a subcommand (e.g. `error-log append-observed --help`) must reach
|
|
54
|
-
// the python helper so its own per-subcommand help shows through.
|
|
55
|
-
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
56
|
-
process.stdout.write(usage);
|
|
57
|
-
return 0;
|
|
58
|
-
}
|
|
59
|
-
const paths = await resolvePaths();
|
|
60
|
-
const entry = resolveInstalledScript(paths, scriptName);
|
|
61
|
-
if (!entry) {
|
|
62
|
-
process.stderr.write(
|
|
63
|
-
`error: ${scriptName} not found — run 'okstra install' (or 'okstra ensure-installed') first\n`,
|
|
64
|
-
);
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
return await spawnPythonEntry(entry, args, paths);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export async function runInstalledValidator({ validatorName, args }) {
|
|
71
|
-
const paths = await resolvePaths();
|
|
72
|
-
const entry = resolveInstalledValidator(paths, validatorName);
|
|
73
|
-
if (!entry) {
|
|
74
|
-
process.stderr.write(
|
|
75
|
-
`error: ${validatorName} not found — run 'okstra install' (or 'okstra ensure-installed') first\n`,
|
|
76
|
-
);
|
|
77
|
-
return 1;
|
|
78
|
-
}
|
|
79
|
-
return await spawnPythonEntry(entry, args, paths);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export async function runPythonSnippet({ script, args = [], extraEnv = {} }) {
|
|
83
|
-
const paths = await resolvePaths();
|
|
84
|
-
return new Promise((resolve) => {
|
|
85
|
-
const child = spawn("python3", ["-c", script, ...args], {
|
|
86
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
87
|
-
env: { ...process.env, PYTHONPATH: buildPythonpath(paths), ...extraEnv },
|
|
88
|
-
});
|
|
89
|
-
// Collect chunks and join once: repeated `s += chunk` is O(n^2) for the
|
|
90
|
-
// large rendered prompts some capture-mode callers stream through here.
|
|
91
|
-
const outChunks = [];
|
|
92
|
-
const errChunks = [];
|
|
93
|
-
child.stdout.on("data", (b) => outChunks.push(b));
|
|
94
|
-
child.stderr.on("data", (b) => errChunks.push(b));
|
|
95
|
-
child.on("error", (err) =>
|
|
96
|
-
resolve({ code: -1, stdout: Buffer.concat(outChunks).toString(), stderr: err.message }),
|
|
97
|
-
);
|
|
98
|
-
child.on("close", (code) =>
|
|
99
|
-
resolve({
|
|
100
|
-
code,
|
|
101
|
-
stdout: Buffer.concat(outChunks).toString(),
|
|
102
|
-
stderr: Buffer.concat(errChunks).toString(),
|
|
103
|
-
}),
|
|
104
|
-
);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export async function runPythonModule({ module, args = [], extraEnv = {}, stdio = "inherit-stdout" }) {
|
|
109
|
-
const paths = await resolvePaths();
|
|
110
|
-
return new Promise((resolve) => {
|
|
111
|
-
const child = spawn("python3", ["-m", module, ...args], {
|
|
112
|
-
stdio: stdio === "capture" ? ["ignore", "pipe", "pipe"] : ["ignore", "inherit", "inherit"],
|
|
113
|
-
env: { ...process.env, PYTHONPATH: buildPythonpath(paths), ...extraEnv },
|
|
114
|
-
});
|
|
115
|
-
// Collect chunks and join once: repeated `s += chunk` is O(n^2) for the
|
|
116
|
-
// large rendered prompts some capture-mode callers stream through here.
|
|
117
|
-
const outChunks = [];
|
|
118
|
-
const errChunks = [];
|
|
119
|
-
if (stdio === "capture") {
|
|
120
|
-
child.stdout.on("data", (b) => outChunks.push(b));
|
|
121
|
-
child.stderr.on("data", (b) => errChunks.push(b));
|
|
122
|
-
}
|
|
123
|
-
child.on("error", (err) =>
|
|
124
|
-
resolve({ code: -1, stdout: Buffer.concat(outChunks).toString(), stderr: err.message }),
|
|
125
|
-
);
|
|
126
|
-
// A signal-killed child reports code === null; normalize to a non-zero exit
|
|
127
|
-
// here so every consumer inherits correct failure semantics from one place.
|
|
128
|
-
child.on("close", (code) =>
|
|
129
|
-
resolve({
|
|
130
|
-
code: typeof code === "number" ? code : 1,
|
|
131
|
-
stdout: Buffer.concat(outChunks).toString(),
|
|
132
|
-
stderr: Buffer.concat(errChunks).toString(),
|
|
133
|
-
}),
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function emitJsonError({ stage, reason, extra = {} }) {
|
|
139
|
-
process.stdout.write(
|
|
140
|
-
JSON.stringify({ ok: false, stage, reason, ...extra }, null, 2) + "\n",
|
|
141
|
-
);
|
|
142
|
-
}
|