zob-harness 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/adapters/registry.json +103 -0
- package/.pi/agents/architecture-cartographer.md +53 -0
- package/.pi/agents/chief-vision.md +39 -0
- package/.pi/agents/clarifier.md +58 -0
- package/.pi/agents/context-steward.md +52 -0
- package/.pi/agents/doc-steward.md +34 -0
- package/.pi/agents/explore.md +49 -0
- package/.pi/agents/factory.md +41 -0
- package/.pi/agents/implementer.md +44 -0
- package/.pi/agents/librarian.md +32 -0
- package/.pi/agents/oracle-merge.md +50 -0
- package/.pi/agents/oracle.md +55 -0
- package/.pi/agents/pattern-miner.md +53 -0
- package/.pi/agents/planner.md +39 -0
- package/.pi/agents/project-dna-golden-evaluator.md +32 -0
- package/.pi/agents/project-dna-ontology-steward.md +30 -0
- package/.pi/agents/project-dna-oracle.md +56 -0
- package/.pi/agents/project-dna-orchestrator.md +60 -0
- package/.pi/agents/project-dna-query-steward.md +38 -0
- package/.pi/agents/project-dna-safety-preflight.md +54 -0
- package/.pi/agents/project-dna-test-linker.md +27 -0
- package/.pi/agents/qa.md +38 -0
- package/.pi/agents/refactor-cartographer.md +28 -0
- package/.pi/agents/refactor-mover.md +31 -0
- package/.pi/agents/refactor-oracle.md +49 -0
- package/.pi/agents/repo-scout.md +60 -0
- package/.pi/agents/sample-architect.md +48 -0
- package/.pi/agents/specifier.md +57 -0
- package/.pi/agents/symbol-range-curator.md +41 -0
- package/.pi/agents/synthesis.md +52 -0
- package/.pi/agents/temp-agent-creator.md +35 -0
- package/.pi/autonomy-policy.json +67 -0
- package/.pi/budget-policy.json +54 -0
- package/.pi/capabilities/zob-public-runtime-capabilities.json +1700 -0
- package/.pi/chains/explore-plan-oracle.json +78 -0
- package/.pi/chains/explore-spec-clarify-plan-oracle.json +64 -0
- package/.pi/chains/explore-spec-plan-oracle.json +53 -0
- package/.pi/chains/spec-clarify-plan-oracle.json +53 -0
- package/.pi/chains/spec-factory-oracle.json +42 -0
- package/.pi/chains/spec-plan-oracle.json +42 -0
- package/.pi/compute-profiles/defaults.json +19 -0
- package/.pi/compute-profiles/overrides.json +13 -0
- package/.pi/compute-profiles/risk-rules.json +16 -0
- package/.pi/daemon-policy.json +80 -0
- package/.pi/damage-control-rules.json +45 -0
- package/.pi/extensions/zob-child-safety/index.ts +212 -0
- package/.pi/extensions/zob-harness/AGENTS.md +28 -0
- package/.pi/extensions/zob-harness/index.ts +391 -0
- package/.pi/extensions/zob-harness/src/AGENTS.md +25 -0
- package/.pi/extensions/zob-harness/src/agents.ts +82 -0
- package/.pi/extensions/zob-harness/src/autonomous-runtime.ts +2912 -0
- package/.pi/extensions/zob-harness/src/autonomy-readiness.ts +778 -0
- package/.pi/extensions/zob-harness/src/budget-policy.ts +308 -0
- package/.pi/extensions/zob-harness/src/capabilities.ts +249 -0
- package/.pi/extensions/zob-harness/src/child-runner.ts +249 -0
- package/.pi/extensions/zob-harness/src/chronicle.ts +262 -0
- package/.pi/extensions/zob-harness/src/compute-profile.ts +602 -0
- package/.pi/extensions/zob-harness/src/compute-workflow-shape.ts +168 -0
- package/.pi/extensions/zob-harness/src/coms-v2/AGENTS.md +16 -0
- package/.pi/extensions/zob-harness/src/coms-v2/envelope.ts +121 -0
- package/.pi/extensions/zob-harness/src/coms-v2/identity.ts +53 -0
- package/.pi/extensions/zob-harness/src/coms-v2/ledger-bridge.ts +67 -0
- package/.pi/extensions/zob-harness/src/coms-v2/local-transport.ts +147 -0
- package/.pi/extensions/zob-harness/src/coms-v2/pending-replies.ts +80 -0
- package/.pi/extensions/zob-harness/src/coms-v2/policy.ts +125 -0
- package/.pi/extensions/zob-harness/src/coms-v2/presence.ts +55 -0
- package/.pi/extensions/zob-harness/src/coms-v2/registry.ts +113 -0
- package/.pi/extensions/zob-harness/src/coms-v2/response-capture.ts +50 -0
- package/.pi/extensions/zob-harness/src/coms-v2/transcript-capture.ts +164 -0
- package/.pi/extensions/zob-harness/src/coms-v2/types.ts +149 -0
- package/.pi/extensions/zob-harness/src/coms-v2/zpeer-profile.ts +140 -0
- package/.pi/extensions/zob-harness/src/coms-v2/zpeer.ts +452 -0
- package/.pi/extensions/zob-harness/src/constants.ts +108 -0
- package/.pi/extensions/zob-harness/src/context-gbrain.ts +465 -0
- package/.pi/extensions/zob-harness/src/daemon-policy.ts +223 -0
- package/.pi/extensions/zob-harness/src/daemon-readiness.ts +134 -0
- package/.pi/extensions/zob-harness/src/daemon-runtime.ts +393 -0
- package/.pi/extensions/zob-harness/src/factory/AGENTS.md +24 -0
- package/.pi/extensions/zob-harness/src/factory/agentic-plan.ts +65 -0
- package/.pi/extensions/zob-harness/src/factory/quarantine.ts +319 -0
- package/.pi/extensions/zob-harness/src/factory/run.ts +520 -0
- package/.pi/extensions/zob-harness/src/factory/validation.ts +454 -0
- package/.pi/extensions/zob-harness/src/factory-selector.ts +318 -0
- package/.pi/extensions/zob-harness/src/full-autonomy-test.ts +226 -0
- package/.pi/extensions/zob-harness/src/git-ops.ts +868 -0
- package/.pi/extensions/zob-harness/src/goal-room.ts +178 -0
- package/.pi/extensions/zob-harness/src/goal-runtime.ts +1569 -0
- package/.pi/extensions/zob-harness/src/goal-todo-imports.ts +111 -0
- package/.pi/extensions/zob-harness/src/goal-todo-types.ts +231 -0
- package/.pi/extensions/zob-harness/src/goal-todos.ts +1410 -0
- package/.pi/extensions/zob-harness/src/goal.ts +152 -0
- package/.pi/extensions/zob-harness/src/governed-requests.ts +436 -0
- package/.pi/extensions/zob-harness/src/interactive-autonomy.ts +595 -0
- package/.pi/extensions/zob-harness/src/launch-apply.ts +313 -0
- package/.pi/extensions/zob-harness/src/merge-queue.ts +290 -0
- package/.pi/extensions/zob-harness/src/mission-control.ts +573 -0
- package/.pi/extensions/zob-harness/src/model-availability.ts +52 -0
- package/.pi/extensions/zob-harness/src/model-routing.ts +429 -0
- package/.pi/extensions/zob-harness/src/orchestration/AGENTS.md +23 -0
- package/.pi/extensions/zob-harness/src/orchestration/adaptive-delegation.ts +547 -0
- package/.pi/extensions/zob-harness/src/orchestration/adaptive-workflow.ts +585 -0
- package/.pi/extensions/zob-harness/src/orchestration/lead-plan.ts +192 -0
- package/.pi/extensions/zob-harness/src/orchestration/plan.ts +168 -0
- package/.pi/extensions/zob-harness/src/orchestration/room.ts +346 -0
- package/.pi/extensions/zob-harness/src/orchestration/run.ts +134 -0
- package/.pi/extensions/zob-harness/src/orchestration/supervised-readonly.ts +1147 -0
- package/.pi/extensions/zob-harness/src/orchestration/widget-readers.ts +132 -0
- package/.pi/extensions/zob-harness/src/output-contracts.ts +656 -0
- package/.pi/extensions/zob-harness/src/project-dna.ts +533 -0
- package/.pi/extensions/zob-harness/src/promotion/AGENTS.md +24 -0
- package/.pi/extensions/zob-harness/src/promotion/candidate.ts +336 -0
- package/.pi/extensions/zob-harness/src/promotion/coms.ts +127 -0
- package/.pi/extensions/zob-harness/src/promotion/documentation.ts +142 -0
- package/.pi/extensions/zob-harness/src/promotion/factory.ts +107 -0
- package/.pi/extensions/zob-harness/src/promotion/ledger.ts +2 -0
- package/.pi/extensions/zob-harness/src/promotion/temp-agent.ts +151 -0
- package/.pi/extensions/zob-harness/src/promotion/types.ts +149 -0
- package/.pi/extensions/zob-harness/src/promotion/validate.ts +6 -0
- package/.pi/extensions/zob-harness/src/promotion/write-lane.ts +162 -0
- package/.pi/extensions/zob-harness/src/prompt-packs.ts +239 -0
- package/.pi/extensions/zob-harness/src/queue.ts +386 -0
- package/.pi/extensions/zob-harness/src/rules.ts +225 -0
- package/.pi/extensions/zob-harness/src/runtime/AGENTS.md +26 -0
- package/.pi/extensions/zob-harness/src/runtime/adaptive-zmode.ts +116 -0
- package/.pi/extensions/zob-harness/src/runtime/auto-compaction.ts +715 -0
- package/.pi/extensions/zob-harness/src/runtime/commands.ts +1315 -0
- package/.pi/extensions/zob-harness/src/runtime/compaction-policy.ts +516 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-click-markers.ts +141 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-feed.ts +415 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-markdown.ts +97 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-monitor.ts +553 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-mouse.ts +205 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-overlay.ts +434 -0
- package/.pi/extensions/zob-harness/src/runtime/events.ts +736 -0
- package/.pi/extensions/zob-harness/src/runtime/goal-todo-overlay.ts +214 -0
- package/.pi/extensions/zob-harness/src/runtime/mode-intent.ts +144 -0
- package/.pi/extensions/zob-harness/src/runtime/plan-capture.ts +270 -0
- package/.pi/extensions/zob-harness/src/runtime/state.ts +403 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-autonomous.ts +117 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-compute.ts +136 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-coms.ts +365 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-context.ts +70 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-delegation.ts +1854 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-factory.ts +810 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-goal-room.ts +46 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-governed-requests.ts +38 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-merge-queue.ts +61 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-mission-control.ts +77 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-orchestration.ts +106 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-project-dna.ts +123 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-worker-pool.ts +93 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-workspace-claims.ts +62 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-zcommit.ts +147 -0
- package/.pi/extensions/zob-harness/src/runtime/widget.ts +353 -0
- package/.pi/extensions/zob-harness/src/runtime/zobHarness.ts +60 -0
- package/.pi/extensions/zob-harness/src/safety.ts +338 -0
- package/.pi/extensions/zob-harness/src/sandbox.ts +1508 -0
- package/.pi/extensions/zob-harness/src/schemas-project-dna.ts +47 -0
- package/.pi/extensions/zob-harness/src/schemas.ts +695 -0
- package/.pi/extensions/zob-harness/src/telemetry.ts +373 -0
- package/.pi/extensions/zob-harness/src/topology/AGENTS.md +22 -0
- package/.pi/extensions/zob-harness/src/topology/chains.ts +236 -0
- package/.pi/extensions/zob-harness/src/topology/coms.ts +211 -0
- package/.pi/extensions/zob-harness/src/topology/orchestration-profiles.ts +204 -0
- package/.pi/extensions/zob-harness/src/topology/teams.ts +113 -0
- package/.pi/extensions/zob-harness/src/types/core.ts +47 -0
- package/.pi/extensions/zob-harness/src/types.ts +939 -0
- package/.pi/extensions/zob-harness/src/utils/AGENTS.md +22 -0
- package/.pi/extensions/zob-harness/src/utils/formatting.ts +34 -0
- package/.pi/extensions/zob-harness/src/utils/hashing.ts +11 -0
- package/.pi/extensions/zob-harness/src/utils/json.ts +28 -0
- package/.pi/extensions/zob-harness/src/utils/paths.ts +54 -0
- package/.pi/extensions/zob-harness/src/utils/records.ts +25 -0
- package/.pi/extensions/zob-harness/src/utils/resources.ts +38 -0
- package/.pi/extensions/zob-harness/src/worker-pool.ts +672 -0
- package/.pi/extensions/zob-harness/src/workspace-claims.ts +297 -0
- package/.pi/extensions/zob-switch/index.ts +180 -0
- package/.pi/factories/budget-preflight-dry-run/batch-manifest.json +59 -0
- package/.pi/factories/budget-preflight-dry-run/factory.json +94 -0
- package/.pi/factories/budget-preflight-dry-run/pilot-manifest.json +50 -0
- package/.pi/factories/budget-preflight-dry-run/smoke-manifest.json +43 -0
- package/.pi/factories/code-review-matrix/batch-manifest.json +61 -0
- package/.pi/factories/code-review-matrix/factory.json +163 -0
- package/.pi/factories/code-review-matrix/pilot-manifest.json +41 -0
- package/.pi/factories/code-review-matrix/smoke-manifest.json +35 -0
- package/.pi/factories/factory-forge/batch-manifest.json +56 -0
- package/.pi/factories/factory-forge/factory.json +84 -0
- package/.pi/factories/factory-forge/pilot-manifest.json +32 -0
- package/.pi/factories/factory-forge/smoke-manifest.json +19 -0
- package/.pi/factories/opencode-pattern-canonizer/batch-manifest.json +54 -0
- package/.pi/factories/opencode-pattern-canonizer/factory.json +86 -0
- package/.pi/factories/opencode-pattern-canonizer/pilot-manifest.json +39 -0
- package/.pi/factories/opencode-pattern-canonizer/smoke-manifest.json +26 -0
- package/.pi/factories/project-dna/README.md +182 -0
- package/.pi/factories/project-dna/batch-manifest.json +37 -0
- package/.pi/factories/project-dna/example-project-dna-manifest-v2.json +80 -0
- package/.pi/factories/project-dna/example-project-dna-manifest.json +58 -0
- package/.pi/factories/project-dna/factory.json +131 -0
- package/.pi/factories/project-dna/golden-cases-smoke.json +62 -0
- package/.pi/factories/project-dna/pi-agentic-ontology.json +88 -0
- package/.pi/factories/project-dna/pilot-manifest.json +32 -0
- package/.pi/factories/project-dna/schemas/benchmark-suite.schema.json +27 -0
- package/.pi/factories/project-dna/schemas/code-knowledge-graph.schema.json +97 -0
- package/.pi/factories/project-dna/schemas/context-pack.schema.json +43 -0
- package/.pi/factories/project-dna/schemas/golden-case.schema.json +36 -0
- package/.pi/factories/project-dna/schemas/manifest-v2.schema.json +128 -0
- package/.pi/factories/project-dna/schemas/manifest.schema.json +77 -0
- package/.pi/factories/project-dna/schemas/ontology.schema.json +45 -0
- package/.pi/factories/project-dna/schemas/project-fingerprint.schema.json +28 -0
- package/.pi/factories/project-dna/schemas/query-steward-report.schema.json +52 -0
- package/.pi/factories/project-dna/smoke-manifest.json +27 -0
- package/.pi/factories/roadmap-smoke-lots/batch-manifest.json +49 -0
- package/.pi/factories/roadmap-smoke-lots/factory.json +89 -0
- package/.pi/factories/roadmap-smoke-lots/pilot-manifest.json +50 -0
- package/.pi/factories/roadmap-smoke-lots/smoke-manifest.json +35 -0
- package/.pi/git-policy.json +120 -0
- package/.pi/mission-control/zob_coms_transport.json +64 -0
- package/.pi/model-catalog.example.json +345 -0
- package/.pi/model-economy.example.json +196 -0
- package/.pi/model-routing.json +86 -0
- package/.pi/orchestrations/adaptive-chief-vision.json +193 -0
- package/.pi/orchestrations/ceo-feature-build.json +182 -0
- package/.pi/orchestrations/readonly-dynamic-smoke.json +75 -0
- package/.pi/output-contracts/agent-event.v1.json +19 -0
- package/.pi/output-contracts/base.v1.json +24 -0
- package/.pi/output-contracts/brain-lookup.v1.json +21 -0
- package/.pi/output-contracts/clarification.v1.json +21 -0
- package/.pi/output-contracts/context-pack.v1.json +20 -0
- package/.pi/output-contracts/context-request.v1.json +21 -0
- package/.pi/output-contracts/context-steward.v1.json +19 -0
- package/.pi/output-contracts/context-writeback-proposal.v1.json +18 -0
- package/.pi/output-contracts/delegation-request.v1.json +21 -0
- package/.pi/output-contracts/explore.v1.json +52 -0
- package/.pi/output-contracts/factory.v1.json +48 -0
- package/.pi/output-contracts/guidance-steward.v1.json +18 -0
- package/.pi/output-contracts/implement.v1.json +40 -0
- package/.pi/output-contracts/launch-authorization.v1.json +21 -0
- package/.pi/output-contracts/lead-plan.v1.json +22 -0
- package/.pi/output-contracts/mission-readiness.v1.json +20 -0
- package/.pi/output-contracts/oracle-merge.v1.json +44 -0
- package/.pi/output-contracts/oracle-request.v1.json +20 -0
- package/.pi/output-contracts/oracle.v1.json +44 -0
- package/.pi/output-contracts/orchestration-profile.v1.json +22 -0
- package/.pi/output-contracts/plan.v1.json +48 -0
- package/.pi/output-contracts/prompt-pack.v1.json +20 -0
- package/.pi/output-contracts/qa.v1.json +40 -0
- package/.pi/output-contracts/research.v1.json +36 -0
- package/.pi/output-contracts/spec.v1.json +22 -0
- package/.pi/output-contracts/synthesis.v1.json +44 -0
- package/.pi/output-contracts/temp-agent-card.v1.json +23 -0
- package/.pi/output-contracts/todo-child-result.v1.json +20 -0
- package/.pi/output-contracts/todo-child-result.v2.json +22 -0
- package/.pi/output-contracts/todo-claim-validation.v1.json +22 -0
- package/.pi/output-contracts/todo-split-request.v1.json +20 -0
- package/.pi/prompts/adaptive-workflow.md +63 -0
- package/.pi/prompts/autonomous-runtime.md +15 -0
- package/.pi/prompts/benchmark-contender.md +15 -0
- package/.pi/prompts/benchmark-judge.md +19 -0
- package/.pi/prompts/clarify-spec.md +20 -0
- package/.pi/prompts/compute-plan.md +36 -0
- package/.pi/prompts/compute-preview.md +42 -0
- package/.pi/prompts/contract.md +29 -0
- package/.pi/prompts/explore.md +13 -0
- package/.pi/prompts/factory-run.md +36 -0
- package/.pi/prompts/factory.md +20 -0
- package/.pi/prompts/implement.md +27 -0
- package/.pi/prompts/model-catalog.md +68 -0
- package/.pi/prompts/model-economy.md +64 -0
- package/.pi/prompts/oracle-merge.md +18 -0
- package/.pi/prompts/oracle.md +13 -0
- package/.pi/prompts/orchestrator.md +48 -0
- package/.pi/prompts/parallel-review.md +21 -0
- package/.pi/prompts/plan.md +21 -0
- package/.pi/prompts/project-dna.md +90 -0
- package/.pi/prompts/refactor-oracle.md +23 -0
- package/.pi/prompts/refactor-slice.md +24 -0
- package/.pi/prompts/research.md +20 -0
- package/.pi/prompts/spec.md +19 -0
- package/.pi/prompts/synthesis.md +18 -0
- package/.pi/rules/always.md +38 -0
- package/.pi/rules/docs.md +32 -0
- package/.pi/rules/factory.md +44 -0
- package/.pi/rules/oracle.md +34 -0
- package/.pi/rules/orchestration.md +44 -0
- package/.pi/rules/project.md +34 -0
- package/.pi/rules/prompts.md +43 -0
- package/.pi/rules/runtime.md +43 -0
- package/.pi/rules/sandbox.md +43 -0
- package/.pi/settings.json +28 -0
- package/.pi/skills/zob-agentic-access/SKILL.md +20 -0
- package/.pi/skills/zob-autonomous-runtime/SKILL.md +41 -0
- package/.pi/skills/zob-commit/SKILL.md +79 -0
- package/.pi/skills/zob-compaction-policy/SKILL.md +92 -0
- package/.pi/skills/zob-compute-profile/SKILL.md +108 -0
- package/.pi/skills/zob-coms-safety/SKILL.md +54 -0
- package/.pi/skills/zob-coms-v2-live/SKILL.md +47 -0
- package/.pi/skills/zob-delegation-routing/SKILL.md +82 -0
- package/.pi/skills/zob-factory/SKILL.md +28 -0
- package/.pi/skills/zob-goal-todo-tree/SKILL.md +279 -0
- package/.pi/skills/zob-harness/SKILL.md +68 -0
- package/.pi/skills/zob-mission-control-coms/SKILL.md +39 -0
- package/.pi/skills/zob-oracle/SKILL.md +21 -0
- package/.pi/skills/zob-owner-pool-drill-writer/SKILL.md +244 -0
- package/.pi/skills/zob-owner-pool-launcher/SKILL.md +261 -0
- package/.pi/skills/zob-project-dna/SKILL.md +275 -0
- package/.pi/skills/zob-sandbox/SKILL.md +29 -0
- package/.pi/skills/zob-spec/SKILL.md +25 -0
- package/.pi/skills/zob-split-refactor/SKILL.md +39 -0
- package/.pi/skills/zob-tool-router/SKILL.md +104 -0
- package/.pi/teams/zob-core.json +122 -0
- package/AGENTS.md +89 -0
- package/CONTRIBUTING.md +56 -0
- package/LICENSE +21 -0
- package/README.md +360 -0
- package/SECURITY.md +35 -0
- package/SOURCE_INDEX.md +46 -0
- package/package.json +135 -0
- package/scripts/README.md +57 -0
- package/scripts/autonomy/mission-readiness-secret-smoke.mjs +90 -0
- package/scripts/compute-profile/plan-workflow.mjs +85 -0
- package/scripts/compute-profile/preview.mjs +242 -0
- package/scripts/compute-profile/regression-smoke.mjs +38 -0
- package/scripts/compute-profile/summarize.mjs +72 -0
- package/scripts/compute-profile/validate-policy.mjs +50 -0
- package/scripts/compute-profile/validate-preview.mjs +95 -0
- package/scripts/compute-profile/validate-workflow.mjs +58 -0
- package/scripts/git-ops/commit-policy-smoke.mjs +221 -0
- package/scripts/goal-todo/child-goal-ref-smoke.mjs +252 -0
- package/scripts/harness-switch/static-smoke.mjs +43 -0
- package/scripts/model-catalog/validate-economy.mjs +223 -0
- package/scripts/model-catalog/validate.mjs +199 -0
- package/scripts/package-surface/validate-script-refs.mjs +190 -0
- package/scripts/path-policy/validate-smoke.mjs +103 -0
- package/scripts/project-dna/bench-smoke.mjs +217 -0
- package/scripts/project-dna/build-capsules.mjs +207 -0
- package/scripts/project-dna/build-sample-spec.mjs +140 -0
- package/scripts/project-dna/emit-golden-cases.mjs +75 -0
- package/scripts/project-dna/emit-ontology.mjs +75 -0
- package/scripts/project-dna/generate-sample.mjs +302 -0
- package/scripts/project-dna/oracle-review-smoke.mjs +157 -0
- package/scripts/project-dna/plan-workflow.mjs +289 -0
- package/scripts/project-dna/query-context.mjs +276 -0
- package/scripts/project-dna/query-steward.mjs +149 -0
- package/scripts/project-dna/scan.mjs +553 -0
- package/scripts/project-dna/validate-5of5.mjs +159 -0
- package/scripts/project-dna/validate-golden-cases.mjs +78 -0
- package/scripts/project-dna/validate-ontology.mjs +97 -0
- package/scripts/project-dna/validate-sample-project.mjs +105 -0
- package/scripts/project-dna/validate-scaffold.mjs +383 -0
- package/scripts/project-dna/validate-scan-artifacts.mjs +187 -0
- package/scripts/project-dna/validate-workflow.mjs +166 -0
- package/scripts/start-pi.sh +4 -0
- package/scripts/worker-pool/static-smoke.mjs +54 -0
- package/scripts/zpeer-local-e2e-smoke.mjs +395 -0
- package/scripts/zpeer-static-smoke.mjs +129 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { buildZobLivePresenceSummary, redactZobLivePeerForMissionControl } from "./coms-v2/presence.js";
|
|
5
|
+
import { readZobComsV2Policy } from "./coms-v2/policy.js";
|
|
6
|
+
import { zpeerMembershipsForPeer } from "./coms-v2/zpeer.js";
|
|
7
|
+
import { readZobLiveRegistrySnapshot } from "./coms-v2/registry.js";
|
|
8
|
+
import { buildQueueDashboardSummary } from "./queue.js";
|
|
9
|
+
import type { TeamDefinition } from "./types.js";
|
|
10
|
+
import { summarizePromotionCandidates } from "./promotion/candidate.js";
|
|
11
|
+
import { buildZobComsMessage, listZobComsMessages, validateZobComsEdge, validateZobComsMessage } from "./topology/coms.js";
|
|
12
|
+
import { sha256 } from "./utils/hashing.js";
|
|
13
|
+
import { readJsonl, readJsonObjectIfPresent } from "./utils/json.js";
|
|
14
|
+
import { safeFileStem } from "./utils/paths.js";
|
|
15
|
+
import { isRecord } from "./utils/records.js";
|
|
16
|
+
|
|
17
|
+
export const MISSION_CONTROL_COMMANDS = ["pause", "resume", "reprioritize", "request_context", "request_oracle", "stop", "approve", "replan"] as const;
|
|
18
|
+
|
|
19
|
+
const MISSION_CONTROL_COMMAND_SET = new Set<string>(MISSION_CONTROL_COMMANDS);
|
|
20
|
+
const FORBIDDEN_BODY_KEYS = new Set(["body", "task", "prompt", "output", "content", "message", "rationale", "text", "diff", "patch"]);
|
|
21
|
+
const TRANSPORT_POLICY_RELATIVE_PATH = ".pi/mission-control/zob_coms_transport.json";
|
|
22
|
+
const COMMAND_PROPOSALS_RELATIVE_PATH = ".pi/mission-control/command-proposals.jsonl";
|
|
23
|
+
const COMMAND_PROPOSALS_DIR_RELATIVE_PATH = ".pi/mission-control/proposals";
|
|
24
|
+
const GOAL_ROOM_DIR_RELATIVE_PATH = ".pi/goal-rooms";
|
|
25
|
+
|
|
26
|
+
export interface MissionControlCommandProposalInput {
|
|
27
|
+
proposalId?: string;
|
|
28
|
+
runId: string;
|
|
29
|
+
command: string;
|
|
30
|
+
requestedBy?: string;
|
|
31
|
+
targetRole?: string;
|
|
32
|
+
priority?: string;
|
|
33
|
+
rationaleHash?: string;
|
|
34
|
+
artifactRefs?: string[];
|
|
35
|
+
todoId?: string;
|
|
36
|
+
subtreeRootTodoId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MissionControlSnapshotInput {
|
|
40
|
+
runId?: string;
|
|
41
|
+
limit?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasForbiddenBodyKey(value: unknown): boolean {
|
|
45
|
+
if (!value || typeof value !== "object") return false;
|
|
46
|
+
if (Array.isArray(value)) return value.some(hasForbiddenBodyKey);
|
|
47
|
+
return Object.entries(value).some(([key, child]) => FORBIDDEN_BODY_KEYS.has(key) || hasForbiddenBodyKey(child));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isHexSha256(value: unknown): boolean {
|
|
51
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/i.test(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function summarizeZpeerRooms(peers: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
55
|
+
const rooms = new Map<string, Array<{ peer: Record<string, unknown>; alias?: string }>>();
|
|
56
|
+
for (const peer of peers) {
|
|
57
|
+
const memberships = zpeerMembershipsForPeer(peer as unknown as Parameters<typeof zpeerMembershipsForPeer>[0]);
|
|
58
|
+
for (const membership of memberships) {
|
|
59
|
+
const list = rooms.get(membership.roomId) ?? [];
|
|
60
|
+
list.push({ peer, alias: membership.alias });
|
|
61
|
+
rooms.set(membership.roomId, list);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...rooms.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([roomId, roomPeers]) => {
|
|
65
|
+
const aliases = roomPeers.map((entry) => entry.alias).filter((alias): alias is string => Boolean(alias)).sort();
|
|
66
|
+
const sessionHashes = roomPeers.map((entry) => typeof entry.peer.sessionHash === "string" ? entry.peer.sessionHash : undefined).filter((sessionHash): sessionHash is string => Boolean(sessionHash));
|
|
67
|
+
return {
|
|
68
|
+
schema: "zob.zpeer-room-summary.v1",
|
|
69
|
+
roomIdHash: sha256(roomId),
|
|
70
|
+
peerCount: roomPeers.length,
|
|
71
|
+
uniquePeerCount: new Set(sessionHashes).size,
|
|
72
|
+
online: roomPeers.filter((entry) => entry.peer.status === "online").length,
|
|
73
|
+
stale: roomPeers.filter((entry) => entry.peer.status === "stale").length,
|
|
74
|
+
offline: roomPeers.filter((entry) => entry.peer.status === "offline").length,
|
|
75
|
+
aliasHashes: aliases.map((alias) => sha256(alias)),
|
|
76
|
+
duplicateAliasHashes: aliases.filter((alias, index) => aliases.indexOf(alias) !== index).filter((alias, index, all) => all.indexOf(alias) === index).map((alias) => sha256(alias)),
|
|
77
|
+
localOnly: true,
|
|
78
|
+
networkEnabled: false,
|
|
79
|
+
bodyStored: false,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isSafeArtifactRef(value: string): boolean {
|
|
85
|
+
if (value.length === 0 || value.startsWith("/") || value.includes("\\") || value.includes("..")) return false;
|
|
86
|
+
if (value === ".env" || value.startsWith(".env.") || value.includes("/.env")) return false;
|
|
87
|
+
if (value.includes("node_modules/") || value.includes("dist/") || value.includes("build/")) return false;
|
|
88
|
+
if (value.endsWith(".pem") || value.endsWith(".key")) return false;
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function boundedLimit(limit: number | undefined, fallback = 10): number {
|
|
93
|
+
return Math.max(1, Math.min(50, Math.floor(limit ?? fallback)));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function sortedEntriesByMtime(dir: string): string[] {
|
|
97
|
+
if (!existsSync(dir)) return [];
|
|
98
|
+
return readdirSync(dir)
|
|
99
|
+
.map((entry) => ({ entry, path: join(dir, entry), stat: statSync(join(dir, entry)) }))
|
|
100
|
+
.filter((item) => item.stat.isDirectory())
|
|
101
|
+
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
|
|
102
|
+
.map((item) => item.entry);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function summarizeRunDir(repoRoot: string, baseRelative: string, runId: string): Record<string, unknown> {
|
|
106
|
+
const runDir = join(repoRoot, baseRelative, runId);
|
|
107
|
+
const validation = readJsonObjectIfPresent(join(runDir, "validation.json"));
|
|
108
|
+
return {
|
|
109
|
+
runId,
|
|
110
|
+
status: typeof validation?.status === "string" ? validation.status : "unknown",
|
|
111
|
+
mode: typeof validation?.mode === "string" ? validation.mode : undefined,
|
|
112
|
+
execution: typeof validation?.execution === "string" ? validation.execution : undefined,
|
|
113
|
+
no_ship: typeof validation?.no_ship === "boolean" ? validation.no_ship : undefined,
|
|
114
|
+
noExecution: typeof validation?.noExecution === "boolean" ? validation.noExecution : undefined,
|
|
115
|
+
validation: existsSync(join(runDir, "validation.json")) ? `${baseRelative}/${runId}/validation.json` : undefined,
|
|
116
|
+
doneSentinel: existsSync(join(runDir, "DONE.sentinel")),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function summarizeLatestRuns(repoRoot: string, baseRelative: string, limit: number): Array<Record<string, unknown>> {
|
|
121
|
+
return sortedEntriesByMtime(join(repoRoot, baseRelative)).slice(0, limit).map((runId) => summarizeRunDir(repoRoot, baseRelative, runId));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function summarizeAdaptiveWorkflowArtifacts(repoRoot: string, limit: number): Array<Record<string, unknown>> {
|
|
125
|
+
const root = join(repoRoot, "reports", "orchestrations");
|
|
126
|
+
if (!existsSync(root)) return [];
|
|
127
|
+
return sortedEntriesByMtime(root).slice(0, Math.max(limit, 20)).flatMap((runId) => {
|
|
128
|
+
const runDir = join(root, runId);
|
|
129
|
+
const validationPath = join(runDir, "adaptive-workflow-validation.json");
|
|
130
|
+
if (!existsSync(validationPath)) return [];
|
|
131
|
+
const validation = readJsonObjectIfPresent(validationPath);
|
|
132
|
+
const workflow = readJsonObjectIfPresent(join(runDir, "adaptive-workflow-run.json"));
|
|
133
|
+
const scalePolicy = readJsonObjectIfPresent(join(runDir, "scale-policy.json"));
|
|
134
|
+
const documentationPolicy = readJsonObjectIfPresent(join(runDir, "documentation-policy.json"));
|
|
135
|
+
return [{
|
|
136
|
+
runId,
|
|
137
|
+
status: workflow?.status,
|
|
138
|
+
effectiveComputeProfile: workflow?.effectiveComputeProfile,
|
|
139
|
+
rootRole: workflow?.rootRole,
|
|
140
|
+
rootNonCoding: validation?.rootNonCoding,
|
|
141
|
+
modelPolicyPresent: validation?.modelPolicyPresent,
|
|
142
|
+
scalePolicyPresent: validation?.scalePolicyPresent,
|
|
143
|
+
documentationPolicyPresent: validation?.documentationPolicyPresent,
|
|
144
|
+
tempAgentRosterPresent: validation?.tempAgentRosterPresent,
|
|
145
|
+
factoryCandidatePresent: validation?.factoryCandidatePresent,
|
|
146
|
+
scaleRequested: scalePolicy?.requestedScale,
|
|
147
|
+
scaleApprovalRequired: scalePolicy?.requiresScaleApproval,
|
|
148
|
+
stalePeerBlocksCompletion: scalePolicy?.stalePeerBlocksCompletion,
|
|
149
|
+
docWritebackPolicy: documentationPolicy?.writebackPolicy,
|
|
150
|
+
valid: validation?.valid,
|
|
151
|
+
errors: Array.isArray(validation?.errors) ? validation.errors : [],
|
|
152
|
+
artifact: `reports/orchestrations/${runId}/adaptive-workflow-validation.json`,
|
|
153
|
+
bodyStored: false,
|
|
154
|
+
}];
|
|
155
|
+
}).slice(0, limit);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function summarizeComputeProfileArtifacts(repoRoot: string, limit: number): Array<Record<string, unknown>> {
|
|
159
|
+
const root = join(repoRoot, "reports", "project-dna-scans");
|
|
160
|
+
if (!existsSync(root)) return [];
|
|
161
|
+
return readdirSync(root)
|
|
162
|
+
.map((runId) => ({ runId, summaryPath: join(root, runId, "compute-mission-control-summary.json") }))
|
|
163
|
+
.filter((item) => existsSync(item.summaryPath))
|
|
164
|
+
.sort((a, b) => statSync(b.summaryPath).mtimeMs - statSync(a.summaryPath).mtimeMs)
|
|
165
|
+
.slice(0, limit)
|
|
166
|
+
.flatMap(({ runId, summaryPath }) => {
|
|
167
|
+
const summary = readJsonObjectIfPresent(summaryPath);
|
|
168
|
+
if (!summary) return [];
|
|
169
|
+
return [{
|
|
170
|
+
runId: summary.runId ?? runId,
|
|
171
|
+
domain: summary.domain,
|
|
172
|
+
requestedProfile: summary.requestedProfile,
|
|
173
|
+
recommendedProfile: summary.recommendedProfile,
|
|
174
|
+
effectiveProfile: summary.effectiveProfile,
|
|
175
|
+
noShip: summary.noShip,
|
|
176
|
+
laneCount: isRecord(summary.workflow) ? summary.workflow.laneCount : undefined,
|
|
177
|
+
parentOwnedDispatch: isRecord(summary.workflow) ? summary.workflow.parentOwnedDispatch : undefined,
|
|
178
|
+
childDirectDispatch: isRecord(summary.workflow) ? summary.workflow.childDirectDispatch : undefined,
|
|
179
|
+
fullHudWidgetWiringImplemented: summary.fullHudWidgetWiringImplemented,
|
|
180
|
+
artifact: `reports/project-dna-scans/${runId}/compute-mission-control-summary.json`,
|
|
181
|
+
bodyStored: summary.bodyStored,
|
|
182
|
+
}];
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function summarizeFactoryStatus(factoryRuns: Array<Record<string, unknown>>): Record<string, unknown> {
|
|
187
|
+
const byStatus: Record<string, number> = {};
|
|
188
|
+
const byMode: Record<string, number> = {};
|
|
189
|
+
for (const run of factoryRuns) {
|
|
190
|
+
const status = typeof run.status === "string" ? run.status : "unknown";
|
|
191
|
+
const mode = typeof run.mode === "string" ? run.mode : "unknown";
|
|
192
|
+
byStatus[status] = (byStatus[status] ?? 0) + 1;
|
|
193
|
+
byMode[mode] = (byMode[mode] ?? 0) + 1;
|
|
194
|
+
}
|
|
195
|
+
return { latestCount: factoryRuns.length, byStatus, byMode };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function sanitizeMissionControlMetadata(value: unknown): unknown {
|
|
199
|
+
if (!value || typeof value !== "object") return value;
|
|
200
|
+
if (Array.isArray(value)) return value.map(sanitizeMissionControlMetadata);
|
|
201
|
+
const sanitized: Record<string, unknown> = {};
|
|
202
|
+
for (const [key, child] of Object.entries(value)) {
|
|
203
|
+
if (key === "output" && typeof child === "number") sanitized.outputTokens = child;
|
|
204
|
+
else if (key === "input" && typeof child === "number") sanitized.inputTokens = child;
|
|
205
|
+
else if (FORBIDDEN_BODY_KEYS.has(key)) sanitized[`${key}Omitted`] = true;
|
|
206
|
+
else sanitized[key] = sanitizeMissionControlMetadata(child);
|
|
207
|
+
}
|
|
208
|
+
return sanitized;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function redactComsMessage(message: Record<string, unknown>): Record<string, unknown> {
|
|
212
|
+
return {
|
|
213
|
+
msgId: message.msgId,
|
|
214
|
+
runId: message.runId,
|
|
215
|
+
sender: message.sender,
|
|
216
|
+
receiver: message.receiver,
|
|
217
|
+
kind: message.kind,
|
|
218
|
+
status: message.status,
|
|
219
|
+
ack: message.ack,
|
|
220
|
+
taskHash: message.taskHash,
|
|
221
|
+
outputHash: message.outputHash,
|
|
222
|
+
replies: message.replies,
|
|
223
|
+
bodyStored: message.bodyStored,
|
|
224
|
+
timestamp: message.timestamp,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function redactGoalRoomEvent(event: Record<string, unknown>, fallbackGoalId: string): Record<string, unknown> {
|
|
229
|
+
return {
|
|
230
|
+
msgId: event.msgId,
|
|
231
|
+
goalId: event.goalId ?? fallbackGoalId,
|
|
232
|
+
runId: event.runId,
|
|
233
|
+
todoId: event.todoId,
|
|
234
|
+
sender: event.sender,
|
|
235
|
+
audience: event.audience,
|
|
236
|
+
kind: event.kind,
|
|
237
|
+
priority: event.priority,
|
|
238
|
+
requiresParentAction: event.requiresParentAction,
|
|
239
|
+
taskId: event.taskId,
|
|
240
|
+
bodyHash: event.bodyHash,
|
|
241
|
+
outputHash: event.outputHash,
|
|
242
|
+
evidenceRefs: Array.isArray(event.evidenceRefs) ? event.evidenceRefs : [],
|
|
243
|
+
artifactRefs: Array.isArray(event.artifactRefs) ? event.artifactRefs : [],
|
|
244
|
+
parentVisible: event.parentVisible,
|
|
245
|
+
hiddenPeerChat: event.hiddenPeerChat,
|
|
246
|
+
workerToWorkerDirect: event.workerToWorkerDirect,
|
|
247
|
+
parentOwnedActions: event.parentOwnedActions,
|
|
248
|
+
bodyStored: event.bodyStored,
|
|
249
|
+
promptBodiesStored: event.promptBodiesStored,
|
|
250
|
+
outputBodiesStored: event.outputBodiesStored,
|
|
251
|
+
createdAt: event.createdAt,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function summarizeGoalRoomEvents(repoRoot: string, limit: number): Array<Record<string, unknown>> {
|
|
256
|
+
const root = join(repoRoot, GOAL_ROOM_DIR_RELATIVE_PATH);
|
|
257
|
+
if (!existsSync(root)) return [];
|
|
258
|
+
return sortedEntriesByMtime(root)
|
|
259
|
+
.flatMap((goalRoomId) => readJsonl(join(root, goalRoomId, "messages.jsonl"))
|
|
260
|
+
.filter((event) => isRecord(event) && event.schema === "zob.goal-room-message.v1" && !hasForbiddenBodyKey(event))
|
|
261
|
+
.map((event) => redactGoalRoomEvent(event, goalRoomId)))
|
|
262
|
+
.sort((a, b) => String(a.createdAt ?? "").localeCompare(String(b.createdAt ?? "")))
|
|
263
|
+
.slice(-limit);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function readCommandProposalLedger(repoRoot: string): Array<Record<string, unknown>> {
|
|
267
|
+
return readJsonl(join(repoRoot, COMMAND_PROPOSALS_RELATIVE_PATH));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function buildCommandProposalId(input: MissionControlCommandProposalInput): string {
|
|
271
|
+
if (input.proposalId) {
|
|
272
|
+
const safe = safeFileStem(input.proposalId);
|
|
273
|
+
if (safe !== input.proposalId) throw new Error(`Unsafe proposalId: ${input.proposalId}`);
|
|
274
|
+
return safe;
|
|
275
|
+
}
|
|
276
|
+
return safeFileStem(`${input.runId}-${input.command}-${Date.now()}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function teamWorkerIds(definition: TeamDefinition): Set<string> {
|
|
280
|
+
return new Set(definition.workers.map((worker) => worker.id));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function teamLeadIds(definition: TeamDefinition): Set<string> {
|
|
284
|
+
return new Set(definition.leads.map((lead) => lead.id));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function validateMissionControlCommandProposalInput(definition: TeamDefinition, input: MissionControlCommandProposalInput): string[] {
|
|
288
|
+
const errors: string[] = [];
|
|
289
|
+
if (!input || typeof input !== "object") return ["Mission Control command proposal input must be an object"];
|
|
290
|
+
if (hasForbiddenBodyKey(input)) errors.push("Mission Control command proposals must not include raw body/task/prompt/output/content/rationale/text fields");
|
|
291
|
+
if (typeof input.runId !== "string" || input.runId.trim().length === 0) errors.push("Mission Control command proposal requires runId");
|
|
292
|
+
if (typeof input.command !== "string" || !MISSION_CONTROL_COMMAND_SET.has(input.command)) errors.push(`Mission Control command must be one of: ${MISSION_CONTROL_COMMANDS.join(", ")}`);
|
|
293
|
+
if (input.rationaleHash !== undefined && !isHexSha256(input.rationaleHash)) errors.push("Mission Control rationaleHash must be a sha256 hex hash when provided");
|
|
294
|
+
if (input.priority !== undefined && !["low", "normal", "high", "critical"].includes(input.priority)) errors.push("Mission Control priority must be low, normal, high, or critical");
|
|
295
|
+
if (input.todoId !== undefined && !/^[A-Za-z0-9._:-]+$/.test(input.todoId)) errors.push("Mission Control todoId must be metadata-safe");
|
|
296
|
+
if (input.subtreeRootTodoId !== undefined && !/^[A-Za-z0-9._:-]+$/.test(input.subtreeRootTodoId)) errors.push("Mission Control subtreeRootTodoId must be metadata-safe");
|
|
297
|
+
if (input.artifactRefs !== undefined) {
|
|
298
|
+
if (!Array.isArray(input.artifactRefs)) errors.push("Mission Control artifactRefs must be an array when provided");
|
|
299
|
+
else {
|
|
300
|
+
const unsafe = input.artifactRefs.filter((ref) => typeof ref !== "string" || !isSafeArtifactRef(ref));
|
|
301
|
+
if (unsafe.length > 0) errors.push(`Mission Control artifactRefs must be safe repo-relative references: ${unsafe.join(", ")}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const workerIds = teamWorkerIds(definition);
|
|
305
|
+
if (typeof input.targetRole === "string" && workerIds.has(input.targetRole)) errors.push("Mission Control command proposals must be parent-owned; direct worker targets are blocked");
|
|
306
|
+
const knownControlRoles = new Set([definition.orchestrator.id, ...teamLeadIds(definition)]);
|
|
307
|
+
if (typeof input.targetRole === "string" && input.targetRole.length > 0 && !knownControlRoles.has(input.targetRole)) errors.push(`Mission Control targetRole must be the orchestrator or a lead role, got '${input.targetRole}'`);
|
|
308
|
+
return errors;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function validateMissionControlCommandProposal(definition: TeamDefinition, input: MissionControlCommandProposalInput): string[] {
|
|
312
|
+
return validateMissionControlCommandProposalInput(definition, input);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function buildMissionControlCommandProposal(definition: TeamDefinition, input: MissionControlCommandProposalInput): Record<string, unknown> {
|
|
316
|
+
const errors = validateMissionControlCommandProposal(definition, input);
|
|
317
|
+
if (errors.length > 0) throw new Error(errors.join("; "));
|
|
318
|
+
const proposalId = buildCommandProposalId(input);
|
|
319
|
+
const receiver = definition.orchestrator.id;
|
|
320
|
+
const commandEnvelope = {
|
|
321
|
+
runId: input.runId,
|
|
322
|
+
command: input.command,
|
|
323
|
+
targetRole: input.targetRole ?? receiver,
|
|
324
|
+
receiver,
|
|
325
|
+
priority: input.priority ?? "normal",
|
|
326
|
+
artifactRefs: input.artifactRefs ?? [],
|
|
327
|
+
todoId: input.todoId ?? null,
|
|
328
|
+
subtreeRootTodoId: input.subtreeRootTodoId ?? null,
|
|
329
|
+
};
|
|
330
|
+
const commandHash = sha256(JSON.stringify(commandEnvelope));
|
|
331
|
+
const proposal = {
|
|
332
|
+
schema: "zob.mission-control-command-proposal.v1",
|
|
333
|
+
proposalId,
|
|
334
|
+
runId: input.runId,
|
|
335
|
+
requestedBy: input.requestedBy ?? "mission-control-dashboard",
|
|
336
|
+
receiver,
|
|
337
|
+
command: input.command,
|
|
338
|
+
commandHash,
|
|
339
|
+
targetRole: input.targetRole ?? receiver,
|
|
340
|
+
priority: input.priority ?? "normal",
|
|
341
|
+
rationaleHash: input.rationaleHash ?? null,
|
|
342
|
+
artifactRefs: input.artifactRefs ?? [],
|
|
343
|
+
todoId: input.todoId ?? null,
|
|
344
|
+
subtreeRootTodoId: input.subtreeRootTodoId ?? null,
|
|
345
|
+
proposalOnly: true,
|
|
346
|
+
parentOwned: true,
|
|
347
|
+
requiresParentApproval: true,
|
|
348
|
+
directWorkerWrite: false,
|
|
349
|
+
transportDispatch: false,
|
|
350
|
+
networkTransport: false,
|
|
351
|
+
bodyStored: false,
|
|
352
|
+
promptBodiesStored: false,
|
|
353
|
+
outputBodiesStored: false,
|
|
354
|
+
generatedAt: new Date().toISOString(),
|
|
355
|
+
};
|
|
356
|
+
if (hasForbiddenBodyKey(proposal)) throw new Error("Refusing to build Mission Control proposal with raw body fields");
|
|
357
|
+
return proposal;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export function writeMissionControlCommandProposal(repoRoot: string, definition: TeamDefinition, input: MissionControlCommandProposalInput): Record<string, unknown> {
|
|
361
|
+
const proposal = buildMissionControlCommandProposal(definition, input);
|
|
362
|
+
const missionDir = join(repoRoot, ".pi", "mission-control");
|
|
363
|
+
const proposalsDir = join(repoRoot, COMMAND_PROPOSALS_DIR_RELATIVE_PATH);
|
|
364
|
+
mkdirSync(missionDir, { recursive: true });
|
|
365
|
+
mkdirSync(proposalsDir, { recursive: true });
|
|
366
|
+
appendFileSync(join(repoRoot, COMMAND_PROPOSALS_RELATIVE_PATH), `${JSON.stringify(proposal)}\n`, "utf8");
|
|
367
|
+
writeFileSync(join(proposalsDir, `${proposal.proposalId}.json`), JSON.stringify(proposal, null, 2), "utf8");
|
|
368
|
+
return { ...proposal, proposalLedger: COMMAND_PROPOSALS_RELATIVE_PATH, proposalArtifact: `${COMMAND_PROPOSALS_DIR_RELATIVE_PATH}/${proposal.proposalId}.json` };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function readTransportPolicy(repoRoot: string): Record<string, unknown> {
|
|
372
|
+
return readJsonObjectIfPresent(join(repoRoot, TRANSPORT_POLICY_RELATIVE_PATH)) ?? {
|
|
373
|
+
schema: "zob.coms-transport-policy.v1",
|
|
374
|
+
name: "zob_coms_transport",
|
|
375
|
+
p0Status: "design_only",
|
|
376
|
+
enabled: false,
|
|
377
|
+
localDispatchEnabled: false,
|
|
378
|
+
networkEnabled: false,
|
|
379
|
+
globalActivation: false,
|
|
380
|
+
dispatchAllowed: false,
|
|
381
|
+
canonicalLedger: ".pi/coms/messages.jsonl",
|
|
382
|
+
statusLedger: ".pi/coms/status.jsonl",
|
|
383
|
+
bodyPolicy: "hash_only",
|
|
384
|
+
heartbeat: { enabled: false, stalePeerCountsAsCompletion: false },
|
|
385
|
+
responseCapture: { enabled: false, storeBodies: false },
|
|
386
|
+
commandPolicy: { proposalOnly: true, directWorkerWrites: false },
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export function buildZobComsTransportReadiness(repoRoot: string): Record<string, unknown> {
|
|
391
|
+
const policy = readTransportPolicy(repoRoot);
|
|
392
|
+
const v2Policy = readZobComsV2Policy(repoRoot);
|
|
393
|
+
const heartbeat = isRecord(policy.heartbeat) ? policy.heartbeat : {};
|
|
394
|
+
const responseCapture = isRecord(policy.responseCapture) ? policy.responseCapture : {};
|
|
395
|
+
const commandPolicy = isRecord(policy.commandPolicy) ? policy.commandPolicy : {};
|
|
396
|
+
const livePresence = buildZobLivePresenceSummary(repoRoot);
|
|
397
|
+
const strictLiveMode = v2Policy.mode === "required_local" || v2Policy.mode === "required_network";
|
|
398
|
+
const checks = [
|
|
399
|
+
{ name: "policy_present", passed: (policy.schema === "zob.coms-transport-policy.v1" || policy.schema === "zob.coms-transport-policy.v2") && policy.name === "zob_coms_transport", detail: TRANSPORT_POLICY_RELATIVE_PATH },
|
|
400
|
+
{ name: "transport_disabled_p0_or_live_required", passed: strictLiveMode || (policy.enabled === false && policy.localDispatchEnabled !== true && policy.dispatchAllowed !== true), detail: JSON.stringify({ mode: v2Policy.mode, enabled: policy.enabled, localDispatchEnabled: policy.localDispatchEnabled, dispatchAllowed: policy.dispatchAllowed }) },
|
|
401
|
+
{ name: "network_disabled", passed: policy.networkEnabled === false && policy.globalActivation !== true, detail: JSON.stringify({ networkEnabled: policy.networkEnabled, globalActivation: policy.globalActivation }) },
|
|
402
|
+
{ name: "zob_ledger_canonical", passed: policy.canonicalLedger === ".pi/coms/messages.jsonl" && policy.statusLedger === ".pi/coms/status.jsonl", detail: JSON.stringify({ canonicalLedger: policy.canonicalLedger, statusLedger: policy.statusLedger }) },
|
|
403
|
+
{ name: "stale_not_completion", passed: heartbeat.stalePeerCountsAsCompletion === false, detail: JSON.stringify(heartbeat) },
|
|
404
|
+
{ name: "response_capture_body_free", passed: responseCapture.storeBodies !== true, detail: JSON.stringify(responseCapture) },
|
|
405
|
+
{ name: "commands_proposal_only", passed: commandPolicy.proposalOnly === true && commandPolicy.directWorkerWrites === false, detail: JSON.stringify(commandPolicy) },
|
|
406
|
+
{ name: "registry_available", passed: livePresence.available === true, detail: JSON.stringify({ mode: livePresence.mode, registry: livePresence.registry, peerCount: livePresence.peerCount }) },
|
|
407
|
+
{ name: "required_local_live_ready_when_enabled", passed: v2Policy.mode !== "required_local" || (livePresence.dispatchEnabled === true && livePresence.networkEnabled === false && livePresence.online > 0), detail: JSON.stringify({ mode: livePresence.mode, online: livePresence.online, stale: livePresence.stale, offline: livePresence.offline }) },
|
|
408
|
+
{ name: "agentic_workflows_require_live", passed: v2Policy.agenticWorkflowsRequireLive === true && v2Policy.legacy.appendOnlySendEnabled === false, detail: JSON.stringify({ agenticWorkflowsRequireLive: v2Policy.agenticWorkflowsRequireLive, appendOnlySendEnabled: v2Policy.legacy.appendOnlySendEnabled, mode: v2Policy.mode }) },
|
|
409
|
+
];
|
|
410
|
+
const failedChecks = checks.filter((check) => !check.passed).map((check) => check.name);
|
|
411
|
+
return {
|
|
412
|
+
schema: "zob.coms-transport-readiness.v1",
|
|
413
|
+
adapter: "zob_coms_transport",
|
|
414
|
+
p0Status: typeof policy.p0Status === "string" ? policy.p0Status : "design_only",
|
|
415
|
+
mode: v2Policy.mode,
|
|
416
|
+
enabled: v2Policy.enabled,
|
|
417
|
+
localDispatchEnabled: v2Policy.localDispatchEnabled,
|
|
418
|
+
networkEnabled: v2Policy.networkEnabled,
|
|
419
|
+
dispatchAllowed: v2Policy.dispatchAllowed,
|
|
420
|
+
noExecution: true,
|
|
421
|
+
checks,
|
|
422
|
+
failedChecks,
|
|
423
|
+
verdict: failedChecks.length === 0 ? "PASS" : "FAIL",
|
|
424
|
+
no_ship: failedChecks.length > 0,
|
|
425
|
+
livePresence,
|
|
426
|
+
evidence: { policy: TRANSPORT_POLICY_RELATIVE_PATH, canonicalLedger: ".pi/coms/messages.jsonl", statusLedger: ".pi/coms/status.jsonl" },
|
|
427
|
+
generatedAt: new Date().toISOString(),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function buildZobCommunicationReadinessAudit(repoRoot: string, definition: TeamDefinition): Record<string, unknown> {
|
|
432
|
+
const orchestratorId = definition.orchestrator.id;
|
|
433
|
+
const firstLead = definition.leads[0];
|
|
434
|
+
const firstWorker = firstLead ? definition.workers.find((worker) => worker.leadId === firstLead.id) : undefined;
|
|
435
|
+
const secondWorker = firstWorker ? definition.workers.find((worker) => worker.id !== firstWorker.id) : undefined;
|
|
436
|
+
const sampleMessage = buildZobComsMessage({ runId: "communication-readiness-sample", sender: orchestratorId, receiver: firstLead?.id ?? orchestratorId, body: "sample body only used for hash computation" });
|
|
437
|
+
const ledgers = [
|
|
438
|
+
...readJsonl(join(repoRoot, ".pi", "coms", "messages.jsonl")),
|
|
439
|
+
...readJsonl(join(repoRoot, ".pi", "coms", "status.jsonl")),
|
|
440
|
+
];
|
|
441
|
+
const transport = buildZobComsTransportReadiness(repoRoot);
|
|
442
|
+
const livePresence = buildZobLivePresenceSummary(repoRoot, definition.name);
|
|
443
|
+
const proposal = buildMissionControlCommandProposal(definition, { runId: "communication-readiness-sample", command: "pause", targetRole: orchestratorId, rationaleHash: sha256("readiness") });
|
|
444
|
+
const directWorkerErrors = firstWorker ? validateMissionControlCommandProposal(definition, { runId: "communication-readiness-sample", command: "stop", targetRole: firstWorker.id, rationaleHash: sha256("direct-worker") }) : ["no worker role available for direct-worker guard sample"];
|
|
445
|
+
const checks = [
|
|
446
|
+
{ name: "canonical_hash_only_ledgers", passed: true, detail: ".pi/coms/messages.jsonl and .pi/coms/status.jsonl remain canonical local ledgers" },
|
|
447
|
+
{ name: "topology_guard_active", passed: Boolean(firstLead) && validateZobComsEdge(definition, orchestratorId, firstLead?.id ?? "").length === 0 && Boolean(firstWorker) && validateZobComsEdge(definition, firstLead?.id ?? "", firstWorker?.id ?? "").length === 0, detail: JSON.stringify({ orchestratorId, leadId: firstLead?.id, workerId: firstWorker?.id }) },
|
|
448
|
+
{ name: "worker_to_worker_blocked", passed: Boolean(firstWorker && secondWorker) && validateZobComsEdge(definition, firstWorker?.id ?? "", secondWorker?.id ?? "").some((error) => error.includes("Worker-to-worker") || error.includes("not allowed")), detail: JSON.stringify({ from: firstWorker?.id, to: secondWorker?.id }) },
|
|
449
|
+
{ name: "message_body_storage_blocked", passed: sampleMessage.bodyStored === false && typeof sampleMessage.bodyHash === "string" && validateZobComsMessage(sampleMessage).length === 0 && !hasForbiddenBodyKey(sampleMessage), detail: "sample message hashes body without persisting it" },
|
|
450
|
+
{ name: "existing_ledgers_body_free", passed: !ledgers.some(hasForbiddenBodyKey), detail: `records=${ledgers.length}` },
|
|
451
|
+
{ name: "bounded_await_cap", passed: true, detail: "awaitZobComsMessage caps timeoutMs at 5000ms" },
|
|
452
|
+
{ name: "transport_policy_safe", passed: transport.verdict === "PASS" && (transport.mode === "required_local" ? transport.dispatchAllowed === true && transport.networkEnabled === false : transport.enabled === false && transport.dispatchAllowed === false && transport.networkEnabled === false), detail: JSON.stringify({ verdict: transport.verdict, mode: transport.mode, enabled: transport.enabled, dispatchAllowed: transport.dispatchAllowed, networkEnabled: transport.networkEnabled }) },
|
|
453
|
+
{ name: "transport_design_disabled", passed: transport.mode === "required_local" ? transport.dispatchAllowed === true && transport.networkEnabled === false : transport.enabled === false && transport.dispatchAllowed === false && transport.networkEnabled === false, detail: JSON.stringify({ compatibilityCheck: true, mode: transport.mode }) },
|
|
454
|
+
{ name: "stale_transport_not_completion", passed: (transport.checks as Array<Record<string, unknown>>).some((check) => check.name === "stale_not_completion" && check.passed === true), detail: "stale/offline peers are not successful completion evidence" },
|
|
455
|
+
{ name: "registry_observe_only_available", passed: livePresence.available === true && livePresence.networkEnabled === false && livePresence.stalePeerCountsAsCompletion === false && (livePresence.mode === "required_local" ? livePresence.dispatchEnabled === true && livePresence.online > 0 : livePresence.dispatchEnabled === false), detail: JSON.stringify({ mode: livePresence.mode, peerCount: livePresence.peerCount, online: livePresence.online, stale: livePresence.stale, offline: livePresence.offline }) },
|
|
456
|
+
{ name: "dashboard_commands_are_proposals", passed: proposal.proposalOnly === true && proposal.parentOwned === true && proposal.directWorkerWrite === false && proposal.transportDispatch === false, detail: JSON.stringify({ command: proposal.command, receiver: proposal.receiver, proposalOnly: proposal.proposalOnly }) },
|
|
457
|
+
{ name: "dashboard_direct_worker_commands_blocked", passed: directWorkerErrors.some((error) => error.includes("direct worker")), detail: JSON.stringify(directWorkerErrors) },
|
|
458
|
+
];
|
|
459
|
+
const failedChecks = checks.filter((check) => !check.passed).map((check) => check.name);
|
|
460
|
+
return {
|
|
461
|
+
schema: "zob.communication-readiness-audit.v1",
|
|
462
|
+
verdict: failedChecks.length === 0 ? "PASS" : "FAIL",
|
|
463
|
+
no_ship: failedChecks.length > 0,
|
|
464
|
+
checks,
|
|
465
|
+
failedChecks,
|
|
466
|
+
evidence: { transportPolicy: TRANSPORT_POLICY_RELATIVE_PATH, comsMessages: ".pi/coms/messages.jsonl", comsStatus: ".pi/coms/status.jsonl" },
|
|
467
|
+
bodyStored: false,
|
|
468
|
+
promptBodiesStored: false,
|
|
469
|
+
outputBodiesStored: false,
|
|
470
|
+
generatedAt: new Date().toISOString(),
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function buildMissionControlSnapshot(repoRoot: string, definition: TeamDefinition, input: MissionControlSnapshotInput = {}): Record<string, unknown> {
|
|
475
|
+
const limit = boundedLimit(input.limit, 5);
|
|
476
|
+
const comsMessages = listZobComsMessages(repoRoot, { runId: input.runId, limit });
|
|
477
|
+
const comsLedgerRecords = readJsonl(join(repoRoot, ".pi", "coms", "messages.jsonl"));
|
|
478
|
+
const comsStatusRecords = readJsonl(join(repoRoot, ".pi", "coms", "status.jsonl"));
|
|
479
|
+
const factoryRuns = summarizeLatestRuns(repoRoot, "reports/factory-runs", limit);
|
|
480
|
+
const orchestrationRuns = summarizeLatestRuns(repoRoot, "reports/orchestrations", limit);
|
|
481
|
+
const queueDashboard = sanitizeMissionControlMetadata(buildQueueDashboardSummary(repoRoot));
|
|
482
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
483
|
+
const telemetryDaily = sanitizeMissionControlMetadata(readJsonObjectIfPresent(join(repoRoot, ".pi", "logs", "summaries", `${today}.json`))) as Record<string, unknown> | undefined;
|
|
484
|
+
const autonomyAudit = readJsonObjectIfPresent(join(repoRoot, "reports", "autonomy-readiness-audit-smoke.json"));
|
|
485
|
+
const factoryRegistryAudit = readJsonObjectIfPresent(join(repoRoot, "reports", "factory-registry-readiness-audit-smoke.json"));
|
|
486
|
+
const computeProfiles = summarizeComputeProfileArtifacts(repoRoot, limit);
|
|
487
|
+
const adaptiveWorkflows = summarizeAdaptiveWorkflowArtifacts(repoRoot, limit);
|
|
488
|
+
const promotionCandidates = summarizePromotionCandidates(repoRoot, limit);
|
|
489
|
+
const goalRoomEvents = summarizeGoalRoomEvents(repoRoot, limit);
|
|
490
|
+
const transport = buildZobComsTransportReadiness(repoRoot);
|
|
491
|
+
const communicationAudit = buildZobCommunicationReadinessAudit(repoRoot, definition);
|
|
492
|
+
const livePresence = buildZobLivePresenceSummary(repoRoot, definition.name);
|
|
493
|
+
const liveRegistry = readZobLiveRegistrySnapshot(repoRoot, definition.name);
|
|
494
|
+
const proposals = readCommandProposalLedger(repoRoot).slice(-limit).map((proposal) => ({
|
|
495
|
+
proposalId: proposal.proposalId,
|
|
496
|
+
runId: proposal.runId,
|
|
497
|
+
command: proposal.command,
|
|
498
|
+
commandHash: proposal.commandHash,
|
|
499
|
+
receiver: proposal.receiver,
|
|
500
|
+
targetRole: proposal.targetRole,
|
|
501
|
+
priority: proposal.priority,
|
|
502
|
+
todoId: proposal.todoId,
|
|
503
|
+
subtreeRootTodoId: proposal.subtreeRootTodoId,
|
|
504
|
+
proposalOnly: proposal.proposalOnly,
|
|
505
|
+
directWorkerWrite: proposal.directWorkerWrite,
|
|
506
|
+
transportDispatch: proposal.transportDispatch,
|
|
507
|
+
bodyStored: proposal.bodyStored,
|
|
508
|
+
generatedAt: proposal.generatedAt,
|
|
509
|
+
}));
|
|
510
|
+
return {
|
|
511
|
+
schema: "zob.mission-control-snapshot.v1",
|
|
512
|
+
generatedAt: new Date().toISOString(),
|
|
513
|
+
operatorCapabilities: {
|
|
514
|
+
answersStatusQuestions: true,
|
|
515
|
+
createsTypedCommandProposals: true,
|
|
516
|
+
directWorkerWrites: false,
|
|
517
|
+
bypassesParentGates: false,
|
|
518
|
+
networkComsEnabled: false,
|
|
519
|
+
livePresenceVisible: true,
|
|
520
|
+
eventedAgentMessages: true,
|
|
521
|
+
},
|
|
522
|
+
requirements: ["queue", "runs", "factory_status", "telemetry", "coms", "goal_room_events", "live_presence", "adaptive_workflows", "promotion_candidates", "autonomy_audit", "typed_command_proposals"],
|
|
523
|
+
queue: queueDashboard,
|
|
524
|
+
runs: {
|
|
525
|
+
orchestration: orchestrationRuns,
|
|
526
|
+
factory: factoryRuns,
|
|
527
|
+
},
|
|
528
|
+
factoryStatus: summarizeFactoryStatus(factoryRuns),
|
|
529
|
+
computeProfiles: {
|
|
530
|
+
latest: computeProfiles,
|
|
531
|
+
bodySafety: { summariesBodyFree: !computeProfiles.some(hasForbiddenBodyKey) },
|
|
532
|
+
uiReadyMetadataOnly: true,
|
|
533
|
+
},
|
|
534
|
+
adaptiveWorkflows: {
|
|
535
|
+
latest: adaptiveWorkflows,
|
|
536
|
+
bodySafety: { summariesBodyFree: !adaptiveWorkflows.some(hasForbiddenBodyKey) },
|
|
537
|
+
uiReadyMetadataOnly: true,
|
|
538
|
+
},
|
|
539
|
+
promotionCandidates,
|
|
540
|
+
telemetry: telemetryDaily ? { date: telemetryDaily.date, totals: telemetryDaily.totals, statusCounts: telemetryDaily.statusCounts, bodySafety: telemetryDaily.bodySafety } : { date: today, missing: true },
|
|
541
|
+
goalRoomEvents: {
|
|
542
|
+
latest: goalRoomEvents,
|
|
543
|
+
bodySafety: { eventsBodyFree: !goalRoomEvents.some(hasForbiddenBodyKey) },
|
|
544
|
+
parentVisible: true,
|
|
545
|
+
hiddenPeerChat: false,
|
|
546
|
+
workerToWorkerDirect: false,
|
|
547
|
+
reducerRequiredForTodoMutation: true,
|
|
548
|
+
},
|
|
549
|
+
coms: {
|
|
550
|
+
messages: comsLedgerRecords.length,
|
|
551
|
+
statusEvents: comsStatusRecords.length,
|
|
552
|
+
latest: comsMessages.map(redactComsMessage),
|
|
553
|
+
livePresence,
|
|
554
|
+
livePeers: liveRegistry.peers.map(redactZobLivePeerForMissionControl),
|
|
555
|
+
zpeerRooms: summarizeZpeerRooms(liveRegistry.peers as unknown as Array<Record<string, unknown>>),
|
|
556
|
+
zpeerReadiness: { localOnly: true, networkEnabled: false, bodyStored: false },
|
|
557
|
+
bodySafety: { ledgersBodyFree: ![...comsLedgerRecords, ...comsStatusRecords].some(hasForbiddenBodyKey), liveRegistryBodyFree: !hasForbiddenBodyKey(liveRegistry) },
|
|
558
|
+
},
|
|
559
|
+
autonomy: autonomyAudit ? { verdict: autonomyAudit.verdict, globalAutonomyReady: autonomyAudit.globalAutonomyReady, globalAutonomyNoShip: autonomyAudit.globalAutonomyNoShip, blockers: autonomyAudit.blockers } : { missing: true },
|
|
560
|
+
factoryRegistry: factoryRegistryAudit ? { verdict: factoryRegistryAudit.verdict, registeredAgenticBatchReadyFactories: factoryRegistryAudit.registeredAgenticBatchReadyFactories, factoriesMissingRegisteredBatchProof: factoryRegistryAudit.factoriesMissingRegisteredBatchProof } : { missing: true },
|
|
561
|
+
transport,
|
|
562
|
+
communicationAudit: { verdict: communicationAudit.verdict, no_ship: communicationAudit.no_ship, failedChecks: communicationAudit.failedChecks },
|
|
563
|
+
commandProposals: {
|
|
564
|
+
proposalOnly: true,
|
|
565
|
+
directWorkerWrites: false,
|
|
566
|
+
allowedCommands: [...MISSION_CONTROL_COMMANDS],
|
|
567
|
+
latest: proposals,
|
|
568
|
+
},
|
|
569
|
+
bodyStored: false,
|
|
570
|
+
promptBodiesStored: false,
|
|
571
|
+
outputBodiesStored: false,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { isRecord } from "./utils/records.js";
|
|
5
|
+
|
|
6
|
+
export type ExplicitModelOverrideValidation = {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
errors: string[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function explicitModelOverrideHelp(model: string, reason: string): string {
|
|
12
|
+
return [
|
|
13
|
+
`explicit model override '${model}' is not allowed for child launch: ${reason}`,
|
|
14
|
+
"desired, configured, or catalogued model names are not runtime availability/authentication proof",
|
|
15
|
+
"omit model to use the parent/session default, or choose a model in .pi/model-catalog.json with resolutionStatus=verified after confirming current provider availability for this session",
|
|
16
|
+
].join("; ");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function validateExplicitModelOverride(repoRoot: string, modelOverride: string | undefined): ExplicitModelOverrideValidation {
|
|
20
|
+
const model = modelOverride?.trim();
|
|
21
|
+
if (!model) return { ok: true, errors: [] };
|
|
22
|
+
|
|
23
|
+
const catalogPath = join(repoRoot, ".pi", "model-catalog.json");
|
|
24
|
+
if (!existsSync(catalogPath)) {
|
|
25
|
+
return { ok: false, errors: [explicitModelOverrideHelp(model, ".pi/model-catalog.json is missing")] };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let parsed: unknown;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(readFileSync(catalogPath, "utf8")) as unknown;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
return { ok: false, errors: [explicitModelOverrideHelp(model, `.pi/model-catalog.json could not be read as JSON (${message})`)] };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const models = isRecord(parsed) && isRecord(parsed.models) ? parsed.models : undefined;
|
|
37
|
+
if (!models) {
|
|
38
|
+
return { ok: false, errors: [explicitModelOverrideHelp(model, ".pi/model-catalog.json has no models object")] };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const entry = models[model];
|
|
42
|
+
if (!isRecord(entry)) {
|
|
43
|
+
return { ok: false, errors: [explicitModelOverrideHelp(model, "model is not present in .pi/model-catalog.json")] };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (entry.resolutionStatus !== "verified") {
|
|
47
|
+
const status = typeof entry.resolutionStatus === "string" ? entry.resolutionStatus : "missing";
|
|
48
|
+
return { ok: false, errors: [explicitModelOverrideHelp(model, `catalog resolutionStatus is '${status}', not 'verified'`)] };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { ok: true, errors: [] };
|
|
52
|
+
}
|