okstra 0.174.0 → 0.175.1
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 +4 -0
- package/docs/architecture.md +7 -1
- package/docs/cli.md +26 -6
- package/docs/contributor-change-matrix.md +2 -2
- package/docs/project-structure-overview.md +16 -7
- package/docs/task-process/README.md +2 -0
- package/docs/task-process/implementation-planning.md +1 -1
- package/docs/task-process/implementation.md +1 -1
- 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/usage.sh +4 -4
- package/runtime/bin/okstra-error-log.py +27 -0
- package/runtime/bin/okstra-provider-exec.py +217 -5
- package/runtime/bin/okstra.sh +10 -0
- package/runtime/prompts/lead/convergence.md +27 -18
- package/runtime/prompts/lead/okstra-lead-contract.md +3 -1
- package/runtime/prompts/lead/plan-body-verification.md +10 -3
- package/runtime/prompts/lead/team-contract.md +1 -1
- package/runtime/prompts/profiles/change-impact-analysis.md +16 -0
- package/runtime/prompts/profiles/error-analysis.md +20 -0
- package/runtime/prompts/profiles/feature-analysis.md +16 -0
- package/runtime/prompts/profiles/final-verification.md +16 -0
- package/runtime/prompts/profiles/implementation-option-selection.md +16 -0
- package/runtime/prompts/profiles/implementation-planning.md +20 -0
- package/runtime/prompts/profiles/implementation.md +15 -0
- package/runtime/prompts/profiles/improvement-discovery.md +16 -0
- package/runtime/prompts/profiles/project-analysis.md +16 -0
- package/runtime/prompts/profiles/release-handoff.md +4 -0
- package/runtime/prompts/profiles/requirements-discovery.md +20 -0
- package/runtime/prompts/wizard/prompts.ko.json +18 -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/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/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 +1092 -63
- 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 +32 -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 +13 -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_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/index.py +6 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +43 -3
- package/runtime/python/okstra_ctl/legacy_model_selection.py +490 -0
- 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/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/registry/provider_registry.py +8 -4
- package/runtime/python/okstra_ctl/render.py +78 -10
- 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 +217 -0
- package/runtime/python/okstra_ctl/run.py +1207 -258
- package/runtime/python/okstra_ctl/run_index_row.py +7 -1
- 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 +1253 -62
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +68 -65
- 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/write_policy.py +571 -0
- 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 +25 -0
- package/runtime/skills/okstra-run/SKILL.md +9 -9
- 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/worker-prompt-preamble.md +6 -2
- package/runtime/validators/lib/fixtures.sh +49 -16
- package/runtime/validators/validate-run.py +429 -35
- 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
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { runPythonSnippet, emitJsonError } from "../../lib/python-helper.mjs";
|
|
2
|
-
|
|
3
|
-
const USAGE = `okstra task-show — summarize a task's manifest and workflow state
|
|
4
|
-
|
|
5
|
-
Usage:
|
|
6
|
-
okstra task-show <task-key> task-key is project-id:task-group:task-id
|
|
7
|
-
okstra task-show <task-key> --cwd <dir> Resolve PROJECT_ROOT from <dir>
|
|
8
|
-
okstra task-show <task-key> --project <dir> Use <dir> directly as PROJECT_ROOT
|
|
9
|
-
|
|
10
|
-
Output: JSON with taskKey, taskType, taskRoot, brief path, workflow phases,
|
|
11
|
-
artifacts, modelAssignments, latestRunPath. Replaces the
|
|
12
|
-
\`cat task-manifest.json | python3 -c ...\` summarization pattern.
|
|
13
|
-
`;
|
|
14
|
-
|
|
15
|
-
function parseArgs(args) {
|
|
16
|
-
const opts = { cwd: process.cwd(), projectRoot: "", taskKey: "" };
|
|
17
|
-
const positional = [];
|
|
18
|
-
for (let i = 0; i < args.length; i++) {
|
|
19
|
-
const a = args[i];
|
|
20
|
-
if (a === "--cwd") {
|
|
21
|
-
opts.cwd = args[++i];
|
|
22
|
-
if (!opts.cwd) throw new Error("--cwd requires a path");
|
|
23
|
-
} else if (a === "--project") {
|
|
24
|
-
opts.projectRoot = args[++i];
|
|
25
|
-
if (!opts.projectRoot) throw new Error("--project requires a path");
|
|
26
|
-
} else if (a.startsWith("--")) {
|
|
27
|
-
throw new Error(`unknown argument '${a}'`);
|
|
28
|
-
} else {
|
|
29
|
-
positional.push(a);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (positional.length !== 1) {
|
|
33
|
-
throw new Error("expected exactly one positional argument: <task-key>");
|
|
34
|
-
}
|
|
35
|
-
opts.taskKey = positional[0];
|
|
36
|
-
return opts;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const SCRIPT = `
|
|
40
|
-
import json, sys
|
|
41
|
-
from pathlib import Path
|
|
42
|
-
from okstra_project import (
|
|
43
|
-
resolve_project_root, task_read_side_snapshot,
|
|
44
|
-
ResolverError, StateError,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
explicit = sys.argv[1]
|
|
48
|
-
cwd = sys.argv[2]
|
|
49
|
-
task_key = sys.argv[3]
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
pr = resolve_project_root(explicit_root=explicit, cwd=cwd)
|
|
53
|
-
except ResolverError as e:
|
|
54
|
-
print(json.dumps({"ok": False, "stage": "resolve", "reason": str(e)}))
|
|
55
|
-
sys.exit(2)
|
|
56
|
-
|
|
57
|
-
pr_path = Path(pr)
|
|
58
|
-
try:
|
|
59
|
-
snapshot = task_read_side_snapshot(pr_path, task_key)
|
|
60
|
-
except StateError as e:
|
|
61
|
-
print(json.dumps({
|
|
62
|
-
"ok": False,
|
|
63
|
-
"stage": getattr(e, "stage", None) or "task_snapshot",
|
|
64
|
-
"reason": str(e),
|
|
65
|
-
}))
|
|
66
|
-
sys.exit(1)
|
|
67
|
-
|
|
68
|
-
out = {"ok": True, **snapshot}
|
|
69
|
-
print(json.dumps(out, ensure_ascii=False, default=str, indent=2))
|
|
70
|
-
`;
|
|
71
|
-
|
|
72
|
-
export async function run(args) {
|
|
73
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
74
|
-
process.stdout.write(USAGE);
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
let opts;
|
|
78
|
-
try {
|
|
79
|
-
opts = parseArgs(args);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
|
|
82
|
-
return 2;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const result = await runPythonSnippet({
|
|
86
|
-
script: SCRIPT,
|
|
87
|
-
args: [opts.projectRoot, opts.cwd, opts.taskKey],
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
if (result.code !== 0 && !result.stdout.trim()) {
|
|
91
|
-
emitJsonError({
|
|
92
|
-
stage: "python",
|
|
93
|
-
reason: `python invocation failed: ${result.stderr.trim() || "no output"}`,
|
|
94
|
-
});
|
|
95
|
-
return 1;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
process.stdout.write(result.stdout);
|
|
99
|
-
return result.code === 0 ? 0 : result.code;
|
|
100
|
-
}
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { buildPythonpath, resolvePaths } from "../../lib/paths.mjs";
|
|
4
|
-
import { fileExists, runProcess } from "../../lib/proc.mjs";
|
|
5
|
-
|
|
6
|
-
const USAGE = `okstra check-project — verify that the current project has okstra setup
|
|
7
|
-
|
|
8
|
-
Usage:
|
|
9
|
-
okstra check-project Resolve PROJECT_ROOT from cwd, look for
|
|
10
|
-
.okstra/project.json,
|
|
11
|
-
print JSON status to stdout.
|
|
12
|
-
okstra check-project --cwd <dir> Use <dir> as the search starting point
|
|
13
|
-
instead of process cwd.
|
|
14
|
-
okstra check-project --json Same as default (kept for symmetry with
|
|
15
|
-
'paths --json').
|
|
16
|
-
okstra check-project --quiet Suppress stdout on success; exit code
|
|
17
|
-
alone reports state.
|
|
18
|
-
|
|
19
|
-
Exit codes:
|
|
20
|
-
0 project.json found, projectId present
|
|
21
|
-
1 project.json missing or unreadable (project setup not done)
|
|
22
|
-
2 PROJECT_ROOT could not be resolved from cwd (no project marker
|
|
23
|
-
ancestor; user should pass --cwd or run from within a project)
|
|
24
|
-
|
|
25
|
-
User-facing skills should call this after 'ensure-installed' and refuse
|
|
26
|
-
to proceed if the exit code is non-zero, directing the user to
|
|
27
|
-
'/okstra-setup' first.
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
function parseArgs(args) {
|
|
31
|
-
const opts = { cwd: process.cwd(), quiet: false, json: true };
|
|
32
|
-
for (let i = 0; i < args.length; i++) {
|
|
33
|
-
const a = args[i];
|
|
34
|
-
if (a === "--quiet" || a === "-q") opts.quiet = true;
|
|
35
|
-
else if (a === "--json") opts.json = true;
|
|
36
|
-
else if (a === "--cwd") {
|
|
37
|
-
const next = args[i + 1];
|
|
38
|
-
if (!next || next.startsWith("--")) throw new Error("--cwd requires a path");
|
|
39
|
-
opts.cwd = next;
|
|
40
|
-
i++;
|
|
41
|
-
} else {
|
|
42
|
-
throw new Error(`unknown argument '${a}'`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return opts;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function emit(opts, payload) {
|
|
49
|
-
if (opts.quiet) return;
|
|
50
|
-
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function run(args) {
|
|
54
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
55
|
-
process.stdout.write(USAGE);
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let opts;
|
|
60
|
-
try {
|
|
61
|
-
opts = parseArgs(args);
|
|
62
|
-
} catch (err) {
|
|
63
|
-
process.stderr.write(`error: ${err.message}\n\n${USAGE}`);
|
|
64
|
-
return 2;
|
|
65
|
-
}
|
|
66
|
-
const { code, payload } = await checkProject({ cwd: opts.cwd });
|
|
67
|
-
emit(opts, payload);
|
|
68
|
-
return code;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Core check shared with 'okstra preflight' — resolves PROJECT_ROOT from cwd
|
|
72
|
-
// and validates .okstra/project.json without writing to stdout.
|
|
73
|
-
export async function checkProject({ cwd = process.cwd() } = {}) {
|
|
74
|
-
const paths = await resolvePaths();
|
|
75
|
-
|
|
76
|
-
const probe = await runProcess(
|
|
77
|
-
"python3",
|
|
78
|
-
[
|
|
79
|
-
"-c",
|
|
80
|
-
[
|
|
81
|
-
"import json, sys",
|
|
82
|
-
"from okstra_project import resolve_project_root, project_json_path, ResolverError",
|
|
83
|
-
"try:",
|
|
84
|
-
" pr = resolve_project_root(explicit_root='', cwd=sys.argv[1])",
|
|
85
|
-
" print('PROJECT_ROOT', pr)",
|
|
86
|
-
" print('PROJECT_JSON', project_json_path(pr))",
|
|
87
|
-
"except ResolverError as e:",
|
|
88
|
-
" print('RESOLVER_ERROR', e)",
|
|
89
|
-
].join("\n"),
|
|
90
|
-
cwd,
|
|
91
|
-
],
|
|
92
|
-
{ PYTHONPATH: buildPythonpath(paths) },
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
if (probe.code !== 0) {
|
|
96
|
-
const raw = probe.stderr.trim() || probe.stdout.trim();
|
|
97
|
-
return {
|
|
98
|
-
code: 1,
|
|
99
|
-
payload: {
|
|
100
|
-
ok: false,
|
|
101
|
-
stage: "python",
|
|
102
|
-
reason:
|
|
103
|
-
`python invocation failed: ${raw}. ` +
|
|
104
|
-
"This usually means the okstra runtime is stale or missing — " +
|
|
105
|
-
"run 'okstra doctor' to diagnose, then 'okstra ensure-installed' " +
|
|
106
|
-
"to repair.",
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const lines = probe.stdout.trim().split("\n");
|
|
112
|
-
const tagOf = (key) =>
|
|
113
|
-
lines
|
|
114
|
-
.find((l) => l.startsWith(key + " "))
|
|
115
|
-
?.slice(key.length + 1)
|
|
116
|
-
.trim() ?? null;
|
|
117
|
-
|
|
118
|
-
const resolverError = tagOf("RESOLVER_ERROR");
|
|
119
|
-
if (resolverError) {
|
|
120
|
-
return {
|
|
121
|
-
code: 2,
|
|
122
|
-
payload: { ok: false, stage: "resolve", reason: resolverError, cwd },
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const projectRoot = tagOf("PROJECT_ROOT");
|
|
127
|
-
const projectJsonPath = tagOf("PROJECT_JSON");
|
|
128
|
-
if (!projectRoot || !projectJsonPath) {
|
|
129
|
-
return {
|
|
130
|
-
code: 1,
|
|
131
|
-
payload: {
|
|
132
|
-
ok: false,
|
|
133
|
-
stage: "parse",
|
|
134
|
-
reason: "could not parse python output",
|
|
135
|
-
raw: probe.stdout,
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!(await fileExists(projectJsonPath))) {
|
|
141
|
-
return {
|
|
142
|
-
code: 1,
|
|
143
|
-
payload: {
|
|
144
|
-
ok: false,
|
|
145
|
-
stage: "project_json_missing",
|
|
146
|
-
reason: `${projectJsonPath} not found — run /okstra-setup in this project first`,
|
|
147
|
-
projectRoot,
|
|
148
|
-
projectJsonPath,
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
let projectId = null;
|
|
154
|
-
try {
|
|
155
|
-
const data = JSON.parse(await fs.readFile(projectJsonPath, "utf8"));
|
|
156
|
-
projectId = typeof data?.projectId === "string" ? data.projectId : null;
|
|
157
|
-
} catch (err) {
|
|
158
|
-
return {
|
|
159
|
-
code: 1,
|
|
160
|
-
payload: {
|
|
161
|
-
ok: false,
|
|
162
|
-
stage: "project_json_invalid",
|
|
163
|
-
reason: `failed to parse ${projectJsonPath}: ${err.message}`,
|
|
164
|
-
projectRoot,
|
|
165
|
-
projectJsonPath,
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (!projectId) {
|
|
171
|
-
return {
|
|
172
|
-
code: 1,
|
|
173
|
-
payload: {
|
|
174
|
-
ok: false,
|
|
175
|
-
stage: "project_json_invalid",
|
|
176
|
-
reason: `${projectJsonPath} missing projectId field`,
|
|
177
|
-
projectRoot,
|
|
178
|
-
projectJsonPath,
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
code: 0,
|
|
185
|
-
payload: { ok: true, projectRoot, projectJsonPath, projectId },
|
|
186
|
-
};
|
|
187
|
-
}
|
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import { dirname, join, resolve, isAbsolute } from "node:path";
|
|
3
|
-
import { buildPythonpath, resolvePaths, resolveOkstraHome } from "../../lib/paths.mjs";
|
|
4
|
-
import { OKSTRA_DIR, projectJsonPath } from "../../lib/okstra-dirs.mjs";
|
|
5
|
-
import { fileExists, runProcess } from "../../lib/proc.mjs";
|
|
6
|
-
|
|
7
|
-
const USAGE = `okstra config — read / write okstra settings (project + global scopes)
|
|
8
|
-
|
|
9
|
-
Settings are persisted as JSON keys in one of two files:
|
|
10
|
-
project: <project-root>/${OKSTRA_DIR}/project.json
|
|
11
|
-
global: ~/.okstra/config.json
|
|
12
|
-
|
|
13
|
-
Supported keys (CLI alias -> JSON field):
|
|
14
|
-
pr-template-path -> prTemplatePath
|
|
15
|
-
PR body template used by the release-handoff phase.
|
|
16
|
-
Path may be absolute, ~/-prefixed, or (project scope
|
|
17
|
-
only) relative to <project-root>.
|
|
18
|
-
|
|
19
|
-
report-language -> reportLanguage
|
|
20
|
-
Final-report language. One of: en, ko, auto.
|
|
21
|
-
'auto' is resolved by the report-writer lead from
|
|
22
|
-
the task brief at run time.
|
|
23
|
-
|
|
24
|
-
Usage:
|
|
25
|
-
okstra config get <key> [--scope project|global|all]
|
|
26
|
-
Print the value at the requested scope.
|
|
27
|
-
'all' prints every scope, plus the effective resolved value where
|
|
28
|
-
available (for pr-template-path the resolver may fall back to the
|
|
29
|
-
bundled skill default).
|
|
30
|
-
|
|
31
|
-
okstra config set <key> <value> [--scope project|global]
|
|
32
|
-
Write the value. Scope is required unless cwd is inside an okstra
|
|
33
|
-
project (then defaults to 'project'). Global scope only accepts
|
|
34
|
-
absolute or ~/-prefixed paths.
|
|
35
|
-
|
|
36
|
-
okstra config unset <key> [--scope project|global]
|
|
37
|
-
Remove the key from the chosen scope.
|
|
38
|
-
|
|
39
|
-
okstra config show [--scope project|global|all]
|
|
40
|
-
Dump every okstra-managed key from the chosen scope as JSON.
|
|
41
|
-
|
|
42
|
-
Common options:
|
|
43
|
-
--cwd <dir> Search starting point for project root (default: pwd)
|
|
44
|
-
--json Force JSON output for get/show (default for show)
|
|
45
|
-
--quiet Suppress informational stdout on set/unset; exit
|
|
46
|
-
code alone reports success
|
|
47
|
-
`;
|
|
48
|
-
|
|
49
|
-
// CLI-key -> { jsonField, scopes, validate }
|
|
50
|
-
// validate(value, ctx) returns null on success or an error string.
|
|
51
|
-
const KEYS = {
|
|
52
|
-
"pr-template-path": {
|
|
53
|
-
jsonField: "prTemplatePath",
|
|
54
|
-
scopes: ["project", "global"],
|
|
55
|
-
validate(value, ctx) {
|
|
56
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
57
|
-
return "value must be a non-empty path";
|
|
58
|
-
}
|
|
59
|
-
const v = value.trim();
|
|
60
|
-
if (ctx.scope === "global") {
|
|
61
|
-
if (!v.startsWith("~/") && !v.startsWith("~\\") && !isAbsolute(v)) {
|
|
62
|
-
return (
|
|
63
|
-
"global scope requires an absolute path or '~/'-prefixed path " +
|
|
64
|
-
`(got ${JSON.stringify(v)}). Use --scope project for project-root-relative paths.`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
"report-language": {
|
|
72
|
-
jsonField: "reportLanguage",
|
|
73
|
-
scopes: ["project", "global"],
|
|
74
|
-
validate(value) {
|
|
75
|
-
const allowed = new Set(["en", "ko", "auto"]);
|
|
76
|
-
if (typeof value !== "string" || !allowed.has(value)) {
|
|
77
|
-
return (
|
|
78
|
-
`value must be one of: en, ko, auto (got ${JSON.stringify(value)})`
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
function parseArgs(args) {
|
|
87
|
-
const opts = {
|
|
88
|
-
op: null,
|
|
89
|
-
key: null,
|
|
90
|
-
value: null,
|
|
91
|
-
scope: null,
|
|
92
|
-
cwd: process.cwd(),
|
|
93
|
-
json: false,
|
|
94
|
-
quiet: false,
|
|
95
|
-
};
|
|
96
|
-
const positional = [];
|
|
97
|
-
for (let i = 0; i < args.length; i++) {
|
|
98
|
-
const a = args[i];
|
|
99
|
-
if (a === "--scope") {
|
|
100
|
-
const next = args[i + 1];
|
|
101
|
-
if (!next) throw new Error("--scope requires a value (project|global|all)");
|
|
102
|
-
opts.scope = next;
|
|
103
|
-
i++;
|
|
104
|
-
} else if (a === "--cwd") {
|
|
105
|
-
const next = args[i + 1];
|
|
106
|
-
if (!next) throw new Error("--cwd requires a path");
|
|
107
|
-
opts.cwd = next;
|
|
108
|
-
i++;
|
|
109
|
-
} else if (a === "--json") {
|
|
110
|
-
opts.json = true;
|
|
111
|
-
} else if (a === "--quiet" || a === "-q") {
|
|
112
|
-
opts.quiet = true;
|
|
113
|
-
} else if (a.startsWith("--")) {
|
|
114
|
-
throw new Error(`unknown flag ${a}`);
|
|
115
|
-
} else {
|
|
116
|
-
positional.push(a);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
opts.op = positional[0] ?? null;
|
|
120
|
-
opts.key = positional[1] ?? null;
|
|
121
|
-
opts.value = positional[2] ?? null;
|
|
122
|
-
return opts;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function okstraHome() {
|
|
126
|
-
return resolveOkstraHome();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function globalConfigPath() {
|
|
130
|
-
return join(okstraHome(), "config.json");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function projectConfigPath(projectRoot) {
|
|
134
|
-
return projectJsonPath(projectRoot);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async function readJson(p) {
|
|
138
|
-
if (!(await fileExists(p))) return null;
|
|
139
|
-
const text = await fs.readFile(p, "utf8");
|
|
140
|
-
try {
|
|
141
|
-
const data = JSON.parse(text);
|
|
142
|
-
return typeof data === "object" && data !== null ? data : {};
|
|
143
|
-
} catch (err) {
|
|
144
|
-
throw new Error(`failed to parse ${p}: ${err.message}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async function writeJsonAtomic(p, data) {
|
|
149
|
-
await fs.mkdir(dirname(p), { recursive: true });
|
|
150
|
-
const tmp = `${p}.tmp.${process.pid}`;
|
|
151
|
-
await fs.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
152
|
-
await fs.rename(tmp, p);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async function resolveProjectRoot(cwd) {
|
|
156
|
-
const paths = await resolvePaths();
|
|
157
|
-
const result = await runProcess(
|
|
158
|
-
"python3",
|
|
159
|
-
[
|
|
160
|
-
"-c",
|
|
161
|
-
[
|
|
162
|
-
"import sys",
|
|
163
|
-
"from okstra_project import resolve_project_root, ResolverError",
|
|
164
|
-
"try:",
|
|
165
|
-
" print(resolve_project_root(explicit_root='', cwd=sys.argv[1]))",
|
|
166
|
-
"except ResolverError as e:",
|
|
167
|
-
" sys.stderr.write(str(e)+'\\n'); sys.exit(2)",
|
|
168
|
-
].join("\n"),
|
|
169
|
-
cwd,
|
|
170
|
-
],
|
|
171
|
-
{ PYTHONPATH: buildPythonpath(paths) },
|
|
172
|
-
);
|
|
173
|
-
if (result.code === 0) return result.stdout.trim();
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function emit(opts, payload) {
|
|
178
|
-
if (opts.quiet) return;
|
|
179
|
-
if (opts.json || typeof payload !== "string") {
|
|
180
|
-
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
181
|
-
} else {
|
|
182
|
-
process.stdout.write(`${payload}\n`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async function effectivePrTemplatePath(projectRoot) {
|
|
187
|
-
// Mirror the python resolver order without depending on it for the simple
|
|
188
|
-
// case where we just want to surface the chain in 'config get --scope all'.
|
|
189
|
-
// Python remains the source of truth at run time; this is informational.
|
|
190
|
-
const paths = await resolvePaths();
|
|
191
|
-
const result = await runProcess(
|
|
192
|
-
"python3",
|
|
193
|
-
[
|
|
194
|
-
"-c",
|
|
195
|
-
[
|
|
196
|
-
"import json, sys",
|
|
197
|
-
"from pathlib import Path",
|
|
198
|
-
"from okstra_ctl.pr_template import resolve_pr_template_path, PrTemplateError",
|
|
199
|
-
"try:",
|
|
200
|
-
" r = resolve_pr_template_path(Path(sys.argv[1]))",
|
|
201
|
-
" print(json.dumps({'ok': True, 'path': str(r.path), 'source': r.source}))",
|
|
202
|
-
"except PrTemplateError as e:",
|
|
203
|
-
" print(json.dumps({'ok': False, 'reason': str(e)}))",
|
|
204
|
-
].join("\n"),
|
|
205
|
-
projectRoot ?? process.cwd(),
|
|
206
|
-
],
|
|
207
|
-
{ PYTHONPATH: buildPythonpath(paths) },
|
|
208
|
-
);
|
|
209
|
-
if (result.code !== 0) return null;
|
|
210
|
-
try {
|
|
211
|
-
return JSON.parse(result.stdout.trim());
|
|
212
|
-
} catch {
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function opGet(opts) {
|
|
218
|
-
const spec = KEYS[opts.key];
|
|
219
|
-
const scope = opts.scope ?? "all";
|
|
220
|
-
const projectRoot = await resolveProjectRoot(opts.cwd);
|
|
221
|
-
|
|
222
|
-
const out = {};
|
|
223
|
-
if (scope === "project" || scope === "all") {
|
|
224
|
-
if (!projectRoot) {
|
|
225
|
-
out.project = { available: false, reason: "cwd not inside an okstra project" };
|
|
226
|
-
} else {
|
|
227
|
-
const cfg = (await readJson(projectConfigPath(projectRoot))) ?? {};
|
|
228
|
-
out.project = {
|
|
229
|
-
available: true,
|
|
230
|
-
path: projectConfigPath(projectRoot),
|
|
231
|
-
value: cfg[spec.jsonField] ?? null,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
if (scope === "global" || scope === "all") {
|
|
236
|
-
const cfg = (await readJson(globalConfigPath())) ?? {};
|
|
237
|
-
out.global = {
|
|
238
|
-
available: true,
|
|
239
|
-
path: globalConfigPath(),
|
|
240
|
-
value: cfg[spec.jsonField] ?? null,
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (scope === "all" && opts.key === "pr-template-path") {
|
|
245
|
-
const effective = await effectivePrTemplatePath(projectRoot);
|
|
246
|
-
if (effective) out.effective = effective;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (scope !== "all" && !opts.json) {
|
|
250
|
-
const entry = out[scope];
|
|
251
|
-
if (entry?.available && entry.value !== null) {
|
|
252
|
-
emit(opts, entry.value);
|
|
253
|
-
} else {
|
|
254
|
-
emit(opts, "");
|
|
255
|
-
}
|
|
256
|
-
return 0;
|
|
257
|
-
}
|
|
258
|
-
emit(opts, out);
|
|
259
|
-
return 0;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
async function opSet(opts) {
|
|
263
|
-
const spec = KEYS[opts.key];
|
|
264
|
-
if (opts.value === null) throw new Error(`'config set ${opts.key}' requires a value argument`);
|
|
265
|
-
let scope = opts.scope;
|
|
266
|
-
const projectRoot = await resolveProjectRoot(opts.cwd);
|
|
267
|
-
if (!scope) {
|
|
268
|
-
scope = projectRoot ? "project" : null;
|
|
269
|
-
if (!scope) {
|
|
270
|
-
throw new Error(
|
|
271
|
-
"--scope is required when cwd is not inside an okstra project. " +
|
|
272
|
-
"Pass --scope project or --scope global.",
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (!spec.scopes.includes(scope)) {
|
|
277
|
-
throw new Error(`key '${opts.key}' does not support scope '${scope}'`);
|
|
278
|
-
}
|
|
279
|
-
const ctx = { scope, projectRoot };
|
|
280
|
-
const err = spec.validate(opts.value, ctx);
|
|
281
|
-
if (err) throw new Error(err);
|
|
282
|
-
|
|
283
|
-
if (scope === "project" && !projectRoot) {
|
|
284
|
-
throw new Error("cwd not inside an okstra project — cannot write project scope");
|
|
285
|
-
}
|
|
286
|
-
const targetPath =
|
|
287
|
-
scope === "project" ? projectConfigPath(projectRoot) : globalConfigPath();
|
|
288
|
-
const existing = (await readJson(targetPath)) ?? {};
|
|
289
|
-
existing[spec.jsonField] = opts.value;
|
|
290
|
-
await writeJsonAtomic(targetPath, existing);
|
|
291
|
-
emit(opts, { ok: true, scope, path: targetPath, key: opts.key, value: opts.value });
|
|
292
|
-
return 0;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
async function opUnset(opts) {
|
|
296
|
-
const spec = KEYS[opts.key];
|
|
297
|
-
let scope = opts.scope;
|
|
298
|
-
const projectRoot = await resolveProjectRoot(opts.cwd);
|
|
299
|
-
if (!scope) {
|
|
300
|
-
scope = projectRoot ? "project" : null;
|
|
301
|
-
if (!scope) throw new Error("--scope is required (project|global)");
|
|
302
|
-
}
|
|
303
|
-
if (scope === "project" && !projectRoot) {
|
|
304
|
-
throw new Error("cwd not inside an okstra project — cannot unset project scope");
|
|
305
|
-
}
|
|
306
|
-
const targetPath =
|
|
307
|
-
scope === "project" ? projectConfigPath(projectRoot) : globalConfigPath();
|
|
308
|
-
const existing = (await readJson(targetPath)) ?? {};
|
|
309
|
-
if (!(spec.jsonField in existing)) {
|
|
310
|
-
emit(opts, { ok: true, scope, path: targetPath, key: opts.key, removed: false });
|
|
311
|
-
return 0;
|
|
312
|
-
}
|
|
313
|
-
delete existing[spec.jsonField];
|
|
314
|
-
await writeJsonAtomic(targetPath, existing);
|
|
315
|
-
emit(opts, { ok: true, scope, path: targetPath, key: opts.key, removed: true });
|
|
316
|
-
return 0;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
async function opShow(opts) {
|
|
320
|
-
const scope = opts.scope ?? "all";
|
|
321
|
-
const projectRoot = await resolveProjectRoot(opts.cwd);
|
|
322
|
-
const out = {};
|
|
323
|
-
if (scope === "project" || scope === "all") {
|
|
324
|
-
out.project = projectRoot
|
|
325
|
-
? {
|
|
326
|
-
path: projectConfigPath(projectRoot),
|
|
327
|
-
data: (await readJson(projectConfigPath(projectRoot))) ?? {},
|
|
328
|
-
}
|
|
329
|
-
: { available: false, reason: "cwd not inside an okstra project" };
|
|
330
|
-
}
|
|
331
|
-
if (scope === "global" || scope === "all") {
|
|
332
|
-
out.global = {
|
|
333
|
-
path: globalConfigPath(),
|
|
334
|
-
data: (await readJson(globalConfigPath())) ?? {},
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
emit({ ...opts, json: true }, out);
|
|
338
|
-
return 0;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export async function run(args) {
|
|
342
|
-
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
343
|
-
process.stdout.write(USAGE);
|
|
344
|
-
return args.length === 0 ? 2 : 0;
|
|
345
|
-
}
|
|
346
|
-
const opts = parseArgs(args);
|
|
347
|
-
if (!opts.op) {
|
|
348
|
-
process.stderr.write("missing subcommand (get|set|unset|show)\n");
|
|
349
|
-
return 2;
|
|
350
|
-
}
|
|
351
|
-
if (opts.scope !== null && !["project", "global", "all"].includes(opts.scope)) {
|
|
352
|
-
process.stderr.write(`invalid --scope: ${opts.scope}\n`);
|
|
353
|
-
return 2;
|
|
354
|
-
}
|
|
355
|
-
if (["get", "set", "unset"].includes(opts.op)) {
|
|
356
|
-
if (!opts.key) {
|
|
357
|
-
process.stderr.write(`'config ${opts.op}' requires a key argument\n`);
|
|
358
|
-
return 2;
|
|
359
|
-
}
|
|
360
|
-
if (!KEYS[opts.key]) {
|
|
361
|
-
process.stderr.write(
|
|
362
|
-
`unknown key '${opts.key}'. Supported: ${Object.keys(KEYS).join(", ")}\n`,
|
|
363
|
-
);
|
|
364
|
-
return 2;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
try {
|
|
368
|
-
switch (opts.op) {
|
|
369
|
-
case "get":
|
|
370
|
-
return await opGet(opts);
|
|
371
|
-
case "set":
|
|
372
|
-
return await opSet(opts);
|
|
373
|
-
case "unset":
|
|
374
|
-
return await opUnset(opts);
|
|
375
|
-
case "show":
|
|
376
|
-
return await opShow(opts);
|
|
377
|
-
default:
|
|
378
|
-
process.stderr.write(`unknown subcommand '${opts.op}'\n`);
|
|
379
|
-
return 2;
|
|
380
|
-
}
|
|
381
|
-
} catch (err) {
|
|
382
|
-
process.stderr.write(`error: ${err.message}\n`);
|
|
383
|
-
return 1;
|
|
384
|
-
}
|
|
385
|
-
}
|