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
|
@@ -12,7 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import json
|
|
14
14
|
import re
|
|
15
|
-
from collections.abc import Mapping
|
|
15
|
+
from collections.abc import Mapping
|
|
16
16
|
from dataclasses import dataclass
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
@@ -45,25 +45,26 @@ _EVIDENCE_COMMAND_RE = re.compile(
|
|
|
45
45
|
r"^- Evidence command:[ \t]*(?P<payload>.*)$", re.MULTILINE
|
|
46
46
|
)
|
|
47
47
|
_EVIDENCE_COMMAND_FIELDS = ("command", "cwd", "exitCode", "outputSummary")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
r"(?i)(authorization\s*:\s*\S+|"
|
|
55
|
-
r"\b(?:[A-Za-z_][A-Za-z0-9_-]*)?(?:auth|credential|pass(?:wd|word)?|pwd|"
|
|
56
|
-
r"token|secret|api[_-]?key|access[_-]?key)[A-Za-z0-9_-]*\s*=|"
|
|
57
|
-
r"--[\w-]*(?:auth|credential|pass(?:wd|word)?|pwd|token|secret|"
|
|
58
|
-
r"api[-_]?key|access[-_]?key)[\w-]*(?:[ =])\S+|"
|
|
59
|
-
r"\w+://[^\s:/@]+:[^\s@/]+@)"
|
|
60
|
-
)
|
|
61
|
-
_KNOWN_SECRET_RE = re.compile(
|
|
62
|
-
r"(?:AKIA|ASIA)[0-9A-Z]{16}|gh[pousr]_[A-Za-z0-9_]{8,}|"
|
|
63
|
-
r"github_pat_[A-Za-z0-9_]{8,}|xox[abprs]-[A-Za-z0-9-]{8,}|"
|
|
64
|
-
r"\bsk-[A-Za-z0-9_-]{8,}\b|"
|
|
65
|
-
r"\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b"
|
|
48
|
+
_EVIDENCE_COMMAND_IDENTITY_FIELDS = (
|
|
49
|
+
"participantRef",
|
|
50
|
+
"roleExecutionRef",
|
|
51
|
+
"invocationRef",
|
|
52
|
+
"attempt",
|
|
53
|
+
"executionLabel",
|
|
66
54
|
)
|
|
55
|
+
_EVIDENCE_COMMAND_STRING_FIELDS = ("command", "cwd", "outputSummary")
|
|
56
|
+
# There is deliberately no secret detector here.
|
|
57
|
+
#
|
|
58
|
+
# One lived on this path and only ever cost runs. It matched the *name* half of
|
|
59
|
+
# an assignment, so `AUTH_MODE=off` and `TOKEN_TTL=60` were "sensitive material"
|
|
60
|
+
# and the row was refused; a worker that cannot record the command it ran has no
|
|
61
|
+
# way to satisfy the evidence ledger that demands it, and the run ends
|
|
62
|
+
# `contract-violated` over a switch. Judging the value half instead only moves
|
|
63
|
+
# the guesswork. What belongs in a row is the command's shape — the keys — and a
|
|
64
|
+
# value that must not be written down is the worker's to leave out or pass as a
|
|
65
|
+
# `$VAR` reference. A run does not need it: at execution time the value comes
|
|
66
|
+
# from the environment or from the person running it, and if it is absent the
|
|
67
|
+
# command fails then, where the failure is legible.
|
|
67
68
|
_FILE_LINE_CITATION_RE = re.compile(
|
|
68
69
|
r"`(?P<path>(?!https?://)[^`\n]+?):(?P<line>\d+(?:-\d+)?)`"
|
|
69
70
|
)
|
|
@@ -116,34 +117,18 @@ class EvidenceCommand:
|
|
|
116
117
|
cwd: str
|
|
117
118
|
exit_code: int
|
|
118
119
|
output_summary: str
|
|
120
|
+
identity: dict[str, object] | None = None
|
|
119
121
|
|
|
120
122
|
def to_record(self) -> dict[str, object]:
|
|
121
|
-
|
|
123
|
+
record: dict[str, object] = {
|
|
122
124
|
"command": self.command,
|
|
123
125
|
"cwd": self.cwd,
|
|
124
126
|
"exitCode": self.exit_code,
|
|
125
127
|
"outputSummary": self.output_summary,
|
|
126
128
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if isinstance(value, Mapping):
|
|
131
|
-
return any(
|
|
132
|
-
(
|
|
133
|
-
_SENSITIVE_KEY_RE.search(str(key)) is not None
|
|
134
|
-
and nested not in (None, "", False)
|
|
135
|
-
)
|
|
136
|
-
or _contains_sensitive_material(nested)
|
|
137
|
-
for key, nested in value.items()
|
|
138
|
-
)
|
|
139
|
-
if isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
|
|
140
|
-
return any(_contains_sensitive_material(item) for item in value)
|
|
141
|
-
if not isinstance(value, str):
|
|
142
|
-
return False
|
|
143
|
-
return (
|
|
144
|
-
_SENSITIVE_TEXT_RE.search(value) is not None
|
|
145
|
-
or _KNOWN_SECRET_RE.search(value) is not None
|
|
146
|
-
)
|
|
129
|
+
if self.identity:
|
|
130
|
+
record.update(self.identity)
|
|
131
|
+
return record
|
|
147
132
|
|
|
148
133
|
|
|
149
134
|
def _evidence_command_contract_failures(
|
|
@@ -151,7 +136,9 @@ def _evidence_command_contract_failures(
|
|
|
151
136
|
) -> list[str]:
|
|
152
137
|
failures: list[str] = []
|
|
153
138
|
missing = [key for key in _EVIDENCE_COMMAND_FIELDS if key not in payload]
|
|
154
|
-
unexpected = sorted(
|
|
139
|
+
unexpected = sorted(
|
|
140
|
+
set(payload) - set(_EVIDENCE_COMMAND_FIELDS) - set(_EVIDENCE_COMMAND_IDENTITY_FIELDS)
|
|
141
|
+
)
|
|
155
142
|
if missing:
|
|
156
143
|
failures.append(
|
|
157
144
|
f"Evidence command row {row_number} is missing {', '.join(missing)}"
|
|
@@ -173,21 +160,15 @@ def _evidence_command_contract_failures(
|
|
|
173
160
|
return failures
|
|
174
161
|
|
|
175
162
|
|
|
176
|
-
def _evidence_command_from_payload(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if sensitive:
|
|
180
|
-
return EvidenceCommand(
|
|
181
|
-
command="[redacted: potential secret]",
|
|
182
|
-
cwd="[redacted: potential secret]",
|
|
183
|
-
exit_code=payload["exitCode"],
|
|
184
|
-
output_summary="omitted because potential secret material was detected",
|
|
185
|
-
)
|
|
163
|
+
def _evidence_command_from_payload(payload: Mapping[str, object]) -> EvidenceCommand:
|
|
164
|
+
from okstra_ctl.execution_identity import stored_identity
|
|
165
|
+
|
|
186
166
|
return EvidenceCommand(
|
|
187
167
|
command=payload["command"],
|
|
188
168
|
cwd=payload["cwd"],
|
|
189
169
|
exit_code=payload["exitCode"],
|
|
190
170
|
output_summary=payload["outputSummary"],
|
|
171
|
+
identity=stored_identity(payload) or None,
|
|
191
172
|
)
|
|
192
173
|
|
|
193
174
|
|
|
@@ -209,16 +190,11 @@ def parse_evidence_commands(
|
|
|
209
190
|
f"Evidence command row {row_number} must be a JSON object"
|
|
210
191
|
)
|
|
211
192
|
continue
|
|
212
|
-
sensitive = _contains_sensitive_material(payload)
|
|
213
|
-
if sensitive:
|
|
214
|
-
failures.append(
|
|
215
|
-
f"Evidence command row {row_number} contains sensitive material"
|
|
216
|
-
)
|
|
217
193
|
contract_failures = _evidence_command_contract_failures(payload, row_number)
|
|
218
194
|
failures.extend(contract_failures)
|
|
219
195
|
if contract_failures:
|
|
220
196
|
continue
|
|
221
|
-
commands.append(_evidence_command_from_payload(payload
|
|
197
|
+
commands.append(_evidence_command_from_payload(payload))
|
|
222
198
|
return tuple(commands), tuple(failures)
|
|
223
199
|
|
|
224
200
|
|
|
@@ -375,7 +351,26 @@ def check_worker_results_audit(
|
|
|
375
351
|
*,
|
|
376
352
|
worker: str | None = None,
|
|
377
353
|
) -> list[str]:
|
|
378
|
-
"""Every audit-sidecar contract
|
|
354
|
+
"""Every audit-sidecar contract finding among this run's worker results.
|
|
355
|
+
|
|
356
|
+
Blocking findings first, then the advisory citation-ledger ones. Mid-run
|
|
357
|
+
callers want both in one list: the worker session is still alive and can fix
|
|
358
|
+
either. Phase 7 separates them — see `worker_results_audit_findings`.
|
|
359
|
+
"""
|
|
360
|
+
blocking, advisories = worker_results_audit_findings(
|
|
361
|
+
run_dir, task_type, seq, worker=worker
|
|
362
|
+
)
|
|
363
|
+
return blocking + advisories
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def worker_results_audit_findings(
|
|
367
|
+
run_dir: Path,
|
|
368
|
+
task_type: str,
|
|
369
|
+
seq: str | None,
|
|
370
|
+
*,
|
|
371
|
+
worker: str | None = None,
|
|
372
|
+
) -> tuple[list[str], list[str]]:
|
|
373
|
+
"""The same checks, split into `(blocking, advisory)`.
|
|
379
374
|
|
|
380
375
|
*run_dir* is `runs/<task-type>/`; `worker-results/` and `prompts/` hang off
|
|
381
376
|
it. *seq* scopes the check to one run — `worker-results/` accumulates every
|
|
@@ -383,16 +378,24 @@ def check_worker_results_audit(
|
|
|
383
378
|
did not produce. Pass ``None`` only when the seq is genuinely unknown, which
|
|
384
379
|
falls back to not filtering rather than silently checking nothing.
|
|
385
380
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
381
|
+
Blocking: a result file that still carries the `## 0. Reading Confirmation`
|
|
382
|
+
heading (that block moved to the sidecar), a missing sidecar, and a
|
|
383
|
+
malformed Evidence command row. Each of those means the audit trail itself
|
|
384
|
+
is absent or unreadable.
|
|
385
|
+
|
|
386
|
+
Advisory: a `path:line` citation with no matching Evidence read row. The
|
|
387
|
+
ledger exists and is readable; what the check found is a citation whose
|
|
388
|
+
spelling does not match a row. That is worth reporting and not worth
|
|
389
|
+
voiding a finished run over — one unmatched citation among hundreds used to
|
|
390
|
+
take the whole phase to `contract-violated`, which stops the run without
|
|
391
|
+
telling anyone whether the finding itself was wrong.
|
|
390
392
|
"""
|
|
391
393
|
failures: list[str] = []
|
|
394
|
+
advisories: list[str] = []
|
|
392
395
|
if not (run_dir / "worker-results").is_dir():
|
|
393
396
|
# No worker-results directory means no analysis workers ran (e.g.
|
|
394
397
|
# `release-handoff`, which is single-lead). Nothing to enforce.
|
|
395
|
-
return failures
|
|
398
|
+
return failures, advisories
|
|
396
399
|
|
|
397
400
|
for path, worker_role, result_seq in worker_result_files(run_dir, task_type, seq, worker):
|
|
398
401
|
rel = path.name
|
|
@@ -426,7 +429,7 @@ def check_worker_results_audit(
|
|
|
426
429
|
|
|
427
430
|
_, command_failures = read_evidence_commands(audit_path)
|
|
428
431
|
failures.extend(command_failures)
|
|
429
|
-
|
|
432
|
+
advisories.extend(_evidence_read_ledger_failures(
|
|
430
433
|
run_dir=run_dir,
|
|
431
434
|
worker_role=worker_role,
|
|
432
435
|
task_type=task_type,
|
|
@@ -435,4 +438,4 @@ def check_worker_results_audit(
|
|
|
435
438
|
result_content=content,
|
|
436
439
|
audit_path=audit_path,
|
|
437
440
|
))
|
|
438
|
-
return failures
|
|
441
|
+
return failures, advisories
|
|
@@ -14,6 +14,7 @@ from pathlib import Path
|
|
|
14
14
|
|
|
15
15
|
from .domain.worker_exec import ExecutionPolicy, WorkerExecRequest
|
|
16
16
|
from .domain.worker_role import role_spec
|
|
17
|
+
from .write_policy import WriteEnforcement, WritePolicy
|
|
17
18
|
|
|
18
19
|
# Carried over from the codex wrapper, where it was one provider's rule: cargo's
|
|
19
20
|
# package-cache flock and its registry live outside every workspace, so a
|
|
@@ -36,6 +37,8 @@ def build_request(
|
|
|
36
37
|
role: str,
|
|
37
38
|
idle_timeout_seconds: int,
|
|
38
39
|
session_id: str = "",
|
|
40
|
+
write_policy: WritePolicy | None = None,
|
|
41
|
+
write_enforcement: WriteEnforcement | None = None,
|
|
39
42
|
) -> WorkerExecRequest:
|
|
40
43
|
"""One dispatch, with every value the strategies will not re-derive.
|
|
41
44
|
|
|
@@ -53,7 +56,10 @@ def build_request(
|
|
|
53
56
|
# Nobody is at the keyboard to answer an approval prompt, so the gate is
|
|
54
57
|
# open and the boundary comes from the write scope instead.
|
|
55
58
|
policy=ExecutionPolicy(
|
|
56
|
-
auto_approve=True,
|
|
59
|
+
auto_approve=True,
|
|
60
|
+
write_scope=write_scope(root, worktree, role),
|
|
61
|
+
write_policy=write_policy,
|
|
62
|
+
write_enforcement=write_enforcement,
|
|
57
63
|
),
|
|
58
64
|
idle_timeout_seconds=idle_timeout_seconds,
|
|
59
65
|
session_id=session_id,
|
|
@@ -21,7 +21,9 @@ from functools import partial
|
|
|
21
21
|
from pathlib import Path
|
|
22
22
|
from typing import Any, Callable, Mapping
|
|
23
23
|
|
|
24
|
+
from .domain.provider import ServedModelAttestation, ServedModelNormalizer
|
|
24
25
|
from .domain.worker_exec import (
|
|
26
|
+
SERVED_MODEL_MISMATCH_EXIT_CODE,
|
|
25
27
|
STREAM_JSON,
|
|
26
28
|
ExecCommand,
|
|
27
29
|
ExecutionStrategy,
|
|
@@ -67,7 +69,11 @@ def run_worker(
|
|
|
67
69
|
log_path: Path,
|
|
68
70
|
status_path: Path,
|
|
69
71
|
status_extra: Mapping[str, Any] = _NO_STATUS_EXTRA,
|
|
72
|
+
served_model_normalizer: ServedModelNormalizer | None = None,
|
|
73
|
+
served_model_verifier: Callable[[ServedModelAttestation], str] | None = None,
|
|
70
74
|
) -> int:
|
|
75
|
+
_validate_status_extra(status_extra)
|
|
76
|
+
_validate_request_write_contract(request, status_extra)
|
|
71
77
|
command = strategy.build_command(request)
|
|
72
78
|
started_monotonic = time.monotonic()
|
|
73
79
|
status = _started_status(status_extra, log_path)
|
|
@@ -76,7 +82,7 @@ def run_worker(
|
|
|
76
82
|
|
|
77
83
|
try:
|
|
78
84
|
with guard:
|
|
79
|
-
exit_code, timed_out, idle_seconds = _launch(
|
|
85
|
+
exit_code, timed_out, idle_seconds, raw_model = _launch(
|
|
80
86
|
command,
|
|
81
87
|
log_path,
|
|
82
88
|
presentation=presentation,
|
|
@@ -94,6 +100,14 @@ def run_worker(
|
|
|
94
100
|
raise
|
|
95
101
|
|
|
96
102
|
status = _closed(status, started_monotonic)
|
|
103
|
+
if served_model_normalizer is not None:
|
|
104
|
+
attestation = served_model_normalizer(raw_model)
|
|
105
|
+
status["servedModelAttestation"] = _attestation_payload(attestation)
|
|
106
|
+
if served_model_verifier is not None:
|
|
107
|
+
failure = served_model_verifier(attestation)
|
|
108
|
+
if failure:
|
|
109
|
+
status["failure"] = failure
|
|
110
|
+
exit_code = SERVED_MODEL_MISMATCH_EXIT_CODE
|
|
97
111
|
status["exit_code"] = exit_code
|
|
98
112
|
if timed_out:
|
|
99
113
|
status.update(
|
|
@@ -106,6 +120,57 @@ def run_worker(
|
|
|
106
120
|
return exit_code
|
|
107
121
|
|
|
108
122
|
|
|
123
|
+
def _validate_status_extra(status_extra: Mapping[str, Any]) -> None:
|
|
124
|
+
schema = status_extra.get("schemaVersion")
|
|
125
|
+
identity_version = status_extra.get("executionIdentityVersion")
|
|
126
|
+
identity_keys = {
|
|
127
|
+
"participantRef",
|
|
128
|
+
"roleExecutionRef",
|
|
129
|
+
"executionLabel",
|
|
130
|
+
"dutyId",
|
|
131
|
+
"invocationRef",
|
|
132
|
+
}
|
|
133
|
+
if schema is None and identity_version is None:
|
|
134
|
+
if set(status_extra) & (
|
|
135
|
+
identity_keys | {"attempt", "servedModelAttestation"}
|
|
136
|
+
):
|
|
137
|
+
raise ValueError("worker status mixes v1 and v2 execution identity")
|
|
138
|
+
return
|
|
139
|
+
if schema != "2.0" or identity_version != 2:
|
|
140
|
+
raise ValueError("worker status mixes v1 and v2 execution identity")
|
|
141
|
+
if any(
|
|
142
|
+
not isinstance(status_extra.get(key), str) or not status_extra[key]
|
|
143
|
+
for key in identity_keys
|
|
144
|
+
):
|
|
145
|
+
raise ValueError("worker status v2 execution identity is incomplete")
|
|
146
|
+
attempt = status_extra.get("attempt")
|
|
147
|
+
if not isinstance(attempt, int) or isinstance(attempt, bool) or attempt < 1:
|
|
148
|
+
raise ValueError("worker status v2 attempt must be positive")
|
|
149
|
+
attestation = status_extra.get("servedModelAttestation")
|
|
150
|
+
if not isinstance(attestation, Mapping) or set(attestation) != {
|
|
151
|
+
"observedModel",
|
|
152
|
+
"normalizedModelRef",
|
|
153
|
+
"level",
|
|
154
|
+
"source",
|
|
155
|
+
}:
|
|
156
|
+
raise ValueError("worker status served model attestation is invalid")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _validate_request_write_contract(
|
|
160
|
+
request: WorkerExecRequest, status_extra: Mapping[str, Any]
|
|
161
|
+
) -> None:
|
|
162
|
+
if status_extra.get("executionIdentityVersion") != 2:
|
|
163
|
+
return
|
|
164
|
+
policy = request.policy.write_policy
|
|
165
|
+
enforcement = request.policy.write_enforcement
|
|
166
|
+
if policy is None or enforcement is None:
|
|
167
|
+
raise ValueError("v2 worker request has no write contract")
|
|
168
|
+
if status_extra.get("writePolicyDigest") != policy.digest:
|
|
169
|
+
raise ValueError("v2 worker request write policy digest changed")
|
|
170
|
+
if status_extra.get("writeEnforcement") != enforcement.to_payload():
|
|
171
|
+
raise ValueError("v2 worker request write enforcement changed")
|
|
172
|
+
|
|
173
|
+
|
|
109
174
|
def _launch(
|
|
110
175
|
command: ExecCommand,
|
|
111
176
|
log_path: Path,
|
|
@@ -113,7 +178,7 @@ def _launch(
|
|
|
113
178
|
presentation: str,
|
|
114
179
|
idle_timeout_seconds: int,
|
|
115
180
|
on_spawn: Callable[[subprocess.Popen[bytes]], None],
|
|
116
|
-
) -> tuple[int, bool, int]:
|
|
181
|
+
) -> tuple[int, bool, int, str | None]:
|
|
117
182
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
118
183
|
with log_path.open("w", encoding="utf-8") as log_file:
|
|
119
184
|
# The strategy decided where this provider runs — some CLIs work in the
|
|
@@ -128,7 +193,8 @@ def _launch(
|
|
|
128
193
|
env=_child_env(),
|
|
129
194
|
)
|
|
130
195
|
on_spawn(process)
|
|
131
|
-
|
|
196
|
+
observation = _ServedModelObservation()
|
|
197
|
+
exit_code, timed_out, idle_seconds = _pump(
|
|
132
198
|
process,
|
|
133
199
|
log_file,
|
|
134
200
|
stream_format=command.stream_format,
|
|
@@ -136,7 +202,19 @@ def _launch(
|
|
|
136
202
|
presentation=presentation,
|
|
137
203
|
idle_timeout_seconds=idle_timeout_seconds,
|
|
138
204
|
stdin_text=command.stdin_text,
|
|
205
|
+
observe_served_model=command.observe_served_model,
|
|
206
|
+
model_observation=observation,
|
|
139
207
|
)
|
|
208
|
+
return exit_code, timed_out, idle_seconds, observation.raw_model
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class _ServedModelObservation:
|
|
212
|
+
def __init__(self) -> None:
|
|
213
|
+
self.raw_model: str | None = None
|
|
214
|
+
|
|
215
|
+
def record(self, raw_model: str | None) -> None:
|
|
216
|
+
if self.raw_model is None and isinstance(raw_model, str) and raw_model.strip():
|
|
217
|
+
self.raw_model = raw_model
|
|
140
218
|
|
|
141
219
|
|
|
142
220
|
class _AbnormalExit:
|
|
@@ -253,6 +331,8 @@ def _pump(
|
|
|
253
331
|
presentation: str,
|
|
254
332
|
idle_timeout_seconds: int,
|
|
255
333
|
stdin_text: str | None = None,
|
|
334
|
+
observe_served_model: Callable[[Mapping[str, Any]], str | None],
|
|
335
|
+
model_observation: _ServedModelObservation,
|
|
256
336
|
) -> tuple[int, bool, int]:
|
|
257
337
|
selector = selectors.DefaultSelector()
|
|
258
338
|
readers, finalize_log = _register_output(
|
|
@@ -261,6 +341,8 @@ def _pump(
|
|
|
261
341
|
log_file,
|
|
262
342
|
stream_format=stream_format,
|
|
263
343
|
normalise=normalise,
|
|
344
|
+
observe_served_model=observe_served_model,
|
|
345
|
+
model_observation=model_observation,
|
|
264
346
|
presentation=presentation,
|
|
265
347
|
)
|
|
266
348
|
outgoing = _register_prompt(selector, process, stdin_text)
|
|
@@ -357,6 +439,8 @@ def _register_output(
|
|
|
357
439
|
*,
|
|
358
440
|
stream_format: str,
|
|
359
441
|
normalise: Normalise,
|
|
442
|
+
observe_served_model: Callable[[Mapping[str, Any]], str | None],
|
|
443
|
+
model_observation: _ServedModelObservation,
|
|
360
444
|
presentation: str,
|
|
361
445
|
) -> tuple[dict[int, _LineReader], Callable[[], None]]:
|
|
362
446
|
"""Register every stream this child speaks, each with its own destination.
|
|
@@ -367,7 +451,17 @@ def _register_output(
|
|
|
367
451
|
assert process.stdout is not None
|
|
368
452
|
if stream_format == STREAM_JSON:
|
|
369
453
|
sinks = [
|
|
370
|
-
(
|
|
454
|
+
(
|
|
455
|
+
process.stdout,
|
|
456
|
+
partial(
|
|
457
|
+
_emit_event,
|
|
458
|
+
log_file,
|
|
459
|
+
presentation,
|
|
460
|
+
normalise,
|
|
461
|
+
observe_served_model,
|
|
462
|
+
model_observation,
|
|
463
|
+
),
|
|
464
|
+
)
|
|
371
465
|
]
|
|
372
466
|
finalize_log: Callable[[], None] = _nothing_to_finalize
|
|
373
467
|
else:
|
|
@@ -519,7 +613,12 @@ class _ProgressSink:
|
|
|
519
613
|
|
|
520
614
|
|
|
521
615
|
def _emit_event(
|
|
522
|
-
log_file,
|
|
616
|
+
log_file,
|
|
617
|
+
presentation: str,
|
|
618
|
+
normalise: Normalise,
|
|
619
|
+
observe_served_model: Callable[[Mapping[str, Any]], str | None],
|
|
620
|
+
model_observation: _ServedModelObservation,
|
|
621
|
+
line: str,
|
|
523
622
|
) -> str | None:
|
|
524
623
|
"""Write one line of a JSON stream out; return closing text if this is it.
|
|
525
624
|
|
|
@@ -542,6 +641,7 @@ def _emit_event(
|
|
|
542
641
|
return None
|
|
543
642
|
if not isinstance(event, dict):
|
|
544
643
|
return None
|
|
644
|
+
model_observation.record(observe_served_model(event))
|
|
545
645
|
|
|
546
646
|
closing: str | None = None
|
|
547
647
|
for entry in normalise(event):
|
|
@@ -560,6 +660,15 @@ def _emit_event(
|
|
|
560
660
|
return closing
|
|
561
661
|
|
|
562
662
|
|
|
663
|
+
def _attestation_payload(attestation: ServedModelAttestation) -> dict[str, Any]:
|
|
664
|
+
return {
|
|
665
|
+
"observedModel": attestation.observed_model,
|
|
666
|
+
"normalizedModelRef": attestation.normalized_model_ref,
|
|
667
|
+
"level": attestation.level,
|
|
668
|
+
"source": attestation.source,
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
|
|
563
672
|
def _write_log(log_file, lines) -> None:
|
|
564
673
|
for line in lines:
|
|
565
674
|
log_file.write(line + "\n")
|
|
@@ -605,6 +714,22 @@ def _child_env() -> dict[str, str]:
|
|
|
605
714
|
return env
|
|
606
715
|
|
|
607
716
|
|
|
717
|
+
def write_host_event(
|
|
718
|
+
path: Path,
|
|
719
|
+
*,
|
|
720
|
+
invocation_ref: str,
|
|
721
|
+
attempt: int,
|
|
722
|
+
event_type: str,
|
|
723
|
+
payload: Mapping[str, Any],
|
|
724
|
+
) -> Mapping[str, Any]:
|
|
725
|
+
"""Append one orchestrator-owned host event from the runner boundary."""
|
|
726
|
+
from .attempt_evidence import HostEventStreamWriter
|
|
727
|
+
|
|
728
|
+
return HostEventStreamWriter(
|
|
729
|
+
path, invocation_ref=invocation_ref, attempt=attempt
|
|
730
|
+
).append(event_type, payload)
|
|
731
|
+
|
|
732
|
+
|
|
608
733
|
def _write_status(path: Path, status: Mapping[str, Any]) -> None:
|
|
609
734
|
"""Best-effort status write; a sidecar failure must not break the run.
|
|
610
735
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""V1 provider-worker roster compatibility parsing.
|
|
2
2
|
|
|
3
3
|
Profile 파일에서 권장 worker 목록을 뽑고(`resolve_profile_workers`), 사용자
|
|
4
4
|
오버라이드와 합쳐 정규화한다(`normalize_workers`). bash workers.sh 의
|
|
@@ -28,8 +28,10 @@ class WorkersError(Exception):
|
|
|
28
28
|
"""invalid worker selection — surface to user."""
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def
|
|
32
|
-
"""
|
|
31
|
+
def _resolve_v1_workers_under(profile_path: Path, headers: set[str]) -> list[str]:
|
|
32
|
+
"""Read legacy provider-worker bullets without interpreting role YAML.
|
|
33
|
+
|
|
34
|
+
Collect ` - <id> …` sub-bullets under any of `headers`
|
|
33
35
|
until the next top-level bullet. Returns first token (before any
|
|
34
36
|
` — ` / ` -- ` / whitespace) of each captured line.
|
|
35
37
|
"""
|
|
@@ -61,7 +63,7 @@ def resolve_profile_workers(profile_path: Path) -> list[str]:
|
|
|
61
63
|
`- Workers:` / `- Reviewers:` / `- Analysers:`) 섹션 아래 sub-bullet 들을
|
|
62
64
|
worker id 리스트로 돌려준다. profile 파일이 없거나 섹션이 없으면 빈 리스트.
|
|
63
65
|
"""
|
|
64
|
-
return
|
|
66
|
+
return _resolve_v1_workers_under(profile_path, PROFILE_BULLET_HEADERS)
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
def resolve_optional_workers(profile_path: Path) -> list[str]:
|
|
@@ -69,7 +71,7 @@ def resolve_optional_workers(profile_path: Path) -> list[str]:
|
|
|
69
71
|
들에서 worker id 만 추출한다. (` - antigravity — when added …` → `antigravity`)
|
|
70
72
|
Required 와 중복되는 항목은 제거. ALLOWED_WORKERS 밖 토큰도 제거.
|
|
71
73
|
"""
|
|
72
|
-
raw =
|
|
74
|
+
raw = _resolve_v1_workers_under(profile_path, PROFILE_BULLET_HEADERS_OPTIONAL)
|
|
73
75
|
required = set(resolve_profile_workers(profile_path))
|
|
74
76
|
seen: set[str] = set()
|
|
75
77
|
out: list[str] = []
|