peaks-loop 4.0.0-beta.9 → 4.0.3
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/CHANGELOG.md +572 -234
- package/README-en.md +67 -30
- package/README.md +67 -30
- package/agents/karpathy-reviewer.md +33 -0
- package/bin/peaks.js +0 -0
- package/dist/cli/cli-helpers.d.ts +31 -6
- package/dist/cli/cli-helpers.js +48 -25
- package/dist/cli/commands/_register.d.ts +3 -0
- package/dist/cli/commands/_register.js +139 -0
- package/dist/cli/commands/_super.d.ts +10 -0
- package/dist/cli/commands/_super.js +97 -0
- package/dist/cli/commands/adapter-commands-s2a.js +1 -1
- package/dist/cli/commands/asset-commands.js +33 -16
- package/dist/cli/commands/audit-commands.js +2 -2
- package/dist/cli/commands/autonomous-swarm-commands.d.ts +12 -0
- package/dist/cli/commands/autonomous-swarm-commands.js +120 -0
- package/dist/cli/commands/bee-commands.js +1 -1
- package/dist/cli/commands/capability-commands.js +1 -1
- package/dist/cli/commands/capability-worker-config-sc-commands.js +0 -2
- package/dist/cli/commands/changeset-commands.d.ts +13 -0
- package/dist/cli/commands/changeset-commands.js +46 -0
- package/dist/cli/commands/code-commands.d.ts +11 -1
- package/dist/cli/commands/code-commands.js +19 -699
- package/dist/cli/commands/code-job-shape-commands.d.ts +9 -0
- package/dist/cli/commands/code-job-shape-commands.js +164 -0
- package/dist/cli/commands/code-mode-gate-commands.d.ts +9 -0
- package/dist/cli/commands/code-mode-gate-commands.js +223 -0
- package/dist/cli/commands/code-review-commands.js +2 -2
- package/dist/cli/commands/code-run-command.d.ts +12 -0
- package/dist/cli/commands/code-run-command.js +68 -0
- package/dist/cli/commands/code-runtime-commands.d.ts +11 -0
- package/dist/cli/commands/code-runtime-commands.js +391 -0
- package/dist/cli/commands/codegraph-commands.js +1 -1
- package/dist/cli/commands/compact-command.js +53 -1
- package/dist/cli/commands/complexity-commands.js +1 -1
- package/dist/cli/commands/config-commands.js +4 -75
- package/dist/cli/commands/container-commands.d.ts +28 -0
- package/dist/cli/commands/container-commands.js +221 -0
- package/dist/cli/commands/context-commands.js +3 -2
- package/dist/cli/commands/core/artifacts-command.js +1 -1
- package/dist/cli/commands/core/binding-commands.js +1 -1
- package/dist/cli/commands/core/doctor-command.js +63 -3
- package/dist/cli/commands/core/memory-command.js +1 -1
- package/dist/cli/commands/core/profile-command.js +1 -1
- package/dist/cli/commands/core/proxy-command.js +1 -1
- package/dist/cli/commands/core/session-command.js +9 -7
- package/dist/cli/commands/core/skill-command.js +7 -4
- package/dist/cli/commands/core/standards-command.js +1 -1
- package/dist/cli/commands/cron-commands.d.ts +57 -0
- package/dist/cli/commands/cron-commands.js +257 -0
- package/dist/cli/commands/cron-scheduler-commands.d.ts +47 -0
- package/dist/cli/commands/cron-scheduler-commands.js +284 -0
- package/dist/cli/commands/dashboard-commands.d.ts +4 -0
- package/dist/cli/commands/dashboard-commands.js +10 -0
- package/dist/cli/commands/dashboard-long-run.d.ts +25 -0
- package/dist/cli/commands/dashboard-long-run.js +122 -0
- package/dist/cli/commands/dashboard-summary.d.ts +12 -0
- package/dist/cli/commands/dashboard-summary.js +58 -0
- package/dist/cli/commands/dispatch-commands.d.ts +0 -7
- package/dist/cli/commands/dispatch-commands.js +372 -8
- package/dist/cli/commands/dispatch-from-dag.js +4 -1
- package/dist/cli/commands/doc-commands.js +1 -1
- package/dist/cli/commands/ecc-commands.d.ts +30 -0
- package/dist/cli/commands/ecc-commands.js +119 -0
- package/dist/cli/commands/evolution-commands.js +1 -1
- package/dist/cli/commands/feedback-commands.js +1 -1
- package/dist/cli/commands/final-review-commands.js +1 -1
- package/dist/cli/commands/fixture-commands.js +1 -1
- package/dist/cli/commands/fork-commands.js +1 -1
- package/dist/cli/commands/gate-commands.js +128 -6
- package/dist/cli/commands/governance-classify-contract-commands.d.ts +21 -0
- package/dist/cli/commands/governance-classify-contract-commands.js +273 -0
- package/dist/cli/commands/heartbeat-commands.js +76 -5
- package/dist/cli/commands/heartbeat-watch-command.d.ts +31 -0
- package/dist/cli/commands/heartbeat-watch-command.js +146 -0
- package/dist/cli/commands/hook-handle.js +1 -1
- package/dist/cli/commands/hooks-commands.js +126 -10
- package/dist/cli/commands/ide-commands.js +1 -1
- package/dist/cli/commands/impact-commands.js +1 -1
- package/dist/cli/commands/job-commands.js +34 -1
- package/dist/cli/commands/lease-metrics-commands.d.ts +67 -0
- package/dist/cli/commands/lease-metrics-commands.js +231 -0
- package/dist/cli/commands/lease-stats-commands.d.ts +65 -0
- package/dist/cli/commands/lease-stats-commands.js +107 -0
- package/dist/cli/commands/legacy-commands.js +1 -1
- package/dist/cli/commands/log-commands.js +1 -1
- package/dist/cli/commands/loop-commands.js +1 -1
- package/dist/cli/commands/loop-eval-commands.js +1 -1
- package/dist/cli/commands/memory-commands.js +1 -1
- package/dist/cli/commands/migrate-1-4-1-command.js +1 -1
- package/dist/cli/commands/migrate-v2-10-to-v2-11-command.js +1 -1
- package/dist/cli/commands/mut-commands.d.ts +1 -1
- package/dist/cli/commands/mut-commands.js +1 -5
- package/dist/cli/commands/observability-commands.js +1 -1
- package/dist/cli/commands/openspec-commands.js +65 -4
- package/dist/cli/commands/perf-audit-commands.js +3 -3
- package/dist/cli/commands/perf-commands.js +1 -1
- package/dist/cli/commands/polyrepo-commands.js +1 -1
- package/dist/cli/commands/prd-blocks-commands.js +1 -1
- package/dist/cli/commands/prd-commands.js +4 -2
- package/dist/cli/commands/preferences-commands.js +23 -3
- package/dist/cli/commands/project-commands.js +1 -1
- package/dist/cli/commands/qa-business-review-commands.js +1 -1
- package/dist/cli/commands/qa-commands.d.ts +1 -1
- package/dist/cli/commands/qa-commands.js +39 -3
- package/dist/cli/commands/release-commands.d.ts +15 -0
- package/dist/cli/commands/release-commands.js +113 -21
- package/dist/cli/commands/request-commands.js +1 -1
- package/dist/cli/commands/retrospective-commands.js +1 -1
- package/dist/cli/commands/reviewer-commands.js +1 -1
- package/dist/cli/commands/role-commands.js +1 -1
- package/dist/cli/commands/runtime-commands-helpers.d.ts +7 -0
- package/dist/cli/commands/runtime-commands-helpers.js +24 -0
- package/dist/cli/commands/runtime-commands.js +1 -2
- package/dist/cli/commands/sc-commands.js +4 -2
- package/dist/cli/commands/scan-commands.js +1 -1
- package/dist/cli/commands/security-audit-commands.js +3 -3
- package/dist/cli/commands/sediment-commands.js +10 -1
- package/dist/cli/commands/session-24h-mode.d.ts +26 -0
- package/dist/cli/commands/session-24h-mode.js +196 -0
- package/dist/cli/commands/share-commands.d.ts +19 -0
- package/dist/cli/commands/share-commands.js +121 -2
- package/dist/cli/commands/skill-conformance-commands.js +1 -1
- package/dist/cli/commands/skill-loop-engineering-readiness-commands.js +1 -1
- package/dist/cli/commands/skill-search-commands.js +4 -1
- package/dist/cli/commands/slice-commands.js +1 -1
- package/dist/cli/commands/slice-integrate-commands.js +1 -1
- package/dist/cli/commands/slice-review-commands.js +1 -1
- package/dist/cli/commands/smoke-commands.js +1 -1
- package/dist/cli/commands/sop-commands.js +1 -1
- package/dist/cli/commands/spill-demo-command.d.ts +7 -0
- package/dist/cli/commands/spill-demo-command.js +29 -0
- package/dist/cli/commands/statusline-commands.d.ts +12 -0
- package/dist/cli/commands/statusline-commands.js +79 -17
- package/dist/cli/commands/sub-agent-commands.js +2 -1
- package/dist/cli/commands/sub-agent-shared.d.ts +10 -0
- package/dist/cli/commands/sub-agent-shared.js +24 -1
- package/dist/cli/commands/swarm-commands.d.ts +13 -0
- package/dist/cli/commands/swarm-commands.js +77 -0
- package/dist/cli/commands/tech-commands.d.ts +64 -0
- package/dist/cli/commands/tech-commands.js +195 -0
- package/dist/cli/commands/understand-commands.js +1 -1
- package/dist/cli/commands/upgrade-commands.d.ts +2 -0
- package/dist/cli/commands/upgrade-commands.js +40 -5
- package/dist/cli/commands/user-touchpoint-commands.js +1 -1
- package/dist/cli/commands/verdict-aggregate-command.js +1 -1
- package/dist/cli/commands/vm-commands.d.ts +31 -0
- package/dist/cli/commands/vm-commands.js +274 -0
- package/dist/cli/commands/workflow-commands.js +24 -1
- package/dist/cli/commands/workflow-plan-commands.js +1 -1
- package/dist/cli/commands/workspace/init-command.js +1 -1
- package/dist/cli/commands/workspace/migrate-command.js +1 -1
- package/dist/cli/commands/workspace/reconcile-command.js +1 -1
- package/dist/cli/commands/worktree-auth-commands.d.ts +29 -0
- package/dist/cli/commands/worktree-auth-commands.js +652 -0
- package/dist/cli/index.js +58 -13
- package/dist/cli/program.d.ts +2 -2
- package/dist/cli/program.js +86 -281
- package/dist/services/24h-mode/decider.d.ts +103 -0
- package/dist/services/24h-mode/decider.js +144 -0
- package/dist/services/24h-mode/index.d.ts +12 -0
- package/dist/services/24h-mode/index.js +12 -0
- package/dist/services/24h-mode/state.d.ts +48 -0
- package/dist/services/24h-mode/state.js +51 -0
- package/dist/services/24h-mode/store.d.ts +27 -0
- package/dist/services/24h-mode/store.js +119 -0
- package/dist/services/artifacts/artifact-prerequisites.js +1 -1
- package/dist/services/artifacts/request-artifact-service.js +1 -1
- package/dist/services/artifacts/workspace-service.js +1 -1
- package/dist/services/audit/enforcers/lint-bee-runtime-contract.d.ts +25 -0
- package/dist/services/audit/enforcers/lint-bee-runtime-contract.js +91 -0
- package/dist/services/audit/enforcers/lint-peaks-code-runtime.d.ts +16 -0
- package/dist/services/audit/enforcers/lint-peaks-code-runtime.js +31 -0
- package/dist/services/audit/enforcers/lint-peaks-skill-runtime.d.ts +23 -0
- package/dist/services/audit/enforcers/lint-peaks-skill-runtime.js +59 -0
- package/dist/services/audit/enforcers/lint-peaks-ui-sc-txt-runtime.d.ts +28 -0
- package/dist/services/audit/enforcers/lint-peaks-ui-sc-txt-runtime.js +86 -0
- package/dist/services/audit/enforcers/lint-prd-artifact-handoff.d.ts +16 -0
- package/dist/services/audit/enforcers/lint-prd-artifact-handoff.js +41 -0
- package/dist/services/audit/enforcers/lint-prd-source-snapshot.d.ts +27 -0
- package/dist/services/audit/enforcers/lint-prd-source-snapshot.js +47 -0
- package/dist/services/audit/enforcers/lint-qa-gateguard-and-runtime.d.ts +19 -0
- package/dist/services/audit/enforcers/lint-qa-gateguard-and-runtime.js +47 -0
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.d.ts +18 -0
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.js +70 -0
- package/dist/services/audit/enforcers/lint-skill-presence-mandatory.d.ts +25 -0
- package/dist/services/audit/enforcers/lint-skill-presence-mandatory.js +53 -0
- package/dist/services/audit/red-line-catalog-p2-a.d.ts +0 -6
- package/dist/services/audit/red-line-catalog-p2-a.js +230 -1
- package/dist/services/audit/static-service.d.ts +32 -25
- package/dist/services/audit/static-service.js +30 -109
- package/dist/services/audit-independent/index.d.ts +2 -0
- package/dist/services/audit-independent/index.js +2 -0
- package/dist/services/autonomous-swarm/autonomous-swarm-service.d.ts +127 -0
- package/dist/services/autonomous-swarm/autonomous-swarm-service.js +446 -0
- package/dist/services/changeset/changeset-check-service.d.ts +22 -0
- package/dist/services/changeset/changeset-check-service.js +47 -0
- package/dist/services/code/auto-compact-modes.d.ts +30 -0
- package/dist/services/code/auto-compact-modes.js +38 -0
- package/dist/services/code/auto-compact-orchestrator.d.ts +43 -5
- package/dist/services/code/auto-compact-orchestrator.js +101 -21
- package/dist/services/code/dag-orchestrator.d.ts +30 -1
- package/dist/services/code/dag-orchestrator.js +106 -1
- package/dist/services/code/status-line-renderer.d.ts +2 -0
- package/dist/services/code/status-line-renderer.js +21 -3
- package/dist/services/code-review/ocr-service.d.ts +1 -1
- package/dist/services/code-review/ocr-service.js +6 -3
- package/dist/services/compact-history/compact-history-service.d.ts +41 -0
- package/dist/services/compact-history/compact-history-service.js +62 -0
- package/dist/services/compact-statusline/compact-statusline-service.d.ts +16 -0
- package/dist/services/compact-statusline/compact-statusline-service.js +83 -0
- package/dist/services/config/config-service.d.ts +1 -12
- package/dist/services/config/config-service.js +3 -72
- package/dist/services/config/config-types.d.ts +2 -4
- package/dist/services/config/config-types.js +1 -1
- package/dist/services/container/container-lease.d.ts +67 -0
- package/dist/services/container/container-lease.js +135 -0
- package/dist/services/context/auto-compact-dispatcher.d.ts +40 -5
- package/dist/services/context/auto-compact-dispatcher.js +32 -102
- package/dist/services/context/auto-compact-reader.js +1 -1
- package/dist/services/context/auto-compact-types.d.ts +27 -2
- package/dist/services/context/auto-compact-types.js +8 -1
- package/dist/services/context/build-dispatch-system-prompt.d.ts +75 -0
- package/dist/services/context/build-dispatch-system-prompt.js +117 -0
- package/dist/services/context/collector.d.ts +2 -2
- package/dist/services/context/context-builder.d.ts +4 -4
- package/dist/services/context/context-schema.d.ts +48 -48
- package/dist/services/context/ide-detect.d.ts +4 -0
- package/dist/services/context/ide-detect.js +24 -0
- package/dist/services/context/main-session-monitor.d.ts +1 -4
- package/dist/services/context/main-session-monitor.js +1 -24
- package/dist/services/context/memory-index-reader.d.ts +8 -0
- package/dist/services/context/memory-index-reader.js +57 -0
- package/dist/services/context/memory-lru-cache.d.ts +12 -0
- package/dist/services/context/memory-lru-cache.js +60 -0
- package/dist/services/context/memory-preflight-config.d.ts +19 -0
- package/dist/services/context/memory-preflight-config.js +25 -0
- package/dist/services/context/memory-preflight-service.d.ts +19 -0
- package/dist/services/context/memory-preflight-service.js +120 -0
- package/dist/services/context/spillover-store.d.ts +23 -0
- package/dist/services/context/spillover-store.js +155 -0
- package/dist/services/context/spillover-types.d.ts +18 -0
- package/dist/services/context/spillover-types.js +1 -0
- package/dist/services/crystallization/crystallization-service.d.ts +22 -5
- package/dist/services/crystallization/crystallization-service.js +8 -14
- package/dist/services/crystallization/crystallization-types.d.ts +6 -6
- package/dist/services/crystallization/evidence-brief-builder.d.ts +1 -1
- package/dist/services/crystallization/index.d.ts +13 -0
- package/dist/services/crystallization/index.js +13 -0
- package/dist/services/dashboard/project-dashboard-service.js +2 -2
- package/dist/services/dispatch/await-batch.d.ts +70 -0
- package/dist/services/dispatch/await-batch.js +272 -0
- package/dist/services/dispatch/batch-counter.js +1 -1
- package/dist/services/dispatch/dispatch-record-writer.d.ts +126 -4
- package/dist/services/dispatch/dispatch-record-writer.js +239 -9
- package/dist/services/dispatch/slice-dag.d.ts +46 -0
- package/dist/services/dispatch/slice-dag.js +6 -0
- package/dist/services/dispatch/stage-enum.d.ts +27 -0
- package/dist/services/dispatch/stage-enum.js +48 -0
- package/dist/services/dispatch/startup-timeout.d.ts +86 -0
- package/dist/services/dispatch/startup-timeout.js +97 -0
- package/dist/services/dispatch/sub-agent-dispatcher.js +40 -89
- package/dist/services/dispatch/test-tool-detection.d.ts +25 -1
- package/dist/services/dispatch/test-tool-detection.js +80 -0
- package/dist/services/doctor/doctor-service/checks/check-id-schema.d.ts +18 -0
- package/dist/services/doctor/doctor-service/checks/check-id-schema.js +64 -0
- package/dist/services/doctor/doctor-service/checks/codegraph-capability.d.ts +14 -0
- package/dist/services/doctor/doctor-service/checks/codegraph-capability.js +69 -0
- package/dist/services/doctor/doctor-service/checks/dist-source-version.d.ts +32 -0
- package/dist/services/doctor/doctor-service/checks/dist-source-version.js +110 -0
- package/dist/services/doctor/doctor-service/checks/gateguard-conflict.d.ts +24 -0
- package/dist/services/doctor/doctor-service/checks/gateguard-conflict.js +164 -0
- package/dist/services/doctor/doctor-service/checks/l3-memory-health.d.ts +16 -0
- package/dist/services/doctor/doctor-service/checks/l3-memory-health.js +57 -0
- package/dist/services/doctor/doctor-service/checks/l3-orphan-sessions.d.ts +19 -0
- package/dist/services/doctor/doctor-service/checks/l3-orphan-sessions.js +66 -0
- package/dist/services/doctor/doctor-service/checks/schema-validity.d.ts +10 -0
- package/dist/services/doctor/doctor-service/checks/schema-validity.js +33 -0
- package/dist/services/doctor/doctor-service/checks/skill-apply-note.d.ts +20 -0
- package/dist/services/doctor/doctor-service/checks/skill-apply-note.js +85 -0
- package/dist/services/doctor/doctor-service/checks/skill-existence.d.ts +13 -0
- package/dist/services/doctor/doctor-service/checks/skill-existence.js +30 -0
- package/dist/services/doctor/doctor-service/checks/skill-name-match.d.ts +10 -0
- package/dist/services/doctor/doctor-service/checks/skill-name-match.js +25 -0
- package/dist/services/doctor/doctor-service/checks/skill-parse.d.ts +10 -0
- package/dist/services/doctor/doctor-service/checks/skill-parse.js +19 -0
- package/dist/services/doctor/doctor-service/checks/skill-presence.d.ts +21 -0
- package/dist/services/doctor/doctor-service/checks/skill-presence.js +75 -0
- package/dist/services/doctor/doctor-service/checks/skill-runbook.d.ts +14 -0
- package/dist/services/doctor/doctor-service/checks/skill-runbook.js +47 -0
- package/dist/services/doctor/doctor-service/checks/statusline-install.d.ts +14 -0
- package/dist/services/doctor/doctor-service/checks/statusline-install.js +32 -0
- package/dist/services/doctor/doctor-service/checks/statusline-runtime.d.ts +13 -0
- package/dist/services/doctor/doctor-service/checks/statusline-runtime.js +30 -0
- package/dist/services/doctor/doctor-service/checks/user-config.d.ts +11 -0
- package/dist/services/doctor/doctor-service/checks/user-config.js +27 -0
- package/dist/services/doctor/doctor-service/checks/workspace-init.d.ts +16 -0
- package/dist/services/doctor/doctor-service/checks/workspace-init.js +34 -0
- package/dist/services/doctor/doctor-service/checks/workspace-layout.d.ts +33 -0
- package/dist/services/doctor/doctor-service/checks/workspace-layout.js +180 -0
- package/dist/services/doctor/doctor-service/index.d.ts +48 -0
- package/dist/services/doctor/doctor-service/index.js +254 -0
- package/dist/services/doctor/doctor-service/plugin-registry.d.ts +41 -0
- package/dist/services/doctor/doctor-service/plugin-registry.js +77 -0
- package/dist/services/doctor/doctor-service/report/final-summary.d.ts +20 -0
- package/dist/services/doctor/doctor-service/report/final-summary.js +29 -0
- package/dist/services/doctor/doctor-service/types.d.ts +245 -0
- package/dist/services/doctor/doctor-service/types.js +15 -0
- package/dist/services/doctor/doctor-service.d.ts +15 -146
- package/dist/services/doctor/doctor-service.js +22 -926
- package/dist/services/doctor/index.d.ts +22 -0
- package/dist/services/doctor/index.js +22 -0
- package/dist/services/env/shell-probe.d.ts +71 -0
- package/dist/services/env/shell-probe.js +161 -0
- package/dist/services/evolution/evolution-types.d.ts +39 -39
- package/dist/services/final-review/final-review-service.d.ts +11 -1
- package/dist/services/final-review/index.d.ts +2 -0
- package/dist/services/final-review/index.js +1 -0
- package/dist/services/hooks/auto-compact-hook-install.d.ts +4 -5
- package/dist/services/hooks/auto-compact-hook-install.js +4 -5
- package/dist/services/hooks/worktree-authorization-gate.d.ts +205 -0
- package/dist/services/hooks/worktree-authorization-gate.js +492 -0
- package/dist/services/ide/adapters/claude-code-adapter.js +2 -2
- package/dist/services/ide/adapters/qoder-adapter.d.ts +25 -0
- package/dist/services/ide/adapters/qoder-adapter.js +57 -0
- package/dist/services/ide/adapters/tongyi-lingma-adapter.d.ts +16 -0
- package/dist/services/ide/adapters/tongyi-lingma-adapter.js +45 -0
- package/dist/services/ide/ide-registry.js +6 -0
- package/dist/services/ide/ide-types.d.ts +1 -1
- package/dist/services/job/job-types.d.ts +56 -56
- package/dist/services/job-snapshot/index.d.ts +8 -0
- package/dist/services/job-snapshot/index.js +7 -0
- package/dist/services/{job/job-resource-snapshot.d.ts → job-snapshot/snapshot.d.ts} +1 -1
- package/dist/services/job-snapshot/types.d.ts +7 -0
- package/dist/services/job-snapshot/types.js +1 -0
- package/dist/services/karpathy-cost/karpathy-cost-check-service.d.ts +67 -0
- package/dist/services/karpathy-cost/karpathy-cost-check-service.js +108 -0
- package/dist/services/log/retention.d.ts +16 -0
- package/dist/services/log/retention.js +17 -0
- package/dist/services/loop/loop-bee-relation-types.d.ts +6 -6
- package/dist/services/loop/loop-release-types.d.ts +24 -24
- package/dist/services/loop/monotonic-runner.d.ts +17 -11
- package/dist/services/loop/monotonic-runner.js +118 -79
- package/dist/services/memory/project-memory-service/index/kind-dispatch.d.ts +8 -0
- package/dist/services/memory/project-memory-service/index/kind-dispatch.js +253 -0
- package/dist/services/memory/project-memory-service/index/ranking.d.ts +6 -0
- package/dist/services/memory/project-memory-service/index/ranking.js +171 -0
- package/dist/services/memory/project-memory-service/index/search.d.ts +34 -0
- package/dist/services/memory/project-memory-service/index/search.js +194 -0
- package/dist/services/memory/project-memory-service/index.d.ts +9 -0
- package/dist/services/memory/project-memory-service/index.js +24 -0
- package/dist/services/memory/project-memory-service/parsers/frontmatter.d.ts +9 -0
- package/dist/services/memory/project-memory-service/parsers/frontmatter.js +106 -0
- package/dist/services/memory/project-memory-service/parsers/markdown-pure.d.ts +7 -0
- package/dist/services/memory/project-memory-service/parsers/markdown-pure.js +96 -0
- package/dist/services/memory/project-memory-service/store/atomic-write.d.ts +5 -0
- package/dist/services/memory/project-memory-service/store/atomic-write.js +56 -0
- package/dist/services/memory/project-memory-service/store/paths.d.ts +8 -0
- package/dist/services/memory/project-memory-service/store/paths.js +116 -0
- package/dist/services/memory/project-memory-service/types.d.ts +128 -0
- package/dist/services/memory/project-memory-service/types.js +9 -0
- package/dist/services/memory/project-memory-service.d.ts +1 -167
- package/dist/services/memory/project-memory-service.js +19 -816
- package/dist/services/migrate-skill-name/schema.d.ts +2 -2
- package/dist/services/observability/aggregation.d.ts +27 -0
- package/dist/services/observability/aggregation.js +72 -0
- package/dist/services/observability/observability-service.d.ts +73 -7
- package/dist/services/observability/observability-service.js +87 -1
- package/dist/services/openspec/artifact-boundary.d.ts +138 -0
- package/dist/services/openspec/artifact-boundary.js +150 -0
- package/dist/services/openspec/coverage-evidence-reader.d.ts +191 -0
- package/dist/services/openspec/coverage-evidence-reader.js +386 -0
- package/dist/services/openspec/openspec-archive-service.d.ts +70 -0
- package/dist/services/openspec/openspec-archive-service.js +320 -8
- package/dist/services/openspec/openspec-bridge-service.js +1 -1
- package/dist/services/openspec/openspec-init-service.js +1 -1
- package/dist/services/openspec/openspec-propose-from-doctor-service.js +1 -1
- package/dist/services/openspec/openspec-render-service.js +7 -4
- package/dist/services/openspec/openspec-scan-service.js +1 -1
- package/dist/services/openspec/openspec-validate-service.js +5 -4
- package/dist/services/preferences/preferences-service.js +10 -0
- package/dist/services/preferences/preferences-types.d.ts +13 -0
- package/dist/services/preferences/preferences-types.js +11 -0
- package/dist/services/qa/screenshot-archive-service.d.ts +51 -0
- package/dist/services/qa/screenshot-archive-service.js +134 -0
- package/dist/services/rd/rd-service.js +10 -11
- package/dist/services/rd/types.d.ts +32 -32
- package/dist/services/rd-swarm/rd-swarm-service.d.ts +60 -0
- package/dist/services/rd-swarm/rd-swarm-service.js +93 -0
- package/dist/services/recommendations/capability-seed-items.js +0 -1
- package/dist/services/recommendations/capability-seed-mappings.js +0 -1
- package/dist/services/recommendations/capability-seed-sources.js +0 -1
- package/dist/services/release/version-precheck-service.d.ts +51 -0
- package/dist/services/release/version-precheck-service.js +257 -0
- package/dist/services/scan/acceptance-coverage-service.js +1 -1
- package/dist/services/scan/archetype-service.js +1 -1
- package/dist/services/scan/existing-system-service.js +1 -1
- package/dist/services/scan/libraries-service.js +1 -1
- package/dist/services/sediment/json-schema.d.ts +40 -40
- package/dist/services/share/bundle-types.d.ts +12 -12
- package/dist/services/share/run-state-contract.d.ts +2 -2
- package/dist/services/skill/skill-search-service.d.ts +12 -7
- package/dist/services/skill/skill-search-service.js +8 -4
- package/dist/services/skillhub/migrations/001-initial.sql +71 -0
- package/dist/services/skillhub/migrations/002-loop-release.sql +32 -0
- package/dist/services/skillhub/migrations/003-loop-bee-relation.sql +35 -0
- package/dist/services/skillhub/migrations/004-loop-bee-extension.sql +65 -0
- package/dist/services/skillhub/migrations/005-evolution-evaluation.sql +81 -0
- package/dist/services/skillhub/migrations/006-crystallization-event.sql +92 -0
- package/dist/services/skills/hooks-settings-service.d.ts +75 -0
- package/dist/services/skills/hooks-settings-service.js +230 -2
- package/dist/services/skills/skill-registry.d.ts +1 -0
- package/dist/services/skills/skill-registry.js +6 -4
- package/dist/services/skills/skill-runbook-service.js +1 -1
- package/dist/services/slice/slice-check-service.js +1 -1
- package/dist/services/standards/main-session-monitor-ban-hook.d.ts +14 -0
- package/dist/services/standards/main-session-monitor-ban-hook.js +19 -0
- package/dist/services/standards/missing-standards-detector.d.ts +25 -0
- package/dist/services/standards/missing-standards-detector.js +43 -12
- package/dist/services/tech/tech-change-id-service.d.ts +82 -0
- package/dist/services/tech/tech-change-id-service.js +117 -0
- package/dist/services/understand/understand-hybrid-service.js +1 -1
- package/dist/services/understand/understand-scan-service.js +2 -2
- package/dist/services/upgrade/upgrade-service.js +4 -3
- package/dist/services/verdict/envelopes.d.ts +2 -2
- package/dist/services/verdict/envelopes.js +2 -2
- package/dist/services/verdict/verdict-aggregator.d.ts +3 -3
- package/dist/services/vm/vm-lease.d.ts +40 -0
- package/dist/services/vm/vm-lease.js +137 -0
- package/dist/services/workflow/autonomous-resume-writer.js +1 -1
- package/dist/services/workflow/pipeline-verify-gate-support.d.ts +47 -0
- package/dist/services/workflow/pipeline-verify-gate-support.js +194 -0
- package/dist/services/workflow/pipeline-verify-service.d.ts +17 -81
- package/dist/services/workflow/pipeline-verify-service.js +42 -218
- package/dist/services/workflow/pipeline-verify-types.d.ts +90 -0
- package/dist/services/workflow/pipeline-verify-types.js +10 -0
- package/dist/services/workflow/plan-reader.d.ts +1 -1
- package/dist/services/workflow/plan-reader.js +1 -1
- package/dist/services/workflow/plan-refresher.d.ts +1 -1
- package/dist/services/workflow/plan-refresher.js +1 -1
- package/dist/services/workflow/plan-trigger-detector.d.ts +1 -1
- package/dist/services/workflow/plan-trigger-detector.js +1 -1
- package/dist/services/workflow/workflow-autonomous-resume-helpers.d.ts +1 -1
- package/dist/services/workflow/workflow-autonomous-service.d.ts +2 -98
- package/dist/services/workflow/workflow-autonomous-types.d.ts +114 -0
- package/dist/services/workflow/workflow-autonomous-types.js +21 -0
- package/dist/services/workflow/workflow-router-service.js +18 -16
- package/dist/services/workflow/workflow-spec-lint.d.ts +13 -0
- package/dist/services/workflow/workflow-spec-lint.js +75 -0
- package/dist/services/workflow/workflow-spec-types.d.ts +100 -0
- package/dist/services/workflow/workflow-spec-types.js +13 -0
- package/dist/services/workflow/workflow-spec-yaml.d.ts +17 -0
- package/dist/services/workflow/workflow-spec-yaml.js +88 -0
- package/dist/services/workflow/workflow-spec.d.ts +11 -91
- package/dist/services/workflow/workflow-spec.js +16 -145
- package/dist/services/workspace/migrate-service.js +1 -1
- package/dist/services/workspace/workspace-service.js +1 -1
- package/dist/services/worktree/worktree-lease.d.ts +170 -0
- package/dist/services/worktree/worktree-lease.js +242 -0
- package/package.json +91 -51
- package/scripts/clean-dist.mjs +31 -1
- package/scripts/copy-templates.mjs +16 -0
- package/scripts/sync-version.mjs +53 -2
- package/skills/bee/peaks-perf-audit/SKILL.md +17 -0
- package/skills/bee/peaks-prd/SKILL.md +16 -0
- package/skills/bee/peaks-prd/test-prompts.json +12 -0
- package/skills/bee/peaks-qa/SKILL.md +16 -1
- package/skills/bee/peaks-qa/references/qa-sub-agent-dispatch.md +22 -0
- package/skills/bee/peaks-qa/test-prompts.json +12 -0
- package/skills/bee/peaks-rd/SKILL.md +29 -20
- package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +39 -0
- package/skills/bee/peaks-rd/test-prompts.json +12 -0
- package/skills/bee/peaks-reviewer/SKILL.md +17 -0
- package/skills/bee/peaks-sc/SKILL.md +16 -0
- package/skills/bee/peaks-security-audit/SKILL.md +17 -0
- package/skills/bee/peaks-txt/SKILL.md +16 -0
- package/skills/bee/peaks-txt/test-prompts.json +12 -0
- package/skills/bee/peaks-ui/SKILL.md +49 -43
- package/skills/bee/peaks-ui/test-prompts.json +12 -0
- package/skills/peaks-code/SKILL.md +54 -109
- package/skills/peaks-code/references/boundaries.md +15 -1
- package/skills/peaks-code/references/cron-scheduler-deployment.md +313 -0
- package/skills/peaks-code/references/external-skill-invocation.md +27 -0
- package/skills/peaks-code/references/lease-dashboard.html +224 -0
- package/skills/peaks-code/references/lease-stats.sample.json +26 -0
- package/skills/peaks-code/references/peaks-worktree-l2-enforcers.md +208 -0
- package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
- package/skills/peaks-code/references/runbook.md +63 -1
- package/skills/peaks-code/references/startup-sequence.md +110 -0
- package/skills/peaks-code/references/step-0-8-gate.md +1 -1
- package/skills/peaks-code/references/sub-agent-dispatch.md +92 -1
- package/skills/peaks-code/references/worktree-governance.md +123 -0
- package/skills/peaks-code/test-prompts.json +12 -0
- package/skills/peaks-doctor/SKILL.md +1 -1
- package/skills/peaks-ide/SKILL.md +1 -1
- package/skills/peaks-solo/SKILL.md +21 -0
- package/skills/peaks-solo/references/triage-decision-table.md +6 -0
- package/skills/peaks-sop/test-prompts.json +17 -0
- package/dist/cli/commands/agent-commands.d.ts +0 -20
- package/dist/cli/commands/agent-commands.js +0 -48
- package/dist/cli/commands/classify-classify-commands.d.ts +0 -19
- package/dist/cli/commands/classify-classify-commands.js +0 -151
- package/dist/cli/commands/contract-commands.d.ts +0 -26
- package/dist/cli/commands/contract-commands.js +0 -114
- package/dist/cli/commands/session-auto-compact-hook-command.d.ts +0 -37
- package/dist/cli/commands/session-auto-compact-hook-command.js +0 -127
- package/dist/cli/commands/worker-commands.d.ts +0 -3
- package/dist/cli/commands/worker-commands.js +0 -52
- package/dist/services/agent/ecc-agent-service.d.ts +0 -47
- package/dist/services/agent/ecc-agent-service.js +0 -143
- package/dist/services/config/provider-service.d.ts +0 -48
- package/dist/services/config/provider-service.js +0 -143
- package/dist/services/context/dispatch-context-guard.d.ts +0 -27
- package/dist/services/context/dispatch-context-guard.js +0 -192
- package/dist/services/context/shared-channel.d.ts +0 -93
- package/dist/services/context/shared-channel.js +0 -308
- package/dist/services/filesystem/file-lock.d.ts +0 -11
- package/dist/services/filesystem/file-lock.js +0 -152
- package/dist/services/mut/assert-scanner.d.ts +0 -6
- package/dist/services/mut/assert-scanner.js +0 -116
- package/dist/services/mut/index.d.ts +0 -8
- package/dist/services/mut/index.js +0 -7
- package/dist/services/mut/mut-runner.d.ts +0 -39
- package/dist/services/mut/mut-runner.js +0 -29
- package/dist/services/mut/production-stryker.d.ts +0 -2
- package/dist/services/mut/production-stryker.js +0 -75
- package/dist/services/mut/report-builder.d.ts +0 -11
- package/dist/services/mut/report-builder.js +0 -110
- package/dist/services/mut/report-loader.d.ts +0 -31
- package/dist/services/mut/report-loader.js +0 -78
- package/dist/services/mut/thresholds.d.ts +0 -21
- package/dist/services/mut/thresholds.js +0 -22
- package/dist/services/mut/types.d.ts +0 -336
- package/dist/services/mut/types.js +0 -59
- package/dist/services/providers/minimax-provider-service.d.ts +0 -24
- package/dist/services/providers/minimax-provider-service.js +0 -143
- package/dist/services/providers/minimax-worker-service.d.ts +0 -21
- package/dist/services/providers/minimax-worker-service.js +0 -83
- package/dist/shared/fs.d.ts +0 -4
- package/dist/shared/fs.js +0 -26
- package/dist/shared/paths.d.ts +0 -6
- package/dist/shared/paths.js +0 -50
- package/dist/shared/result.d.ts +0 -22
- package/dist/shared/result.js +0 -46
- package/dist/shared/version.d.ts +0 -1
- package/dist/shared/version.js +0 -1
- package/examples/video-demo/README.md +0 -142
- package/examples/video-demo/out/en-closing-960.png +0 -0
- package/examples/video-demo/out/zh-closing-960.png +0 -0
- package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
- package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
- /package/dist/services/{job/job-resource-snapshot.js → job-snapshot/snapshot.js} +0 -0
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
28
28
|
import { dirname, resolve } from 'node:path';
|
|
29
29
|
import { assertSafeDispatchRecordPath, dispatchRecordPath } from '../security/safe-settings-path.js';
|
|
30
|
-
import { withFileLockSync } from '
|
|
30
|
+
import { withFileLockSync } from 'peaks-loop-shared-channel';
|
|
31
|
+
import { isStageLabel } from './stage-enum.js';
|
|
32
|
+
import { emitLeaseEvent } from '../observability/observability-service.js';
|
|
31
33
|
const MAX_PROMPT_BYTES = 256 * 1024;
|
|
32
34
|
/** Write a new dispatch record (G2 + G5 + G6). Returns the absolute path. */
|
|
33
35
|
export function writeInitialDispatchRecord(input) {
|
|
@@ -42,7 +44,7 @@ export function writeInitialDispatchRecord(input) {
|
|
|
42
44
|
const path = dispatchRecordPath(projectRoot, sessionId, requestId, now());
|
|
43
45
|
const safePath = assertSafeDispatchRecordPath(path, projectRoot);
|
|
44
46
|
const record = {
|
|
45
|
-
version:
|
|
47
|
+
version: '3.1',
|
|
46
48
|
createdAt: now().toISOString(),
|
|
47
49
|
completedAt: null,
|
|
48
50
|
outcome: 'no-execution',
|
|
@@ -61,7 +63,30 @@ export function writeInitialDispatchRecord(input) {
|
|
|
61
63
|
batchId,
|
|
62
64
|
heartbeats: [],
|
|
63
65
|
lastBeatAt: null,
|
|
64
|
-
status: 'queued'
|
|
66
|
+
status: 'queued',
|
|
67
|
+
// Slice 2026-07-29-dispatch-stall-governance / S5 (AC-5.1) — new
|
|
68
|
+
// records start with `stage: null`; the sub-agent promotes it
|
|
69
|
+
// through `setStage` / the heartbeat CLI's `--stage` flag.
|
|
70
|
+
stage: null,
|
|
71
|
+
// Slice 2026-07-29-worktree-l2-extended Part 3.A: when the
|
|
72
|
+
// dispatch was issued with --isolation worktree, persist the
|
|
73
|
+
// lease id so the finalize-time release hook in markCompleted
|
|
74
|
+
// can fire. Validation is the same 16-hex regex the gate uses
|
|
75
|
+
// (gate-commands.ts), so an attacker-controlled toolCall.env
|
|
76
|
+
// cannot inject a non-hex value and get the release path to
|
|
77
|
+
// misfire.
|
|
78
|
+
leaseId: typeof input.leaseId === 'string' && /^[a-f0-9]{16}$/.test(input.leaseId)
|
|
79
|
+
? input.leaseId
|
|
80
|
+
: null,
|
|
81
|
+
// Slice 2026-07-29-worktree-l2-extended Part 7: v3.1 field.
|
|
82
|
+
// ISO timestamp when the isolation mode was set up. Default
|
|
83
|
+
// null when the dispatch did not request isolation. We do
|
|
84
|
+
// NOT validate the format — the writer is the source of
|
|
85
|
+
// truth here, and any ISO 8601 string Date.parse() can
|
|
86
|
+
// handle is acceptable for the dashboard.
|
|
87
|
+
isolationStartedAt: typeof input.isolationStartedAt === 'string' && input.isolationStartedAt.length > 0
|
|
88
|
+
? input.isolationStartedAt
|
|
89
|
+
: null
|
|
65
90
|
};
|
|
66
91
|
writeAtomic(safePath, record);
|
|
67
92
|
// Slice 2026-06-23-audit-4th #A4: register the path in the
|
|
@@ -142,7 +167,15 @@ function unregisterActiveDispatch(input) {
|
|
|
142
167
|
}
|
|
143
168
|
if (input.recordPath in index) {
|
|
144
169
|
index[input.recordPath] = { ...index[input.recordPath], status: input.status };
|
|
145
|
-
|
|
170
|
+
// Slice 2026-07-29-dispatch-stall-governance / S1 — `never-started`
|
|
171
|
+
// and `unreadable` are terminal (the startup-timeout service writes
|
|
172
|
+
// them as terminal markers). Unregister on the full terminal set.
|
|
173
|
+
if (input.status === 'done' ||
|
|
174
|
+
input.status === 'failed' ||
|
|
175
|
+
input.status === 'cancelled' ||
|
|
176
|
+
input.status === 'no-execution' ||
|
|
177
|
+
input.status === 'never-started' ||
|
|
178
|
+
input.status === 'unreadable') {
|
|
146
179
|
delete index[input.recordPath];
|
|
147
180
|
}
|
|
148
181
|
const tmp = `${indexPath}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -267,6 +300,109 @@ function mapStatusToAggregate(latest, current) {
|
|
|
267
300
|
}
|
|
268
301
|
return latest;
|
|
269
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Slice 2026-07-29-worktree-l2-extended Part 3.A: fire-and-forget
|
|
305
|
+
* auto-release for the lease owned by a dispatch. Called from
|
|
306
|
+
* `markCompleted` (terminal status) and from the heartbeat CLI
|
|
307
|
+
* (`--status done`).
|
|
308
|
+
*
|
|
309
|
+
* Design:
|
|
310
|
+
* - The release subprocess is spawned ASYNC and detached. The
|
|
311
|
+
* finalize-time caller (heartbeat / share / dispatch reducer)
|
|
312
|
+
* does NOT await it; the caller's job is to record the
|
|
313
|
+
* finalization, not to wait for the lease cleanup.
|
|
314
|
+
* - Failures are swallowed (best-effort, same as `git worktree
|
|
315
|
+
* remove` inside `peaks worktree release` itself). The next
|
|
316
|
+
* `peaks worktree gc` pass is the safety net.
|
|
317
|
+
* - Idempotent: re-calling with the same leaseId is a no-op on
|
|
318
|
+
* the release side (the CLI refuses to re-release an already-
|
|
319
|
+
* released lease; see Part 1 release command).
|
|
320
|
+
* - The leaseId MUST be 16-hex (same regex the gate uses). Any
|
|
321
|
+
* other value is silently ignored — we never shell out to
|
|
322
|
+
* `peaks worktree release` with attacker-controlled input.
|
|
323
|
+
*/
|
|
324
|
+
export function tryAutoReleaseLease(args) {
|
|
325
|
+
if (typeof args.leaseId !== 'string' || !/^[a-f0-9]{16}$/.test(args.leaseId)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (typeof args.projectRoot !== 'string' || args.projectRoot.length === 0) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// Spawn detached. The CLI itself runs `git worktree remove` and
|
|
332
|
+
// marks the lease released; we trust its at-least-once semantics.
|
|
333
|
+
// `node:child_process` is loaded via dynamic import so this module
|
|
334
|
+
// remains ESM-compatible (the compiled heartbeat CLI throws
|
|
335
|
+
// `require is not defined` if we use `require` here).
|
|
336
|
+
void (async () => {
|
|
337
|
+
let spawned = false;
|
|
338
|
+
try {
|
|
339
|
+
const cp = await import('node:child_process');
|
|
340
|
+
const child = cp.spawn(process.execPath, [
|
|
341
|
+
process.argv[1] ?? '',
|
|
342
|
+
'worktree', 'release',
|
|
343
|
+
'--lease-id', args.leaseId,
|
|
344
|
+
'--project', args.projectRoot,
|
|
345
|
+
'--session', args.sessionId,
|
|
346
|
+
'--json'
|
|
347
|
+
],
|
|
348
|
+
// `pipe` rather than `ignore` so a spawn failure (e.g. ENOENT
|
|
349
|
+
// on process.argv[1] in a test) shows up on stderr instead
|
|
350
|
+
// of vanishing into the void. The release CLI is short-lived
|
|
351
|
+
// so buffering is irrelevant.
|
|
352
|
+
{ stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, detached: true });
|
|
353
|
+
spawned = true;
|
|
354
|
+
if (process.env.PEAKS_WORKTREE_LEASE_DEBUG) {
|
|
355
|
+
child.stderr?.on('data', (d) => process.stderr.write(`[release] ${d.toString('utf8')}`));
|
|
356
|
+
child.stdout?.on('data', (d) => process.stderr.write(`[release] ${d.toString('utf8')}`));
|
|
357
|
+
child.on('error', (e) => process.stderr.write(`[release error] ${e.message}\n`));
|
|
358
|
+
child.on('exit', (code) => process.stderr.write(`[release exit] code=${code}\n`));
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
child.stderr?.on('data', () => { });
|
|
362
|
+
child.stdout?.on('data', () => { });
|
|
363
|
+
child.on('error', () => { });
|
|
364
|
+
}
|
|
365
|
+
child.unref();
|
|
366
|
+
}
|
|
367
|
+
catch (e) {
|
|
368
|
+
// Slice 2026-07-29-worktree-l2-extended Part 4.A: surface
|
|
369
|
+
// auto-release failures to the observability stream so the
|
|
370
|
+
// dashboard can alert. The spawn-attempt itself threw (not
|
|
371
|
+
// a child-process exit-code failure — those are not
|
|
372
|
+
// catchable from the parent because the child is detached
|
|
373
|
+
// and unref'd). emitLeaseEvent is fire-and-forget; it
|
|
374
|
+
// returns a result we don't inspect.
|
|
375
|
+
emitLeaseEvent({
|
|
376
|
+
sessionId: args.sessionId,
|
|
377
|
+
projectRoot: args.projectRoot,
|
|
378
|
+
kind: 'autoRelease-failed',
|
|
379
|
+
leaseId: args.leaseId,
|
|
380
|
+
reason: e.message
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
if (spawned) {
|
|
384
|
+
// Record the success path. Idempotent with the manual
|
|
385
|
+
// `peaks worktree release` metric — the release CLI itself
|
|
386
|
+
// emits a 'release' event when it runs and lands. Two
|
|
387
|
+
// events for one logical release is acceptable; the
|
|
388
|
+
// dashboard can dedup or count both under
|
|
389
|
+
// lease.autoRelease.count.
|
|
390
|
+
emitLeaseEvent({
|
|
391
|
+
sessionId: args.sessionId,
|
|
392
|
+
projectRoot: args.projectRoot,
|
|
393
|
+
kind: 'autoRelease',
|
|
394
|
+
leaseId: args.leaseId
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
})();
|
|
398
|
+
// NB: we deliberately do NOT log per-call here — every heartbeat
|
|
399
|
+
// that reports done in a busy session would otherwise spam the
|
|
400
|
+
// log. The release CLI itself emits a structured envelope on
|
|
401
|
+
// success; that's the audit record.
|
|
402
|
+
if (args.logger !== undefined) {
|
|
403
|
+
args.logger(`peaks.worktree.autoRelease leaseId=${args.leaseId} sessionId=${args.sessionId}`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
270
406
|
/** Mark a record as completed (success / failed / cancelled / no-execution). */
|
|
271
407
|
export function markCompleted(input) {
|
|
272
408
|
// Slice 2026-06-23-audit-3rd #3: lock + re-read so a concurrent
|
|
@@ -302,6 +438,25 @@ export function markCompleted(input) {
|
|
|
302
438
|
/* best-effort */
|
|
303
439
|
}
|
|
304
440
|
}
|
|
441
|
+
// Slice 2026-07-29-worktree-l2-extended Part 3.A: finalize-time
|
|
442
|
+
// lease release. The terminal status (done/failed/cancelled/
|
|
443
|
+
// no-execution) means the sub-agent is no longer using the
|
|
444
|
+
// worktree; auto-release closes the loop. The release is detached
|
|
445
|
+
// and best-effort; a crash here cannot roll back the markCompleted
|
|
446
|
+
// write (we already returned from the lock). The next gc pass is
|
|
447
|
+
// the safety net.
|
|
448
|
+
if (result.record.leaseId !== null && typeof input.projectRoot === 'string' && input.projectRoot.length > 0) {
|
|
449
|
+
try {
|
|
450
|
+
tryAutoReleaseLease({
|
|
451
|
+
projectRoot: input.projectRoot,
|
|
452
|
+
sessionId: result.record.sessionId,
|
|
453
|
+
leaseId: result.record.leaseId
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
catch { // best-effort; release is async anyway
|
|
457
|
+
/* swallow */
|
|
458
|
+
}
|
|
459
|
+
}
|
|
305
460
|
return result;
|
|
306
461
|
}
|
|
307
462
|
/** Mark a record as disposed (reducer ran). */
|
|
@@ -318,6 +473,32 @@ export function markDisposed(recordPath, now = () => new Date()) {
|
|
|
318
473
|
return { record: next };
|
|
319
474
|
});
|
|
320
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* Slice 2026-07-29-dispatch-stall-governance / S5 (AC-5.1) — promote
|
|
478
|
+
* the record's `stage` field. Rejects unknown values with
|
|
479
|
+
* `INVALID_STAGE`; the LLM-side runner surfaces the error so the
|
|
480
|
+
* sub-agent can pick from the bounded enum in ./stage-enum.ts.
|
|
481
|
+
*
|
|
482
|
+
* Atomic via the same `withFileLockSync` lock as `appendHeartbeat` /
|
|
483
|
+
* `markCompleted`. `null` is a valid argument ("clear the stage")
|
|
484
|
+
* but unknown strings are not.
|
|
485
|
+
*/
|
|
486
|
+
export function setStage(input) {
|
|
487
|
+
if (input.stage !== null && !isStageLabel(input.stage)) {
|
|
488
|
+
const err = new Error(`stage must be one of the bounded stage labels (got: ${JSON.stringify(input.stage)})`);
|
|
489
|
+
err.code = 'INVALID_STAGE';
|
|
490
|
+
throw err;
|
|
491
|
+
}
|
|
492
|
+
return withFileLockSync(input.recordPath, () => {
|
|
493
|
+
const existing = readRecord(input.recordPath);
|
|
494
|
+
const next = {
|
|
495
|
+
...existing,
|
|
496
|
+
stage: input.stage
|
|
497
|
+
};
|
|
498
|
+
writeAtomic(input.recordPath, next);
|
|
499
|
+
return { record: next };
|
|
500
|
+
});
|
|
501
|
+
}
|
|
321
502
|
/**
|
|
322
503
|
* Read a dispatch record with backward-compat defaults. Old records
|
|
323
504
|
* missing G5 / G6 fields are upgraded on read (no error, no overwrite).
|
|
@@ -363,6 +544,19 @@ function upgradeRecord(parsed) {
|
|
|
363
544
|
throw new Error('Dispatch record root must be an object');
|
|
364
545
|
}
|
|
365
546
|
const obj = parsed;
|
|
547
|
+
// Slice 2026-07-29-rid-prose-only-sweep Part 34: the version
|
|
548
|
+
// field is now the literal '3.1'. Legacy v2 and v3 records
|
|
549
|
+
// (version: 2 or version: 3) are accepted transparently and
|
|
550
|
+
// upgraded to v3.1 on read. The forward-compat check rejects
|
|
551
|
+
// records with an unknown version string (which would
|
|
552
|
+
// indicate either a much-older build or a much-newer one
|
|
553
|
+
// with a schema we have not implemented). v1 records
|
|
554
|
+
// (pre-audit-trail) must be regenerated.
|
|
555
|
+
const rawVersion = obj.version;
|
|
556
|
+
if (rawVersion !== '3.1' && rawVersion !== 3 && rawVersion !== 2 && rawVersion !== 1) {
|
|
557
|
+
throw new Error(`Dispatch record version mismatch: expected '3.1', 3, 2, or 1, got ${JSON.stringify(rawVersion)}. ` +
|
|
558
|
+
'The v1 → v3.1 migration is in-file; records from much older or newer builds must be regenerated.');
|
|
559
|
+
}
|
|
366
560
|
const role = stringField(obj, 'role');
|
|
367
561
|
const requestId = stringField(obj, 'requestId');
|
|
368
562
|
const sessionId = stringField(obj, 'sessionId');
|
|
@@ -384,7 +578,14 @@ function upgradeRecord(parsed) {
|
|
|
384
578
|
? obj.heartbeats.filter(isValidHeartbeat)
|
|
385
579
|
: [];
|
|
386
580
|
const lastBeatAt = typeof obj.lastBeatAt === 'string' ? obj.lastBeatAt : null;
|
|
387
|
-
|
|
581
|
+
// Slice 2026-07-29-dispatch-stall-governance / S1 (UQ-1) — `no-execution`
|
|
582
|
+
// keeps its natural "dispatched, never executed" reading; an unparseable
|
|
583
|
+
// status field now resolves to a *distinct* `unreadable` label so the
|
|
584
|
+
// caller can tell "corrupt record" apart from "record written, no first
|
|
585
|
+
// heartbeat" (which is the new `never-started` state).
|
|
586
|
+
const status = isDispatchStatus(obj.status)
|
|
587
|
+
? obj.status
|
|
588
|
+
: 'unreadable';
|
|
388
589
|
const completedAt = typeof obj.completedAt === 'string' ? obj.completedAt : null;
|
|
389
590
|
const outcome = isOutcome(obj.outcome) ? obj.outcome : 'no-execution';
|
|
390
591
|
const artifactPaths = Array.isArray(obj.artifactPaths)
|
|
@@ -396,7 +597,7 @@ function upgradeRecord(parsed) {
|
|
|
396
597
|
? obj.batchId
|
|
397
598
|
: 'legacy-batch';
|
|
398
599
|
return {
|
|
399
|
-
version:
|
|
600
|
+
version: '3.1',
|
|
400
601
|
createdAt,
|
|
401
602
|
completedAt,
|
|
402
603
|
outcome,
|
|
@@ -411,7 +612,27 @@ function upgradeRecord(parsed) {
|
|
|
411
612
|
batchId,
|
|
412
613
|
heartbeats,
|
|
413
614
|
lastBeatAt,
|
|
414
|
-
status
|
|
615
|
+
status,
|
|
616
|
+
// Slice 2026-07-29-dispatch-stall-governance / S5 (AC-5.1 / PB-2)
|
|
617
|
+
// — legacy records (pre-slice) had no `stage` field. The reader
|
|
618
|
+
// defaults to `null` so the watch surface can tell "no stage ever
|
|
619
|
+
// emitted" apart from "stage: ''" (which is itself a *valid*
|
|
620
|
+
// round-trip through the writer — an empty stage is rejected by
|
|
621
|
+
// `setStage`, but a record that round-tripped through a non-strict
|
|
622
|
+
// tool would land here).
|
|
623
|
+
stage: typeof obj.stage === 'string' && obj.stage.length > 0 ? obj.stage : null,
|
|
624
|
+
// Slice 2026-07-29-worktree-l2-extended Part 3.A: legacy records
|
|
625
|
+
// have no `leaseId`; default to `null` so the auto-release hook
|
|
626
|
+
// in `markCompleted` is a clean no-op for them.
|
|
627
|
+
leaseId: typeof obj.leaseId === 'string' && /^[a-f0-9]{16}$/.test(obj.leaseId)
|
|
628
|
+
? obj.leaseId
|
|
629
|
+
: null,
|
|
630
|
+
// Slice 2026-07-29-worktree-l2-extended Part 7: v3 → v3.1
|
|
631
|
+
// migration. Legacy records have no `isolationStartedAt`; default
|
|
632
|
+
// to `null`. v3.1 readers can treat the field as opt-in.
|
|
633
|
+
isolationStartedAt: typeof obj.isolationStartedAt === 'string' && obj.isolationStartedAt.length > 0
|
|
634
|
+
? obj.isolationStartedAt
|
|
635
|
+
: null
|
|
415
636
|
};
|
|
416
637
|
}
|
|
417
638
|
function isObject(v) {
|
|
@@ -434,12 +655,21 @@ function isValidHeartbeat(v) {
|
|
|
434
655
|
}
|
|
435
656
|
function isHeartbeatStatus(v) {
|
|
436
657
|
return (v === 'queued' || v === 'running' || v === 'finalizing' ||
|
|
437
|
-
v === 'done' || v === 'failed' || v === 'stale'
|
|
658
|
+
v === 'done' || v === 'failed' || v === 'stale' ||
|
|
659
|
+
// Slice 2026-07-29-dispatch-stall-governance / S2 — accept the
|
|
660
|
+
// S1 terminal members so a sub-agent can report `cancelled`,
|
|
661
|
+
// `no-execution`, `never-started`, or `unreadable` through the
|
|
662
|
+
// heartbeat CLI.
|
|
663
|
+
v === 'cancelled' || v === 'no-execution' ||
|
|
664
|
+
v === 'never-started' || v === 'unreadable');
|
|
438
665
|
}
|
|
439
666
|
function isDispatchStatus(v) {
|
|
440
667
|
return (v === 'queued' || v === 'running' || v === 'finalizing' ||
|
|
441
668
|
v === 'done' || v === 'failed' || v === 'cancelled' ||
|
|
442
|
-
v === 'no-execution' || v === 'stale'
|
|
669
|
+
v === 'no-execution' || v === 'stale' ||
|
|
670
|
+
// Slice 2026-07-29-dispatch-stall-governance / S1 — accept the two
|
|
671
|
+
// new terminal members from the startup-timeout service.
|
|
672
|
+
v === 'never-started' || v === 'unreadable');
|
|
443
673
|
}
|
|
444
674
|
function isOutcome(v) {
|
|
445
675
|
return (v === 'success' || v === 'failed' || v === 'timeout' ||
|
|
@@ -79,3 +79,49 @@ export declare function sliceReadyToRun(dag: SliceDag, completed: ReadonlySet<st
|
|
|
79
79
|
export declare function serializeDag(dag: SliceDag): string;
|
|
80
80
|
/** SHA-256 hash of the serialized DAG. Stable across runs. */
|
|
81
81
|
export declare function hashDag(dag: SliceDag): string;
|
|
82
|
+
/**
|
|
83
|
+
* Knobs for wave planning + artifact-pass behaviour.
|
|
84
|
+
*
|
|
85
|
+
* - `maxConcurrency`: hard cap on how many slices a single Wave can hold.
|
|
86
|
+
* Each topological level is chunked into Waves of at most this many
|
|
87
|
+
* slice IDs (default 6 per `2026-07-28-24h-loop-audit.md` E direction).
|
|
88
|
+
* - `passArtifacts`: when true, each Wave's prompt is augmented with a
|
|
89
|
+
* `WaveArtifact` envelope (contracts of preceding Waves). Default
|
|
90
|
+
* false — the existing `runDag` ancestor-injection path already covers
|
|
91
|
+
* per-slice contract coverage.
|
|
92
|
+
*/
|
|
93
|
+
export interface WaveOptions {
|
|
94
|
+
readonly maxConcurrency: number;
|
|
95
|
+
readonly passArtifacts: boolean;
|
|
96
|
+
}
|
|
97
|
+
/** Default wave options: 6 leaves per wave; artifact-pass off. */
|
|
98
|
+
export declare const DEFAULT_MAX_CONCURRENCY = 6;
|
|
99
|
+
export declare const DEFAULT_WAVE_OPTIONS: WaveOptions;
|
|
100
|
+
/**
|
|
101
|
+
* Artifact envelope emitted when a Wave completes successfully.
|
|
102
|
+
*
|
|
103
|
+
* - `waveIndex`: sequential, 0-based across the whole plan.
|
|
104
|
+
* - `completedLeaves`: slice IDs that finished (`status: 'done'`). Failed
|
|
105
|
+
* or cancelled leaves are NOT included.
|
|
106
|
+
* - `contracts`: per-slice public contract snapshot (sliceId → record).
|
|
107
|
+
* Stored verbatim so a downstream Wave can re-inject this without
|
|
108
|
+
* re-reading the disk-side contract store.
|
|
109
|
+
* - `passedAt`: ISO timestamp of Wave completion (caller-supplied to keep
|
|
110
|
+
* the surface pure).
|
|
111
|
+
*/
|
|
112
|
+
export interface WaveArtifact {
|
|
113
|
+
readonly waveIndex: number;
|
|
114
|
+
readonly completedLeaves: readonly string[];
|
|
115
|
+
readonly contracts: Readonly<Record<string, unknown>>;
|
|
116
|
+
readonly passedAt: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A single dispatch Wave. Holds the slice IDs that must execute together,
|
|
120
|
+
* respecting `WaveOptions.maxConcurrency`. Waves are emitted in
|
|
121
|
+
* topological order; downstream consumers may treat `waveIndex` as a
|
|
122
|
+
* monotonic cursor.
|
|
123
|
+
*/
|
|
124
|
+
export interface Wave {
|
|
125
|
+
readonly waveIndex: number;
|
|
126
|
+
readonly slices: readonly string[];
|
|
127
|
+
}
|
|
@@ -236,3 +236,9 @@ export function serializeDag(dag) {
|
|
|
236
236
|
export function hashDag(dag) {
|
|
237
237
|
return createHash('sha256').update(serializeDag(dag)).digest('hex');
|
|
238
238
|
}
|
|
239
|
+
/** Default wave options: 6 leaves per wave; artifact-pass off. */
|
|
240
|
+
export const DEFAULT_MAX_CONCURRENCY = 6;
|
|
241
|
+
export const DEFAULT_WAVE_OPTIONS = {
|
|
242
|
+
maxConcurrency: DEFAULT_MAX_CONCURRENCY,
|
|
243
|
+
passArtifacts: false
|
|
244
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 2026-07-29-dispatch-stall-governance / S5 — bounded stage
|
|
3
|
+
* vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* Why a bounded enum (not a free-form string):
|
|
6
|
+
* - a free-form `stage` recreates the `note` field, which already
|
|
7
|
+
* exists and did not solve visibility.
|
|
8
|
+
* - the watch surface renders a stage label inline (`role 30%
|
|
9
|
+
* (5s ago) [planning]`); an unbounded vocabulary would let typos
|
|
10
|
+
* and near-duplicates spread across the swarm.
|
|
11
|
+
* - the LLM-side runner can validate the stage at write time
|
|
12
|
+
* (`setStage` rejects unknown values with `INVALID_STAGE`).
|
|
13
|
+
*
|
|
14
|
+
* The enum is intentionally small and stable. Adding a new stage is a
|
|
15
|
+
* deliberate code change (this file + the `setStage` validation) so a
|
|
16
|
+
* future user cannot accidentally flood the watch with `awaiting-coffee`
|
|
17
|
+
* or `idk`.
|
|
18
|
+
*
|
|
19
|
+
* `null` is NOT a stage — it is the absence of a stage. Records that
|
|
20
|
+
* have not yet been promoted carry `stage: null`; the watch surface
|
|
21
|
+
* renders no marker.
|
|
22
|
+
*/
|
|
23
|
+
export declare const STAGE_LABELS: readonly ["intake", "planning", "gathering", "analyzing", "writing", "testing", "reviewing", "finalizing"];
|
|
24
|
+
export type StageLabel = (typeof STAGE_LABELS)[number];
|
|
25
|
+
export declare const DEFAULT_STAGE_LABELS: readonly StageLabel[];
|
|
26
|
+
export declare function isStageLabel(value: unknown): value is StageLabel;
|
|
27
|
+
export declare function normalizeStage(value: string | null | undefined): StageLabel | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 2026-07-29-dispatch-stall-governance / S5 — bounded stage
|
|
3
|
+
* vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* Why a bounded enum (not a free-form string):
|
|
6
|
+
* - a free-form `stage` recreates the `note` field, which already
|
|
7
|
+
* exists and did not solve visibility.
|
|
8
|
+
* - the watch surface renders a stage label inline (`role 30%
|
|
9
|
+
* (5s ago) [planning]`); an unbounded vocabulary would let typos
|
|
10
|
+
* and near-duplicates spread across the swarm.
|
|
11
|
+
* - the LLM-side runner can validate the stage at write time
|
|
12
|
+
* (`setStage` rejects unknown values with `INVALID_STAGE`).
|
|
13
|
+
*
|
|
14
|
+
* The enum is intentionally small and stable. Adding a new stage is a
|
|
15
|
+
* deliberate code change (this file + the `setStage` validation) so a
|
|
16
|
+
* future user cannot accidentally flood the watch with `awaiting-coffee`
|
|
17
|
+
* or `idk`.
|
|
18
|
+
*
|
|
19
|
+
* `null` is NOT a stage — it is the absence of a stage. Records that
|
|
20
|
+
* have not yet been promoted carry `stage: null`; the watch surface
|
|
21
|
+
* renders no marker.
|
|
22
|
+
*/
|
|
23
|
+
export const STAGE_LABELS = [
|
|
24
|
+
'intake',
|
|
25
|
+
'planning',
|
|
26
|
+
'gathering',
|
|
27
|
+
'analyzing',
|
|
28
|
+
'writing',
|
|
29
|
+
'testing',
|
|
30
|
+
'reviewing',
|
|
31
|
+
'finalizing'
|
|
32
|
+
];
|
|
33
|
+
export const DEFAULT_STAGE_LABELS = STAGE_LABELS;
|
|
34
|
+
export function isStageLabel(value) {
|
|
35
|
+
return typeof value === 'string' && STAGE_LABELS.includes(value);
|
|
36
|
+
}
|
|
37
|
+
export function normalizeStage(value) {
|
|
38
|
+
if (value === null || value === undefined)
|
|
39
|
+
return null;
|
|
40
|
+
if (typeof value !== 'string')
|
|
41
|
+
return null;
|
|
42
|
+
const trimmed = value.trim();
|
|
43
|
+
if (trimmed.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
if (isStageLabel(trimmed))
|
|
46
|
+
return trimmed;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice 2026-07-29-dispatch-stall-governance / S1 — startup-timeout service.
|
|
3
|
+
*
|
|
4
|
+
* Why a separate module (vs adding the logic inline to
|
|
5
|
+
* `dispatch-record-writer.ts`):
|
|
6
|
+
* - the writer is the on-disk format owner; the eval logic is a small
|
|
7
|
+
* pure function over a `DispatchRecord` snapshot.
|
|
8
|
+
* - keeps the writer surface unchanged (no extra `markStartupTimeout`
|
|
9
|
+
* method) so other consumers (heartbeat, watch, batch poller) do not
|
|
10
|
+
* have to learn a new mutation API.
|
|
11
|
+
* - a future `markStartupTimeout` writer helper, if added, would import
|
|
12
|
+
* this module's STARTUP_OUTCOME / DEFAULT_STARTUP_BUDGET_MS so the
|
|
13
|
+
* CLI help text and the eval share a single source of truth.
|
|
14
|
+
*
|
|
15
|
+
* Contract (see tests/unit/dispatch/startup-timeout.test.ts for the
|
|
16
|
+
* pinned assertions):
|
|
17
|
+
*
|
|
18
|
+
* evaluateStartupTimeout(record, now, opts) → StartupTimeoutEvaluation
|
|
19
|
+
*
|
|
20
|
+
* - `outcome: 'within-budget' | 'never-started' | 'unreadable'`
|
|
21
|
+
* - `targetStatus: DispatchRecordStatus` — the status to write when
|
|
22
|
+
* `marked === true`. Distinct from `stale` (heartbeat seen, gone
|
|
23
|
+
* quiet) and from `no-execution` (the pre-slice silent default).
|
|
24
|
+
* - `marked: boolean` — whether the caller should write
|
|
25
|
+
* `targetStatus` to the record.
|
|
26
|
+
* - `reason: string` — short human-readable rationale, rendered in
|
|
27
|
+
* the watcher text line and in the dispatch envelope's
|
|
28
|
+
* `notes[]`.
|
|
29
|
+
*
|
|
30
|
+
* DEFAULT_STARTUP_BUDGET_MS = 60_000
|
|
31
|
+
* - 1 order of magnitude above the measured 4–6s cold-start figure
|
|
32
|
+
* from .peaks/memory/2026-07-28-sub-agent-visibility-issue.md
|
|
33
|
+
* - well below the 5-minute heartbeat stale threshold so this
|
|
34
|
+
* fires first
|
|
35
|
+
* - configurable via opts.budgetMs
|
|
36
|
+
*
|
|
37
|
+
* STARTUP_OUTCOME = { NEVER_STARTED: 'never-started', UNREADABLE:
|
|
38
|
+
* 'unreadable' }
|
|
39
|
+
* - exported so the CLI help text, the watch command, and the
|
|
40
|
+
* reader's legacy fallback all reference the same strings.
|
|
41
|
+
*/
|
|
42
|
+
import type { DispatchRecord, DispatchRecordStatus } from './dispatch-record-writer.js';
|
|
43
|
+
/**
|
|
44
|
+
* Default budget: 60s. 1 order of magnitude above the measured 4–6s
|
|
45
|
+
* cold-start figure from .peaks/memory/2026-07-28-sub-agent-visibility-
|
|
46
|
+
* issue.md; well below the 5-min heartbeat stale threshold so this
|
|
47
|
+
* fires first.
|
|
48
|
+
*/
|
|
49
|
+
export declare const DEFAULT_STARTUP_BUDGET_MS = 60000;
|
|
50
|
+
/**
|
|
51
|
+
* String constants for the new terminal statuses. Distinct from the
|
|
52
|
+
* pre-slice `stale` (heartbeat seen, then quiet) and `no-execution`
|
|
53
|
+
* (legacy silent fallback). These are added to the writer's
|
|
54
|
+
* `DispatchRecordStatus` union in the same slice; the constants here
|
|
55
|
+
* are the canonical source so the CLI help / watch / writer all
|
|
56
|
+
* reference the same strings.
|
|
57
|
+
*/
|
|
58
|
+
export declare const STARTUP_OUTCOME: {
|
|
59
|
+
readonly NEVER_STARTED: "never-started";
|
|
60
|
+
readonly UNREADABLE: "unreadable";
|
|
61
|
+
};
|
|
62
|
+
export type StartupTimeoutOutcome = 'within-budget' | 'never-started' | 'unreadable';
|
|
63
|
+
export interface StartupTimeoutOptions {
|
|
64
|
+
/** Override the default 60s budget. */
|
|
65
|
+
readonly budgetMs?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Test seam: when true, the record is treated as if its body is
|
|
68
|
+
* corrupt (status field unparseable). The function returns
|
|
69
|
+
* `{ outcome: 'unreadable', ... }` and recommends writing the
|
|
70
|
+
* `unreadable` status. The CLI never sets this; the read path does.
|
|
71
|
+
*/
|
|
72
|
+
readonly corrupt?: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface StartupTimeoutEvaluation {
|
|
75
|
+
readonly outcome: StartupTimeoutOutcome;
|
|
76
|
+
readonly marked: boolean;
|
|
77
|
+
readonly targetStatus: DispatchRecordStatus;
|
|
78
|
+
readonly reason: string;
|
|
79
|
+
readonly ageMs: number;
|
|
80
|
+
readonly budgetMs: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Pure eval. Returns a typed triple; the caller decides whether to
|
|
84
|
+
* write `targetStatus` to the record.
|
|
85
|
+
*/
|
|
86
|
+
export declare function evaluateStartupTimeout(record: DispatchRecord, now?: () => Date, options?: StartupTimeoutOptions): StartupTimeoutEvaluation;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default budget: 60s. 1 order of magnitude above the measured 4–6s
|
|
3
|
+
* cold-start figure from .peaks/memory/2026-07-28-sub-agent-visibility-
|
|
4
|
+
* issue.md; well below the 5-min heartbeat stale threshold so this
|
|
5
|
+
* fires first.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_STARTUP_BUDGET_MS = 60_000;
|
|
8
|
+
/**
|
|
9
|
+
* String constants for the new terminal statuses. Distinct from the
|
|
10
|
+
* pre-slice `stale` (heartbeat seen, then quiet) and `no-execution`
|
|
11
|
+
* (legacy silent fallback). These are added to the writer's
|
|
12
|
+
* `DispatchRecordStatus` union in the same slice; the constants here
|
|
13
|
+
* are the canonical source so the CLI help / watch / writer all
|
|
14
|
+
* reference the same strings.
|
|
15
|
+
*/
|
|
16
|
+
export const STARTUP_OUTCOME = {
|
|
17
|
+
NEVER_STARTED: 'never-started',
|
|
18
|
+
UNREADABLE: 'unreadable'
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Pure eval. Returns a typed triple; the caller decides whether to
|
|
22
|
+
* write `targetStatus` to the record.
|
|
23
|
+
*/
|
|
24
|
+
export function evaluateStartupTimeout(record, now = () => new Date(), options = {}) {
|
|
25
|
+
const budgetMs = options.budgetMs ?? DEFAULT_STARTUP_BUDGET_MS;
|
|
26
|
+
const safeBudget = Number.isFinite(budgetMs) && budgetMs > 0 ? budgetMs : DEFAULT_STARTUP_BUDGET_MS;
|
|
27
|
+
const createdAt = parseIsoOrFallback(record.createdAt, now);
|
|
28
|
+
const ageMs = Math.max(0, now().getTime() - createdAt.getTime());
|
|
29
|
+
if (options.corrupt === true) {
|
|
30
|
+
return {
|
|
31
|
+
outcome: 'unreadable',
|
|
32
|
+
marked: true,
|
|
33
|
+
targetStatus: 'unreadable',
|
|
34
|
+
reason: `record body is corrupt (status field unparseable) at age ${ageMs}ms`,
|
|
35
|
+
ageMs,
|
|
36
|
+
budgetMs: safeBudget
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// A record that already reached `running` (or beyond) is by definition
|
|
40
|
+
// not a startup-timeout candidate. `stale` (heartbeat seen, then
|
|
41
|
+
// quiet) is its own ladder; we do not reclassify it.
|
|
42
|
+
if (record.status === 'running' || record.status === 'finalizing') {
|
|
43
|
+
return {
|
|
44
|
+
outcome: 'within-budget',
|
|
45
|
+
marked: false,
|
|
46
|
+
targetStatus: record.status,
|
|
47
|
+
reason: `record is ${record.status} and not eligible for startup timeout`,
|
|
48
|
+
ageMs,
|
|
49
|
+
budgetMs: safeBudget
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// A terminal record is not eligible either (the marker functions own
|
|
53
|
+
// the terminal transition; this evaluator is a read-only gate).
|
|
54
|
+
const TERMINAL = [
|
|
55
|
+
'done',
|
|
56
|
+
'failed',
|
|
57
|
+
'cancelled',
|
|
58
|
+
'no-execution',
|
|
59
|
+
'stale',
|
|
60
|
+
'never-started',
|
|
61
|
+
'unreadable'
|
|
62
|
+
];
|
|
63
|
+
if (TERMINAL.includes(record.status)) {
|
|
64
|
+
return {
|
|
65
|
+
outcome: 'within-budget',
|
|
66
|
+
marked: false,
|
|
67
|
+
targetStatus: record.status,
|
|
68
|
+
reason: `record is terminal (${record.status}) and not eligible for startup timeout`,
|
|
69
|
+
ageMs,
|
|
70
|
+
budgetMs: safeBudget
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (ageMs < safeBudget) {
|
|
74
|
+
return {
|
|
75
|
+
outcome: 'within-budget',
|
|
76
|
+
marked: false,
|
|
77
|
+
targetStatus: record.status,
|
|
78
|
+
reason: `record age ${ageMs}ms is within ${safeBudget}ms startup budget`,
|
|
79
|
+
ageMs,
|
|
80
|
+
budgetMs: safeBudget
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
outcome: 'never-started',
|
|
85
|
+
marked: true,
|
|
86
|
+
targetStatus: 'never-started',
|
|
87
|
+
reason: `record stayed ${record.status} for ${ageMs}ms (budget ${safeBudget}ms) without a first heartbeat`,
|
|
88
|
+
ageMs,
|
|
89
|
+
budgetMs: safeBudget
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseIsoOrFallback(iso, now) {
|
|
93
|
+
const d = new Date(iso);
|
|
94
|
+
if (!Number.isNaN(d.getTime()))
|
|
95
|
+
return d;
|
|
96
|
+
return new Date(now().getTime());
|
|
97
|
+
}
|