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,715 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import type { CompactionResult, ExtensionAPI, ExtensionContext, SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { compact, estimateTokens, findCutPoint } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
|
|
5
|
+
import { sha256 } from "../utils/hashing.js";
|
|
6
|
+
import { isRecord } from "../utils/records.js";
|
|
7
|
+
import { buildZobCompactionInstructions, withZobCompactionDetails, ZOB_COMPACTION_TARGET_TOKENS, type ZobCompactionDetails } from "./compaction-policy.js";
|
|
8
|
+
import type { HarnessRuntimeState } from "./state.js";
|
|
9
|
+
|
|
10
|
+
export const ZCOMPACT_ENTRY_TYPE = "zob-zcompact";
|
|
11
|
+
export const ZCOMPACT_CONFIG_SCHEMA = "zob.zcompact-config.v1";
|
|
12
|
+
export const ZCOMPACT_RUN_SCHEMA = "zob.zcompact-run.v1";
|
|
13
|
+
export const ZCOMPACT_AUTO_MARKER = "ZOB_ZCOMPACT_AUTO";
|
|
14
|
+
|
|
15
|
+
export type ZcompactMode = "off" | "observe" | "auto";
|
|
16
|
+
export type ZcompactRunReason = "auto_threshold" | "manual_trigger";
|
|
17
|
+
export type ZcompactDecisionAction = "off" | "wait" | "would_compact" | "started" | "skipped" | "deferred" | "blocked";
|
|
18
|
+
|
|
19
|
+
type CompactPreparation = Parameters<typeof compact>[0];
|
|
20
|
+
type CompactMessage = CompactPreparation["messagesToSummarize"][number];
|
|
21
|
+
|
|
22
|
+
export interface ZcompactUsageSnapshot {
|
|
23
|
+
at: string;
|
|
24
|
+
tokens?: number;
|
|
25
|
+
contextWindow?: number;
|
|
26
|
+
percent?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ZcompactDecision {
|
|
30
|
+
at: string;
|
|
31
|
+
action: ZcompactDecisionAction;
|
|
32
|
+
reason: string;
|
|
33
|
+
usage?: ZcompactUsageSnapshot;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ZcompactPendingRun {
|
|
37
|
+
runId: string;
|
|
38
|
+
reason: ZcompactRunReason;
|
|
39
|
+
startedAt: string;
|
|
40
|
+
contextTokens: number;
|
|
41
|
+
contextWindow: number;
|
|
42
|
+
percentBefore: number;
|
|
43
|
+
keepRecentTokens: number;
|
|
44
|
+
estimatedSummarizedTokens: number;
|
|
45
|
+
triggerPercent: number;
|
|
46
|
+
compactOldestFraction: number;
|
|
47
|
+
targetAfterPercent: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ZcompactRunRecord extends ZcompactPendingRun {
|
|
51
|
+
status: "running" | "completed" | "failed" | "cancelled";
|
|
52
|
+
completedAt?: string;
|
|
53
|
+
firstKeptEntryId?: string;
|
|
54
|
+
tokensBefore?: number;
|
|
55
|
+
estimatedSummaryTokens?: number;
|
|
56
|
+
estimatedNetSavedTokens?: number;
|
|
57
|
+
summaryHash?: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ZcompactRuntimeState {
|
|
62
|
+
mode: ZcompactMode;
|
|
63
|
+
triggerPercent: number;
|
|
64
|
+
compactOldestFraction: number;
|
|
65
|
+
targetAfterPercent: number;
|
|
66
|
+
minSummarizableTokens: number;
|
|
67
|
+
cooldownMs: number;
|
|
68
|
+
running: boolean;
|
|
69
|
+
pending?: ZcompactPendingRun;
|
|
70
|
+
lastRun?: ZcompactRunRecord;
|
|
71
|
+
lastDecision?: ZcompactDecision;
|
|
72
|
+
lastUsage?: ZcompactUsageSnapshot;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createZcompactRuntimeState(): ZcompactRuntimeState {
|
|
76
|
+
return {
|
|
77
|
+
mode: "off",
|
|
78
|
+
triggerPercent: 60,
|
|
79
|
+
compactOldestFraction: 0.25,
|
|
80
|
+
targetAfterPercent: 25,
|
|
81
|
+
minSummarizableTokens: 8_000,
|
|
82
|
+
cooldownMs: 120_000,
|
|
83
|
+
running: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function nowIso(): string {
|
|
88
|
+
return new Date().toISOString();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function finiteNumber(value: unknown): number | undefined {
|
|
92
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function numberField(record: Record<string, unknown>, key: string): number | undefined {
|
|
96
|
+
return finiteNumber(record[key]);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function stringField(record: Record<string, unknown>, key: string): string | undefined {
|
|
100
|
+
const value = record[key];
|
|
101
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function clamp(value: number, min: number, max: number): number {
|
|
105
|
+
return Math.max(min, Math.min(max, value));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function safePercent(value: number, fallback: number): number {
|
|
109
|
+
return clamp(Number.isFinite(value) ? value : fallback, 1, 95);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function safeFraction(value: number, fallback: number): number {
|
|
113
|
+
return clamp(Number.isFinite(value) ? value : fallback, 0.05, 0.8);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseMaybePercentOrFraction(raw: string | undefined): number | undefined {
|
|
117
|
+
if (!raw) return undefined;
|
|
118
|
+
const cleaned = raw.trim().replace(/%$/, "");
|
|
119
|
+
const parsed = Number(cleaned);
|
|
120
|
+
if (!Number.isFinite(parsed)) return undefined;
|
|
121
|
+
return parsed > 1 ? parsed / 100 : parsed;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseMaybePercent(raw: string | undefined): number | undefined {
|
|
125
|
+
if (!raw) return undefined;
|
|
126
|
+
const cleaned = raw.trim().replace(/%$/, "");
|
|
127
|
+
const parsed = Number(cleaned);
|
|
128
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function formatPercent(value: number | undefined, digits = 1): string {
|
|
132
|
+
return typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(digits)}%` : "n/a";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function formatTokenCount(value: number | undefined): string {
|
|
136
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "n/a";
|
|
137
|
+
const safe = Math.max(0, Math.floor(value));
|
|
138
|
+
if (safe < 1_000) return String(safe);
|
|
139
|
+
if (safe < 1_000_000) return `${(safe / 1_000).toFixed(safe < 10_000 ? 1 : 0)}k`;
|
|
140
|
+
return `${(safe / 1_000_000).toFixed(1)}m`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function usageSnapshot(ctx: ExtensionContext): ZcompactUsageSnapshot {
|
|
144
|
+
const usage = ctx.getContextUsage();
|
|
145
|
+
const tokens = finiteNumber(usage?.tokens);
|
|
146
|
+
const contextWindow = finiteNumber(usage?.contextWindow);
|
|
147
|
+
const percent = finiteNumber(usage?.percent);
|
|
148
|
+
return { at: nowIso(), ...(tokens !== undefined ? { tokens } : {}), ...(contextWindow !== undefined ? { contextWindow } : {}), ...(percent !== undefined ? { percent } : {}) };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function usageIsKnown(usage: ZcompactUsageSnapshot): usage is ZcompactUsageSnapshot & { tokens: number; contextWindow: number; percent: number } {
|
|
152
|
+
return typeof usage.tokens === "number" && typeof usage.contextWindow === "number" && typeof usage.percent === "number";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function decision(state: ZcompactRuntimeState, action: ZcompactDecisionAction, reason: string, usage?: ZcompactUsageSnapshot): ZcompactDecision {
|
|
156
|
+
const record = { at: nowIso(), action, reason, ...(usage ? { usage } : {}) };
|
|
157
|
+
state.lastDecision = record;
|
|
158
|
+
if (usage) state.lastUsage = usage;
|
|
159
|
+
return record;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function msSince(iso: string | undefined): number | undefined {
|
|
163
|
+
if (!iso) return undefined;
|
|
164
|
+
const time = Date.parse(iso);
|
|
165
|
+
return Number.isFinite(time) ? Date.now() - time : undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function shouldNotifyDecision(state: ZcompactRuntimeState, action: ZcompactDecisionAction): boolean {
|
|
169
|
+
if (state.lastDecision?.action !== action) return true;
|
|
170
|
+
const age = msSince(state.lastDecision.at);
|
|
171
|
+
return age === undefined || age > Math.min(state.cooldownMs, 30_000);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function zcompactSettingsEntry(state: ZcompactRuntimeState, reason: string): Record<string, unknown> {
|
|
175
|
+
return {
|
|
176
|
+
schema: ZCOMPACT_CONFIG_SCHEMA,
|
|
177
|
+
policyVersion: 2,
|
|
178
|
+
event: "config",
|
|
179
|
+
mode: state.mode,
|
|
180
|
+
triggerPercent: state.triggerPercent,
|
|
181
|
+
compactOldestFraction: state.compactOldestFraction,
|
|
182
|
+
targetAfterPercent: state.targetAfterPercent,
|
|
183
|
+
minSummarizableTokens: state.minSummarizableTokens,
|
|
184
|
+
cooldownMs: state.cooldownMs,
|
|
185
|
+
reason,
|
|
186
|
+
bodyStored: false,
|
|
187
|
+
promptBodiesStored: false,
|
|
188
|
+
outputBodiesStored: false,
|
|
189
|
+
generatedAt: nowIso(),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function zcompactRunEntry(run: ZcompactRunRecord, event: "start" | "complete" | "failed" | "cancelled"): Record<string, unknown> {
|
|
194
|
+
return {
|
|
195
|
+
schema: ZCOMPACT_RUN_SCHEMA,
|
|
196
|
+
policyVersion: 2,
|
|
197
|
+
event,
|
|
198
|
+
runId: run.runId,
|
|
199
|
+
reason: run.reason,
|
|
200
|
+
status: run.status,
|
|
201
|
+
startedAt: run.startedAt,
|
|
202
|
+
completedAt: run.completedAt,
|
|
203
|
+
contextTokens: run.contextTokens,
|
|
204
|
+
contextWindow: run.contextWindow,
|
|
205
|
+
percentBefore: run.percentBefore,
|
|
206
|
+
keepRecentTokens: run.keepRecentTokens,
|
|
207
|
+
estimatedSummarizedTokens: run.estimatedSummarizedTokens,
|
|
208
|
+
estimatedSummaryTokens: run.estimatedSummaryTokens,
|
|
209
|
+
estimatedNetSavedTokens: run.estimatedNetSavedTokens,
|
|
210
|
+
firstKeptEntryId: run.firstKeptEntryId,
|
|
211
|
+
tokensBefore: run.tokensBefore,
|
|
212
|
+
summaryHash: run.summaryHash,
|
|
213
|
+
errorHash: run.error ? sha256(run.error) : undefined,
|
|
214
|
+
triggerPercent: run.triggerPercent,
|
|
215
|
+
compactOldestFraction: run.compactOldestFraction,
|
|
216
|
+
targetAfterPercent: run.targetAfterPercent,
|
|
217
|
+
bodyStored: false,
|
|
218
|
+
promptBodiesStored: false,
|
|
219
|
+
outputBodiesStored: false,
|
|
220
|
+
generatedAt: nowIso(),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function appendConfig(pi: ExtensionAPI, state: ZcompactRuntimeState, reason: string): void {
|
|
225
|
+
pi.appendEntry(ZCOMPACT_ENTRY_TYPE, zcompactSettingsEntry(state, reason));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function appendRun(pi: ExtensionAPI, run: ZcompactRunRecord, event: "start" | "complete" | "failed" | "cancelled"): void {
|
|
229
|
+
pi.appendEntry(ZCOMPACT_ENTRY_TYPE, zcompactRunEntry(run, event));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function restoreZcompactStateFromBranch(branch: unknown[], current: ZcompactRuntimeState = createZcompactRuntimeState()): ZcompactRuntimeState {
|
|
233
|
+
const restored: ZcompactRuntimeState = { ...current, running: false, pending: undefined };
|
|
234
|
+
let latestConfigPolicyVersion: number | undefined;
|
|
235
|
+
for (const entry of branch) {
|
|
236
|
+
if (!isRecord(entry) || entry.customType !== ZCOMPACT_ENTRY_TYPE || !isRecord(entry.data)) continue;
|
|
237
|
+
const data = entry.data as Record<string, unknown>;
|
|
238
|
+
const schema = stringField(data, "schema");
|
|
239
|
+
if (schema === ZCOMPACT_CONFIG_SCHEMA) {
|
|
240
|
+
latestConfigPolicyVersion = numberField(data, "policyVersion");
|
|
241
|
+
const mode = stringField(data, "mode");
|
|
242
|
+
if (mode === "off" || mode === "observe" || mode === "auto") restored.mode = mode;
|
|
243
|
+
restored.triggerPercent = safePercent(numberField(data, "triggerPercent") ?? restored.triggerPercent, restored.triggerPercent);
|
|
244
|
+
restored.compactOldestFraction = safeFraction(numberField(data, "compactOldestFraction") ?? restored.compactOldestFraction, restored.compactOldestFraction);
|
|
245
|
+
restored.targetAfterPercent = safePercent(numberField(data, "targetAfterPercent") ?? restored.targetAfterPercent, restored.targetAfterPercent);
|
|
246
|
+
restored.minSummarizableTokens = Math.max(0, Math.trunc(numberField(data, "minSummarizableTokens") ?? restored.minSummarizableTokens));
|
|
247
|
+
restored.cooldownMs = Math.max(0, Math.trunc(numberField(data, "cooldownMs") ?? restored.cooldownMs));
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (schema !== ZCOMPACT_RUN_SCHEMA) continue;
|
|
251
|
+
const runId = stringField(data, "runId");
|
|
252
|
+
const reason = stringField(data, "reason");
|
|
253
|
+
const status = stringField(data, "status");
|
|
254
|
+
if (!runId || (reason !== "auto_threshold" && reason !== "manual_trigger")) continue;
|
|
255
|
+
const run: ZcompactRunRecord = {
|
|
256
|
+
runId,
|
|
257
|
+
reason,
|
|
258
|
+
status: status === "completed" || status === "failed" || status === "cancelled" ? status : "running",
|
|
259
|
+
startedAt: stringField(data, "startedAt") ?? stringField(data, "generatedAt") ?? nowIso(),
|
|
260
|
+
completedAt: stringField(data, "completedAt"),
|
|
261
|
+
contextTokens: Math.max(0, Math.trunc(numberField(data, "contextTokens") ?? 0)),
|
|
262
|
+
contextWindow: Math.max(1, Math.trunc(numberField(data, "contextWindow") ?? 1)),
|
|
263
|
+
percentBefore: numberField(data, "percentBefore") ?? 0,
|
|
264
|
+
keepRecentTokens: Math.max(1, Math.trunc(numberField(data, "keepRecentTokens") ?? 1)),
|
|
265
|
+
estimatedSummarizedTokens: Math.max(0, Math.trunc(numberField(data, "estimatedSummarizedTokens") ?? 0)),
|
|
266
|
+
estimatedSummaryTokens: numberField(data, "estimatedSummaryTokens"),
|
|
267
|
+
estimatedNetSavedTokens: numberField(data, "estimatedNetSavedTokens"),
|
|
268
|
+
triggerPercent: numberField(data, "triggerPercent") ?? restored.triggerPercent,
|
|
269
|
+
compactOldestFraction: numberField(data, "compactOldestFraction") ?? restored.compactOldestFraction,
|
|
270
|
+
targetAfterPercent: numberField(data, "targetAfterPercent") ?? restored.targetAfterPercent,
|
|
271
|
+
firstKeptEntryId: stringField(data, "firstKeptEntryId"),
|
|
272
|
+
tokensBefore: numberField(data, "tokensBefore"),
|
|
273
|
+
summaryHash: stringField(data, "summaryHash"),
|
|
274
|
+
};
|
|
275
|
+
restored.lastRun = run;
|
|
276
|
+
}
|
|
277
|
+
if (latestConfigPolicyVersion === undefined && restored.triggerPercent === 50 && restored.targetAfterPercent === 38 && restored.compactOldestFraction === 0.25) {
|
|
278
|
+
restored.triggerPercent = 60;
|
|
279
|
+
restored.targetAfterPercent = 25;
|
|
280
|
+
}
|
|
281
|
+
return restored;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function zcompactHelpText(): string {
|
|
285
|
+
return [
|
|
286
|
+
"# ZOB zcompact",
|
|
287
|
+
"",
|
|
288
|
+
"Session-local proactive compaction for long coding-agent conversations.",
|
|
289
|
+
"",
|
|
290
|
+
"Commands:",
|
|
291
|
+
"/zcompact status # show current usage and settings",
|
|
292
|
+
"/zcompact observe # report what would compact at the threshold, no mutation",
|
|
293
|
+
"/zcompact on # auto-compact when context reaches the threshold",
|
|
294
|
+
"/zcompact off # disable proactive compaction",
|
|
295
|
+
"/zcompact threshold 60 # set trigger percent",
|
|
296
|
+
"/zcompact target 25 # compact enough to return near 25% context",
|
|
297
|
+
"/zcompact fraction 25 # minimum oldest batch when target needs less",
|
|
298
|
+
"/zcompact trigger # compact now using current target, even below threshold",
|
|
299
|
+
"",
|
|
300
|
+
"Safety:",
|
|
301
|
+
"- summary is a continuity index, not evidence",
|
|
302
|
+
"- recent messages remain in clear text according to the fraction",
|
|
303
|
+
"- ledgers store metadata/hashes only, not prompt/output bodies",
|
|
304
|
+
].join("\n");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function formatZcompactHudLine(state: ZcompactRuntimeState, ctx: ExtensionContext): string {
|
|
308
|
+
const usage = usageSnapshot(ctx);
|
|
309
|
+
state.lastUsage = usage;
|
|
310
|
+
const usageText = usageIsKnown(usage)
|
|
311
|
+
? `${formatPercent(usage.percent)} ${formatTokenCount(usage.tokens)}/${formatTokenCount(usage.contextWindow)}`
|
|
312
|
+
: "usage n/a";
|
|
313
|
+
const modeText = state.running ? "running" : state.mode;
|
|
314
|
+
const last = state.lastRun
|
|
315
|
+
? ` · last ${state.lastRun.status}${typeof state.lastRun.estimatedNetSavedTokens === "number" ? ` saved≈${formatTokenCount(state.lastRun.estimatedNetSavedTokens)}` : ""}`
|
|
316
|
+
: "";
|
|
317
|
+
return `ctx ${usageText} · zcompact ${modeText}@${formatPercent(state.triggerPercent, 0)}→${formatPercent(state.targetAfterPercent, 0)} minOld≈${formatPercent(state.compactOldestFraction * 100, 0)}${last}`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function formatZcompactStatus(state: ZcompactRuntimeState, ctx: ExtensionContext): string {
|
|
321
|
+
const usage = usageSnapshot(ctx);
|
|
322
|
+
state.lastUsage = usage;
|
|
323
|
+
const lines = [
|
|
324
|
+
`zcompact: ${state.running ? "running" : state.mode}`,
|
|
325
|
+
usageIsKnown(usage)
|
|
326
|
+
? `context: ${formatPercent(usage.percent)} ${formatTokenCount(usage.tokens)}/${formatTokenCount(usage.contextWindow)} tokens`
|
|
327
|
+
: "context: usage unavailable",
|
|
328
|
+
`trigger: ${formatPercent(state.triggerPercent, 0)}`,
|
|
329
|
+
`target after: ~${formatPercent(state.targetAfterPercent, 0)} of context; compact enough older messages to return near target`,
|
|
330
|
+
`minimum batch: oldest ~${formatPercent(state.compactOldestFraction * 100, 0)} when target needs less; cooldown: ${Math.round(state.cooldownMs / 1000)}s`,
|
|
331
|
+
`min summarizable: ${formatTokenCount(state.minSummarizableTokens)} tokens`,
|
|
332
|
+
];
|
|
333
|
+
if (state.pending) {
|
|
334
|
+
lines.push(`pending: ${state.pending.runId} ${state.pending.reason} keepRecent=${formatTokenCount(state.pending.keepRecentTokens)} summarize≈${formatTokenCount(state.pending.estimatedSummarizedTokens)}`);
|
|
335
|
+
}
|
|
336
|
+
if (state.lastRun) {
|
|
337
|
+
lines.push(`last: ${state.lastRun.status} ${state.lastRun.reason} at ${state.lastRun.completedAt ?? state.lastRun.startedAt}`);
|
|
338
|
+
lines.push(`last tokens: before=${formatTokenCount(state.lastRun.tokensBefore ?? state.lastRun.contextTokens)} keepRecent=${formatTokenCount(state.lastRun.keepRecentTokens)} summary≈${formatTokenCount(state.lastRun.estimatedSummaryTokens)} netSaved≈${formatTokenCount(state.lastRun.estimatedNetSavedTokens)}`);
|
|
339
|
+
if (state.lastRun.summaryHash) lines.push(`last summaryHash: ${state.lastRun.summaryHash.slice(0, 16)}`);
|
|
340
|
+
}
|
|
341
|
+
if (state.lastDecision) lines.push(`last decision: ${state.lastDecision.action} · ${state.lastDecision.reason}`);
|
|
342
|
+
return lines.join("\n");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function zcompactBudgetForTarget(input: { availableEntryTokens: number; contextTokens: number; contextWindow: number; targetAfterPercent: number; compactOldestFraction: number }): { keepRecentTokens: number; estimatedSummarizedTokens: number } {
|
|
346
|
+
const safeAvailable = Math.max(1, Math.floor(input.availableEntryTokens));
|
|
347
|
+
const maxKeep = Math.max(1, safeAvailable - 1);
|
|
348
|
+
const targetTotalTokens = Math.max(1, Math.floor(input.contextWindow * (input.targetAfterPercent / 100)));
|
|
349
|
+
const nonCompactableTokens = Math.max(0, Math.floor(input.contextTokens) - safeAvailable);
|
|
350
|
+
const targetKeepRecentTokens = Math.floor(targetTotalTokens - nonCompactableTokens - ZOB_COMPACTION_TARGET_TOKENS);
|
|
351
|
+
const minimumBatchKeepRecentTokens = Math.floor(safeAvailable * (1 - input.compactOldestFraction));
|
|
352
|
+
const desiredKeepRecentTokens = Math.min(targetKeepRecentTokens, minimumBatchKeepRecentTokens);
|
|
353
|
+
const keepRecentTokens = Math.max(1, Math.min(maxKeep, desiredKeepRecentTokens));
|
|
354
|
+
return { keepRecentTokens, estimatedSummarizedTokens: Math.max(0, safeAvailable - keepRecentTokens) };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function buildPendingRun(state: ZcompactRuntimeState, usage: ZcompactUsageSnapshot & { tokens: number; contextWindow: number; percent: number }, reason: ZcompactRunReason): ZcompactPendingRun {
|
|
358
|
+
const budget = zcompactBudgetForTarget({ availableEntryTokens: usage.tokens, contextTokens: usage.tokens, contextWindow: usage.contextWindow, targetAfterPercent: state.targetAfterPercent, compactOldestFraction: state.compactOldestFraction });
|
|
359
|
+
return {
|
|
360
|
+
runId: randomUUID(),
|
|
361
|
+
reason,
|
|
362
|
+
startedAt: nowIso(),
|
|
363
|
+
contextTokens: usage.tokens,
|
|
364
|
+
contextWindow: usage.contextWindow,
|
|
365
|
+
percentBefore: usage.percent,
|
|
366
|
+
keepRecentTokens: budget.keepRecentTokens,
|
|
367
|
+
estimatedSummarizedTokens: budget.estimatedSummarizedTokens,
|
|
368
|
+
triggerPercent: state.triggerPercent,
|
|
369
|
+
compactOldestFraction: state.compactOldestFraction,
|
|
370
|
+
targetAfterPercent: state.targetAfterPercent,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function zcompactCustomInstructions(pending: ZcompactPendingRun): string {
|
|
375
|
+
return [
|
|
376
|
+
ZCOMPACT_AUTO_MARKER,
|
|
377
|
+
`run_id: ${pending.runId}`,
|
|
378
|
+
`reason: ${pending.reason}`,
|
|
379
|
+
`trigger_percent: ${pending.triggerPercent}`,
|
|
380
|
+
`compact_oldest_fraction: ${pending.compactOldestFraction}`,
|
|
381
|
+
`target_after_percent: ${pending.targetAfterPercent}`,
|
|
382
|
+
`keep_recent_tokens: ${pending.keepRecentTokens}`,
|
|
383
|
+
"Summarize only the older compacted span; preserve the latest retained messages as the immediate source of truth.",
|
|
384
|
+
"Keep the summary as a continuity index with refs/hashes/statuses and do not paste raw tool outputs, prompts, diffs, secrets, or full file bodies.",
|
|
385
|
+
].join("\n");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function finishRun(pi: ExtensionAPI, state: ZcompactRuntimeState, result: CompactionResult | undefined, status: "completed" | "failed" | "cancelled", error?: string): ZcompactRunRecord | undefined {
|
|
389
|
+
const pending = state.pending;
|
|
390
|
+
if (!pending) {
|
|
391
|
+
state.running = false;
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
const estimatedSummaryTokens = result?.summary ? Math.ceil(result.summary.length / 4) : undefined;
|
|
395
|
+
const run: ZcompactRunRecord = {
|
|
396
|
+
...pending,
|
|
397
|
+
status,
|
|
398
|
+
completedAt: nowIso(),
|
|
399
|
+
firstKeptEntryId: result?.firstKeptEntryId,
|
|
400
|
+
tokensBefore: result?.tokensBefore,
|
|
401
|
+
estimatedSummaryTokens,
|
|
402
|
+
estimatedNetSavedTokens: typeof estimatedSummaryTokens === "number" ? Math.max(0, pending.estimatedSummarizedTokens - estimatedSummaryTokens) : undefined,
|
|
403
|
+
summaryHash: result?.summary ? sha256(result.summary) : undefined,
|
|
404
|
+
error,
|
|
405
|
+
};
|
|
406
|
+
state.lastRun = run;
|
|
407
|
+
state.running = false;
|
|
408
|
+
state.pending = undefined;
|
|
409
|
+
appendRun(pi, run, status === "completed" ? "complete" : status === "failed" ? "failed" : "cancelled");
|
|
410
|
+
return run;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export async function maybeTriggerZcompact(pi: ExtensionAPI, state: HarnessRuntimeState, ctx: ExtensionContext, options: { force?: boolean; bypassCooldown?: boolean; reason?: ZcompactRunReason; source?: string; render?: () => void } = {}): Promise<boolean> {
|
|
414
|
+
const zcompact = state.zcompact;
|
|
415
|
+
const usage = usageSnapshot(ctx);
|
|
416
|
+
zcompact.lastUsage = usage;
|
|
417
|
+
|
|
418
|
+
if (!options.force && zcompact.mode === "off") {
|
|
419
|
+
decision(zcompact, "off", "zcompact disabled", usage);
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (!usageIsKnown(usage)) {
|
|
423
|
+
decision(zcompact, "skipped", "context usage unavailable", usage);
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (!options.force && usage.percent < zcompact.triggerPercent) {
|
|
427
|
+
decision(zcompact, "wait", `context below threshold (${formatPercent(usage.percent)} < ${formatPercent(zcompact.triggerPercent)})`, usage);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
if (zcompact.running || zcompact.pending) {
|
|
431
|
+
decision(zcompact, "deferred", "zcompact already running", usage);
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (state.runtimeGoalContinuationCompactionFor) {
|
|
435
|
+
decision(zcompact, "deferred", "runtime goal compaction already running", usage);
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const pending = buildPendingRun(zcompact, usage, options.reason ?? (options.force ? "manual_trigger" : "auto_threshold"));
|
|
439
|
+
if (!options.force && pending.estimatedSummarizedTokens < zcompact.minSummarizableTokens) {
|
|
440
|
+
decision(zcompact, "skipped", `summarizable span too small (${formatTokenCount(pending.estimatedSummarizedTokens)} < ${formatTokenCount(zcompact.minSummarizableTokens)})`, usage);
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
const cooldownAge = msSince(zcompact.lastRun?.completedAt);
|
|
444
|
+
if (!options.force && !options.bypassCooldown && cooldownAge !== undefined && cooldownAge < zcompact.cooldownMs) {
|
|
445
|
+
decision(zcompact, "deferred", `cooldown active (${Math.ceil((zcompact.cooldownMs - cooldownAge) / 1000)}s remaining)`, usage);
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
if (!options.force && (!ctx.isIdle() || ctx.hasPendingMessages())) {
|
|
449
|
+
decision(zcompact, "deferred", "agent busy or queued messages pending", usage);
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (!options.force && zcompact.mode === "observe") {
|
|
453
|
+
const notify = shouldNotifyDecision(zcompact, "would_compact");
|
|
454
|
+
decision(zcompact, "would_compact", `would compact toward ${formatPercent(zcompact.targetAfterPercent, 0)} now; use /zcompact on to enable`, usage);
|
|
455
|
+
if (notify && ctx.hasUI) ctx.ui.notify(`zcompact observe: context ${formatPercent(usage.percent)} >= ${formatPercent(zcompact.triggerPercent)}; would summarize ≈${formatTokenCount(pending.estimatedSummarizedTokens)} and keep recent ≈${formatTokenCount(pending.keepRecentTokens)} clear.`, "info");
|
|
456
|
+
options.render?.();
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
zcompact.pending = pending;
|
|
461
|
+
zcompact.running = true;
|
|
462
|
+
const run: ZcompactRunRecord = { ...pending, status: "running" };
|
|
463
|
+
zcompact.lastRun = run;
|
|
464
|
+
appendRun(pi, run, "start");
|
|
465
|
+
decision(zcompact, "started", `${pending.reason} started`, usage);
|
|
466
|
+
if (ctx.hasUI) ctx.ui.notify(`zcompact: compacting toward ${formatPercent(pending.targetAfterPercent, 0)} context; summarizing older ≈${formatTokenCount(pending.estimatedSummarizedTokens)} and keeping recent ≈${formatTokenCount(pending.keepRecentTokens)} clear.`, "info");
|
|
467
|
+
options.render?.();
|
|
468
|
+
ctx.compact({
|
|
469
|
+
customInstructions: zcompactCustomInstructions(pending),
|
|
470
|
+
onComplete: (result) => {
|
|
471
|
+
const completed = finishRun(pi, zcompact, result, "completed");
|
|
472
|
+
if (completed && ctx.hasUI) ctx.ui.notify(`zcompact complete: net saved≈${formatTokenCount(completed.estimatedNetSavedTokens)} summaryHash=${completed.summaryHash?.slice(0, 12) ?? "n/a"}`, "info");
|
|
473
|
+
options.render?.();
|
|
474
|
+
},
|
|
475
|
+
onError: (error) => {
|
|
476
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
477
|
+
finishRun(pi, zcompact, undefined, "failed", message);
|
|
478
|
+
if (ctx.hasUI) ctx.ui.notify(`zcompact failed: ${message}`, "warning");
|
|
479
|
+
options.render?.();
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function timestampMs(value: string | undefined): number {
|
|
486
|
+
if (!value) return Date.now();
|
|
487
|
+
const parsed = Date.parse(value);
|
|
488
|
+
return Number.isFinite(parsed) ? parsed : Date.now();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function messageFromEntryForCompaction(entry: SessionEntry): CompactMessage | undefined {
|
|
492
|
+
if (entry.type === "compaction") return undefined;
|
|
493
|
+
if (entry.type === "message") return entry.message as CompactMessage;
|
|
494
|
+
if (entry.type === "custom_message") {
|
|
495
|
+
return {
|
|
496
|
+
role: "custom",
|
|
497
|
+
customType: entry.customType,
|
|
498
|
+
content: entry.content,
|
|
499
|
+
display: entry.display,
|
|
500
|
+
details: entry.details,
|
|
501
|
+
timestamp: timestampMs(entry.timestamp),
|
|
502
|
+
} as CompactMessage;
|
|
503
|
+
}
|
|
504
|
+
if (entry.type === "branch_summary") {
|
|
505
|
+
return {
|
|
506
|
+
role: "branchSummary",
|
|
507
|
+
summary: entry.summary,
|
|
508
|
+
fromId: entry.fromId,
|
|
509
|
+
timestamp: timestampMs(entry.timestamp),
|
|
510
|
+
} as CompactMessage;
|
|
511
|
+
}
|
|
512
|
+
return undefined;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function latestCompactionIndex(entries: SessionEntry[]): number {
|
|
516
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
517
|
+
if (entries[index]?.type === "compaction") return index;
|
|
518
|
+
}
|
|
519
|
+
return -1;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function estimateEntryRangeTokens(entries: SessionEntry[], start: number, end: number): number {
|
|
523
|
+
let total = 0;
|
|
524
|
+
for (let index = start; index < end; index += 1) {
|
|
525
|
+
const message = messageFromEntryForCompaction(entries[index]);
|
|
526
|
+
if (message) total += estimateTokens(message);
|
|
527
|
+
}
|
|
528
|
+
return total;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function applyDynamicZcompactBudget(state: HarnessRuntimeState, availableEntryTokens: number): void {
|
|
532
|
+
const pending = state.zcompact.pending;
|
|
533
|
+
if (!pending) return;
|
|
534
|
+
const budget = zcompactBudgetForTarget({ availableEntryTokens, contextTokens: pending.contextTokens, contextWindow: pending.contextWindow, targetAfterPercent: pending.targetAfterPercent, compactOldestFraction: pending.compactOldestFraction });
|
|
535
|
+
pending.keepRecentTokens = budget.keepRecentTokens;
|
|
536
|
+
pending.estimatedSummarizedTokens = budget.estimatedSummarizedTokens;
|
|
537
|
+
const running = state.zcompact.lastRun;
|
|
538
|
+
if (running?.runId === pending.runId && running.status === "running") {
|
|
539
|
+
running.keepRecentTokens = pending.keepRecentTokens;
|
|
540
|
+
running.estimatedSummarizedTokens = pending.estimatedSummarizedTokens;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function cloneFileOps(fileOps: CompactPreparation["fileOps"]): CompactPreparation["fileOps"] {
|
|
545
|
+
return {
|
|
546
|
+
read: new Set(fileOps.read),
|
|
547
|
+
written: new Set(fileOps.written),
|
|
548
|
+
edited: new Set(fileOps.edited),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
export function buildZcompactPreparation(state: HarnessRuntimeState, base: CompactPreparation, branchEntries: SessionEntry[]): CompactPreparation {
|
|
553
|
+
const pending = state.zcompact.pending;
|
|
554
|
+
if (!pending) return base;
|
|
555
|
+
const prevCompactionIndex = latestCompactionIndex(branchEntries);
|
|
556
|
+
let previousSummary: string | undefined;
|
|
557
|
+
let boundaryStart = 0;
|
|
558
|
+
if (prevCompactionIndex >= 0) {
|
|
559
|
+
const previous = branchEntries[prevCompactionIndex];
|
|
560
|
+
if (previous?.type === "compaction") {
|
|
561
|
+
previousSummary = previous.summary;
|
|
562
|
+
const firstKeptEntryIndex = branchEntries.findIndex((entry) => entry.id === previous.firstKeptEntryId);
|
|
563
|
+
boundaryStart = firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : prevCompactionIndex + 1;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
const boundaryEnd = branchEntries.length;
|
|
567
|
+
const availableEntryTokens = estimateEntryRangeTokens(branchEntries, boundaryStart, boundaryEnd);
|
|
568
|
+
applyDynamicZcompactBudget(state, availableEntryTokens);
|
|
569
|
+
if (pending.estimatedSummarizedTokens < state.zcompact.minSummarizableTokens) throw new Error(`zcompact compactable span too small (${formatTokenCount(pending.estimatedSummarizedTokens)} < ${formatTokenCount(state.zcompact.minSummarizableTokens)})`);
|
|
570
|
+
const cutPoint = findCutPoint(branchEntries, boundaryStart, boundaryEnd, pending.keepRecentTokens);
|
|
571
|
+
const firstKeptEntry = branchEntries[cutPoint.firstKeptEntryIndex];
|
|
572
|
+
if (!firstKeptEntry?.id) throw new Error("zcompact could not find a dynamic kept-entry boundary");
|
|
573
|
+
const historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;
|
|
574
|
+
if (historyEnd < boundaryStart) throw new Error("zcompact dynamic cut point is before the compaction boundary");
|
|
575
|
+
const messagesToSummarize: CompactPreparation["messagesToSummarize"] = [];
|
|
576
|
+
for (let index = boundaryStart; index < historyEnd; index += 1) {
|
|
577
|
+
const message = messageFromEntryForCompaction(branchEntries[index]);
|
|
578
|
+
if (message) messagesToSummarize.push(message);
|
|
579
|
+
}
|
|
580
|
+
const turnPrefixMessages: CompactPreparation["turnPrefixMessages"] = [];
|
|
581
|
+
if (cutPoint.isSplitTurn) {
|
|
582
|
+
for (let index = cutPoint.turnStartIndex; index < cutPoint.firstKeptEntryIndex; index += 1) {
|
|
583
|
+
const message = messageFromEntryForCompaction(branchEntries[index]);
|
|
584
|
+
if (message) turnPrefixMessages.push(message);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (messagesToSummarize.length === 0 && turnPrefixMessages.length === 0) throw new Error("zcompact dynamic summarization span is empty");
|
|
588
|
+
return {
|
|
589
|
+
...base,
|
|
590
|
+
firstKeptEntryId: firstKeptEntry.id,
|
|
591
|
+
messagesToSummarize,
|
|
592
|
+
turnPrefixMessages,
|
|
593
|
+
isSplitTurn: cutPoint.isSplitTurn,
|
|
594
|
+
previousSummary,
|
|
595
|
+
fileOps: cloneFileOps(base.fileOps),
|
|
596
|
+
settings: { ...base.settings, keepRecentTokens: pending.keepRecentTokens },
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export function cancelZcompactPending(pi: ExtensionAPI, state: ZcompactRuntimeState, error: string): ZcompactRunRecord | undefined {
|
|
601
|
+
return finishRun(pi, state, undefined, "failed", error);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export async function runZcompactCompactionHook(state: HarnessRuntimeState, input: { preparation: CompactPreparation; branchEntries: SessionEntry[]; ctx: ExtensionContext; apiKey?: string; headers?: Record<string, string>; signal: AbortSignal }): Promise<CompactionResult<ZobCompactionDetails>> {
|
|
605
|
+
const pending = state.zcompact.pending;
|
|
606
|
+
const preparation = buildZcompactPreparation(state, input.preparation, input.branchEntries);
|
|
607
|
+
const customInstructions = buildZobCompactionInstructions(state, {
|
|
608
|
+
reason: pending?.reason ?? "auto_threshold",
|
|
609
|
+
customInstructions: pending ? zcompactCustomInstructions(pending) : ZCOMPACT_AUTO_MARKER,
|
|
610
|
+
fileOps: preparation.fileOps,
|
|
611
|
+
});
|
|
612
|
+
if (!input.ctx.model) throw new Error("model unavailable");
|
|
613
|
+
const result = await compact(preparation, input.ctx.model, input.apiKey, input.headers, customInstructions, input.signal);
|
|
614
|
+
return withZobCompactionDetails(state, result, { fileOps: preparation.fileOps });
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
export async function handleZcompactCommand(pi: ExtensionAPI, state: HarnessRuntimeState, args: string, ctx: ExtensionContext, render: () => void): Promise<void> {
|
|
618
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
619
|
+
const requested = (parts[0] ?? "status").toLowerCase();
|
|
620
|
+
const zcompact = state.zcompact;
|
|
621
|
+
if (requested === "help" || requested === "--help" || requested === "-h") {
|
|
622
|
+
ctx.ui.setEditorText(zcompactHelpText());
|
|
623
|
+
ctx.ui.notify("ZOB zcompact help inserted.", "info");
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
if (requested === "status" || requested.length === 0) {
|
|
627
|
+
render();
|
|
628
|
+
ctx.ui.notify(formatZcompactStatus(zcompact, ctx), "info");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (requested === "on" || requested === "auto") {
|
|
632
|
+
zcompact.mode = "auto";
|
|
633
|
+
appendConfig(pi, zcompact, "command_on");
|
|
634
|
+
render();
|
|
635
|
+
ctx.ui.notify(`zcompact auto enabled: trigger ${formatPercent(zcompact.triggerPercent, 0)} → target ${formatPercent(zcompact.targetAfterPercent, 0)}`, "info");
|
|
636
|
+
await maybeTriggerZcompact(pi, state, ctx, { source: "command_on", bypassCooldown: true, render });
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (requested === "off" || requested === "disable" || requested === "disabled") {
|
|
640
|
+
zcompact.mode = "off";
|
|
641
|
+
appendConfig(pi, zcompact, "command_off");
|
|
642
|
+
render();
|
|
643
|
+
ctx.ui.notify("zcompact disabled", "warning");
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (requested === "observe" || requested === "dry-run" || requested === "dryrun") {
|
|
647
|
+
zcompact.mode = "observe";
|
|
648
|
+
appendConfig(pi, zcompact, "command_observe");
|
|
649
|
+
render();
|
|
650
|
+
ctx.ui.notify(`zcompact observe enabled: will report at ${formatPercent(zcompact.triggerPercent, 0)} without compacting`, "info");
|
|
651
|
+
await maybeTriggerZcompact(pi, state, ctx, { source: "command_observe", render });
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (requested === "threshold") {
|
|
655
|
+
const value = parseMaybePercent(parts[1]);
|
|
656
|
+
if (value === undefined) {
|
|
657
|
+
ctx.ui.notify("Use /zcompact threshold 60", "warning");
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
zcompact.triggerPercent = safePercent(value, zcompact.triggerPercent);
|
|
661
|
+
appendConfig(pi, zcompact, "command_threshold");
|
|
662
|
+
render();
|
|
663
|
+
ctx.ui.notify(`zcompact trigger set to ${formatPercent(zcompact.triggerPercent, 0)}`, "info");
|
|
664
|
+
if (zcompact.mode !== "off") await maybeTriggerZcompact(pi, state, ctx, { source: "command_threshold", bypassCooldown: true, render });
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (requested === "target" || requested === "target-after" || requested === "target_after") {
|
|
668
|
+
const value = parseMaybePercent(parts[1]);
|
|
669
|
+
if (value === undefined) {
|
|
670
|
+
ctx.ui.notify("Use /zcompact target 25", "warning");
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
zcompact.targetAfterPercent = safePercent(value, zcompact.targetAfterPercent);
|
|
674
|
+
appendConfig(pi, zcompact, "command_target");
|
|
675
|
+
render();
|
|
676
|
+
ctx.ui.notify(`zcompact target after set to ${formatPercent(zcompact.targetAfterPercent, 0)}`, "info");
|
|
677
|
+
if (zcompact.mode !== "off") await maybeTriggerZcompact(pi, state, ctx, { source: "command_target", bypassCooldown: true, render });
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (requested === "fraction" || requested === "oldest" || requested === "compact") {
|
|
681
|
+
const value = parseMaybePercentOrFraction(parts[1]);
|
|
682
|
+
if (value === undefined) {
|
|
683
|
+
ctx.ui.notify("Use /zcompact fraction 25", "warning");
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
zcompact.compactOldestFraction = safeFraction(value, zcompact.compactOldestFraction);
|
|
687
|
+
appendConfig(pi, zcompact, "command_fraction");
|
|
688
|
+
render();
|
|
689
|
+
ctx.ui.notify(`zcompact minimum batch set to oldest ~${formatPercent(zcompact.compactOldestFraction * 100, 0)}; target remains ${formatPercent(zcompact.targetAfterPercent, 0)}`, "info");
|
|
690
|
+
if (zcompact.mode !== "off") await maybeTriggerZcompact(pi, state, ctx, { source: "command_fraction", bypassCooldown: true, render });
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (requested === "trigger" || requested === "now") {
|
|
694
|
+
const started = await maybeTriggerZcompact(pi, state, ctx, { force: true, reason: "manual_trigger", source: "command", render });
|
|
695
|
+
if (!started) ctx.ui.notify(`zcompact trigger did not start: ${zcompact.lastDecision?.reason ?? "see status"}`, "warning");
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
ctx.ui.notify("Unknown /zcompact command. Use /zcompact help|status|observe|on|off|threshold|target|fraction|trigger.", "warning");
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
export function zcompactConfigSummary(state: ZcompactRuntimeState): Record<string, unknown> {
|
|
702
|
+
return {
|
|
703
|
+
mode: state.mode,
|
|
704
|
+
triggerPercent: state.triggerPercent,
|
|
705
|
+
compactOldestFraction: state.compactOldestFraction,
|
|
706
|
+
targetAfterPercent: state.targetAfterPercent,
|
|
707
|
+
minSummarizableTokens: state.minSummarizableTokens,
|
|
708
|
+
cooldownMs: state.cooldownMs,
|
|
709
|
+
running: state.running,
|
|
710
|
+
hasPending: Boolean(state.pending),
|
|
711
|
+
lastRunStatus: state.lastRun?.status,
|
|
712
|
+
lastDecisionAction: state.lastDecision?.action,
|
|
713
|
+
bodyStored: false,
|
|
714
|
+
};
|
|
715
|
+
}
|