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,211 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { TeamDefinition, ZobComsMessageInput } from "../types.js";
|
|
5
|
+
import { sha256 } from "../utils/hashing.js";
|
|
6
|
+
import { readJsonl } from "../utils/json.js";
|
|
7
|
+
|
|
8
|
+
function comsDir(repoRoot: string): string {
|
|
9
|
+
return join(repoRoot, ".pi", "coms");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function comsMessagesPath(repoRoot: string): string {
|
|
13
|
+
return join(comsDir(repoRoot), "messages.jsonl");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function comsStatusPath(repoRoot: string): string {
|
|
17
|
+
return join(comsDir(repoRoot), "status.jsonl");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ZobComsStatusTransitionOptions = {
|
|
21
|
+
outputHash?: string | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function nonEmptyString(value: unknown): value is string {
|
|
25
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function completionEvidencePresent(repoRoot: string, msgId: string, message: Record<string, unknown>, options: ZobComsStatusTransitionOptions): boolean {
|
|
29
|
+
if (nonEmptyString(options.outputHash)) return true;
|
|
30
|
+
if (nonEmptyString(message.outputHash)) return true;
|
|
31
|
+
const messages = readJsonl(comsMessagesPath(repoRoot));
|
|
32
|
+
return messages.some((candidate) => candidate.parentId === msgId && nonEmptyString(candidate.outputHash) && (candidate.status === "completed" || candidate.kind === "live_response_ref" || String(candidate.kind ?? "").endsWith("_reply")));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function validateZobComsEdge(definition: TeamDefinition, sender: string, receiver: string): string[] {
|
|
36
|
+
const errors: string[] = [];
|
|
37
|
+
const orchestratorId = definition.orchestrator.id;
|
|
38
|
+
const leadIds = new Set(definition.leads.map((lead) => lead.id));
|
|
39
|
+
const workerToLead = new Map(definition.workers.map((worker) => [worker.id, worker.leadId]));
|
|
40
|
+
const leadToWorkers = new Map(definition.leads.map((lead) => [lead.id, new Set((lead.workerIds ?? definition.workers.filter((worker) => worker.leadId === lead.id).map((worker) => worker.id)))]));
|
|
41
|
+
const knownIds = new Set([orchestratorId, ...leadIds, ...workerToLead.keys()]);
|
|
42
|
+
if (!knownIds.has(sender)) errors.push(`Unknown coms sender '${sender}'`);
|
|
43
|
+
if (!knownIds.has(receiver)) errors.push(`Unknown coms receiver '${receiver}'`);
|
|
44
|
+
if (errors.length > 0) return errors;
|
|
45
|
+
if (sender === orchestratorId && leadIds.has(receiver)) return [];
|
|
46
|
+
if (leadIds.has(sender) && receiver === orchestratorId) return [];
|
|
47
|
+
if (leadIds.has(sender) && leadToWorkers.get(sender)?.has(receiver)) return [];
|
|
48
|
+
if (workerToLead.has(sender) && workerToLead.get(sender) === receiver) return [];
|
|
49
|
+
if (workerToLead.has(sender) && workerToLead.has(receiver)) errors.push("Worker-to-worker coms are blocked by topology guard");
|
|
50
|
+
else errors.push(`Coms edge not allowed by team topology: ${sender} -> ${receiver}`);
|
|
51
|
+
return errors;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function buildZobComsMessage(input: ZobComsMessageInput): Record<string, unknown> {
|
|
55
|
+
const bodyPolicy = input.bodyPolicy ?? "hash_only";
|
|
56
|
+
const bodyHash = input.body ? sha256(input.body) : undefined;
|
|
57
|
+
return {
|
|
58
|
+
schema: "zob.coms-message.v1",
|
|
59
|
+
msgId: input.taskId ? `${input.runId}:${input.sender}:${input.receiver}:${input.taskId}` : `${input.runId}:${input.sender}:${input.receiver}:${Date.now()}`,
|
|
60
|
+
runId: input.runId,
|
|
61
|
+
parentId: input.parentId,
|
|
62
|
+
sender: input.sender,
|
|
63
|
+
receiver: input.receiver,
|
|
64
|
+
kind: input.kind ?? "handoff",
|
|
65
|
+
taskId: input.taskId,
|
|
66
|
+
taskHash: input.taskHash ?? bodyHash,
|
|
67
|
+
outputHash: input.outputHash ?? null,
|
|
68
|
+
status: input.status ?? "queued",
|
|
69
|
+
ack: input.ack ?? "not_sent",
|
|
70
|
+
bodyPolicy,
|
|
71
|
+
bodyStored: false,
|
|
72
|
+
bodyHash,
|
|
73
|
+
metadata: input.metadata ?? {},
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function validateZobComsMessage(message: Record<string, unknown>): string[] {
|
|
79
|
+
const errors: string[] = [];
|
|
80
|
+
for (const field of ["schema", "msgId", "runId", "sender", "receiver", "kind", "status", "bodyPolicy"]) {
|
|
81
|
+
if (typeof message[field] !== "string") errors.push(`Coms message missing string field '${field}'`);
|
|
82
|
+
}
|
|
83
|
+
if (message.schema !== "zob.coms-message.v1") errors.push("Coms message schema must be zob.coms-message.v1");
|
|
84
|
+
if ("body" in message || "task" in message || "output" in message || "prompt" in message) errors.push("Coms message must not store prompt/task/output bodies");
|
|
85
|
+
if (message.bodyStored !== false) errors.push("Coms message bodyStored must be false");
|
|
86
|
+
if (message.bodyPolicy !== "hash_only" && message.bodyPolicy !== "redacted") errors.push("Coms bodyPolicy must be hash_only or redacted");
|
|
87
|
+
if (message.taskHash !== undefined && message.taskHash !== null && typeof message.taskHash !== "string") errors.push("Coms taskHash must be string/null");
|
|
88
|
+
if (message.outputHash !== undefined && message.outputHash !== null && typeof message.outputHash !== "string") errors.push("Coms outputHash must be string/null");
|
|
89
|
+
if (message.status === "completed" && !nonEmptyString(message.outputHash)) errors.push("Coms completed message requires outputHash evidence");
|
|
90
|
+
return errors;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function appendZobComsMessage(repoRoot: string, definition: TeamDefinition, input: ZobComsMessageInput): Record<string, unknown> {
|
|
94
|
+
const edgeErrors = validateZobComsEdge(definition, input.sender, input.receiver);
|
|
95
|
+
if (edgeErrors.length > 0) throw new Error(edgeErrors.join("; "));
|
|
96
|
+
const message = buildZobComsMessage(input);
|
|
97
|
+
const messageErrors = validateZobComsMessage(message);
|
|
98
|
+
if (messageErrors.length > 0) throw new Error(messageErrors.join("; "));
|
|
99
|
+
mkdirSync(comsDir(repoRoot), { recursive: true });
|
|
100
|
+
appendFileSync(comsMessagesPath(repoRoot), `${JSON.stringify(message)}\n`, "utf8");
|
|
101
|
+
appendFileSync(comsStatusPath(repoRoot), `${JSON.stringify({ schema: "zob.coms-status.v1", event: "message_appended", msgId: message.msgId, runId: message.runId, sender: message.sender, receiver: message.receiver, status: message.status, ack: message.ack, outputHash: message.outputHash ?? null, timestamp: message.timestamp, bodyStored: false })}\n`, "utf8");
|
|
102
|
+
return message;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildZobComsDerivedMessage(message: Record<string, unknown>, events: Array<Record<string, unknown>>, messages: Array<Record<string, unknown>>): Record<string, unknown> {
|
|
106
|
+
const msgId = String(message.msgId ?? "");
|
|
107
|
+
const ownEvents = events.filter((event) => event.msgId === msgId);
|
|
108
|
+
const latestStatus = [...ownEvents].reverse().find((event) => typeof event.status === "string");
|
|
109
|
+
const latestAck = [...ownEvents].reverse().find((event) => typeof event.ack === "string");
|
|
110
|
+
const replyIds = messages.filter((candidate) => candidate.parentId === msgId).map((candidate) => candidate.msgId).filter((replyId): replyId is string => typeof replyId === "string");
|
|
111
|
+
return {
|
|
112
|
+
...message,
|
|
113
|
+
status: typeof latestStatus?.status === "string" ? latestStatus.status : message.status,
|
|
114
|
+
ack: typeof latestAck?.ack === "string" ? latestAck.ack : message.ack,
|
|
115
|
+
replyIds,
|
|
116
|
+
replies: replyIds.length,
|
|
117
|
+
lastEvent: ownEvents.length > 0 ? ownEvents[ownEvents.length - 1] : undefined,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function appendZobComsStatusEvent(repoRoot: string, event: Record<string, unknown>): Record<string, unknown> {
|
|
122
|
+
if ("body" in event || "task" in event || "output" in event || "prompt" in event || "content" in event || "message" in event || "text" in event || "rationale" in event || "diff" in event || "patch" in event) throw new Error("Coms status event must not store prompt/task/output bodies");
|
|
123
|
+
mkdirSync(comsDir(repoRoot), { recursive: true });
|
|
124
|
+
const record = { schema: "zob.coms-status.v1", timestamp: new Date().toISOString(), ...event, bodyStored: false };
|
|
125
|
+
appendFileSync(comsStatusPath(repoRoot), `${JSON.stringify(record)}\n`, "utf8");
|
|
126
|
+
return getZobComsMessage(repoRoot, String(event.msgId)) ?? record;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function listZobComsMessages(repoRoot: string, filter: { runId?: string; receiver?: string; sender?: string; status?: string; limit?: number } = {}): Array<Record<string, unknown>> {
|
|
130
|
+
const limit = Math.max(1, Math.min(100, Math.floor(filter.limit ?? 20)));
|
|
131
|
+
const messages = readJsonl(comsMessagesPath(repoRoot));
|
|
132
|
+
const events = readJsonl(comsStatusPath(repoRoot));
|
|
133
|
+
return messages
|
|
134
|
+
.map((message) => buildZobComsDerivedMessage(message, events, messages))
|
|
135
|
+
.filter((message) => !filter.runId || message.runId === filter.runId)
|
|
136
|
+
.filter((message) => !filter.receiver || message.receiver === filter.receiver)
|
|
137
|
+
.filter((message) => !filter.sender || message.sender === filter.sender)
|
|
138
|
+
.filter((message) => !filter.status || message.status === filter.status)
|
|
139
|
+
.slice(-limit);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function getZobComsMessage(repoRoot: string, msgId: string): Record<string, unknown> | undefined {
|
|
143
|
+
const messages = readJsonl(comsMessagesPath(repoRoot));
|
|
144
|
+
const message = messages.find((candidate) => candidate.msgId === msgId);
|
|
145
|
+
return message ? buildZobComsDerivedMessage(message, readJsonl(comsStatusPath(repoRoot)), messages) : undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function ackZobComsMessage(repoRoot: string, msgId: string, actor: string): Record<string, unknown> {
|
|
149
|
+
const message = getZobComsMessage(repoRoot, msgId);
|
|
150
|
+
if (!message) throw new Error(`Coms message not found: ${msgId}`);
|
|
151
|
+
if (message.receiver !== actor) throw new Error(`Coms ACK actor must be receiver: ${actor}`);
|
|
152
|
+
return appendZobComsStatusEvent(repoRoot, { event: "ack", msgId, runId: message.runId, actor, ack: "received", status: "acknowledged" });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function transitionZobComsStatus(repoRoot: string, msgId: string, actor: string, status: string, options: ZobComsStatusTransitionOptions = {}): Record<string, unknown> {
|
|
156
|
+
const message = getZobComsMessage(repoRoot, msgId);
|
|
157
|
+
if (!message) throw new Error(`Coms message not found: ${msgId}`);
|
|
158
|
+
if (message.sender !== actor && message.receiver !== actor) throw new Error(`Coms status actor must be sender or receiver: ${actor}`);
|
|
159
|
+
if (status === "completed" && !completionEvidencePresent(repoRoot, msgId, message, options)) throw new Error("Coms completed status requires outputHash or live response evidence");
|
|
160
|
+
const event: Record<string, unknown> = { event: "status", msgId, runId: message.runId, actor, status };
|
|
161
|
+
if (nonEmptyString(options.outputHash)) event.outputHash = options.outputHash;
|
|
162
|
+
return appendZobComsStatusEvent(repoRoot, event);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function replyZobComsMessage(repoRoot: string, definition: TeamDefinition, msgId: string, input: Omit<ZobComsMessageInput, "runId" | "parentId">): Record<string, unknown> {
|
|
166
|
+
const parent = getZobComsMessage(repoRoot, msgId);
|
|
167
|
+
if (!parent || typeof parent.runId !== "string") throw new Error(`Coms parent message not found: ${msgId}`);
|
|
168
|
+
const reply = appendZobComsMessage(repoRoot, definition, { ...input, runId: parent.runId, parentId: msgId, kind: input.kind ?? "reply" });
|
|
169
|
+
appendZobComsStatusEvent(repoRoot, { event: "reply", msgId, runId: parent.runId, actor: input.sender, replyMsgId: reply.msgId, status: parent.status, outputHash: reply.outputHash ?? null });
|
|
170
|
+
return reply;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function awaitZobComsMessage(repoRoot: string, filter: { runId?: string; receiver?: string; status?: string; timeoutMs?: number; pollMs?: number } = {}): Promise<Record<string, unknown> | undefined> {
|
|
174
|
+
const timeoutMs = Math.max(0, Math.min(5000, Math.floor(filter.timeoutMs ?? 1000)));
|
|
175
|
+
const pollMs = Math.max(25, Math.min(1000, Math.floor(filter.pollMs ?? 100)));
|
|
176
|
+
const deadline = Date.now() + timeoutMs;
|
|
177
|
+
do {
|
|
178
|
+
const [message] = listZobComsMessages(repoRoot, { runId: filter.runId, receiver: filter.receiver, status: filter.status, limit: 1 });
|
|
179
|
+
if (message) return message;
|
|
180
|
+
if (Date.now() >= deadline) break;
|
|
181
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, Math.min(pollMs, Math.max(0, deadline - Date.now()))));
|
|
182
|
+
} while (Date.now() <= deadline);
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function mirrorOrchestrationToComs(repoRoot: string, definition: TeamDefinition, messages: Array<Record<string, unknown>>): number {
|
|
187
|
+
let mirrored = 0;
|
|
188
|
+
for (const message of messages) {
|
|
189
|
+
const sender = typeof message.sender === "string" ? message.sender : "";
|
|
190
|
+
const receiver = typeof message.receiver === "string" ? message.receiver : "";
|
|
191
|
+
const edgeErrors = validateZobComsEdge(definition, sender, receiver);
|
|
192
|
+
if (edgeErrors.length > 0) continue;
|
|
193
|
+
appendZobComsMessage(repoRoot, definition, {
|
|
194
|
+
runId: typeof message.runId === "string" ? message.runId : "unknown-run",
|
|
195
|
+
sender,
|
|
196
|
+
receiver,
|
|
197
|
+
kind: "plan_only_handoff",
|
|
198
|
+
taskId: typeof message.taskId === "string" ? message.taskId : undefined,
|
|
199
|
+
parentId: typeof message.parentId === "string" ? message.parentId : undefined,
|
|
200
|
+
taskHash: typeof message.taskHash === "string" ? message.taskHash : undefined,
|
|
201
|
+
outputHash: typeof message.outputHash === "string" ? message.outputHash : null,
|
|
202
|
+
status: typeof message.status === "string" ? message.status : "planned",
|
|
203
|
+
ack: typeof message.ack === "string" ? message.ack : "not_sent",
|
|
204
|
+
metadata: { source: "orchestrate_run", execution: typeof message.execution === "string" ? message.execution : "plan_only", noExecution: true },
|
|
205
|
+
});
|
|
206
|
+
mirrored += 1;
|
|
207
|
+
}
|
|
208
|
+
return mirrored;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { mirrorOrchestrationToComs };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { loadProjectAgents } from "../agents.js";
|
|
5
|
+
import { normalizeAdaptiveDelegationPolicy, validateAdaptiveDelegationPolicy } from "../orchestration/adaptive-delegation.js";
|
|
6
|
+
import { validateOutputContractId } from "../output-contracts.js";
|
|
7
|
+
import { validateAllowedPathPolicy, validateDelegateTaskWriteScope, validateForbiddenPathPolicy, validateToolList } from "../safety.js";
|
|
8
|
+
import type { OrchestrateRunInput, OrchestrationProfileDefinition, OrchestrationProfilePhase, OrchestrationProfileRole, TeamDefinition } from "../types.js";
|
|
9
|
+
import { parseJsonFile } from "../utils/json.js";
|
|
10
|
+
import { isSafeArtifactName, safeFileStem } from "../utils/paths.js";
|
|
11
|
+
import { isRecord } from "../utils/records.js";
|
|
12
|
+
import { listZobResourceJsonStems, readableZobResourcePath } from "../utils/resources.js";
|
|
13
|
+
import { isStringArray, loadTeamDefinition, validateTeamDefinition } from "./teams.js";
|
|
14
|
+
|
|
15
|
+
function orchestrationProfilesDir(repoRoot: string): string {
|
|
16
|
+
return join(repoRoot, ".pi", "orchestrations");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isOrchestrationProfileRole(value: unknown): value is OrchestrationProfileRole {
|
|
20
|
+
return (
|
|
21
|
+
isRecord(value) &&
|
|
22
|
+
typeof value.id === "string" &&
|
|
23
|
+
typeof value.roleType === "string" &&
|
|
24
|
+
typeof value.agent === "string" &&
|
|
25
|
+
typeof value.outputContract === "string" &&
|
|
26
|
+
(value.modelClass === undefined || typeof value.modelClass === "string") &&
|
|
27
|
+
(value.leadId === undefined || typeof value.leadId === "string") &&
|
|
28
|
+
(value.canDelegateTo === undefined || isStringArray(value.canDelegateTo)) &&
|
|
29
|
+
(value.requiredTools === undefined || isStringArray(value.requiredTools)) &&
|
|
30
|
+
(value.tools === undefined || isStringArray(value.tools)) &&
|
|
31
|
+
(value.allowedPaths === undefined || isStringArray(value.allowedPaths)) &&
|
|
32
|
+
(value.forbiddenPaths === undefined || isStringArray(value.forbiddenPaths)) &&
|
|
33
|
+
(value.rules === undefined || isStringArray(value.rules))
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isOrchestrationProfilePhase(value: unknown): value is OrchestrationProfilePhase {
|
|
38
|
+
return (
|
|
39
|
+
isRecord(value) &&
|
|
40
|
+
typeof value.id === "string" &&
|
|
41
|
+
typeof value.type === "string" &&
|
|
42
|
+
(value.run === undefined || isStringArray(value.run)) &&
|
|
43
|
+
(value.required === undefined || typeof value.required === "boolean") &&
|
|
44
|
+
(value.requiresOutputContract === undefined || typeof value.requiresOutputContract === "string") &&
|
|
45
|
+
(value.modelClassOverride === undefined || typeof value.modelClassOverride === "string") &&
|
|
46
|
+
(value.noShipOnFail === undefined || typeof value.noShipOnFail === "boolean")
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isOrchestrationProfileDefinition(value: unknown): value is OrchestrationProfileDefinition {
|
|
51
|
+
return (
|
|
52
|
+
isRecord(value) &&
|
|
53
|
+
(value.schema === undefined || value.schema === "zob.orchestration-profile.v1") &&
|
|
54
|
+
typeof value.name === "string" &&
|
|
55
|
+
typeof value.version === "string" &&
|
|
56
|
+
(value.description === undefined || typeof value.description === "string") &&
|
|
57
|
+
isOrchestrationProfileRole(value.orchestrator) &&
|
|
58
|
+
Array.isArray(value.roles) &&
|
|
59
|
+
value.roles.every(isOrchestrationProfileRole) &&
|
|
60
|
+
Array.isArray(value.edges) &&
|
|
61
|
+
value.edges.every((edge) => Array.isArray(edge) && edge.length === 2 && typeof edge[0] === "string" && typeof edge[1] === "string") &&
|
|
62
|
+
Array.isArray(value.phases) &&
|
|
63
|
+
value.phases.every(isOrchestrationProfilePhase) &&
|
|
64
|
+
(value.finalReportRole === undefined || typeof value.finalReportRole === "string")
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function listOrchestrationProfiles(repoRoot: string): string[] {
|
|
69
|
+
return listZobResourceJsonStems(repoRoot, "orchestrations");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function loadOrchestrationProfile(repoRoot: string, profileName: string): { definition?: OrchestrationProfileDefinition; profilePath: string; errors: string[] } {
|
|
73
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(profileName)) return { profilePath: join(orchestrationProfilesDir(repoRoot), `${safeFileStem(profileName)}.json`), errors: [`Invalid orchestration profile name '${profileName}'`] };
|
|
74
|
+
const profilePath = readableZobResourcePath(repoRoot, "orchestrations", `${profileName}.json`);
|
|
75
|
+
if (!existsSync(profilePath)) return { profilePath, errors: [`Orchestration profile not found: ${profilePath}`] };
|
|
76
|
+
try {
|
|
77
|
+
const parsed = parseJsonFile(profilePath);
|
|
78
|
+
if (!isOrchestrationProfileDefinition(parsed)) return { profilePath, errors: [`Invalid orchestration profile: ${profilePath}`] };
|
|
79
|
+
if (parsed.name !== profileName) return { profilePath, errors: [`Orchestration profile name '${parsed.name}' does not match requested '${profileName}'`] };
|
|
80
|
+
return { definition: parsed, profilePath, errors: [] };
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return { profilePath, errors: [`Could not parse orchestration profile '${profilePath}': ${error instanceof Error ? error.message : String(error)}`] };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function validateOrchestrationProfile(repoRoot: string, profile: OrchestrationProfileDefinition | undefined): string[] {
|
|
87
|
+
const errors: string[] = [];
|
|
88
|
+
if (!profile) return ["Orchestration profile is missing"];
|
|
89
|
+
if (!isSafeArtifactName(profile.name)) errors.push(`Orchestration profile name must be path-safe: ${profile.name}`);
|
|
90
|
+
const agents = new Map(loadProjectAgents(repoRoot).map((agent) => [agent.name.toLowerCase(), agent]));
|
|
91
|
+
const modelClasses = new Set(Object.keys(profile.modelPolicy?.classes ?? {}));
|
|
92
|
+
if (modelClasses.size === 0) errors.push("Orchestration profile must define modelPolicy.classes");
|
|
93
|
+
|
|
94
|
+
const roleIds = new Set<string>();
|
|
95
|
+
const allRoles = [profile.orchestrator, ...profile.roles];
|
|
96
|
+
for (const role of allRoles) {
|
|
97
|
+
if (roleIds.has(role.id)) errors.push(`Duplicate orchestration role id: ${role.id}`);
|
|
98
|
+
roleIds.add(role.id);
|
|
99
|
+
if (!isSafeArtifactName(role.id)) errors.push(`Orchestration role id must be path-safe: ${role.id}`);
|
|
100
|
+
const agent = agents.get(role.agent.toLowerCase());
|
|
101
|
+
if (!agent) {
|
|
102
|
+
errors.push(`Role '${role.id}' references unknown agent '${role.agent}'`);
|
|
103
|
+
} else {
|
|
104
|
+
const tools = role.requiredTools ?? role.tools ?? [];
|
|
105
|
+
errors.push(...validateToolList(agent, tools).map((error) => `Role '${role.id}': ${error}`));
|
|
106
|
+
errors.push(...validateDelegateTaskWriteScope(tools, role.allowedPaths).map((error) => `Role '${role.id}': ${error}`));
|
|
107
|
+
}
|
|
108
|
+
errors.push(...validateAllowedPathPolicy(role.allowedPaths, `Role '${role.id}' allowedPaths`, repoRoot));
|
|
109
|
+
errors.push(...validateForbiddenPathPolicy(role.forbiddenPaths, `Role '${role.id}' forbiddenPaths`, repoRoot));
|
|
110
|
+
errors.push(...validateOutputContractId(role.outputContract).map((error) => `Role '${role.id}': ${error}`));
|
|
111
|
+
if (role.modelClass && !modelClasses.has(role.modelClass)) errors.push(`Role '${role.id}' references unknown modelClass '${role.modelClass}'`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const leadIds = new Set(profile.roles.filter((role) => role.roleType === "lead" || role.canDelegateTo !== undefined).map((role) => role.id));
|
|
115
|
+
for (const role of profile.roles) {
|
|
116
|
+
if (role.roleType === "worker" && role.leadId && !leadIds.has(role.leadId)) errors.push(`Worker '${role.id}' references unknown lead '${role.leadId}'`);
|
|
117
|
+
for (const workerId of role.canDelegateTo ?? []) {
|
|
118
|
+
if (!roleIds.has(workerId)) errors.push(`Role '${role.id}' canDelegateTo unknown role '${workerId}'`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const seenEdges = new Set<string>();
|
|
123
|
+
for (const [sender, receiver] of profile.edges) {
|
|
124
|
+
const edgeKey = `${sender}->${receiver}`;
|
|
125
|
+
if (seenEdges.has(edgeKey)) errors.push(`Duplicate orchestration edge: ${edgeKey}`);
|
|
126
|
+
seenEdges.add(edgeKey);
|
|
127
|
+
if (!roleIds.has(sender)) errors.push(`Edge sender unknown: ${sender}`);
|
|
128
|
+
if (!roleIds.has(receiver)) errors.push(`Edge receiver unknown: ${receiver}`);
|
|
129
|
+
const senderRole = allRoles.find((role) => role.id === sender);
|
|
130
|
+
const receiverRole = allRoles.find((role) => role.id === receiver);
|
|
131
|
+
if (senderRole?.roleType === "worker" && receiverRole?.roleType === "worker") errors.push(`Worker-to-worker edge requires explicit future policy gate: ${edgeKey}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for (const phase of profile.phases) {
|
|
135
|
+
if (!isSafeArtifactName(phase.id)) errors.push(`Orchestration phase id must be path-safe: ${phase.id}`);
|
|
136
|
+
for (const roleId of phase.run ?? []) {
|
|
137
|
+
if (!roleIds.has(roleId)) errors.push(`Phase '${phase.id}' references unknown role '${roleId}'`);
|
|
138
|
+
}
|
|
139
|
+
if (phase.requiresOutputContract) errors.push(...validateOutputContractId(phase.requiresOutputContract).map((error) => `Phase '${phase.id}': ${error}`));
|
|
140
|
+
if (phase.modelClassOverride && !modelClasses.has(phase.modelClassOverride)) errors.push(`Phase '${phase.id}' references unknown modelClassOverride '${phase.modelClassOverride}'`);
|
|
141
|
+
}
|
|
142
|
+
if (profile.finalReportRole && !roleIds.has(profile.finalReportRole)) errors.push(`finalReportRole references unknown role '${profile.finalReportRole}'`);
|
|
143
|
+
return errors;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function roleTools(role: OrchestrationProfileRole): string[] {
|
|
147
|
+
return role.requiredTools ?? role.tools ?? [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function teamDefinitionFromOrchestrationProfile(profile: OrchestrationProfileDefinition): TeamDefinition {
|
|
151
|
+
const leads = profile.roles.filter((role) => role.roleType === "lead" || role.canDelegateTo !== undefined).map((role) => ({
|
|
152
|
+
id: role.id,
|
|
153
|
+
agent: role.agent,
|
|
154
|
+
description: `Lead role from orchestration profile ${profile.name}`,
|
|
155
|
+
requiredTools: roleTools(role),
|
|
156
|
+
outputContract: role.outputContract,
|
|
157
|
+
workerIds: role.canDelegateTo ?? profile.roles.filter((candidate) => candidate.roleType === "worker" && candidate.leadId === role.id).map((candidate) => candidate.id),
|
|
158
|
+
responsibilities: role.rules,
|
|
159
|
+
}));
|
|
160
|
+
const workers = profile.roles.filter((role) => role.roleType === "worker").map((role) => ({
|
|
161
|
+
id: role.id,
|
|
162
|
+
leadId: role.leadId ?? "",
|
|
163
|
+
agent: role.agent,
|
|
164
|
+
description: `Worker role from orchestration profile ${profile.name}`,
|
|
165
|
+
requiredTools: roleTools(role),
|
|
166
|
+
outputContract: role.outputContract,
|
|
167
|
+
taskTemplate: `Execute profile worker '${role.id}' for goal: {goal}. Return evidence, blockers, compliance, and deliverable_delivered. Run id: {run.id}.`,
|
|
168
|
+
}));
|
|
169
|
+
return {
|
|
170
|
+
name: profile.name,
|
|
171
|
+
version: profile.version,
|
|
172
|
+
description: profile.description ?? `Orchestration profile ${profile.name}`,
|
|
173
|
+
orchestrator: {
|
|
174
|
+
id: profile.orchestrator.id,
|
|
175
|
+
agent: profile.orchestrator.agent,
|
|
176
|
+
description: `Orchestrator role from orchestration profile ${profile.name}`,
|
|
177
|
+
requiredTools: roleTools(profile.orchestrator),
|
|
178
|
+
outputContract: profile.orchestrator.outputContract,
|
|
179
|
+
responsibilities: profile.orchestrator.rules,
|
|
180
|
+
},
|
|
181
|
+
leads,
|
|
182
|
+
workers,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function validateOrchestrateRunInputs(repoRoot: string, input: OrchestrateRunInput): string[] {
|
|
187
|
+
const errors: string[] = [];
|
|
188
|
+
if (!input.goal || input.goal.trim().length === 0) errors.push("goal is required");
|
|
189
|
+
if (input.run_id && safeFileStem(input.run_id) !== input.run_id) errors.push(`run_id must be path-safe: ${input.run_id}`);
|
|
190
|
+
if (input.execution !== undefined && input.execution !== "plan_only" && input.execution !== "supervised_smoke" && input.execution !== "supervised_readonly") errors.push("orchestrate_run only supports execution=plan_only, execution=supervised_smoke, or execution=supervised_readonly");
|
|
191
|
+
if (input.max_workers !== undefined && (!Number.isInteger(input.max_workers) || input.max_workers < 1)) errors.push("max_workers must be a positive integer");
|
|
192
|
+
errors.push(...validateAdaptiveDelegationPolicy(normalizeAdaptiveDelegationPolicy(input.adaptive_delegation)));
|
|
193
|
+
if (input.team && input.profile) errors.push("orchestrate_run accepts either team or profile, not both");
|
|
194
|
+
if (input.profile) {
|
|
195
|
+
const profile = loadOrchestrationProfile(repoRoot, input.profile);
|
|
196
|
+
errors.push(...profile.errors);
|
|
197
|
+
errors.push(...validateOrchestrationProfile(repoRoot, profile.definition));
|
|
198
|
+
} else {
|
|
199
|
+
const team = loadTeamDefinition(repoRoot, input.team ?? "zob-core");
|
|
200
|
+
errors.push(...team.errors);
|
|
201
|
+
errors.push(...validateTeamDefinition(repoRoot, team.definition));
|
|
202
|
+
}
|
|
203
|
+
return errors;
|
|
204
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { loadProjectAgents } from "../agents.js";
|
|
5
|
+
import { validateOutputContractId } from "../output-contracts.js";
|
|
6
|
+
import { validateToolList } from "../safety.js";
|
|
7
|
+
import type { HarnessAgent, TeamDefinition, TeamLead, TeamRoleBase, TeamWorker } from "../types.js";
|
|
8
|
+
import { parseJsonFile } from "../utils/json.js";
|
|
9
|
+
import { isSafeArtifactName, safeFileStem } from "../utils/paths.js";
|
|
10
|
+
import { isRecord } from "../utils/records.js";
|
|
11
|
+
import { readableZobResourcePath } from "../utils/resources.js";
|
|
12
|
+
|
|
13
|
+
function isStringArray(value: unknown): value is string[] {
|
|
14
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isTeamRoleBase(value: unknown): value is TeamRoleBase {
|
|
18
|
+
return (
|
|
19
|
+
isRecord(value) &&
|
|
20
|
+
typeof value.id === "string" &&
|
|
21
|
+
typeof value.agent === "string" &&
|
|
22
|
+
isStringArray(value.requiredTools) &&
|
|
23
|
+
typeof value.outputContract === "string" &&
|
|
24
|
+
(value.description === undefined || typeof value.description === "string") &&
|
|
25
|
+
(value.model === undefined || typeof value.model === "string") &&
|
|
26
|
+
(value.responsibilities === undefined || isStringArray(value.responsibilities))
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isTeamLead(value: unknown): value is TeamLead {
|
|
31
|
+
return isTeamRoleBase(value) && (!isRecord(value) || value.workerIds === undefined || isStringArray(value.workerIds));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isTeamWorker(value: unknown): value is TeamWorker {
|
|
35
|
+
return isTeamRoleBase(value) && isRecord(value) && typeof value.leadId === "string" && (value.taskTemplate === undefined || typeof value.taskTemplate === "string");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isTeamDefinition(value: unknown): value is TeamDefinition {
|
|
39
|
+
return (
|
|
40
|
+
isRecord(value) &&
|
|
41
|
+
typeof value.name === "string" &&
|
|
42
|
+
typeof value.version === "string" &&
|
|
43
|
+
typeof value.description === "string" &&
|
|
44
|
+
isTeamRoleBase(value.orchestrator) &&
|
|
45
|
+
Array.isArray(value.leads) &&
|
|
46
|
+
value.leads.every(isTeamLead) &&
|
|
47
|
+
Array.isArray(value.workers) &&
|
|
48
|
+
value.workers.every(isTeamWorker)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function loadTeamDefinition(repoRoot: string, teamName: string): { definition?: TeamDefinition; teamPath: string; errors: string[] } {
|
|
53
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(teamName)) return { teamPath: join(repoRoot, ".pi", "teams", `${safeFileStem(teamName)}.json`), errors: [`Invalid team name '${teamName}'`] };
|
|
54
|
+
const teamPath = readableZobResourcePath(repoRoot, "teams", `${teamName}.json`);
|
|
55
|
+
if (!existsSync(teamPath)) return { teamPath, errors: [`Team topology not found: ${teamPath}`] };
|
|
56
|
+
try {
|
|
57
|
+
const parsed = parseJsonFile(teamPath);
|
|
58
|
+
if (!isTeamDefinition(parsed)) return { teamPath, errors: [`Invalid team topology: ${teamPath}`] };
|
|
59
|
+
if (parsed.name !== teamName) return { teamPath, errors: [`Team topology name '${parsed.name}' does not match requested '${teamName}'`] };
|
|
60
|
+
return { definition: parsed, teamPath, errors: [] };
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return { teamPath, errors: [`Could not parse team topology '${teamPath}': ${error instanceof Error ? error.message : String(error)}`] };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validateTeamRole(role: TeamRoleBase, label: string, agents: Map<string, HarnessAgent>): string[] {
|
|
67
|
+
const errors: string[] = [];
|
|
68
|
+
if (!isSafeArtifactName(role.id)) errors.push(`${label} id must be path-safe: ${role.id}`);
|
|
69
|
+
const agent = agents.get(role.agent.toLowerCase());
|
|
70
|
+
if (!agent) {
|
|
71
|
+
errors.push(`${label} references unknown agent '${role.agent}'`);
|
|
72
|
+
} else {
|
|
73
|
+
errors.push(...validateToolList(agent, role.requiredTools).map((error) => `${label}: ${error}`));
|
|
74
|
+
}
|
|
75
|
+
errors.push(...validateOutputContractId(role.outputContract).map((error) => `${label}: ${error}`));
|
|
76
|
+
return errors;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function validateTeamDefinition(repoRoot: string, definition: TeamDefinition | undefined): string[] {
|
|
80
|
+
const errors: string[] = [];
|
|
81
|
+
if (!definition) return ["Team topology is missing"];
|
|
82
|
+
if (!isSafeArtifactName(definition.name)) errors.push(`Team name must be path-safe: ${definition.name}`);
|
|
83
|
+
const agents = new Map(loadProjectAgents(repoRoot).map((agent) => [agent.name.toLowerCase(), agent]));
|
|
84
|
+
const ids = new Set<string>();
|
|
85
|
+
const markId = (id: string, label: string): void => {
|
|
86
|
+
if (ids.has(id)) errors.push(`Duplicate team role id: ${id}`);
|
|
87
|
+
ids.add(id);
|
|
88
|
+
if (!isSafeArtifactName(id)) errors.push(`${label} id must be path-safe: ${id}`);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
markId(definition.orchestrator.id, "orchestrator");
|
|
92
|
+
errors.push(...validateTeamRole(definition.orchestrator, `orchestrator '${definition.orchestrator.id}'`, agents));
|
|
93
|
+
if (definition.leads.length === 0) errors.push("Team topology must define at least one lead");
|
|
94
|
+
if (definition.workers.length === 0) errors.push("Team topology must define at least one worker");
|
|
95
|
+
|
|
96
|
+
const leadIds = new Set(definition.leads.map((lead) => lead.id));
|
|
97
|
+
const workerIds = new Set(definition.workers.map((worker) => worker.id));
|
|
98
|
+
for (const lead of definition.leads) {
|
|
99
|
+
markId(lead.id, "lead");
|
|
100
|
+
errors.push(...validateTeamRole(lead, `lead '${lead.id}'`, agents));
|
|
101
|
+
for (const workerId of lead.workerIds ?? []) {
|
|
102
|
+
if (!workerIds.has(workerId)) errors.push(`Lead '${lead.id}' references unknown worker '${workerId}'`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const worker of definition.workers) {
|
|
106
|
+
markId(worker.id, "worker");
|
|
107
|
+
errors.push(...validateTeamRole(worker, `worker '${worker.id}'`, agents));
|
|
108
|
+
if (!leadIds.has(worker.leadId)) errors.push(`Worker '${worker.id}' references unknown lead '${worker.leadId}'`);
|
|
109
|
+
}
|
|
110
|
+
return errors;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { isStringArray };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type ModeName = "explore" | "plan" | "implement" | "oracle" | "factory" | "orchestrator";
|
|
2
|
+
export type AgentScope = "project" | "user" | "both";
|
|
3
|
+
export type ChildThinkingLevel = "low" | "medium" | "high" | "xhigh";
|
|
4
|
+
|
|
5
|
+
export interface ChildChangedPathRef {
|
|
6
|
+
path: string;
|
|
7
|
+
pathHash: string;
|
|
8
|
+
status: string;
|
|
9
|
+
contentHash?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TextBlock = { type: "text"; text: string };
|
|
13
|
+
export type AssistantLikeMessage = {
|
|
14
|
+
role?: string;
|
|
15
|
+
content?: Array<TextBlock | { type: string; [key: string]: unknown }>;
|
|
16
|
+
usage?: {
|
|
17
|
+
input?: number;
|
|
18
|
+
output?: number;
|
|
19
|
+
cacheRead?: number;
|
|
20
|
+
cacheWrite?: number;
|
|
21
|
+
totalTokens?: number;
|
|
22
|
+
cost?: { total?: number };
|
|
23
|
+
};
|
|
24
|
+
model?: string;
|
|
25
|
+
provider?: string;
|
|
26
|
+
stopReason?: string;
|
|
27
|
+
errorMessage?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type JsonEvent = {
|
|
31
|
+
type?: string;
|
|
32
|
+
message?: AssistantLikeMessage;
|
|
33
|
+
messages?: AssistantLikeMessage[];
|
|
34
|
+
assistantMessageEvent?: { type?: string; delta?: string };
|
|
35
|
+
toolName?: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface HarnessAgent {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
tools?: string[];
|
|
42
|
+
model?: string;
|
|
43
|
+
thinking?: ChildThinkingLevel | string;
|
|
44
|
+
prompt: string;
|
|
45
|
+
source: "project" | "user";
|
|
46
|
+
filePath: string;
|
|
47
|
+
}
|