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,1315 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { AutocompleteItem } from "@earendil-works/pi-tui";
|
|
3
|
+
|
|
4
|
+
import { MODE_PROMPTS } from "../constants.js";
|
|
5
|
+
import type { ModeName, QueueTickResult } from "../types.js";
|
|
6
|
+
import { discoverAgents, formatAgentList } from "../agents.js";
|
|
7
|
+
import { buildComputePreview, resolveComputeProfile, type ComputeRequestedProfile } from "../compute-profile.js";
|
|
8
|
+
import { buildComputeWorkflowShape } from "../compute-workflow-shape.js";
|
|
9
|
+
import { buildDaemonRuntimeState, buildDaemonTickPlan, type DaemonRuntimeState, type DaemonTickPlan } from "../daemon-runtime.js";
|
|
10
|
+
import { runQueueDaemonTick } from "../queue.js";
|
|
11
|
+
import { buildProjectDnaAgenticPlan, buildProjectDnaQueryResult, buildProjectDnaReadinessAudit } from "../project-dna.js";
|
|
12
|
+
import { resolveAdaptiveZmodeEntrypoint, renderAdaptiveZmodeTemplate } from "./adaptive-zmode.js";
|
|
13
|
+
import { handleZcompactCommand } from "./auto-compaction.js";
|
|
14
|
+
import { sha256 } from "../utils/hashing.js";
|
|
15
|
+
import { buildZcommitPlan, formatZcommitPlan, formatZcommitStatus, readZcommitPolicy, runGovernedZcommitAdopt, runGovernedZcommitCommit, runGovernedZcommitPush, type ZcommitAdoptResult, type ZcommitCommandResult, type ZcommitOwnedPathRef, type ZcommitToggleState } from "../git-ops.js";
|
|
16
|
+
import { writeZpeerLocalProfileFromPeer } from "../coms-v2/zpeer-profile.js";
|
|
17
|
+
import { buildZpeerRoomSummary, changeZpeerAlias, changeZpeerRoom, joinZpeerRoom, leaveZpeerRoom, peerAliasInRoom, refreshZpeerSelf, sendZpeerPrompt, useZpeerRoom, zpeerMembershipsForPeer, type ZpeerSendMode } from "../coms-v2/zpeer.js";
|
|
18
|
+
import { parseBillableJobIntake, validateBillableJobIntake } from "../goal.js";
|
|
19
|
+
import { handleGoalCommand, handleGoalGateCommand, pauseRuntimeGoalForStop } from "../goal-runtime.js";
|
|
20
|
+
import { formatRuleResolution, resolveRuleProfile } from "../rules.js";
|
|
21
|
+
import { formatContractTemplate } from "../safety.js";
|
|
22
|
+
import { showDelegationOverlay } from "./delegation-overlay.js";
|
|
23
|
+
import { finishDelegationRun } from "./delegation-monitor.js";
|
|
24
|
+
import { showGoalTodoOverlay } from "./goal-todo-overlay.js";
|
|
25
|
+
import type { HarnessRuntimeState } from "./state.js";
|
|
26
|
+
import {
|
|
27
|
+
asInteractiveAutonomyMode,
|
|
28
|
+
formatInteractiveAutonomyStatus,
|
|
29
|
+
formatMissionReadinessForUi,
|
|
30
|
+
readInteractiveAutonomyPolicy,
|
|
31
|
+
scoreMissionReadiness,
|
|
32
|
+
toAutonomyStateLedgerEntry,
|
|
33
|
+
toMissionReadinessLedgerEntry,
|
|
34
|
+
} from "../interactive-autonomy.js";
|
|
35
|
+
import { applyMode, renderHarnessWidget } from "./widget.js";
|
|
36
|
+
|
|
37
|
+
const COMPUTE_PROFILES = ["auto", "low", "medium", "high", "xhigh", "max"] as const;
|
|
38
|
+
const COMPUTE_DOMAINS = ["generic", "project-dna", "factory", "orchestration"] as const;
|
|
39
|
+
|
|
40
|
+
function zcommitArgumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
41
|
+
const query = prefix.trim().toLowerCase();
|
|
42
|
+
const items: AutocompleteItem[] = [
|
|
43
|
+
{ value: "status", label: "status [paths/globs...]", description: "show governed commit state without staging" },
|
|
44
|
+
{ value: "plan", label: "plan [paths/globs...]", description: "plan safe workspace dirty files or explicit pathspecs" },
|
|
45
|
+
{ value: "adopt ", label: "adopt <paths...>", description: "advanced: explicitly mark exact dirty paths as owned without staging" },
|
|
46
|
+
{ value: "autocommit on", label: "autocommit on", description: "enable easy autocommit at assistant message end" },
|
|
47
|
+
{ value: "autocommit off", label: "autocommit off", description: "turn off session autocommit metadata" },
|
|
48
|
+
{ value: "autopush on", label: "autopush on", description: "enable gated autopush metadata only when autocommit is on" },
|
|
49
|
+
{ value: "autopush off", label: "autopush off", description: "turn off session autopush metadata" },
|
|
50
|
+
{ value: "commit", label: "commit [paths/globs...]", description: "commit safe workspace changes or explicit pathspecs with a Conventional Commit" },
|
|
51
|
+
{ value: "push", label: "push", description: "push last /zcommit commit to allowed remote/branch only" },
|
|
52
|
+
];
|
|
53
|
+
const filtered = query
|
|
54
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
55
|
+
: items;
|
|
56
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function zcommitOwnedPathLedgerRefs(state: HarnessRuntimeState): Array<Pick<ZcommitOwnedPathRef, "path" | "source" | "pathHash" | "lastOwnedAt">> {
|
|
60
|
+
return Object.values(state.zcommit.ownedPathRefs ?? {}).map((ref) => ({ path: ref.path, source: ref.source, pathHash: ref.pathHash, lastOwnedAt: ref.lastOwnedAt })).sort((a, b) => a.path.localeCompare(b.path));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function zcommitLedgerEntry(action: string, state: HarnessRuntimeState, plan: ReturnType<typeof buildZcommitPlan>, result?: ZcommitCommandResult | ZcommitAdoptResult): Record<string, unknown> {
|
|
64
|
+
return {
|
|
65
|
+
schema: "zob.zcommit-command.v1",
|
|
66
|
+
action,
|
|
67
|
+
status: result ? (result.ok ? "ok" : "blocked_or_failed") : undefined,
|
|
68
|
+
autocommit: state.zcommit.autocommit,
|
|
69
|
+
autopush: state.zcommit.autopush,
|
|
70
|
+
policyLoaded: plan.policyLoaded,
|
|
71
|
+
selectionMode: plan.selectionMode,
|
|
72
|
+
validationMode: plan.validationMode,
|
|
73
|
+
selectionPathspecHashes: plan.selectionPathspecs.map((pathspec) => sha256(pathspec)),
|
|
74
|
+
dirtyCount: plan.dirtyFiles.length,
|
|
75
|
+
touchedCount: plan.touchedFiles.length,
|
|
76
|
+
eligibleCount: plan.eligible.length,
|
|
77
|
+
excludedCount: plan.excluded.length,
|
|
78
|
+
forbiddenCount: plan.forbidden.length,
|
|
79
|
+
unexpectedStagedCount: plan.unexpectedStaged.length,
|
|
80
|
+
eligiblePathHashes: plan.eligible.map((file) => sha256(file.path)),
|
|
81
|
+
excludedPathHashes: plan.excluded.map((file) => sha256(file.path)),
|
|
82
|
+
ownedPathRefs: zcommitOwnedPathLedgerRefs(state),
|
|
83
|
+
noShip: plan.noShip,
|
|
84
|
+
commitEnabled: plan.commitEnabled,
|
|
85
|
+
pushEnabled: plan.pushEnabled,
|
|
86
|
+
lastCommitHash: state.zcommit.lastCommit?.hash,
|
|
87
|
+
lastCommitShortHash: state.zcommit.lastCommit?.shortHash,
|
|
88
|
+
validationOk: result && result.action !== "adopt" ? result.validation?.ok : undefined,
|
|
89
|
+
validationCommand: result && result.action !== "adopt" ? result.validation?.command : undefined,
|
|
90
|
+
adoptedPathHashes: result?.action === "adopt" ? result.adopted.map((path) => sha256(path)) : undefined,
|
|
91
|
+
adoptExcludedPathHashes: result?.action === "adopt" ? result.excluded.map((entry) => sha256(entry.path)) : undefined,
|
|
92
|
+
adoptExcludedReasons: result?.action === "adopt" ? result.excluded.map((entry) => entry.reason) : undefined,
|
|
93
|
+
errorHashes: result?.errors.map((error) => sha256(error)),
|
|
94
|
+
actualGitCommitRun: result?.actualGitCommitRun ?? false,
|
|
95
|
+
actualGitPushRun: result?.actualGitPushRun ?? false,
|
|
96
|
+
bodyStored: false,
|
|
97
|
+
generatedAt: new Date().toISOString(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function setZcommitToggle(state: HarnessRuntimeState, key: "autocommit" | "autopush", value: ZcommitToggleState): void {
|
|
102
|
+
state.zcommit[key] = value;
|
|
103
|
+
state.zcommit.updatedAt = new Date().toISOString();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function computeArgumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
107
|
+
const query = prefix.trim().toLowerCase();
|
|
108
|
+
const items: AutocompleteItem[] = [
|
|
109
|
+
{ value: "auto", label: "auto", description: "preview then choose low/medium/high/xhigh/max" },
|
|
110
|
+
{ value: "low", label: "low", description: "fast single-agent/deterministic effort" },
|
|
111
|
+
{ value: "medium", label: "medium", description: "balanced default effort" },
|
|
112
|
+
{ value: "high", label: "high", description: "multi-lane + stronger validation" },
|
|
113
|
+
{ value: "xhigh", label: "xhigh", description: "extra-high quality + adversarial checks" },
|
|
114
|
+
{ value: "max", label: "max", description: "approval-gated maximum effort" },
|
|
115
|
+
{ value: "--domain project-dna", label: "--domain project-dna", description: "score as ProjectDNA/reference-project work" },
|
|
116
|
+
{ value: "--domain factory", label: "--domain factory", description: "score as factory workflow work" },
|
|
117
|
+
{ value: "--domain orchestration", label: "--domain orchestration", description: "score as orchestration work" },
|
|
118
|
+
{ value: "help", label: "help", description: "show compute command template" },
|
|
119
|
+
];
|
|
120
|
+
const filtered = query
|
|
121
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
122
|
+
: items;
|
|
123
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseComputeCommandArgs(args: string): { requestedProfile: ComputeRequestedProfile; domain: string; targetPath: string; maxProfile?: string; riskHints: string[]; help: boolean } {
|
|
127
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
128
|
+
let requestedProfile: ComputeRequestedProfile = "auto";
|
|
129
|
+
let domain = "generic";
|
|
130
|
+
let targetPath = ".";
|
|
131
|
+
let maxProfile: string | undefined;
|
|
132
|
+
const riskHints: string[] = [];
|
|
133
|
+
let positionalTargetSeen = false;
|
|
134
|
+
let help = false;
|
|
135
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
136
|
+
const part = parts[index];
|
|
137
|
+
if (part === "help" || part === "--help" || part === "-h") {
|
|
138
|
+
help = true;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (part === "--domain" && parts[index + 1]) {
|
|
142
|
+
const next = parts[++index];
|
|
143
|
+
domain = COMPUTE_DOMAINS.includes(next as typeof COMPUTE_DOMAINS[number]) ? next : "generic";
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if ((part === "--max" || part === "--max-profile") && parts[index + 1]) {
|
|
147
|
+
maxProfile = parts[++index];
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if ((part === "--risk" || part === "--risk-hint") && parts[index + 1]) {
|
|
151
|
+
riskHints.push(parts[++index]);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (COMPUTE_PROFILES.includes(part as ComputeRequestedProfile)) {
|
|
155
|
+
requestedProfile = part as ComputeRequestedProfile;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (!positionalTargetSeen) {
|
|
159
|
+
targetPath = part;
|
|
160
|
+
positionalTargetSeen = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return { requestedProfile, domain, targetPath, maxProfile, riskHints, help };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function computeHelpTemplate(): string {
|
|
167
|
+
return [
|
|
168
|
+
"# ZOB compute profile",
|
|
169
|
+
"",
|
|
170
|
+
"Usage examples:",
|
|
171
|
+
"/compute auto .",
|
|
172
|
+
"/compute high . --domain generic",
|
|
173
|
+
"/compute xhigh . --risk durable --max-profile xhigh",
|
|
174
|
+
"/effort medium .",
|
|
175
|
+
"",
|
|
176
|
+
"Profiles: auto | low | medium | high | xhigh | max",
|
|
177
|
+
"Domains: generic | project-dna | factory | orchestration",
|
|
178
|
+
"",
|
|
179
|
+
"Notes:",
|
|
180
|
+
"- preview/resolve only; no child dispatch",
|
|
181
|
+
"- max remains approval-gated",
|
|
182
|
+
"- childDirectDispatch=false",
|
|
183
|
+
].join("\n");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function projectDnaArgumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
187
|
+
const query = prefix.trim().toLowerCase();
|
|
188
|
+
const items: AutocompleteItem[] = [
|
|
189
|
+
{ value: "readiness", label: "readiness", description: "audit ProjectDNA repo-local readiness" },
|
|
190
|
+
{ value: "plan .pi/factories/project-dna/example-project-dna-manifest-v2.json reports/project-dna-scans/project-dna-factory-smoke", label: "plan workflow", description: "metadata-only agentic workflow plan from manifest v2" },
|
|
191
|
+
{ value: "query reports/project-dna-scans/project-dna-factory-smoke factory schema validation", label: "query smoke", description: "bounded cited query against smoke scan artifacts" },
|
|
192
|
+
{ value: "query reports/project-dna-scans/pi-real-20260529-v1 register tool extension command runtime", label: "query pi-real", description: "bounded cited query against existing real Pi scan artifacts" },
|
|
193
|
+
{ value: "help", label: "help", description: "show ProjectDNA command template" },
|
|
194
|
+
];
|
|
195
|
+
const filtered = query
|
|
196
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
197
|
+
: items;
|
|
198
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function projectDnaHelpTemplate(): string {
|
|
202
|
+
return [
|
|
203
|
+
"# ZOB ProjectDNA",
|
|
204
|
+
"",
|
|
205
|
+
"Usage examples:",
|
|
206
|
+
"/project-dna readiness",
|
|
207
|
+
"/project-dna plan .pi/factories/project-dna/example-project-dna-manifest-v2.json reports/project-dna-scans/project-dna-factory-smoke",
|
|
208
|
+
"/project-dna query reports/project-dna-scans/project-dna-factory-smoke factory schema validation",
|
|
209
|
+
"/project-dna query reports/project-dna-scans/pi-real-20260529-v1 register tool extension command runtime",
|
|
210
|
+
"",
|
|
211
|
+
"Notes:",
|
|
212
|
+
"- plan builds metadata-only agentic workflow shape from manifest v2",
|
|
213
|
+
"- query reads repo-local ProjectDNA scan artifacts only",
|
|
214
|
+
"- returns bounded cited context packs",
|
|
215
|
+
"- raw query text is hashed in outputs and not persisted",
|
|
216
|
+
"- no source scan, no backend write, no child dispatch",
|
|
217
|
+
].join("\n");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function parseProjectDnaCommandArgs(args: string): { mode: "help" | "readiness" | "plan" | "query"; manifestPath?: string; scanDir?: string; query?: string } {
|
|
221
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
222
|
+
if (parts.length === 0 || parts[0] === "help" || parts[0] === "--help" || parts[0] === "-h") return { mode: "help" };
|
|
223
|
+
if (parts[0] === "readiness") return { mode: "readiness", scanDir: parts[1] };
|
|
224
|
+
if (parts[0] === "plan") {
|
|
225
|
+
const manifestPath = parts[1];
|
|
226
|
+
const scanDir = parts[2]?.startsWith("reports/project-dna-scans/") ? parts[2] : undefined;
|
|
227
|
+
return manifestPath ? { mode: "plan", manifestPath, scanDir } : { mode: "help" };
|
|
228
|
+
}
|
|
229
|
+
if (parts[0] === "query") {
|
|
230
|
+
const maybeScanDir = parts[1];
|
|
231
|
+
const hasScanDir = typeof maybeScanDir === "string" && maybeScanDir.startsWith("reports/project-dna-scans/");
|
|
232
|
+
const scanDir = hasScanDir ? maybeScanDir : undefined;
|
|
233
|
+
const queryText = parts.slice(hasScanDir ? 2 : 1).join(" ").trim();
|
|
234
|
+
return { mode: queryText ? "query" : "help", scanDir, query: queryText };
|
|
235
|
+
}
|
|
236
|
+
return { mode: "query", query: parts.join(" ") };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function autonomyArgumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
240
|
+
const query = prefix.trim().toLowerCase();
|
|
241
|
+
const items: AutocompleteItem[] = [
|
|
242
|
+
{ value: "status", label: "status", description: "show current autonomy policy/readiness" },
|
|
243
|
+
{ value: "daemon status", label: "daemon status", description: "show scoped plan-only daemon state; no execution" },
|
|
244
|
+
{ value: "daemon tick", label: "daemon tick", description: "record one scoped plan-only daemon tick" },
|
|
245
|
+
{ value: "daemon tick --queue-readonly", label: "daemon tick --queue-readonly", description: "explicit one-shot read-only queue bridge" },
|
|
246
|
+
{ value: "daemon start --max-ticks 3", label: "daemon start --max-ticks 3", description: "start bounded supervised plan-only session loop" },
|
|
247
|
+
{ value: "daemon stop", label: "daemon stop", description: "stop supervised daemon session loop" },
|
|
248
|
+
{ value: "daemon plan-tick", label: "daemon plan-tick", description: "preview next daemon action only; no execution" },
|
|
249
|
+
{ value: "adaptive", label: "adaptive", description: "score request then auto-launch, clarify, or block" },
|
|
250
|
+
{ value: "controlled", label: "controlled", description: "challenge-first until readiness is high" },
|
|
251
|
+
{ value: "open", label: "open", description: "launch directly when safety gates pass" },
|
|
252
|
+
{ value: "stop", label: "stop", description: "disable interactive autonomy" },
|
|
253
|
+
{ value: "score", label: "score <text>", description: "hash-only score a mission draft without launching" },
|
|
254
|
+
{ value: "help", label: "help", description: "insert autonomy command help" },
|
|
255
|
+
];
|
|
256
|
+
const filtered = query
|
|
257
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
258
|
+
: items;
|
|
259
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function autonomyHelpTemplate(): string {
|
|
263
|
+
return [
|
|
264
|
+
"# ZOB interactive autonomy",
|
|
265
|
+
"",
|
|
266
|
+
"Commands:",
|
|
267
|
+
"/autonomy adaptive # default: score launch vs clarify vs block",
|
|
268
|
+
"/autonomy controlled # challenge-first until enough info",
|
|
269
|
+
"/autonomy open # launch direct when safety gates pass",
|
|
270
|
+
"/autonomy status # show mode, policy, latest readiness",
|
|
271
|
+
"/autonomy daemon status # show scoped daemon metadata and bounded loop state",
|
|
272
|
+
"/autonomy daemon tick # record one scoped plan-only daemon tick",
|
|
273
|
+
"/autonomy daemon tick --queue-readonly # explicit one-shot safe read-only queue bridge",
|
|
274
|
+
"/autonomy daemon start --max-ticks 3 # bounded supervised session-local plan-only loop",
|
|
275
|
+
"/autonomy daemon stop # stop supervised daemon loop",
|
|
276
|
+
"/autonomy daemon plan-tick # compatibility alias for tick without queue bridge",
|
|
277
|
+
"/autonomy stop # disable interactive autonomy",
|
|
278
|
+
"",
|
|
279
|
+
"Semantics:",
|
|
280
|
+
"- spec understood + launch decision = no per-action approval for in-scope safe work",
|
|
281
|
+
"- safety gates stay on: no secrets, no destructive commands, no production apply/global claim",
|
|
282
|
+
"- persisted entries are hash/body-free (mission-readiness.v1)",
|
|
283
|
+
"- daemon commands are default-off, scoped to active goal, plan-only, and never auto-start",
|
|
284
|
+
"- daemon start is session-local, supervised, bounded by --max-ticks, and cleared on shutdown",
|
|
285
|
+
].join("\n");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function daemonInputFromState(state: HarnessRuntimeState) {
|
|
289
|
+
return {
|
|
290
|
+
policy: state.daemon.policy,
|
|
291
|
+
runtimeGoal: state.runtimeGoal,
|
|
292
|
+
goalTodos: state.goalTodos,
|
|
293
|
+
autonomy: {
|
|
294
|
+
mode: state.autonomy.mode,
|
|
295
|
+
enabled: state.autonomy.enabled,
|
|
296
|
+
lastReadiness: state.autonomy.lastReadiness,
|
|
297
|
+
lastLaunchAuthorization: state.autonomy.lastLaunchAuthorization,
|
|
298
|
+
},
|
|
299
|
+
loop: state.daemon.loop,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function daemonRuntimeLedgerEntry(daemonState: DaemonRuntimeState): Record<string, unknown> {
|
|
304
|
+
return {
|
|
305
|
+
schema: daemonState.schema,
|
|
306
|
+
status: daemonState.status,
|
|
307
|
+
reasonCodes: daemonState.reasonCodes,
|
|
308
|
+
enabled: daemonState.policy.enabled,
|
|
309
|
+
planOnly: true,
|
|
310
|
+
scopedToActiveGoal: true,
|
|
311
|
+
goalId: daemonState.goal?.goalId,
|
|
312
|
+
goalStatus: daemonState.goal?.status,
|
|
313
|
+
oracleStatus: daemonState.goal?.oracleStatus,
|
|
314
|
+
launchAuthorized: daemonState.launchAuthorized,
|
|
315
|
+
selectedTodoId: daemonState.selectedTodo?.id,
|
|
316
|
+
selectedTodoPath: daemonState.selectedTodo?.path,
|
|
317
|
+
selectedTodoStatus: daemonState.selectedTodo?.status,
|
|
318
|
+
todoCounts: daemonState.todoCounts,
|
|
319
|
+
loop: daemonState.loop,
|
|
320
|
+
autoStartDaemon: false,
|
|
321
|
+
continuousLoop: false,
|
|
322
|
+
cronEnabled: false,
|
|
323
|
+
childDispatchAllowed: false,
|
|
324
|
+
queueClaimed: false,
|
|
325
|
+
todoMutated: false,
|
|
326
|
+
productionApplyAllowed: false,
|
|
327
|
+
bodyStored: false,
|
|
328
|
+
promptBodiesStored: false,
|
|
329
|
+
outputBodiesStored: false,
|
|
330
|
+
generatedAt: new Date().toISOString(),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function daemonPlanLedgerEntry(plan: DaemonTickPlan, daemonState: DaemonRuntimeState): Record<string, unknown> {
|
|
335
|
+
return {
|
|
336
|
+
schema: plan.schema,
|
|
337
|
+
status: plan.status,
|
|
338
|
+
action: plan.action,
|
|
339
|
+
reasonCodes: plan.reasonCodes,
|
|
340
|
+
enabled: daemonState.policy.enabled,
|
|
341
|
+
planOnly: true,
|
|
342
|
+
goalId: plan.goalId,
|
|
343
|
+
selectedTodoId: plan.todo?.id,
|
|
344
|
+
selectedTodoPath: plan.todo?.path,
|
|
345
|
+
selectedTodoStatus: plan.todo?.status,
|
|
346
|
+
loop: daemonState.loop,
|
|
347
|
+
stop: { stop: plan.stop.stop, status: plan.stop.status, reasonCodes: plan.stop.reasonCodes },
|
|
348
|
+
writesPlanned: false,
|
|
349
|
+
todoMutationPlanned: false,
|
|
350
|
+
queueClaimPlanned: false,
|
|
351
|
+
childDispatchPlanned: false,
|
|
352
|
+
autoStartDaemon: false,
|
|
353
|
+
continuousLoop: false,
|
|
354
|
+
cronEnabled: false,
|
|
355
|
+
productionApplyAllowed: false,
|
|
356
|
+
bodyStored: false,
|
|
357
|
+
promptBodiesStored: false,
|
|
358
|
+
outputBodiesStored: false,
|
|
359
|
+
generatedAt: new Date().toISOString(),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function formatDaemonStatusForUi(daemonState: DaemonRuntimeState): string {
|
|
364
|
+
const todo = daemonState.selectedTodo ? ` · todo=${daemonState.selectedTodo.path}/${daemonState.selectedTodo.status}` : "";
|
|
365
|
+
const loop = daemonState.loop;
|
|
366
|
+
const loopText = loop ? ` · loop=${loop.status} ticks=${loop.tickCount}${loop.maxTicks ? `/${loop.maxTicks}` : ""}${loop.blocker ? ` blocker=${loop.blocker}` : ""}` : "";
|
|
367
|
+
return `daemon ${daemonState.policy.enabled ? "plan-only" : "off"}/${daemonState.status}${todo}${loopText} · reasons=${daemonState.reasonCodes.slice(0, 3).join(",") || "none"} · autoStart=false globalLoop=false execution=false`;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function formatDaemonPlanForUi(plan: DaemonTickPlan, queueTick?: QueueTickResult): string {
|
|
371
|
+
const todo = plan.todo ? ` · todo=${plan.todo.path}/${plan.todo.status}` : "";
|
|
372
|
+
const queue = queueTick ? ` · queue=${queueTick.status}/claimed=${queueTick.claimed}` : "";
|
|
373
|
+
return `daemon tick action=${plan.action} status=${plan.status}${todo}${queue} · stop=${plan.stop.stop} · writes=false todo_mutation=false child_dispatch=false`;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const DAEMON_SESSION_TICK_INTERVAL_MS = 1_000;
|
|
377
|
+
|
|
378
|
+
type HarnessCommandContext = Parameters<Parameters<ExtensionAPI["registerCommand"]>[1]["handler"]>[1];
|
|
379
|
+
|
|
380
|
+
function clearDaemonLoopTimer(state: HarnessRuntimeState): void {
|
|
381
|
+
if (state.daemon.loopTimer) clearTimeout(state.daemon.loopTimer);
|
|
382
|
+
state.daemon.loopTimer = undefined;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function stopDaemonLoop(state: HarnessRuntimeState, blocker?: string): void {
|
|
386
|
+
clearDaemonLoopTimer(state);
|
|
387
|
+
state.daemon.loop = {
|
|
388
|
+
...state.daemon.loop,
|
|
389
|
+
status: "stopped",
|
|
390
|
+
stoppedAt: new Date().toISOString(),
|
|
391
|
+
blocker: blocker ?? state.daemon.loop.blocker,
|
|
392
|
+
autoStartDaemon: false,
|
|
393
|
+
continuousLoop: false,
|
|
394
|
+
cronEnabled: false,
|
|
395
|
+
};
|
|
396
|
+
state.daemon.updatedAt = state.daemon.loop.stoppedAt;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function parseDaemonMaxTicks(parts: string[]): number | undefined {
|
|
400
|
+
const index = parts.findIndex((part) => part === "--max-ticks" || part === "--max_ticks");
|
|
401
|
+
if (index < 0 || !parts[index + 1]) return undefined;
|
|
402
|
+
const parsed = Number.parseInt(parts[index + 1], 10);
|
|
403
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.min(Math.trunc(parsed), 100) : undefined;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function daemonQueueTickLedgerEntry(result: QueueTickResult): Record<string, unknown> {
|
|
407
|
+
return {
|
|
408
|
+
schema: result.schema,
|
|
409
|
+
claimed: result.claimed,
|
|
410
|
+
jobId: result.jobId,
|
|
411
|
+
jobType: result.jobType,
|
|
412
|
+
status: result.status,
|
|
413
|
+
stopCondition: result.stopCondition,
|
|
414
|
+
errors: result.errors,
|
|
415
|
+
staleRecovered: result.staleRecovered,
|
|
416
|
+
maxWorkers: result.maxWorkers,
|
|
417
|
+
budgetEnforced: result.budgetEnforced,
|
|
418
|
+
promptBodiesStored: false,
|
|
419
|
+
outputBodiesStored: false,
|
|
420
|
+
bodyStored: false,
|
|
421
|
+
explicitManualReadOnlyBridge: true,
|
|
422
|
+
productionApplyAllowed: false,
|
|
423
|
+
childDispatchAllowed: false,
|
|
424
|
+
generatedAt: new Date().toISOString(),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function recordDaemonTick(pi: ExtensionAPI, state: HarnessRuntimeState, ctx: HarnessCommandContext, options: { queueReadonly?: boolean } = {}): { daemonState: DaemonRuntimeState; plan: DaemonTickPlan; queueTick?: QueueTickResult } {
|
|
429
|
+
const now = new Date().toISOString();
|
|
430
|
+
state.daemon.loop = {
|
|
431
|
+
...state.daemon.loop,
|
|
432
|
+
tickCount: state.daemon.loop.tickCount + 1,
|
|
433
|
+
lastTickAt: now,
|
|
434
|
+
blocker: undefined,
|
|
435
|
+
autoStartDaemon: false,
|
|
436
|
+
continuousLoop: false,
|
|
437
|
+
cronEnabled: false,
|
|
438
|
+
};
|
|
439
|
+
const daemonInput = daemonInputFromState(state);
|
|
440
|
+
const daemonState = buildDaemonRuntimeState({ ...daemonInput, policy: { ...state.daemon.policy, enabled: true } });
|
|
441
|
+
const plan = buildDaemonTickPlan(daemonState);
|
|
442
|
+
let queueTick: QueueTickResult | undefined;
|
|
443
|
+
if (options.queueReadonly === true) {
|
|
444
|
+
queueTick = runQueueDaemonTick(ctx.cwd);
|
|
445
|
+
state.daemon.lastQueueTick = queueTick;
|
|
446
|
+
pi.appendEntry("zob-daemon-queue-tick", daemonQueueTickLedgerEntry(queueTick));
|
|
447
|
+
}
|
|
448
|
+
state.daemon.lastStatus = daemonState;
|
|
449
|
+
state.daemon.lastPlan = plan;
|
|
450
|
+
state.daemon.updatedAt = now;
|
|
451
|
+
pi.appendEntry("zob-daemon-runtime", daemonRuntimeLedgerEntry(daemonState));
|
|
452
|
+
pi.appendEntry("zob-daemon-plan", daemonPlanLedgerEntry(plan, daemonState));
|
|
453
|
+
return { daemonState, plan, queueTick };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function scheduleDaemonLoop(pi: ExtensionAPI, state: HarnessRuntimeState, ctx: HarnessCommandContext): void {
|
|
457
|
+
if (state.daemon.loop.status !== "running") return;
|
|
458
|
+
if (state.daemon.loop.maxTicks !== undefined && state.daemon.loop.tickCount >= state.daemon.loop.maxTicks) {
|
|
459
|
+
stopDaemonLoop(state, "max_ticks_reached");
|
|
460
|
+
renderHarnessWidget(pi, state, ctx);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
clearDaemonLoopTimer(state);
|
|
464
|
+
const timer = setTimeout(() => {
|
|
465
|
+
if (state.daemon.loop.status !== "running") return;
|
|
466
|
+
const { plan } = recordDaemonTick(pi, state, ctx);
|
|
467
|
+
if (plan.stop.stop) stopDaemonLoop(state, `stop_condition_${plan.status}`);
|
|
468
|
+
if (state.daemon.loop.maxTicks !== undefined && state.daemon.loop.tickCount >= state.daemon.loop.maxTicks) stopDaemonLoop(state, "max_ticks_reached");
|
|
469
|
+
renderHarnessWidget(pi, state, ctx);
|
|
470
|
+
if (state.daemon.loop.status === "running") scheduleDaemonLoop(pi, state, ctx);
|
|
471
|
+
}, DAEMON_SESSION_TICK_INTERVAL_MS);
|
|
472
|
+
timer.unref?.();
|
|
473
|
+
state.daemon.loopTimer = timer;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function abortForegroundWork(ctx: HarnessCommandContext): boolean {
|
|
477
|
+
const idle = typeof ctx.isIdle === "function" ? ctx.isIdle() : true;
|
|
478
|
+
if (idle) return false;
|
|
479
|
+
if (typeof ctx.abort !== "function") return false;
|
|
480
|
+
ctx.abort();
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function abortBackgroundDelegations(state: HarnessRuntimeState): { abortedCount: number; runIds: string[] } {
|
|
485
|
+
const runIds: string[] = [];
|
|
486
|
+
for (const [runId, run] of state.backgroundDelegations.entries()) {
|
|
487
|
+
if (run.result || run.error || run.abortController.signal.aborted) continue;
|
|
488
|
+
run.abortController.abort();
|
|
489
|
+
runIds.push(runId);
|
|
490
|
+
finishDelegationRun(state.delegations, runId, {
|
|
491
|
+
status: "aborted",
|
|
492
|
+
endedAtMs: Date.now(),
|
|
493
|
+
gatePassed: false,
|
|
494
|
+
failureKind: "aborted",
|
|
495
|
+
stopReason: "aborted",
|
|
496
|
+
stopCondition: "slash_stop",
|
|
497
|
+
errorMessage: "aborted by /stop",
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
return { abortedCount: runIds.length, runIds };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function stopCommandLedgerEntry(input: {
|
|
504
|
+
foregroundAbortRequested: boolean;
|
|
505
|
+
idleBeforeStop: boolean;
|
|
506
|
+
pendingMessagesBeforeStop: boolean;
|
|
507
|
+
backgroundAbortedCount: number;
|
|
508
|
+
backgroundRunIds: string[];
|
|
509
|
+
daemonWasRunning: boolean;
|
|
510
|
+
runtimeGoalPaused: boolean;
|
|
511
|
+
runtimeGoalId?: string;
|
|
512
|
+
}): Record<string, unknown> {
|
|
513
|
+
return {
|
|
514
|
+
schema: "zob.stop-command.v1",
|
|
515
|
+
foregroundAbortRequested: input.foregroundAbortRequested,
|
|
516
|
+
idleBeforeStop: input.idleBeforeStop,
|
|
517
|
+
pendingMessagesBeforeStop: input.pendingMessagesBeforeStop,
|
|
518
|
+
backgroundAbortedCount: input.backgroundAbortedCount,
|
|
519
|
+
backgroundRunIds: input.backgroundRunIds,
|
|
520
|
+
daemonWasRunning: input.daemonWasRunning,
|
|
521
|
+
runtimeGoalPaused: input.runtimeGoalPaused,
|
|
522
|
+
runtimeGoalId: input.runtimeGoalId,
|
|
523
|
+
bodyStored: false,
|
|
524
|
+
promptBodiesStored: false,
|
|
525
|
+
outputBodiesStored: false,
|
|
526
|
+
generatedAt: new Date().toISOString(),
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function delegationArgumentCompletions(state: HarnessRuntimeState, prefix: string): AutocompleteItem[] | null {
|
|
531
|
+
const query = prefix.trim().toLowerCase();
|
|
532
|
+
const items: AutocompleteItem[] = [];
|
|
533
|
+
const seen = new Set<string>();
|
|
534
|
+
const add = (value: string, label: string, description?: string) => {
|
|
535
|
+
if (!value || seen.has(value)) return;
|
|
536
|
+
seen.add(value);
|
|
537
|
+
items.push({ value, label, ...(description ? { description } : {}) });
|
|
538
|
+
};
|
|
539
|
+
const runs = [...state.delegations.runs].sort((a, b) => b.startedAtMs - a.startedAtMs);
|
|
540
|
+
for (const run of runs) add(run.agent, run.agent, "agent");
|
|
541
|
+
for (const run of runs.slice(0, 40)) add(run.id.slice(0, 8), run.id.slice(0, 8), `${run.agent} · ${run.status}`);
|
|
542
|
+
const filtered = query
|
|
543
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
544
|
+
: items;
|
|
545
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export function registerHarnessCommands(pi: ExtensionAPI, state: HarnessRuntimeState): void {
|
|
549
|
+
pi.registerCommand("zmode", {
|
|
550
|
+
description: "Switch ZOB harness mode: explore | plan | implement | oracle | factory | orchestrator. Orchestrator routes to adaptive-chief-vision plan_only defaults.",
|
|
551
|
+
handler: async (args, ctx) => {
|
|
552
|
+
const requestedText = args.trim();
|
|
553
|
+
const adaptiveEntrypoint = resolveAdaptiveZmodeEntrypoint(requestedText);
|
|
554
|
+
if (adaptiveEntrypoint) {
|
|
555
|
+
applyMode(pi, state, ctx, adaptiveEntrypoint.appliedHarnessMode);
|
|
556
|
+
state.activeRuleResolution = resolveRuleProfile({ repoRoot: ctx.cwd, mode: state.activeMode });
|
|
557
|
+
pi.appendEntry("zob-adaptive-zmode-entrypoint", adaptiveEntrypoint);
|
|
558
|
+
ctx.ui.setEditorText(renderAdaptiveZmodeTemplate(adaptiveEntrypoint));
|
|
559
|
+
renderHarnessWidget(pi, state, ctx);
|
|
560
|
+
ctx.ui.notify(`ZOB ${adaptiveEntrypoint.requestedMode} routed to ${adaptiveEntrypoint.profile} (${adaptiveEntrypoint.executionDefault}); root remains non-coding and parent-owned.`, "info");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const requested = requestedText as ModeName;
|
|
564
|
+
const modes = Object.keys(MODE_PROMPTS) as ModeName[];
|
|
565
|
+
if (!requested) {
|
|
566
|
+
const choice = await ctx.ui.select("ZOB mode", modes);
|
|
567
|
+
if (choice) {
|
|
568
|
+
applyMode(pi, state, ctx, choice as ModeName);
|
|
569
|
+
state.activeRuleResolution = resolveRuleProfile({ repoRoot: ctx.cwd, mode: state.activeMode });
|
|
570
|
+
}
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (!modes.includes(requested)) {
|
|
574
|
+
ctx.ui.notify(`Unknown mode '${requested}'. Use: ${modes.join(", ")}`, "warning");
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
applyMode(pi, state, ctx, requested);
|
|
578
|
+
state.activeRuleResolution = resolveRuleProfile({ repoRoot: ctx.cwd, mode: state.activeMode });
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
pi.registerCommand("stop", {
|
|
583
|
+
description: "Stop current foreground work, background delegate_task runs, daemon loop, and runtime-goal auto-continuation without shutting down Pi.",
|
|
584
|
+
handler: async (_args, ctx) => {
|
|
585
|
+
const idleBeforeStop = typeof ctx.isIdle === "function" ? ctx.isIdle() : true;
|
|
586
|
+
const pendingMessagesBeforeStop = typeof ctx.hasPendingMessages === "function" ? ctx.hasPendingMessages() : false;
|
|
587
|
+
const daemonWasRunning = state.daemon.loop.status === "running";
|
|
588
|
+
const runtimeGoalId = state.runtimeGoal?.goalId;
|
|
589
|
+
const foregroundAbortRequested = abortForegroundWork(ctx);
|
|
590
|
+
const background = abortBackgroundDelegations(state);
|
|
591
|
+
stopDaemonLoop(state, "slash_stop");
|
|
592
|
+
const pausedGoal = pauseRuntimeGoalForStop(pi, state, "stopped by /stop; use /goal resume to continue");
|
|
593
|
+
const daemonState = buildDaemonRuntimeState(daemonInputFromState(state));
|
|
594
|
+
state.daemon.lastStatus = daemonState;
|
|
595
|
+
pi.appendEntry("zob-daemon-runtime", daemonRuntimeLedgerEntry(daemonState));
|
|
596
|
+
pi.appendEntry("zob-stop", stopCommandLedgerEntry({
|
|
597
|
+
foregroundAbortRequested,
|
|
598
|
+
idleBeforeStop,
|
|
599
|
+
pendingMessagesBeforeStop,
|
|
600
|
+
backgroundAbortedCount: background.abortedCount,
|
|
601
|
+
backgroundRunIds: background.runIds,
|
|
602
|
+
daemonWasRunning,
|
|
603
|
+
runtimeGoalPaused: Boolean(pausedGoal && pausedGoal.goalId === runtimeGoalId && pausedGoal.status === "paused"),
|
|
604
|
+
runtimeGoalId,
|
|
605
|
+
}));
|
|
606
|
+
renderHarnessWidget(pi, state, ctx);
|
|
607
|
+
ctx.ui.notify(`ZOB stop: foreground=${foregroundAbortRequested ? "aborted" : "idle"} background_aborted=${background.abortedCount} daemon=${daemonWasRunning ? "stopped" : "already_stopped"} goal=${pausedGoal?.status ?? "none"}`, "warning");
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
pi.registerShortcut("ctrl+alt+d", {
|
|
612
|
+
description: "Open ZOB delegated-agent viewer",
|
|
613
|
+
handler: async (ctx) => {
|
|
614
|
+
await showDelegationOverlay(ctx, state);
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
const openDelegatesCommand = async (args: string, ctx: Parameters<Parameters<typeof pi.registerCommand>[1]["handler"]>[1]): Promise<void> => {
|
|
619
|
+
await showDelegationOverlay(ctx, state, args.trim().split(/\s+/).filter(Boolean)[0]);
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
pi.registerCommand("delegates", {
|
|
623
|
+
description: "Open ZOB delegated-agent viewer. Optional: /delegates <id|agent>",
|
|
624
|
+
getArgumentCompletions: (prefix) => delegationArgumentCompletions(state, prefix),
|
|
625
|
+
handler: openDelegatesCommand,
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
pi.registerCommand("delegate", {
|
|
629
|
+
description: "Alias for /delegates. Optional: /delegate <id|agent>",
|
|
630
|
+
getArgumentCompletions: (prefix) => delegationArgumentCompletions(state, prefix),
|
|
631
|
+
handler: openDelegatesCommand,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
const rememberZpeerEvent = (event: { kind: NonNullable<typeof state.zobLive.lastEvent>["kind"]; roomId?: string; fromAlias?: string; toAlias?: string; status: string; reason?: string; msgId?: string; taskHash?: string; outputHash?: string }): void => {
|
|
635
|
+
state.zobLive.lastEvent = { ...event, at: new Date().toISOString(), localOnly: true, networkEnabled: false, bodyStored: false };
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
const emitZpeerEvent = (event: Parameters<typeof rememberZpeerEvent>[0]): void => {
|
|
639
|
+
rememberZpeerEvent(event);
|
|
640
|
+
void pi.sendMessage({
|
|
641
|
+
customType: "zob-zpeer-event",
|
|
642
|
+
content: `ZPeer ${event.kind} ${event.fromAlias ? `@${event.fromAlias}` : "?"} → ${event.toAlias ? `@${event.toAlias}` : "?"} ${event.status}`,
|
|
643
|
+
display: true,
|
|
644
|
+
details: { ...state.zobLive.lastEvent },
|
|
645
|
+
}, { triggerTurn: false });
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
pi.registerCommand("zpeer", {
|
|
649
|
+
description: "Room-scoped local peer sessions: /zpeer, /zpeer name <alias>, /zpeer room <roomId>, /zpeer @alias <prompt>",
|
|
650
|
+
handler: async (args, ctx) => {
|
|
651
|
+
if (!state.zobLive.peerCard) {
|
|
652
|
+
ctx.ui.notify("/zpeer unavailable: current session has not registered a local peer endpoint yet", "warning");
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const self = refreshZpeerSelf(ctx.cwd, state.zobLive.peerCard);
|
|
656
|
+
state.zobLive.peerCard = self;
|
|
657
|
+
const trimmed = args.trim();
|
|
658
|
+
if (!trimmed) {
|
|
659
|
+
const summary = buildZpeerRoomSummary(ctx.cwd, self);
|
|
660
|
+
pi.appendEntry("zob-zpeer", {
|
|
661
|
+
schema: "zob.zpeer-command.v1",
|
|
662
|
+
action: "status",
|
|
663
|
+
roomIdHash: sha256(summary.roomId),
|
|
664
|
+
aliasHash: sha256(summary.selfAlias ?? ""),
|
|
665
|
+
peerCount: summary.peerCount,
|
|
666
|
+
online: summary.online,
|
|
667
|
+
stale: summary.stale,
|
|
668
|
+
offline: summary.offline,
|
|
669
|
+
duplicateAliasCount: summary.duplicateAliases.length,
|
|
670
|
+
membershipCount: summary.membershipCount ?? zpeerMembershipsForPeer(self).length,
|
|
671
|
+
localOnly: true,
|
|
672
|
+
networkEnabled: false,
|
|
673
|
+
bodyStored: false,
|
|
674
|
+
promptBodiesStored: false,
|
|
675
|
+
outputBodiesStored: false,
|
|
676
|
+
generatedAt: new Date().toISOString(),
|
|
677
|
+
});
|
|
678
|
+
emitZpeerEvent({ kind: "status", roomId: summary.roomId, fromAlias: summary.selfAlias, status: `online=${summary.online}/${summary.peerCount}`, reason: `stale=${summary.stale} offline=${summary.offline}` });
|
|
679
|
+
renderHarnessWidget(pi, state, ctx);
|
|
680
|
+
const availableAliases = summary.aliases.filter((alias) => alias !== summary.selfAlias).map((alias) => `@${alias}`).join(", ") || "none";
|
|
681
|
+
const unavailable = summary.stale + summary.offline;
|
|
682
|
+
ctx.ui.notify(`zpeer room=${summary.roomId} memberships=${summary.membershipCount ?? zpeerMembershipsForPeer(self).length} self=@${summary.selfAlias ?? "?"} onlinePeers=${Math.max(0, summary.online - 1)} unavailable=${unavailable} peers=${availableAliases} · usage: /zpeer @alias <prompt> | /zpeer in <room> @alias <prompt> · safety: local-only/hash-only/bodyStored=false`, "info");
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const parts = trimmed.split(/\s+/);
|
|
686
|
+
const verb = parts[0]?.toLowerCase();
|
|
687
|
+
if (verb === "name") {
|
|
688
|
+
const result = changeZpeerAlias(ctx.cwd, self, parts[1] ?? "");
|
|
689
|
+
if (!result.ok) {
|
|
690
|
+
ctx.ui.notify(`/zpeer name blocked: ${result.reason}`, "warning");
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
state.zobLive.peerCard = result.peer;
|
|
694
|
+
writeZpeerLocalProfileFromPeer(ctx.cwd, result.peer);
|
|
695
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "name", aliasHash: sha256(result.peer.zpeerAlias ?? ""), roomIdHash: sha256(result.peer.zpeerRoomId ?? "default"), localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
696
|
+
renderHarnessWidget(pi, state, ctx);
|
|
697
|
+
ctx.ui.notify(`zpeer alias set to @${result.peer.zpeerAlias}`, "info");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (verb === "room") {
|
|
701
|
+
const result = changeZpeerRoom(ctx.cwd, self, parts[1] ?? "");
|
|
702
|
+
if (!result.ok) {
|
|
703
|
+
ctx.ui.notify(`/zpeer room blocked: ${result.reason}`, "warning");
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
state.zobLive.peerCard = result.peer;
|
|
707
|
+
writeZpeerLocalProfileFromPeer(ctx.cwd, result.peer);
|
|
708
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "room", aliasHash: sha256(result.peer.zpeerAlias ?? ""), roomIdHash: sha256(result.peer.zpeerRoomId ?? "default"), membershipCount: zpeerMembershipsForPeer(result.peer).length, localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
709
|
+
renderHarnessWidget(pi, state, ctx);
|
|
710
|
+
ctx.ui.notify(`zpeer room set to ${result.peer.zpeerRoomId} as @${result.peer.zpeerAlias}`, "info");
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (verb === "rooms") {
|
|
714
|
+
const memberships = zpeerMembershipsForPeer(self);
|
|
715
|
+
const summaries = memberships.map((membership) => buildZpeerRoomSummary(ctx.cwd, self, membership.roomId));
|
|
716
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "rooms", roomIdHash: sha256(self.zpeerRoomId ?? "default"), membershipCount: memberships.length, roomHashes: memberships.map((membership) => sha256(membership.roomId)), localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
717
|
+
renderHarnessWidget(pi, state, ctx);
|
|
718
|
+
ctx.ui.notify(`zpeer active=${self.zpeerRoomId ?? "default"} rooms=${summaries.map((summary) => `${summary.roomId}(${summary.online}/${summary.peerCount})`).join(", ") || "none"}`, "info");
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
if (verb === "join") {
|
|
722
|
+
const asIndex = parts.indexOf("as");
|
|
723
|
+
const alias = asIndex >= 0 ? parts[asIndex + 1] : undefined;
|
|
724
|
+
const role = parts.includes("--bridge") ? "bridge" : parts.includes("--observer") ? "observer" : "member";
|
|
725
|
+
const result = joinZpeerRoom(ctx.cwd, self, parts[1] ?? "", alias, role);
|
|
726
|
+
if (!result.ok) {
|
|
727
|
+
ctx.ui.notify(`/zpeer join blocked: ${result.reason}`, "warning");
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
state.zobLive.peerCard = result.peer;
|
|
731
|
+
writeZpeerLocalProfileFromPeer(ctx.cwd, result.peer);
|
|
732
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "join", aliasHash: sha256(alias ?? result.peer.zpeerAlias ?? ""), roomIdHash: sha256(parts[1] ?? "default"), membershipCount: zpeerMembershipsForPeer(result.peer).length, localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
733
|
+
renderHarnessWidget(pi, state, ctx);
|
|
734
|
+
ctx.ui.notify(`zpeer joined ${parts[1]} (${role}); active=${result.peer.zpeerRoomId}`, "info");
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
if (verb === "use") {
|
|
738
|
+
const result = useZpeerRoom(ctx.cwd, self, parts[1] ?? "");
|
|
739
|
+
if (!result.ok) {
|
|
740
|
+
ctx.ui.notify(`/zpeer use blocked: ${result.reason}`, "warning");
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
state.zobLive.peerCard = result.peer;
|
|
744
|
+
writeZpeerLocalProfileFromPeer(ctx.cwd, result.peer);
|
|
745
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "use", aliasHash: sha256(result.peer.zpeerAlias ?? ""), roomIdHash: sha256(result.peer.zpeerRoomId ?? "default"), membershipCount: zpeerMembershipsForPeer(result.peer).length, localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
746
|
+
renderHarnessWidget(pi, state, ctx);
|
|
747
|
+
ctx.ui.notify(`zpeer active room set to ${result.peer.zpeerRoomId} as @${result.peer.zpeerAlias}`, "info");
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (verb === "leave") {
|
|
751
|
+
const result = leaveZpeerRoom(ctx.cwd, self, parts[1] ?? "");
|
|
752
|
+
if (!result.ok) {
|
|
753
|
+
ctx.ui.notify(`/zpeer leave blocked: ${result.reason}`, "warning");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
state.zobLive.peerCard = result.peer;
|
|
757
|
+
writeZpeerLocalProfileFromPeer(ctx.cwd, result.peer);
|
|
758
|
+
pi.appendEntry("zob-zpeer", { schema: "zob.zpeer-command.v1", action: "leave", roomIdHash: sha256(parts[1] ?? "default"), membershipCount: zpeerMembershipsForPeer(result.peer).length, localOnly: true, networkEnabled: false, bodyStored: false, promptBodiesStored: false, outputBodiesStored: false, generatedAt: new Date().toISOString() });
|
|
759
|
+
renderHarnessWidget(pi, state, ctx);
|
|
760
|
+
ctx.ui.notify(`zpeer left ${parts[1]}; active=${result.peer.zpeerRoomId}`, "info");
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const sendModeFromParts = (inputParts: string[]): { mode: ZpeerSendMode; aliasToken?: string; bodyStartIndex: number } => {
|
|
764
|
+
const first = inputParts[0]?.toLowerCase();
|
|
765
|
+
if (first === "async" || first === "await" || first === "long") return { mode: first, aliasToken: inputParts[1], bodyStartIndex: 2 };
|
|
766
|
+
return { mode: inputParts.includes("--async") ? "async" : inputParts.includes("--long") ? "long" : "await", aliasToken: inputParts[0], bodyStartIndex: 1 };
|
|
767
|
+
};
|
|
768
|
+
const explicitRoomId = verb === "in" ? parts[1] : undefined;
|
|
769
|
+
const sendParts = explicitRoomId ? parts.slice(2) : parts;
|
|
770
|
+
const sendMode = sendModeFromParts(sendParts);
|
|
771
|
+
if (sendMode.aliasToken?.startsWith("@")) {
|
|
772
|
+
const targetAlias = sendMode.aliasToken.slice(1);
|
|
773
|
+
const transientPrompt = sendParts.slice(sendMode.bodyStartIndex).filter((part) => part !== "--async" && part !== "--long").join(" ").trim();
|
|
774
|
+
const replyTimeoutMs = sendMode.mode === "long" ? 30 * 60 * 1000 : 10 * 60 * 1000;
|
|
775
|
+
const eventRoomId = explicitRoomId ?? state.zobLive.peerCard.zpeerRoomId ?? "default";
|
|
776
|
+
const eventFromAlias = peerAliasInRoom(state.zobLive.peerCard, eventRoomId) ?? state.zobLive.peerCard.zpeerAlias;
|
|
777
|
+
if (sendMode.mode !== "async") emitZpeerEvent({ kind: "attempt", roomId: eventRoomId, fromAlias: eventFromAlias, toAlias: targetAlias, status: "attempt", taskHash: transientPrompt.trim() ? sha256(transientPrompt) : undefined });
|
|
778
|
+
let feedbackEmittedTerminal = false;
|
|
779
|
+
const result = await sendZpeerPrompt(ctx.cwd, state.zobLive.peerCard, targetAlias, transientPrompt, (msgId) => state.zobLive.pendingReplies.wait(msgId, replyTimeoutMs), {
|
|
780
|
+
mode: sendMode.mode,
|
|
781
|
+
roomId: explicitRoomId,
|
|
782
|
+
onFeedback: (feedback) => {
|
|
783
|
+
feedbackEmittedTerminal = feedback.result.status === "waiting" || feedback.result.status === "reply" || feedback.result.status === "completed" || feedback.result.status === "blocked" || feedback.result.status === "error" || feedback.result.status === "timeout" || feedback.result.status === "expired";
|
|
784
|
+
const feedbackRoomId = feedback.result.roomId ?? eventRoomId;
|
|
785
|
+
emitZpeerEvent({ kind: feedback.kind, roomId: feedbackRoomId, fromAlias: state.zobLive.peerCard ? peerAliasInRoom(state.zobLive.peerCard, feedbackRoomId) ?? eventFromAlias : eventFromAlias, toAlias: feedback.result.targetAlias ?? targetAlias, status: feedback.result.status, reason: feedback.result.reason, msgId: feedback.result.msgId, taskHash: feedback.result.taskHash, outputHash: feedback.result.outputHash });
|
|
786
|
+
},
|
|
787
|
+
});
|
|
788
|
+
const terminalKind = result.status === "reply" || result.status === "completed" ? "reply" : result.status === "blocked" ? "blocked" : result.status === "timeout" ? "timeout" : result.status === "expired" ? "expired" : result.status === "error" ? "error" : result.status === "waiting" ? "waiting" : "delivered";
|
|
789
|
+
if (!feedbackEmittedTerminal) {
|
|
790
|
+
const resultRoomId = result.roomId ?? eventRoomId;
|
|
791
|
+
emitZpeerEvent({ kind: terminalKind, roomId: resultRoomId, fromAlias: peerAliasInRoom(state.zobLive.peerCard, resultRoomId) ?? eventFromAlias, toAlias: result.targetAlias ?? targetAlias, status: result.status, reason: result.reason, msgId: result.msgId, taskHash: result.taskHash, outputHash: result.outputHash });
|
|
792
|
+
}
|
|
793
|
+
pi.appendEntry("zob-zpeer", {
|
|
794
|
+
schema: "zob.zpeer-command.v1",
|
|
795
|
+
action: sendMode.mode === "async" ? "send_async" : sendMode.mode === "long" ? "send_long_await" : "send_await",
|
|
796
|
+
status: result.status,
|
|
797
|
+
reasonHash: result.reason ? sha256(result.reason) : undefined,
|
|
798
|
+
msgId: result.msgId,
|
|
799
|
+
targetAliasHash: result.targetAlias ? sha256(result.targetAlias) : undefined,
|
|
800
|
+
roomIdHash: sha256(result.roomId ?? eventRoomId),
|
|
801
|
+
taskHash: result.taskHash,
|
|
802
|
+
outputHash: result.outputHash,
|
|
803
|
+
localOnly: true,
|
|
804
|
+
networkEnabled: false,
|
|
805
|
+
bodyStored: false,
|
|
806
|
+
promptBodiesStored: false,
|
|
807
|
+
outputBodiesStored: false,
|
|
808
|
+
generatedAt: new Date().toISOString(),
|
|
809
|
+
});
|
|
810
|
+
renderHarnessWidget(pi, state, ctx);
|
|
811
|
+
if ((result.status === "reply" || result.status === "completed") && result.transientResponse) {
|
|
812
|
+
void pi.sendMessage({
|
|
813
|
+
customType: "zob-zpeer-response",
|
|
814
|
+
content: result.transientResponse,
|
|
815
|
+
display: true,
|
|
816
|
+
details: { msgId: result.msgId, targetAlias, outputHash: result.outputHash, bodyStored: false },
|
|
817
|
+
}, { triggerTurn: false });
|
|
818
|
+
ctx.ui.notify(`zpeer ${result.roomId ?? eventRoomId} @${targetAlias} reply · response displayed transiently · outputHash=${result.outputHash ?? "present"}`, "info");
|
|
819
|
+
} else {
|
|
820
|
+
const ok = result.status === "reply" || result.status === "completed" || result.status === "waiting" || result.status === "delivered";
|
|
821
|
+
ctx.ui.notify(ok ? `zpeer ${result.roomId ?? eventRoomId} @${targetAlias} ${result.status}${result.outputHash ? ` outputHash=${result.outputHash}` : ""}` : `zpeer ${result.roomId ?? eventRoomId} @${targetAlias} ${result.status}: ${result.reason ?? "see metadata"}`, ok ? "info" : "warning");
|
|
822
|
+
}
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
ctx.ui.notify("Usage: /zpeer | /zpeer rooms | /zpeer join <roomId> [as <alias>] | /zpeer use <roomId> | /zpeer leave <roomId> | /zpeer @alias <prompt> | /zpeer in <roomId> @alias <prompt>", "warning");
|
|
826
|
+
},
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
pi.registerCommand("zstatus", {
|
|
830
|
+
description: "Refresh the ZOB harness widget from latest reports and sentinels. Use 'delegations' to open child-agent run details.",
|
|
831
|
+
handler: async (args, ctx) => {
|
|
832
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
833
|
+
const requested = (parts[0] ?? "").toLowerCase();
|
|
834
|
+
if (["delegations", "delegation", "delegate", "agents"].includes(requested)) {
|
|
835
|
+
await showDelegationOverlay(ctx, state, parts[1]);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
if (["todos", "todo", "goal-todos", "goal_todos"].includes(requested)) {
|
|
839
|
+
await showGoalTodoOverlay(ctx, state, parts[1]);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
renderHarnessWidget(pi, state, ctx);
|
|
843
|
+
ctx.ui.notify("ZOB status refreshed from reports/", "info");
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
pi.registerCommand("zcompact", {
|
|
848
|
+
description: "Configure/session-run proactive ZOB compaction: /zcompact observe|on|off|status|threshold 60|target 25|fraction 25|trigger",
|
|
849
|
+
getArgumentCompletions: (prefix) => {
|
|
850
|
+
const query = prefix.trim().toLowerCase();
|
|
851
|
+
const items = [
|
|
852
|
+
{ value: "status", label: "status", description: "show context usage and zcompact settings" },
|
|
853
|
+
{ value: "observe", label: "observe", description: "report threshold hits without compacting" },
|
|
854
|
+
{ value: "on", label: "on", description: "enable auto-compaction at threshold" },
|
|
855
|
+
{ value: "off", label: "off", description: "disable proactive compaction" },
|
|
856
|
+
{ value: "threshold 60", label: "threshold 60", description: "trigger at 60% context" },
|
|
857
|
+
{ value: "target 25", label: "target 25", description: "compact enough to return near 25% context" },
|
|
858
|
+
{ value: "fraction 25", label: "fraction 25", description: "minimum oldest batch if target needs less" },
|
|
859
|
+
{ value: "trigger", label: "trigger", description: "compact now using current strategy" },
|
|
860
|
+
{ value: "help", label: "help", description: "insert command help" },
|
|
861
|
+
];
|
|
862
|
+
const filtered = query
|
|
863
|
+
? items.filter((item) => item.value.toLowerCase().startsWith(query) || item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query))
|
|
864
|
+
: items;
|
|
865
|
+
return filtered.length > 0 ? filtered.slice(0, 20) : null;
|
|
866
|
+
},
|
|
867
|
+
handler: async (args, ctx) => {
|
|
868
|
+
await handleZcompactCommand(pi, state, args, ctx, () => renderHarnessWidget(pi, state, ctx));
|
|
869
|
+
},
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
pi.registerCommand("zcommit", {
|
|
873
|
+
description: "Easy governed ZOB commit workflow: /zcommit status [paths/globs...]|plan [paths/globs...]|adopt <paths...>|commit [paths/globs...]|push|autocommit on|off|autopush on|off (no aliases)",
|
|
874
|
+
getArgumentCompletions: zcommitArgumentCompletions,
|
|
875
|
+
handler: async (args, ctx) => {
|
|
876
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
877
|
+
const requested = (parts[0] ?? "status").toLowerCase();
|
|
878
|
+
const pathspecArgs = parts.slice(1).filter((part) => part !== "--");
|
|
879
|
+
|
|
880
|
+
if (requested === "status") {
|
|
881
|
+
const plan = buildZcommitPlan(ctx.cwd, state.zcommit, { pathspecs: pathspecArgs });
|
|
882
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry("status", state, plan));
|
|
883
|
+
ctx.ui.notify(formatZcommitStatus(plan), plan.noShip ? "warning" : "info");
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
if (requested === "plan") {
|
|
887
|
+
const plan = buildZcommitPlan(ctx.cwd, state.zcommit, { pathspecs: pathspecArgs });
|
|
888
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry("plan", state, plan));
|
|
889
|
+
ctx.ui.notify(formatZcommitPlan(plan), plan.noShip ? "warning" : "info");
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (requested === "adopt") {
|
|
893
|
+
const result = runGovernedZcommitAdopt(ctx.cwd, state.zcommit, parts.slice(1));
|
|
894
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry(result.ok ? "adopt_completed" : "adopt_blocked", state, result.plan, result));
|
|
895
|
+
renderHarnessWidget(pi, state, ctx);
|
|
896
|
+
const adopted = result.adopted.join(", ") || "none";
|
|
897
|
+
const excluded = result.excluded.map((entry) => `${entry.path}(${entry.reason})`).join(", ") || "none";
|
|
898
|
+
const errors = result.errors.join(" | ") || "none";
|
|
899
|
+
ctx.ui.notify(`${result.message}; adopted=[${adopted}] excluded=[${excluded}] errors=[${errors}]; ${formatZcommitPlan(result.plan)}`, result.ok ? "info" : "warning");
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
if (requested === "autocommit" || requested === "autopush") {
|
|
903
|
+
const value = parts[1]?.toLowerCase();
|
|
904
|
+
if (value !== "on" && value !== "off") {
|
|
905
|
+
ctx.ui.notify(`Usage: /zcommit ${requested} on|off`, "warning");
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
const policy = readZcommitPolicy(ctx.cwd);
|
|
909
|
+
if (value === "on" && !policy.loaded) {
|
|
910
|
+
ctx.ui.notify(`/zcommit ${requested} on blocked: .pi/git-policy.json must load first`, "warning");
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
if (requested === "autopush" && value === "on" && state.zcommit.autocommit !== "on") {
|
|
914
|
+
ctx.ui.notify("/zcommit autopush on blocked: enable /zcommit autocommit on first; fail-closed", "warning");
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
setZcommitToggle(state, requested, value);
|
|
918
|
+
if (requested === "autocommit" && value === "off") setZcommitToggle(state, "autopush", "off");
|
|
919
|
+
const nextPlan = buildZcommitPlan(ctx.cwd, state.zcommit);
|
|
920
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry(`${requested}_${value}`, state, nextPlan));
|
|
921
|
+
renderHarnessWidget(pi, state, ctx);
|
|
922
|
+
ctx.ui.notify(`zcommit ${requested}=${value} (easy mode=${nextPlan.selectionMode}; commit=${nextPlan.commitEnabled ? "easy-ready" : "blocked"} push=${nextPlan.pushEnabled ? "gated" : "blocked"})`, value === "on" ? "warning" : "info");
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
if (requested === "commit") {
|
|
926
|
+
const result = runGovernedZcommitCommit(ctx.cwd, state.zcommit, { pathspecs: pathspecArgs });
|
|
927
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry(result.ok ? "commit_created" : "commit_blocked", state, result.plan, result));
|
|
928
|
+
renderHarnessWidget(pi, state, ctx);
|
|
929
|
+
ctx.ui.notify(result.message, result.ok ? "info" : "warning");
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
if (requested === "push") {
|
|
933
|
+
const result = runGovernedZcommitPush(ctx.cwd, state.zcommit, { explicitPush: true });
|
|
934
|
+
pi.appendEntry("zob-zcommit", zcommitLedgerEntry(result.ok ? "push_completed" : "push_blocked", state, result.plan, result));
|
|
935
|
+
renderHarnessWidget(pi, state, ctx);
|
|
936
|
+
ctx.ui.notify(result.message, result.ok ? "info" : "warning");
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
ctx.ui.notify("Unknown /zcommit command. Use status [paths/globs...]|plan [paths/globs...]|adopt <paths...>|autocommit on|off|autopush on|off|commit [paths/globs...]|push. No aliases are registered.", "warning");
|
|
940
|
+
},
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
const handleAutonomyCommand = async (args: string, ctx: Parameters<Parameters<typeof pi.registerCommand>[1]["handler"]>[1]): Promise<void> => {
|
|
944
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
945
|
+
const requested = (parts[0] ?? "status").toLowerCase();
|
|
946
|
+
state.autonomy.policy = readInteractiveAutonomyPolicy(ctx.cwd);
|
|
947
|
+
state.autonomy.policyHash = sha256(JSON.stringify({ ...state.autonomy.policy, source: undefined }));
|
|
948
|
+
|
|
949
|
+
if (requested === "help" || requested === "--help" || requested === "-h") {
|
|
950
|
+
ctx.ui.setEditorText(autonomyHelpTemplate());
|
|
951
|
+
ctx.ui.notify("ZOB autonomy help inserted.", "info");
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (requested === "daemon") {
|
|
956
|
+
const daemonSubcommand = (parts[1] ?? "status").toLowerCase();
|
|
957
|
+
if (!["status", "plan-tick", "tick", "start", "stop"].includes(daemonSubcommand)) {
|
|
958
|
+
ctx.ui.notify("Unsupported daemon command. Use /autonomy daemon status|tick|start --max-ticks N|stop.", "warning");
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
if (daemonSubcommand === "stop") {
|
|
962
|
+
stopDaemonLoop(state, "manual_stop");
|
|
963
|
+
const daemonState = buildDaemonRuntimeState(daemonInputFromState(state));
|
|
964
|
+
state.daemon.lastStatus = daemonState;
|
|
965
|
+
pi.appendEntry("zob-daemon-runtime", daemonRuntimeLedgerEntry(daemonState));
|
|
966
|
+
renderHarnessWidget(pi, state, ctx);
|
|
967
|
+
ctx.ui.notify(formatDaemonStatusForUi(daemonState), "warning");
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (daemonSubcommand === "start") {
|
|
971
|
+
const maxTicks = parseDaemonMaxTicks(parts);
|
|
972
|
+
if (!maxTicks) {
|
|
973
|
+
ctx.ui.notify("Use /autonomy daemon start --max-ticks N with N>=1 for a bounded supervised session loop.", "warning");
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
if (state.daemon.loop.status === "running") {
|
|
977
|
+
ctx.ui.notify(`daemon loop already running ticks=${state.daemon.loop.tickCount}/${state.daemon.loop.maxTicks ?? "?"}; use /autonomy daemon stop first`, "warning");
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const startedAt = new Date().toISOString();
|
|
981
|
+
state.daemon.loop = {
|
|
982
|
+
schema: "zob.daemon-loop-snapshot.v1",
|
|
983
|
+
status: "running",
|
|
984
|
+
tickCount: 0,
|
|
985
|
+
maxTicks,
|
|
986
|
+
startedAt,
|
|
987
|
+
supervised: true,
|
|
988
|
+
bounded: true,
|
|
989
|
+
sessionLocal: true,
|
|
990
|
+
autoStartDaemon: false,
|
|
991
|
+
continuousLoop: false,
|
|
992
|
+
cronEnabled: false,
|
|
993
|
+
};
|
|
994
|
+
state.daemon.policy = { ...state.daemon.policy, enabled: true };
|
|
995
|
+
const { daemonState, plan } = recordDaemonTick(pi, state, ctx);
|
|
996
|
+
if (plan.stop.stop) stopDaemonLoop(state, `stop_condition_${plan.status}`);
|
|
997
|
+
if (state.daemon.loop.tickCount >= maxTicks) stopDaemonLoop(state, "max_ticks_reached");
|
|
998
|
+
if (state.daemon.loop.status === "running") scheduleDaemonLoop(pi, state, ctx);
|
|
999
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1000
|
+
ctx.ui.notify(formatDaemonStatusForUi(daemonState), plan.stop.stop ? "warning" : "info");
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
if (daemonSubcommand === "tick" || daemonSubcommand === "plan-tick") {
|
|
1004
|
+
const queueReadonly = parts.includes("--queue-readonly") || parts.includes("--queue_readonly");
|
|
1005
|
+
const unsupportedQueueFlag = parts.includes("--queue") && !queueReadonly;
|
|
1006
|
+
if (unsupportedQueueFlag) {
|
|
1007
|
+
ctx.ui.notify("Use explicit /autonomy daemon tick --queue-readonly for the safe read-only queue bridge.", "warning");
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
const { plan, queueTick } = recordDaemonTick(pi, state, ctx, { queueReadonly });
|
|
1011
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1012
|
+
ctx.ui.notify(formatDaemonPlanForUi(plan, queueTick), plan.stop.stop || queueTick?.status === "failed" ? "warning" : "info");
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const daemonState = buildDaemonRuntimeState(daemonInputFromState(state));
|
|
1016
|
+
state.daemon.lastStatus = daemonState;
|
|
1017
|
+
state.daemon.updatedAt = new Date().toISOString();
|
|
1018
|
+
pi.appendEntry("zob-daemon-runtime", daemonRuntimeLedgerEntry(daemonState));
|
|
1019
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1020
|
+
ctx.ui.notify(formatDaemonStatusForUi(daemonState), daemonState.status === "blocked" || daemonState.status === "needs_user" || daemonState.status === "needs_oracle" ? "warning" : "info");
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (requested === "score") {
|
|
1025
|
+
const draft = parts.slice(1).join(" ");
|
|
1026
|
+
if (!draft) {
|
|
1027
|
+
ctx.ui.notify("Use /autonomy score <mission draft> to score without launching.", "warning");
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
const scored = scoreMissionReadiness(draft, { mode: state.autonomy.mode, policy: state.autonomy.policy });
|
|
1031
|
+
const readiness = scored.launchAuthorization
|
|
1032
|
+
? { ...scored, launchAuthorization: undefined, inScopeAutonomousActionsAuthorized: false, manualPerActionApprovalRequired: true }
|
|
1033
|
+
: scored;
|
|
1034
|
+
state.autonomy.lastReadiness = readiness;
|
|
1035
|
+
state.autonomy.lastLaunchAuthorization = undefined;
|
|
1036
|
+
state.autonomy.updatedAt = readiness.generatedAt;
|
|
1037
|
+
pi.appendEntry("zob-mission-readiness", toMissionReadinessLedgerEntry(readiness));
|
|
1038
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1039
|
+
ctx.ui.notify(`${formatMissionReadinessForUi(readiness)} · score-only no launch`, readiness.decision === "block" ? "warning" : "info");
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const requestedMode = requested === "stop" ? "off" : asInteractiveAutonomyMode(requested);
|
|
1044
|
+
if (requestedMode) {
|
|
1045
|
+
state.autonomy.mode = requestedMode;
|
|
1046
|
+
state.autonomy.enabled = requestedMode !== "off";
|
|
1047
|
+
state.autonomy.updatedAt = new Date().toISOString();
|
|
1048
|
+
if (requestedMode === "off") {
|
|
1049
|
+
state.autonomy.lastLaunchAuthorization = undefined;
|
|
1050
|
+
}
|
|
1051
|
+
pi.appendEntry("zob-autonomy-state", toAutonomyStateLedgerEntry(state.autonomy));
|
|
1052
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1053
|
+
ctx.ui.notify(`ZOB autonomy: ${requestedMode}${requestedMode === "off" ? " (stopped)" : ""}`, requestedMode === "off" ? "warning" : "info");
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
if (requested === "status" || requested.length === 0) {
|
|
1058
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1059
|
+
ctx.ui.notify(formatInteractiveAutonomyStatus(state.autonomy), "info");
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
ctx.ui.notify("Unknown autonomy command. Use /autonomy help or /autonomy open|controlled|adaptive|status|stop|daemon status|daemon plan-tick.", "warning");
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
pi.registerCommand("autonomy", {
|
|
1067
|
+
description: "Set/show ZOB interactive autonomy and scoped daemon plan-only status: /autonomy open|controlled|adaptive|status|stop|daemon status|daemon plan-tick",
|
|
1068
|
+
getArgumentCompletions: autonomyArgumentCompletions,
|
|
1069
|
+
handler: handleAutonomyCommand,
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
const handleComputeCommand = async (args: string, ctx: Parameters<Parameters<typeof pi.registerCommand>[1]["handler"]>[1]): Promise<void> => {
|
|
1073
|
+
const parsed = parseComputeCommandArgs(args);
|
|
1074
|
+
if (parsed.help || args.trim().length === 0) {
|
|
1075
|
+
ctx.ui.setEditorText(computeHelpTemplate());
|
|
1076
|
+
ctx.ui.notify("ZOB compute command template inserted. Use /compute auto . or /effort high .", "info");
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
const preview = buildComputePreview(ctx.cwd, {
|
|
1080
|
+
domain: parsed.domain,
|
|
1081
|
+
requestedProfile: parsed.requestedProfile,
|
|
1082
|
+
targetPath: parsed.targetPath,
|
|
1083
|
+
maxProfile: parsed.maxProfile,
|
|
1084
|
+
riskHints: parsed.riskHints,
|
|
1085
|
+
});
|
|
1086
|
+
const resolution = resolveComputeProfile(ctx.cwd, {
|
|
1087
|
+
domain: parsed.domain,
|
|
1088
|
+
requestedProfile: parsed.requestedProfile,
|
|
1089
|
+
targetPath: parsed.targetPath,
|
|
1090
|
+
maxProfile: parsed.maxProfile,
|
|
1091
|
+
riskHints: parsed.riskHints,
|
|
1092
|
+
});
|
|
1093
|
+
const workflow = buildComputeWorkflowShape(ctx.cwd, {
|
|
1094
|
+
domain: parsed.domain,
|
|
1095
|
+
requestedProfile: parsed.requestedProfile,
|
|
1096
|
+
targetPath: parsed.targetPath,
|
|
1097
|
+
maxProfile: parsed.maxProfile,
|
|
1098
|
+
riskHints: parsed.riskHints,
|
|
1099
|
+
});
|
|
1100
|
+
const caps = resolution.caps && typeof resolution.caps === "object" ? resolution.caps as Record<string, unknown> : {};
|
|
1101
|
+
const effectiveProfile = typeof resolution.effectiveProfile === "string" ? resolution.effectiveProfile : "unknown";
|
|
1102
|
+
const recommendedProfile = typeof preview.recommendedProfile === "string" ? preview.recommendedProfile : "unknown";
|
|
1103
|
+
const laneCount = Array.isArray(workflow.lanes) ? workflow.lanes.length : 0;
|
|
1104
|
+
pi.appendEntry("zob-compute-profile", {
|
|
1105
|
+
schema: "zob.compute-command-preview.v1",
|
|
1106
|
+
requestedProfile: parsed.requestedProfile,
|
|
1107
|
+
recommendedProfile,
|
|
1108
|
+
effectiveProfile,
|
|
1109
|
+
domain: parsed.domain,
|
|
1110
|
+
targetPathHash: sha256(parsed.targetPath),
|
|
1111
|
+
targetPathStored: false,
|
|
1112
|
+
maxProfile: parsed.maxProfile,
|
|
1113
|
+
riskHints: parsed.riskHints,
|
|
1114
|
+
caps,
|
|
1115
|
+
laneCount,
|
|
1116
|
+
noShip: resolution.noShip === true,
|
|
1117
|
+
parentOwnedDispatch: true,
|
|
1118
|
+
childDirectDispatch: false,
|
|
1119
|
+
bodyStored: false,
|
|
1120
|
+
promptBodiesStored: false,
|
|
1121
|
+
outputBodiesStored: false,
|
|
1122
|
+
generatedAt: new Date().toISOString(),
|
|
1123
|
+
});
|
|
1124
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1125
|
+
const maxAgents = typeof caps.maxAgents === "number" ? caps.maxAgents : "?";
|
|
1126
|
+
const maxDepth = typeof caps.maxDelegationDepth === "number" ? caps.maxDelegationDepth : "?";
|
|
1127
|
+
const maxParallel = typeof caps.maxParallel === "number" ? caps.maxParallel : "?";
|
|
1128
|
+
const oracleRequired = caps.oracleRequired === true ? "oracle required" : "oracle conditional/off";
|
|
1129
|
+
const noShip = resolution.noShip === true ? " · no_ship=true" : "";
|
|
1130
|
+
ctx.ui.notify(`ZOB compute ${parsed.requestedProfile}→${effectiveProfile} (recommended ${recommendedProfile}) · agents≤${maxAgents} depth≤${maxDepth} parallel≤${maxParallel} · lanes=${laneCount} · ${oracleRequired}${noShip}`, resolution.noShip === true ? "warning" : "info");
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
pi.registerCommand("compute", {
|
|
1134
|
+
description: "Preview/resolve ZOB compute effort: /compute auto|low|medium|high|xhigh|max [target_path]",
|
|
1135
|
+
getArgumentCompletions: computeArgumentCompletions,
|
|
1136
|
+
handler: handleComputeCommand,
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
pi.registerCommand("effort", {
|
|
1140
|
+
description: "Alias for /compute. Example: /effort auto .",
|
|
1141
|
+
getArgumentCompletions: computeArgumentCompletions,
|
|
1142
|
+
handler: handleComputeCommand,
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
const handleProjectDnaCommand = async (args: string, ctx: Parameters<Parameters<typeof pi.registerCommand>[1]["handler"]>[1]): Promise<void> => {
|
|
1146
|
+
const parsed = parseProjectDnaCommandArgs(args);
|
|
1147
|
+
if (parsed.mode === "help") {
|
|
1148
|
+
ctx.ui.setEditorText(projectDnaHelpTemplate());
|
|
1149
|
+
ctx.ui.notify("ZOB ProjectDNA command template inserted.", "info");
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
if (parsed.mode === "readiness") {
|
|
1153
|
+
const audit = buildProjectDnaReadinessAudit(ctx.cwd, { scanDir: parsed.scanDir });
|
|
1154
|
+
pi.appendEntry("zob-project-dna-command", {
|
|
1155
|
+
schema: "zob.project-dna-command-readiness.v1",
|
|
1156
|
+
scanDirHash: sha256(parsed.scanDir ?? "reports/project-dna-scans/project-dna-factory-smoke"),
|
|
1157
|
+
scanDirStored: false,
|
|
1158
|
+
verdict: audit.verdict,
|
|
1159
|
+
noShip: audit.no_ship === true,
|
|
1160
|
+
bodyStored: false,
|
|
1161
|
+
generatedAt: new Date().toISOString(),
|
|
1162
|
+
});
|
|
1163
|
+
ctx.ui.notify(`ZOB ProjectDNA readiness: ${String(audit.verdict)}${audit.no_ship === true ? " · no_ship=true" : ""}`, audit.no_ship === true ? "warning" : "info");
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
if (parsed.mode === "plan") {
|
|
1167
|
+
const plan = buildProjectDnaAgenticPlan(ctx.cwd, { manifestPath: parsed.manifestPath ?? "", scanDir: parsed.scanDir });
|
|
1168
|
+
const lanes = Array.isArray(plan.lanes) ? plan.lanes.length : 0;
|
|
1169
|
+
const effectiveProfile = typeof plan.effective_compute_profile === "string" ? plan.effective_compute_profile : "unknown";
|
|
1170
|
+
const effectiveCapture = typeof plan.effective_capture_mode === "string" ? plan.effective_capture_mode : "unknown";
|
|
1171
|
+
pi.appendEntry("zob-project-dna-command", {
|
|
1172
|
+
schema: "zob.project-dna-command-plan.v1",
|
|
1173
|
+
manifestPathHash: sha256(parsed.manifestPath ?? ""),
|
|
1174
|
+
manifestPathStored: false,
|
|
1175
|
+
scanDirHash: sha256(parsed.scanDir ?? ""),
|
|
1176
|
+
scanDirStored: false,
|
|
1177
|
+
effectiveProfile,
|
|
1178
|
+
effectiveCapture,
|
|
1179
|
+
laneCount: lanes,
|
|
1180
|
+
metadataOnly: true,
|
|
1181
|
+
childDispatchAllowed: false,
|
|
1182
|
+
knowledgeBackendWriteEnabled: false,
|
|
1183
|
+
bodyStored: false,
|
|
1184
|
+
generatedAt: new Date().toISOString(),
|
|
1185
|
+
});
|
|
1186
|
+
ctx.ui.notify(`ZOB ProjectDNA plan: profile=${effectiveProfile} capture=${effectiveCapture} lanes=${lanes}`, "info");
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
const result = buildProjectDnaQueryResult(ctx.cwd, { scanDir: parsed.scanDir, query: parsed.query ?? "project dna", maxFiles: 8 });
|
|
1190
|
+
const files = Array.isArray(result.files_to_read_first) ? result.files_to_read_first.length : 0;
|
|
1191
|
+
const citations = Array.isArray(result.citations) ? result.citations.length : 0;
|
|
1192
|
+
pi.appendEntry("zob-project-dna-command", {
|
|
1193
|
+
schema: "zob.project-dna-command-query.v1",
|
|
1194
|
+
sourceId: result.source_id,
|
|
1195
|
+
scanDirHash: sha256(String(result.scan_dir ?? parsed.scanDir ?? "")),
|
|
1196
|
+
scanDirStored: false,
|
|
1197
|
+
queryHash: result.query_hash,
|
|
1198
|
+
rawQueryStored: false,
|
|
1199
|
+
fileCount: files,
|
|
1200
|
+
citationCount: citations,
|
|
1201
|
+
childDispatchAllowed: false,
|
|
1202
|
+
knowledgeBackendWriteEnabled: false,
|
|
1203
|
+
bodyStored: false,
|
|
1204
|
+
generatedAt: new Date().toISOString(),
|
|
1205
|
+
});
|
|
1206
|
+
ctx.ui.notify(`ZOB ProjectDNA query: source=${String(result.source_id)} files=${files} citations=${citations}`, "info");
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
pi.registerCommand("project-dna", {
|
|
1210
|
+
description: "Plan/query/audit repo-local ProjectDNA context. Example: /project-dna plan .pi/factories/project-dna/example-project-dna-manifest-v2.json reports/project-dna-scans/project-dna-factory-smoke",
|
|
1211
|
+
getArgumentCompletions: projectDnaArgumentCompletions,
|
|
1212
|
+
handler: handleProjectDnaCommand,
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
pi.registerCommand("rules_status", {
|
|
1216
|
+
description: "Resolve active ZOB rule profile for optional paths and current mode",
|
|
1217
|
+
handler: async (args, ctx) => {
|
|
1218
|
+
const paths = args.trim().length > 0 ? args.split(/[\s,]+/).map((item) => item.trim()).filter(Boolean) : undefined;
|
|
1219
|
+
const resolution = resolveRuleProfile({ repoRoot: ctx.cwd, mode: state.activeMode, paths });
|
|
1220
|
+
state.activeRuleResolution = resolution;
|
|
1221
|
+
pi.appendEntry("zob-rules-resolution", {
|
|
1222
|
+
profile: resolution.profile,
|
|
1223
|
+
rulePacks: resolution.rulePacks,
|
|
1224
|
+
allowedTools: resolution.allowedTools,
|
|
1225
|
+
requiredValidation: resolution.requiredValidation,
|
|
1226
|
+
oracleRequired: resolution.oracleRequired,
|
|
1227
|
+
noShipConditions: resolution.noShipConditions,
|
|
1228
|
+
enforcement: resolution.enforcement,
|
|
1229
|
+
errors: resolution.errors,
|
|
1230
|
+
promptBodiesStored: false,
|
|
1231
|
+
outputBodiesStored: false,
|
|
1232
|
+
timestamp: new Date().toISOString(),
|
|
1233
|
+
});
|
|
1234
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1235
|
+
ctx.ui.notify(formatRuleResolution(resolution), resolution.errors.length > 0 ? "warning" : "info");
|
|
1236
|
+
},
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
pi.registerCommand("contract", {
|
|
1240
|
+
description: "Insert the six-part delegation contract template",
|
|
1241
|
+
handler: async (args, ctx) => {
|
|
1242
|
+
ctx.ui.setEditorText(formatContractTemplate(args.trim() || "[atomic goal]"));
|
|
1243
|
+
},
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
pi.registerCommand("goal", {
|
|
1247
|
+
description: "Unified ZOB runtime goal: /goal <objective>, pause, resume, clear, status, gate, todo, oracle PASS|WARN|FAIL",
|
|
1248
|
+
handler: async (args, ctx) => {
|
|
1249
|
+
await handleGoalCommand(pi, state, args, ctx, () => renderHarnessWidget(pi, state, ctx));
|
|
1250
|
+
},
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
pi.registerCommand("todo", {
|
|
1254
|
+
description: "Alias for /goal todo. Manage goal-linked TODOs and subtodos.",
|
|
1255
|
+
handler: async (args, ctx) => {
|
|
1256
|
+
await handleGoalCommand(pi, state, `todo ${args}`.trim(), ctx, () => renderHarnessWidget(pi, state, ctx));
|
|
1257
|
+
},
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
pi.registerCommand("todos", {
|
|
1261
|
+
description: "Alias for /goal todo tree. Use /todos overlay to open the TODO overlay.",
|
|
1262
|
+
handler: async (args, ctx) => {
|
|
1263
|
+
const trimmed = args.trim();
|
|
1264
|
+
if (trimmed === "overlay" || trimmed.startsWith("overlay ") || trimmed === "view" || trimmed.startsWith("view ")) {
|
|
1265
|
+
await showGoalTodoOverlay(ctx, state, trimmed.split(/\s+/)[1]);
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
await handleGoalCommand(pi, state, `todo ${trimmed || "tree"}`.trim(), ctx, () => renderHarnessWidget(pi, state, ctx));
|
|
1269
|
+
},
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
pi.registerCommand("goal_gate", {
|
|
1273
|
+
description: "Alias for /goal gate. Set or insert the active ZOB goal gate; --strict requires it before ZOB dispatch tools.",
|
|
1274
|
+
handler: async (args, ctx) => {
|
|
1275
|
+
handleGoalGateCommand(pi, state, args.trim(), ctx, () => renderHarnessWidget(pi, state, ctx));
|
|
1276
|
+
},
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
pi.registerCommand("job_intake", {
|
|
1280
|
+
description: "Parse billable job intake into active goal plus optional advisory budget sidecar",
|
|
1281
|
+
handler: async (args, ctx) => {
|
|
1282
|
+
const text = args.trim();
|
|
1283
|
+
if (!text) {
|
|
1284
|
+
ctx.ui.setEditorText([
|
|
1285
|
+
"ORIGINAL_USER_ASK: [paste the user's exact ask]",
|
|
1286
|
+
"ACTIVE_GOAL: [one bounded billable job goal]",
|
|
1287
|
+
"EXPECTED_OUTPUT: [observable paid deliverable]",
|
|
1288
|
+
"CONSTRAINTS: [must-do and must-not-do constraints]",
|
|
1289
|
+
"VALIDATION_EVIDENCE: [commands, files, sentinels, or oracle verdict required]",
|
|
1290
|
+
"BUDGET: [optional advisory sidecar; absence is allowed]",
|
|
1291
|
+
].join("\n"));
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
const intake = parseBillableJobIntake(text);
|
|
1295
|
+
const errors = validateBillableJobIntake(intake);
|
|
1296
|
+
if (errors.length > 0) {
|
|
1297
|
+
ctx.ui.notify(`ZOB job intake rejected:\n- ${errors.join("\n- ")}`, "warning");
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
state.activeGoal = intake.goal;
|
|
1301
|
+
state.goalRequired = true;
|
|
1302
|
+
pi.appendEntry("zob-job-intake", intake);
|
|
1303
|
+
renderHarnessWidget(pi, state, ctx);
|
|
1304
|
+
ctx.ui.notify(`ZOB job intake accepted: ${intake.goal.activeGoal.slice(0, 100)} (budget advisory only)`, "info");
|
|
1305
|
+
},
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
pi.registerCommand("agents", {
|
|
1309
|
+
description: "List ZOB project/user specialist agents",
|
|
1310
|
+
handler: async (_args, ctx) => {
|
|
1311
|
+
const agents = discoverAgents(ctx.cwd, "both");
|
|
1312
|
+
ctx.ui.notify(formatAgentList(agents), "info");
|
|
1313
|
+
},
|
|
1314
|
+
});
|
|
1315
|
+
}
|